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
impl Root
sourcepub fn open<P: AsRef<Path>>(path: P) -> Result<Self, Error>
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.
sourcepub fn from_fd_unchecked<Fd: Into<OwnedFd>>(fd: Fd) -> Self
pub fn from_fd_unchecked<Fd: Into<OwnedFd>>(fd: Fd) -> Self
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.
sourcepub fn as_ref(&self) -> RootRef<'_>
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 RootRef
s or RootRef
s not created using
Root::as_ref
).
sourcepub fn resolver_flags(&self) -> ResolverFlags
pub fn resolver_flags(&self) -> ResolverFlags
Get the current ResolverFlags
for this Root
.
sourcepub fn set_resolver_flags(&mut self, flags: ResolverFlags) -> &mut Self
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.
sourcepub fn with_resolver_flags(self, flags: ResolverFlags) -> Self
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.
sourcepub fn try_clone(&self) -> Result<Root, Error>
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.
sourcepub fn resolve<P: AsRef<Path>>(&self, path: P) -> Result<Handle, Error>
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.
sourcepub fn resolve_nofollow<P: AsRef<Path>>(&self, path: P) -> Result<Handle, Error>
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
.
sourcepub fn readlink<P: AsRef<Path>>(&self, path: P) -> Result<PathBuf, Error>
pub fn readlink<P: AsRef<Path>>(&self, path: P) -> Result<PathBuf, Error>
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
.
sourcepub fn create_file<P: AsRef<Path>>(
&self,
path: P,
flags: OpenFlags,
perm: &Permissions,
) -> Result<File, Error>
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
.
sourcepub fn mkdir_all<P: AsRef<Path>>(
&self,
path: P,
perm: &Permissions,
) -> Result<Handle, Error>
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.
sourcepub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<(), Error>
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 Handle
s 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
.
sourcepub fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Error>
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 Handle
s 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
.
sourcepub fn remove_all<P: AsRef<Path>>(&self, path: P) -> Result<(), Error>
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 Handle
s 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.
sourcepub fn rename<P: AsRef<Path>>(
&self,
source: P,
destination: P,
rflags: RenameFlags,
) -> Result<(), Error>
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
impl AsFd for Root
source§fn as_fd(&self) -> BorrowedFd<'_>
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.
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> 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> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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