Skip to main content

ic_host_fs/identity/
mod.rs

1//! Native inode identity observations, without pathname or lifetime custody.
2
3use std::{
4    fs::{File, Metadata},
5    io,
6    os::unix::fs::MetadataExt as _,
7};
8
9/// Native device/inode identity; callers own file-kind admission and persistence.
10///
11/// An identity does not freeze contents or prevent inode reuse after all held
12/// descriptors close. It establishes neither confinement nor namespace custody.
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub struct FileIdentity {
15    /// Filesystem device number.
16    pub device: u64,
17    /// Inode number on that device.
18    pub inode: u64,
19}
20
21impl FileIdentity {
22    /// Observe a caller-owned regular descriptor without reopening its path.
23    ///
24    /// # Errors
25    /// Returns metadata failures or rejects a non-regular descriptor.
26    pub fn from_file(file: &File) -> io::Result<Self> {
27        let metadata = file.metadata()?;
28        if !metadata.is_file() {
29            return Err(io::Error::from(io::ErrorKind::InvalidInput));
30        }
31        Ok(Self::from_metadata(&metadata))
32    }
33
34    /// Observe native identity from metadata of any file kind.
35    ///
36    /// Callers choose following or no-follow metadata and admit the file kind.
37    #[must_use]
38    pub fn from_metadata(metadata: &Metadata) -> Self {
39        Self {
40            device: metadata.dev(),
41            inode: metadata.ino(),
42        }
43    }
44
45    #[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
46    #[cfg_attr(target_vendor = "apple", allow(clippy::cast_sign_loss))]
47    pub(crate) const fn from_stat(stat: &rustix::fs::Stat) -> Self {
48        Self {
49            // Match std's MetadataExt::dev projection of Darwin's signed dev_t.
50            #[cfg(target_vendor = "apple")]
51            device: stat.st_dev as u64,
52            #[cfg(not(target_vendor = "apple"))]
53            device: stat.st_dev,
54            inode: stat.st_ino,
55        }
56    }
57}
58
59#[cfg(test)]
60mod tests;