@openclaw/fs-safe 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/README.md +36 -7
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +2 -8
- package/dist/advanced.d.ts +3 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +3 -0
- package/dist/archive-deadline.d.ts.map +1 -1
- package/dist/archive-deadline.js +22 -23
- package/dist/archive-kind.d.ts +0 -1
- package/dist/archive-kind.d.ts.map +1 -1
- package/dist/archive-kind.js +5 -17
- package/dist/archive-merge.d.ts +1 -0
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +4 -4
- package/dist/archive-native.d.ts +1 -0
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +1 -0
- package/dist/archive-options.d.ts +2 -0
- package/dist/archive-options.d.ts.map +1 -1
- package/dist/archive-parser.wasm +0 -0
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +6 -7
- package/dist/archive-tar-stream.d.ts +3 -0
- package/dist/archive-tar-stream.d.ts.map +1 -1
- package/dist/archive-tar-stream.js +56 -37
- package/dist/archive-tar-wasm.d.ts +16 -4
- package/dist/archive-tar-wasm.d.ts.map +1 -1
- package/dist/archive-tar-wasm.js +134 -34
- package/dist/archive-zip-count.d.ts.map +1 -1
- package/dist/archive-zip-count.js +21 -1
- package/dist/archive-zip-directory.d.ts.map +1 -1
- package/dist/archive-zip-directory.js +23 -1
- package/dist/archive-zip-loader.d.ts +2 -0
- package/dist/archive-zip-loader.d.ts.map +1 -1
- package/dist/archive-zip-loader.js +7 -0
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +7 -2
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +14 -9
- package/dist/byte-view.d.ts +3 -0
- package/dist/byte-view.d.ts.map +1 -0
- package/dist/byte-view.js +13 -0
- package/dist/clone-metadata.d.ts +1 -0
- package/dist/clone-metadata.d.ts.map +1 -1
- package/dist/clone-metadata.js +6 -2
- package/dist/create-directory.d.ts +20 -0
- package/dist/create-directory.d.ts.map +1 -0
- package/dist/create-directory.js +130 -0
- package/dist/create-file-async.d.ts +7 -0
- package/dist/create-file-async.d.ts.map +1 -0
- package/dist/create-file-async.js +121 -0
- package/dist/create-file.d.ts +8 -0
- package/dist/create-file.d.ts.map +1 -0
- package/dist/create-file.js +190 -0
- package/dist/create-owned-file.d.ts +8 -0
- package/dist/create-owned-file.d.ts.map +1 -0
- package/dist/create-owned-file.js +16 -0
- package/dist/create.d.ts +4 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +2 -0
- package/dist/creation-darwin.d.ts +6 -0
- package/dist/creation-darwin.d.ts.map +1 -0
- package/dist/creation-darwin.js +70 -0
- package/dist/creation-file-state.d.ts +19 -0
- package/dist/creation-file-state.d.ts.map +1 -0
- package/dist/creation-file-state.js +118 -0
- package/dist/creation-path.d.ts +21 -0
- package/dist/creation-path.d.ts.map +1 -0
- package/dist/creation-path.js +71 -0
- package/dist/creation-permissions.d.ts +19 -0
- package/dist/creation-permissions.d.ts.map +1 -0
- package/dist/creation-permissions.js +125 -0
- package/dist/directory-durability.d.ts +7 -7
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-durability.js +22 -80
- package/dist/directory-guard.d.ts +3 -0
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-mode-node.d.ts +2 -0
- package/dist/directory-mode-node.d.ts.map +1 -1
- package/dist/directory-mode-node.js +8 -0
- package/dist/directory-receipt.d.ts +24 -0
- package/dist/directory-receipt.d.ts.map +1 -0
- package/dist/directory-receipt.js +123 -0
- package/dist/file-cleanup.d.ts +20 -0
- package/dist/file-cleanup.d.ts.map +1 -0
- package/dist/file-cleanup.js +81 -0
- package/dist/file-contents.d.ts +6 -0
- package/dist/file-contents.d.ts.map +1 -0
- package/dist/file-contents.js +40 -0
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +16 -4
- package/dist/file-lock-sync-root-acquire.d.ts.map +1 -1
- package/dist/file-lock-sync-root-acquire.js +3 -0
- package/dist/file-lock-sync-root-held.d.ts +1 -2
- package/dist/file-lock-sync-root-held.d.ts.map +1 -1
- package/dist/file-lock-sync-root-held.js +7 -5
- package/dist/file-lock-sync-stale-admission.d.ts.map +1 -1
- package/dist/file-lock-sync-stale-admission.js +3 -0
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +8 -11
- package/dist/file-observation.d.ts +1 -1
- package/dist/file-observation.d.ts.map +1 -1
- package/dist/file-store-boundary.d.ts +2 -6
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +3 -9
- package/dist/file-store-sync-write.d.ts.map +1 -1
- package/dist/file-store-sync-write.js +2 -5
- package/dist/file-store.js +3 -3
- package/dist/guarded-mkdir.d.ts +1 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +27 -19
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +2 -5
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +2 -6
- package/dist/json-durable-queue-paths.d.ts.map +1 -1
- package/dist/json-durable-queue-paths.js +2 -24
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +10 -9
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +32 -75
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +19 -21
- package/dist/move-path-cleanup.d.ts +5 -19
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +57 -21
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +63 -40
- package/dist/native-binding.d.ts +11 -1
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-fallback-warning.d.ts +4 -0
- package/dist/native-fallback-warning.d.ts.map +1 -0
- package/dist/native-fallback-warning.js +11 -0
- package/dist/native-operations.d.ts +0 -2
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +0 -24
- package/dist/native-parent-admission.d.ts +2 -0
- package/dist/native-parent-admission.d.ts.map +1 -1
- package/dist/native-parent-admission.js +3 -2
- package/dist/native-pinned-write-windows.d.ts +1 -1
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +173 -28
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +19 -3
- package/dist/native-policy-parent-windows.d.ts.map +1 -1
- package/dist/native-policy-parent-windows.js +15 -6
- package/dist/native-staged-file.d.ts +5 -3
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +90 -40
- package/dist/native.js +2 -2
- package/dist/opened-realpath.d.ts.map +1 -1
- package/dist/opened-realpath.js +11 -2
- package/dist/owner-dacl.d.ts.map +1 -1
- package/dist/owner-dacl.js +10 -4
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +2 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +3 -17
- package/dist/pinned-write-input.d.ts +4 -0
- package/dist/pinned-write-input.d.ts.map +1 -0
- package/dist/pinned-write-input.js +35 -0
- package/dist/pinned-write-mode.d.ts +5 -0
- package/dist/pinned-write-mode.d.ts.map +1 -0
- package/dist/pinned-write-mode.js +31 -0
- package/dist/pinned-write-staged.d.ts +6 -0
- package/dist/pinned-write-staged.d.ts.map +1 -0
- package/dist/pinned-write-staged.js +186 -0
- package/dist/pinned-write-types.d.ts +3 -0
- package/dist/pinned-write-types.d.ts.map +1 -1
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +41 -147
- package/dist/private-directory.d.ts.map +1 -1
- package/dist/private-directory.js +18 -4
- package/dist/private-producer-handoff-sync.d.ts +14 -0
- package/dist/private-producer-handoff-sync.d.ts.map +1 -0
- package/dist/private-producer-handoff-sync.js +114 -0
- package/dist/private-producer-handoff.d.ts +22 -4
- package/dist/private-producer-handoff.d.ts.map +1 -1
- package/dist/private-producer-handoff.js +140 -77
- package/dist/publish-copy-stage.d.ts +2 -1
- package/dist/publish-copy-stage.d.ts.map +1 -1
- package/dist/publish-copy-stage.js +16 -7
- package/dist/publish-file.d.ts +2 -2
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +58 -98
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +35 -44
- package/dist/replace-file-copy-fallback.d.ts.map +1 -1
- package/dist/replace-file-copy-fallback.js +28 -26
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +13 -22
- package/dist/replace-file-descriptor.d.ts.map +1 -1
- package/dist/replace-file-descriptor.js +10 -16
- package/dist/replace-file-temp-owner.d.ts +0 -7
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +9 -60
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +9 -13
- package/dist/root-create-input.d.ts +2 -1
- package/dist/root-create-input.d.ts.map +1 -1
- package/dist/root-create-input.js +13 -4
- package/dist/root-directory-creation.d.ts +3 -3
- package/dist/root-directory-creation.d.ts.map +1 -1
- package/dist/root-directory-creation.js +15 -3
- package/dist/root-directory-list.d.ts.map +1 -1
- package/dist/root-directory-list.js +20 -3
- package/dist/root-file-final-admission.d.ts +1 -1
- package/dist/root-file-final-admission.d.ts.map +1 -1
- package/dist/root-file-final-admission.js +5 -2
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +3 -2
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +78 -27
- package/dist/root-move-noreplace.d.ts +2 -0
- package/dist/root-move-noreplace.d.ts.map +1 -1
- package/dist/root-move-noreplace.js +22 -13
- package/dist/root-options.d.ts +12 -4
- package/dist/root-options.d.ts.map +1 -1
- package/dist/root-path-stat.d.ts.map +1 -1
- package/dist/root-path-stat.js +59 -7
- package/dist/root-read-admission.d.ts.map +1 -1
- package/dist/root-read-admission.js +7 -2
- package/dist/root-remove.d.ts.map +1 -1
- package/dist/root-remove.js +15 -1
- package/dist/root-write-publication.js +1 -1
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +1 -0
- package/dist/secure-file-windows.d.ts +6 -0
- package/dist/secure-file-windows.d.ts.map +1 -1
- package/dist/secure-file-windows.js +34 -117
- package/dist/secure-file.js +2 -2
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +4 -6
- package/dist/sidecar-lock-handle.d.ts +3 -0
- package/dist/sidecar-lock-handle.d.ts.map +1 -1
- package/dist/sidecar-lock-handle.js +6 -0
- package/dist/sidecar-lock-reclaim.d.ts +1 -1
- package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
- package/dist/sidecar-lock-reclaim.js +11 -8
- package/dist/sidecar-lock-root.d.ts.map +1 -1
- package/dist/sidecar-lock-root.js +2 -1
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +3 -5
- package/dist/staged-directory.d.ts +2 -2
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/staged-directory.js +6 -6
- package/dist/staged-file-settlement.d.ts +17 -0
- package/dist/staged-file-settlement.d.ts.map +1 -0
- package/dist/staged-file-settlement.js +57 -0
- package/dist/strict-file-identity.d.ts +1 -1
- package/dist/strict-file-identity.d.ts.map +1 -1
- package/dist/strict-file-identity.js +9 -9
- package/dist/symlink-parents.d.ts.map +1 -1
- package/dist/symlink-parents.js +2 -27
- package/dist/temp-workspace-owner.js +4 -4
- package/dist/unicode-path.d.ts.map +1 -1
- package/dist/unicode-path.js +3 -0
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +4 -2
- package/dist/windows-owner.d.ts.map +1 -1
- package/dist/windows-owner.js +2 -1
- package/dist/windows-security-bridge.cs +336 -0
- package/dist/windows-security-bridge.ps1 +15 -0
- package/dist/windows-security-command.d.ts +26 -0
- package/dist/windows-security-command.d.ts.map +1 -0
- package/dist/windows-security-command.js +363 -0
- package/dist/windows-security-facts.d.ts +6 -0
- package/dist/windows-security-facts.d.ts.map +1 -0
- package/dist/windows-security-facts.js +108 -0
- package/dist/write-file-handle.d.ts +7 -0
- package/dist/write-file-handle.d.ts.map +1 -1
- package/dist/write-file-handle.js +23 -0
- package/dist/write-open-flags.d.ts.map +1 -1
- package/dist/write-open-flags.js +1 -8
- package/dist/write-queue.d.ts.map +1 -1
- package/dist/write-queue.js +1 -4
- package/docs/advanced.md +71 -2
- package/docs/archive.md +102 -39
- package/docs/atomic.md +29 -5
- package/docs/config.md +6 -2
- package/docs/contributing.md +48 -4
- package/docs/copy.md +2 -0
- package/docs/creation.md +132 -0
- package/docs/durability.md +59 -0
- package/docs/file-contents.md +68 -0
- package/docs/install.md +31 -7
- package/docs/json.md +5 -4
- package/docs/local-roots.md +2 -0
- package/docs/migrating-to-0.5.md +15 -6
- package/docs/migrating-to-0.6.md +9 -4
- package/docs/mutation-policy-proof.md +5 -3
- package/docs/native-helper.md +22 -9
- package/docs/native.md +47 -15
- package/docs/path.md +4 -4
- package/docs/permissions.md +37 -14
- package/docs/public-api.md +5 -0
- package/docs/quickstart.md +1 -1
- package/docs/reading.md +2 -2
- package/docs/regular-file.md +3 -0
- package/docs/root.md +43 -0
- package/docs/secret-file.md +11 -2
- package/docs/secure-file.md +9 -4
- package/docs/sidecar-lock.md +14 -5
- package/docs/staged-file.md +9 -3
- package/docs/store.md +3 -1
- package/docs/temp.md +4 -1
- package/docs/types.md +18 -2
- package/docs/walk.md +7 -0
- package/docs/writing.md +80 -7
- package/package.json +18 -15
|
@@ -2,11 +2,20 @@ import { syncFileBestEffortSync } from "./file-sync.js";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import fsSync, {} from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { createFileHandle } from "./create.js";
|
|
6
|
+
import { hasPreservedCreationArtifacts } from "./creation-file-state.js";
|
|
7
|
+
import { assertSyncDirectoryGuard } from "./directory-guard.js";
|
|
5
8
|
import { FsSafeError } from "./errors.js";
|
|
6
|
-
import { nativeOpenFlags, removeNativeCreatedFileIfStillPinned,
|
|
9
|
+
import { nativeOpenFlags, removeNativeCreatedFileIfStillPinned, } from "./native-operations.js";
|
|
10
|
+
import { writePinnedInput } from "./pinned-write-input.js";
|
|
7
11
|
import { captureNativeFdClose } from "./native-binding.js";
|
|
8
12
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
9
13
|
import { assertFinalSymlinkRejected } from "./root-symlink-policy.js";
|
|
14
|
+
import { classifyNativeRenameFailure } from "./native-rename-outcome.js";
|
|
15
|
+
import { cleanupPinnedFilePath } from "./file-cleanup.js";
|
|
16
|
+
import { createStagedFileReceipt, settleStagedFile } from "./staged-file-settlement.js";
|
|
17
|
+
import { exactIdentityMatches } from "./staged-directory.js";
|
|
18
|
+
import { inspectNativeDirectoryObservation } from "./native-directory-observation.js";
|
|
10
19
|
function closeWriteFd(closeFd, fd) {
|
|
11
20
|
if (fd === undefined)
|
|
12
21
|
return;
|
|
@@ -17,39 +26,129 @@ function closeWriteFd(closeFd, fd) {
|
|
|
17
26
|
return { error };
|
|
18
27
|
}
|
|
19
28
|
}
|
|
29
|
+
function readParentIdentity(parentFd, guard) {
|
|
30
|
+
const stat = inspectFileIdentitySync(() => fsSync.fstatSync(parentFd, { bigint: true }));
|
|
31
|
+
if (!stat.isDirectory() || !exactIdentityMatches(guard.stat, stat)) {
|
|
32
|
+
throw new FsSafeError("path-mismatch", "native write parent identity changed");
|
|
33
|
+
}
|
|
34
|
+
return stat;
|
|
35
|
+
}
|
|
36
|
+
function assertNamedParentCurrent(binding, guard, identity) {
|
|
37
|
+
if (typeof binding.observeDirectory === "function") {
|
|
38
|
+
try {
|
|
39
|
+
const observed = inspectNativeDirectoryObservation(binding, guard.dir, identity);
|
|
40
|
+
if (observed.realPath !== guard.realPath) {
|
|
41
|
+
throw new FsSafeError("path-mismatch", "native write parent pathname changed");
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error?.code !== "OBSERVATION_UNAVAILABLE")
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
assertSyncDirectoryGuard({ ...guard, stat: identity });
|
|
51
|
+
}
|
|
20
52
|
export async function runPinnedWriteWindows(binding, params, root, parentFd, parentGuard) {
|
|
21
53
|
const closeFd = captureNativeFdClose(binding);
|
|
22
54
|
const parentPath = parentGuard.realPath;
|
|
23
55
|
let tempFd;
|
|
56
|
+
let privateHandle;
|
|
24
57
|
let targetFd;
|
|
58
|
+
let publicationProbeFd;
|
|
25
59
|
let tempIdentity;
|
|
26
60
|
let tempName = "";
|
|
27
61
|
let renamed = false;
|
|
28
62
|
let completed = false;
|
|
63
|
+
const completeCreate = params.overwrite === false && params.input.kind !== "file" && params.input.stageBeforePublish === true;
|
|
64
|
+
let receipt;
|
|
65
|
+
let publication = Object.freeze({ status: "not-published" });
|
|
66
|
+
let phase = "prepare";
|
|
67
|
+
let failure;
|
|
68
|
+
const closeTemp = async () => {
|
|
69
|
+
const handle = privateHandle;
|
|
70
|
+
const fd = tempFd;
|
|
71
|
+
privateHandle = undefined;
|
|
72
|
+
tempFd = undefined;
|
|
73
|
+
if (handle)
|
|
74
|
+
await handle.close();
|
|
75
|
+
else if (fd !== undefined)
|
|
76
|
+
closeFd(fd);
|
|
77
|
+
};
|
|
29
78
|
try {
|
|
30
79
|
tempName = `.fs-safe-${randomUUID()}.tmp`;
|
|
31
80
|
params.assertBeforeMutation?.();
|
|
32
|
-
|
|
81
|
+
if (params.private) {
|
|
82
|
+
const parentIdentity = fsSync.fstatSync(parentFd, { bigint: true });
|
|
83
|
+
privateHandle = await createFileHandle(path.join(parentPath, tempName), {
|
|
84
|
+
private: true,
|
|
85
|
+
mode: 0o600,
|
|
86
|
+
assertBeforeMutation: params.assertBeforeMutation,
|
|
87
|
+
}, {
|
|
88
|
+
expectedParentIdentity: {
|
|
89
|
+
dev: parentIdentity.dev, ino: parentIdentity.ino, realPath: parentPath,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
tempFd = privateHandle.fd;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
tempFd = binding.openBeneath(parentFd, tempName, nativeOpenFlags(fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_EXCL)).fd;
|
|
96
|
+
}
|
|
33
97
|
const verificationIdentity = inspectFileIdentitySync(() => fsSync.fstatSync(tempFd, { bigint: true }));
|
|
34
98
|
tempIdentity = verificationIdentity;
|
|
35
99
|
// Creation is requested at 0600 in the binding, but a restrictive umask
|
|
36
100
|
// can remove owner access. Keep the unpublished inode private and
|
|
37
101
|
// reopenable until the published name has been identity-fenced.
|
|
38
102
|
fsSync.fchmodSync(tempFd, 0o600);
|
|
39
|
-
await
|
|
40
|
-
if (params.sync !== false)
|
|
41
|
-
|
|
103
|
+
await writePinnedInput(tempFd, params.input, params.maxBytes, params.assertBeforeMutation);
|
|
104
|
+
if (params.sync !== false) {
|
|
105
|
+
if (params.strictFileSync)
|
|
106
|
+
fsSync.fsyncSync(tempFd);
|
|
107
|
+
else
|
|
108
|
+
syncFileBestEffortSync(tempFd);
|
|
109
|
+
}
|
|
42
110
|
if (params.input.kind === "file")
|
|
43
111
|
await params.input.verifySource();
|
|
112
|
+
if (completeCreate) {
|
|
113
|
+
const parentIdentity = readParentIdentity(parentFd, parentGuard);
|
|
114
|
+
receipt = createStagedFileReceipt(Object.freeze({
|
|
115
|
+
path: parentGuard.dir,
|
|
116
|
+
realPath: parentGuard.realPath,
|
|
117
|
+
identity: Object.freeze({ dev: parentIdentity.dev, ino: parentIdentity.ino }),
|
|
118
|
+
}), tempName, fsSync.fstatSync(tempFd, { bigint: true }));
|
|
119
|
+
}
|
|
120
|
+
phase = "publish";
|
|
44
121
|
assertFinalSymlinkRejected(path.join(parentPath, params.basename), params.rejectFinalSymlink);
|
|
45
122
|
params.assertBeforeMutation?.();
|
|
46
|
-
if (params.
|
|
47
|
-
|
|
123
|
+
if (params.assertBeforeMutation) {
|
|
124
|
+
// Callbacks can replace names synchronously. Fence the named parent and
|
|
125
|
+
// stage against retained descriptors before the rename can expose bytes.
|
|
126
|
+
assertNamedParentCurrent(binding, parentGuard, readParentIdentity(parentFd, parentGuard));
|
|
127
|
+
publicationProbeFd = binding.openBeneath(parentFd, tempName, nativeOpenFlags(fsSync.constants.O_RDONLY)).fd;
|
|
128
|
+
const named = inspectFileIdentitySync(() => fsSync.fstatSync(publicationProbeFd, { bigint: true }), verificationIdentity);
|
|
129
|
+
const retained = inspectFileIdentitySync(() => fsSync.fstatSync(tempFd, { bigint: true }), verificationIdentity);
|
|
130
|
+
if (!named.isFile() || !retained.isFile() || named.nlink !== 1n || retained.nlink !== 1n) {
|
|
131
|
+
throw new FsSafeError("path-mismatch", "native write stage changed before publication");
|
|
132
|
+
}
|
|
133
|
+
assertFinalSymlinkRejected(path.join(parentPath, params.basename), params.rejectFinalSymlink);
|
|
48
134
|
}
|
|
49
|
-
|
|
50
|
-
|
|
135
|
+
try {
|
|
136
|
+
if (params.overwrite === false) {
|
|
137
|
+
binding.renameNoReplace(parentFd, tempName, parentFd, params.basename);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
binding.renameReplace(parentFd, tempName, parentFd, params.basename);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (completeCreate && classifyNativeRenameFailure(error) === "indeterminate") {
|
|
145
|
+
publication = Object.freeze({ status: "indeterminate", basename: params.basename, overwrite: false });
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
51
148
|
}
|
|
52
149
|
renamed = true;
|
|
150
|
+
if (receipt)
|
|
151
|
+
publication = Object.freeze({ status: "published", staged: receipt, basename: params.basename, overwrite: false });
|
|
53
152
|
params.onPublished?.(verificationIdentity);
|
|
54
153
|
targetFd = binding.openBeneath(parentFd, params.basename, nativeOpenFlags(fsSync.constants.O_RDONLY)).fd;
|
|
55
154
|
const targetStat = inspectFileIdentitySync(() => fsSync.fstatSync(targetFd, { bigint: true }), verificationIdentity);
|
|
@@ -62,15 +161,21 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
|
|
|
62
161
|
// verifiable and so broader modes are never exposed before that fence.
|
|
63
162
|
try {
|
|
64
163
|
fsSync.fchmodSync(targetFd, params.mode);
|
|
65
|
-
|
|
66
|
-
|
|
164
|
+
// Windows FlushFileBuffers needs write access; the verification reopen is read-only.
|
|
165
|
+
if (params.sync !== false) {
|
|
166
|
+
if (params.strictFileSync)
|
|
167
|
+
fsSync.fsyncSync(tempFd);
|
|
168
|
+
else
|
|
169
|
+
syncFileBestEffortSync(tempFd);
|
|
170
|
+
}
|
|
67
171
|
}
|
|
68
172
|
catch (error) {
|
|
69
|
-
|
|
70
|
-
|
|
173
|
+
if (!completeCreate) {
|
|
174
|
+
closeWriteFd(closeFd, targetFd);
|
|
175
|
+
targetFd = undefined;
|
|
176
|
+
}
|
|
71
177
|
// Staged copies and streamed creates preserve publication for caller recovery.
|
|
72
|
-
if (params.input.kind
|
|
73
|
-
(params.input.kind === "stream" && !params.input.stageBeforePublish)) {
|
|
178
|
+
if (params.input.kind !== "file" && !params.input.stageBeforePublish) {
|
|
74
179
|
removeNativeCreatedFileIfStillPinned({
|
|
75
180
|
parentPath,
|
|
76
181
|
parentFd,
|
|
@@ -87,21 +192,61 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
|
|
|
87
192
|
completed = true;
|
|
88
193
|
return { dev: targetIdentity.dev, ino: targetIdentity.ino };
|
|
89
194
|
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
failure = { error };
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
90
199
|
finally {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
200
|
+
const preservedPreparation = params.private && tempFd === undefined && hasPreservedCreationArtifacts(failure?.error);
|
|
201
|
+
if (completeCreate || preservedPreparation) {
|
|
202
|
+
await settleStagedFile({
|
|
203
|
+
temporaryBasename: tempName, publication, phase, failure,
|
|
204
|
+
cleanup: async () => {
|
|
205
|
+
if (preservedPreparation)
|
|
206
|
+
return "preserved";
|
|
207
|
+
if (publication.status === "indeterminate")
|
|
208
|
+
return "preserved";
|
|
209
|
+
if (renamed || tempFd === undefined)
|
|
210
|
+
return "not-needed";
|
|
211
|
+
return await cleanupPinnedFilePath({
|
|
212
|
+
pathname: path.join(parentPath, tempName), handle: { fd: tempFd },
|
|
213
|
+
identity: tempIdentity, parentGuard, throwOnCleanupError: true,
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
close: [
|
|
217
|
+
() => { if (targetFd !== undefined)
|
|
218
|
+
closeFd(targetFd); },
|
|
219
|
+
() => { if (publicationProbeFd !== undefined)
|
|
220
|
+
closeFd(publicationProbeFd); },
|
|
221
|
+
closeTemp,
|
|
222
|
+
() => closeFd(parentFd),
|
|
223
|
+
() => root.close(),
|
|
224
|
+
],
|
|
99
225
|
});
|
|
100
226
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
227
|
+
else {
|
|
228
|
+
const targetCloseFailure = closeWriteFd(closeFd, targetFd);
|
|
229
|
+
const probeCloseFailure = closeWriteFd(closeFd, publicationProbeFd);
|
|
230
|
+
let tempCloseFailure;
|
|
231
|
+
try {
|
|
232
|
+
await closeTemp();
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
tempCloseFailure = { error };
|
|
236
|
+
}
|
|
237
|
+
if (!renamed) {
|
|
238
|
+
removeNativeCreatedFileIfStillPinned({
|
|
239
|
+
parentPath,
|
|
240
|
+
parentFd,
|
|
241
|
+
basename: tempName,
|
|
242
|
+
created: tempIdentity,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
const parentCloseFailure = closeWriteFd(closeFd, parentFd);
|
|
246
|
+
await root.close().catch(() => undefined);
|
|
247
|
+
const closeFailure = targetCloseFailure ?? probeCloseFailure ?? tempCloseFailure ?? parentCloseFailure;
|
|
248
|
+
if (completed && closeFailure)
|
|
249
|
+
throw closeFailure.error;
|
|
250
|
+
}
|
|
106
251
|
}
|
|
107
252
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-pinned-write.d.ts","sourceRoot":"","sources":["../src/native-pinned-write.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAK3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAIV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AA8W3B,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"native-pinned-write.d.ts","sourceRoot":"","sources":["../src/native-pinned-write.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAK3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAIV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AA8W3B,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8GvH"}
|
|
@@ -368,15 +368,18 @@ export async function runPinnedWriteNative(binding, params) {
|
|
|
368
368
|
assertNativeStaging(binding);
|
|
369
369
|
}
|
|
370
370
|
const directoryFlags = fsSync.constants.O_RDONLY | (fsSync.constants.O_DIRECTORY ?? 0);
|
|
371
|
+
const completeCreate = params.overwrite === false && params.input.kind !== "file" && params.input.stageBeforePublish === true;
|
|
371
372
|
const rootAdmission = await openNativeRootAdmission(binding, {
|
|
372
373
|
rootPath: params.rootPath,
|
|
373
374
|
rootIdentity: params.rootIdentity,
|
|
374
375
|
operation: "native write",
|
|
376
|
+
reportCloseErrors: completeCreate,
|
|
375
377
|
});
|
|
376
378
|
const root = rootAdmission.root;
|
|
377
379
|
const posixRoot = __addDisposableResource(env_2, windows ? undefined : root, true);
|
|
378
380
|
let parentFd;
|
|
379
381
|
let windowsOwnsDirectories = false;
|
|
382
|
+
let admissionFailure;
|
|
380
383
|
// Until stage construction takes ownership, even admission failures must close
|
|
381
384
|
// the raw POSIX parent. Disposal preserves both admission and close failures.
|
|
382
385
|
const parentGuard = __addDisposableResource(env_2, {
|
|
@@ -435,8 +438,13 @@ export async function runPinnedWriteNative(binding, params) {
|
|
|
435
438
|
parentFd = undefined;
|
|
436
439
|
return await writeNativeStage(binding, ownedParent, closeFd, directory, params, verificationGuard);
|
|
437
440
|
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
admissionFailure = { error };
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
438
445
|
finally {
|
|
439
446
|
if (windows && !windowsOwnsDirectories) {
|
|
447
|
+
const closeErrors = [];
|
|
440
448
|
if (parentFd !== undefined) {
|
|
441
449
|
// Match the Windows leaf cleanup contract: an admission or identity
|
|
442
450
|
// failure remains primary, while every owned directory is still given
|
|
@@ -445,11 +453,19 @@ export async function runPinnedWriteNative(binding, params) {
|
|
|
445
453
|
try {
|
|
446
454
|
closeFd(parentFd);
|
|
447
455
|
}
|
|
448
|
-
catch {
|
|
449
|
-
|
|
456
|
+
catch (error) {
|
|
457
|
+
closeErrors.push(error);
|
|
450
458
|
}
|
|
451
459
|
}
|
|
452
|
-
|
|
460
|
+
try {
|
|
461
|
+
await root.close();
|
|
462
|
+
}
|
|
463
|
+
catch (error) {
|
|
464
|
+
closeErrors.push(error);
|
|
465
|
+
}
|
|
466
|
+
if (completeCreate && closeErrors.length > 0) {
|
|
467
|
+
throw new AggregateError([...(admissionFailure ? [admissionFailure.error] : []), ...closeErrors], "native create admission and close failed");
|
|
468
|
+
}
|
|
453
469
|
}
|
|
454
470
|
}
|
|
455
471
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-policy-parent-windows.d.ts","sourceRoot":"","sources":["../src/native-policy-parent-windows.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAEnD,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,OAAO,KAAK,EAAE,iBAAiB,EAAkG,MAAM,mBAAmB,CAAC;AAC3J,OAAO,EAA4B,KAAK,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"native-policy-parent-windows.d.ts","sourceRoot":"","sources":["../src/native-policy-parent-windows.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAEnD,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,OAAO,KAAK,EAAE,iBAAiB,EAAkG,MAAM,mBAAmB,CAAC;AAC3J,OAAO,EAA4B,KAAK,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAK/G,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACxC,WAAW,EAAE,4BAA4B,CAAC;CAC3C,CAAC;AA4BF,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,mBAAmB,GACjC,OAAO,CAAC,YAAY,CAAC,CA+KvB"}
|
|
@@ -10,6 +10,7 @@ import { isSymlinkOpenError } from "./path.js";
|
|
|
10
10
|
import { checkedMutationDirectory } from "./pinned-mutation-observation.js";
|
|
11
11
|
import { canReuseParentWithMutationAssertion } from "./root-write-lock-binding.js";
|
|
12
12
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
13
|
+
import { createSuppressedError } from "./suppressed-error.js";
|
|
13
14
|
function assertParentCurrent(parent) {
|
|
14
15
|
const current = inspectFileIdentitySync(() => fsSync.fstatSync(parent.fd, { bigint: true }), parent.guard.stat);
|
|
15
16
|
assertDirectoryIdentitySync(parent.guard.dir, {
|
|
@@ -19,14 +20,17 @@ function assertParentCurrent(parent) {
|
|
|
19
20
|
});
|
|
20
21
|
return current;
|
|
21
22
|
}
|
|
22
|
-
function closeAfterFailure(closeFd, fd) {
|
|
23
|
+
function closeAfterFailure(closeFd, fd, failure, report = false) {
|
|
23
24
|
if (fd === undefined)
|
|
24
25
|
return;
|
|
25
26
|
try {
|
|
26
27
|
closeFd(fd);
|
|
27
28
|
}
|
|
28
|
-
catch {
|
|
29
|
-
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (report)
|
|
31
|
+
throw failure
|
|
32
|
+
? createSuppressedError(error, failure.error, "native parent admission and close failed")
|
|
33
|
+
: error;
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
export async function capturePolicyAwareWindowsParent(binding, params, rootAdmission) {
|
|
@@ -87,7 +91,7 @@ export async function capturePolicyAwareWindowsParent(binding, params, rootAdmis
|
|
|
87
91
|
return complete;
|
|
88
92
|
}
|
|
89
93
|
catch (error) {
|
|
90
|
-
closeAfterFailure(closeFd, complete.fd);
|
|
94
|
+
closeAfterFailure(closeFd, complete.fd, { error }, rootAdmission.reportCloseErrors);
|
|
91
95
|
throw error;
|
|
92
96
|
}
|
|
93
97
|
}
|
|
@@ -102,6 +106,7 @@ export async function capturePolicyAwareWindowsParent(binding, params, rootAdmis
|
|
|
102
106
|
}),
|
|
103
107
|
};
|
|
104
108
|
let ownedFd;
|
|
109
|
+
let failure;
|
|
105
110
|
const initialTarget = joinPathSegmentRoute(params.rootPath, route, 0, params.basename);
|
|
106
111
|
if (canReuseParentWithMutationAssertion(params.assertBeforeMutation, params.rootPath, initialTarget)) {
|
|
107
112
|
session = params.mutationAdmission?.beginNativeParentWalk?.() ??
|
|
@@ -178,7 +183,7 @@ export async function capturePolicyAwareWindowsParent(binding, params, rootAdmis
|
|
|
178
183
|
}
|
|
179
184
|
}
|
|
180
185
|
catch (error) {
|
|
181
|
-
closeAfterFailure(closeFd, child.fd);
|
|
186
|
+
closeAfterFailure(closeFd, child.fd, { error }, rootAdmission.reportCloseErrors);
|
|
182
187
|
throw error;
|
|
183
188
|
}
|
|
184
189
|
const previousFd = ownedFd;
|
|
@@ -193,8 +198,12 @@ export async function capturePolicyAwareWindowsParent(binding, params, rootAdmis
|
|
|
193
198
|
ownedFd = undefined;
|
|
194
199
|
return current;
|
|
195
200
|
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
failure = { error };
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
196
205
|
finally {
|
|
197
206
|
session?.dispose();
|
|
198
|
-
closeAfterFailure(closeFd, ownedFd);
|
|
207
|
+
closeAfterFailure(closeFd, ownedFd, failure, rootAdmission.reportCloseErrors);
|
|
199
208
|
}
|
|
200
209
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DirectoryReceipt } from "./directory-durability.js";
|
|
2
|
+
import { type BigIntStats, type Stats } from "node:fs";
|
|
2
3
|
import type { AnyAsyncDirectoryGuard } from "./directory-guard.js";
|
|
3
4
|
import type { FileIdentityStat } from "./file-identity.js";
|
|
4
5
|
import { type NativeBinding } from "./native-binding.js";
|
|
@@ -6,10 +7,11 @@ import type { PinnedWriteInput, PinnedWriteParams } from "./pinned-write.js";
|
|
|
6
7
|
import type { PublishedFileReceipt, StagedFile, StagedFileCleanupReceipt, StagedFileReceipt } from "./staged-file-types.js";
|
|
7
8
|
export type NativeStagingBinding = NativeBinding & Required<Pick<NativeBinding, "createStagedFile" | "stagedFileMatches" | "removeStagedFile">>;
|
|
8
9
|
export declare function assertNativeStaging(binding: NativeBinding): asserts binding is NativeStagingBinding;
|
|
10
|
+
type StagedPermissionPolicy = "private-creation" | "mode-only";
|
|
9
11
|
declare class NativeStagedFile implements StagedFile {
|
|
10
12
|
#private;
|
|
11
|
-
constructor(binding: NativeStagingBinding, parentFd: number, closeParentFd: (fd: number) => void, directory: StagedFileReceipt["directory"], portableNames: boolean, publishedMode: number, sync: boolean, assertBeforeMutation?: () => void, name?: string);
|
|
12
|
-
static create(binding: NativeStagingBinding, parentFd: number, closeParentFd: (fd: number) => void, directory: StagedFileReceipt["directory"], input: PinnedWriteInput, mode: number, maxBytes?: number, portableNames?: boolean, sync?: boolean, assertBeforeMutation?: () => void, exclusiveBasename?: string): Promise<NativeStagedFile>;
|
|
13
|
+
constructor(binding: NativeStagingBinding, parentFd: number, closeParentFd: (fd: number) => void, directory: StagedFileReceipt["directory"], portableNames: boolean, publishedMode: number, sync: boolean, assertBeforeMutation?: () => void, name?: string, strictFileSync?: boolean, permissionPolicy?: StagedPermissionPolicy);
|
|
14
|
+
static create(binding: NativeStagingBinding, parentFd: number, closeParentFd: (fd: number) => void, directory: StagedFileReceipt["directory"], input: PinnedWriteInput, mode: number, maxBytes?: number, portableNames?: boolean, sync?: boolean, assertBeforeMutation?: () => void, exclusiveBasename?: string, strictFileSync?: boolean, permissionPolicy?: StagedPermissionPolicy): Promise<NativeStagedFile>;
|
|
13
15
|
static write(binding: NativeStagingBinding, parentFd: number, closeParentFd: (fd: number) => void, directory: StagedFileReceipt["directory"], params: PinnedWriteParams, parentGuard: AnyAsyncDirectoryGuard): Promise<FileIdentityStat>;
|
|
14
16
|
get receipt(): StagedFileReceipt;
|
|
15
17
|
assertCurrent(): Promise<void>;
|
|
@@ -23,7 +25,7 @@ export declare const createNativeStage: (...args: Parameters<typeof NativeStaged
|
|
|
23
25
|
export declare const writeNativeStage: typeof NativeStagedFile.write;
|
|
24
26
|
export type { PublishedFileReceipt, StagedFile, StagedFileCleanupReceipt, StagedFileFailureDetails, StagedFilePublication, StagedFileReceipt, } from "./staged-file-types.js";
|
|
25
27
|
export declare function stageFileInDirectory(options: {
|
|
26
|
-
directory: string | DirectoryReceipt
|
|
28
|
+
directory: string | DirectoryReceipt<Stats | BigIntStats>;
|
|
27
29
|
content: string | Uint8Array;
|
|
28
30
|
/** Published mode; the unpublished stage stays at 0600. Defaults to 0600. */
|
|
29
31
|
mode?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-staged-file.d.ts","sourceRoot":"","sources":["../src/native-staged-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAMlE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAGnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG7E,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,EACV,wBAAwB,EAGxB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-staged-file.d.ts","sourceRoot":"","sources":["../src/native-staged-file.ts"],"names":[],"mappings":"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"}
|