@openclaw/openshell-sandbox 2026.10.5-beta.4 → 2026.10.10-beta.2
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/README.md +1 -1
- package/node_modules/@openclaw/fs-safe/CHANGELOG.md +148 -0
- package/node_modules/@openclaw/fs-safe/README.md +20 -4
- package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/advanced.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-merge.js +28 -3
- package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-read.js +11 -5
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-loader.js +4 -2
- package/node_modules/@openclaw/fs-safe/dist/archive.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/atomic-io.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/bounded-read.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read.js +9 -2
- package/node_modules/@openclaw/fs-safe/dist/clone-metadata.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/clone-metadata.js +2 -1
- package/node_modules/@openclaw/fs-safe/dist/config.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/config.js +5 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-file-input.d.ts +3 -1
- package/node_modules/@openclaw/fs-safe/dist/copy-file-input.js +8 -7
- package/node_modules/@openclaw/fs-safe/dist/copy-link.d.ts +26 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-link.js +170 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-metadata.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-metadata.js +39 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-path-admission.js +11 -2
- package/node_modules/@openclaw/fs-safe/dist/copy-root-file-sync.d.ts +2 -4
- package/node_modules/@openclaw/fs-safe/dist/copy-root-file-sync.js +4 -2
- package/node_modules/@openclaw/fs-safe/dist/copy-tree-portable.js +3 -6
- package/node_modules/@openclaw/fs-safe/dist/copy.js +3 -3
- package/node_modules/@openclaw/fs-safe/dist/create.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/creation-boundary.js +7 -4
- package/node_modules/@openclaw/fs-safe/dist/darwin-acl.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/darwin-acl.js +29 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-durability.d.ts +7 -4
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +20 -5
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.js +27 -2
- package/node_modules/@openclaw/fs-safe/dist/directory-receipt.d.ts +7 -7
- package/node_modules/@openclaw/fs-safe/dist/directory-receipt.js +9 -4
- package/node_modules/@openclaw/fs-safe/dist/durability.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/entry-publication.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/exact-identity.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/exact-identity.js +29 -0
- package/node_modules/@openclaw/fs-safe/dist/file-handle-transfer.js +4 -2
- package/node_modules/@openclaw/fs-safe/dist/file-hash.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/file-hash.js +11 -9
- package/node_modules/@openclaw/fs-safe/dist/file-identity.d.ts +7 -1
- package/node_modules/@openclaw/fs-safe/dist/file-identity.js +27 -5
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-admission.js +1 -2
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +8 -1
- package/node_modules/@openclaw/fs-safe/dist/file-lock.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-write-lease.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/file-write-lease.js +42 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.js +22 -15
- package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/hardlink-fallback.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/hardlink-fallback.js +5 -0
- package/node_modules/@openclaw/fs-safe/dist/index.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/index.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-ownership.js +16 -3
- package/node_modules/@openclaw/fs-safe/dist/local-file-descriptor.js +24 -13
- package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +85 -18
- package/node_modules/@openclaw/fs-safe/dist/native-config.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/native-config.js +11 -0
- package/node_modules/@openclaw/fs-safe/dist/native-directory-observation.js +6 -4
- package/node_modules/@openclaw/fs-safe/dist/native-fallback-warning.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/native-fallback-warning.js +26 -2
- package/node_modules/@openclaw/fs-safe/dist/native-guidance.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-guidance.js +21 -0
- package/node_modules/@openclaw/fs-safe/dist/native-move-fallback.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/native-move-fallback.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/native-operations.js +8 -6
- package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.d.ts +44 -4
- package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.js +85 -15
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.d.ts +3 -3
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.js +33 -6
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.d.ts +4 -1
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +22 -3
- package/node_modules/@openclaw/fs-safe/dist/native-policy-directory-observation.js +4 -3
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file-metadata.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file-metadata.js +16 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +15 -5
- package/node_modules/@openclaw/fs-safe/dist/native-stat-identity.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-stat-identity.js +7 -0
- package/node_modules/@openclaw/fs-safe/dist/native-status.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/native-status.js +30 -0
- package/node_modules/@openclaw/fs-safe/dist/native.d.ts +31 -4
- package/node_modules/@openclaw/fs-safe/dist/native.js +107 -9
- package/node_modules/@openclaw/fs-safe/dist/opened-realpath.js +9 -1
- package/node_modules/@openclaw/fs-safe/dist/overwrite-file-handle.js +4 -1
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.js +9 -1
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-windows.js +83 -47
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.js +8 -3
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-input.js +13 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-staged.js +10 -8
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-types.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/pinned-write.js +7 -5
- package/node_modules/@openclaw/fs-safe/dist/pipe.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/pipe.js +26 -0
- package/node_modules/@openclaw/fs-safe/dist/private-directory.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/private-producer-handoff.js +2 -5
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.d.ts +3 -2
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.js +38 -10
- package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +92 -10
- package/node_modules/@openclaw/fs-safe/dist/publish-file-failure.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file-failure.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file.d.ts +5 -3
- package/node_modules/@openclaw/fs-safe/dist/publish-file.js +26 -20
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.js +3 -4
- package/node_modules/@openclaw/fs-safe/dist/realpath.js +32 -0
- package/node_modules/@openclaw/fs-safe/dist/regular-file.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/regular-file.js +11 -15
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +3 -2
- package/node_modules/@openclaw/fs-safe/dist/root-copy.d.ts +18 -0
- package/node_modules/@openclaw/fs-safe/dist/root-copy.js +128 -0
- package/node_modules/@openclaw/fs-safe/dist/root-create-native.d.ts +8 -13
- package/node_modules/@openclaw/fs-safe/dist/root-create-native.js +252 -27
- package/node_modules/@openclaw/fs-safe/dist/root-directory-creation.js +5 -1
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.d.ts +11 -8
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +35 -13
- package/node_modules/@openclaw/fs-safe/dist/root-file-open-batch-sync.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file-open-batch-sync.js +108 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.js +15 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.js +154 -175
- package/node_modules/@openclaw/fs-safe/dist/root-mkdir-native.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/root-mkdir-native.js +239 -0
- package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.js +37 -15
- package/node_modules/@openclaw/fs-safe/dist/root-native-creation-path.d.ts +32 -0
- package/node_modules/@openclaw/fs-safe/dist/root-native-creation-path.js +56 -0
- package/node_modules/@openclaw/fs-safe/dist/root-options.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/root-public-types.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-remove-native.js +95 -16
- package/node_modules/@openclaw/fs-safe/dist/root-remove.js +6 -4
- package/node_modules/@openclaw/fs-safe/dist/root-walk.js +23 -19
- package/node_modules/@openclaw/fs-safe/dist/root-write-admission.js +8 -6
- package/node_modules/@openclaw/fs-safe/dist/root-write-publication.js +5 -1
- package/node_modules/@openclaw/fs-safe/dist/secure-file-windows.js +3 -1
- package/node_modules/@openclaw/fs-safe/dist/secure-file.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-file.js +10 -4
- package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-retained.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-target.js +8 -1
- package/node_modules/@openclaw/fs-safe/dist/staged-directory.d.ts +13 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-directory.js +29 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +5 -3
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-descriptor.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-descriptor.js +13 -2
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-owner.js +71 -3
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.js +22 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-types.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/trash.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/types.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-native.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/windows-appcontainer.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-appcontainer.js +39 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.js +25 -36
- package/node_modules/@openclaw/fs-safe/dist/windows-security-command.js +24 -5
- package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.js +4 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-helper.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-helper.exe +0 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-helper.js +7 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-test-hooks.d.ts +16 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-test-hooks.js +51 -0
- package/node_modules/@openclaw/fs-safe/dist/write-file-handle.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/write-file-handle.js +12 -10
- package/node_modules/@openclaw/fs-safe/docs/advanced.md +2 -1
- package/node_modules/@openclaw/fs-safe/docs/archive.md +16 -0
- package/node_modules/@openclaw/fs-safe/docs/config.md +71 -1
- package/node_modules/@openclaw/fs-safe/docs/contributing.md +45 -5
- package/node_modules/@openclaw/fs-safe/docs/copy.md +45 -5
- package/node_modules/@openclaw/fs-safe/docs/durability.md +34 -7
- package/node_modules/@openclaw/fs-safe/docs/errors.md +8 -0
- package/node_modules/@openclaw/fs-safe/docs/guest.md +2 -0
- package/node_modules/@openclaw/fs-safe/docs/install.md +47 -27
- package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.5.md +6 -6
- package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.6.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/native-helper.md +79 -6
- package/node_modules/@openclaw/fs-safe/docs/native.md +279 -8
- package/node_modules/@openclaw/fs-safe/docs/permissions.md +64 -15
- package/node_modules/@openclaw/fs-safe/docs/pipe.md +81 -0
- package/node_modules/@openclaw/fs-safe/docs/platform-capabilities.md +63 -0
- package/node_modules/@openclaw/fs-safe/docs/public-api.md +10 -0
- package/node_modules/@openclaw/fs-safe/docs/queue-link-free-design.md +237 -0
- package/node_modules/@openclaw/fs-safe/docs/quickstart.md +23 -3
- package/node_modules/@openclaw/fs-safe/docs/reading.md +56 -2
- package/node_modules/@openclaw/fs-safe/docs/regular-file.md +2 -0
- package/node_modules/@openclaw/fs-safe/docs/secret-file.md +5 -5
- package/node_modules/@openclaw/fs-safe/docs/secure-file.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/security-model.md +35 -0
- package/node_modules/@openclaw/fs-safe/docs/sidecar-lock.md +31 -13
- package/node_modules/@openclaw/fs-safe/docs/staged-file.md +18 -0
- package/node_modules/@openclaw/fs-safe/docs/store.md +15 -0
- package/node_modules/@openclaw/fs-safe/docs/temp.md +39 -0
- package/node_modules/@openclaw/fs-safe/docs/testing.md +13 -0
- package/node_modules/@openclaw/fs-safe/docs/types.md +51 -81
- package/node_modules/@openclaw/fs-safe/docs/walk.md +4 -1
- package/node_modules/@openclaw/fs-safe/docs/watch.md +3 -2
- package/node_modules/@openclaw/fs-safe/docs/writing.md +121 -14
- package/node_modules/@openclaw/fs-safe/package.json +21 -12
- package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-freebsd-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-freebsd-arm64/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-freebsd-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-freebsd-x64/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-win32-arm64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-arm64-msvc/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
- package/package.json +5 -5
- package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.cs +0 -336
- package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.ps1 +0 -90
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { type ExactFileIdentity } from "./exact-identity.js";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import type { PathAliasPolicy } from "./path-policy.js";
|
|
3
4
|
import { type SymlinkPolicy } from "./root-symlink-policy.js";
|
|
4
5
|
import { type PinnedOpenSyncAllowedType, type PinnedOpenSyncFailureReason } from "./pinned-open.js";
|
|
6
|
+
import { type CanonicalRootObservation } from "./root-file-final-admission.js";
|
|
5
7
|
type BoundaryReadFs = Pick<typeof fs, "closeSync" | "constants" | "fstatSync" | "lstatSync" | "openSync" | "readFileSync" | "realpathSync">;
|
|
6
8
|
export type RootFileOpenFailureReason = PinnedOpenSyncFailureReason | "validation";
|
|
7
9
|
export type RootFileOpenResult = {
|
|
@@ -9,6 +11,7 @@ export type RootFileOpenResult = {
|
|
|
9
11
|
path: string;
|
|
10
12
|
fd: number;
|
|
11
13
|
stat: fs.Stats;
|
|
14
|
+
exactIdentity: ExactFileIdentity;
|
|
12
15
|
rootRealPath: string;
|
|
13
16
|
} | {
|
|
14
17
|
ok: false;
|
|
@@ -42,5 +45,9 @@ export declare function matchRootFileOpenFailure<T>(failure: RootFileOpenFailure
|
|
|
42
45
|
io?: (failure: RootFileOpenFailure) => T;
|
|
43
46
|
fallback: (failure: RootFileOpenFailure) => T;
|
|
44
47
|
}): T;
|
|
48
|
+
/** Internal retained-root adapter; the native opener owns component admission. */
|
|
49
|
+
export declare function openRootFileWithRetainedRootSync(params: OpenRootFileSyncParams, root: Extract<CanonicalRootObservation, {
|
|
50
|
+
ok: true;
|
|
51
|
+
}>, admittedFd: number): RootFileOpenResult;
|
|
45
52
|
export declare function openRootFile(params: OpenRootFileParams): Promise<RootFileOpenResult>;
|
|
46
53
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { exactFileIdentity } from "./exact-identity.js";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { resolveRootPathSyncWithCanonicalRootObservation, resolveRootPathWithCanonicalRootObservation, } from "./root-path.js";
|
|
@@ -82,6 +83,8 @@ function finalizeRootFileOpen(params) {
|
|
|
82
83
|
maxBytes: params.maxBytes,
|
|
83
84
|
allowedType: params.allowedType,
|
|
84
85
|
ioFs: params.ioFs,
|
|
86
|
+
admittedFd: params.admittedFd,
|
|
87
|
+
rejectLeafSymlinks: params.rejectLeafSymlinks,
|
|
85
88
|
finalAdmission: createRootFileFinalAdmission(params.ioFs, resolved.rootObservation, resolved.boundaryLabel, rejectHardlinks),
|
|
86
89
|
});
|
|
87
90
|
if (!opened.ok) {
|
|
@@ -92,9 +95,21 @@ function finalizeRootFileOpen(params) {
|
|
|
92
95
|
path: opened.path,
|
|
93
96
|
fd: opened.fd,
|
|
94
97
|
stat: opened.stat,
|
|
98
|
+
exactIdentity: exactFileIdentity(opened.identity),
|
|
95
99
|
rootRealPath: resolved.rootRealPath,
|
|
96
100
|
};
|
|
97
101
|
}
|
|
102
|
+
/** Internal retained-root adapter; the native opener owns component admission. */
|
|
103
|
+
export function openRootFileWithRetainedRootSync(params, root, admittedFd) {
|
|
104
|
+
return finalizeRootFileOpen({
|
|
105
|
+
resolved: {
|
|
106
|
+
absolutePath: params.absolutePath, resolvedPath: params.absolutePath,
|
|
107
|
+
rootRealPath: root.path, rootObservation: root, boundaryLabel: params.boundaryLabel,
|
|
108
|
+
},
|
|
109
|
+
maxBytes: params.maxBytes, rejectHardlinks: params.rejectHardlinks,
|
|
110
|
+
allowedType: params.allowedType, ioFs: fs, admittedFd, rejectLeafSymlinks: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
98
113
|
export async function openRootFile(params) {
|
|
99
114
|
const ioFs = params.ioFs ?? fs;
|
|
100
115
|
const rawAbsolutePath = params.absolutePath;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ExactFileIdentity } from "./exact-identity.js";
|
|
1
2
|
import type { BigIntStats, Stats } from "node:fs";
|
|
2
3
|
import type { FileHandle } from "node:fs/promises";
|
|
3
4
|
import type { ContainmentGuarantee } from "./containment.js";
|
|
@@ -14,6 +15,7 @@ export type OpenResult = {
|
|
|
14
15
|
containment: ContainmentGuarantee;
|
|
15
16
|
realPath: string;
|
|
16
17
|
stat: Stats;
|
|
18
|
+
exactIdentity: ExactFileIdentity;
|
|
17
19
|
[Symbol.asyncDispose](): Promise<void>;
|
|
18
20
|
};
|
|
19
21
|
export interface Root {
|
|
@@ -50,12 +50,13 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
50
50
|
var e = new Error(message);
|
|
51
51
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
52
|
});
|
|
53
|
+
import { exactFileIdentity, numberStats } from "./exact-identity.js";
|
|
53
54
|
import { registerRootHandleContext } from "./root-handle-context.js";
|
|
54
55
|
import fsSync, { constants as fsConstants } from "node:fs";
|
|
55
56
|
import fs from "node:fs/promises";
|
|
56
57
|
import path from "node:path";
|
|
57
58
|
import { normalizeMaxBytes } from "./byte-budget.js";
|
|
58
|
-
import {
|
|
59
|
+
import { copyFileInRoot } from "./root-copy.js";
|
|
59
60
|
import { assertPrivateFileCreationAvailable, resolveCreationPermissions } from "./creation-boundary.js";
|
|
60
61
|
import { assertAsyncDirectoryGuard, assertSyncDirectoryGuard, createAsyncDirectoryGuard, createNearestExistingDirectoryGuard } from "./directory-guard.js";
|
|
61
62
|
import { FsSafeError } from "./errors.js";
|
|
@@ -68,6 +69,7 @@ import { openedPathResolutionError, recordExclusiveCreateFailure, recordOpenedFi
|
|
|
68
69
|
import { runPinnedWriteHelper, runPinnedWriteWithRenamePolicy } from "./pinned-write.js";
|
|
69
70
|
import { preparePinnedWriteMutationAdmission, snapshotPinnedMutationPolicy } from "./pinned-mutation-admission.js";
|
|
70
71
|
import { getNativeBinding } from "./native.js";
|
|
72
|
+
import { getPinnedWriteNativeBinding } from "./native-pinned-write.js";
|
|
71
73
|
import { isFsSafeNativeRequired } from "./native-config.js";
|
|
72
74
|
import { validatePinnedRelativePath } from "./pinned-operation.js";
|
|
73
75
|
import { PATH_ALIAS_POLICIES } from "./path-policy.js";
|
|
@@ -78,7 +80,8 @@ import { sameFileIdentity } from "./file-identity.js";
|
|
|
78
80
|
import { removePathIfIdentityUnchanged } from "./replace-file-temp-owner.js";
|
|
79
81
|
import { realpathSync } from "./realpath.js";
|
|
80
82
|
import { mkdirPathFallback, prepareRootWriteTarget, tryMkdirAtExactParent } from "./root-directory-creation.js";
|
|
81
|
-
import {
|
|
83
|
+
import { tryMkdirNativeParents } from "./root-mkdir-native.js";
|
|
84
|
+
import { buildAtomicWriteTempPath, rootWriteQueueKey, ensureNativeRootCurrent, isNativeCreateCollision, probeNativeCreationPath, tryMkdirNativeDirectChild, tryMkdirRootNative, tryOpenCreateRootNative } from "./root-create-native.js";
|
|
82
85
|
import { isNonRegularWriteOpenError, resolveNonblockingWriteFlag } from "./write-open-flags.js";
|
|
83
86
|
import { resolveRootPath, resolveRootPathSync, resolveRootPathForRemoval } from "./root-path.js";
|
|
84
87
|
import { RemovalPathReceipts } from "./root-remove-receipt.js";
|
|
@@ -101,10 +104,10 @@ import { prepareSharedRootWriteTarget } from "./root-write-complete-parent.js";
|
|
|
101
104
|
import { finishRootFallbackWrite } from "./root-write-publication.js";
|
|
102
105
|
import { withRootFallbackCompatibilityLock } from "./root-write-compatibility.js";
|
|
103
106
|
import { assertRootFallbackWritePath } from "./root-write-lock-binding.js";
|
|
104
|
-
import {
|
|
107
|
+
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
105
108
|
import { admitMoveSourceStat, movePathNative } from "./root-move-noreplace.js";
|
|
106
109
|
import { admitRootReadHandle, inspectOpenedPathIdentitySync } from "./root-read-admission.js";
|
|
107
|
-
import {
|
|
110
|
+
import { onCopyPublication, onCopySourceAdmission } from "./copy-publication.js";
|
|
108
111
|
import { writeAllToFile } from "./write-file-handle.js";
|
|
109
112
|
import { createInputOptions, rethrowCreateInputError, rootWriteInput, retainSidecarCreated } from "./root-create-input.js";
|
|
110
113
|
import { assertFinalSymlinkRejected, mutationSymlinkResolution, readSymlinkResolution } from "./root-symlink-policy.js";
|
|
@@ -113,7 +116,7 @@ import { assertNoWindowsPathAlias, resolvePathPreservingWindowsRoot } from "./wi
|
|
|
113
116
|
import { resolvePinnedObservedPathInRoot } from "./root-observed-path.js";
|
|
114
117
|
import { registerFileLockSyncRootAdapter } from "./file-lock-sync-root.js";
|
|
115
118
|
import { mergeReadOptions, readDefaults, } from "./root-options.js";
|
|
116
|
-
import { composeMutationAssertions,
|
|
119
|
+
import { composeMutationAssertions, rethrowMutationAuthorityError } from "./mutation-authority.js";
|
|
117
120
|
export { DEFAULT_ROOT_MAX_BYTES } from "./root-options.js";
|
|
118
121
|
export { resolveOpenedFileRealPathForHandle } from "./opened-realpath.js";
|
|
119
122
|
function logWarn(message) {
|
|
@@ -141,6 +144,7 @@ function openResult(params) {
|
|
|
141
144
|
containment: "best-effort",
|
|
142
145
|
realPath: params.realPath,
|
|
143
146
|
stat: params.stat,
|
|
147
|
+
exactIdentity: params.exactIdentity,
|
|
144
148
|
[Symbol.asyncDispose]: () => params.handle.close().catch(() => undefined),
|
|
145
149
|
};
|
|
146
150
|
}
|
|
@@ -150,7 +154,7 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
150
154
|
try {
|
|
151
155
|
const inspectPathIdentity = async (inspect) => {
|
|
152
156
|
try {
|
|
153
|
-
return
|
|
157
|
+
return inspectFileIdentitySync(inspect, identity);
|
|
154
158
|
}
|
|
155
159
|
catch (error) {
|
|
156
160
|
const failure = isNotFoundPathError(error) ? openedPathResolutionError(fileNotFoundError()) : error;
|
|
@@ -160,8 +164,10 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
160
164
|
throw failure;
|
|
161
165
|
}
|
|
162
166
|
};
|
|
163
|
-
await inspectPathIdentity(
|
|
164
|
-
|
|
167
|
+
await inspectPathIdentity(() => inspectOpenedPathIdentitySync(filePath, options?.symlinks));
|
|
168
|
+
if (fsSafeTestHooks?.afterOpenedPathIdentityCheck) {
|
|
169
|
+
await fsSafeTestHooks.afterOpenedPathIdentityCheck(filePath, handle);
|
|
170
|
+
}
|
|
165
171
|
const resolved = await resolveOpenedFileRealPathForFd(handle.fd, identity, filePath)
|
|
166
172
|
.catch(async (error) => {
|
|
167
173
|
if (stat.nlink <= 1 && (!preOpenStat || preOpenStat.nlink <= 1n)) {
|
|
@@ -172,7 +178,7 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
172
178
|
const { realPath } = resolved;
|
|
173
179
|
assertNoWindowsPathAlias(realPath, "filesystem", "resolved file path uses a Windows filesystem namespace alias");
|
|
174
180
|
let resolvedStat = resolved.stat;
|
|
175
|
-
await inspectPathIdentity(
|
|
181
|
+
await inspectPathIdentity(() => {
|
|
176
182
|
// Reuse the post-realpath observation; unknown Windows identities still
|
|
177
183
|
// get a fresh observation on inspectFileIdentity's retry.
|
|
178
184
|
const realStat = resolvedStat ?? fsSync.statSync(realPath, { bigint: true });
|
|
@@ -182,7 +188,7 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
182
188
|
}
|
|
183
189
|
return realStat;
|
|
184
190
|
});
|
|
185
|
-
return { opened: openResult({ handle, realPath, stat }), identity };
|
|
191
|
+
return { opened: openResult({ handle, realPath, stat, exactIdentity: exactFileIdentity(identity) }), identity };
|
|
186
192
|
}
|
|
187
193
|
catch (err) {
|
|
188
194
|
await handle.close().catch(() => { });
|
|
@@ -355,7 +361,7 @@ export class RootHandle {
|
|
|
355
361
|
durable: options.durable ?? this.defaults.durable ?? true,
|
|
356
362
|
verifyPublished: options[onCopyPublication],
|
|
357
363
|
admitSource: options[onCopySourceAdmission],
|
|
358
|
-
}).catch(rethrowMutationAuthorityError);
|
|
364
|
+
}, openVerifiedLocalFile).catch(rethrowMutationAuthorityError);
|
|
359
365
|
}
|
|
360
366
|
async exists(relativePath) {
|
|
361
367
|
try {
|
|
@@ -464,7 +470,7 @@ async function openFileInRoot(root, params) {
|
|
|
464
470
|
// The admission helper owns the descriptor until the complete root/file/root
|
|
465
471
|
// fence succeeds, then transfers that still-open handle to the caller.
|
|
466
472
|
const admitted = await admitRootReadHandle({
|
|
467
|
-
root, filePath: resolved, opened: { handle, stat }, identity,
|
|
473
|
+
root, filePath: resolved, opened: { handle, stat, exactIdentity: exactFileIdentity(identity) }, identity,
|
|
468
474
|
hardlinks: params.hardlinks, symlinks: params.symlinks,
|
|
469
475
|
beforeFinalFence: fsSafeTestHooks?.beforeRootReadFinalFence,
|
|
470
476
|
afterPathIdentityCheck: fsSafeTestHooks?.afterRootReadFinalPathIdentityCheck,
|
|
@@ -511,46 +517,61 @@ async function openWritableFileInRoot(root, params, options) {
|
|
|
511
517
|
denyMutations: params.denyMutations,
|
|
512
518
|
mutationSymlinks: params.mutationSymlinks,
|
|
513
519
|
});
|
|
514
|
-
const
|
|
520
|
+
const creationProbe = requireNative && !guardedTarget && params.assertBeforeMutation === undefined && options?.createIfMissing !== false
|
|
521
|
+
? probeNativeCreationPath(root, params.relativePath) : undefined;
|
|
522
|
+
const { resolved } = creationProbe ?? guardedTarget?.resolvedPath ?? await resolveGuardedWritePathInRoot(root, {
|
|
515
523
|
relativePath: params.relativePath,
|
|
516
524
|
});
|
|
517
525
|
const resolveCurrent = async () => (await resolveGuardedWritePathInRoot(root, {
|
|
518
526
|
relativePath: params.relativePath, ...policy,
|
|
519
527
|
})).resolved;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
528
|
+
// Existing-file opens need no mkdir. Keep capability admission, and create
|
|
529
|
+
// missing parents only when the native exclusive-create route is needed.
|
|
530
|
+
const nativeCreatesParents = requireNative && params.mkdir !== false;
|
|
531
|
+
if (nativeCreatesParents) {
|
|
532
|
+
const binding = getNativeBinding("openBeneath", "mkdirChildBeneath", "closeOwnedFd");
|
|
533
|
+
if (!binding)
|
|
534
|
+
throw new FsSafeError("helper-unavailable", "native confined creation is unavailable");
|
|
535
|
+
// Policy selection retains a parent receipt before the existing-file open.
|
|
536
|
+
if (guardedTarget)
|
|
537
|
+
await tryMkdirRootNative({
|
|
538
|
+
originalPath: params.relativePath,
|
|
539
|
+
root, directory: path.dirname(resolved), target: resolved, mkdir: true, policy,
|
|
540
|
+
resolveCurrent, assertBeforeMutation: params.assertBeforeMutation,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
const prepared = !nativeCreatesParents && guardedTarget ? await prepareSharedRootWriteTarget(root, {
|
|
526
544
|
relativePath: params.relativePath, guardedTarget, mkdir: params.mkdir,
|
|
527
545
|
assertBeforeMutation: params.assertBeforeMutation,
|
|
528
546
|
}) : undefined;
|
|
529
547
|
const preparedParent = prepared?.preparedParent;
|
|
530
|
-
let ioPath =
|
|
548
|
+
let ioPath = nativeCreatesParents ? resolved : prepared?.targetPath ?? (params.mkdir === false ? resolved :
|
|
531
549
|
await prepareRootWriteTarget(root, resolved, params.assertBeforeMutation));
|
|
532
550
|
const operationTargetPath = ioPath;
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
if (err instanceof FsSafeError) {
|
|
548
|
-
throw err;
|
|
551
|
+
let observedMissing = Boolean(creationProbe);
|
|
552
|
+
if (!creationProbe)
|
|
553
|
+
try {
|
|
554
|
+
assertFinalSymlinkRejected(ioPath, params.mutationSymlinks !== undefined);
|
|
555
|
+
const resolvedRealPath = params.mutationSymlinks === undefined ? realpathSync.native(ioPath) : ioPath;
|
|
556
|
+
const admittedRealPath = admitPathInsideRoot({
|
|
557
|
+
rootPath: root.rootReal,
|
|
558
|
+
candidatePath: resolvedRealPath,
|
|
559
|
+
rootIdentity: root.rootIdentity,
|
|
560
|
+
});
|
|
561
|
+
if (!admittedRealPath) {
|
|
562
|
+
throw outsideWorkspaceError();
|
|
563
|
+
}
|
|
564
|
+
ioPath = admittedRealPath.path;
|
|
549
565
|
}
|
|
550
|
-
|
|
551
|
-
|
|
566
|
+
catch (err) {
|
|
567
|
+
if (err instanceof FsSafeError) {
|
|
568
|
+
throw err;
|
|
569
|
+
}
|
|
570
|
+
if (!isNotFoundPathError(err)) {
|
|
571
|
+
throw err;
|
|
572
|
+
}
|
|
573
|
+
observedMissing = true;
|
|
552
574
|
}
|
|
553
|
-
}
|
|
554
575
|
assertRootFallbackWritePath(params.expectedWritePath, ioPath);
|
|
555
576
|
const mode = params.mode ?? 0o600;
|
|
556
577
|
let handle;
|
|
@@ -564,55 +585,82 @@ async function openWritableFileInRoot(root, params, options) {
|
|
|
564
585
|
writePathSelection = guardedTarget
|
|
565
586
|
? await prepareGuardedRootWritePathSelection(guardedTarget, ioPath, operationTargetPath, preparedParent)
|
|
566
587
|
: undefined;
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
588
|
+
const createNative = () => tryOpenCreateRootNative({
|
|
589
|
+
originalPath: params.relativePath,
|
|
590
|
+
root, directory: path.dirname(ioPath), target: ioPath, mkdir: params.mkdir !== false, policy,
|
|
591
|
+
selectedParent: creationProbe?.parent,
|
|
592
|
+
resolveCurrent,
|
|
593
|
+
assertBeforeMutation: params.assertBeforeMutation !== undefined || writePathSelection !== undefined ? () => {
|
|
594
|
+
params.assertBeforeMutation?.();
|
|
595
|
+
if (writePathSelection)
|
|
596
|
+
assertRootWritePathSelectionSync(root, writePathSelection);
|
|
597
|
+
} : undefined,
|
|
598
|
+
flags: createFlags, existingFlags, mode,
|
|
599
|
+
});
|
|
600
|
+
let precreated;
|
|
601
|
+
if (requireNative && observedMissing && !guardedTarget && params.assertBeforeMutation === undefined && options?.createIfMissing !== false) {
|
|
602
|
+
try {
|
|
603
|
+
precreated = await createNative();
|
|
575
604
|
}
|
|
576
|
-
|
|
577
|
-
|
|
605
|
+
catch (error) {
|
|
606
|
+
if (!hasNodeErrorCode(error, "EEXIST") || !isNativeCreateCollision(error))
|
|
607
|
+
throw error;
|
|
578
608
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
609
|
+
}
|
|
610
|
+
if (precreated) {
|
|
611
|
+
handle = precreated.handle;
|
|
612
|
+
cleanupCreated = precreated.cleanupCreated;
|
|
613
|
+
releaseCreationParent = precreated.releaseCreationParent;
|
|
614
|
+
createdForWrite = true;
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
try {
|
|
618
|
+
if (writePathSelection)
|
|
619
|
+
assertRootWritePathSelectionSync(root, writePathSelection);
|
|
620
|
+
handle = await fs.open(ioPath, existingFlags, mode);
|
|
589
621
|
}
|
|
590
|
-
|
|
591
|
-
await
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
622
|
+
catch (err) {
|
|
623
|
+
if (await isNonRegularWriteOpenError(err, ioPath, existingFlags)) {
|
|
624
|
+
throw new FsSafeError("not-file", "path is not a regular file under root");
|
|
625
|
+
}
|
|
626
|
+
if (!isNotFoundPathError(err)) {
|
|
627
|
+
throw err;
|
|
628
|
+
}
|
|
629
|
+
if (options?.createIfMissing === false) {
|
|
630
|
+
if (nativeCreatesParents && !guardedTarget)
|
|
631
|
+
await tryMkdirRootNative({
|
|
632
|
+
originalPath: params.relativePath,
|
|
633
|
+
root, directory: path.dirname(ioPath), target: ioPath, mkdir: true, policy,
|
|
634
|
+
resolveCurrent, assertBeforeMutation: params.assertBeforeMutation,
|
|
635
|
+
});
|
|
636
|
+
const parentGuard = writePathSelection?.parentGuard ??
|
|
637
|
+
await createAsyncDirectoryGuard(path.dirname(ioPath), { bigint: true });
|
|
638
|
+
assertRootIdentityCurrentSync(root);
|
|
639
|
+
if (!admitPathInsideRoot({
|
|
640
|
+
rootPath: root.rootReal, candidatePath: parentGuard.realPath, rootIdentity: root.rootIdentity,
|
|
641
|
+
}))
|
|
642
|
+
throw outsideWorkspaceError();
|
|
643
|
+
assertSyncDirectoryGuard(parentGuard);
|
|
644
|
+
return { missing: true, targetPath: ioPath, parentGuard, writeSelection: writePathSelection };
|
|
645
|
+
}
|
|
646
|
+
if (writePathSelection)
|
|
647
|
+
await refreshRootWritePathSelection(writePathSelection);
|
|
648
|
+
const nativeCreated = requireNative ? await createNative() : undefined;
|
|
649
|
+
if (nativeCreated)
|
|
650
|
+
handle = nativeCreated.handle;
|
|
651
|
+
else {
|
|
596
652
|
params.assertBeforeMutation?.();
|
|
597
653
|
if (writePathSelection)
|
|
598
654
|
assertRootWritePathSelectionSync(root, writePathSelection);
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
assertRootWritePathSelectionSync(root, writePathSelection);
|
|
608
|
-
// Windows can follow a dangling symlink even with O_EXCL.
|
|
609
|
-
if (!SUPPORTS_NOFOLLOW)
|
|
610
|
-
assertFinalSymlinkRejected(ioPath, true);
|
|
611
|
-
handle = await fs.open(ioPath, createFlags, mode);
|
|
655
|
+
// Windows can follow a dangling symlink even with O_EXCL.
|
|
656
|
+
if (!SUPPORTS_NOFOLLOW)
|
|
657
|
+
assertFinalSymlinkRejected(ioPath, true);
|
|
658
|
+
handle = await fs.open(ioPath, createFlags, mode);
|
|
659
|
+
}
|
|
660
|
+
cleanupCreated = nativeCreated?.cleanupCreated;
|
|
661
|
+
releaseCreationParent = nativeCreated?.releaseCreationParent;
|
|
662
|
+
createdForWrite = true;
|
|
612
663
|
}
|
|
613
|
-
cleanupCreated = nativeCreated?.cleanupCreated;
|
|
614
|
-
releaseCreationParent = nativeCreated?.releaseCreationParent;
|
|
615
|
-
createdForWrite = true;
|
|
616
664
|
}
|
|
617
665
|
}
|
|
618
666
|
catch (err) {
|
|
@@ -630,7 +678,6 @@ async function openWritableFileInRoot(root, params, options) {
|
|
|
630
678
|
let realPathForCleanup = null;
|
|
631
679
|
let createdIdentity = null;
|
|
632
680
|
try {
|
|
633
|
-
const stat = fsSync.fstatSync(handle.fd);
|
|
634
681
|
const identity = inspectFileIdentitySync(() => {
|
|
635
682
|
const observed = fsSync.fstatSync(handle.fd, { bigint: true });
|
|
636
683
|
if (!observed.isFile()) {
|
|
@@ -640,6 +687,7 @@ async function openWritableFileInRoot(root, params, options) {
|
|
|
640
687
|
throw hardlinkedPathNotAllowedError();
|
|
641
688
|
return observed;
|
|
642
689
|
});
|
|
690
|
+
const stat = numberStats(identity);
|
|
643
691
|
if (createdForWrite)
|
|
644
692
|
createdIdentity = identity;
|
|
645
693
|
let observedIoPath = false;
|
|
@@ -721,6 +769,7 @@ async function openWritableFileInRoot(root, params, options) {
|
|
|
721
769
|
createdForWrite,
|
|
722
770
|
realPath,
|
|
723
771
|
stat,
|
|
772
|
+
exactIdentity: exactFileIdentity(identity),
|
|
724
773
|
[Symbol.asyncDispose]: () => handle.close().catch(() => undefined),
|
|
725
774
|
};
|
|
726
775
|
if (!params.keepCreationParent)
|
|
@@ -851,6 +900,16 @@ async function mkdirPathInRoot(root, params) {
|
|
|
851
900
|
const policy = params.denyMutations === undefined && params.mutationSymlinks === undefined
|
|
852
901
|
? undefined
|
|
853
902
|
: snapshotPinnedMutationPolicy(params.denyMutations, params.mutationSymlinks);
|
|
903
|
+
if (requireNative && !privateMode && !policy && !params.assertBeforeMutation) {
|
|
904
|
+
if (params.allowRoot && params.relativePath === "") {
|
|
905
|
+
ensureNativeRootCurrent(root);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
if (tryMkdirNativeDirectChild(root, params.relativePath))
|
|
909
|
+
return;
|
|
910
|
+
if (tryMkdirNativeParents(root, params.relativePath))
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
854
913
|
const resolution = { relativePath: params.relativePath, allowRoot: params.allowRoot, ...policy };
|
|
855
914
|
const resolveCurrent = policy
|
|
856
915
|
? async () => await resolvePinnedPathInRoot(root, resolution)
|
|
@@ -897,7 +956,7 @@ async function writeFileInRoot(root, params) {
|
|
|
897
956
|
const input = rootWriteInput(params);
|
|
898
957
|
await serializePathWrite(rootWriteQueueKey(root, params.relativePath), async () => {
|
|
899
958
|
if (!params.private && input.kind === "buffer" && !input.stageBeforePublish && process.platform === "win32" &&
|
|
900
|
-
(params.renameIdentity === "verify-content-with-lock" || !
|
|
959
|
+
(params.renameIdentity === "verify-content-with-lock" || !getPinnedWriteNativeBinding({ input }))) {
|
|
901
960
|
await writeFileFallback(root, { ...params, data: input.data });
|
|
902
961
|
return;
|
|
903
962
|
}
|
|
@@ -965,93 +1024,6 @@ async function commitPinnedWriteInRoot(root, pinned, params, input) {
|
|
|
965
1024
|
throw normalizePinnedWriteError(error);
|
|
966
1025
|
}
|
|
967
1026
|
}
|
|
968
|
-
async function copyFileInRoot(root, params) {
|
|
969
|
-
params.signal?.throwIfAborted();
|
|
970
|
-
const clone = resolveFileCopyCloneMode(params.clone);
|
|
971
|
-
let source;
|
|
972
|
-
let sourceIdentity;
|
|
973
|
-
if (typeof params.source === "string") {
|
|
974
|
-
assertNoNulPathInput(params.source, "source path contains a NUL byte");
|
|
975
|
-
assertNoWindowsPathAlias(params.source, "filesystem", "source path uses a Windows filesystem namespace alias");
|
|
976
|
-
({ opened: source, identity: sourceIdentity } = await openVerifiedLocalFile(params.source, {
|
|
977
|
-
hardlinks: params.sourceHardlinks,
|
|
978
|
-
}));
|
|
979
|
-
}
|
|
980
|
-
else {
|
|
981
|
-
source = await params.source.root.open(params.source.relativePath, params.sourceHardlinks === undefined ? undefined : { hardlinks: params.sourceHardlinks });
|
|
982
|
-
try {
|
|
983
|
-
sourceIdentity = await inspectFileIdentity(() => fsSync.fstatSync(source.handle.fd, { bigint: true }));
|
|
984
|
-
}
|
|
985
|
-
catch (error) {
|
|
986
|
-
await source.handle.close().catch(() => undefined);
|
|
987
|
-
throw error;
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
if (params.maxBytes !== undefined && source.stat.size > params.maxBytes) {
|
|
991
|
-
await source.handle.close().catch(() => { });
|
|
992
|
-
throw new FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${source.stat.size})`);
|
|
993
|
-
}
|
|
994
|
-
try {
|
|
995
|
-
const sourceAdmission = params.admitSource?.(sourceIdentity, source.realPath);
|
|
996
|
-
const mode = sourceAdmission?.mode ?? params.mode;
|
|
997
|
-
await serializePathWrite(rootWriteQueueKey(root, params.relativePath), async () => {
|
|
998
|
-
const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, mode ?? (params.preserveSourceMode ? Number(sourceIdentity.mode & 4095n) : undefined), params.denyMutations, params.overwrite !== false, params.mutationSymlinks);
|
|
999
|
-
await serializePathWrite(pinned.targetPath, async () => {
|
|
1000
|
-
await assertCopySourceCurrent(source, sourceIdentity);
|
|
1001
|
-
const verifySource = async () => {
|
|
1002
|
-
params.signal?.throwIfAborted();
|
|
1003
|
-
try {
|
|
1004
|
-
sourceAdmission?.verify();
|
|
1005
|
-
}
|
|
1006
|
-
catch (error) {
|
|
1007
|
-
throw new MutationAuthorityError(error);
|
|
1008
|
-
}
|
|
1009
|
-
if (typeof params.source !== "string") {
|
|
1010
|
-
await params.source.root.stat(".");
|
|
1011
|
-
}
|
|
1012
|
-
await assertCopySourceCurrent(source, sourceIdentity);
|
|
1013
|
-
};
|
|
1014
|
-
const observer = createCopyPublicationObserver(pinned.targetPath, params.onDestinationPublished);
|
|
1015
|
-
try {
|
|
1016
|
-
await runPinnedWriteHelper({
|
|
1017
|
-
rootPath: pinned.rootReal,
|
|
1018
|
-
relativeParentPath: pinned.relativeParentPath,
|
|
1019
|
-
basename: pinned.basename,
|
|
1020
|
-
mkdir: params.mkdir !== false,
|
|
1021
|
-
mode: pinned.mode,
|
|
1022
|
-
overwrite: params.overwrite !== false,
|
|
1023
|
-
rejectFinalSymlink: params.mutationSymlinks !== undefined,
|
|
1024
|
-
maxBytes: params.maxBytes,
|
|
1025
|
-
sync: params.durable !== false,
|
|
1026
|
-
assertBeforeMutation: params.signal || params.assertBeforeMutation ? () => {
|
|
1027
|
-
if (params.signal?.aborted)
|
|
1028
|
-
throw new MutationAuthorityError(params.signal.reason);
|
|
1029
|
-
params.assertBeforeMutation?.();
|
|
1030
|
-
} : undefined,
|
|
1031
|
-
verifyPublished: params.verifyPublished,
|
|
1032
|
-
onPublished: observer.onPublished,
|
|
1033
|
-
input: { kind: "file", handle: source.handle, size: source.stat.size, clone, signal: params.signal, verifySource },
|
|
1034
|
-
rootIdentity: root.rootIdentity,
|
|
1035
|
-
mutationAdmission: pinned.mutationAdmission,
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
|
-
catch (error) {
|
|
1039
|
-
observer.rethrowObserverFailure(error);
|
|
1040
|
-
if (params.signal?.aborted && error === params.signal.reason)
|
|
1041
|
-
throw error;
|
|
1042
|
-
if (isAlreadyExistsError(error)) {
|
|
1043
|
-
throw new FsSafeError("already-exists", "copy destination already exists", { cause: error });
|
|
1044
|
-
}
|
|
1045
|
-
throw normalizePinnedWriteError(error);
|
|
1046
|
-
}
|
|
1047
|
-
await verifySource();
|
|
1048
|
-
});
|
|
1049
|
-
});
|
|
1050
|
-
}
|
|
1051
|
-
finally {
|
|
1052
|
-
await source.handle.close().catch(() => { });
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
1027
|
async function resolvePinnedPathInRoot(root, params) {
|
|
1056
1028
|
const resolved = await resolvePinnedRootPathInRoot(root, {
|
|
1057
1029
|
relativePath: params.relativePath,
|
|
@@ -1203,10 +1175,15 @@ async function movePathFallback(root, params) {
|
|
|
1203
1175
|
}
|
|
1204
1176
|
const guardOptions = { bigint: sourceIdentity !== undefined };
|
|
1205
1177
|
const sourceParentGuard = await createAsyncDirectoryGuard(path.dirname(source.resolved), guardOptions);
|
|
1206
|
-
const targetParentGuard =
|
|
1207
|
-
|
|
1178
|
+
const targetParentGuard = path.dirname(target.resolved) === sourceParentGuard.dir
|
|
1179
|
+
? sourceParentGuard
|
|
1180
|
+
: await createNearestExistingDirectoryGuard(target.rootReal, path.dirname(target.resolved), guardOptions);
|
|
1181
|
+
const beforeMutation = getFsSafeTestHooks()?.beforeRootFallbackMutation;
|
|
1182
|
+
if (beforeMutation)
|
|
1183
|
+
await beforeMutation("move", target.resolved);
|
|
1208
1184
|
await assertAsyncDirectoryGuard(sourceParentGuard);
|
|
1209
|
-
|
|
1185
|
+
if (targetParentGuard !== sourceParentGuard)
|
|
1186
|
+
await assertAsyncDirectoryGuard(targetParentGuard);
|
|
1210
1187
|
try {
|
|
1211
1188
|
assertFinalSymlinkRejected(source.resolved, params.mutationSymlinks !== undefined);
|
|
1212
1189
|
assertFinalSymlinkRejected(target.resolved, params.mutationSymlinks !== undefined);
|
|
@@ -1214,7 +1191,8 @@ async function movePathFallback(root, params) {
|
|
|
1214
1191
|
if (sourceIdentity) {
|
|
1215
1192
|
assertRootIdentityCurrentSync(root);
|
|
1216
1193
|
assertSyncDirectoryGuard(sourceParentGuard);
|
|
1217
|
-
|
|
1194
|
+
if (targetParentGuard !== sourceParentGuard)
|
|
1195
|
+
assertSyncDirectoryGuard(targetParentGuard);
|
|
1218
1196
|
for (const [route, selected, expected, policy] of [
|
|
1219
1197
|
[originalRoutes[0], source.resolved, pinnedSource.canonicalPath, PATH_ALIAS_POLICIES.strict],
|
|
1220
1198
|
[originalRoutes[1], target.resolved, pinnedTarget.canonicalPath, PATH_ALIAS_POLICIES.unlinkTarget],
|
|
@@ -1249,7 +1227,8 @@ async function movePathFallback(root, params) {
|
|
|
1249
1227
|
}
|
|
1250
1228
|
try {
|
|
1251
1229
|
await assertAsyncDirectoryGuard(sourceParentGuard);
|
|
1252
|
-
|
|
1230
|
+
if (targetParentGuard !== sourceParentGuard)
|
|
1231
|
+
await assertAsyncDirectoryGuard(targetParentGuard);
|
|
1253
1232
|
}
|
|
1254
1233
|
catch (error) {
|
|
1255
1234
|
throw normalizePinnedPathError(error);
|