* fix(platform): a saved file keeps its hidden and system attributes on Windows
Every save writes a staging file and renames it over the target, and on
Windows the renamed file keeps the staging file's attributes, not the
replaced file's: a hidden or system file came out of a save visible. The
staging file is now created with the replaced file's FILE_ATTRIBUTE_HIDDEN
and FILE_ATTRIBUTE_SYSTEM (std's OpenOptionsExt::attributes, no unsafe), so
it is hidden from its first moment when the target is, and plain when the
target is plain. A new file gets neither. Read-only targets are still
refused before staging; the archive bit is left to the system.
The test saves plain, hidden, system and hidden+system files through both
staging-name forms and checks the attributes on the staging file before the
flush and on the saved file after; it fails with the fix reverted.
Refs #4593
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(platform): on Windows a saved link takes the link's attributes, not its target's
A save replaces a symbolic link with a regular file, so the attributes it
keeps are the link's own. `metadata` followed the link, and a plain link to
a hidden file came out of a save as a hidden file. Read them with
`symlink_metadata`, as the macOS attribute copy already does. Unix keeps
reading the mode through the link, as before.
The test skips where symbolic links can't be created (no Developer Mode or
administrator rights), as it does on the machine this was written on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up to #319, from review. create_staging, staging_suffixes and
STAGING_ATTEMPTS were copied in pdfcraft-automation and pdfcraft-ui-egui,
which are both L7 and can't depend on each other. They now live once in
the new pdfcraft-platform crate (L7, std only), which layers.rs already
reserved with both sideways edges.
A pure move: the body is unchanged apart from a StagingName parameter
that keeps each caller's existing file name (.{name}.{suffix}.pdfcraft-tmp
for automation, .{name}.pdfcraft-{suffix}.tmp for the desktop save). The
doc comment on staging_suffixes now says the suffix is SipHash keyed from
the OS random source: enough that a name can't be planted in advance, but
not a CSPRNG.
New tests in the platform crate pin both name forms, the 128-byte stem
cut, the 16-name limit and refusal when no suffix is left. The callers'
planted-file, link, folder and failed-rename tests stay where they are.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>