diff --git a/CHANGELOG.md b/CHANGELOG.md index c12d72f..dcb5f55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ Dates are given in YYYY-MM-DD format. ## v0.3 ### v0.3.4 (2021-mm-dd) +#### Features +- Added `-I`/`--ignore-unknown-exts` flag for ignoring files with unknown extensions - for example, if fif doesn't know + what a ".fake" file is, setting this flag will prevent it from renaming "photo.fake" to "photo.jpg". This is useful + for avoiding the case where fif incorrectly mislabels an obscure format it isn't aware of as something else. #### Other - Refactored `formats.rs` - More accurate dependency versions in `Cargo.toml` to ensure that the MSRV stays supported diff --git a/Cargo.lock b/Cargo.lock index 89e864d..677ad75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -544,9 +544,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] diff --git a/src/formats.rs b/src/formats.rs index 99b0e3e..96fdbf5 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -33,10 +33,6 @@ macro_rules! writables { $crate::formats::Writable::Newline }; - (@do Space) => { - $crate::formats::Writable::Space - }; - (@do $arg:expr) => { $arg.into() } @@ -57,7 +53,6 @@ type Entries<'a> = [Result>]; pub enum Writable<'a> { String(&'a str), Path(&'a Path), - Space, Newline, } @@ -80,7 +75,6 @@ fn smart_write(f: &mut W, writeables: &[Writable]) -> io::Result<()> { // ehhhh for writeable in writeables { match writeable { - Writable::Space => write!(f, " ")?, Writable::Newline => { cfg_if! { if #[cfg(windows)] { @@ -189,7 +183,7 @@ impl Format for Shell { impl FormatSteps for Shell { fn rename(&self, f: &mut W, from: &Path, to: &Path) -> io::Result<()> { - smart_write(f, writablesln!("mv -v -i -- ", from, Space, to)) + smart_write(f, writablesln!("mv -v -i -- ", from, "\t", to)) } fn no_known_extension(&self, f: &mut W, path: &Path) -> io::Result<()> { diff --git a/src/main.rs b/src/main.rs index c0076e2..77fc00f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ use crate::mime_db::MimeDb; use crate::parameters::{OutputFormat, ScanOpts}; use crate::utils::{clap_long_version, os_name}; use std::collections::BTreeSet; +use mime_guess::from_ext; mod findings; mod formats; @@ -217,6 +218,13 @@ fn wanted_file( let ext = ext.to_string_lossy().to_lowercase(); let ext = ext.as_str(); + if scan_opts.ignore_unknown_exts { + if from_ext(ext).is_empty() { + // unknown extension, skip. + return false; + } + } + if let Some(exts) = exts { // only scan if the file has one of the specified extensions. exts.contains(&ext) diff --git a/src/parameters.rs b/src/parameters.rs index 6bd9d0f..dcfb8b6 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -128,6 +128,11 @@ pub struct Parameters { /// The directory to process. #[clap(name = "DIR", default_value = ".", parse(from_os_str))] pub dir: PathBuf, + + /// Don't rename files with extensions unknown to fif. + /// For example, with this option, fif will not rename "image.unknown" to "image.jpg" + #[clap(short = 'I', long)] + pub ignore_unknown_exts: bool, } fn lowercase_exts(exts: &str) -> Result<(), String> { @@ -147,6 +152,8 @@ pub struct ScanOpts { pub extensionless: bool, /// Should symlinks be followed? pub follow_symlinks: bool, + /// Whether to rename files with unknown extensions. + pub ignore_unknown_exts: bool, } impl Parameters { @@ -214,6 +221,7 @@ impl Parameters { hidden: self.scan_hidden, extensionless: self.scan_extensionless, follow_symlinks: self.follow_symlinks, + ignore_unknown_exts: self.ignore_unknown_exts } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 72dfcda..f9fd871 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -100,6 +100,7 @@ fn simple_directory() { files.insert("test.pdf", PDF_BYTES); files.insert("test.zip", ZIP_BYTES); files.insert("wrong.jpg", PNG_BYTES); + files.insert("ignore.fake_ext", ZIP_BYTES); let dir = tempdir().expect("Failed to create temporary directory."); set_current_dir(dir.path()).expect("Failed to change directory."); @@ -117,11 +118,13 @@ fn simple_directory() { hidden: true, extensionless: false, follow_symlinks: false, + ignore_unknown_exts: true, }; let entries = scan_directory(dir.path(), None, None, &scan_opts).expect("Directory scan failed."); - assert_eq!(entries.len(), files.len()); + // there should be one file missing: "ignore.fake_ext" + assert_eq!(entries.len(), files.len() - 1); // initialise global mime DB - this is needed because `scan_from_walkdir` expects it to be present. crate::init_db(); @@ -209,6 +212,7 @@ fn argument_parsing() { hidden: false, extensionless: false, follow_symlinks: true, + ignore_unknown_exts: false, }, "ScanOpts are incorrect" ); @@ -329,7 +333,7 @@ fn identify_random_bytes() { for (mime, count) in &results { println!("{}:\t{} counts", mime, count); } - println!("No type found:\t{} counts", 500 - results.values().sum::()); + println!("No type found:\t{} counts", results.values().len() as i32 - results.values().sum::()); } #[test] @@ -363,7 +367,7 @@ fn outputs_move_commands() { // the output should contain a command like "mv -i misnamed_file.png misnamed_file.jpg" assert!( - contents.contains("misnamed_file.jpg"), + contents.contains("misnamed_file.jpg") && contents.contains("misnamed_file.png"), "{} output doesn't contain move command!\n===\n{}", format, contents @@ -433,9 +437,8 @@ fn writables_is_correct() { "henlo".into(), Path::new("henlo").into(), Writable::Newline, - Writable::Space ], - writables!["henlo", (Path::new("henlo")), Newline, Space] + writables!["henlo", (Path::new("henlo")), Newline] ); }