1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
use finder::Checker; #[cfg(unix)] use libc; #[cfg(unix)] use std::ffi::CString; use std::fs; #[cfg(unix)] use std::os::unix::ffi::OsStrExt; use std::path::Path; pub struct ExecutableChecker; impl ExecutableChecker { pub fn new() -> ExecutableChecker { ExecutableChecker } } impl Checker for ExecutableChecker { #[cfg(unix)] fn is_valid(&self, path: &Path) -> bool { CString::new(path.as_os_str().as_bytes()) .and_then(|c| Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 })) .unwrap_or(false) } #[cfg(windows)] fn is_valid(&self, _path: &Path) -> bool { true } } pub struct ExistedChecker; impl ExistedChecker { pub fn new() -> ExistedChecker { ExistedChecker } } impl Checker for ExistedChecker { #[cfg(target_os = "windows")] fn is_valid(&self, path: &Path) -> bool { fs::symlink_metadata(path) .map(|metadata| { let file_type = metadata.file_type(); file_type.is_file() || file_type.is_symlink() }) .unwrap_or(false) } #[cfg(not(target_os = "windows"))] fn is_valid(&self, path: &Path) -> bool { fs::metadata(path) .map(|metadata| metadata.is_file()) .unwrap_or(false) } } pub struct CompositeChecker { checkers: Vec<Box<dyn Checker>>, } impl CompositeChecker { pub fn new() -> CompositeChecker { CompositeChecker { checkers: Vec::new(), } } pub fn add_checker(mut self, checker: Box<dyn Checker>) -> CompositeChecker { self.checkers.push(checker); self } } impl Checker for CompositeChecker { fn is_valid(&self, path: &Path) -> bool { self.checkers.iter().all(|checker| checker.is_valid(path)) } }