1pub use os_impl::*;
9
10#[cfg(windows)]
12mod os_impl {
13 use std::path::Path;
14
15 use crate::diagnostics::DiagCtx;
16
17 pub fn check_filesystem_support(_sources: &[&Path], _output: &Path) -> bool {
18 return false;
19 }
20
21 pub fn check(_path: &Path, _diag_ctx: DiagCtx) {}
22}
23
24#[cfg(unix)]
25mod os_impl {
26 use std::fs;
27 use std::os::unix::prelude::*;
28 use std::path::Path;
29 use std::process::{Command, Stdio};
30
31 use crate::walk::{filter_dirs, walk_no_read};
32
33 enum FilesystemSupport {
34 Supported,
35 Unsupported,
36 ReadOnlyFs,
37 }
38
39 use FilesystemSupport::*;
40
41 use crate::diagnostics::DiagCtx;
42
43 fn is_executable(path: &Path) -> std::io::Result<bool> {
44 Ok(path.metadata()?.mode() & 0o111 != 0)
45 }
46
47 pub fn check_filesystem_support(sources: &[&Path], output: &Path) -> bool {
48 fn check_dir(dir: &Path) -> FilesystemSupport {
61 let path = dir.join("tidy-test-file");
62 match fs::File::create(&path) {
63 Ok(file) => {
64 let exec = is_executable(&path).unwrap_or(false);
65 drop(file);
66 fs::remove_file(&path).expect("Deleted temp file");
67 if exec { Unsupported } else { Supported }
70 }
71 Err(e) => {
72 if e.raw_os_error() == Some(30) {
78 eprintln!("tidy: Skipping binary file check, read-only filesystem");
79 return ReadOnlyFs;
80 }
81
82 panic!("unable to create temporary file `{path:?}`: {e:?}");
83 }
84 }
85 }
86
87 for &source_dir in sources {
88 match check_dir(source_dir) {
89 Unsupported => return false,
90 ReadOnlyFs => return matches!(check_dir(output), Supported),
91 _ => {}
92 }
93 }
94
95 true
96 }
97
98 const RI_EXCLUSION_LIST: &[&str] = &[
101 "src/tools/rust-installer/test/image1/bin/program",
102 "src/tools/rust-installer/test/image1/bin/program2",
103 "src/tools/rust-installer/test/image1/bin/bad-bin",
104 "src/tools/rust-installer/test/image2/bin/oldprogram",
105 "src/tools/rust-installer/test/image3/bin/cargo",
106 ];
107
108 fn filter_rust_installer_no_so_bins(path: &Path) -> bool {
109 RI_EXCLUSION_LIST.iter().any(|p| path.ends_with(p))
110 }
111
112 #[cfg(unix)]
113 pub fn check(path: &Path, diag_ctx: DiagCtx) {
114 let mut check = diag_ctx.start_check("bins");
115
116 use std::ffi::OsStr;
117
118 const ALLOWED: &[&str] = &["configure", "x"];
119
120 for p in RI_EXCLUSION_LIST {
121 if !path.join(Path::new(p)).exists() {
122 check.error(format!("rust-installer test bins missed: {p}"));
123 }
124 }
125
126 walk_no_read(
129 &[path],
130 |path, _is_dir| {
131 filter_dirs(path)
132 || path.ends_with("src/etc")
133 || filter_rust_installer_no_so_bins(path)
134 },
135 &mut |entry| {
136 let file = entry.path();
137 let extension = file.extension();
138 let scripts = ["py", "sh", "ps1", "woff2"];
139 if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
140 return;
141 }
142
143 if t!(is_executable(file), file) {
144 let rel_path = file.strip_prefix(path).unwrap();
145 let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
146
147 if ALLOWED.contains(&git_friendly_path.as_str()) {
148 return;
149 }
150
151 let output = Command::new("git")
152 .arg("ls-files")
153 .arg(&git_friendly_path)
154 .current_dir(path)
155 .stderr(Stdio::null())
156 .output()
157 .unwrap_or_else(|e| {
158 panic!("could not run git ls-files: {e}");
159 });
160 let path_bytes = rel_path.as_os_str().as_bytes();
161 if output.status.success() && output.stdout.starts_with(path_bytes) {
162 check.error(format!("binary checked into source: {}", file.display()));
163 }
164 }
165 },
166 )
167 }
168}