1 | use crate::finder::Checker;
|
2 | use crate::{NonFatalError, NonFatalErrorHandler};
|
3 | use std::fs;
|
4 | use std::path::Path;
|
5 |
|
6 | pub struct ExecutableChecker;
|
7 |
|
8 | impl ExecutableChecker {
|
9 | pub fn new() -> ExecutableChecker {
|
10 | ExecutableChecker
|
11 | }
|
12 | }
|
13 |
|
14 | impl Checker for ExecutableChecker {
|
15 | #[cfg (any(unix, target_os = "wasi" , target_os = "redox" ))]
|
16 | fn is_valid<F: NonFatalErrorHandler>(
|
17 | &self,
|
18 | path: &Path,
|
19 | nonfatal_error_handler: &mut F,
|
20 | ) -> bool {
|
21 | use std::io;
|
22 |
|
23 | use rustix::fs as rfs;
|
24 | let ret = rfs::access(path, rfs::Access::EXEC_OK)
|
25 | .map_err(|e| {
|
26 | nonfatal_error_handler.handle(NonFatalError::Io(io::Error::from_raw_os_error(
|
27 | e.raw_os_error(),
|
28 | )))
|
29 | })
|
30 | .is_ok();
|
31 | #[cfg (feature = "tracing" )]
|
32 | tracing::trace!("{} EXEC_OK = {ret}" , path.display());
|
33 | ret
|
34 | }
|
35 |
|
36 | #[cfg (windows)]
|
37 | fn is_valid<F: NonFatalErrorHandler>(
|
38 | &self,
|
39 | _path: &Path,
|
40 | _nonfatal_error_handler: &mut F,
|
41 | ) -> bool {
|
42 | true
|
43 | }
|
44 | }
|
45 |
|
46 | pub struct ExistedChecker;
|
47 |
|
48 | impl ExistedChecker {
|
49 | pub fn new() -> ExistedChecker {
|
50 | ExistedChecker
|
51 | }
|
52 | }
|
53 |
|
54 | impl Checker for ExistedChecker {
|
55 | #[cfg (target_os = "windows" )]
|
56 | fn is_valid<F: NonFatalErrorHandler>(
|
57 | &self,
|
58 | path: &Path,
|
59 | nonfatal_error_handler: &mut F,
|
60 | ) -> bool {
|
61 | let ret = fs::symlink_metadata(path)
|
62 | .map(|metadata| {
|
63 | let file_type = metadata.file_type();
|
64 | #[cfg (feature = "tracing" )]
|
65 | tracing::trace!(
|
66 | "{} is_file() = {}, is_symlink() = {}" ,
|
67 | path.display(),
|
68 | file_type.is_file(),
|
69 | file_type.is_symlink()
|
70 | );
|
71 | file_type.is_file() || file_type.is_symlink()
|
72 | })
|
73 | .map_err(|e| {
|
74 | nonfatal_error_handler.handle(NonFatalError::Io(e));
|
75 | })
|
76 | .unwrap_or(false)
|
77 | && (path.extension().is_some() || matches_arch(path, nonfatal_error_handler));
|
78 | #[cfg (feature = "tracing" )]
|
79 | tracing::trace!(
|
80 | "{} has_extension = {}, ExistedChecker::is_valid() = {ret}" ,
|
81 | path.display(),
|
82 | path.extension().is_some()
|
83 | );
|
84 | ret
|
85 | }
|
86 |
|
87 | #[cfg (not(target_os = "windows" ))]
|
88 | fn is_valid<F: NonFatalErrorHandler>(
|
89 | &self,
|
90 | path: &Path,
|
91 | nonfatal_error_handler: &mut F,
|
92 | ) -> bool {
|
93 | let ret = fs::metadata(path).map(|metadata| metadata.is_file());
|
94 | #[cfg (feature = "tracing" )]
|
95 | tracing::trace!("{} is_file() = {ret:?}" , path.display());
|
96 | match ret {
|
97 | Ok(ret) => ret,
|
98 | Err(e) => {
|
99 | nonfatal_error_handler.handle(NonFatalError::Io(e));
|
100 | false
|
101 | }
|
102 | }
|
103 | }
|
104 | }
|
105 |
|
106 | #[cfg (target_os = "windows" )]
|
107 | fn matches_arch<F: NonFatalErrorHandler>(path: &Path, nonfatal_error_handler: &mut F) -> bool {
|
108 | use std::io;
|
109 |
|
110 | let ret = winsafe::GetBinaryType(&path.display().to_string())
|
111 | .map_err(|e| {
|
112 | nonfatal_error_handler.handle(NonFatalError::Io(io::Error::from_raw_os_error(
|
113 | e.raw() as i32
|
114 | )))
|
115 | })
|
116 | .is_ok();
|
117 | #[cfg (feature = "tracing" )]
|
118 | tracing::trace!("{} matches_arch() = {ret}" , path.display());
|
119 | ret
|
120 | }
|
121 |
|
122 | pub struct CompositeChecker {
|
123 | existed_checker: ExistedChecker,
|
124 | executable_checker: ExecutableChecker,
|
125 | }
|
126 |
|
127 | impl CompositeChecker {
|
128 | pub fn new() -> CompositeChecker {
|
129 | CompositeChecker {
|
130 | executable_checker: ExecutableChecker::new(),
|
131 | existed_checker: ExistedChecker::new(),
|
132 | }
|
133 | }
|
134 | }
|
135 |
|
136 | impl Checker for CompositeChecker {
|
137 | fn is_valid<F: NonFatalErrorHandler>(
|
138 | &self,
|
139 | path: &Path,
|
140 | nonfatal_error_handler: &mut F,
|
141 | ) -> bool {
|
142 | self.existed_checker.is_valid(path, nonfatal_error_handler)
|
143 | && self
|
144 | .executable_checker
|
145 | .is_valid(path, nonfatal_error_handler)
|
146 | }
|
147 | }
|
148 | |