1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
//! A utility to read file IDs that are unique on a given device.
//!
//! Modern file systems assign a unique ID to each file. On Linux and MacOS it is called an `inode number`, on Windows it is called a `file index`.
//! Together with the `device id`, a file can be identified uniquely on a device at a given time.
//!
//! Keep in mind though, that IDs may be re-used at some point.
//!
//! ## Example
//!
//! ```rust
//! let file = tempfile::NamedTempFile::new().unwrap();
//!
//! let file_id = file_id::get_file_id(file.path()).unwrap();
//!
//! println!("{file_id:?}");
//! ```
use std::{fs, io, path::Path};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
/// Unique identifier of a file
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct FileId {
/// Device ID or volume serial number
pub device: u64,
/// Inode number or file index
pub file: u64,
}
impl FileId {
pub fn new(device: u64, file: u64) -> Self {
Self { device, file }
}
}
/// Get the `FileId` for the file at `path`
#[cfg(target_family = "unix")]
pub fn get_file_id(path: impl AsRef<Path>) -> io::Result<FileId> {
use std::os::unix::fs::MetadataExt;
let metadata = fs::metadata(path.as_ref())?;
Ok(FileId {
device: metadata.dev(),
file: metadata.ino(),
})
}
/// Get the `FileId` for the file at `path`
#[cfg(target_family = "windows")]
pub fn get_file_id(path: impl AsRef<Path>) -> io::Result<FileId> {
use winapi_util::{file::information, Handle};
let handle = Handle::from_path_any(path.as_ref())?;
let info = information(&handle)?;
Ok(FileId {
device: info.volume_serial_number(),
file: info.file_index(),
})
}