// fif - File Info Fixer // Copyright (C) 2021 Lynnesbian // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . mod parameters; mod inspectors; use std::path::{Path}; use walkdir::{WalkDir, DirEntry}; use smartstring::alias::String; use structopt::StructOpt; use log::{info}; // TODO: test if this actually works on a windows machine #[cfg(windows)] fn is_hidden(entry: &DirEntry) -> bool { use std::os::windows::prelude::*; use std::fs; fs::metadata(entry) // try to get metadata for file .map_or( false, // if getting metadata/attributes fails, assume it's not hidden |f| f.file_attributes() & 0x2 // flag for hidden - https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants ) } #[cfg(not(windows))] fn is_hidden(entry: &DirEntry) -> bool { entry.file_name().to_str().map_or(false, |f| f.starts_with('.') && f != ".") } fn wanted_file(args: ¶meters::Parameters, entry: &DirEntry) -> bool { if !args.scan_hidden && is_hidden(entry) { // skip hidden files and directories. this check is performed first because it's very lightweight. return false; } if entry.file_type().is_dir() { // always allow directories - there's no point doing file extension matching on something that isn't a file. return true; } let ext = Path::new(entry.file_name()) // create a Path from the entry... .extension() // get its extension... .map(|e| String::from(e.to_string_lossy())); // and convert it from an OsStr to a String. if ext.is_none() { return false } // don't scan files without extensions. TODO - this should be configurable if let Some(extensions) = &args.extensions { // if the user has specified a list of extensions to check against, make sure this file ends in one of them. // TODO - maybe use ascii_lowercase instead? return extensions.contains(&ext.unwrap().to_ascii_lowercase().into()) } true } fn main() { let args = parameters::Parameters::from_args(); // env_logger::init(); let db = xdg_mime::SharedMimeInfo::new(); println!("{:#?}", args); // println!("{:#?}", args.dirs); println!("=====\nIterating directory: {:?}\n=====", args.dirs); let stepper = WalkDir::new(&args.dirs).into_iter(); let entries: Vec = stepper .filter_entry(|e| wanted_file(&args, e)) // filter out unwanted files .filter_map(|e| e.ok()) // ignore anything that fails, e.g. files we don't have read access on .collect(); info!("Found {} items to check", entries.len()); // println!("{:#?}", entries); }