Originals: compare lengths before the Windows file identity

On ReFS two files can share the 64-bit file index that same_file
compares, so same_file now rejects files of different lengths before
it checks the volume serial number and file index.

The hard-link test skips with a recorded reason when the temporary
folder's volume has no hard links (FAT/exFAT, some shares), the same
errors publish_new treats as a volume without hard links.
This commit is contained in:
dotCooCoo
2026-10-25 22:32:37 -07:00
parent 7ebbb17a82
commit a97f19605c
3 changed files with 16 additions and 4 deletions
Generated
+1
View File
@@ -3218,6 +3218,7 @@ dependencies = [
"lightcraft-geom",
"lightcraft-meta",
"lightcraft-raw",
"lightcraft-testkit",
"log",
"proptest",
"same-file",
+1
View File
@@ -25,4 +25,5 @@ same-file = { workspace = true }
[dev-dependencies]
lightcraft-geom = { workspace = true }
lightcraft-testkit = { workspace = true }
proptest = { workspace = true }
+14 -4
View File
@@ -279,17 +279,18 @@ pub fn same_file(a: &Path, b: &Path) -> bool {
}
#[cfg(not(unix))]
{
if ma.len() != mb.len() {
return false;
}
// A hard link has its own path but shares the volume serial number and file index with
// its original. A volume that does not report them is compared by resolved path below.
// On ReFS two files can share the 64-bit file index, so the lengths are compared first.
#[cfg(windows)]
{
if ::same_file::is_same_file(a, b).unwrap_or(false) {
return true;
}
}
if ma.len() != mb.len() {
return false;
}
match (fs::canonicalize(a), fs::canonicalize(b)) {
(Ok(x), Ok(y)) => x == y || x.to_string_lossy().to_lowercase() == y.to_string_lossy().to_lowercase(),
_ => false,
@@ -413,7 +414,16 @@ mod tests {
let p = d.join("IMG_1.jpg");
fs::write(&p, b"original").unwrap();
let linked = d.join("linked.png");
fs::hard_link(&p, &linked).unwrap();
match fs::hard_link(&p, &linked) {
Ok(()) => {}
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => panic!("{}: {e}", linked.display()),
// no hard links on this volume (FAT/exFAT, some shares), as in `publish_new`
Err(e) => {
let _ = fs::remove_dir_all(&d);
lightcraft_testkit::skip!(System, "no hard links in {}: {e}", d.display());
return;
}
}
fs::write(d.join("copy.png"), b"original").unwrap();
assert!(same_file(&p, &linked), "a hard link is the same file");
assert!(same_file(&linked, &p));