pub trait DirHandle:
Sized
+ Send
+ Sync
+ Sealed {
type Attrs: Copy;
Show 14 methods
// Required methods
fn open_root(path: &Path) -> Result<Self, GuardIo>;
fn open_child_dir(&self, name: &OsStr) -> Result<Self, GuardIo>;
fn make_child_dir(&self, name: &OsStr) -> Result<(), GuardIo>;
fn open_child_file(
&self,
name: &OsStr,
mode: OpenMode,
) -> Result<File, GuardIo>;
fn create_child_file(
&self,
name: &OsStr,
excl: Excl,
) -> Result<File, GuardIo>;
fn rename_child(&self, from: &OsStr, to: &OsStr) -> Result<(), GuardIo>;
fn unlink_child(&self, name: &OsStr);
fn child_kind(&self, name: &OsStr) -> Option<NodeKind>;
fn child_attrs(&self, name: &OsStr) -> Option<Self::Attrs>;
fn apply_attrs(&self, file: &File, attrs: Self::Attrs) -> Result<()>;
fn identity(&self) -> Result<NodeId, GuardIo>;
fn resolve_beneath(
&self,
rel: &Path,
mode: OpenMode,
) -> Result<Option<File>, GuardIo>;
fn into_file(self) -> File ⓘ;
fn sync_name_durability(&self) -> Result<(), GuardIo>;
}Expand description
A directory the caller already proved is inside the guard root, and the only way to go one step deeper.
INVARIANT, enforced by the type and not by review: no method accepts an
absolute path, and no method accepts a multi-component path. Every
operation names one component, relative to self. That is what makes
fsguard’s one-door property structural — code handed a DirHandle still
cannot reach outside it, which is strictly stronger than free functions,
where nothing but discipline stops a second open() on a full path.
The one exception proves the rule: resolve_beneath
takes a multi-component relative path, and the whole point of it is that
the kernel enforces beneath-ness in a single syscall. It is not a
weakening of the invariant, it is the invariant delegated to the one place
that can honor it atomically.
Sealed, because the guarantees above are statements about all implementors.
Required Associated Types§
Required Methods§
Sourcefn open_root(path: &Path) -> Result<Self, GuardIo>
fn open_root(path: &Path) -> Result<Self, GuardIo>
Open the guard root itself, by name. The root is ours, not the model’s — this is the only place a full path enters, and it is the anchor every other method is relative to.
Sourcefn open_child_dir(&self, name: &OsStr) -> Result<Self, GuardIo>
fn open_child_dir(&self, name: &OsStr) -> Result<Self, GuardIo>
Open a child directory without following any link at the final
component. Unix O_NOFOLLOW|O_DIRECTORY; Windows
FILE_OPEN_REPARSE_POINT|FILE_DIRECTORY_FILE relative to the handle.
Sourcefn make_child_dir(&self, name: &OsStr) -> Result<(), GuardIo>
fn make_child_dir(&self, name: &OsStr) -> Result<(), GuardIo>
mkdirat. Succeeding when it already exists is the caller’s business,
not this method’s.
fn open_child_file(&self, name: &OsStr, mode: OpenMode) -> Result<File, GuardIo>
fn create_child_file(&self, name: &OsStr, excl: Excl) -> Result<File, GuardIo>
fn rename_child(&self, from: &OsStr, to: &OsStr) -> Result<(), GuardIo>
Sourcefn unlink_child(&self, name: &OsStr)
fn unlink_child(&self, name: &OsStr)
Best-effort removal of our own temp file. A failure here has nothing to report, which is why it returns nothing.
Sourcefn child_kind(&self, name: &OsStr) -> Option<NodeKind>
fn child_kind(&self, name: &OsStr) -> Option<NodeKind>
Classify a child without following it, or None if it does not
exist. See NodeKind — the fail-closed default is the whole point.
fn child_attrs(&self, name: &OsStr) -> Option<Self::Attrs>
fn apply_attrs(&self, file: &File, attrs: Self::Attrs) -> Result<()>
Sourcefn identity(&self) -> Result<NodeId, GuardIo>
fn identity(&self) -> Result<NodeId, GuardIo>
Stable identity, for the belt-and-braces check that the handle we validated and the path we return are the same object.
Sourcefn resolve_beneath(
&self,
rel: &Path,
mode: OpenMode,
) -> Result<Option<File>, GuardIo>
fn resolve_beneath( &self, rel: &Path, mode: OpenMode, ) -> Result<Option<File>, GuardIo>
Single-syscall beneath-resolution where the OS has one: Linux openat2
with RESOLVE_BENEATH|RESOLVE_NO_SYMLINKS|RESOLVE_NO_MAGICLINKS,
Windows NtCreateFile with OBJ_DONT_REPARSE.
Ok(None) means this kernel does not offer it (pre-5.6 Linux, a
seccomp filter returning ENOSYS/EPERM, pre-1607 Windows) and the caller
must fall through to the component-wise descent. It does not mean
“allowed” — an actual refusal is Err.
Sourcefn into_file(self) -> File ⓘ
fn into_file(self) -> File ⓘ
Hand back the handle for this directory itself, for the one case where the caller’s target is the directory it already descended to. Widens nothing: it returns the object the caller already holds.
Sourcefn sync_name_durability(&self) -> Result<(), GuardIo>
fn sync_name_durability(&self) -> Result<(), GuardIo>
After this returns, the most recent rename in this directory survives a crash.
CONTRACT is the guarantee, not the mechanism, and the two platforms
reach it differently: Unix must fsync the directory fd, because
without it the rename can be lost even though the data was synced. NTFS
journals the metadata operation itself, so on Windows the guarantee
already holds when the rename returns. Windows returning Ok is
therefore a claim that the property is satisfied — not a no-op standing
in for a capability the platform lacks.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".