Skip to content

Add a physical-only engine for dehydrate backup deletion - #2149

Draft
Tyrie Vella (tyrielv) wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/backup-physical-delete
Draft

Tyrie Vella (tyrielv) wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/backup-physical-delete

Conversation

@tyrielv

@tyrielv Tyrie Vella (tyrielv) commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Problem and Context

After dehydrate moves placeholders into a backup, ordinary directory enumeration can still return projected-only names from the active provider. An attempt to open these names fails with Windows error 369. A normal recursive delete can stop before it deletes the physical backup.

This PR adds a shared Windows deletion engine without a product caller. It does not expose a cleanup command or change dehydrate, mount, or provider behavior. Callers remain responsible for user consent and eligibility after successful dehydrate.

Changes

  • Add WindowsDehydrateBackup to select one timestamped backup, including the legacy timestamp format and the worktree layout.
  • Pin the scope with native handles. Use handle-relative child opens and file identities to reject replaced entries. Reject scope aliases and unrelated reparse points.
  • Enumerate only on-disk entries with NtQueryDirectoryFileEx and SL_RETURN_ON_DISK_ENTRIES_ONLY. Delete entries by handle without file-data access or attribute changes.
  • Preserve raw UTF-16 filename code units, including unpaired surrogates that NTFS permits.
  • Use POSIX disposition to delete names even when compatible readers remain open. Retain entries with incompatible handles and return native errors.
  • Return cancellation, per-call progress, and bounded failure samples. Stop on callback errors and permit retry. Reject concurrent or reentrant scope operations.
  • Add white-box functional tests for scope boundaries, identity replacement, readonly files, raw UTF-16 names, long paths, and multi-buffer enumeration. These tests also exercise cancellation, retry, callback errors, compatible readers, directory-depth limits, and bounded failure samples.
  • Add a separate white-box provider fixture that reproduces projected-only traversal failures and deletes folder or full-root backups with the original provider active. The tests include cold and hydrated placeholders plus file and directory tombstones. Each progress callback reads a different live file.
  • Run deletion in a separate test process. Add a live-root control to verify notification handlers. The tests record notifications during backup deletion without claiming that every moved-backup operation can trigger them.
  • Add a cold-backup read control for folder backups. Full-root backups assert provider-unknown error 372 before deletion, so the engine must delete without data reads.
  • Isolate both fixtures under Tests.WhiteBox with the WhiteBox category and explicit product references. Document the white-box boundary separately from black-box functional tests.

Known gaps and deliberate decisions

  • Drive-root backup parents — The library rejects this layout. Other worktree backups use the directory that contains the worktree as the backup parent.
  • Backup selection — Callers must distinguish completed backups from timestamp-shaped worktree containers. Names and optional file identities do not establish consent or successful dehydrate.
  • Minimum Windows version — Runtime checks cover current x64 and ARM64 CI images. Minimum-version execution remains outstanding because current CI uses newer Windows versions.

Enumerate on-disk entries through native handles so projected-only names
cannot block backup deletion while the original provider remains active.
Pin the selected backup, reject replaced entries and unrelated reparse
points, and preserve explicit cancellation and retry results.

Preserve raw UTF-16 names and report progress after handles close.
Propagate callback errors, reject reentrant operations, and delete names
despite compatible readers.

Add separate white-box functional fixtures for filesystem and provider
integration. Run client operations in a separate test process and verify
notification delivery with a live-file control. Exercise cold reads,
file and directory tombstones, scope guards, and bounded failure samples.
Pin control-file handles before deletion to reject fixture aliases.
Document the white-box boundary and the backup-parent contract.

Keep the engine dormant until a separate product caller exposes cleanup.

Assisted-by: GPT-6.1 Sol
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv
Tyrie Vella (tyrielv) force-pushed the tyrielv/backup-physical-delete branch from 591f291 to e142c66 Compare October 30, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant