use std::fs::{File, Metadata};
use std::io;
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
pub(super) struct NativeIdentity {
volume: u64,
file: [u8; 16],
}
pub(super) fn require_direct_entry(metadata: &Metadata) -> io::Result<()> {
if metadata.file_type().is_symlink() {
return Err(super::invalid(
"symlinks are outside the captured fault model",
));
}
#[cfg(windows)]
{
use std::os::windows::fs::MetadataExt;
const FILE_ATTRIBUTE_REPARSE_POINT: u32 = 0x400;
if metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0 {
return Err(super::invalid(
"reparse points are outside the captured fault model",
));
}
}
Ok(())
}
#[cfg(unix)]
pub(super) fn of_file(file: &File) -> io::Result<NativeIdentity> {
use std::os::unix::fs::MetadataExt;
let metadata = file.metadata()?;
Ok(NativeIdentity {
volume: metadata.dev(),
file: u128::from(metadata.ino()).to_le_bytes(),
})
}
#[cfg(windows)]
pub(super) fn of_file(file: &File) -> io::Result<NativeIdentity> {
use std::ffi::c_void;
use std::os::windows::io::AsRawHandle;
#[link(name = "kernel32")]
unsafe extern "system" {
#[link_name = "GetFileInformationByHandleEx"]
fn get_file_information_by_handle_ex(
file: *mut c_void,
class: i32,
information: *mut c_void,
size: u32,
) -> i32;
}
const FILE_ID_INFO: i32 = 18;
let mut identity = NativeIdentity::default();
let success = unsafe {
get_file_information_by_handle_ex(
file.as_raw_handle(),
FILE_ID_INFO,
std::ptr::from_mut(&mut identity).cast(),
std::mem::size_of::<NativeIdentity>() as u32,
)
};
if success == 0 {
return Err(io::Error::last_os_error());
}
Ok(identity)
}
#[cfg(not(any(unix, windows)))]
pub(super) fn of_file(_file: &File) -> io::Result<NativeIdentity> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"native identity requires Unix or Windows",
))
}