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 => {
87 return match check_dir(output) {
88 Supported => true,
89 _ => false,
90 };
91 }
92 _ => {}
93 }
94 }
95
96 true
97 }
98
99 const RI_EXCLUSION_LIST: &[&str] = &[
102 "src/tools/rust-installer/test/image1/bin/program",
103 "src/tools/rust-installer/test/image1/bin/program2",
104 "src/tools/rust-installer/test/image1/bin/bad-bin",
105 "src/tools/rust-installer/test/image2/bin/oldprogram",
106 "src/tools/rust-installer/test/image3/bin/cargo",
107 ];
108
109 fn filter_rust_installer_no_so_bins(path: &Path) -> bool {
110 RI_EXCLUSION_LIST.iter().any(|p| path.ends_with(p))
111 }
112
113 #[cfg(unix)]
114 pub fn check(path: &Path, bad: &mut bool) {
115 use std::ffi::OsStr;
116
117 const ALLOWED: &[&str] = &["configure", "x"];
118
119 for p in RI_EXCLUSION_LIST {
120 if !path.join(Path::new(p)).exists() {
121 tidy_error!(bad, "rust-installer test bins missed: {p}");
122 }
123 }
124
125 walk_no_read(
128 &[path],
129 |path, _is_dir| {
130 filter_dirs(path)
131 || path.ends_with("src/etc")
132 || filter_rust_installer_no_so_bins(path)
133 },
134 &mut |entry| {
135 let file = entry.path();
136 let extension = file.extension();
137 let scripts = ["py", "sh", "ps1", "woff2"];
138 if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
139 return;
140 }
141
142 if t!(is_executable(&file), file) {
143 let rel_path = file.strip_prefix(path).unwrap();
144 let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
145
146 if ALLOWED.contains(&git_friendly_path.as_str()) {
147 return;
148 }
149
150 let output = Command::new("git")
151 .arg("ls-files")
152 .arg(&git_friendly_path)
153 .current_dir(path)
154 .stderr(Stdio::null())
155 .output()
156 .unwrap_or_else(|e| {
157 panic!("could not run git ls-files: {e}");
158 });
159 let path_bytes = rel_path.as_os_str().as_bytes();
160 if output.status.success() && output.stdout.starts_with(path_bytes) {
161 tidy_error!(bad, "binary checked into source: {}", file.display());
162 }
163 }
164 },
165 )
166 }
167}