@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-path-cleanup.d.ts","sourceRoot":"","sources":["../src/move-path-cleanup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"move-path-cleanup.d.ts","sourceRoot":"","sources":["../src/move-path-cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAM7B,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B,CAAC,aAAa,GAAG;IACf,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,CAAA;KAAE,CAAC,CAAC;IACjE,iBAAiB,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;IACrE,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC,GACF,CAAC,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEvC,KAAK,wBAAwB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,aAAa,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC7C,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,aAAa,CAUhB;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAUxE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAI5D;AAED,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,IAAI,CAAC,CAIf;AA0BD,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,mBAAmB,GAC5B,uBAAuB,CAuBzB;AAsDD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,uBAAuB,EAC9B,oBAAoB,EAAE,MAAM,IAAI,GAC/B,OAAO,CAAC,wBAAwB,CAAC,CAkFnC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fsSync from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { FsSafeError } from "./errors.js";
|
|
5
|
+
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
4
6
|
export function entryIdentity(stat) {
|
|
5
7
|
return {
|
|
6
8
|
ctimeMs: stat.ctimeMs,
|
|
@@ -21,9 +23,6 @@ export function sameIdentity(a, b) {
|
|
|
21
23
|
a.mtimeMs === b.mtimeMs &&
|
|
22
24
|
a.ctimeMs === b.ctimeMs);
|
|
23
25
|
}
|
|
24
|
-
function sameDirectoryNode(a, b) {
|
|
25
|
-
return a.dev === b.dev && a.ino === b.ino;
|
|
26
|
-
}
|
|
27
26
|
export function sourceChangedError(sourcePath) {
|
|
28
27
|
return Object.assign(new Error(`Source changed during move fallback: ${sourcePath}`), {
|
|
29
28
|
code: "ESTALE",
|
|
@@ -113,22 +112,19 @@ function mergeCleanupResults(a, b) {
|
|
|
113
112
|
return a === "stale" || b === "stale" ? "stale" : "removed";
|
|
114
113
|
}
|
|
115
114
|
export async function cleanupCopiedEntry(sourcePath, manifest, state, assertBeforeMutation) {
|
|
116
|
-
const aliasGroup = manifest.kind === "leaf" ? state.aliasGroups.get(identityKey(manifest)) : undefined;
|
|
117
|
-
if (aliasGroup?.stale) {
|
|
118
|
-
return "stale";
|
|
119
|
-
}
|
|
120
|
-
let currentStat;
|
|
121
|
-
try {
|
|
122
|
-
currentStat = fsSync.lstatSync(sourcePath);
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
if (error?.code === "ENOENT") {
|
|
126
|
-
return aliasGroup ? poisonAliasGroup(aliasGroup) : "removed";
|
|
127
|
-
}
|
|
128
|
-
throw error;
|
|
129
|
-
}
|
|
130
115
|
if (manifest.kind === "directory") {
|
|
131
|
-
|
|
116
|
+
let currentStat;
|
|
117
|
+
try {
|
|
118
|
+
currentStat = inspectFileIdentitySync(() => fsSync.lstatSync(sourcePath, { bigint: true }), manifest.directoryIdentity);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error?.code === "ENOENT")
|
|
122
|
+
return "removed";
|
|
123
|
+
if (error instanceof FsSafeError && error.code === "path-mismatch")
|
|
124
|
+
return "stale";
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
if (!currentStat.isDirectory()) {
|
|
132
128
|
return "stale";
|
|
133
129
|
}
|
|
134
130
|
// A same-inode directory can gain unrelated children after commit. Still
|
|
@@ -137,7 +133,23 @@ export async function cleanupCopiedEntry(sourcePath, manifest, state, assertBefo
|
|
|
137
133
|
for (const child of manifest.children) {
|
|
138
134
|
result = mergeCleanupResults(result, await cleanupCopiedEntry(path.join(sourcePath, child.name), child.manifest, state, assertBeforeMutation));
|
|
139
135
|
}
|
|
136
|
+
// Child cleanup and the caller's authority check can replace the directory.
|
|
137
|
+
// Keep the final exact observation after both, immediately before removal.
|
|
140
138
|
assertBeforeMutation();
|
|
139
|
+
try {
|
|
140
|
+
currentStat = inspectFileIdentitySync(() => fsSync.lstatSync(sourcePath, { bigint: true }), manifest.directoryIdentity);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (error?.code === "ENOENT") {
|
|
144
|
+
return "stale";
|
|
145
|
+
}
|
|
146
|
+
if (error instanceof FsSafeError && error.code === "path-mismatch")
|
|
147
|
+
return "stale";
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
if (!currentStat.isDirectory()) {
|
|
151
|
+
return "stale";
|
|
152
|
+
}
|
|
141
153
|
try {
|
|
142
154
|
await fs.rmdir(sourcePath);
|
|
143
155
|
}
|
|
@@ -150,6 +162,20 @@ export async function cleanupCopiedEntry(sourcePath, manifest, state, assertBefo
|
|
|
150
162
|
}
|
|
151
163
|
return result;
|
|
152
164
|
}
|
|
165
|
+
const aliasGroup = state.aliasGroups.get(identityKey(manifest));
|
|
166
|
+
if (aliasGroup?.stale) {
|
|
167
|
+
return "stale";
|
|
168
|
+
}
|
|
169
|
+
let currentStat;
|
|
170
|
+
try {
|
|
171
|
+
currentStat = fsSync.lstatSync(sourcePath);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
if (error?.code === "ENOENT") {
|
|
175
|
+
return aliasGroup ? poisonAliasGroup(aliasGroup) : "removed";
|
|
176
|
+
}
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
153
179
|
const expected = aliasGroup?.expected ?? manifest;
|
|
154
180
|
if (!sameIdentity(expected, entryIdentity(currentStat))) {
|
|
155
181
|
return aliasGroup ? poisonAliasGroup(aliasGroup) : "stale";
|
package/dist/move-path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAAC;AAEH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,KAAK,sBAAsB,GAAG,cAAc,GAAG,uBAAuB,CAAC;AAEvE,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,sBAAsB,GAAG,SAAS,CASpC;AAoSD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CAoHf"}
|
package/dist/move-path.js
CHANGED
|
@@ -2,14 +2,16 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import fsSync, { constants as fsConstants } from "node:fs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
5
|
+
import { createAsyncDirectoryGuard, inspectDirectoryIdentitySync } from "./directory-guard.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
7
|
import { guardedRename } from "./guarded-mutation.js";
|
|
8
8
|
import { assertSourceStillMatches, cleanupCopiedEntry, createCleanupCopiedEntryState, entryIdentity, sameIdentity, sourceChangedError, } from "./move-path-cleanup.js";
|
|
9
9
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
10
|
+
import { realpathSync } from "./realpath.js";
|
|
10
11
|
import { cleanupPinnedFilePath } from "./replace-file-temp-owner.js";
|
|
11
12
|
import { createMoveStageOwner } from "./move-path-stage.js";
|
|
12
|
-
import {
|
|
13
|
+
import { admitStandalonePublicationPath } from "./standalone-publication-path.js";
|
|
14
|
+
import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
|
|
13
15
|
export function moveCopyFallbackReasonForRenameError(error, platform = process.platform) {
|
|
14
16
|
const code = error?.code;
|
|
15
17
|
if (code === "EXDEV") {
|
|
@@ -176,6 +178,19 @@ async function copyRegularFilePinned(params) {
|
|
|
176
178
|
}
|
|
177
179
|
return openedIdentity;
|
|
178
180
|
}
|
|
181
|
+
function inspectSourceDirectory(sourcePath, expected) {
|
|
182
|
+
try {
|
|
183
|
+
return inspectDirectoryIdentitySync(sourcePath, expected);
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
const code = error?.code;
|
|
187
|
+
if (code === "ENOENT" || code === "ENOTDIR" ||
|
|
188
|
+
(error instanceof FsSafeError && (error.code === "path-mismatch" || error.code === "not-file"))) {
|
|
189
|
+
throw sourceChangedError(sourcePath);
|
|
190
|
+
}
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
179
194
|
async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
180
195
|
const sourceStat = fsSync.lstatSync(from);
|
|
181
196
|
const identity = entryIdentity(sourceStat);
|
|
@@ -193,6 +208,8 @@ async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
|
193
208
|
return { ...identity, kind: "leaf" };
|
|
194
209
|
}
|
|
195
210
|
if (sourceStat.isDirectory()) {
|
|
211
|
+
const directoryStat = inspectSourceDirectory(from);
|
|
212
|
+
const directoryIdentity = Object.freeze({ dev: directoryStat.dev, ino: directoryStat.ino });
|
|
196
213
|
await fs.mkdir(to, { mode: modeBits(sourceStat.mode) || 0o755 });
|
|
197
214
|
options.onCreated?.(fsSync.lstatSync(to, { bigint: true }));
|
|
198
215
|
const children = [];
|
|
@@ -215,10 +232,11 @@ async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
|
215
232
|
// Directory traversal is path-based in Node. Treat a changed parent as a
|
|
216
233
|
// stale move before committing so swapped-in outside trees are not imported.
|
|
217
234
|
await assertSourceStillMatches(from, identity);
|
|
235
|
+
inspectSourceDirectory(from, directoryIdentity);
|
|
218
236
|
// mkdir() honors process umask. Restore the source mode before commit so
|
|
219
237
|
// EXDEV fallback preserves directory permissions like fs.cp did.
|
|
220
238
|
await chmodDirectoryPinned(to, modeBits(sourceStat.mode));
|
|
221
|
-
return { ...identity, children, kind: "directory" };
|
|
239
|
+
return { ...identity, children, directoryIdentity, kind: "directory" };
|
|
222
240
|
}
|
|
223
241
|
if (!sourceStat.isFile()) {
|
|
224
242
|
throw new Error(`Refusing to move non-file path with copy fallback: ${from}`);
|
|
@@ -244,6 +262,13 @@ function assertSynchronousResult(returned, name) {
|
|
|
244
262
|
}
|
|
245
263
|
}
|
|
246
264
|
export async function movePathWithCopyFallback(options) {
|
|
265
|
+
const from = admitStandalonePublicationPath(options.from, "move source uses a Windows filesystem namespace alias");
|
|
266
|
+
const to = admitStandalonePublicationPath(options.to, "move destination uses a Windows filesystem namespace alias");
|
|
267
|
+
const sourcePath = path.resolve(from);
|
|
268
|
+
const targetPath = path.resolve(to);
|
|
269
|
+
assertNoWindowsPathAlias(sourcePath, "filesystem", "move source uses a Windows filesystem namespace alias");
|
|
270
|
+
assertNoWindowsPathAlias(targetPath, "filesystem", "move destination uses a Windows filesystem namespace alias");
|
|
271
|
+
const sourceHardlinks = options.sourceHardlinks;
|
|
247
272
|
// Keep the initiating owner's callbacks across preparation and copy fallback.
|
|
248
273
|
const callerRenameAssert = options.assertBeforeRename;
|
|
249
274
|
const callerMutationAssert = options.assertBeforeMutation;
|
|
@@ -279,9 +304,7 @@ export async function movePathWithCopyFallback(options) {
|
|
|
279
304
|
assertSynchronousResult(callerPublished?.(publicationReceipt), "onDestinationPublished");
|
|
280
305
|
}
|
|
281
306
|
};
|
|
282
|
-
const
|
|
283
|
-
const targetPath = path.resolve(options.to);
|
|
284
|
-
const rejectHardlinks = options.sourceHardlinks === "reject";
|
|
307
|
+
const rejectHardlinks = sourceHardlinks === "reject";
|
|
285
308
|
if (rejectHardlinks) {
|
|
286
309
|
await preflightSourceHardlinks(sourcePath);
|
|
287
310
|
}
|
|
@@ -320,6 +343,8 @@ export async function movePathWithCopyFallback(options) {
|
|
|
320
343
|
}, sourceIdentity);
|
|
321
344
|
const cleanupState = createCleanupCopiedEntryState(sourcePath, manifest);
|
|
322
345
|
await assertCopyDestinationOutsideSource(sourcePath, targetPath, manifest);
|
|
346
|
+
if (manifest.kind === "directory")
|
|
347
|
+
inspectSourceDirectory(sourcePath, manifest.directoryIdentity);
|
|
323
348
|
await guardedRename({
|
|
324
349
|
from: staged,
|
|
325
350
|
to: targetPath,
|
package/dist/native-binding.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export interface NativeFileIdentity {
|
|
|
15
15
|
isDirectory: boolean;
|
|
16
16
|
isSymbolicLink: boolean;
|
|
17
17
|
}
|
|
18
|
+
export interface NativeDirectoryObservation {
|
|
19
|
+
dev: bigint;
|
|
20
|
+
ino: bigint;
|
|
21
|
+
realPath: string;
|
|
22
|
+
}
|
|
18
23
|
export interface NativeArchiveEntry {
|
|
19
24
|
index: number;
|
|
20
25
|
path: string;
|
|
@@ -80,12 +85,21 @@ export interface NativeWindowsDescriptorSecurityFacts {
|
|
|
80
85
|
identity: string;
|
|
81
86
|
security: NativeWindowsSecurityFacts;
|
|
82
87
|
}
|
|
88
|
+
export interface NativeDarwinAclFacts {
|
|
89
|
+
state: "absent" | "empty" | "present";
|
|
90
|
+
}
|
|
83
91
|
export interface NativeBinding {
|
|
92
|
+
/** Internal: consumes only a descriptor returned by this binding. */
|
|
93
|
+
closeOwnedFd(fd: number): void;
|
|
94
|
+
/** Internal Darwin-only synchronous inspection; the caller retains its fd. */
|
|
95
|
+
inspectDarwinAcl?(fd: number): NativeDarwinAclFacts;
|
|
84
96
|
/** POSIX system canonicalization; confinement and identity policy stay with callers. */
|
|
85
97
|
canonicalizePath?(path: string, ordinary: boolean): {
|
|
86
98
|
path?: string;
|
|
87
99
|
errno?: number;
|
|
88
100
|
};
|
|
101
|
+
/** Internal: exact directory identity and canonical path from one no-follow handle. */
|
|
102
|
+
observeDirectory?(path: string): NativeDirectoryObservation;
|
|
89
103
|
/** Linux/Windows byte transfer; callers retain both admitted descriptors until settlement. */
|
|
90
104
|
copyFileContents?(sourceFd: number, targetFd: number, signal?: AbortSignal): Promise<void>;
|
|
91
105
|
/** Internal: same private, immutable input ownership as the ZIP buffer reader. */
|
|
@@ -112,6 +126,8 @@ export interface NativeBinding {
|
|
|
112
126
|
fstatIdentity(fd: number): NativeFileIdentity;
|
|
113
127
|
inspectArchiveNative(path: string, kind: string, limits: TarMeterLimits, signal: AbortSignal): Promise<NativeArchiveEntry[]>;
|
|
114
128
|
linkBeneath(sourceRootFd: number, sourceRelPath: string, targetRootFd: number, targetRelPath: string): void;
|
|
129
|
+
/** Direct-child mkdir; true is receipt provenance only, never cleanup ownership. */
|
|
130
|
+
mkdirChildBeneath?(parentFd: number, basename: string, mode: number): boolean;
|
|
115
131
|
mkdirBeneath(rootFd: number, relPath: string, mode: number): void;
|
|
116
132
|
openBeneath(rootFd: number, relPath: string, flags: number): NativeOpenBeneathResult;
|
|
117
133
|
readArchiveEntryNative(path: string, kind: string, requested: string, maxBytes: number, limits: TarMeterLimits, signal: AbortSignal): Promise<Buffer>;
|
|
@@ -125,4 +141,5 @@ export interface NativeBinding {
|
|
|
125
141
|
renameReplace(sourceRootFd: number, sourceRelPath: string, targetRootFd: number, targetRelPath: string): void;
|
|
126
142
|
sha256File(fd: number, maxBytes?: number, signal?: AbortSignal): Promise<NativeFileHash>;
|
|
127
143
|
}
|
|
144
|
+
export declare function captureNativeFdClose(binding: NativeBinding): (fd: number) => void;
|
|
128
145
|
//# sourceMappingURL=native-binding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"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"}
|
package/dist/native-binding.js
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { FsSafeError } from "./errors.js";
|
|
2
|
+
export function captureNativeFdClose(binding) {
|
|
3
|
+
if (typeof binding.closeOwnedFd !== "function") {
|
|
4
|
+
throw new FsSafeError("helper-unavailable", "native descriptor ownership is unavailable");
|
|
5
|
+
}
|
|
6
|
+
// Retained descriptors must remain disposable after native configuration changes.
|
|
7
|
+
return binding.closeOwnedFd.bind(binding);
|
|
8
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type NativeBinding } from "./native.js";
|
|
2
|
+
import type { NativeDirectoryObservation } from "./native-binding.js";
|
|
3
|
+
import type { ExactStatIdentity } from "./stat-observation.js";
|
|
4
|
+
export type NativeDirectoryObservationBackend = NativeBinding & {
|
|
5
|
+
observeDirectory(pathname: string): NativeDirectoryObservation;
|
|
6
|
+
};
|
|
7
|
+
export type NativeDirectoryObservationGuard = NativeDirectoryObservation & {
|
|
8
|
+
dir: string;
|
|
9
|
+
identity: ExactStatIdentity;
|
|
10
|
+
nativeDirectoryObservation: true;
|
|
11
|
+
};
|
|
12
|
+
export declare function getNativeDirectoryObservationBackend(enabled?: boolean): NativeDirectoryObservationBackend | undefined;
|
|
13
|
+
/** Exact identity, type, and canonical path captured from one retained handle. */
|
|
14
|
+
export declare function inspectNativeDirectoryObservation(backend: NativeDirectoryObservationBackend, pathname: string, expected?: ExactStatIdentity, platform?: NodeJS.Platform): NativeDirectoryObservation;
|
|
15
|
+
export declare function extendNativeDirectoryObservationGuard(observation: NativeDirectoryObservation, dir: string): NativeDirectoryObservationGuard;
|
|
16
|
+
export declare function isNativeDirectoryObservationGuard(guard: unknown): guard is NativeDirectoryObservationGuard;
|
|
17
|
+
//# sourceMappingURL=native-directory-observation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-directory-observation.d.ts","sourceRoot":"","sources":["../src/native-directory-observation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,MAAM,iCAAiC,GAAG,aAAa,GAAG;IAC9D,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CAAC;CAChE,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG,0BAA0B,GAAG;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,0BAA0B,EAAE,IAAI,CAAC;CAClC,CAAC;AAEF,wBAAgB,oCAAoC,CAClD,OAAO,UAAO,GACb,iCAAiC,GAAG,SAAS,CAM/C;AAeD,kFAAkF;AAClF,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,iCAAiC,EAC1C,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,0BAA0B,CAM5B;AAED,wBAAgB,qCAAqC,CACnD,WAAW,EAAE,0BAA0B,EACvC,GAAG,EAAE,MAAM,GACV,+BAA+B,CAMjC;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,+BAA+B,CAG1C"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { FsSafeError } from "./errors.js";
|
|
3
|
+
import { getNativeBinding } from "./native.js";
|
|
4
|
+
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
5
|
+
export function getNativeDirectoryObservationBackend(enabled = true) {
|
|
6
|
+
if (!enabled)
|
|
7
|
+
return undefined;
|
|
8
|
+
const binding = getNativeBinding();
|
|
9
|
+
return binding && typeof binding.observeDirectory === "function"
|
|
10
|
+
? binding
|
|
11
|
+
: undefined;
|
|
12
|
+
}
|
|
13
|
+
function validateNativeDirectoryObservation(observation) {
|
|
14
|
+
if (!observation || typeof observation.dev !== "bigint" || observation.dev < 0n ||
|
|
15
|
+
typeof observation.ino !== "bigint" || observation.ino < 0n ||
|
|
16
|
+
typeof observation.realPath !== "string" ||
|
|
17
|
+
observation.realPath.includes("\0") ||
|
|
18
|
+
(!path.isAbsolute(observation.realPath) && !path.win32.isAbsolute(observation.realPath))) {
|
|
19
|
+
throw new FsSafeError("path-mismatch", "native directory observation is invalid");
|
|
20
|
+
}
|
|
21
|
+
return observation;
|
|
22
|
+
}
|
|
23
|
+
/** Exact identity, type, and canonical path captured from one retained handle. */
|
|
24
|
+
export function inspectNativeDirectoryObservation(backend, pathname, expected, platform = process.platform) {
|
|
25
|
+
return inspectFileIdentitySync(() => validateNativeDirectoryObservation(backend.observeDirectory(pathname)), expected, platform);
|
|
26
|
+
}
|
|
27
|
+
export function extendNativeDirectoryObservationGuard(observation, dir) {
|
|
28
|
+
const guard = observation;
|
|
29
|
+
guard.dir = dir;
|
|
30
|
+
guard.identity = guard;
|
|
31
|
+
guard.nativeDirectoryObservation = true;
|
|
32
|
+
return guard;
|
|
33
|
+
}
|
|
34
|
+
export function isNativeDirectoryObservationGuard(guard) {
|
|
35
|
+
return typeof guard === "object" && guard !== null &&
|
|
36
|
+
guard.nativeDirectoryObservation === true;
|
|
37
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-operations.d.ts","sourceRoot":"","sources":["../src/native-operations.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-operations.d.ts","sourceRoot":"","sources":["../src/native-operations.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAK7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAI1D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAS5D;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,gBAAgB,EACvB,QAAQ,CAAC,EAAE,MAAM,EACjB,oBAAoB,CAAC,EAAE,MAAM,IAAI,GAChC,OAAO,CAAC,IAAI,CAAC,CAoBf;AA0BD,wBAAgB,oCAAoC,CAAC,MAAM,EAAE;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,GAAG,IAAI,CAqBP;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAyDvC"}
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { FsSafeError } from "./errors.js";
|
|
5
5
|
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
6
6
|
import { getNativeBinding } from "./native.js";
|
|
7
|
+
import { captureNativeFdClose } from "./native-binding.js";
|
|
7
8
|
import { writeAllToFile } from "./write-file-handle.js";
|
|
8
9
|
import { writeCopyFileToFd } from "./copy-file-input.js";
|
|
9
10
|
export function nativeOpenFlags(flags) {
|
|
@@ -44,7 +45,7 @@ export async function writeNativeInput(fd, input, maxBytes, assertBeforeMutation
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
|
-
function wrapNativeFd(fd, containment) {
|
|
48
|
+
function wrapNativeFd(fd, containment, closeFd) {
|
|
48
49
|
let open = true;
|
|
49
50
|
return {
|
|
50
51
|
fd,
|
|
@@ -52,7 +53,7 @@ function wrapNativeFd(fd, containment) {
|
|
|
52
53
|
async close() {
|
|
53
54
|
if (open) {
|
|
54
55
|
open = false;
|
|
55
|
-
|
|
56
|
+
closeFd(fd);
|
|
56
57
|
}
|
|
57
58
|
},
|
|
58
59
|
async stat() {
|
|
@@ -89,6 +90,7 @@ export async function createNativeExclusiveFile(targetPath, mode) {
|
|
|
89
90
|
if (!binding) {
|
|
90
91
|
return undefined;
|
|
91
92
|
}
|
|
93
|
+
const closeFd = captureNativeFdClose(binding);
|
|
92
94
|
const parentPath = path.dirname(targetPath);
|
|
93
95
|
const basename = path.basename(targetPath);
|
|
94
96
|
const parent = await fs.open(parentPath, fsSync.constants.O_RDONLY |
|
|
@@ -113,12 +115,12 @@ export async function createNativeExclusiveFile(targetPath, mode) {
|
|
|
113
115
|
fd = opened.fd;
|
|
114
116
|
fsSync.fchmodSync(fd, mode);
|
|
115
117
|
created = fsSync.fstatSync(fd, { bigint: true });
|
|
116
|
-
return wrapNativeFd(fd, opened.containment);
|
|
118
|
+
return wrapNativeFd(fd, opened.containment, closeFd);
|
|
117
119
|
}
|
|
118
120
|
catch (error) {
|
|
119
121
|
if (fd !== undefined) {
|
|
120
122
|
try {
|
|
121
|
-
|
|
123
|
+
closeFd(fd);
|
|
122
124
|
}
|
|
123
125
|
catch {
|
|
124
126
|
// Preserve the original error.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type BigIntStats, type Stats } from "node:fs";
|
|
2
|
+
import type { FileHandle } from "node:fs/promises";
|
|
3
|
+
import type { FileIdentityStat } from "./file-identity.js";
|
|
4
|
+
import type { NativeBinding } from "./native.js";
|
|
5
|
+
import { describeStagedDirectory } from "./staged-directory.js";
|
|
6
|
+
type RootIdentity = Pick<FileIdentityStat, "dev" | "ino">;
|
|
7
|
+
export type NativeRootAdmission = {
|
|
8
|
+
exactRoot: boolean;
|
|
9
|
+
operation: string;
|
|
10
|
+
root: FileHandle;
|
|
11
|
+
rootPath: string;
|
|
12
|
+
};
|
|
13
|
+
export type NativeParentAdmission = {
|
|
14
|
+
fd: number;
|
|
15
|
+
close(): void;
|
|
16
|
+
guard: {
|
|
17
|
+
dir: string;
|
|
18
|
+
realPath: string;
|
|
19
|
+
stat: Stats | BigIntStats;
|
|
20
|
+
};
|
|
21
|
+
stagedDirectory?: ReturnType<typeof describeStagedDirectory>;
|
|
22
|
+
};
|
|
23
|
+
export declare function sameNativeIdentity(left: RootIdentity, right: RootIdentity): boolean;
|
|
24
|
+
export declare function openNativeRootAdmission(binding: NativeBinding, params: {
|
|
25
|
+
rootPath: string;
|
|
26
|
+
rootIdentity?: RootIdentity;
|
|
27
|
+
operation?: string;
|
|
28
|
+
}): Promise<NativeRootAdmission>;
|
|
29
|
+
export declare function openNativeParentAdmission(binding: NativeBinding, rootAdmission: NativeRootAdmission, relativeParentPath: string): Promise<NativeParentAdmission>;
|
|
30
|
+
export declare function closeNativeParentAdmission(admission: NativeParentAdmission | undefined): void;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=native-parent-admission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-parent-admission.d.ts","sourceRoot":"","sources":["../src/native-parent-admission.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,EAAE,uBAAuB,EAAwB,MAAM,uBAAuB,CAAC;AAKtF,KAAK,YAAY,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,IAAI,IAAI,CAAC;IACd,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,GAAG,WAAW,CAAA;KAAE,CAAC;IACpE,eAAe,CAAC,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;CAC9D,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,YAAY,GAClB,OAAO,CAET;AAaD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5E,OAAO,CAAC,mBAAmB,CAAC,CAgD9B;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,aAAa,EACtB,aAAa,EAAE,mBAAmB,EAClC,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,qBAAqB,CAAC,CA+DhC;AAED,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,qBAAqB,GAAG,SAAS,GAAG,IAAI,CAE7F"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import fsSync, {} from "node:fs";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { inspectDirectoryIdentity } from "./directory-guard.js";
|
|
5
|
+
import { FsSafeError } from "./errors.js";
|
|
6
|
+
import { captureNativeFdClose } from "./native-binding.js";
|
|
7
|
+
import { realpathSync } from "./realpath.js";
|
|
8
|
+
import { describeStagedDirectory, exactIdentityMatches } from "./staged-directory.js";
|
|
9
|
+
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
10
|
+
import { createSuppressedError } from "./suppressed-error.js";
|
|
11
|
+
import { assertNoWindowsPathAlias, pathForWindowsFilesystem } from "./windows-path-alias.js";
|
|
12
|
+
export function sameNativeIdentity(left, right) {
|
|
13
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
14
|
+
}
|
|
15
|
+
function unavailable(message) {
|
|
16
|
+
return new FsSafeError("helper-unavailable", message);
|
|
17
|
+
}
|
|
18
|
+
function assertParentAdmissionAvailable(binding) {
|
|
19
|
+
if (typeof binding.openBeneath !== "function") {
|
|
20
|
+
throw unavailable("native parent directory admission is unavailable");
|
|
21
|
+
}
|
|
22
|
+
captureNativeFdClose(binding);
|
|
23
|
+
}
|
|
24
|
+
export async function openNativeRootAdmission(binding, params) {
|
|
25
|
+
assertParentAdmissionAvailable(binding);
|
|
26
|
+
const directoryFlags = fsSync.constants.O_RDONLY | (fsSync.constants.O_DIRECTORY ?? 0);
|
|
27
|
+
assertNoWindowsPathAlias(params.rootPath, "filesystem", "native root uses a Windows filesystem namespace alias");
|
|
28
|
+
const root = await fs.open(pathForWindowsFilesystem(params.rootPath), directoryFlags);
|
|
29
|
+
try {
|
|
30
|
+
const exactRoot = typeof params.rootIdentity?.dev === "bigint" &&
|
|
31
|
+
typeof params.rootIdentity.ino === "bigint";
|
|
32
|
+
let rootMatches;
|
|
33
|
+
if (exactRoot) {
|
|
34
|
+
inspectFileIdentitySync(() => fsSync.fstatSync(root.fd, { bigint: true }), params.rootIdentity);
|
|
35
|
+
rootMatches = true;
|
|
36
|
+
}
|
|
37
|
+
else if (process.platform === "win32") {
|
|
38
|
+
if (typeof binding.fstatIdentity !== "function") {
|
|
39
|
+
throw unavailable("native root directory identity checks are unavailable");
|
|
40
|
+
}
|
|
41
|
+
const identity = binding.fstatIdentity(root.fd);
|
|
42
|
+
rootMatches = !params.rootIdentity || sameNativeIdentity(params.rootIdentity, identity);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const identity = fsSync.fstatSync(root.fd, { bigint: true });
|
|
46
|
+
rootMatches = !params.rootIdentity || exactIdentityMatches(params.rootIdentity, identity);
|
|
47
|
+
}
|
|
48
|
+
if (!rootMatches) {
|
|
49
|
+
throw new FsSafeError("path-mismatch", `root path changed during ${params.operation ?? "native admission"}`);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
exactRoot,
|
|
53
|
+
operation: params.operation ?? "native admission",
|
|
54
|
+
root,
|
|
55
|
+
rootPath: params.rootPath,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
try {
|
|
60
|
+
await root.close();
|
|
61
|
+
}
|
|
62
|
+
catch (closeError) {
|
|
63
|
+
// Windows admission keeps the typed boundary failure primary.
|
|
64
|
+
if (process.platform !== "win32") {
|
|
65
|
+
throw createSuppressedError(closeError, error, "native root admission and close failed");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export async function openNativeParentAdmission(binding, rootAdmission, relativeParentPath) {
|
|
72
|
+
assertParentAdmissionAvailable(binding);
|
|
73
|
+
const closeFd = captureNativeFdClose(binding);
|
|
74
|
+
const directoryFlags = fsSync.constants.O_RDONLY | (fsSync.constants.O_DIRECTORY ?? 0);
|
|
75
|
+
assertNoWindowsPathAlias(relativeParentPath, "relative", "native parent uses a Windows filesystem namespace alias");
|
|
76
|
+
const opened = binding.openBeneath(rootAdmission.root.fd, relativeParentPath, directoryFlags);
|
|
77
|
+
if (!opened || !Number.isInteger(opened.fd) || opened.fd < 0) {
|
|
78
|
+
throw unavailable("native parent directory admission did not provide a descriptor");
|
|
79
|
+
}
|
|
80
|
+
const parentFd = opened.fd;
|
|
81
|
+
try {
|
|
82
|
+
const parentInput = relativeParentPath
|
|
83
|
+
? path.join(rootAdmission.rootPath, ...relativeParentPath.split("/"))
|
|
84
|
+
: rootAdmission.rootPath;
|
|
85
|
+
const parentPath = realpathSync.native(pathForWindowsFilesystem(parentInput));
|
|
86
|
+
assertNoWindowsPathAlias(parentPath, "filesystem", "native parent uses a Windows filesystem namespace alias");
|
|
87
|
+
const stagedDirectory = process.platform === "win32"
|
|
88
|
+
? undefined
|
|
89
|
+
: describeStagedDirectory(parentFd, parentPath);
|
|
90
|
+
const parentPathStat = rootAdmission.exactRoot
|
|
91
|
+
? await inspectDirectoryIdentity(parentPath, inspectFileIdentitySync(() => fsSync.fstatSync(parentFd, { bigint: true })))
|
|
92
|
+
: fsSync.lstatSync(pathForWindowsFilesystem(parentPath));
|
|
93
|
+
if (process.platform === "win32" && !rootAdmission.exactRoot) {
|
|
94
|
+
if (typeof binding.fstatIdentity !== "function") {
|
|
95
|
+
throw unavailable("native parent directory identity checks are unavailable");
|
|
96
|
+
}
|
|
97
|
+
const parentIdentity = binding.fstatIdentity(parentFd);
|
|
98
|
+
if (parentPathStat.isSymbolicLink() || !sameNativeIdentity(parentPathStat, parentIdentity)) {
|
|
99
|
+
throw new FsSafeError("path-mismatch", `${rootAdmission.operation} parent changed during resolution`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (process.platform !== "win32" &&
|
|
103
|
+
(parentPathStat.isSymbolicLink() || !exactIdentityMatches(parentPathStat, stagedDirectory.identity))) {
|
|
104
|
+
throw new FsSafeError("path-mismatch", `${rootAdmission.operation} parent changed during resolution`);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
fd: parentFd,
|
|
108
|
+
close: () => closeFd(parentFd),
|
|
109
|
+
guard: { dir: parentPath, realPath: parentPath, stat: parentPathStat },
|
|
110
|
+
stagedDirectory,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
try {
|
|
115
|
+
closeFd(parentFd);
|
|
116
|
+
}
|
|
117
|
+
catch (closeError) {
|
|
118
|
+
if (process.platform !== "win32") {
|
|
119
|
+
throw createSuppressedError(closeError, error, "native parent admission and close failed");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function closeNativeParentAdmission(admission) {
|
|
126
|
+
admission?.close();
|
|
127
|
+
}
|
|
@@ -3,6 +3,5 @@ import type { AnyAsyncDirectoryGuard } from "./directory-guard.js";
|
|
|
3
3
|
import type { FileIdentityStat } from "./file-identity.js";
|
|
4
4
|
import type { NativeBinding } from "./native.js";
|
|
5
5
|
import type { PinnedWriteParams } from "./pinned-write.js";
|
|
6
|
-
export declare function sameNativeIdentity(left: Pick<FileIdentityStat, "dev" | "ino">, right: Pick<FileIdentityStat, "dev" | "ino">): boolean;
|
|
7
6
|
export declare function runPinnedWriteWindows(binding: NativeBinding, params: PinnedWriteParams, root: FileHandle, parentFd: number, parentGuard: AnyAsyncDirectoryGuard): Promise<FileIdentityStat>;
|
|
8
7
|
//# sourceMappingURL=native-pinned-write-windows.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-pinned-write-windows.d.ts","sourceRoot":"","sources":["../src/native-pinned-write-windows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"native-pinned-write-windows.d.ts","sourceRoot":"","sources":["../src/native-pinned-write-windows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAa3D,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,gBAAgB,CAAC,CA2F3B"}
|