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