From 8a152d41189dd7a3c52d398a14e51627c3eb39b4 Mon Sep 17 00:00:00 2001 From: Lynne Date: Wed, 3 Mar 2021 01:12:29 +1000 Subject: [PATCH] new option for scanning extensionless files, nicer #[cfg]s, -s no longer skips hidden root dir... --- Cargo.lock | 2 +- Cargo.toml | 4 ++-- src/main.rs | 30 +++++++++++++++++++----------- src/mime_db.rs | 2 +- src/parameters.rs | 16 ++++++++++++++++ src/tests/mod.rs | 11 ++++++++--- 6 files changed, 47 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f0e1f1..c05cf51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,7 +168,7 @@ checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193" [[package]] name = "fif" -version = "0.2.7" +version = "0.2.8" dependencies = [ "cached", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index be45743..2eec540 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "fif" description = "A command-line tool for detecting and optionally correcting files with incorrect extensions." -version = "0.2.7" +version = "0.2.8" authors = ["Lynnesbian "] edition = "2018" license = "GPL-3.0-or-later" @@ -35,7 +35,7 @@ rayon = { version = "1.5.0", optional = true } exitcode = "1.1.2" cfg-if = "1.0.0" -[target.'cfg(any(unix, target_os="redox"))'.dependencies] +[target.'cfg(unix)'.dependencies] xdg-mime = "0.3" [patch.crates-io] diff --git a/src/main.rs b/src/main.rs index 483b509..c458a59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ use walkdir::{DirEntry, WalkDir}; use crate::findings::Findings; use crate::formats::{Format, Script}; use crate::mime_db::MimeDb; -use crate::parameters::OutputFormat; +use crate::parameters::{OutputFormat, ScanOpts}; use crate::scan_error::ScanError; use env_logger::Env; use std::process::exit; @@ -46,7 +46,7 @@ mod scan_error; mod tests; cfg_if! { - if #[cfg(any(all(not(unix), not(feature = "xdg-mime-backend")), all(unix, feature = "infer-backend")))] { + if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] { /// A [OnceCell] holding an instance of [mime_db::MimeDb]. static MIMEDB: OnceCell = OnceCell::new(); /// The backend being used; either "Infer" or "XDG-Mime". @@ -80,7 +80,7 @@ fn main() { debug!("Checking files with extensions: {:?}", extensions); - let entries = scan_directory(&args.dirs, &extensions, args.scan_hidden); + let entries = scan_directory(&args.dirs, &extensions, &args.get_scan_opts()); if entries.is_none() { // no need to log anything for fatal errors - fif will already have printed something obvious like @@ -161,9 +161,15 @@ cfg_if! { } } -/// Returns `true` if a file matches the given criteria. -fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool { - if !scan_hidden && is_hidden(entry) { +/// Returns `true` if a file matches the given criteria. This means checking whether the file's extension appears in +/// `exts`, potentially skipping over hidden files, and so on. +fn wanted_file(entry: &DirEntry, exts: &[&str], scan_opts: &ScanOpts) -> bool { + if entry.depth() == 0 { + // the root directory should always be scanned. + return true; + } + + if !scan_opts.hidden && is_hidden(entry) { // skip hidden files and directories. this check is performed first because it's very lightweight. return false; } @@ -175,9 +181,10 @@ fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool { let ext = extension_from_path(entry.path()); - if ext.is_none() { + if ext.is_none() && !scan_opts.extensionless { + // don't scan files without extensions. return false; - } // don't scan files without extensions. TODO - this should be configurable + } exts.contains(&ext.unwrap().to_lowercase().as_str()) } @@ -186,6 +193,7 @@ fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool { /// /// The extension is currently [converted to a lossy string](std::ffi::OsStr::to_string_lossy), although it will /// (eventually) in future return an OsStr instead. +// TODO: ↑ fn extension_from_path(path: &Path) -> Option { path.extension(). // Get the path's extension map(|e| String::from(e.to_string_lossy())) // Convert from OsStr to String @@ -258,11 +266,11 @@ fn scan_from_walkdir(entries: &[DirEntry]) -> Vec> { /// Scans a given directory with [WalkDir], filters with [wanted_file], checks for errors, and returns a vector of /// [DirEntry]s. -fn scan_directory(dirs: &PathBuf, exts: &Vec<&str>, scan_hidden: bool) -> Option> { +fn scan_directory(dirs: &PathBuf, exts: &Vec<&str>, scan_opts: &ScanOpts) -> Option> { let stepper = WalkDir::new(dirs).into_iter(); let mut probably_fatal_error = false; let entries: Vec = stepper - .filter_entry(|e| wanted_file(scan_hidden, exts, e)) // filter out unwanted files + .filter_entry(|e| wanted_file(e, exts, scan_opts)) // filter out unwanted files .filter_map(|e| { if let Err(err) = &e { debug!("uh oh spaghettio!! {:#?}", e); @@ -299,7 +307,7 @@ fn scan_directory(dirs: &PathBuf, exts: &Vec<&str>, scan_hidden: bool) -> Option /// Initialises [MIMEDB] with a value dependent on the current backend. fn init_db() { cfg_if! { - if #[cfg(any(all(not(unix), not(feature = "xdg-mime-backend")), all(unix, feature = "infer-backend")))] { + if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] { MIMEDB .set(mime_db::InferDb::init()) .or(Err("Failed to initialise Infer backend!")) diff --git a/src/mime_db.rs b/src/mime_db.rs index 43bb6db..a0f532e 100644 --- a/src/mime_db.rs +++ b/src/mime_db.rs @@ -9,7 +9,7 @@ pub trait MimeDb { } cfg_if! { - if #[cfg(any(all(not(target_os = "linux"), not(feature = "xdg-mime-backend")), all(target_os = "linux", feature = "infer-backend")))] { + if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] { use std::str::FromStr; pub struct InferDb { diff --git a/src/parameters.rs b/src/parameters.rs index 12779d3..a095954 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -47,6 +47,10 @@ pub struct Parameters { #[clap(short, long)] pub scan_hidden: bool, + /// Scan files without extensions + #[clap(short = 'S', long)] + pub scan_extensionless: bool, + /// Output format to use #[clap(short, long, default_value = "script", arg_enum)] pub output_format: OutputFormat, @@ -57,6 +61,14 @@ pub struct Parameters { pub dirs: PathBuf, } +/// Further options relating to scanning. +pub struct ScanOpts { + /// Whether hidden files and directories should be scanned. + pub hidden: bool, + /// Whether files without extensions should be scanned. + pub extensionless: bool +} + impl Parameters { pub fn extensions(&self) -> Vec<&str> { if let Some(exts) = &self.exts { @@ -70,4 +82,8 @@ impl Parameters { unreachable!() } } + + pub fn get_scan_opts(&self) -> ScanOpts { + ScanOpts { hidden: self.scan_hidden, extensionless: self.scan_extensionless } + } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 609208f..60e63d8 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -2,7 +2,7 @@ use crate::inspectors::mime_extension_lookup; use crate::mime_db::*; use crate::{extension_from_path, init_db, scan_directory, scan_from_walkdir}; -use crate::parameters::Parameters; +use crate::parameters::{Parameters, ScanOpts}; use cfg_if::cfg_if; use mime_guess::mime::{APPLICATION_OCTET_STREAM, APPLICATION_PDF, IMAGE_JPEG, IMAGE_PNG}; use mime_guess::Mime; @@ -16,7 +16,7 @@ const PDF_BYTES: &[u8] = b"%PDF-"; const ZIP_BYTES: &[u8] = b"PK\x03\x04"; cfg_if! { - if #[cfg(any(all(not(target_os = "linux"), not(feature = "xdg-mime-backend")), all(target_os = "linux", feature = "infer-backend")))] { + if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] { fn get_mime_db() -> InferDb { InferDb::init() } @@ -95,10 +95,15 @@ fn simple_directory() { drop(file); } + let scan_opts = ScanOpts{ + hidden: true, + extensionless: false + }; + let entries = scan_directory( &dir.path().to_path_buf(), &vec!["jpg", "jpeg", "png", "pdf", "zip"], - true, + &scan_opts, ) .expect("Directory scan failed.");