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