diff --git a/Cargo.lock b/Cargo.lock index 6aaf91a..665dddc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,6 +118,7 @@ dependencies = [ "scoped-pool 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "unbytify 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index b8577c3..f29a417 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,6 @@ fnv = "1.0.6" unbytify = "0.2.0" regex = "1.3.1" glob = "0.3.0" + +[build-dependencies] +version_check = "0.9" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..bc6ca1e --- /dev/null +++ b/build.rs @@ -0,0 +1,12 @@ +extern crate version_check; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + if cfg!(unix){ + println!("cargo:rustc-cfg=use_ino"); + } else if version_check::is_feature_flaggable().unwrap_or(false) && cfg!(windows) { + println!("cargo:rustc-cfg=use_windows_file_numbers"); + } else{ + println!("cargo:rustc-cfg=use_ino_placeholder"); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0b20db4..0a6aba4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,18 @@ -use std::fs::{File, Metadata}; +#![cfg_attr(use_windows_file_numbers, feature(windows_by_handle))] + +#[cfg(any(use_ino, use_ino_placeholder))] +use std::fs::Metadata; + +#[cfg(use_ino)] +use std::os::unix::fs::MetadataExt; + +#[cfg(use_windows_file_numbers)] +use std::os::windows::fs::MetadataExt; + +#[cfg(use_windows_file_numbers)] +use std::path::Path; + +use std::fs::File; use std::io::{self, Read, Write, Seek, SeekFrom}; use std::path::PathBuf; use std::sync::mpsc::{Sender, channel}; @@ -7,8 +21,6 @@ use structopt::StructOpt; use fnv::{FnvHashMap as HashMap, FnvHashSet as HashSet}; use blake3::Hasher; use walkdir::{DirEntry, WalkDir}; -#[cfg(unix)] -use std::os::unix::fs::MetadataExt; use regex::Regex; use glob::Pattern; @@ -232,14 +244,26 @@ fn main() { // We take care to avoid visiting a single inode twice, // which takes care of (false positive) hardlinks. - #[cfg(unix)] + #[cfg(use_ino)] fn check_inode(set: &mut HashSet<(u64, u64)>, entry: &Metadata) -> bool { set.insert((entry.dev(), entry.ino())) } - #[cfg(not(unix))] + + #[cfg(use_windows_file_numbers)] + fn check_inode(set: &mut HashSet<(u32, u64)>, entry: &Path) -> Option { + let meta = match std::fs::metadata(entry){ + Ok(m) => m, + Err(_) => return None, + }; + + return Some(set.insert( (meta.volume_serial_number()?, meta.file_index()?) )); + } + + #[cfg(use_ino_placeholder)] fn check_inode(_: &mut HashSet<(u64, u64)>, _: &Metadata) -> bool { true } + // Set up thread pool for our various tasks. Number of CPUs + 1 has been // found to be a good pool size, likely since the walker thread should be @@ -303,11 +327,23 @@ fn main() { Ok(meta) => { let fsize = meta.len(); if fsize >= minsize && fsize <= maxsize { + + #[cfg(any(use_ino, use_ino_placeholder))] if check_inode(&mut inodes, &meta) { if !hidden_excluded(&dir_entry) && matches_pattern(&dir_entry) { process(fsize, dir_entry); } } + + + #[cfg(use_windows_file_numbers)] + match check_inode(&mut inodes, dir_entry.path()) { + Some(true) => if !hidden_excluded(&dir_entry) && matches_pattern(&dir_entry) { + process(fsize, dir_entry); + }, + Some(false) => (), + None => eprintln!("Can't determine file or device number"), + } } } Err(e) => {