Skip to main content

acyclic_fs/
native_identity.rs

1//! Stable identities for already-open native filesystem roots.
2
3/// Stable native identity of one held filesystem root.
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub struct NativeRootIdentity {
6    pub(crate) device: u64,
7    pub(crate) object: u64,
8}
9
10impl NativeRootIdentity {
11    /// Derives identity from an already-open root handle.
12    ///
13    /// # Errors
14    ///
15    /// Returns an I/O error when this platform cannot report a stable root
16    /// identity.
17    pub fn from_file(file: &std::fs::File) -> std::io::Result<Self> {
18        native_root_identity(file)
19    }
20
21    pub(crate) fn from_metadata(metadata: &cap_std::fs::Metadata) -> std::io::Result<Self> {
22        native_metadata_identity(metadata)
23    }
24
25    /// Returns the canonical platform-neutral 16-byte identity encoding.
26    #[must_use]
27    pub fn to_bytes(self) -> [u8; 16] {
28        let mut bytes = [0_u8; 16];
29        bytes[..8].copy_from_slice(&self.device.to_le_bytes());
30        bytes[8..].copy_from_slice(&self.object.to_le_bytes());
31        bytes
32    }
33
34    /// Decodes the exact canonical identity representation.
35    #[must_use]
36    pub fn from_bytes(bytes: [u8; 16]) -> Self {
37        let mut device = [0_u8; 8];
38        device.copy_from_slice(&bytes[..8]);
39        let mut object = [0_u8; 8];
40        object.copy_from_slice(&bytes[8..]);
41        Self {
42            device: u64::from_le_bytes(device),
43            object: u64::from_le_bytes(object),
44        }
45    }
46}
47
48#[cfg(unix)]
49fn native_metadata_identity(
50    metadata: &cap_std::fs::Metadata,
51) -> std::io::Result<NativeRootIdentity> {
52    use cap_std::fs::MetadataExt;
53    Ok(NativeRootIdentity {
54        device: metadata.dev(),
55        object: metadata.ino(),
56    })
57}
58
59#[cfg(windows)]
60fn native_metadata_identity(
61    metadata: &cap_std::fs::Metadata,
62) -> std::io::Result<NativeRootIdentity> {
63    use cap_primitives::fs::_WindowsByHandle;
64    let device = metadata.volume_serial_number().ok_or_else(|| {
65        std::io::Error::new(
66            std::io::ErrorKind::Unsupported,
67            "host volume identity is unavailable",
68        )
69    })?;
70    let object = metadata.file_index().ok_or_else(|| {
71        std::io::Error::new(
72            std::io::ErrorKind::Unsupported,
73            "host file identity is unavailable",
74        )
75    })?;
76    Ok(NativeRootIdentity {
77        device: u64::from(device),
78        object,
79    })
80}
81
82#[cfg(not(any(unix, windows)))]
83fn native_metadata_identity(_: &cap_std::fs::Metadata) -> std::io::Result<NativeRootIdentity> {
84    Err(std::io::Error::new(
85        std::io::ErrorKind::Unsupported,
86        "stable host file identity is unavailable on this platform",
87    ))
88}
89
90#[cfg(unix)]
91fn native_root_identity(file: &std::fs::File) -> std::io::Result<NativeRootIdentity> {
92    use std::os::unix::fs::MetadataExt;
93    let metadata = file.metadata()?;
94    Ok(NativeRootIdentity {
95        device: metadata.dev(),
96        object: metadata.ino(),
97    })
98}
99
100#[cfg(windows)]
101fn native_root_identity(file: &std::fs::File) -> std::io::Result<NativeRootIdentity> {
102    let metadata = cap_std::fs::File::from_std(file.try_clone()?).metadata()?;
103    native_metadata_identity(&metadata)
104}
105
106#[cfg(not(any(unix, windows)))]
107fn native_root_identity(_: &std::fs::File) -> std::io::Result<NativeRootIdentity> {
108    Err(std::io::Error::new(
109        std::io::ErrorKind::Unsupported,
110        "stable root identity is unavailable on this platform",
111    ))
112}