1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Merge pull request #1998 from paulotten/issue1969

Consider device id when comparing files
This commit is contained in:
Sylvestre Ledru 2021-04-05 22:34:12 +02:00 committed by GitHub
commit 3f3b12ebcc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -32,7 +32,7 @@ use winapi::um::minwinbase::{FileIdInfo, FileStandardInfo};
#[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<u128>,
inode: Option<FileInfo>,
created: u64,
accessed: u64,
modified: u64,
@ -73,13 +79,18 @@ impl Stat {
fn new(path: PathBuf) -> Result<Stat> {
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<u128> {
let mut inode = None;
fn get_file_info(path: &PathBuf) -> Option<FileInfo> {
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<u128> {
);
if success != 0 {
inode = Some(std::mem::transmute::<FILE_ID_128, u128>(file_info.FileId));
result = Some(FileInfo {
file_id: std::mem::transmute::<FILE_ID_128, u128>(file_info.FileId),
dev_id: std::mem::transmute::<ULONGLONG, u64>(file_info.VolumeSerialNumber),
});
}
}
inode
result
}
fn unit_string_to_number(s: &str) -> Option<u64> {
@ -239,7 +253,7 @@ fn du(
mut my_stat: Stat,
options: &Options,
depth: usize,
inodes: &mut HashSet<u128>,
inodes: &mut HashSet<FileInfo>,
) -> Box<dyn DoubleEndedIterator<Item = Stat>> {
let mut stats = vec![];
let mut futures = vec![];
@ -526,7 +540,7 @@ Try '{} --help' for more information.",
let path = PathBuf::from(&path_str);
match Stat::new(path) {
Ok(stat) => {
let mut inodes: HashSet<u128> = HashSet::new();
let mut inodes: HashSet<FileInfo> = HashSet::new();
let iter = du(stat, &options, 0, &mut inodes);
let (_, len) = iter.size_hint();