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