Compare commits

...
Author SHA1 Message Date
Dylan M. Taylor d593b28bff Automation roots: compare canonical components exactly 2026-11-04 04:35:53 +00:00
+7 -18
View File
@@ -10,7 +10,8 @@
//! folder, the rest of the path being plain names (`..` below a missing folder is refused, and so
//! is a link that leads nowhere).
//! - The result must lie inside one of the roots of its kind, compared by whole components
//! (`/work2` isn't inside `/work`), without regard to case on Windows.
//! (`/work2` isn't inside `/work`), by the case the disk stores (links are resolved first, so a
//! differently cased spelling of a root still lands inside it).
//! - Read and write access are separate: a root given alone grants only its own kind of access.
//!
//! Roots are in force on a thread inside [`confine`], and in the whole process after
@@ -266,24 +267,12 @@ fn resolve(path: &Path) -> Result<PathBuf, String> {
}
}
/// Is `path` (resolved) `root` or inside it, component by component (without regard to case on
/// Windows, whose file systems ignore it)?
/// Is `path` (resolved) `root` or inside it, component by component? Both come from
/// `canonicalize`, which gives the name's case as the disk stores it, so equal means the same
/// folder; folding case would equate two folders on a case-sensitive Windows directory.
fn inside(path: &Path, root: &Path) -> bool {
let mut path = path.components();
root.components().all(|r| path.next().is_some_and(|p| same_component(p, r)))
}
fn same_component(a: Component, b: Component) -> bool {
if a == b {
return true;
}
if !cfg!(windows) {
return false;
}
match (a.as_os_str().to_str(), b.as_os_str().to_str()) {
(Some(a), Some(b)) => a.to_lowercase() == b.to_lowercase(),
_ => false,
}
root.components().all(|r| path.next().is_some_and(|p| p == r))
}
/// A Windows device name (`CON`, `NUL`, `COM1`… also with an extension), which names no file.
@@ -476,7 +465,7 @@ mod tests {
#[cfg(windows)]
#[test]
fn windows_ignores_case_and_refuses_devices() {
fn windows_resolves_case_and_refuses_devices() {
let (base, roots) = folders("case");
let upper = s(base.join("IN/a.scraft"));
assert_eq!(roots.check(&upper, Access::Read), Ok(()), "{upper}");