1 | use crate::finder::Checker;
|
2 | use std::fs;
|
3 | use std::path::Path;
|
4 |
|
5 | pub struct ExecutableChecker;
|
6 |
|
7 | impl ExecutableChecker {
|
8 | pub fn new() -> ExecutableChecker {
|
9 | ExecutableChecker
|
10 | }
|
11 | }
|
12 |
|
13 | impl Checker for ExecutableChecker {
|
14 | #[cfg (any(unix, target_os = "wasi" ))]
|
15 | fn is_valid(&self, path: &Path) -> bool {
|
16 | use rustix::fs as rfs;
|
17 | rfs::access(path, access:rfs::Access::EXEC_OK).is_ok()
|
18 | }
|
19 |
|
20 | #[cfg (windows)]
|
21 | fn is_valid(&self, _path: &Path) -> bool {
|
22 | true
|
23 | }
|
24 | }
|
25 |
|
26 | pub struct ExistedChecker;
|
27 |
|
28 | impl ExistedChecker {
|
29 | pub fn new() -> ExistedChecker {
|
30 | ExistedChecker
|
31 | }
|
32 | }
|
33 |
|
34 | impl Checker for ExistedChecker {
|
35 | #[cfg (target_os = "windows" )]
|
36 | fn is_valid(&self, path: &Path) -> bool {
|
37 | fs::symlink_metadata(path)
|
38 | .map(|metadata| {
|
39 | let file_type = metadata.file_type();
|
40 | file_type.is_file() || file_type.is_symlink()
|
41 | })
|
42 | .unwrap_or(false)
|
43 | && (path.extension().is_some() || matches_arch(path))
|
44 | }
|
45 |
|
46 | #[cfg (not(target_os = "windows" ))]
|
47 | fn is_valid(&self, path: &Path) -> bool {
|
48 | fs::metadata(path)
|
49 | .map(|metadata| metadata.is_file())
|
50 | .unwrap_or(default:false)
|
51 | }
|
52 | }
|
53 |
|
54 | #[cfg (target_os = "windows" )]
|
55 | fn matches_arch(path: &Path) -> bool {
|
56 | use std::os::windows::prelude::OsStrExt;
|
57 |
|
58 | let os_str = path
|
59 | .as_os_str()
|
60 | .encode_wide()
|
61 | .chain(std::iter::once(0))
|
62 | .collect::<Vec<u16>>();
|
63 | let mut out = 0;
|
64 | let is_executable = unsafe {
|
65 | windows_sys::Win32::Storage::FileSystem::GetBinaryTypeW(os_str.as_ptr(), &mut out)
|
66 | };
|
67 | is_executable != 0
|
68 | }
|
69 |
|
70 | pub struct CompositeChecker {
|
71 | checkers: Vec<Box<dyn Checker>>,
|
72 | }
|
73 |
|
74 | impl CompositeChecker {
|
75 | pub fn new() -> CompositeChecker {
|
76 | CompositeChecker {
|
77 | checkers: Vec::new(),
|
78 | }
|
79 | }
|
80 |
|
81 | pub fn add_checker(mut self, checker: Box<dyn Checker>) -> CompositeChecker {
|
82 | self.checkers.push(checker);
|
83 | self
|
84 | }
|
85 | }
|
86 |
|
87 | impl Checker for CompositeChecker {
|
88 | fn is_valid(&self, path: &Path) -> bool {
|
89 | self.checkers.iter().all(|checker: &Box| checker.is_valid(path))
|
90 | }
|
91 | }
|
92 | |