Skip to content

core: the collision guard compares planned names byte for byte, and Windows filesystems are case-insensitive #91

Description

@otsobide

What happens

plan_names refuses two entries that would be written under one name, which is the guarantee that stops a rename from quietly destroying a file. The comparison is byte for byte.

Windows and macOS default filesystems are case-insensitive. Two entries whose planned names differ only in case are one file there, and the guard does not see it.

Reproduction

rewrite_entry("Report.txt") = "Report.txt"
rewrite_entry("report.txt") = "report.txt"
byte-equal? false            -> no collision reported

Both are then written, the second over the first, and the returned listing names two files where the disk holds one. The user is told both were extracted.

Where it bites hardest

A rename can create the collision, which is the case the guard exists for. WHAT?.txt answered with _ and what_.txt already in the archive collide on Windows and not in the comparison, so the very substitution the user was asked to supply is what loses their data.

Note on scope

Case folding is not a one-liner and should not pretend to be. Simple ASCII lowercasing covers the realistic archive and is honest about its limits; full Unicode case folding is a different conversation, and the Turkish dotless i is the usual reason. Worth deciding which one this guard promises, and saying so in the doc comment either way.

The rules are already data (NameRules::windows() versus ::unix()), so case-insensitivity belongs there as another field rather than as a #[cfg], which is what keeps it testable from a Mac.

Found while auditing the Windows CI failure that led to #88.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions