Loading crates/fs-mistrust/src/err.rs +5 −0 Original line number Original line Diff line number Diff line Loading @@ -67,6 +67,10 @@ pub enum Error { /// impossible. /// impossible. #[error("Problem finding current directory")] #[error("Problem finding current directory")] CurrentDirectory(#[source] Arc<IoError>), CurrentDirectory(#[source] Arc<IoError>), /// We tried to create a directory, and encountered a failure in doing so. #[error("Problem creating directory")] CreatingDir(#[source] Arc<IoError>), } } impl Error { impl Error { Loading @@ -90,6 +94,7 @@ impl Error { Error::Multiple(_) => return None, Error::Multiple(_) => return None, Error::StepsExceeded => return None, Error::StepsExceeded => return None, Error::CurrentDirectory(_) => return None, Error::CurrentDirectory(_) => return None, Error::CreatingDir(_) => return None, } } .as_path(), .as_path(), ) ) Loading crates/fs-mistrust/src/lib.rs +82 −2 Original line number Original line Diff line number Diff line Loading @@ -86,7 +86,6 @@ //! https://gitlab.torproject.org/tpo/core/tor/-/blob/main/src/lib/fs/dir.c#L70 //! https://gitlab.torproject.org/tpo/core/tor/-/blob/main/src/lib/fs/dir.c#L70 // TODO: Stuff to add before this crate is ready.... // TODO: Stuff to add before this crate is ready.... // - Ability to create directory if it doesn't exist. // - Test the absolute heck out of it. // - Test the absolute heck out of it. // POSSIBLY TODO: // POSSIBLY TODO: Loading Loading @@ -131,7 +130,11 @@ mod imp; pub(crate) mod testing; pub(crate) mod testing; pub mod walk; pub mod walk; use std::path::{Path, PathBuf}; use std::{ fs::DirBuilder, path::{Path, PathBuf}, sync::Arc, }; pub use err::Error; pub use err::Error; Loading Loading @@ -292,6 +295,15 @@ impl Mistrust { pub fn check_directory<P: AsRef<Path>>(&self, dir: P) -> Result<()> { pub fn check_directory<P: AsRef<Path>>(&self, dir: P) -> Result<()> { self.verifier().require_directory().check(dir) self.verifier().require_directory().check(dir) } } /// As `check_directory`, but create the directory if needed. /// /// `m.check_directory(dir)` is equivalent to /// `m.verifier().make_directory(dir)`. If you need different behavior, see /// [`Verifier`] for more options. pub fn make_directory<P: AsRef<Path>>(&self, dir: P) -> Result<()> { self.verifier().make_directory(dir) } } } impl<'a> Verifier<'a> { impl<'a> Verifier<'a> { Loading Loading @@ -370,6 +382,44 @@ impl<'a> Verifier<'a> { None => Ok(()), None => Ok(()), } } } } /// Check whether `path` is a valid directory, and create it if it doesn't /// exist. /// /// Returns `Ok` if the directory already existed or if it was just created, /// and it conforms to the requirements of this `Verifier` and the /// [`Mistrust`] that created it. /// /// Return an error if: /// * there was a permissions or ownership problem in the path or any of /// its ancestors, /// * there was a problem when creating the directory /// * after creating the directory, we found that it had a permissions or /// ownership problem. pub fn make_directory<P: AsRef<Path>>(mut self, path: P) -> Result<()> { self.enforce_type = Some(Type::Dir); let path = path.as_ref(); match self.clone().check(path) { Err(Error::NotFound(_)) => {} Err(other_error) => return Err(other_error), Ok(()) => return Ok(()), // no error; file exists. } // Looks like we got a "not found", so we're creating the path. let mut bld = DirBuilder::new(); #[cfg(target_family = "unix")] { use std::os::unix::fs::DirBuilderExt; bld.mode(0o700); } bld.recursive(true) .create(path) .map_err(|e| Error::CreatingDir(Arc::new(e)))?; // We built the path! But for paranoia's sake, check it again. self.check(path) } } } #[cfg(test)] #[cfg(test)] Loading Loading @@ -576,6 +626,36 @@ mod test { assert!(matches!(e, Error::BadPermission(_, _))); assert!(matches!(e, Error::BadPermission(_, _))); } } #[test] fn make_directory() { let d = Dir::new(); d.dir("a/b"); let mut m = Mistrust::new(); m.ignore_prefix(d.canonical_root()).unwrap(); #[cfg(target_family = "unix")] { // Try once with bad permissions. d.chmod("a", 0o777); let e = m.make_directory(d.path("a/b/c/d")).unwrap_err(); assert!(matches!(e, Error::BadPermission(_, _))); // Now make the permissions correct. d.chmod("a", 0o0700); d.chmod("a/b", 0o0700); } // Make the directory! m.make_directory(d.path("a/b/c/d")).unwrap(); // Make sure it exists and has good permissions. m.check_directory(d.path("a/b/c/d")).unwrap(); // Try make_directory again and make sure _that_ succeeds. m.make_directory(d.path("a/b/c/d")).unwrap(); } // TODO: Write far more tests. // TODO: Write far more tests. // * Can there be a test for a failed readlink()? I can't see an easy way // * Can there be a test for a failed readlink()? I can't see an easy way // to provoke that without trying to make a time-of-check/time-of-use race // to provoke that without trying to make a time-of-check/time-of-use race Loading Loading
crates/fs-mistrust/src/err.rs +5 −0 Original line number Original line Diff line number Diff line Loading @@ -67,6 +67,10 @@ pub enum Error { /// impossible. /// impossible. #[error("Problem finding current directory")] #[error("Problem finding current directory")] CurrentDirectory(#[source] Arc<IoError>), CurrentDirectory(#[source] Arc<IoError>), /// We tried to create a directory, and encountered a failure in doing so. #[error("Problem creating directory")] CreatingDir(#[source] Arc<IoError>), } } impl Error { impl Error { Loading @@ -90,6 +94,7 @@ impl Error { Error::Multiple(_) => return None, Error::Multiple(_) => return None, Error::StepsExceeded => return None, Error::StepsExceeded => return None, Error::CurrentDirectory(_) => return None, Error::CurrentDirectory(_) => return None, Error::CreatingDir(_) => return None, } } .as_path(), .as_path(), ) ) Loading
crates/fs-mistrust/src/lib.rs +82 −2 Original line number Original line Diff line number Diff line Loading @@ -86,7 +86,6 @@ //! https://gitlab.torproject.org/tpo/core/tor/-/blob/main/src/lib/fs/dir.c#L70 //! https://gitlab.torproject.org/tpo/core/tor/-/blob/main/src/lib/fs/dir.c#L70 // TODO: Stuff to add before this crate is ready.... // TODO: Stuff to add before this crate is ready.... // - Ability to create directory if it doesn't exist. // - Test the absolute heck out of it. // - Test the absolute heck out of it. // POSSIBLY TODO: // POSSIBLY TODO: Loading Loading @@ -131,7 +130,11 @@ mod imp; pub(crate) mod testing; pub(crate) mod testing; pub mod walk; pub mod walk; use std::path::{Path, PathBuf}; use std::{ fs::DirBuilder, path::{Path, PathBuf}, sync::Arc, }; pub use err::Error; pub use err::Error; Loading Loading @@ -292,6 +295,15 @@ impl Mistrust { pub fn check_directory<P: AsRef<Path>>(&self, dir: P) -> Result<()> { pub fn check_directory<P: AsRef<Path>>(&self, dir: P) -> Result<()> { self.verifier().require_directory().check(dir) self.verifier().require_directory().check(dir) } } /// As `check_directory`, but create the directory if needed. /// /// `m.check_directory(dir)` is equivalent to /// `m.verifier().make_directory(dir)`. If you need different behavior, see /// [`Verifier`] for more options. pub fn make_directory<P: AsRef<Path>>(&self, dir: P) -> Result<()> { self.verifier().make_directory(dir) } } } impl<'a> Verifier<'a> { impl<'a> Verifier<'a> { Loading Loading @@ -370,6 +382,44 @@ impl<'a> Verifier<'a> { None => Ok(()), None => Ok(()), } } } } /// Check whether `path` is a valid directory, and create it if it doesn't /// exist. /// /// Returns `Ok` if the directory already existed or if it was just created, /// and it conforms to the requirements of this `Verifier` and the /// [`Mistrust`] that created it. /// /// Return an error if: /// * there was a permissions or ownership problem in the path or any of /// its ancestors, /// * there was a problem when creating the directory /// * after creating the directory, we found that it had a permissions or /// ownership problem. pub fn make_directory<P: AsRef<Path>>(mut self, path: P) -> Result<()> { self.enforce_type = Some(Type::Dir); let path = path.as_ref(); match self.clone().check(path) { Err(Error::NotFound(_)) => {} Err(other_error) => return Err(other_error), Ok(()) => return Ok(()), // no error; file exists. } // Looks like we got a "not found", so we're creating the path. let mut bld = DirBuilder::new(); #[cfg(target_family = "unix")] { use std::os::unix::fs::DirBuilderExt; bld.mode(0o700); } bld.recursive(true) .create(path) .map_err(|e| Error::CreatingDir(Arc::new(e)))?; // We built the path! But for paranoia's sake, check it again. self.check(path) } } } #[cfg(test)] #[cfg(test)] Loading Loading @@ -576,6 +626,36 @@ mod test { assert!(matches!(e, Error::BadPermission(_, _))); assert!(matches!(e, Error::BadPermission(_, _))); } } #[test] fn make_directory() { let d = Dir::new(); d.dir("a/b"); let mut m = Mistrust::new(); m.ignore_prefix(d.canonical_root()).unwrap(); #[cfg(target_family = "unix")] { // Try once with bad permissions. d.chmod("a", 0o777); let e = m.make_directory(d.path("a/b/c/d")).unwrap_err(); assert!(matches!(e, Error::BadPermission(_, _))); // Now make the permissions correct. d.chmod("a", 0o0700); d.chmod("a/b", 0o0700); } // Make the directory! m.make_directory(d.path("a/b/c/d")).unwrap(); // Make sure it exists and has good permissions. m.check_directory(d.path("a/b/c/d")).unwrap(); // Try make_directory again and make sure _that_ succeeds. m.make_directory(d.path("a/b/c/d")).unwrap(); } // TODO: Write far more tests. // TODO: Write far more tests. // * Can there be a test for a failed readlink()? I can't see an easy way // * Can there be a test for a failed readlink()? I can't see an easy way // to provoke that without trying to make a time-of-check/time-of-use race // to provoke that without trying to make a time-of-check/time-of-use race Loading