pub struct FsRoot { /* private fields */ }Expand description
A directory the API may touch, and nothing outside it.
Held by value in the app state; every filesystem path in the API is produced by one of these methods and by no other route.
Implementations§
Source§impl FsRoot
impl FsRoot
Sourcepub fn new(root: impl AsRef<Path>) -> Result<Self>
pub fn new(root: impl AsRef<Path>) -> Result<Self>
Anchor a jail at root, which must already exist.
Canonicalised once here so every later comparison is against a path with symlinks already resolved — otherwise a symlinked root would make every containment check compare unlike things.
Sourcepub fn resolve_existing(&self, rel: &str) -> Result<PathBuf, FsError>
pub fn resolve_existing(&self, rel: &str) -> Result<PathBuf, FsError>
Resolve a path that must already exist.
Containment is decided by canonicalising the deepest part of the path that exists, never by the kind of error a full canonicalisation returned. Branching on the error kind is what leaks: a path whose parent is a file fails with ENOTDIR while a path whose parent is absent fails with NotFound, so answering differently tells the caller which files exist outside the jail. It also mishandles a symlink that points out of the root — the link resolves, the target does not exist, and a lexical check sees a path that never left.
Walking down instead means every real directory on the way is resolved
through its symlinks and checked, and the verdict never depends on an
errno. resolve_for_create uses the same discipline.
Sourcepub fn resolve_for_create(&self, rel: &str) -> Result<PathBuf, FsError>
pub fn resolve_for_create(&self, rel: &str) -> Result<PathBuf, FsError>
Resolve a path that does not exist yet (an upload target).
The target itself cannot be canonicalised, so the nearest existing
ancestor is canonicalised instead and the remaining segments are checked
lexically. Those segments may not contain ..: with nothing on disk to
resolve against, a traversal there would go unnoticed until the write.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for FsRoot
impl RefUnwindSafe for FsRoot
impl Send for FsRoot
impl Sync for FsRoot
impl Unpin for FsRoot
impl UnsafeUnpin for FsRoot
impl UnwindSafe for FsRoot
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.