Build and behave correctly on every release target
Split platform into a portable core (mod.rs) plus unix.rs and windows.rs. - Linux: statx through syscall(2) so static musl links (fstatat fallback on ENOSYS); virtual-fs detection compares f_type as u32. - macOS: Finder trash (~/.Trash or /Volumes/X/.Trashes/<uid>, "name N" collisions, EXDEV falls through to the next location) and `open -R` reveal; never headless. - FreeBSD/NetBSD: fstatat with birth time; trash and reveal unsupported, permanent delete still available on headless systems. - Windows: std read_dir and metadata, allocated size unknown, no inode identity, Recycle Bin via SHFileOperationW (FOF_ALLOWUNDO, all architectures), Explorer /select reveal, no permanent delete, '\\' separator with Windows glob semantics, abs paths via GetFullPathNameW, config in %AppData%. - Local time via a portable LocalTime helper (localtime_r tm_gmtoff on Unix, SystemTimeToTzSpecificLocalTime on Windows) replacing libc tm and mktime in the TUI, snapshot and filter code. - errno, stat field names and mode_t width handled per OS; Unix-only tests gated; clippy clean on all targets. Adds windows-sys =0.61.2 (Windows only; Win32_Foundation, Win32_System_Time, Win32_UI_Shell), already in the lockfile via crossterm.
This commit is contained in:
+10
-5
@@ -484,7 +484,8 @@ impl Controller {
|
||||
self.excludes.iter().any(|(is_path, p)| {
|
||||
if *is_path {
|
||||
path == p.as_slice()
|
||||
|| path.starts_with(p) && path.get(p.len()) == Some(&b'/')
|
||||
|| path.starts_with(p)
|
||||
&& path.get(p.len()).is_some_and(|&b| platform::is_sep(b))
|
||||
|| platform::glob_match(p, path)
|
||||
} else {
|
||||
platform::glob_match(p, name)
|
||||
@@ -662,7 +663,6 @@ fn err_msg(e: &io::Error) -> String {
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct TempDir(pub PathBuf);
|
||||
@@ -716,7 +716,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
pub fn run_scan(root: &Path, o: Options) -> Tree {
|
||||
let s = start(root.as_os_str().as_bytes(), o, Cancel::new()).unwrap();
|
||||
let s = start(root.as_os_str().as_encoded_bytes(), o, Cancel::new()).unwrap();
|
||||
s.done()
|
||||
.recv_timeout(std::time::Duration::from_secs(60))
|
||||
.expect_err("scan did not finish (deadlock?)");
|
||||
@@ -797,7 +797,7 @@ pub(crate) mod tests {
|
||||
mk_tree(&root.0, 8, 3, 2);
|
||||
let c = Cancel::new();
|
||||
let s = start(
|
||||
root.0.as_os_str().as_bytes(),
|
||||
root.0.as_os_str().as_encoded_bytes(),
|
||||
Options {
|
||||
workers: 2,
|
||||
job_buffer: 1,
|
||||
@@ -816,6 +816,7 @@ pub(crate) mod tests {
|
||||
assert!(t.stats.cancelled && t.stats.incomplete());
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn symlink_loops() {
|
||||
let root = TempDir::new("loop");
|
||||
@@ -845,6 +846,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn hardlinks_counted_once() {
|
||||
let root = TempDir::new("hl");
|
||||
@@ -863,6 +865,7 @@ pub(crate) mod tests {
|
||||
assert!(t.node(0).tot_size < 200000);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn permission_errors_surface() {
|
||||
if unsafe { libc::geteuid() } == 0 {
|
||||
@@ -873,7 +876,7 @@ pub(crate) mod tests {
|
||||
let locked = root.0.join("locked");
|
||||
std::fs::create_dir(&locked).unwrap();
|
||||
std::fs::write(locked.join("f"), b"x").unwrap();
|
||||
std::fs::set_permissions(&locked, std::fs::Permissions::from_mode(0)).unwrap();
|
||||
std::fs::set_permissions(&locked, std::fs::Permissions::from_mode(0o000)).unwrap();
|
||||
let t = run_scan(
|
||||
&root.0,
|
||||
Options {
|
||||
@@ -907,8 +910,10 @@ pub(crate) mod tests {
|
||||
assert_eq!((t.stats.excluded, t.node(0).files), (2, 1));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn hostile_names_preserved() {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
let root = TempDir::new("names");
|
||||
let names: [&[u8]; 6] = [
|
||||
"日本語.txt".as_bytes(),
|
||||
|
||||
Reference in New Issue
Block a user