file_source/
metadata_ext.rs1use std::fs::File;
7#[cfg(unix)]
8use std::os::unix::fs::MetadataExt;
9#[cfg(windows)]
10use std::{mem::zeroed, ptr};
11
12#[cfg(windows)]
13use winapi::shared::minwindef::DWORD;
14#[cfg(windows)]
15use winapi::um::{
16 fileapi::GetFileInformationByHandle, fileapi::BY_HANDLE_FILE_INFORMATION,
17 ioapiset::DeviceIoControl, winioctl::FSCTL_GET_REPARSE_POINT,
18 winnt::FILE_ATTRIBUTE_REPARSE_POINT, winnt::MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
19};
20
21#[cfg(not(windows))]
22pub trait PortableFileExt {
23 fn portable_dev(&self) -> std::io::Result<u64>;
24 fn portable_ino(&self) -> std::io::Result<u64>;
25}
26
27#[cfg(windows)]
28pub trait PortableFileExt: std::os::windows::io::AsRawHandle {
29 fn portable_dev(&self) -> std::io::Result<u64>;
30 fn portable_ino(&self) -> std::io::Result<u64>;
31 #[allow(unused_assignments, unused_variables)]
33 fn reparse_point<'a>(
34 &self,
35 space: &'a mut [u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
36 ) -> std::io::Result<(DWORD, &'a REPARSE_DATA_BUFFER)> {
37 unsafe {
38 let mut bytes = 0;
39 cvt({
40 DeviceIoControl(
41 self.as_raw_handle(),
42 FSCTL_GET_REPARSE_POINT,
43 ptr::null_mut(),
44 0,
45 space.as_mut_ptr() as *mut _,
46 space.len() as DWORD,
47 &mut bytes,
48 ptr::null_mut(),
49 )
50 })?;
51 Ok((bytes, &*(space.as_ptr() as *const REPARSE_DATA_BUFFER)))
52 }
53 }
54 #[allow(unused_assignments, unused_variables)]
56 fn get_file_info(&self) -> std::io::Result<BY_HANDLE_FILE_INFORMATION> {
57 unsafe {
58 let mut info: BY_HANDLE_FILE_INFORMATION = zeroed();
59 cvt(GetFileInformationByHandle(self.as_raw_handle(), &mut info))?;
60 let mut reparse_tag = 0;
61 if info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0 {
62 let mut b = [0; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize];
63 if let Ok((_, buf)) = self.reparse_point(&mut b) {
64 reparse_tag = buf.ReparseTag;
65 }
66 }
67 Ok(info)
68 }
69 }
70}
71
72#[cfg(unix)]
73impl PortableFileExt for File {
74 fn portable_dev(&self) -> std::io::Result<u64> {
75 Ok(self.metadata()?.dev())
76 }
77 fn portable_ino(&self) -> std::io::Result<u64> {
78 Ok(self.metadata()?.ino())
79 }
80}
81
82#[cfg(windows)]
83impl PortableFileExt for File {
84 fn portable_dev(&self) -> std::io::Result<u64> {
85 let info = self.get_file_info()?;
86 Ok(info.dwVolumeSerialNumber.into())
87 }
88 fn portable_ino(&self) -> std::io::Result<u64> {
90 let info = self.get_file_info()?;
91 Ok((info.nFileIndexLow as u64) | ((info.nFileIndexHigh as u64) << 32))
93 }
94}
95
96#[cfg(windows)]
98#[allow(dead_code, non_snake_case, non_camel_case_types)]
99pub struct REPARSE_DATA_BUFFER {
100 pub ReparseTag: libc::c_uint,
101 pub ReparseDataLength: libc::c_ushort,
102 pub Reserved: libc::c_ushort,
103 pub rest: (),
104}
105
106#[cfg(windows)]
108pub fn cvt(result: i32) -> std::io::Result<usize> {
109 if result < 0 {
110 Err(std::io::Error::from_raw_os_error(-result))
111 } else {
112 Ok(result as usize)
113 }
114}