Files
deepseek-harness/docs/rfc/implemented/bug-fix/2026-07-19-windows-atomic-write-dacl-preservation.md
Tianyi Cui 2b673bd68d fix(fs): preserve Windows DACLs across atomic replacement
Copy an existing target's DACL onto the empty staging file before any content is written, then publish with ReplaceFileW so Windows replacement keeps the target security descriptor instead of inheriting the broader parent policy.

Keep new-file inheritance and POSIX mode behavior unchanged, retain the already-protected temp when a concurrently removed target requires rename fallback, and translate native errors into Node-style codes for the filesystem error boundary.

Add host-independent Win32 binding coverage, native Windows descriptor assertions, package documentation, and a bilingual implemented RFC that supersedes the earlier inheritance-only replacement claim.
2026-07-19 12:38:18 +08:00

2.2 KiB

RFC: Preserve Windows DACLs during atomic file replacement

Status: implemented

English | 中文

Problem

On Windows, creating the staging directory and temp file under the target's parent and relying only on inherited DACLs is sufficient for a new file, but not for replacing an existing file whose explicit or protected DACL is narrower than its parent: content is written under the broader parent DACL, and rename carries that staging descriptor onto the replacement.

Decision

dsh-fs-local reads an existing target's DACL with GetFileSecurityW, applies it to the empty temp file with inheritance protected before writing content, and publishes the closed temp with ReplaceFileW. The protected staging descriptor prevents the temp directory's inherited entries from broadening access; ReplaceFileW preserves the original target security descriptor and other replacement metadata. New files have no prior descriptor to preserve and continue to inherit the destination directory's DACL.

Native Windows coverage protects a target DACL, inspects the written staging file, and compares the final replacement descriptor. Host-independent binding tests cover Win32 error translation and every native call boundary.

Alternatives considered

Rely on directory inheritance for replacements. Rejected because a target may carry a narrower explicit or protected DACL than its parent, so inheritance neither protects staged content nor preserves the target access policy.

Use ReplaceFileW without protecting the temp. Rejected because it repairs the final descriptor only after the content has already been written under the staging file's inherited DACL.

Install an owner-only DACL for every write. Rejected because it would discard deliberate project sharing. Copying the target DACL preserves the deployment's existing access policy instead of inventing one.

Consequences

Replacing a Windows file now requires permission to read the target DACL and set the temp DACL; failure is loud before content is written. The package carries Koffi for the narrow Win32 calls, loaded only on Windows replacement paths. New-file behavior remains directory-inherited, and POSIX mode behavior is unchanged.