From 7112182dbcbd55925df7d33d11d8090cd043d16f Mon Sep 17 00:00:00 2001 From: Paul Otten Date: Thu, 1 Apr 2021 18:37:20 -0400 Subject: [PATCH] Consider device id when comparing files --- src/uu/du/src/du.rs | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 2eb7bd658..c311f982e 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -32,7 +32,7 @@ use winapi::um::minwinbase::{FileStandardInfo, FileIdInfo}; #[cfg(windows)] use winapi::um::winbase::GetFileInformationByHandleEx; #[cfg(windows)] -use winapi::um::winnt::FILE_ID_128; +use winapi::um::winnt::{FILE_ID_128, ULONGLONG}; const NAME: &str = "du"; const SUMMARY: &str = "estimate file space usage"; @@ -58,12 +58,18 @@ struct Options { separate_dirs: bool, } +#[derive(PartialEq, Eq, Hash, Clone, Copy)] +struct FileInfo { + file_id: u128, + dev_id: u64, +} + struct Stat { path: PathBuf, is_dir: bool, size: u64, blocks: u64, - inode: Option, + inode: Option, created: u64, accessed: u64, modified: u64, @@ -73,13 +79,18 @@ impl Stat { fn new(path: PathBuf) -> Result { let metadata = fs::symlink_metadata(&path)?; + #[cfg(not(windows))] + let file_info = FileInfo { + file_id: metadata.ino() as u128, + dev_id: metadata.dev(), + }; #[cfg(not(windows))] return Ok(Stat { path, is_dir: metadata.is_dir(), size: metadata.len(), blocks: metadata.blocks() as u64, - inode: Some(metadata.ino() as u128), + inode: Some(file_info), created: metadata.mtime() as u64, accessed: metadata.atime() as u64, modified: metadata.mtime() as u64, @@ -88,14 +99,14 @@ impl Stat { #[cfg(windows)] let size_on_disk = get_size_on_disk(&path); #[cfg(windows)] - let inode = get_inode(&path); + let file_info = get_file_info(&path); #[cfg(windows)] Ok(Stat { path, is_dir: metadata.is_dir(), size: metadata.len(), blocks: size_on_disk / 1024 * 2, - inode: inode, + inode: file_info, created: windows_time_to_unix_time(metadata.creation_time()), accessed: windows_time_to_unix_time(metadata.last_access_time()), modified: windows_time_to_unix_time(metadata.last_write_time()), @@ -143,12 +154,12 @@ fn get_size_on_disk(path: &PathBuf) -> u64 { } #[cfg(windows)] -fn get_inode(path: &PathBuf) -> Option { - let mut inode = None; +fn get_file_info(path: &PathBuf) -> Option { + let mut result = None; let file = match fs::File::open(path) { Ok(file) => file, - Err(_) => return inode, + Err(_) => return result, }; let handle = file.as_raw_handle(); @@ -165,11 +176,14 @@ fn get_inode(path: &PathBuf) -> Option { ); if success != 0 { - inode = Some(std::mem::transmute::(file_info.FileId)); + result = Some(FileInfo { + file_id: std::mem::transmute::(file_info.FileId), + dev_id: std::mem::transmute::(file_info.VolumeSerialNumber), + }); } } - inode + result } fn unit_string_to_number(s: &str) -> Option { @@ -239,7 +253,7 @@ fn du( mut my_stat: Stat, options: &Options, depth: usize, - inodes: &mut HashSet, + inodes: &mut HashSet, ) -> Box> { let mut stats = vec![]; let mut futures = vec![]; @@ -523,7 +537,7 @@ Try '{} --help' for more information.", let path = PathBuf::from(&path_str); match Stat::new(path) { Ok(stat) => { - let mut inodes: HashSet = HashSet::new(); + let mut inodes: HashSet = HashSet::new(); let iter = du(stat, &options, 0, &mut inodes); let (_, len) = iter.size_hint();