mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-15 14:43:28 +00:00
cap-std's Windows `rename`, `remove_file` and `create_dir` are path-based: they append the request to the handle's own path, read back without its `\\?\` prefix, and call `std::fs` (sunfishcode/cap-std#348). Below a drive root that still resolves; below a UNC root (`\\wsl.localhost\...`, any network share) it becomes the relative `UNC\wsl.localhost\...` and fails with ERROR_PATH_NOT_FOUND. `AuthorizedWorkspace::write` then left only its `.pcsave.tmp` behind, `export_sequence` could not create a new directory, and `ExportSequence::cleanup` could not remove its own frames. Opening files and directories and `stat` are handle-relative and work below any root, so everything is built on them. Files are removed through the held directory handle (`remove_file_in`: `Dir::remove_file`, then on the UNC `NotFound` an open relative to the same handle with FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_OPEN_REPARSE_POINT). The two steps that have no handle-relative form, creating a directory and renaming the finished temporary file into place, run on the canonical root path (trusted launch configuration, never the request) below directories that were each verified a plain directory through the handle of their parent and are held open for the duration (`held_directory_chain`, `pinned_directory_chain`). cap-std opens directories without FILE_SHARE_DELETE, so a held ancestor cannot be renamed away or replaced by a link while the ambient step runs. The rename is therefore the same temp-file + rename replace as on every other root: a failed save keeps the original, and no temporary file is stranded. Drive roots and Unix are unchanged. The regression tests use the temp drive's administrative share (`\\localhost\C$\...`) and skip on a runner that does not expose it; the pinned-ancestor test shows a held chain refusing the swap with ERROR_SHARING_VIOLATION. The security model notes document the two ambient operations. Fixes #10317 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>