@openclaw/fs-safe 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +119 -0
- package/README.md +15 -8
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +32 -11
- package/dist/advanced.d.ts +3 -1
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +3 -1
- package/dist/archive-entry.d.ts.map +1 -1
- package/dist/archive-entry.js +4 -3
- package/dist/archive-gzip-tail.d.ts.map +1 -1
- package/dist/archive-gzip-tail.js +13 -9
- 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 +55 -46
- 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 +50 -17
- 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/bounded-read.js +2 -2
- 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/device-path.d.ts.map +1 -1
- package/dist/device-path.js +5 -3
- 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 +12 -2
- 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-prune.d.ts.map +1 -1
- package/dist/file-store-prune.js +9 -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 +1 -0
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +85 -23
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +3 -2
- package/dist/guarded-mkdir.d.ts +10 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +217 -33
- package/dist/guest.d.ts.map +1 -1
- package/dist/guest.js +16 -5
- package/dist/home-dir.d.ts.map +1 -1
- package/dist/home-dir.js +73 -10
- package/dist/install-path.d.ts +6 -0
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +67 -19
- package/dist/json-durable-queue-ownership.d.ts +8 -0
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +134 -43
- 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 +6 -0
- package/dist/json-durable-queue-read.d.ts.map +1 -0
- package/dist/json-durable-queue-read.js +61 -0
- package/dist/json-durable-queue.d.ts +1 -1
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +83 -134
- 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 +21 -0
- package/dist/native-binding.d.ts.map +1 -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-parent-admission.d.ts +31 -0
- package/dist/native-parent-admission.d.ts.map +1 -0
- package/dist/native-parent-admission.js +124 -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 +0 -3
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +309 -40
- 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 +14 -0
- package/dist/path-scope-lexical.d.ts.map +1 -0
- package/dist/path-scope-lexical.js +37 -0
- 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 +35 -6
- 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 +152 -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 +33 -29
- 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 +29 -0
- package/dist/root-boundary.d.ts.map +1 -0
- package/dist/root-boundary.js +182 -0
- package/dist/root-context.d.ts +12 -1
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +89 -16
- 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 +182 -33
- 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 +316 -325
- 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-move-preflight.d.ts +8 -0
- package/dist/root-move-preflight.d.ts.map +1 -0
- package/dist/root-move-preflight.js +16 -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 +2 -0
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +63 -22
- 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 +13 -0
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +263 -73
- 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 -29
- package/dist/root-paths.d.ts.map +1 -1
- package/dist/root-paths.js +89 -178
- 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-walk.d.ts.map +1 -1
- package/dist/root-walk.js +2 -1
- 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-mode.d.ts +2 -0
- package/dist/root-write-mode.d.ts.map +1 -1
- package/dist/root-write-mode.js +20 -7
- 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 +18 -7
- package/dist/safe-path-segment.d.ts.map +1 -1
- package/dist/safe-path-segment.js +3 -1
- 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-windows.d.ts +10 -0
- package/dist/secure-file-windows.d.ts.map +1 -0
- package/dist/secure-file-windows.js +186 -0
- package/dist/secure-file.d.ts.map +1 -1
- package/dist/secure-file.js +98 -10
- 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 -1
- package/dist/sibling-staged-file.d.ts.map +1 -1
- package/dist/sibling-staged-file.js +181 -50
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +27 -12
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +45 -15
- package/dist/sidecar-lock-root.d.ts.map +1 -1
- package/dist/sidecar-lock-root.js +4 -2
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +2 -3
- 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 +133 -4
- 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 +20 -16
- 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 +28 -1
- package/docs/archive.md +29 -2
- package/docs/atomic.md +27 -3
- package/docs/contributing.md +4 -1
- package/docs/copy.md +4 -1
- package/docs/durability.md +18 -2
- package/docs/errors.md +14 -6
- package/docs/file-store.md +30 -3
- package/docs/filename.md +21 -7
- package/docs/guest.md +5 -0
- package/docs/install-path.md +61 -15
- package/docs/install.md +12 -8
- 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 +28 -9
- package/docs/native.md +46 -10
- 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 +12 -1
- package/docs/permissions.md +26 -1
- package/docs/private-file-store.md +14 -0
- package/docs/public-api.md +14 -0
- package/docs/quickstart.md +1 -1
- package/docs/reading.md +8 -1
- package/docs/root.md +21 -4
- package/docs/secret-file.md +3 -0
- package/docs/secure-file.md +21 -16
- package/docs/security-model.md +76 -9
- package/docs/sidecar-lock.md +28 -1
- package/docs/store.md +27 -2
- package/docs/temp.md +262 -34
- package/docs/test-hooks.md +14 -0
- package/docs/writing.md +38 -8
- package/package.json +10 -10
package/dist/root-path.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
1
|
+
import fs, {} from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { shortPath } from "./error-detail.js";
|
|
4
|
+
import { pathEscapeError, sanitizeRootPathError, symlinkEscapeError } from "./root-path-errors.js";
|
|
4
5
|
import { FsSafeError } from "./errors.js";
|
|
5
|
-
import {
|
|
6
|
+
import { isNativeDirectoryObservationGuard } from "./native-directory-observation.js";
|
|
7
|
+
import { assertNoNulPathInput, isNotFoundPathError, isPathRelativeEscape, } from "./path.js";
|
|
6
8
|
import { absolutePathWithRawSegments, rawPathRelativeToCanonicalRoot, resolvePathViaExistingAncestor, resolvePathViaExistingAncestorSync, } from "./root-path-existing.js";
|
|
9
|
+
import { admitPathInsideRoot, } from "./root-boundary.js";
|
|
10
|
+
import { RootPathObservationError, captureRootPathObservedDirectory, createRootPathTraversalObservation, inspectRootPathTraversalEntry, } from "./root-path-observation.js";
|
|
7
11
|
import { resolveSymlinkHopPath, resolveSymlinkHopPathSync } from "./root-path-symlink.js";
|
|
8
12
|
import { assertNoDriveRelativePathSegments } from "./safe-path-segment.js";
|
|
13
|
+
import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathFromBasePreservingWindowsRoot, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
|
|
9
14
|
export { resolvePathViaExistingAncestorSync } from "./root-path-existing.js";
|
|
15
|
+
export { RootPathObservationError, } from "./root-path-observation.js";
|
|
10
16
|
export const ROOT_PATH_ALIAS_POLICIES = {
|
|
11
17
|
strict: Object.freeze({
|
|
12
18
|
allowFinalSymlinkForUnlink: false,
|
|
@@ -25,15 +31,47 @@ export async function resolveRootPath(params) {
|
|
|
25
31
|
throw sanitizeRootPathError(error);
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
|
-
async function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
export async function resolveRootPathWithCanonicalRootObservation(params, observeRoot) {
|
|
35
|
+
try {
|
|
36
|
+
return await resolveRootPathInternal(params, undefined, undefined, observeRoot);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
throw sanitizeRootPathError(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function resolveRootPathInternal(params, observationRequest, observationOutput, observeRoot, removalReceipts) {
|
|
43
|
+
const input = captureValidRootPathInputs(params);
|
|
44
|
+
const rawAbsolutePath = absolutePathWithRawSegments(input.absolutePath);
|
|
45
|
+
const rootPath = resolvePathPreservingWindowsRoot(input.rootPath);
|
|
46
|
+
const absolutePath = resolvePathPreservingWindowsRoot(rawAbsolutePath);
|
|
47
|
+
const rootCanonicalPath = input.rootCanonicalPath
|
|
48
|
+
? resolvePathPreservingWindowsRoot(input.rootCanonicalPath)
|
|
35
49
|
: await resolvePathViaExistingAncestor(rootPath);
|
|
36
|
-
|
|
50
|
+
assertNoWindowsPathAlias(rootPath);
|
|
51
|
+
assertNoWindowsPathAlias(absolutePath);
|
|
52
|
+
assertNoWindowsPathAlias(rootCanonicalPath);
|
|
53
|
+
observeRoot?.(rootCanonicalPath);
|
|
54
|
+
return resolveRootPathLexicalAsync(prepareRootTraversal(input, rootPath, rootCanonicalPath, absolutePath, rawAbsolutePath), observationRequest, observationOutput, removalReceipts);
|
|
55
|
+
}
|
|
56
|
+
export async function resolveRootPathWithObservation(params, request) {
|
|
57
|
+
const output = {};
|
|
58
|
+
try {
|
|
59
|
+
const resolved = await resolveRootPathInternal(params, request, output);
|
|
60
|
+
return output.receipt ? { resolved, receipt: output.receipt } : { resolved };
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw sanitizeRootPathError(error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Removal receipts are separate from metadata observations and canonical-root
|
|
67
|
+
// callbacks; the public resolver's options and result remain unchanged.
|
|
68
|
+
export async function resolveRootPathForRemoval(params, receipts) {
|
|
69
|
+
try {
|
|
70
|
+
return await resolveRootPathInternal(params, undefined, undefined, undefined, receipts);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw sanitizeRootPathError(error);
|
|
74
|
+
}
|
|
37
75
|
}
|
|
38
76
|
export function resolveRootPathSync(params) {
|
|
39
77
|
try {
|
|
@@ -43,46 +81,90 @@ export function resolveRootPathSync(params) {
|
|
|
43
81
|
throw sanitizeRootPathError(error);
|
|
44
82
|
}
|
|
45
83
|
}
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
84
|
+
export function resolveRootPathSyncWithCanonicalRootObservation(params, observeRoot) {
|
|
85
|
+
try {
|
|
86
|
+
return resolveRootPathSyncInternal(params, observeRoot);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw sanitizeRootPathError(error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function resolveRootPathSyncInternal(params, observeRoot) {
|
|
93
|
+
const input = captureValidRootPathInputs(params);
|
|
94
|
+
const rawAbsolutePath = absolutePathWithRawSegments(input.absolutePath);
|
|
95
|
+
const rootPath = resolvePathPreservingWindowsRoot(input.rootPath);
|
|
96
|
+
const absolutePath = resolvePathPreservingWindowsRoot(rawAbsolutePath);
|
|
97
|
+
const rootCanonicalPath = input.rootCanonicalPath
|
|
98
|
+
? resolvePathPreservingWindowsRoot(input.rootCanonicalPath)
|
|
53
99
|
: resolvePathViaExistingAncestorSync(rootPath);
|
|
54
|
-
|
|
100
|
+
assertNoWindowsPathAlias(rootPath);
|
|
101
|
+
assertNoWindowsPathAlias(absolutePath);
|
|
102
|
+
assertNoWindowsPathAlias(rootCanonicalPath);
|
|
103
|
+
observeRoot?.(rootCanonicalPath);
|
|
104
|
+
return resolveRootPathLexicalSync(prepareRootTraversal(input, rootPath, rootCanonicalPath, absolutePath, rawAbsolutePath));
|
|
55
105
|
}
|
|
56
|
-
function prepareRootTraversal(params, rootPath, rootCanonicalPath, absolutePath) {
|
|
57
|
-
let raw =
|
|
58
|
-
|
|
59
|
-
|
|
106
|
+
function prepareRootTraversal(params, rootPath, rootCanonicalPath, absolutePath, rawAbsolutePath) {
|
|
107
|
+
let raw = rawAbsolutePath;
|
|
108
|
+
let trustedAbsolutePath = false;
|
|
109
|
+
const direct = admitRawPathInsideRoot(rootPath, raw, params.rootIdentity);
|
|
110
|
+
if (direct) {
|
|
111
|
+
raw = direct.path;
|
|
112
|
+
trustedAbsolutePath = direct.admission === "identity";
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const canonical = admitRawPathInsideRoot(rootCanonicalPath, raw, params.rootIdentity);
|
|
116
|
+
const relative = canonical?.relativePath
|
|
60
117
|
?? rawPathRelativeToCanonicalRoot(raw, rootCanonicalPath, params);
|
|
61
118
|
if (relative === undefined) {
|
|
62
119
|
throw pathEscapeError({ rootPath, absolutePath: raw, boundaryLabel: params.boundaryLabel });
|
|
63
120
|
}
|
|
64
|
-
|
|
121
|
+
trustedAbsolutePath = canonical?.admission === "identity";
|
|
122
|
+
raw = relative === "" ? rootPath : `${rootPath}${path.sep}${relative}`;
|
|
65
123
|
}
|
|
66
124
|
return {
|
|
67
|
-
params
|
|
68
|
-
|
|
125
|
+
params,
|
|
126
|
+
rawAbsolutePath: raw,
|
|
127
|
+
rootPath,
|
|
128
|
+
rootCanonicalPath,
|
|
129
|
+
// Preserve the caller-spelling receipt for ordinary aliases. Only a
|
|
130
|
+
// Windows case-fold admission must return the identity-gated Root spelling,
|
|
131
|
+
// because downstream I/O must not reuse the ambiguous caller prefix.
|
|
132
|
+
absolutePath: trustedAbsolutePath ? resolvePathPreservingWindowsRoot(raw) : absolutePath,
|
|
133
|
+
observationEligible: raw === rawAbsolutePath && !trustedAbsolutePath,
|
|
69
134
|
};
|
|
70
135
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
assertNoEmbeddedDriveRelativeSegment(
|
|
136
|
+
function captureValidRootPathInputs(params) {
|
|
137
|
+
const rootPath = params.rootPath;
|
|
138
|
+
assertNoNulPathInput(rootPath, "root path contains a NUL byte");
|
|
139
|
+
const absolutePath = params.absolutePath;
|
|
140
|
+
assertNoNulPathInput(absolutePath, "absolute path contains a NUL byte");
|
|
141
|
+
assertNoWindowsPathAlias(rootPath, "filesystem", "root path uses a Windows filesystem namespace alias");
|
|
142
|
+
assertNoWindowsPathAlias(absolutePath, "filesystem", "absolute path uses a Windows filesystem namespace alias");
|
|
143
|
+
assertNoEmbeddedDriveRelativeSegment(rootPath, "root path");
|
|
144
|
+
assertNoEmbeddedDriveRelativeSegment(absolutePath, "absolute path");
|
|
145
|
+
const rootCanonicalPath = params.rootCanonicalPath;
|
|
146
|
+
if (rootCanonicalPath !== undefined) {
|
|
147
|
+
assertNoNulPathInput(rootCanonicalPath, "canonical root path contains a NUL byte");
|
|
148
|
+
assertNoWindowsPathAlias(rootCanonicalPath, "filesystem", "canonical root path uses a Windows filesystem namespace alias");
|
|
149
|
+
assertNoEmbeddedDriveRelativeSegment(rootCanonicalPath, "canonical root path");
|
|
85
150
|
}
|
|
151
|
+
// Keep traversal policy with the admitted paths across ancestor and symlink
|
|
152
|
+
// resolution. Caller-owned flags and getters must not change a running walk.
|
|
153
|
+
const policy = params.policy;
|
|
154
|
+
const rootIdentity = params.rootIdentity;
|
|
155
|
+
return {
|
|
156
|
+
rootPath,
|
|
157
|
+
absolutePath,
|
|
158
|
+
rootCanonicalPath,
|
|
159
|
+
rootIdentity: rootIdentity == null ? undefined : { dev: rootIdentity.dev, ino: rootIdentity.ino },
|
|
160
|
+
boundaryLabel: params.boundaryLabel,
|
|
161
|
+
policy: policy == null ? undefined : {
|
|
162
|
+
allowFinalSymlinkForUnlink: policy.allowFinalSymlinkForUnlink,
|
|
163
|
+
},
|
|
164
|
+
rejectSymlinks: params.rejectSymlinks,
|
|
165
|
+
rejectFinalSymlink: params.rejectFinalSymlink,
|
|
166
|
+
rejectUnresolvedSymlinks: params.rejectUnresolvedSymlinks,
|
|
167
|
+
};
|
|
86
168
|
}
|
|
87
169
|
function assertNoEmbeddedDriveRelativeSegment(filePath, label) {
|
|
88
170
|
if (process.platform !== "win32") {
|
|
@@ -92,13 +174,15 @@ function assertNoEmbeddedDriveRelativeSegment(filePath, label) {
|
|
|
92
174
|
assertNoDriveRelativePathSegments(filePath.slice(root.length).replaceAll("\\", "/"), label);
|
|
93
175
|
}
|
|
94
176
|
function createLexicalTraversalState(params) {
|
|
95
|
-
const rawAbsolutePath = params.
|
|
96
|
-
const relative =
|
|
177
|
+
const rawAbsolutePath = params.rawAbsolutePath;
|
|
178
|
+
const relative = admitRawPathInsideRoot(params.rootPath, rawAbsolutePath, params.params.rootIdentity)?.relativePath;
|
|
97
179
|
if (relative === undefined)
|
|
98
180
|
throw new Error("Path traversal must begin at the root");
|
|
99
181
|
const segments = splitTraversalSegments(relative);
|
|
100
182
|
return {
|
|
101
183
|
segments,
|
|
184
|
+
relativePath: relative,
|
|
185
|
+
reuseLexicalCanonical: false,
|
|
102
186
|
finalComponentIndex: segments.findLastIndex((segment) => segment !== "."),
|
|
103
187
|
allowFinalSymlink: params.params.policy?.allowFinalSymlinkForUnlink === true,
|
|
104
188
|
canonicalCursor: params.rootCanonicalPath,
|
|
@@ -114,8 +198,16 @@ function createLexicalTraversalContext(params) {
|
|
|
114
198
|
rootPath: params.rootPath,
|
|
115
199
|
rootCanonicalPath: params.rootCanonicalPath,
|
|
116
200
|
absolutePath: params.absolutePath,
|
|
201
|
+
observationEligible: params.observationEligible,
|
|
117
202
|
};
|
|
118
203
|
}
|
|
204
|
+
function createLexicalTraversalObservation(context, request) {
|
|
205
|
+
const observation = createRootPathTraversalObservation(context, request);
|
|
206
|
+
if (observation && observation.targetIndex >= 0) {
|
|
207
|
+
context.state.reuseLexicalCanonical = true;
|
|
208
|
+
}
|
|
209
|
+
return observation;
|
|
210
|
+
}
|
|
119
211
|
function splitTraversalSegments(value) {
|
|
120
212
|
const segments = value
|
|
121
213
|
.split(process.platform === "win32" ? /[\\/]+/ : /\/+/)
|
|
@@ -124,38 +216,53 @@ function splitTraversalSegments(value) {
|
|
|
124
216
|
segments.push(".");
|
|
125
217
|
return segments;
|
|
126
218
|
}
|
|
127
|
-
function
|
|
219
|
+
function admitRawPathInsideRoot(rootPath, candidatePath, rootIdentity) {
|
|
128
220
|
if (!path.isAbsolute(candidatePath)) {
|
|
129
221
|
return undefined;
|
|
130
222
|
}
|
|
131
|
-
|
|
223
|
+
// Every caller supplies the already-resolved root selected by
|
|
224
|
+
// resolveRootPathInternal; resolving it again is redundant on each traversal.
|
|
225
|
+
const root = rootPath;
|
|
132
226
|
const candidate = process.platform === "win32"
|
|
133
227
|
? candidatePath.replaceAll("/", path.sep)
|
|
134
228
|
: candidatePath;
|
|
229
|
+
if (process.platform === "win32") {
|
|
230
|
+
return admitPathInsideRoot({ rootPath: root, candidatePath: candidate, rootIdentity });
|
|
231
|
+
}
|
|
135
232
|
if (candidate === root) {
|
|
136
|
-
return "";
|
|
233
|
+
return { admission: "exact", path: candidate, relativePath: "" };
|
|
137
234
|
}
|
|
138
235
|
const rootWithSep = root.endsWith(path.sep) ? root : `${root}${path.sep}`;
|
|
139
236
|
const candidatePrefix = candidate.slice(0, rootWithSep.length);
|
|
140
|
-
|
|
141
|
-
?
|
|
142
|
-
|
|
143
|
-
|
|
237
|
+
return candidatePrefix === rootWithSep
|
|
238
|
+
? {
|
|
239
|
+
admission: "exact",
|
|
240
|
+
path: candidate,
|
|
241
|
+
relativePath: candidate.slice(rootWithSep.length),
|
|
242
|
+
}
|
|
243
|
+
: undefined;
|
|
144
244
|
}
|
|
145
245
|
function assertLexicalCursorInsideBoundary(context, candidatePath) {
|
|
146
|
-
assertInsideBoundary({
|
|
246
|
+
return assertInsideBoundary({
|
|
147
247
|
boundaryLabel: context.resolveParams.boundaryLabel,
|
|
148
248
|
rootCanonicalPath: context.rootCanonicalPath,
|
|
249
|
+
rootIdentity: context.resolveParams.rootIdentity,
|
|
149
250
|
candidatePath,
|
|
150
251
|
absolutePath: context.absolutePath,
|
|
151
252
|
});
|
|
152
253
|
}
|
|
153
254
|
function advanceCanonicalCursorForSegment(context, segment) {
|
|
154
|
-
|
|
155
|
-
|
|
255
|
+
const candidatePath = context.state.reuseLexicalCanonical
|
|
256
|
+
? context.state.lexicalCursor
|
|
257
|
+
: resolvePathFromBasePreservingWindowsRoot(context.state.canonicalCursor, segment);
|
|
258
|
+
context.state.canonicalCursor = assertLexicalCursorInsideBoundary(context, candidatePath);
|
|
259
|
+
}
|
|
260
|
+
function disableLexicalTraversalObservation(context, observation) {
|
|
261
|
+
observation.enabled = false;
|
|
262
|
+
context.state.reuseLexicalCanonical = false;
|
|
156
263
|
}
|
|
157
264
|
function finalizeLexicalResolution(context, kind) {
|
|
158
|
-
assertLexicalCursorInsideBoundary(context, context.state.canonicalCursor);
|
|
265
|
+
context.state.canonicalCursor = assertLexicalCursorInsideBoundary(context, context.state.canonicalCursor);
|
|
159
266
|
return buildResolvedRootPath({
|
|
160
267
|
absolutePath: context.absolutePath,
|
|
161
268
|
canonicalPath: context.state.canonicalCursor,
|
|
@@ -181,18 +288,22 @@ function lexicalStatDisposition(params) {
|
|
|
181
288
|
return params.allowFinalSymlink && params.isLast ? "break" : "resolve-link";
|
|
182
289
|
}
|
|
183
290
|
function applyResolvedSymlinkHop(context, linkCanonical) {
|
|
184
|
-
|
|
291
|
+
let admitted;
|
|
292
|
+
try {
|
|
293
|
+
admitted = assertLexicalCursorInsideBoundary(context, linkCanonical);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
185
296
|
throw symlinkEscapeError({
|
|
186
297
|
boundaryLabel: context.resolveParams.boundaryLabel,
|
|
187
298
|
rootCanonicalPath: context.rootCanonicalPath,
|
|
188
299
|
symlinkPath: context.state.lexicalCursor,
|
|
189
300
|
});
|
|
190
301
|
}
|
|
191
|
-
context.state.canonicalCursor =
|
|
192
|
-
context.state.lexicalCursor =
|
|
302
|
+
context.state.canonicalCursor = admitted;
|
|
303
|
+
context.state.lexicalCursor = admitted;
|
|
193
304
|
}
|
|
194
305
|
function applyParentTraversalStep(context) {
|
|
195
|
-
context.state.lexicalCursor =
|
|
306
|
+
context.state.lexicalCursor = resolvePathFromBasePreservingWindowsRoot(context.state.lexicalCursor, "..");
|
|
196
307
|
advanceCanonicalCursorForSegment(context, "..");
|
|
197
308
|
if (context.state.missingDepth > 0)
|
|
198
309
|
context.state.missingDepth -= 1;
|
|
@@ -205,12 +316,13 @@ function assertDirectoryBeforeMoreSegments(stat, pathname, isLast) {
|
|
|
205
316
|
function assertResolvedLinkDirectory(pathname, isLast) {
|
|
206
317
|
if (isLast)
|
|
207
318
|
return;
|
|
208
|
-
const stat = fs.statSync(pathname);
|
|
319
|
+
const stat = fs.statSync(pathForWindowsFilesystem(pathname));
|
|
209
320
|
assertDirectoryBeforeMoreSegments(stat, pathname, isLast);
|
|
210
321
|
}
|
|
211
|
-
async function resolveRootPathLexicalAsync(params) {
|
|
322
|
+
async function resolveRootPathLexicalAsync(params, observationRequest, observationOutput, removalReceipts) {
|
|
212
323
|
const context = createLexicalTraversalContext(params);
|
|
213
324
|
const { state } = context;
|
|
325
|
+
const observation = createLexicalTraversalObservation(context, observationRequest);
|
|
214
326
|
for (let idx = 0; idx < state.segments.length; idx += 1) {
|
|
215
327
|
const segment = state.segments[idx] ?? "";
|
|
216
328
|
const isLast = idx === state.segments.length - 1;
|
|
@@ -227,14 +339,56 @@ async function resolveRootPathLexicalAsync(params) {
|
|
|
227
339
|
continue;
|
|
228
340
|
}
|
|
229
341
|
let stat;
|
|
342
|
+
let observed;
|
|
230
343
|
try {
|
|
231
|
-
|
|
344
|
+
if (removalReceipts && !isLast) {
|
|
345
|
+
const directoryStat = fs.lstatSync(pathForWindowsFilesystem(state.lexicalCursor), { bigint: true });
|
|
346
|
+
if (directoryStat.isDirectory() && !directoryStat.isSymbolicLink()) {
|
|
347
|
+
removalReceipts.observeDirectory(state.lexicalCursor, directoryStat);
|
|
348
|
+
}
|
|
349
|
+
stat = directoryStat;
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
const directorySlot = observation?.enabled === true && idx === observation.directoryIndex;
|
|
353
|
+
const targetSlot = observation?.enabled === true && idx === observation.targetIndex;
|
|
354
|
+
const observeExactly = directorySlot || targetSlot;
|
|
355
|
+
if (observeExactly) {
|
|
356
|
+
observed = inspectRootPathTraversalEntry(state.lexicalCursor, directorySlot, observation);
|
|
357
|
+
}
|
|
358
|
+
stat = isNativeDirectoryObservationGuard(observed)
|
|
359
|
+
? undefined
|
|
360
|
+
: observed?.stat ?? fs.lstatSync(state.lexicalCursor);
|
|
361
|
+
}
|
|
232
362
|
}
|
|
233
363
|
catch (error) {
|
|
364
|
+
if (observation?.enabled && observation.request.kind === "stat" &&
|
|
365
|
+
idx === observation.targetIndex && observation.directoryGuard) {
|
|
366
|
+
const parentReceipt = {
|
|
367
|
+
kind: "stat-parent",
|
|
368
|
+
rootGuard: observation.request.rootGuard,
|
|
369
|
+
directoryGuard: observation.directoryGuard,
|
|
370
|
+
directoryObserver: observation.directoryObserver,
|
|
371
|
+
targetPath: state.lexicalCursor,
|
|
372
|
+
};
|
|
373
|
+
// Stop here: the generic missing-path fallback would re-admit a parent.
|
|
374
|
+
// Preserve observation-only versus ordinary traversal error precedence.
|
|
375
|
+
throw new RootPathObservationError(error instanceof RootPathObservationError ? error.error : sanitizeRootPathError(error), parentReceipt, !(error instanceof RootPathObservationError));
|
|
376
|
+
}
|
|
234
377
|
if (handleLexicalLstatFailure(context, error, segment))
|
|
235
378
|
continue;
|
|
236
379
|
throw error;
|
|
237
380
|
}
|
|
381
|
+
if (isNativeDirectoryObservationGuard(observed)) {
|
|
382
|
+
advanceCanonicalCursorForSegment(context, segment);
|
|
383
|
+
captureRootPathObservedDirectory(observation, observed, state.lexicalCursor, state.canonicalCursor, context.rootCanonicalPath, context.resolveParams.rootIdentity);
|
|
384
|
+
if (idx === observation.targetIndex) {
|
|
385
|
+
observation.targetPath = state.canonicalCursor;
|
|
386
|
+
observation.target = observed;
|
|
387
|
+
}
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (!stat)
|
|
391
|
+
throw new Error("directory observation did not return metadata");
|
|
238
392
|
const isSymbolicLink = stat.isSymbolicLink();
|
|
239
393
|
if (!isSymbolicLink)
|
|
240
394
|
assertDirectoryBeforeMoreSegments(stat, state.lexicalCursor, isLast);
|
|
@@ -248,10 +402,24 @@ async function resolveRootPathLexicalAsync(params) {
|
|
|
248
402
|
if (disposition !== "resolve-link") {
|
|
249
403
|
state.preserveFinalSymlink = disposition === "break";
|
|
250
404
|
advanceCanonicalCursorForSegment(context, segment);
|
|
405
|
+
if (observation?.enabled && isSymbolicLink) {
|
|
406
|
+
disableLexicalTraversalObservation(context, observation);
|
|
407
|
+
}
|
|
408
|
+
if (observation?.enabled && idx === observation.directoryIndex) {
|
|
409
|
+
const captured = observed?.identity && captureRootPathObservedDirectory(observation, observed, state.canonicalCursor, state.canonicalCursor, context.rootCanonicalPath, context.resolveParams.rootIdentity);
|
|
410
|
+
if (!captured)
|
|
411
|
+
disableLexicalTraversalObservation(context, observation);
|
|
412
|
+
}
|
|
413
|
+
if (observation?.enabled && idx === observation.targetIndex) {
|
|
414
|
+
observation.targetPath = state.canonicalCursor;
|
|
415
|
+
observation.target = observed?.identity ? observed : undefined;
|
|
416
|
+
}
|
|
251
417
|
if (state.preserveFinalSymlink)
|
|
252
418
|
break;
|
|
253
419
|
continue;
|
|
254
420
|
}
|
|
421
|
+
if (observation?.enabled)
|
|
422
|
+
disableLexicalTraversalObservation(context, observation);
|
|
255
423
|
const linkCanonical = await resolveSymlinkHopPath(state.lexicalCursor, {
|
|
256
424
|
rejectUnresolved: context.resolveParams.rejectUnresolvedSymlinks,
|
|
257
425
|
});
|
|
@@ -261,7 +429,26 @@ async function resolveRootPathLexicalAsync(params) {
|
|
|
261
429
|
}
|
|
262
430
|
assertResolvedLinkDirectory(linkCanonical, isLast);
|
|
263
431
|
}
|
|
264
|
-
const
|
|
432
|
+
const completeObservation = observation?.enabled === true && observation.directoryGuard !== undefined &&
|
|
433
|
+
observation.targetPath === state.canonicalCursor && observation.target !== undefined;
|
|
434
|
+
const kind = completeObservation
|
|
435
|
+
? {
|
|
436
|
+
exists: true,
|
|
437
|
+
kind: isNativeDirectoryObservationGuard(observation.target)
|
|
438
|
+
? "directory"
|
|
439
|
+
: toResolvedKind(observation.target.stat),
|
|
440
|
+
}
|
|
441
|
+
: await getPathKind(state.canonicalCursor, state.preserveFinalSymlink);
|
|
442
|
+
if (completeObservation && observationOutput) {
|
|
443
|
+
observationOutput.receipt = {
|
|
444
|
+
kind: observation.request.kind,
|
|
445
|
+
rootGuard: observation.request.rootGuard,
|
|
446
|
+
directoryGuard: observation.directoryGuard,
|
|
447
|
+
directoryObserver: observation.directoryObserver,
|
|
448
|
+
targetPath: observation.targetPath,
|
|
449
|
+
target: observation.target,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
265
452
|
return finalizeLexicalResolution(context, kind);
|
|
266
453
|
}
|
|
267
454
|
function resolveRootPathLexicalSync(params) {
|
|
@@ -333,9 +520,10 @@ function buildResolvedRootPath(params) {
|
|
|
333
520
|
}
|
|
334
521
|
async function getPathKind(absolutePath, preserveFinalSymlink) {
|
|
335
522
|
try {
|
|
523
|
+
const operationPath = pathForWindowsFilesystem(absolutePath);
|
|
336
524
|
const stat = preserveFinalSymlink
|
|
337
|
-
? fs.lstatSync(
|
|
338
|
-
: fs.statSync(
|
|
525
|
+
? fs.lstatSync(operationPath)
|
|
526
|
+
: fs.statSync(operationPath);
|
|
339
527
|
return { exists: true, kind: toResolvedKind(stat) };
|
|
340
528
|
}
|
|
341
529
|
catch (error) {
|
|
@@ -347,7 +535,10 @@ async function getPathKind(absolutePath, preserveFinalSymlink) {
|
|
|
347
535
|
}
|
|
348
536
|
function getPathKindSync(absolutePath, preserveFinalSymlink) {
|
|
349
537
|
try {
|
|
350
|
-
const
|
|
538
|
+
const operationPath = pathForWindowsFilesystem(absolutePath);
|
|
539
|
+
const stat = preserveFinalSymlink
|
|
540
|
+
? fs.lstatSync(operationPath)
|
|
541
|
+
: fs.statSync(operationPath);
|
|
351
542
|
return { exists: true, kind: toResolvedKind(stat) };
|
|
352
543
|
}
|
|
353
544
|
catch (error) {
|
|
@@ -370,7 +561,7 @@ function toResolvedKind(stat) {
|
|
|
370
561
|
return "other";
|
|
371
562
|
}
|
|
372
563
|
function relativeInsideRoot(rootPath, targetPath) {
|
|
373
|
-
const relative = path.relative(
|
|
564
|
+
const relative = path.relative(resolvePathPreservingWindowsRoot(rootPath), resolvePathPreservingWindowsRoot(targetPath));
|
|
374
565
|
if (!relative || relative === ".") {
|
|
375
566
|
return "";
|
|
376
567
|
}
|
|
@@ -380,14 +571,13 @@ function relativeInsideRoot(rootPath, targetPath) {
|
|
|
380
571
|
return relative;
|
|
381
572
|
}
|
|
382
573
|
function assertInsideBoundary(params) {
|
|
383
|
-
|
|
384
|
-
|
|
574
|
+
const admitted = admitPathInsideRoot({
|
|
575
|
+
rootPath: params.rootCanonicalPath,
|
|
576
|
+
candidatePath: params.candidatePath,
|
|
577
|
+
rootIdentity: params.rootIdentity,
|
|
578
|
+
});
|
|
579
|
+
if (admitted) {
|
|
580
|
+
return admitted.path;
|
|
385
581
|
}
|
|
386
582
|
throw new Error(`Path resolves outside ${params.boundaryLabel} (${shortPath(params.rootCanonicalPath)}): ${shortPath(params.absolutePath)}`);
|
|
387
583
|
}
|
|
388
|
-
function pathEscapeError(params) {
|
|
389
|
-
return new Error(`Path escapes ${params.boundaryLabel} (${shortPath(params.rootPath)}): ${shortPath(params.absolutePath)}`);
|
|
390
|
-
}
|
|
391
|
-
function symlinkEscapeError(params) {
|
|
392
|
-
return new Error(`Symlink escapes ${params.boundaryLabel} (${shortPath(params.rootCanonicalPath)}): ${shortPath(params.symlinkPath)}`);
|
|
393
|
-
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ResolvePathWithinRootParams } from "./path-scope-lexical.js";
|
|
2
|
+
export declare function resolvePathWithinRoot(params: ResolvePathWithinRootParams): {
|
|
3
|
+
ok: true;
|
|
4
|
+
path: string;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
error: string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=root-paths-lexical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-paths-lexical.d.ts","sourceRoot":"","sources":["../src/root-paths-lexical.ts"],"names":[],"mappings":"AACA,OAAO,EAAmC,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAU5G,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,2BAA2B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAgB3D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolvePathWithinNormalizedRoot } from "./path-scope-lexical.js";
|
|
3
|
+
import { hasWindowsPathAlias, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
|
|
4
|
+
function invalidPath(scopeLabel) {
|
|
5
|
+
return { ok: false, error: `Invalid path: must stay within ${scopeLabel}` };
|
|
6
|
+
}
|
|
7
|
+
export function resolvePathWithinRoot(params) {
|
|
8
|
+
const rootDir = params.rootDir;
|
|
9
|
+
if (typeof rootDir !== "string")
|
|
10
|
+
path.resolve(rootDir);
|
|
11
|
+
const requestedPath = params.requestedPath;
|
|
12
|
+
const scopeLabel = params.scopeLabel;
|
|
13
|
+
const defaultFileName = params.defaultFileName;
|
|
14
|
+
if (hasWindowsPathAlias(rootDir, "filesystem") ||
|
|
15
|
+
hasWindowsPathAlias(requestedPath, "filesystem") ||
|
|
16
|
+
(defaultFileName !== undefined &&
|
|
17
|
+
hasWindowsPathAlias(defaultFileName, "filesystem"))) {
|
|
18
|
+
return invalidPath(scopeLabel);
|
|
19
|
+
}
|
|
20
|
+
const root = resolvePathPreservingWindowsRoot(rootDir);
|
|
21
|
+
return resolvePathWithinNormalizedRoot({ rootDir, requestedPath, scopeLabel, defaultFileName }, root);
|
|
22
|
+
}
|
package/dist/root-paths.d.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type DirectoryResult } from "./root-directory.js";
|
|
2
|
+
export { resolvePathWithinRoot } from "./root-paths-lexical.js";
|
|
3
|
+
export { ensureDirectoryWithinRoot } from "./root-directory.js";
|
|
2
4
|
type InvalidPathResult = {
|
|
3
5
|
ok: false;
|
|
4
6
|
error: string;
|
|
5
7
|
};
|
|
6
|
-
type DirectoryResult = {
|
|
7
|
-
ok: true;
|
|
8
|
-
path: string;
|
|
9
|
-
} | {
|
|
10
|
-
ok: false;
|
|
11
|
-
error: string;
|
|
12
|
-
diagnostic?: FsSafeError;
|
|
13
|
-
};
|
|
14
8
|
type ResolvePathsWithinRootParams = {
|
|
15
9
|
rootDir: string;
|
|
16
10
|
requestedPaths: string[];
|
|
@@ -50,18 +44,6 @@ export type PathScope = {
|
|
|
50
44
|
mode?: number;
|
|
51
45
|
}): Promise<DirectoryResult>;
|
|
52
46
|
};
|
|
53
|
-
export declare function resolvePathWithinRoot(params: {
|
|
54
|
-
rootDir: string;
|
|
55
|
-
requestedPath: string;
|
|
56
|
-
scopeLabel: string;
|
|
57
|
-
defaultFileName?: string;
|
|
58
|
-
}): {
|
|
59
|
-
ok: true;
|
|
60
|
-
path: string;
|
|
61
|
-
} | {
|
|
62
|
-
ok: false;
|
|
63
|
-
error: string;
|
|
64
|
-
};
|
|
65
47
|
export declare function resolveWritablePathWithinRoot(params: {
|
|
66
48
|
rootDir: string;
|
|
67
49
|
requestedPath: string;
|
|
@@ -74,16 +56,8 @@ export declare function resolveWritablePathWithinRoot(params: {
|
|
|
74
56
|
ok: false;
|
|
75
57
|
error: string;
|
|
76
58
|
}>;
|
|
77
|
-
export declare function ensureDirectoryWithinRoot(params: {
|
|
78
|
-
rootDir: string;
|
|
79
|
-
requestedPath: string;
|
|
80
|
-
scopeLabel: string;
|
|
81
|
-
defaultDirName?: string;
|
|
82
|
-
mode?: number;
|
|
83
|
-
}): Promise<DirectoryResult>;
|
|
84
59
|
export declare function resolvePathsWithinRoot(params: ResolvePathsWithinRootParams): ResolvePathsWithinRootResult;
|
|
85
60
|
export declare function resolveExistingPathsWithinRoot(params: ResolvePathsWithinRootParams): Promise<ResolvePathsWithinRootResult>;
|
|
86
61
|
export declare function resolveStrictExistingPathsWithinRoot(params: ResolvePathsWithinRootParams): Promise<ResolvePathsWithinRootResult>;
|
|
87
62
|
export declare function pathScope(rootDir: string, options: PathScopeOptions): PathScope;
|
|
88
|
-
export {};
|
|
89
63
|
//# sourceMappingURL=root-paths.d.ts.map
|
package/dist/root-paths.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-paths.d.ts","sourceRoot":"","sources":["../src/root-paths.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-paths.d.ts","sourceRoot":"","sources":["../src/root-paths.ts"],"names":[],"mappings":"AAgBA,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEhE,KAAK,iBAAiB,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACtD,KAAK,4BAA4B,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AACF,KAAK,4BAA4B,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,iBAAiB,CAAC;AACtF,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CACL,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,4BAA4B,CAAC;IACnE,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC1E,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IACvE,QAAQ,CACN,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,SAAS,CACP,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,uBAAuB,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GACpD,OAAO,CAAC,eAAe,CAAC,CAAC;CAC7B,CAAC;AAoEF,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA0CrE;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,4BAA4B,GACnC,4BAA4B,CA2B9B;AAED,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,4BAA4B,CAAC,CAEvC;AAED,wBAAsB,oCAAoC,CACxD,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,4BAA4B,CAAC,CAEvC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAyC/E"}
|