forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#134677 - tgross35:rollup-ozoeyop, r=tgross35
Rollup of 4 pull requests Successful merges: - rust-lang#129220 (Add platform docs for FreeBSD.) - rust-lang#134659 (test-infra: improve compiletest and run-make-support symlink handling) - rust-lang#134668 (Make sure we don't lose default struct value when formatting struct) - rust-lang#134672 (Revert stabilization of the `#[coverage(..)]` attribute) r? `@ghost` `@rustbot` modify labels: rollup
- Loading branch information
Showing
142 changed files
with
969 additions
and
433 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
//! Misc filesystem related helpers for use by bootstrap and tools. | ||
use std::fs::Metadata; | ||
use std::path::Path; | ||
use std::{fs, io}; | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
/// Helper to ignore [`std::io::ErrorKind::NotFound`], but still propagate other | ||
/// [`std::io::ErrorKind`]s. | ||
pub fn ignore_not_found<Op>(mut op: Op) -> io::Result<()> | ||
where | ||
Op: FnMut() -> io::Result<()>, | ||
{ | ||
match op() { | ||
Ok(()) => Ok(()), | ||
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()), | ||
Err(e) => Err(e), | ||
} | ||
} | ||
|
||
/// A wrapper around [`std::fs::remove_dir_all`] that can also be used on *non-directory entries*, | ||
/// including files and symbolic links. | ||
/// | ||
/// - This will produce an error if the target path is not found. | ||
/// - Like [`std::fs::remove_dir_all`], this helper does not traverse symbolic links, will remove | ||
/// symbolic link itself. | ||
/// - This helper is **not** robust against races on the underlying filesystem, behavior is | ||
/// unspecified if this helper is called concurrently. | ||
/// - This helper is not robust against TOCTOU problems. | ||
/// | ||
/// FIXME: this implementation is insufficiently robust to replace bootstrap's clean `rm_rf` | ||
/// implementation: | ||
/// | ||
/// - This implementation currently does not perform retries. | ||
#[track_caller] | ||
pub fn recursive_remove<P: AsRef<Path>>(path: P) -> io::Result<()> { | ||
let path = path.as_ref(); | ||
let metadata = fs::symlink_metadata(path)?; | ||
#[cfg(windows)] | ||
let is_dir_like = |meta: &fs::Metadata| { | ||
use std::os::windows::fs::FileTypeExt; | ||
meta.is_dir() || meta.file_type().is_symlink_dir() | ||
}; | ||
#[cfg(not(windows))] | ||
let is_dir_like = fs::Metadata::is_dir; | ||
|
||
if is_dir_like(&metadata) { | ||
fs::remove_dir_all(path) | ||
} else { | ||
try_remove_op_set_perms(fs::remove_file, path, metadata) | ||
} | ||
} | ||
|
||
fn try_remove_op_set_perms<'p, Op>(mut op: Op, path: &'p Path, metadata: Metadata) -> io::Result<()> | ||
where | ||
Op: FnMut(&'p Path) -> io::Result<()>, | ||
{ | ||
match op(path) { | ||
Ok(()) => Ok(()), | ||
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => { | ||
let mut perms = metadata.permissions(); | ||
perms.set_readonly(false); | ||
fs::set_permissions(path, perms)?; | ||
op(path) | ||
} | ||
Err(e) => Err(e), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
#![deny(unused_must_use)] | ||
|
||
use std::{env, fs, io}; | ||
|
||
use super::recursive_remove; | ||
|
||
mod recursive_remove_tests { | ||
use super::*; | ||
|
||
// Basic cases | ||
|
||
#[test] | ||
fn nonexistent_path() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_nonexistent_path"); | ||
assert!(fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)); | ||
assert!(recursive_remove(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)); | ||
} | ||
|
||
#[test] | ||
fn file() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_file"); | ||
fs::write(&path, b"").unwrap(); | ||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
assert!(recursive_remove(&path).is_ok()); | ||
assert!(fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)); | ||
} | ||
|
||
mod dir_tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn dir_empty() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_dir_tests_dir_empty"); | ||
fs::create_dir_all(&path).unwrap(); | ||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
assert!(recursive_remove(&path).is_ok()); | ||
assert!( | ||
fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
} | ||
|
||
#[test] | ||
fn dir_recursive() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_dir_tests_dir_recursive"); | ||
fs::create_dir_all(&path).unwrap(); | ||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
|
||
let file_a = path.join("a.txt"); | ||
fs::write(&file_a, b"").unwrap(); | ||
assert!(fs::symlink_metadata(&file_a).is_ok()); | ||
|
||
let dir_b = path.join("b"); | ||
fs::create_dir_all(&dir_b).unwrap(); | ||
assert!(fs::symlink_metadata(&dir_b).is_ok()); | ||
|
||
let file_c = dir_b.join("c.rs"); | ||
fs::write(&file_c, b"").unwrap(); | ||
assert!(fs::symlink_metadata(&file_c).is_ok()); | ||
|
||
assert!(recursive_remove(&path).is_ok()); | ||
|
||
assert!( | ||
fs::symlink_metadata(&file_a).is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
assert!( | ||
fs::symlink_metadata(&dir_b).is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
assert!( | ||
fs::symlink_metadata(&file_c).is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
} | ||
} | ||
|
||
/// Check that [`recursive_remove`] does not traverse symlinks and only removes symlinks | ||
/// themselves. | ||
/// | ||
/// Symlink-to-file versus symlink-to-dir is a distinction that's important on Windows, but not | ||
/// on Unix. | ||
mod symlink_tests { | ||
use super::*; | ||
|
||
#[cfg(unix)] | ||
#[test] | ||
fn unix_symlink() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_unix_symlink"); | ||
let symlink_path = | ||
tmpdir.join("__INTERNAL_BOOTSTRAP__symlink_tests_unix_symlink_symlink"); | ||
fs::write(&path, b"").unwrap(); | ||
|
||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
assert!( | ||
fs::symlink_metadata(&symlink_path) | ||
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
|
||
std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); | ||
|
||
assert!(recursive_remove(&symlink_path).is_ok()); | ||
|
||
// Check that the symlink got removed... | ||
assert!( | ||
fs::symlink_metadata(&symlink_path) | ||
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
// ... but pointed-to file still exists. | ||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
|
||
fs::remove_file(&path).unwrap(); | ||
} | ||
|
||
#[cfg(windows)] | ||
#[test] | ||
fn windows_symlink_to_file() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_windows_symlink_to_file"); | ||
let symlink_path = tmpdir | ||
.join("__INTERNAL_BOOTSTRAP_SYMLINK_symlink_tests_windows_symlink_to_file_symlink"); | ||
fs::write(&path, b"").unwrap(); | ||
|
||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
assert!( | ||
fs::symlink_metadata(&symlink_path) | ||
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
|
||
std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap(); | ||
|
||
assert!(recursive_remove(&symlink_path).is_ok()); | ||
|
||
// Check that the symlink-to-file got removed... | ||
assert!( | ||
fs::symlink_metadata(&symlink_path) | ||
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
// ... but pointed-to file still exists. | ||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
|
||
fs::remove_file(&path).unwrap(); | ||
} | ||
|
||
#[cfg(windows)] | ||
#[test] | ||
fn windows_symlink_to_dir() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_windows_symlink_to_dir"); | ||
let symlink_path = | ||
tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_windows_symlink_to_dir_symlink"); | ||
fs::create_dir_all(&path).unwrap(); | ||
|
||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
assert!( | ||
fs::symlink_metadata(&symlink_path) | ||
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
|
||
std::os::windows::fs::symlink_dir(&path, &symlink_path).unwrap(); | ||
|
||
assert!(recursive_remove(&symlink_path).is_ok()); | ||
|
||
// Check that the symlink-to-dir got removed... | ||
assert!( | ||
fs::symlink_metadata(&symlink_path) | ||
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
// ... but pointed-to dir still exists. | ||
assert!(fs::symlink_metadata(&path).is_ok()); | ||
|
||
fs::remove_dir_all(&path).unwrap(); | ||
} | ||
} | ||
|
||
/// Read-only file and directories only need special handling on Windows. | ||
#[cfg(windows)] | ||
mod readonly_tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn overrides_readonly() { | ||
let tmpdir = env::temp_dir(); | ||
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_readonly_tests_overrides_readonly"); | ||
|
||
// In case of a previous failed test: | ||
if let Ok(mut perms) = fs::symlink_metadata(&path).map(|m| m.permissions()) { | ||
perms.set_readonly(false); | ||
fs::set_permissions(&path, perms).unwrap(); | ||
fs::remove_file(&path).unwrap(); | ||
} | ||
|
||
fs::write(&path, b"").unwrap(); | ||
|
||
let mut perms = fs::symlink_metadata(&path).unwrap().permissions(); | ||
perms.set_readonly(true); | ||
fs::set_permissions(&path, perms).unwrap(); | ||
|
||
// Check that file exists but is read-only, and that normal `std::fs::remove_file` fails | ||
// to delete the file. | ||
assert!(fs::symlink_metadata(&path).is_ok_and(|m| m.permissions().readonly())); | ||
assert!( | ||
fs::remove_file(&path).is_err_and(|e| e.kind() == io::ErrorKind::PermissionDenied) | ||
); | ||
|
||
assert!(recursive_remove(&path).is_ok()); | ||
|
||
assert!( | ||
fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound) | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
pub mod ci; | ||
pub mod drop_bomb; | ||
pub mod fs; | ||
pub mod git; | ||
pub mod metrics; | ||
pub mod stage0_parser; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.