docs(fs): explain guarded cleanup invariants

This commit is contained in:
Peter Steinberger 2026-05-06 22:35:26 +01:00
parent d27434b50c
commit feb21f0be6
No known key found for this signature in database
4 changed files with 8 additions and 1 deletions

View File

@ -32,6 +32,9 @@ export async function withAsyncDirectoryGuards<T>(
} catch (error) {
if (options.onPostGuardFailure) {
try {
// The mutation may have returned an owned resource before the post-guard
// check detected a swapped directory. Give callers one chance to close
// handles without letting cleanup hide the boundary failure.
await options.onPostGuardFailure(result, error);
} catch {
// Preserve the boundary failure. Cleanup is best-effort.

View File

@ -217,6 +217,8 @@ async function runPinnedWriteFallback(params: {
),
{
onPostGuardFailure: async (openedHandle) => {
// The parent failed verification, so targetPath may now resolve
// somewhere else. Close the fd, but do not clean up by path.
await openedHandle.close().catch(() => undefined);
},
},

View File

@ -1627,7 +1627,7 @@ async function writeMissingFileFallback(
},
{
onPostGuardFailure: async ({ handle }) => {
created = false;
created = false; // Parent is untrusted now; skip outer path cleanup by name.
await handle.close().catch(() => undefined);
},
},

View File

@ -30,6 +30,8 @@ export function assertSafePathSegment(
segment: string,
options: SafePathSegmentOptions = {},
): string {
// Validate the exact value callers will later join into paths; trimming here
// would let whitespace-padded ids pass and then be used verbatim.
if (!isSafePathSegment(segment, options)) {
throw new FsSafeError(
"invalid-path",