]> git.proxmox.com Git - rustc.git/blame - src/tools/tidy/src/bins.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / src / tools / tidy / src / bins.rs
CommitLineData
a7813a04
XL
1//! Tidy check to ensure that there are no binaries checked into the source tree
2//! by accident.
3//!
4//! In the past we've accidentally checked in test binaries and such which add a
9fa01778
XL
5//! huge amount of bloat to the Git history, so it's good to just ensure we
6//! don't do that again.
a7813a04 7
cdc7bbd5 8pub use os_impl::*;
a7813a04 9
9fa01778 10// All files are executable on Windows, so just check on Unix.
a7813a04 11#[cfg(windows)]
cdc7bbd5
XL
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}
a7813a04
XL
21
22#[cfg(unix)]
cdc7bbd5 23mod os_impl {
a7813a04
XL
24 use std::fs;
25 use std::os::unix::prelude::*;
cdc7bbd5 26 use std::path::Path;
dfeec247 27 use std::process::{Command, Stdio};
a7813a04 28
cdc7bbd5
XL
29 enum FilesystemSupport {
30 Supported,
31 Unsupported,
32 ReadOnlyFs,
33 }
34
35 use FilesystemSupport::*;
36
29967ef6
XL
37 fn is_executable(path: &Path) -> std::io::Result<bool> {
38 Ok(path.metadata()?.mode() & 0o111 != 0)
39 }
40
cdc7bbd5
XL
41 pub fn check_filesystem_support(sources: &[&Path], output: &Path) -> bool {
42 // We want to avoid false positives on filesystems that do not support the
43 // executable bit. This occurs on some versions of Window's linux subsystem,
44 // for example.
45 //
46 // We try to create the temporary file first in the src directory, which is
47 // the preferred location as it's most likely to be on the same filesystem,
48 // and then in the output (`build`) directory if that fails. Sometimes we
49 // see the source directory mounted as read-only which means we can't
50 // readily create a file there to test.
51 //
52 // See #36706 and #74753 for context.
53
54 fn check_dir(dir: &Path) -> FilesystemSupport {
55 let path = dir.join("tidy-test-file");
56 match fs::File::create(&path) {
57 Ok(file) => {
58 let exec = is_executable(&path).unwrap_or(false);
59 std::mem::drop(file);
60 std::fs::remove_file(&path).expect("Deleted temp file");
61 // If the file is executable, then we assume that this
62 // filesystem does not track executability, so skip this check.
63 return if exec { Unsupported } else { Supported };
64 }
65 Err(e) => {
66 // If the directory is read-only or we otherwise don't have rights,
67 // just don't run this check.
68 //
69 // 30 is the "Read-only filesystem" code at least in one CI
70 // environment.
71 if e.raw_os_error() == Some(30) {
72 eprintln!("tidy: Skipping binary file check, read-only filesystem");
73 return ReadOnlyFs;
74 }
75
76 panic!("unable to create temporary file `{:?}`: {:?}", path, e);
77 }
78 };
29967ef6 79 }
29967ef6 80
cdc7bbd5
XL
81 for &source_dir in sources {
82 match check_dir(source_dir) {
83 Unsupported => return false,
84 ReadOnlyFs => {
85 return match check_dir(output) {
86 Supported => true,
87 _ => false,
88 };
89 }
90 _ => {}
91 }
9e0c209e 92 }
cdc7bbd5
XL
93
94 return true;
9e0c209e
SL
95 }
96
cdc7bbd5
XL
97 #[cfg(unix)]
98 pub fn check(path: &Path, bad: &mut bool) {
f2b60f7d
FG
99 use std::ffi::OsStr;
100
101 const ALLOWED: &[&str] = &["configure", "x"];
064997fb 102
cdc7bbd5
XL
103 crate::walk_no_read(
104 path,
064997fb
FG
105 &mut |path| {
106 crate::filter_dirs(path)
107 || path.ends_with("src/etc")
108 // This is a list of directories that we almost certainly
109 // don't need to walk. A future PR will likely want to
110 // remove these in favor of crate::walk_no_read using git
111 // ls-files to discover the paths we should check, which
112 // would naturally ignore all of these directories. It's
113 // also likely faster than walking the directory tree
114 // directly (since git is just reading from a couple files
115 // to produce the results).
116 || path.ends_with("target")
117 || path.ends_with("build")
118 || path.ends_with(".git")
119 },
cdc7bbd5
XL
120 &mut |entry| {
121 let file = entry.path();
f2b60f7d
FG
122 let extension = file.extension();
123 let scripts = ["py", "sh", "ps1"];
124 if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
cdc7bbd5
XL
125 return;
126 }
a7813a04 127
cdc7bbd5
XL
128 if t!(is_executable(&file), file) {
129 let rel_path = file.strip_prefix(path).unwrap();
130 let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
064997fb
FG
131
132 if ALLOWED.contains(&git_friendly_path.as_str()) {
133 return;
134 }
135
cdc7bbd5
XL
136 let output = Command::new("git")
137 .arg("ls-files")
138 .arg(&git_friendly_path)
139 .current_dir(path)
140 .stderr(Stdio::null())
141 .output()
142 .unwrap_or_else(|e| {
5e7ed085 143 panic!("could not run git ls-files: {e}");
cdc7bbd5
XL
144 });
145 let path_bytes = rel_path.as_os_str().as_bytes();
146 if output.status.success() && output.stdout.starts_with(path_bytes) {
147 tidy_error!(bad, "binary checked into source: {}", file.display());
148 }
dfeec247 149 }
cdc7bbd5
XL
150 },
151 )
152 }
a7813a04 153}