@openclaw/fs-safe 0.12.0 → 0.13.1
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 +73 -0
- package/README.md +12 -7
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +32 -11
- package/dist/advanced.d.ts +2 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +2 -0
- package/dist/archive-input.d.ts.map +1 -1
- package/dist/archive-input.js +6 -2
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +15 -2
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +7 -19
- package/dist/archive-plan.js +1 -1
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +18 -13
- package/dist/archive-staging.d.ts.map +1 -1
- package/dist/archive-staging.js +43 -10
- package/dist/archive-tar-inspect.d.ts.map +1 -1
- package/dist/archive-tar-inspect.js +4 -1
- package/dist/archive-zip-admission.d.ts +1 -1
- package/dist/archive-zip-admission.d.ts.map +1 -1
- package/dist/archive-zip-admission.js +2 -2
- package/dist/archive-zip-directory.d.ts +3 -0
- package/dist/archive-zip-directory.d.ts.map +1 -1
- package/dist/archive-zip-directory.js +13 -2
- package/dist/archive-zip-loader.d.ts +3 -2
- package/dist/archive-zip-loader.d.ts.map +1 -1
- package/dist/archive-zip-loader.js +30 -4
- package/dist/archive-zip-manifest.d.ts +5 -0
- package/dist/archive-zip-manifest.d.ts.map +1 -0
- package/dist/archive-zip-manifest.js +22 -0
- package/dist/archive-zip-names.d.ts +6 -1
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +35 -14
- package/dist/archive-zip-preflight.d.ts.map +1 -1
- package/dist/archive-zip-preflight.js +3 -2
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +9 -4
- package/dist/copy-file-input.d.ts +1 -1
- package/dist/copy-file-input.d.ts.map +1 -1
- package/dist/copy-file-input.js +2 -0
- package/dist/darwin-acl.d.ts +4 -0
- package/dist/darwin-acl.d.ts.map +1 -0
- package/dist/darwin-acl.js +24 -0
- package/dist/deny-mutations.d.ts.map +1 -1
- package/dist/deny-mutations.js +8 -2
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-durability.js +67 -23
- package/dist/directory-entry-path.d.ts +3 -0
- package/dist/directory-entry-path.d.ts.map +1 -0
- package/dist/directory-entry-path.js +21 -0
- package/dist/directory-guard.d.ts +17 -1
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-guard.js +134 -48
- package/dist/directory-mode-node.d.ts +12 -0
- package/dist/directory-mode-node.d.ts.map +1 -1
- package/dist/directory-mode-node.js +102 -4
- package/dist/effective-uid.d.ts +2 -0
- package/dist/effective-uid.d.ts.map +1 -0
- package/dist/effective-uid.js +25 -0
- package/dist/file-handle-transfer.d.ts.map +1 -1
- package/dist/file-handle-transfer.js +98 -27
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +3 -0
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +36 -6
- package/dist/file-lock.d.ts.map +1 -1
- package/dist/file-lock.js +29 -9
- package/dist/file-observation.d.ts +1 -1
- package/dist/file-observation.d.ts.map +1 -1
- package/dist/file-store-boundary.d.ts +6 -2
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +20 -65
- package/dist/file-store-copy-source.d.ts +5 -0
- package/dist/file-store-copy-source.d.ts.map +1 -0
- package/dist/file-store-copy-source.js +31 -0
- package/dist/file-store-path.d.ts.map +1 -1
- package/dist/file-store-path.js +4 -1
- package/dist/file-store-sync-directory.d.ts +16 -0
- package/dist/file-store-sync-directory.d.ts.map +1 -0
- package/dist/file-store-sync-directory.js +349 -0
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +11 -28
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +65 -20
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +3 -2
- package/dist/guarded-mkdir.d.ts +8 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +176 -27
- package/dist/guest.d.ts.map +1 -1
- package/dist/guest.js +4 -1
- package/dist/home-dir.d.ts.map +1 -1
- package/dist/home-dir.js +73 -10
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +54 -19
- package/dist/json-durable-queue-ownership.d.ts +6 -0
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +89 -42
- package/dist/json-durable-queue-paths.d.ts +11 -0
- package/dist/json-durable-queue-paths.d.ts.map +1 -0
- package/dist/json-durable-queue-paths.js +42 -0
- package/dist/json-durable-queue-read.d.ts.map +1 -1
- package/dist/json-durable-queue-read.js +2 -0
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +50 -58
- package/dist/json-store.d.ts.map +1 -1
- package/dist/json-store.js +5 -1
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +54 -22
- package/dist/local-file-access.d.ts.map +1 -1
- package/dist/local-file-access.js +4 -0
- package/dist/local-file-descriptor.d.ts +17 -0
- package/dist/local-file-descriptor.d.ts.map +1 -0
- package/dist/local-file-descriptor.js +84 -0
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +35 -7
- package/dist/move-path-cleanup.d.ts +2 -0
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +44 -18
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +31 -6
- package/dist/native-binding.d.ts +17 -0
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-binding.js +8 -1
- package/dist/native-directory-observation.d.ts +17 -0
- package/dist/native-directory-observation.d.ts.map +1 -0
- package/dist/native-directory-observation.js +37 -0
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +6 -4
- package/dist/native-parent-admission.d.ts +32 -0
- package/dist/native-parent-admission.d.ts.map +1 -0
- package/dist/native-parent-admission.js +127 -0
- package/dist/native-pinned-write-windows.d.ts +0 -1
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +8 -9
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +314 -42
- package/dist/native-staged-file.d.ts +4 -4
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +20 -10
- package/dist/native.d.ts +1 -1
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +7 -2
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +15 -5
- package/dist/overwrite-file-handle.d.ts.map +1 -1
- package/dist/overwrite-file-handle.js +5 -1
- package/dist/owner-dacl.d.ts.map +1 -1
- package/dist/owner-dacl.js +2 -0
- package/dist/path-policy.d.ts.map +1 -1
- package/dist/path-policy.js +7 -2
- package/dist/path-prefix.d.ts +7 -0
- package/dist/path-prefix.d.ts.map +1 -0
- package/dist/path-prefix.js +82 -0
- package/dist/path-scope-lexical.d.ts.map +1 -1
- package/dist/path-scope-lexical.js +18 -8
- package/dist/path-segment-route.d.ts +7 -0
- package/dist/path-segment-route.d.ts.map +1 -0
- package/dist/path-segment-route.js +24 -0
- package/dist/path-suffix-aliases.d.ts +10 -0
- package/dist/path-suffix-aliases.d.ts.map +1 -0
- package/dist/path-suffix-aliases.js +386 -0
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +16 -5
- package/dist/permissions-windows.d.ts.map +1 -1
- package/dist/permissions-windows.js +14 -3
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +37 -8
- package/dist/pinned-mutation-admission.d.ts +25 -0
- package/dist/pinned-mutation-admission.d.ts.map +1 -0
- package/dist/pinned-mutation-admission.js +425 -0
- package/dist/pinned-mutation-observation.d.ts +34 -0
- package/dist/pinned-mutation-observation.d.ts.map +1 -0
- package/dist/pinned-mutation-observation.js +142 -0
- package/dist/pinned-mutation-shared-route.d.ts +24 -0
- package/dist/pinned-mutation-shared-route.d.ts.map +1 -0
- package/dist/pinned-mutation-shared-route.js +70 -0
- package/dist/pinned-open.d.ts +6 -0
- package/dist/pinned-open.d.ts.map +1 -1
- package/dist/pinned-open.js +28 -10
- package/dist/pinned-write-types.d.ts +75 -0
- package/dist/pinned-write-types.d.ts.map +1 -0
- package/dist/pinned-write-types.js +1 -0
- package/dist/pinned-write.d.ts +7 -33
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +151 -17
- package/dist/private-directory.d.ts.map +1 -1
- package/dist/private-directory.js +2 -0
- package/dist/private-producer-handoff.d.ts +16 -0
- package/dist/private-producer-handoff.d.ts.map +1 -0
- package/dist/private-producer-handoff.js +272 -0
- package/dist/private-temp-workspace.d.ts +2 -39
- package/dist/private-temp-workspace.d.ts.map +1 -1
- package/dist/private-temp-workspace.js +183 -77
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +38 -32
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +56 -45
- package/dist/replace-directory.d.ts.map +1 -1
- package/dist/replace-directory.js +12 -5
- package/dist/replace-file-temp-owner.d.ts +1 -0
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +12 -1
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +24 -24
- package/dist/root-boundary.d.ts +4 -0
- package/dist/root-boundary.d.ts.map +1 -1
- package/dist/root-boundary.js +6 -1
- package/dist/root-context.d.ts +12 -1
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +57 -11
- package/dist/root-directory-creation.d.ts +13 -0
- package/dist/root-directory-creation.d.ts.map +1 -0
- package/dist/root-directory-creation.js +212 -0
- package/dist/root-directory-list.d.ts +16 -4
- package/dist/root-directory-list.d.ts.map +1 -1
- package/dist/root-directory-list.js +180 -39
- package/dist/root-directory.d.ts +23 -0
- package/dist/root-directory.d.ts.map +1 -0
- package/dist/root-directory.js +141 -0
- package/dist/root-errors.d.ts.map +1 -1
- package/dist/root-errors.js +12 -1
- package/dist/root-file-final-admission.d.ts +21 -0
- package/dist/root-file-final-admission.d.ts.map +1 -0
- package/dist/root-file-final-admission.js +83 -0
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +103 -24
- package/dist/root-impl.d.ts +1 -0
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +289 -317
- package/dist/root-move-noreplace.d.ts +14 -0
- package/dist/root-move-noreplace.d.ts.map +1 -0
- package/dist/root-move-noreplace.js +202 -0
- package/dist/root-observed-path.d.ts +9 -0
- package/dist/root-observed-path.d.ts.map +1 -0
- package/dist/root-observed-path.js +95 -0
- package/dist/root-path-errors.d.ts +12 -0
- package/dist/root-path-errors.d.ts.map +1 -0
- package/dist/root-path-errors.js +13 -0
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +53 -20
- package/dist/root-path-observation.d.ts +63 -0
- package/dist/root-path-observation.d.ts.map +1 -0
- package/dist/root-path-observation.js +180 -0
- package/dist/root-path-stat.d.ts +5 -0
- package/dist/root-path-stat.d.ts.map +1 -0
- package/dist/root-path-stat.js +101 -0
- package/dist/root-path-symlink.d.ts.map +1 -1
- package/dist/root-path-symlink.js +23 -4
- package/dist/root-path.d.ts +11 -0
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +215 -53
- package/dist/root-paths-lexical.d.ts +9 -0
- package/dist/root-paths-lexical.d.ts.map +1 -0
- package/dist/root-paths-lexical.js +22 -0
- package/dist/root-paths.d.ts +3 -25
- package/dist/root-paths.d.ts.map +1 -1
- package/dist/root-paths.js +77 -154
- package/dist/root-read-admission.d.ts +26 -0
- package/dist/root-read-admission.d.ts.map +1 -0
- package/dist/root-read-admission.js +94 -0
- package/dist/root-remove-identity.d.ts +15 -0
- package/dist/root-remove-identity.d.ts.map +1 -0
- package/dist/root-remove-identity.js +89 -0
- package/dist/root-remove-receipt.d.ts +17 -0
- package/dist/root-remove-receipt.d.ts.map +1 -0
- package/dist/root-remove-receipt.js +37 -0
- package/dist/root-remove.d.ts +2 -1
- package/dist/root-remove.d.ts.map +1 -1
- package/dist/root-remove.js +172 -10
- package/dist/root-write-admission.d.ts +68 -0
- package/dist/root-write-admission.d.ts.map +1 -0
- package/dist/root-write-admission.js +322 -0
- package/dist/root-write-compatibility.d.ts +13 -0
- package/dist/root-write-compatibility.d.ts.map +1 -0
- package/dist/root-write-compatibility.js +74 -0
- package/dist/root-write-complete-parent.d.ts +42 -0
- package/dist/root-write-complete-parent.d.ts.map +1 -0
- package/dist/root-write-complete-parent.js +195 -0
- package/dist/root-write-publication.d.ts +24 -0
- package/dist/root-write-publication.d.ts.map +1 -0
- package/dist/root-write-publication.js +85 -0
- package/dist/root-write-verification.d.ts.map +1 -1
- package/dist/root-write-verification.js +6 -4
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +62 -24
- package/dist/secret-read-async.d.ts.map +1 -1
- package/dist/secret-read-async.js +18 -13
- package/dist/secret-read-policy.d.ts.map +1 -1
- package/dist/secret-read-policy.js +5 -1
- package/dist/secure-file.d.ts.map +1 -1
- package/dist/secure-file.js +92 -7
- package/dist/secure-temp-dir.d.ts +6 -3
- package/dist/secure-temp-dir.d.ts.map +1 -1
- package/dist/secure-temp-dir.js +121 -101
- package/dist/secure-temp-repair.d.ts +35 -0
- package/dist/secure-temp-repair.d.ts.map +1 -0
- package/dist/secure-temp-repair.js +106 -0
- package/dist/sibling-staged-file.d.ts +3 -2
- package/dist/sibling-staged-file.d.ts.map +1 -1
- package/dist/sibling-staged-file.js +179 -55
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +27 -13
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +44 -14
- package/dist/sidecar-lock-root.d.ts.map +1 -1
- package/dist/sidecar-lock-root.js +4 -2
- package/dist/staged-directory.d.ts +14 -5
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/staged-directory.js +54 -3
- package/dist/standalone-publication-path.d.ts +2 -0
- package/dist/standalone-publication-path.d.ts.map +1 -0
- package/dist/standalone-publication-path.js +6 -0
- package/dist/stat-observation.d.ts +11 -0
- package/dist/stat-observation.d.ts.map +1 -0
- package/dist/stat-observation.js +64 -0
- package/dist/strict-file-identity.d.ts.map +1 -1
- package/dist/strict-file-identity.js +39 -2
- package/dist/symlink-parents.d.ts.map +1 -1
- package/dist/symlink-parents.js +7 -2
- package/dist/temp-target.d.ts +2 -0
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +130 -3
- package/dist/temp-workspace-admission.d.ts +22 -0
- package/dist/temp-workspace-admission.d.ts.map +1 -0
- package/dist/temp-workspace-admission.js +374 -0
- package/dist/temp-workspace-child-admission.d.ts +13 -0
- package/dist/temp-workspace-child-admission.d.ts.map +1 -0
- package/dist/temp-workspace-child-admission.js +95 -0
- package/dist/temp-workspace-descriptor.d.ts +48 -0
- package/dist/temp-workspace-descriptor.d.ts.map +1 -0
- package/dist/temp-workspace-descriptor.js +363 -0
- package/dist/temp-workspace-identity.d.ts +15 -0
- package/dist/temp-workspace-identity.d.ts.map +1 -0
- package/dist/temp-workspace-identity.js +41 -0
- package/dist/temp-workspace-owner.d.ts +7 -6
- package/dist/temp-workspace-owner.d.ts.map +1 -1
- package/dist/temp-workspace-owner.js +121 -61
- package/dist/temp-workspace-permissions.d.ts +4 -0
- package/dist/temp-workspace-permissions.d.ts.map +1 -0
- package/dist/temp-workspace-permissions.js +32 -0
- package/dist/temp-workspace-types.d.ts +40 -0
- package/dist/temp-workspace-types.d.ts.map +1 -0
- package/dist/temp-workspace-types.js +1 -0
- package/dist/temp.d.ts +1 -1
- package/dist/temp.d.ts.map +1 -1
- package/dist/temp.js +1 -1
- package/dist/test-hooks.d.ts +7 -0
- package/dist/test-hooks.d.ts.map +1 -1
- package/dist/text-atomic.d.ts.map +1 -1
- package/dist/text-atomic.js +3 -1
- package/dist/trash.d.ts.map +1 -1
- package/dist/trash.js +54 -8
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +9 -6
- package/dist/windows-owner.d.ts.map +1 -1
- package/dist/windows-owner.js +5 -0
- package/dist/windows-path-alias.d.ts +39 -0
- package/dist/windows-path-alias.d.ts.map +1 -0
- package/dist/windows-path-alias.js +153 -0
- package/docs/advanced.md +25 -0
- package/docs/archive.md +23 -2
- package/docs/atomic.md +27 -3
- package/docs/copy.md +3 -0
- package/docs/durability.md +14 -0
- package/docs/errors.md +14 -6
- package/docs/file-store.md +24 -3
- package/docs/filename.md +14 -7
- package/docs/install-path.md +2 -2
- package/docs/install.md +8 -7
- package/docs/json-store.md +5 -1
- package/docs/json.md +11 -0
- package/docs/mutation-policy-proof.md +65 -0
- package/docs/native-helper.md +41 -11
- package/docs/native.md +32 -8
- package/docs/output.md +33 -11
- package/docs/path-prefix.md +64 -0
- package/docs/path-suffix-aliases.md +159 -0
- package/docs/path.md +11 -0
- package/docs/private-file-store.md +14 -0
- package/docs/public-api.md +9 -0
- package/docs/quickstart.md +1 -1
- package/docs/reading.md +8 -1
- package/docs/root.md +18 -3
- package/docs/secret-file.md +3 -0
- package/docs/secure-file.md +6 -2
- package/docs/security-model.md +75 -8
- package/docs/sidecar-lock.md +28 -1
- package/docs/store.md +5 -1
- package/docs/temp.md +260 -36
- package/docs/test-hooks.md +14 -0
- package/docs/writing.md +38 -8
- package/package.json +10 -10
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type DenyMutationPolicy } from "./deny-mutations.js";
|
|
2
|
+
import { type RootContext } from "./root-context.js";
|
|
3
|
+
import { type MutationSymlinkPolicy } from "./root-symlink-policy.js";
|
|
4
|
+
export declare function movePathNoReplaceNative(root: RootContext, params: {
|
|
5
|
+
assertBeforeMutation?: () => void;
|
|
6
|
+
denyMutations?: DenyMutationPolicy;
|
|
7
|
+
mutationSymlinks?: MutationSymlinkPolicy;
|
|
8
|
+
}, paths: {
|
|
9
|
+
sourcePath: string;
|
|
10
|
+
sourceParentPath: string;
|
|
11
|
+
targetPath: string;
|
|
12
|
+
targetParentPath: string;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=root-move-noreplace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-move-noreplace.d.ts","sourceRoot":"","sources":["../src/root-move-noreplace.ts"],"names":[],"mappings":"AAIA,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AASvF,OAAO,EAA4D,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAU/G,OAAO,EAA8B,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAqDlG,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE;IACN,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;CAC1C,EACD,KAAK,EAAE;IACL,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GACA,OAAO,CAAC,IAAI,CAAC,CA0If"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import fsSync, {} from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { assertAsyncDirectoryGuard, assertSyncDirectoryGuard } from "./directory-guard.js";
|
|
4
|
+
import { FsSafeError } from "./errors.js";
|
|
5
|
+
import { assertMutationNotDenied } from "./deny-mutations.js";
|
|
6
|
+
import { closeNativeParentAdmission, openNativeParentAdmission, openNativeRootAdmission, } from "./native-parent-admission.js";
|
|
7
|
+
import { getNativeBinding } from "./native.js";
|
|
8
|
+
import { isNotFoundPathError } from "./path.js";
|
|
9
|
+
import { assertRootIdentityCurrent, assertRootIdentityCurrentSync } from "./root-context.js";
|
|
10
|
+
import { resolveRootPathSync } from "./root-path.js";
|
|
11
|
+
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
12
|
+
import { fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, outsideWorkspaceError, } from "./root-errors.js";
|
|
13
|
+
import { assertFinalSymlinkRejected } from "./root-symlink-policy.js";
|
|
14
|
+
import { createSuppressedError } from "./suppressed-error.js";
|
|
15
|
+
import { getFsSafeTestHooks } from "./test-hooks.js";
|
|
16
|
+
function nativeParentRelativePath(rootReal, parentPath) {
|
|
17
|
+
const relative = path.relative(rootReal, parentPath);
|
|
18
|
+
if (relative === "" || relative === ".")
|
|
19
|
+
return "";
|
|
20
|
+
const firstSegment = relative.split(path.sep)[0];
|
|
21
|
+
if (firstSegment === ".." ||
|
|
22
|
+
path.isAbsolute(relative)) {
|
|
23
|
+
throw outsideWorkspaceError();
|
|
24
|
+
}
|
|
25
|
+
return relative.split(path.sep).join(path.posix.sep);
|
|
26
|
+
}
|
|
27
|
+
function admitMovePath(root, parent, basename) {
|
|
28
|
+
const admitted = admitPathInsideRoot({
|
|
29
|
+
rootPath: root.rootReal,
|
|
30
|
+
candidatePath: path.join(parent.guard.realPath, basename),
|
|
31
|
+
rootIdentity: root.rootIdentity,
|
|
32
|
+
});
|
|
33
|
+
if (!admitted)
|
|
34
|
+
throw outsideWorkspaceError();
|
|
35
|
+
return admitted.path;
|
|
36
|
+
}
|
|
37
|
+
function nativePrimitiveUnavailable(error) {
|
|
38
|
+
const code = error?.code;
|
|
39
|
+
return code === "ENOSYS" || code === "ENOTSUP" || code === "EOPNOTSUPP";
|
|
40
|
+
}
|
|
41
|
+
function normalizeMoveError(error) {
|
|
42
|
+
if (isNotFoundPathError(error)) {
|
|
43
|
+
return fileNotFoundError(error instanceof Error ? error : undefined);
|
|
44
|
+
}
|
|
45
|
+
if (nativePrimitiveUnavailable(error)) {
|
|
46
|
+
return new FsSafeError("helper-unavailable", "native no-replace move is unavailable", {
|
|
47
|
+
cause: error instanceof Error ? error : undefined,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return error;
|
|
51
|
+
}
|
|
52
|
+
function normalizeRenameNoReplaceError(error) {
|
|
53
|
+
if (error?.code === "EINVAL") {
|
|
54
|
+
return new FsSafeError("helper-unavailable", "native no-replace move is unavailable on this filesystem", {
|
|
55
|
+
cause: error instanceof Error ? error : undefined,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return normalizeMoveError(error);
|
|
59
|
+
}
|
|
60
|
+
export async function movePathNoReplaceNative(root, params, paths) {
|
|
61
|
+
try {
|
|
62
|
+
fsSync.lstatSync(paths.targetPath);
|
|
63
|
+
throw new FsSafeError("already-exists", "destination exists");
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof FsSafeError)
|
|
67
|
+
throw error;
|
|
68
|
+
if (!isNotFoundPathError(error))
|
|
69
|
+
throw error;
|
|
70
|
+
// Advisory fast rejection only. renameNoReplace owns the collision decision.
|
|
71
|
+
}
|
|
72
|
+
const binding = getNativeBinding();
|
|
73
|
+
if (!binding || typeof binding.renameNoReplace !== "function") {
|
|
74
|
+
throw new FsSafeError("helper-unavailable", "native no-replace move is unavailable");
|
|
75
|
+
}
|
|
76
|
+
const rootAdmission = await openNativeRootAdmission(binding, {
|
|
77
|
+
rootPath: root.rootReal,
|
|
78
|
+
rootIdentity: root.rootIdentity,
|
|
79
|
+
operation: "native move",
|
|
80
|
+
});
|
|
81
|
+
let sourceParent;
|
|
82
|
+
let targetParent;
|
|
83
|
+
let failed = false;
|
|
84
|
+
let operationError;
|
|
85
|
+
try {
|
|
86
|
+
const sourceParentRelativePath = nativeParentRelativePath(root.rootReal, paths.sourceParentPath);
|
|
87
|
+
sourceParent = await openNativeParentAdmission(binding, rootAdmission, sourceParentRelativePath);
|
|
88
|
+
const targetParentRelativePath = nativeParentRelativePath(root.rootReal, paths.targetParentPath);
|
|
89
|
+
targetParent = targetParentRelativePath === sourceParentRelativePath
|
|
90
|
+
? sourceParent
|
|
91
|
+
: await openNativeParentAdmission(binding, rootAdmission, targetParentRelativePath);
|
|
92
|
+
const parentAdmissions = targetParent === sourceParent
|
|
93
|
+
? [sourceParent]
|
|
94
|
+
: [sourceParent, targetParent];
|
|
95
|
+
await getFsSafeTestHooks()?.beforeRootFallbackMutation?.("move", paths.targetPath);
|
|
96
|
+
const admittedSourcePath = admitMovePath(root, sourceParent, path.basename(paths.sourcePath));
|
|
97
|
+
const admittedTargetPath = admitMovePath(root, targetParent, path.basename(paths.targetPath));
|
|
98
|
+
if (params.denyMutations) {
|
|
99
|
+
// Native admission can follow a newly introduced contained parent alias.
|
|
100
|
+
// Authorize the selected names, then recheck every retained directory.
|
|
101
|
+
await assertMutationNotDenied(admittedSourcePath, params.denyMutations, { protectAncestors: true });
|
|
102
|
+
await assertMutationNotDenied(admittedTargetPath, params.denyMutations, { protectAncestors: true });
|
|
103
|
+
}
|
|
104
|
+
await assertRootIdentityCurrent(root);
|
|
105
|
+
for (const admission of parentAdmissions)
|
|
106
|
+
assertSyncDirectoryGuard(admission.guard);
|
|
107
|
+
let sourceStat;
|
|
108
|
+
try {
|
|
109
|
+
sourceStat = fsSync.lstatSync(admittedSourcePath);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
throw normalizeMoveError(error);
|
|
113
|
+
}
|
|
114
|
+
if (sourceStat.isSymbolicLink()) {
|
|
115
|
+
throw new FsSafeError("symlink", "symlink not allowed");
|
|
116
|
+
}
|
|
117
|
+
if (sourceStat.isFile() && sourceStat.nlink > 1) {
|
|
118
|
+
throw hardlinkedPathNotAllowedError();
|
|
119
|
+
}
|
|
120
|
+
if (sourceStat.isDirectory()) {
|
|
121
|
+
throw new FsSafeError("invalid-path", "directory moves require overwrite: true");
|
|
122
|
+
}
|
|
123
|
+
assertFinalSymlinkRejected(admittedTargetPath, params.mutationSymlinks !== undefined);
|
|
124
|
+
params.assertBeforeMutation?.();
|
|
125
|
+
if (params.assertBeforeMutation || params.mutationSymlinks === "reject") {
|
|
126
|
+
// Do not carry directory freshness across the live authority callback.
|
|
127
|
+
assertRootIdentityCurrentSync(root);
|
|
128
|
+
if (params.mutationSymlinks === "reject") {
|
|
129
|
+
// Validate both full pre-native routes; selected canonical names have
|
|
130
|
+
// already erased any parent symlink followed during admission.
|
|
131
|
+
for (const absolutePath of [paths.sourcePath, paths.targetPath]) {
|
|
132
|
+
resolveRootPathSync({
|
|
133
|
+
absolutePath,
|
|
134
|
+
rootPath: root.rootReal,
|
|
135
|
+
rootCanonicalPath: root.rootReal,
|
|
136
|
+
rootIdentity: root.rootIdentity,
|
|
137
|
+
boundaryLabel: "root",
|
|
138
|
+
rejectSymlinks: true,
|
|
139
|
+
rejectFinalSymlink: true,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const admission of parentAdmissions)
|
|
144
|
+
assertSyncDirectoryGuard(admission.guard);
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
binding.renameNoReplace(sourceParent.fd, path.basename(paths.sourcePath), targetParent.fd, path.basename(paths.targetPath));
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (isAlreadyExistsError(error) || error?.code === "ENOTEMPTY") {
|
|
151
|
+
throw new FsSafeError("already-exists", "destination exists", {
|
|
152
|
+
cause: error instanceof Error ? error : undefined,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
throw normalizeRenameNoReplaceError(error);
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
for (const admission of parentAdmissions)
|
|
159
|
+
await assertAsyncDirectoryGuard(admission.guard);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
throw normalizePinnedPathError(error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
failed = true;
|
|
167
|
+
operationError = normalizeMoveError(error);
|
|
168
|
+
}
|
|
169
|
+
const closeErrors = [];
|
|
170
|
+
const closedFds = new Set();
|
|
171
|
+
for (const admission of [targetParent, sourceParent]) {
|
|
172
|
+
if (!admission || closedFds.has(admission.fd))
|
|
173
|
+
continue;
|
|
174
|
+
closedFds.add(admission.fd);
|
|
175
|
+
try {
|
|
176
|
+
closeNativeParentAdmission(admission);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
closeErrors.push(error);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
await rootAdmission.root.close();
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
closeErrors.push(error);
|
|
187
|
+
}
|
|
188
|
+
if (failed) {
|
|
189
|
+
if (closeErrors.length > 0) {
|
|
190
|
+
const closeError = closeErrors.length === 1
|
|
191
|
+
? closeErrors[0]
|
|
192
|
+
: new AggregateError(closeErrors, "native move descriptor closes failed");
|
|
193
|
+
throw createSuppressedError(closeError, operationError, "native move and descriptor close failed");
|
|
194
|
+
}
|
|
195
|
+
throw operationError;
|
|
196
|
+
}
|
|
197
|
+
if (closeErrors.length === 1)
|
|
198
|
+
throw closeErrors[0];
|
|
199
|
+
if (closeErrors.length > 1) {
|
|
200
|
+
throw new AggregateError(closeErrors, "native move descriptor closes failed");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type RootPathObservationKind, type RootPathObservationReceipt } from "./root-path.js";
|
|
2
|
+
import { type RootContext } from "./root-context.js";
|
|
3
|
+
export type PinnedObservedPath = {
|
|
4
|
+
rootReal: string;
|
|
5
|
+
resolved: string;
|
|
6
|
+
receipt?: RootPathObservationReceipt;
|
|
7
|
+
};
|
|
8
|
+
export declare function resolvePinnedObservedPathInRoot(root: RootContext, relativePath: string, kind: RootPathObservationKind): Promise<PinnedObservedPath | undefined>;
|
|
9
|
+
//# sourceMappingURL=root-observed-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-observed-path.d.ts","sourceRoot":"","sources":["../src/root-observed-path.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAChC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,0BAA0B,CAAC;CACtC,CAAC;AAEF,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAgFzC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { FsSafeError } from "./errors.js";
|
|
3
|
+
import { getNativeDirectoryObservationBackend } from "./native-directory-observation.js";
|
|
4
|
+
import { isNotFoundPathError } from "./path.js";
|
|
5
|
+
import { PATH_ALIAS_POLICIES } from "./path-policy.js";
|
|
6
|
+
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
7
|
+
import { assertRootPathObservationReceiptCurrent } from "./root-directory-list.js";
|
|
8
|
+
import { RootPathObservationError, resolveRootPathWithObservation, } from "./root-path.js";
|
|
9
|
+
import { createRootObservationGuard, ensureTrailingSep, expandRelativePathWithHome, } from "./root-context.js";
|
|
10
|
+
import { fileNotFoundError, outsideWorkspaceError } from "./root-errors.js";
|
|
11
|
+
import { getFsSafeTestHooks } from "./test-hooks.js";
|
|
12
|
+
export async function resolvePinnedObservedPathInRoot(root, relativePath, kind) {
|
|
13
|
+
const rootGuard = await createRootObservationGuard(root);
|
|
14
|
+
if (!rootGuard)
|
|
15
|
+
return undefined;
|
|
16
|
+
// Race hooks exercise the established JavaScript observation points. Do not
|
|
17
|
+
// silently move those points into the native helper in test configurations.
|
|
18
|
+
const directoryObserver = getNativeDirectoryObservationBackend(getFsSafeTestHooks() === undefined);
|
|
19
|
+
const rootReal = root.rootReal;
|
|
20
|
+
let observed;
|
|
21
|
+
try {
|
|
22
|
+
const expandedPath = await expandRelativePathWithHome(relativePath);
|
|
23
|
+
const observationPath = process.platform === "win32"
|
|
24
|
+
? expandedPath.replaceAll("/", path.sep)
|
|
25
|
+
: expandedPath;
|
|
26
|
+
observed = await resolveRootPathWithObservation({
|
|
27
|
+
absolutePath: path.isAbsolute(observationPath)
|
|
28
|
+
? observationPath
|
|
29
|
+
: observationPath === ""
|
|
30
|
+
? rootReal
|
|
31
|
+
: `${ensureTrailingSep(rootReal)}${observationPath}`,
|
|
32
|
+
rootPath: rootReal,
|
|
33
|
+
rootCanonicalPath: rootReal,
|
|
34
|
+
rootIdentity: root.rootIdentity,
|
|
35
|
+
boundaryLabel: "root",
|
|
36
|
+
policy: PATH_ALIAS_POLICIES.strict,
|
|
37
|
+
}, { kind, rootGuard, directoryObserver });
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error instanceof RootPathObservationError) {
|
|
41
|
+
if (error.parentReceipt) {
|
|
42
|
+
assertRootPathObservationReceiptCurrent(root, error.parentReceipt);
|
|
43
|
+
if (error.traversalFailure && !isNotFoundPathError(error.error)) {
|
|
44
|
+
if (error.error instanceof FsSafeError && error.error.code === "symlink")
|
|
45
|
+
throw error.error;
|
|
46
|
+
throw new FsSafeError("path-alias", "path alias escape blocked", { cause: error.error });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (isNotFoundPathError(error.error)) {
|
|
50
|
+
if (kind === "stat") {
|
|
51
|
+
throw fileNotFoundError(error.error instanceof Error ? error.error : undefined);
|
|
52
|
+
}
|
|
53
|
+
throw new FsSafeError("not-found", "directory not found", {
|
|
54
|
+
cause: error.error instanceof Error ? error.error : undefined,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
throw error.error;
|
|
58
|
+
}
|
|
59
|
+
if (error instanceof FsSafeError && error.code === "symlink")
|
|
60
|
+
throw error;
|
|
61
|
+
throw new FsSafeError("path-alias", "path alias escape blocked", { cause: error });
|
|
62
|
+
}
|
|
63
|
+
const resolved = observed.resolved;
|
|
64
|
+
if (observed.receipt) {
|
|
65
|
+
// A receipt is emitted only for the straight traversal whose lexical and
|
|
66
|
+
// canonical cursors stayed identical and inside the checked boundary.
|
|
67
|
+
return {
|
|
68
|
+
rootReal: resolved.rootCanonicalPath,
|
|
69
|
+
resolved: resolved.canonicalPath,
|
|
70
|
+
receipt: observed.receipt,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const relativeResolved = path.relative(resolved.rootCanonicalPath, resolved.canonicalPath);
|
|
74
|
+
if (relativeResolved === "" || relativeResolved === ".") {
|
|
75
|
+
return {
|
|
76
|
+
rootReal: resolved.rootCanonicalPath,
|
|
77
|
+
resolved: resolved.canonicalPath,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const firstSegment = relativeResolved.split(path.sep)[0];
|
|
81
|
+
if (firstSegment === ".." || path.isAbsolute(relativeResolved)) {
|
|
82
|
+
throw outsideWorkspaceError();
|
|
83
|
+
}
|
|
84
|
+
const admittedCanonicalPath = admitPathInsideRoot({
|
|
85
|
+
rootPath: resolved.rootCanonicalPath,
|
|
86
|
+
candidatePath: resolved.canonicalPath,
|
|
87
|
+
rootIdentity: root.rootIdentity,
|
|
88
|
+
});
|
|
89
|
+
if (!admittedCanonicalPath)
|
|
90
|
+
throw outsideWorkspaceError();
|
|
91
|
+
return {
|
|
92
|
+
rootReal: resolved.rootCanonicalPath,
|
|
93
|
+
resolved: admittedCanonicalPath.path,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function sanitizeRootPathError(error: unknown): unknown;
|
|
2
|
+
export declare function pathEscapeError(params: {
|
|
3
|
+
boundaryLabel: string;
|
|
4
|
+
rootPath: string;
|
|
5
|
+
absolutePath: string;
|
|
6
|
+
}): Error;
|
|
7
|
+
export declare function symlinkEscapeError(params: {
|
|
8
|
+
boundaryLabel: string;
|
|
9
|
+
rootCanonicalPath: string;
|
|
10
|
+
symlinkPath: string;
|
|
11
|
+
}): Error;
|
|
12
|
+
//# sourceMappingURL=root-path-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-path-errors.d.ts","sourceRoot":"","sources":["../src/root-path-errors.ts"],"names":[],"mappings":"AAEA,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK7D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,KAAK,CAIR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,KAAK,CAIR"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { formatErrorDetail, shortPath } from "./error-detail.js";
|
|
2
|
+
export function sanitizeRootPathError(error) {
|
|
3
|
+
if (error instanceof Error) {
|
|
4
|
+
error.message = formatErrorDetail(error.message);
|
|
5
|
+
}
|
|
6
|
+
return error;
|
|
7
|
+
}
|
|
8
|
+
export function pathEscapeError(params) {
|
|
9
|
+
return new Error(`Path escapes ${params.boundaryLabel} (${shortPath(params.rootPath)}): ${shortPath(params.absolutePath)}`);
|
|
10
|
+
}
|
|
11
|
+
export function symlinkEscapeError(params) {
|
|
12
|
+
return new Error(`Symlink escapes ${params.boundaryLabel} (${shortPath(params.rootCanonicalPath)}): ${shortPath(params.symlinkPath)}`);
|
|
13
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-path-existing.d.ts","sourceRoot":"","sources":["../src/root-path-existing.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-path-existing.d.ts","sourceRoot":"","sources":["../src/root-path-existing.ts"],"names":[],"mappings":"AAWA,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAEpF,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAarE;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EACzB,OAAO,GAAE;IACP,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,oBAAoB,CAAC;CAChC,GACL,MAAM,GAAG,SAAS,CAqDpB;AAkBD,wBAAsB,8BAA8B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkCxF;AAED,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAqC7E"}
|
|
@@ -4,15 +4,28 @@ import { FsSafeError } from "./errors.js";
|
|
|
4
4
|
import { formatErrorDetail } from "./error-detail.js";
|
|
5
5
|
import { isNotFoundPathError, isPathInside } from "./path.js";
|
|
6
6
|
import { realpathSync } from "./realpath.js";
|
|
7
|
+
import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
|
|
7
8
|
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
8
9
|
export function absolutePathWithRawSegments(candidate) {
|
|
9
|
-
if (path.
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
if (path.sep !== "\\") {
|
|
11
|
+
if (path.isAbsolute(candidate))
|
|
12
|
+
return candidate;
|
|
13
|
+
const base = process.cwd();
|
|
14
|
+
return `${base}${base.endsWith(path.sep) ? "" : path.sep}${candidate}`;
|
|
15
|
+
}
|
|
16
|
+
const raw = path.sep === "\\" ? candidate.replaceAll("/", "\\") : candidate;
|
|
17
|
+
const absolute = path.isAbsolute(raw);
|
|
18
|
+
if (absolute && raw[0] !== "\\")
|
|
19
|
+
return raw;
|
|
20
|
+
const drive = path.parse(raw).root;
|
|
21
|
+
if (absolute && drive !== "\\")
|
|
22
|
+
return raw;
|
|
12
23
|
const base = drive ? path.resolve(drive) : process.cwd();
|
|
13
|
-
return `${base}${path.sep}${
|
|
24
|
+
return `${base}${base.endsWith(path.sep) ? "" : path.sep}${raw.slice(drive.length)}`;
|
|
14
25
|
}
|
|
15
26
|
export function rawPathRelativeToCanonicalRoot(candidate, rootCanonicalPath, options = {}) {
|
|
27
|
+
assertNoWindowsPathAlias(candidate);
|
|
28
|
+
assertNoWindowsPathAlias(rootCanonicalPath);
|
|
16
29
|
const absolute = absolutePathWithRawSegments(candidate);
|
|
17
30
|
const raw = process.platform === "win32" ? absolute.replaceAll("/", path.sep) : absolute;
|
|
18
31
|
const filesystemRoot = path.parse(raw).root;
|
|
@@ -26,7 +39,8 @@ export function rawPathRelativeToCanonicalRoot(candidate, rootCanonicalPath, opt
|
|
|
26
39
|
let canonical;
|
|
27
40
|
let isSymlink = false;
|
|
28
41
|
try {
|
|
29
|
-
const
|
|
42
|
+
const operationPath = pathForWindowsFilesystem(prefix);
|
|
43
|
+
const stat = fs.lstatSync(operationPath);
|
|
30
44
|
isSymlink = stat.isSymbolicLink();
|
|
31
45
|
// Check the original leaf before canonicalization can erase an entry alias.
|
|
32
46
|
if (isSymlink && options.rejectFinalSymlink && index === finalComponentIndex) {
|
|
@@ -35,8 +49,10 @@ export function rawPathRelativeToCanonicalRoot(candidate, rootCanonicalPath, opt
|
|
|
35
49
|
if (!isSymlink && !stat.isDirectory() && index < segments.length - 1)
|
|
36
50
|
return undefined;
|
|
37
51
|
traversedSymlink ||= isSymlink;
|
|
38
|
-
canonical = realpathSync.native(
|
|
39
|
-
|
|
52
|
+
canonical = realpathSync.native(operationPath);
|
|
53
|
+
assertNoWindowsPathAlias(canonical);
|
|
54
|
+
if (isSymlink && index < segments.length - 1 &&
|
|
55
|
+
!fs.statSync(pathForWindowsFilesystem(canonical)).isDirectory())
|
|
40
56
|
return undefined;
|
|
41
57
|
if (isSymlink && !isPathInside(rootCanonicalPath, canonical) && !isPathInside(canonical, rootCanonicalPath)) {
|
|
42
58
|
throw new FsSafeError("outside-workspace", `symlink prefix resolves outside the root ancestry: ${formatErrorDetail(candidate)}`);
|
|
@@ -70,7 +86,7 @@ function isFilesystemRoot(candidate) {
|
|
|
70
86
|
}
|
|
71
87
|
async function pathExists(targetPath) {
|
|
72
88
|
try {
|
|
73
|
-
fs.lstatSync(targetPath);
|
|
89
|
+
fs.lstatSync(pathForWindowsFilesystem(targetPath));
|
|
74
90
|
return true;
|
|
75
91
|
}
|
|
76
92
|
catch (error) {
|
|
@@ -81,7 +97,9 @@ async function pathExists(targetPath) {
|
|
|
81
97
|
}
|
|
82
98
|
}
|
|
83
99
|
export async function resolvePathViaExistingAncestor(targetPath) {
|
|
84
|
-
|
|
100
|
+
assertNoWindowsPathAlias(targetPath);
|
|
101
|
+
const normalized = resolvePathPreservingWindowsRoot(targetPath);
|
|
102
|
+
assertNoWindowsPathAlias(normalized);
|
|
85
103
|
let cursor = normalized;
|
|
86
104
|
const missingSuffix = [];
|
|
87
105
|
while (!isFilesystemRoot(cursor) && !(await pathExists(cursor))) {
|
|
@@ -95,21 +113,30 @@ export async function resolvePathViaExistingAncestor(targetPath) {
|
|
|
95
113
|
if (!(await pathExists(cursor))) {
|
|
96
114
|
return normalized;
|
|
97
115
|
}
|
|
116
|
+
let rawResolvedAncestor;
|
|
98
117
|
try {
|
|
99
|
-
|
|
100
|
-
return missingSuffix.length === 0
|
|
101
|
-
? resolvedAncestor
|
|
102
|
-
: path.resolve(resolvedAncestor, ...missingSuffix);
|
|
118
|
+
rawResolvedAncestor = realpathSync.native(pathForWindowsFilesystem(cursor));
|
|
103
119
|
}
|
|
104
120
|
catch {
|
|
105
121
|
return normalized;
|
|
106
122
|
}
|
|
123
|
+
assertNoWindowsPathAlias(rawResolvedAncestor);
|
|
124
|
+
const resolvedAncestor = resolvePathPreservingWindowsRoot(rawResolvedAncestor);
|
|
125
|
+
assertNoWindowsPathAlias(resolvedAncestor);
|
|
126
|
+
const resolved = missingSuffix.length === 0
|
|
127
|
+
? resolvedAncestor
|
|
128
|
+
: path.resolve(resolvedAncestor, ...missingSuffix);
|
|
129
|
+
assertNoWindowsPathAlias(resolved);
|
|
130
|
+
return resolved;
|
|
107
131
|
}
|
|
108
132
|
export function resolvePathViaExistingAncestorSync(targetPath) {
|
|
109
|
-
|
|
133
|
+
assertNoWindowsPathAlias(targetPath);
|
|
134
|
+
const normalized = resolvePathPreservingWindowsRoot(targetPath);
|
|
135
|
+
assertNoWindowsPathAlias(normalized);
|
|
110
136
|
let cursor = normalized;
|
|
111
137
|
const missingSuffix = [];
|
|
112
|
-
while (!isFilesystemRoot(cursor) &&
|
|
138
|
+
while (!isFilesystemRoot(cursor) &&
|
|
139
|
+
!fs.existsSync(pathForWindowsFilesystem(cursor))) {
|
|
113
140
|
missingSuffix.unshift(path.basename(cursor));
|
|
114
141
|
const parent = path.dirname(cursor);
|
|
115
142
|
if (parent === cursor) {
|
|
@@ -117,16 +144,22 @@ export function resolvePathViaExistingAncestorSync(targetPath) {
|
|
|
117
144
|
}
|
|
118
145
|
cursor = parent;
|
|
119
146
|
}
|
|
120
|
-
if (!fs.existsSync(cursor)) {
|
|
147
|
+
if (!fs.existsSync(pathForWindowsFilesystem(cursor))) {
|
|
121
148
|
return normalized;
|
|
122
149
|
}
|
|
150
|
+
let rawResolvedAncestor;
|
|
123
151
|
try {
|
|
124
|
-
|
|
125
|
-
return missingSuffix.length === 0
|
|
126
|
-
? resolvedAncestor
|
|
127
|
-
: path.resolve(resolvedAncestor, ...missingSuffix);
|
|
152
|
+
rawResolvedAncestor = realpathSync(pathForWindowsFilesystem(cursor));
|
|
128
153
|
}
|
|
129
154
|
catch {
|
|
130
155
|
return normalized;
|
|
131
156
|
}
|
|
157
|
+
assertNoWindowsPathAlias(rawResolvedAncestor);
|
|
158
|
+
const resolvedAncestor = resolvePathPreservingWindowsRoot(rawResolvedAncestor);
|
|
159
|
+
assertNoWindowsPathAlias(resolvedAncestor);
|
|
160
|
+
const resolved = missingSuffix.length === 0
|
|
161
|
+
? resolvedAncestor
|
|
162
|
+
: path.resolve(resolvedAncestor, ...missingSuffix);
|
|
163
|
+
assertNoWindowsPathAlias(resolved);
|
|
164
|
+
return resolved;
|
|
132
165
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs, { type BigIntStats } from "node:fs";
|
|
2
|
+
import { type DirectoryObservationGuard } from "./directory-guard.js";
|
|
3
|
+
import { type NativeDirectoryObservationBackend, type NativeDirectoryObservationGuard } from "./native-directory-observation.js";
|
|
4
|
+
import { type RootBoundaryIdentity } from "./root-boundary.js";
|
|
5
|
+
import { type StatObservationReceipt } from "./stat-observation.js";
|
|
6
|
+
export type RootPathObservationKind = "stat" | "directory";
|
|
7
|
+
export type RootPathDirectoryObservationGuard = DirectoryObservationGuard | NativeDirectoryObservationGuard;
|
|
8
|
+
export type RootPathTargetObservation = StatObservationReceipt | NativeDirectoryObservationGuard;
|
|
9
|
+
/** An exact receipt owned by one stat/list operation. Never cache it. */
|
|
10
|
+
export type RootPathObservationReceipt = {
|
|
11
|
+
kind: RootPathObservationKind;
|
|
12
|
+
rootGuard: DirectoryObservationGuard;
|
|
13
|
+
directoryGuard: RootPathDirectoryObservationGuard;
|
|
14
|
+
directoryObserver?: NativeDirectoryObservationBackend;
|
|
15
|
+
targetPath: string;
|
|
16
|
+
target: RootPathTargetObservation;
|
|
17
|
+
};
|
|
18
|
+
/** A failed initial target lookup must not discard its already admitted parent. */
|
|
19
|
+
export type RootPathParentObservationReceipt = Omit<RootPathObservationReceipt, "kind" | "target"> & {
|
|
20
|
+
kind: "stat-parent";
|
|
21
|
+
};
|
|
22
|
+
export type RootPathObservationRequest = {
|
|
23
|
+
kind: RootPathObservationKind;
|
|
24
|
+
rootGuard: DirectoryObservationGuard;
|
|
25
|
+
directoryObserver?: NativeDirectoryObservationBackend;
|
|
26
|
+
};
|
|
27
|
+
export type RootPathTraversalObservation = {
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
request: RootPathObservationRequest;
|
|
30
|
+
targetIndex: number;
|
|
31
|
+
directoryIndex: number;
|
|
32
|
+
directoryGuard?: RootPathDirectoryObservationGuard;
|
|
33
|
+
directoryObserver?: NativeDirectoryObservationBackend;
|
|
34
|
+
targetPath?: string;
|
|
35
|
+
target?: RootPathTargetObservation;
|
|
36
|
+
};
|
|
37
|
+
export type RootPathObservedTraversalEntry = StatObservationReceipt | {
|
|
38
|
+
stat: fs.Stats | BigIntStats;
|
|
39
|
+
identity?: undefined;
|
|
40
|
+
} | NativeDirectoryObservationGuard;
|
|
41
|
+
export declare class RootPathObservationError extends Error {
|
|
42
|
+
readonly error: unknown;
|
|
43
|
+
readonly parentReceipt?: RootPathParentObservationReceipt | undefined;
|
|
44
|
+
readonly traversalFailure: boolean;
|
|
45
|
+
constructor(error: unknown, parentReceipt?: RootPathParentObservationReceipt | undefined, traversalFailure?: boolean);
|
|
46
|
+
}
|
|
47
|
+
export type RootPathTraversalContext = {
|
|
48
|
+
observationEligible: boolean;
|
|
49
|
+
rootPath: string;
|
|
50
|
+
rootCanonicalPath: string;
|
|
51
|
+
resolveParams: {
|
|
52
|
+
rootIdentity?: RootBoundaryIdentity;
|
|
53
|
+
};
|
|
54
|
+
state: {
|
|
55
|
+
finalComponentIndex: number;
|
|
56
|
+
relativePath: string;
|
|
57
|
+
segments: string[];
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
export declare function createRootPathTraversalObservation(context: RootPathTraversalContext, request?: RootPathObservationRequest): RootPathTraversalObservation | undefined;
|
|
61
|
+
export declare function inspectRootPathTraversalEntry(pathname: string, directorySlot: boolean, observation: RootPathTraversalObservation): RootPathObservedTraversalEntry;
|
|
62
|
+
export declare function captureRootPathObservedDirectory(observation: RootPathTraversalObservation, observed: RootPathObservedTraversalEntry, publicPath: string, canonicalPath: string, rootCanonicalPath: string, rootIdentity?: RootBoundaryIdentity): boolean;
|
|
63
|
+
//# sourceMappingURL=root-path-observation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-path-observation.d.ts","sourceRoot":"","sources":["../src/root-path-observation.ts"],"names":[],"mappings":"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"}
|