pathrs

Struct Root

source
pub struct Root { /* private fields */ }
Expand description

A handle to the root of a directory tree.

§Safety

At the time of writing, it is considered a very bad idea to open a Root inside a possibly-attacker-controlled directory tree. While we do have protections that should defend against it (for both drivers), it’s far more dangerous than just opening a directory tree which is not inside a potentially-untrusted directory.

§Errors

If at any point an attack is detected during the execution of a Root method, an error will be returned. The method of attack detection is multi-layered and operates through explicit /proc/self/fd checks as well as (in the case of the native backend) kernel-space checks that will trigger -EXDEV in certain attack scenarios.

Additionally, if this root directory is moved then any subsequent operations will fail with a SafetyViolation error since it’s not obvious whether there is an attacker or if the path was moved innocently. This restriction might be relaxed in the future.

Implementations§

source§

impl Root

source

pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, Error>

Open a Root handle.

The resolver backend used by this handle is chosen at runtime based on which resolvers are supported by the running kernel.

§Errors

path must be an existing directory, and must (at the moment) be a fully-resolved pathname with no symlink components. This restriction might be relaxed in the future.

source

pub fn from_fd_unchecked<Fd: Into<OwnedFd>>(fd: Fd) -> Self

Wrap an OwnedFd into a Root.

The configuration is set to the system default and should be configured prior to usage, if appropriate.

§Safety

The caller guarantees that the provided file is an O_PATH file descriptor with exactly the same semantics as one created through Root::open. This means that this function should usually be used to convert an OwnedFd returned from OwnedFd::from (possibly from another process) into a Root.

While this function is not marked as unsafe (because the safety guarantee required is not related to memory-safety), users should still take great care when using this method because it can cause other kinds of unsafety.

source

pub fn as_ref(&self) -> RootRef<'_>

Borrow this Root as a RootRef.

The ResolverFlags of the Root are inherited by the RootRef byt are not shared (Root::set_resolver_flags does not affect existing RootRefs or RootRefs not created using Root::as_ref).

source

pub fn resolver_flags(&self) -> ResolverFlags

Get the current ResolverFlags for this Root.

source

pub fn set_resolver_flags(&mut self, flags: ResolverFlags) -> &mut Self

Set the ResolverFlags for all operations in this Root.

Note that this only affects this instance of Root. Neither other Root instances nor existing RootRef references to this Root will have their ResolverFlags unchanged.

source

pub fn with_resolver_flags(self, flags: ResolverFlags) -> Self

Set the ResolverFlags for all operations in this Root.

This is identical to Root::set_resolver_flags except that it can more easily be used with chaining to configure a Root in a single line:

let root = Root::open(rootdir)?.with_resolver_flags(ResolverFlags::NO_SYMLINKS);
// Continue to use root.

If you want to temporarily set flags just for a small set of operations, you should use Root::as_ref to create a temporary RootRef and use RootRef::with_resolver_flags instead.

source

pub fn try_clone(&self) -> Result<Root, Error>

Create a copy of an existing Root.

The new handle is completely independent from the original, but references the same underlying file and has the same configuration.

source

pub fn resolve<P: AsRef<Path>>(&self, path: P) -> Result<Handle, Error>

Within the given Root’s tree, resolve path and return a Handle.

All symlink path components are scoped to Root. Trailing symlinks are followed, if you want to get a handle to a symlink use resolve_nofollow.

§Errors

If path doesn’t exist, or an attack was detected during resolution, a corresponding Error will be returned. If no error is returned, then the path is guaranteed to have been reachable from the root of the directory tree and thus have been inside the root at one point in the resolution.

source

pub fn resolve_nofollow<P: AsRef<Path>>(&self, path: P) -> Result<Handle, Error>

Identical to resolve, except that trailing symlinks are not followed.

If the trailing component is a symlink resolve_nofollow will return a handle to the symlink itself. This is effectively equivalent to O_NOFOLLOW.

Get the target of a symlink within a Root.

NOTE: The returned path is not modified to be “safe” outside of the root. You should not use this path for doing further path lookups – use resolve instead.

This method is just shorthand for calling readlinkat(2) on the handle returned by resolve_nofollow.

source

pub fn create<P: AsRef<Path>>( &self, path: P, inode_type: &InodeType, ) -> Result<(), Error>

Within the Root’s tree, create an inode at path as specified by inode_type.

§Errors

If the path already exists (regardless of the type of the existing inode), an error is returned.

source

pub fn create_file<P: AsRef<Path>>( &self, path: P, flags: OpenFlags, perm: &Permissions, ) -> Result<File, Error>

Create an InodeType::File within the Root’s tree at path with the mode given by perm, and return a Handle to the newly-created file.

However, unlike the trivial way of doing the above:

root.create(path, inode_type)?;
// What happens if the file is replaced here!?
let handle = root.resolve(path, perm)?;

create_file guarantees that the returned Handle is the same as the file created by the operation. This is only possible to guarantee for ordinary files because there is no O_CREAT-equivalent for other inode types.

§Errors

Identical to create.

source

pub fn mkdir_all<P: AsRef<Path>>( &self, path: P, perm: &Permissions, ) -> Result<Handle, Error>

Within the Root’s tree, create a directory and any of its parent component if they are missing. This is effectively equivalent to std::fs::create_dir_all, Go’s os.MkdirAll, or Unix’s mkdir -p.

The provided set of Permissions only applies to path components created by this function, existing components will not have their permissions modified. In addition, if the provided path already exists and is a directory, this function will return successfully.

The returned Handle is an O_DIRECTORY handle referencing the created directory (due to kernel limitations, we cannot guarantee that the handle is the exact directory created and not a similar-looking directory that was swapped in by an attacker, but we do as much validation as possible to make sure the directory is functionally identical to the directory we would’ve created).

§Errors

This method will return an error if any of the path components in the provided path were invalid (non-directory components or dangling symlink components) or if certain exchange attacks were detected.

If an error occurs, it is possible for any number of the directories in path to have been created despite this method returning an error.

source

pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<(), Error>

Within the Root’s tree, remove the empty directory at path.

Any existing Handles to path will continue to work as before, since Linux does not invalidate file handles to unlinked files (though, directory handling is not as simple).

§Errors

If the path does not exist, was not actually a directory, or was a non-empty directory an error will be returned. In order to remove a directory and all of its children, you can use remove_all.

source

pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Error>

Within the Root’s tree, remove the file (any non-directory inode) at path.

Any existing Handles to path will continue to work as before, since Linux does not invalidate file handles to unlinked files (though, directory handling is not as simple).

§Errors

If the path does not exist or was actually a directory an error will be returned. In order to remove a path regardless of its type (even if it is a non-empty directory), you can use remove_all.

source

pub fn remove_all<P: AsRef<Path>>(&self, path: P) -> Result<(), Error>

Within the Root’s tree, recursively delete the provided path and any children it contains if it is a directory. This is effectively equivalent to std::fs::remove_dir_all, Go’s os.RemoveAll, or Unix’s rm -r.

Any existing Handles to paths within path will continue to work as before, since Linux does not invalidate file handles to unlinked files (though, directory handling is not as simple).

§Errors

If the path does not exist or some other error occurred during the deletion process an error will be returned.

source

pub fn rename<P: AsRef<Path>>( &self, source: P, destination: P, rflags: RenameFlags, ) -> Result<(), Error>

Within the Root’s tree, perform a rename with the given source and directory. The flags argument is passed directly to renameat2(2).

§Errors

The error rules are identical to renameat2(2).

Trait Implementations§

source§

impl AsFd for Root

source§

fn as_fd(&self) -> BorrowedFd<'_>

Access the underlying file descriptor for a Root.

Note: This method is primarily intended to allow for tests and other code to check the status of the underlying OwnedFd without having to use OwnedFd::from. It is not safe to use this BorrowedFd directly to do filesystem operations. Please use the provided Root methods.

source§

impl Debug for Root

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<Root> for OwnedFd

source§

fn from(root: Root) -> Self

Unwrap a Root to reveal the underlying OwnedFd.

Note: This method is primarily intended to allow for file descriptor passing or otherwise transmitting file descriptor information. It is not safe to use this OwnedFd directly to do filesystem operations. Please use the provided Root methods.

Auto Trait Implementations§

§

impl Freeze for Root

§

impl RefUnwindSafe for Root

§

impl Send for Root

§

impl Sync for Root

§

impl Unpin for Root

§

impl UnwindSafe for Root

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.