@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
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import fsSync from "node:fs";
|
|
1
|
+
import { randomInt, randomUUID } from "node:crypto";
|
|
2
|
+
import fsSync, {} from "node:fs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileStore, fileStoreSync, } from "./file-store.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
7
|
import { isNotFoundPathError } from "./path.js";
|
|
8
|
-
import {
|
|
9
|
-
import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
|
|
8
|
+
import { inspectDirectoryIdentitySync } from "./directory-guard.js";
|
|
10
9
|
import { throwFsSafeReadError } from "./root-errors.js";
|
|
11
10
|
import { matchRootFileOpenFailure, openRootFileSync, } from "./root-file.js";
|
|
12
11
|
import { registerTempPathForExit, } from "./temp-cleanup.js";
|
|
13
12
|
import { TempWorkspaceCleanupCapability, TempWorkspaceCleanupOwner, } from "./temp-workspace-owner.js";
|
|
13
|
+
import { assertNoWindowsPathAlias, hasWindowsPathAlias, } from "./windows-path-alias.js";
|
|
14
|
+
import { TempWorkspaceRetainedChild } from "./temp-workspace-descriptor.js";
|
|
15
|
+
import { admitRetainedTempWorkspaceChild, admitRetainedTempWorkspaceChildSync, validateInitialTempWorkspaceChild, } from "./temp-workspace-child-admission.js";
|
|
16
|
+
import { admitTempWorkspaceRoot, admitTempWorkspaceRootSync, } from "./temp-workspace-admission.js";
|
|
17
|
+
import { validateTempWorkspaceDirMode } from "./temp-workspace-permissions.js";
|
|
14
18
|
function resolveTempWorkspaceCleanupSafety(value) {
|
|
15
19
|
if (value === undefined || value === "compatible")
|
|
16
20
|
return "compatible";
|
|
@@ -25,8 +29,43 @@ function sanitizeTempPrefix(prefix) {
|
|
|
25
29
|
}
|
|
26
30
|
return sanitized.endsWith("-") ? sanitized : `${sanitized}-`;
|
|
27
31
|
}
|
|
32
|
+
const TEMP_WORKSPACE_SUFFIX_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
33
|
+
const TEMP_WORKSPACE_SUFFIX_SPACE = TEMP_WORKSPACE_SUFFIX_ALPHABET.length ** 6;
|
|
34
|
+
const TEMP_WORKSPACE_DIRECT_CREATE_ATTEMPTS = 64;
|
|
35
|
+
function randomTempWorkspaceChildPath(childPrefix) {
|
|
36
|
+
let encoded = randomInt(TEMP_WORKSPACE_SUFFIX_SPACE);
|
|
37
|
+
let suffix = "";
|
|
38
|
+
for (let index = 0; index < 6; index += 1) {
|
|
39
|
+
suffix = TEMP_WORKSPACE_SUFFIX_ALPHABET[encoded % TEMP_WORKSPACE_SUFFIX_ALPHABET.length] + suffix;
|
|
40
|
+
encoded = Math.floor(encoded / TEMP_WORKSPACE_SUFFIX_ALPHABET.length);
|
|
41
|
+
}
|
|
42
|
+
return `${childPrefix}${suffix}`;
|
|
43
|
+
}
|
|
44
|
+
function canCreateTempWorkspaceWithRequestedMode(dirMode) {
|
|
45
|
+
return (process.platform === "linux" || process.platform === "darwin") && dirMode !== 0o700 &&
|
|
46
|
+
(dirMode & 0o700) === 0o700 && (dirMode & 0o7000) === 0 && (dirMode & 0o022) === 0;
|
|
47
|
+
}
|
|
48
|
+
function createTempWorkspaceWithRequestedModeSync(childPrefix, dirMode, prepareChildCreation) {
|
|
49
|
+
let collision;
|
|
50
|
+
for (let attempt = 0; attempt < TEMP_WORKSPACE_DIRECT_CREATE_ATTEMPTS; attempt += 1) {
|
|
51
|
+
const candidate = randomTempWorkspaceChildPath(childPrefix);
|
|
52
|
+
prepareChildCreation();
|
|
53
|
+
try {
|
|
54
|
+
fsSync.mkdirSync(candidate, { mode: dirMode, recursive: false });
|
|
55
|
+
return candidate;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error.code !== "EEXIST")
|
|
59
|
+
throw error;
|
|
60
|
+
collision = error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throw collision;
|
|
64
|
+
}
|
|
28
65
|
function resolveWorkspaceLeaf(dir, fileName) {
|
|
29
|
-
|
|
66
|
+
const resolved = path.join(dir, assertWorkspaceFileName(fileName));
|
|
67
|
+
assertNoWindowsPathAlias(resolved, "filesystem", "temp workspace path uses a Windows filesystem namespace alias");
|
|
68
|
+
return resolved;
|
|
30
69
|
}
|
|
31
70
|
function assertWorkspaceFileName(fileName) {
|
|
32
71
|
const value = fileName.trim();
|
|
@@ -36,6 +75,7 @@ function assertWorkspaceFileName(fileName) {
|
|
|
36
75
|
value.includes("\0") ||
|
|
37
76
|
value.includes("/") ||
|
|
38
77
|
value.includes("\\") ||
|
|
78
|
+
hasWindowsPathAlias(value, "relative") ||
|
|
39
79
|
path.basename(value) !== value) {
|
|
40
80
|
throw new Error(`Invalid temp workspace file name: ${JSON.stringify(fileName)}`);
|
|
41
81
|
}
|
|
@@ -67,55 +107,60 @@ function throwTempWorkspaceOpenFailure(failure) {
|
|
|
67
107
|
},
|
|
68
108
|
});
|
|
69
109
|
}
|
|
70
|
-
async function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (!stat.isDirectory()) {
|
|
74
|
-
throw new Error(`Temp root must be a directory: ${dir}`);
|
|
75
|
-
}
|
|
76
|
-
await fs.chmod(dir, mode).catch(() => undefined);
|
|
77
|
-
}
|
|
78
|
-
function ensurePrivateDirectorySync(dir, mode) {
|
|
79
|
-
fsSync.mkdirSync(recursiveMkdirPath(dir), { recursive: true, mode });
|
|
80
|
-
const stat = fsSync.statSync(dir);
|
|
81
|
-
if (!stat.isDirectory()) {
|
|
82
|
-
throw new Error(`Temp root must be a directory: ${dir}`);
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
fsSync.chmodSync(dir, mode);
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
// Best-effort on platforms that do not enforce POSIX modes.
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
async function createTempWorkspace(options) {
|
|
110
|
+
async function createTempWorkspace(options, scopedPrefix = false) {
|
|
111
|
+
const rootDir = options.rootDir;
|
|
112
|
+
assertNoWindowsPathAlias(rootDir, "filesystem", "temp workspace root uses a Windows filesystem namespace alias");
|
|
92
113
|
const dirMode = options.dirMode ?? 0o700;
|
|
114
|
+
validateTempWorkspaceDirMode(dirMode);
|
|
93
115
|
const mode = options.mode ?? 0o600;
|
|
94
116
|
const cleanupSafety = resolveTempWorkspaceCleanupSafety(options.cleanupSafety);
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
117
|
+
const admission = await admitTempWorkspaceRoot(rootDir);
|
|
118
|
+
const root = admission.dir;
|
|
119
|
+
assertNoWindowsPathAlias(root, "filesystem", "temp workspace root uses a Windows filesystem namespace alias");
|
|
120
|
+
// Capture and sanitize caller-controlled prefix data before retaining descriptors.
|
|
121
|
+
const rawPrefix = options.prefix;
|
|
122
|
+
const workspacePrefix = scopedPrefix
|
|
123
|
+
? `${sanitizeTempPrefix(rawPrefix)}${randomUUID()}-`
|
|
124
|
+
: rawPrefix;
|
|
125
|
+
const childPrefix = path.join(root, sanitizeTempPrefix(workspacePrefix));
|
|
126
|
+
assertNoWindowsPathAlias(childPrefix, "filesystem", "temp workspace path uses a Windows filesystem namespace alias");
|
|
127
|
+
const capability = new TempWorkspaceCleanupCapability(root, cleanupSafety, admission, dirMode);
|
|
105
128
|
let dir;
|
|
106
129
|
let stat;
|
|
130
|
+
let retainedChild;
|
|
131
|
+
let retainChildDescriptor = false;
|
|
107
132
|
let cleanupOwner;
|
|
108
133
|
let unregisterTempDir;
|
|
109
134
|
try {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
135
|
+
// Native capability discovery is complete before this synchronous
|
|
136
|
+
// boundary. The existing canonical-root route now captures the complete
|
|
137
|
+
// ancestry and associates its provisional parent descriptor here, then
|
|
138
|
+
// dispatches mkdtemp without yielding or invoking another probe.
|
|
139
|
+
capability.prepareChildCreation();
|
|
140
|
+
dir = await fs.mkdtemp(childPrefix);
|
|
141
|
+
assertNoWindowsPathAlias(dir, "filesystem", "temp workspace path uses a Windows filesystem namespace alias");
|
|
116
142
|
if (capability.parent)
|
|
117
143
|
capability.assertCurrent();
|
|
118
|
-
|
|
144
|
+
else
|
|
145
|
+
admission.assertCurrent();
|
|
146
|
+
stat = inspectDirectoryIdentitySync(dir);
|
|
147
|
+
const needsModeInitialization = validateInitialTempWorkspaceChild(stat, admission.ownerUid, dirMode);
|
|
148
|
+
// Retain while the child still has its private creation mode so an
|
|
149
|
+
// explicit dirMode such as 0 cannot make identity descriptor acquisition fail.
|
|
150
|
+
retainedChild = TempWorkspaceRetainedChild.retain(dir, stat);
|
|
151
|
+
const modeInitialization = admitRetainedTempWorkspaceChild(retainedChild, needsModeInitialization, admission, dirMode);
|
|
152
|
+
if (modeInitialization)
|
|
153
|
+
await modeInitialization;
|
|
154
|
+
retainChildDescriptor = capability.admitChildDescriptor(retainedChild.ensureReadable());
|
|
155
|
+
// Final adoption order is deliberate: complete ancestry, retained cleanup
|
|
156
|
+
// parent, then descriptor and named checks of the original child identity.
|
|
157
|
+
if (capability.parent)
|
|
158
|
+
capability.assertAncestryCurrent();
|
|
159
|
+
else
|
|
160
|
+
admission.assertAncestry();
|
|
161
|
+
stat = retainedChild.finalizeAdmission(admission.ownerUid, dirMode);
|
|
162
|
+
cleanupOwner = new TempWorkspaceCleanupOwner(retainedChild, capability, retainChildDescriptor);
|
|
163
|
+
retainedChild = undefined;
|
|
119
164
|
unregisterTempDir = registerTempPathForExit(dir, {
|
|
120
165
|
cleanupSync: () => cleanupOwner.cleanupSync(),
|
|
121
166
|
});
|
|
@@ -124,8 +169,26 @@ async function createTempWorkspace(options) {
|
|
|
124
169
|
try {
|
|
125
170
|
if (cleanupOwner)
|
|
126
171
|
cleanupOwner.cleanupSync();
|
|
127
|
-
else
|
|
128
|
-
|
|
172
|
+
else {
|
|
173
|
+
const closeErrors = [];
|
|
174
|
+
try {
|
|
175
|
+
retainedChild?.close();
|
|
176
|
+
}
|
|
177
|
+
catch (closeError) {
|
|
178
|
+
closeErrors.push(closeError);
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
capability.close();
|
|
182
|
+
}
|
|
183
|
+
catch (closeError) {
|
|
184
|
+
closeErrors.push(closeError);
|
|
185
|
+
}
|
|
186
|
+
if (closeErrors.length === 1)
|
|
187
|
+
throw closeErrors[0];
|
|
188
|
+
if (closeErrors.length > 1) {
|
|
189
|
+
throw new AggregateError(closeErrors, "temp workspace admission descriptor close failed");
|
|
190
|
+
}
|
|
191
|
+
}
|
|
129
192
|
}
|
|
130
193
|
catch (cleanupError) {
|
|
131
194
|
throw new AggregateError([error, cleanupError], "temp workspace creation and cleanup both failed");
|
|
@@ -178,10 +241,7 @@ export async function tempWorkspace(options) {
|
|
|
178
241
|
return await createTempWorkspace(options);
|
|
179
242
|
}
|
|
180
243
|
export async function withTempWorkspace(options, run) {
|
|
181
|
-
const workspace = await createTempWorkspace(
|
|
182
|
-
...options,
|
|
183
|
-
prefix: `${sanitizeTempPrefix(options.prefix)}${randomUUID()}-`,
|
|
184
|
-
});
|
|
244
|
+
const workspace = await createTempWorkspace(options, true);
|
|
185
245
|
try {
|
|
186
246
|
return await run(workspace);
|
|
187
247
|
}
|
|
@@ -189,39 +249,67 @@ export async function withTempWorkspace(options, run) {
|
|
|
189
249
|
await workspace.cleanup();
|
|
190
250
|
}
|
|
191
251
|
}
|
|
192
|
-
|
|
252
|
+
function createTempWorkspaceSync(options, scopedPrefix = false) {
|
|
253
|
+
const rootDir = options.rootDir;
|
|
254
|
+
assertNoWindowsPathAlias(rootDir, "filesystem", "temp workspace root uses a Windows filesystem namespace alias");
|
|
193
255
|
const dirMode = options.dirMode ?? 0o700;
|
|
256
|
+
validateTempWorkspaceDirMode(dirMode);
|
|
194
257
|
const mode = options.mode ?? 0o600;
|
|
195
258
|
const cleanupSafety = resolveTempWorkspaceCleanupSafety(options.cleanupSafety);
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
259
|
+
const admission = admitTempWorkspaceRootSync(rootDir);
|
|
260
|
+
const root = admission.dir;
|
|
261
|
+
assertNoWindowsPathAlias(root, "filesystem", "temp workspace root uses a Windows filesystem namespace alias");
|
|
262
|
+
// Capture and sanitize caller-controlled prefix data before retaining descriptors.
|
|
263
|
+
const rawPrefix = options.prefix;
|
|
264
|
+
const workspacePrefix = scopedPrefix
|
|
265
|
+
? `${sanitizeTempPrefix(rawPrefix)}${randomUUID()}-`
|
|
266
|
+
: rawPrefix;
|
|
267
|
+
const childPrefix = path.join(root, sanitizeTempPrefix(workspacePrefix));
|
|
268
|
+
assertNoWindowsPathAlias(childPrefix, "filesystem", "temp workspace path uses a Windows filesystem namespace alias");
|
|
269
|
+
const capability = new TempWorkspaceCleanupCapability(root, cleanupSafety, admission, dirMode);
|
|
206
270
|
let dir;
|
|
207
271
|
let stat;
|
|
272
|
+
let retainedChild;
|
|
273
|
+
let retainChildDescriptor = false;
|
|
274
|
+
let needsModeInitialization;
|
|
208
275
|
let cleanupOwner;
|
|
209
276
|
let unregisterTempDir;
|
|
210
277
|
try {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
278
|
+
const directRequestedMode = canCreateTempWorkspaceWithRequestedMode(dirMode);
|
|
279
|
+
if (directRequestedMode) {
|
|
280
|
+
dir = createTempWorkspaceWithRequestedModeSync(childPrefix, dirMode, () => capability.prepareChildCreation());
|
|
214
281
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
stat = fsSync.lstatSync(dir, { bigint: true });
|
|
219
|
-
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
220
|
-
throw new Error(`Temp workspace must be a directory: ${dir}`);
|
|
282
|
+
else {
|
|
283
|
+
capability.prepareChildCreation();
|
|
284
|
+
dir = fsSync.mkdtempSync(childPrefix);
|
|
221
285
|
}
|
|
286
|
+
assertNoWindowsPathAlias(dir, "filesystem", "temp workspace path uses a Windows filesystem namespace alias");
|
|
222
287
|
if (capability.parent)
|
|
223
288
|
capability.assertCurrent();
|
|
224
|
-
|
|
289
|
+
else
|
|
290
|
+
admission.assertCurrent();
|
|
291
|
+
if (directRequestedMode) {
|
|
292
|
+
const created = TempWorkspaceRetainedChild.retainCreated(dir);
|
|
293
|
+
retainedChild = created.retained;
|
|
294
|
+
stat = created.stat;
|
|
295
|
+
needsModeInitialization = validateInitialTempWorkspaceChild(stat, admission.ownerUid, dirMode);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
stat = inspectDirectoryIdentitySync(dir);
|
|
299
|
+
needsModeInitialization = validateInitialTempWorkspaceChild(stat, admission.ownerUid, dirMode);
|
|
300
|
+
retainedChild = TempWorkspaceRetainedChild.retain(dir, stat);
|
|
301
|
+
}
|
|
302
|
+
admitRetainedTempWorkspaceChildSync(retainedChild, needsModeInitialization, admission, dirMode);
|
|
303
|
+
retainChildDescriptor = capability.admitChildDescriptor(retainedChild.ensureReadable());
|
|
304
|
+
// Match async adoption: complete ancestry and retained cleanup authority
|
|
305
|
+
// precede descriptor and named child security-state checks.
|
|
306
|
+
if (capability.parent)
|
|
307
|
+
capability.assertAncestryCurrent();
|
|
308
|
+
else
|
|
309
|
+
admission.assertAncestry();
|
|
310
|
+
stat = retainedChild.finalizeAdmission(admission.ownerUid, dirMode);
|
|
311
|
+
cleanupOwner = new TempWorkspaceCleanupOwner(retainedChild, capability, retainChildDescriptor);
|
|
312
|
+
retainedChild = undefined;
|
|
225
313
|
unregisterTempDir = registerTempPathForExit(dir, {
|
|
226
314
|
cleanupSync: () => cleanupOwner.cleanupSync(),
|
|
227
315
|
});
|
|
@@ -230,8 +318,26 @@ export function tempWorkspaceSync(options) {
|
|
|
230
318
|
try {
|
|
231
319
|
if (cleanupOwner)
|
|
232
320
|
cleanupOwner.cleanupSync();
|
|
233
|
-
else
|
|
234
|
-
|
|
321
|
+
else {
|
|
322
|
+
const closeErrors = [];
|
|
323
|
+
try {
|
|
324
|
+
retainedChild?.close();
|
|
325
|
+
}
|
|
326
|
+
catch (closeError) {
|
|
327
|
+
closeErrors.push(closeError);
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
capability.close();
|
|
331
|
+
}
|
|
332
|
+
catch (closeError) {
|
|
333
|
+
closeErrors.push(closeError);
|
|
334
|
+
}
|
|
335
|
+
if (closeErrors.length === 1)
|
|
336
|
+
throw closeErrors[0];
|
|
337
|
+
if (closeErrors.length > 1) {
|
|
338
|
+
throw new AggregateError(closeErrors, "temp workspace admission descriptor close failed");
|
|
339
|
+
}
|
|
340
|
+
}
|
|
235
341
|
}
|
|
236
342
|
catch (cleanupError) {
|
|
237
343
|
throw new AggregateError([error, cleanupError], "temp workspace creation and cleanup both failed");
|
|
@@ -293,11 +399,11 @@ export function tempWorkspaceSync(options) {
|
|
|
293
399
|
},
|
|
294
400
|
};
|
|
295
401
|
}
|
|
402
|
+
export function tempWorkspaceSync(options) {
|
|
403
|
+
return createTempWorkspaceSync(options);
|
|
404
|
+
}
|
|
296
405
|
export function withTempWorkspaceSync(options, run) {
|
|
297
|
-
const workspace =
|
|
298
|
-
...options,
|
|
299
|
-
prefix: `${sanitizeTempPrefix(options.prefix)}${randomUUID()}-`,
|
|
300
|
-
});
|
|
406
|
+
const workspace = createTempWorkspaceSync(options, true);
|
|
301
407
|
try {
|
|
302
408
|
return run(workspace);
|
|
303
409
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAML,KAAK,qCAAqC,EAC3C,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAML,KAAK,qCAAqC,EAC3C,MAAM,2BAA2B,CAAC;AAKnC,YAAY,EACV,2BAA2B,EAC3B,wCAAwC,EACxC,kCAAkC,EAClC,gCAAgC,EAChC,qCAAqC,GACtC,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,4BAA4B,GAAG,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAEjG,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAIF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE/D;AAyND,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,gBAAgB,CAAC;IAC1C,QAAQ,EAAE,4BAA4B,CAAC;IACvC,aAAa,CAAC,EAAE,qCAAqC,CAAC;IACtD,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA6NtC"}
|
package/dist/publish-file.js
CHANGED
|
@@ -10,28 +10,15 @@ import { syncFileBestEffortSync } from "./file-sync.js";
|
|
|
10
10
|
import { getNativeBinding, requireNativeBinding } from "./native.js";
|
|
11
11
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
12
12
|
import { directorySyncFailure, publicationFailure, rememberCreatedTarget, } from "./publish-file-failure.js";
|
|
13
|
+
import { admitStandalonePublicationPath } from "./standalone-publication-path.js";
|
|
13
14
|
import { getFsSafeTestHooks } from "./test-hooks.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"ENOTSUP",
|
|
18
|
-
"EOPNOTSUPP",
|
|
19
|
-
"ENOSYS",
|
|
20
|
-
]);
|
|
21
|
-
const NATIVE_COPY_FALLBACK_CODES = new Set([
|
|
22
|
-
"EINVAL",
|
|
23
|
-
"ENOSYS",
|
|
24
|
-
"ENOTSUP",
|
|
25
|
-
"EOPNOTSUPP",
|
|
26
|
-
"EPERM",
|
|
27
|
-
"EXDEV",
|
|
28
|
-
]);
|
|
15
|
+
import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
|
|
16
|
+
const HARDLINK_FALLBACK_CODES = new Set(["EPERM", "EXDEV", "ENOTSUP", "EOPNOTSUPP", "ENOSYS"]);
|
|
17
|
+
const NATIVE_COPY_FALLBACK_CODES = new Set(["EINVAL", "ENOSYS", "ENOTSUP", "EOPNOTSUPP", "EPERM", "EXDEV"]);
|
|
29
18
|
export function isHardlinkFallbackError(error) {
|
|
30
19
|
return HARDLINK_FALLBACK_CODES.has(error?.code ?? "");
|
|
31
20
|
}
|
|
32
|
-
function sourceOpenFlags() {
|
|
33
|
-
return resolveReadOpenFlags();
|
|
34
|
-
}
|
|
21
|
+
function sourceOpenFlags() { return resolveReadOpenFlags(); }
|
|
35
22
|
function directoryOpenFlags() {
|
|
36
23
|
return (fsSync.constants.O_RDONLY |
|
|
37
24
|
(typeof fsSync.constants.O_DIRECTORY === "number" ? fsSync.constants.O_DIRECTORY : 0));
|
|
@@ -190,12 +177,27 @@ async function syncPublishedParent(params) {
|
|
|
190
177
|
}
|
|
191
178
|
}
|
|
192
179
|
export async function publishFileExclusive(params) {
|
|
193
|
-
const
|
|
194
|
-
const
|
|
180
|
+
const sourcePathInput = admitStandalonePublicationPath(params.sourcePath, "publication source uses a Windows filesystem namespace alias");
|
|
181
|
+
const targetPathInput = admitStandalonePublicationPath(params.targetPath, "publication target uses a Windows filesystem namespace alias");
|
|
182
|
+
const parentReceiptInput = params.parentReceipt;
|
|
183
|
+
const parentReceipt = parentReceiptInput
|
|
184
|
+
? { path: parentReceiptInput.path, realPath: parentReceiptInput.realPath,
|
|
185
|
+
identity: parentReceiptInput.identity }
|
|
186
|
+
: undefined;
|
|
187
|
+
if (parentReceipt) {
|
|
188
|
+
assertNoWindowsPathAlias(parentReceipt.path, "filesystem", "publication parent uses a Windows filesystem namespace alias");
|
|
189
|
+
}
|
|
190
|
+
const sourcePath = path.resolve(sourcePathInput);
|
|
191
|
+
const targetPath = path.resolve(targetPathInput);
|
|
192
|
+
assertNoWindowsPathAlias(sourcePath, "filesystem", "publication source uses a Windows filesystem namespace alias");
|
|
193
|
+
assertNoWindowsPathAlias(targetPath, "filesystem", "publication target uses a Windows filesystem namespace alias");
|
|
195
194
|
const parentPath = path.dirname(targetPath);
|
|
196
|
-
if (
|
|
195
|
+
if (parentReceipt && path.resolve(parentReceipt.path) !== parentPath) {
|
|
197
196
|
throw new FsSafeError("path-mismatch", "publication parent receipt does not match target parent");
|
|
198
197
|
}
|
|
198
|
+
if (parentReceipt) {
|
|
199
|
+
assertNoWindowsPathAlias(parentReceipt.realPath, "filesystem", "publication parent uses a Windows filesystem namespace alias");
|
|
200
|
+
}
|
|
199
201
|
const sourcePathStat = fsSync.lstatSync(sourcePath);
|
|
200
202
|
if (sourcePathStat.isSymbolicLink() || !sourcePathStat.isFile()) {
|
|
201
203
|
throw new FsSafeError("not-file", "publication source must be a regular file");
|
|
@@ -204,38 +206,40 @@ export async function publishFileExclusive(params) {
|
|
|
204
206
|
let parent;
|
|
205
207
|
let sourceNativeParent;
|
|
206
208
|
let targetNativeParent;
|
|
209
|
+
const strategy = params.strategy;
|
|
207
210
|
const failure = {
|
|
208
|
-
phase:
|
|
211
|
+
phase: strategy === "rename-noreplace" ? "rename-create" : "hardlink-create",
|
|
209
212
|
targetCreated: false,
|
|
210
213
|
preserveTarget: false,
|
|
211
214
|
};
|
|
212
215
|
try {
|
|
213
|
-
parent = await pinDirectory(
|
|
216
|
+
parent = await pinDirectory(parentReceipt ?? parentPath, {
|
|
214
217
|
label: "publication parent",
|
|
215
218
|
});
|
|
216
219
|
const sourceIdentity = fsSync.fstatSync(source.fd);
|
|
217
220
|
const sourceExactIdentity = fsSync.fstatSync(source.fd, { bigint: true });
|
|
218
221
|
const sourcePathExactIdentity = fsSync.lstatSync(sourcePath, { bigint: true });
|
|
222
|
+
const expectedSourceIdentity = params.expectedSourceIdentity;
|
|
219
223
|
if (sourcePathExactIdentity.isSymbolicLink() ||
|
|
220
224
|
!sourcePathExactIdentity.isFile() ||
|
|
221
225
|
!sameFileIdentity(sourcePathExactIdentity, sourceExactIdentity) ||
|
|
222
|
-
(
|
|
223
|
-
!sameFileIdentity(
|
|
224
|
-
typeof
|
|
226
|
+
(expectedSourceIdentity &&
|
|
227
|
+
!sameFileIdentity(expectedSourceIdentity, typeof expectedSourceIdentity.dev === "bigint" ||
|
|
228
|
+
typeof expectedSourceIdentity.ino === "bigint"
|
|
225
229
|
? sourceExactIdentity
|
|
226
230
|
: sourceIdentity))) {
|
|
227
231
|
throw new FsSafeError("path-mismatch", "publication source identity did not match");
|
|
228
232
|
}
|
|
229
233
|
await parent.assertCurrent();
|
|
230
234
|
await assertPinnedSourceCurrent({ sourcePath, handle: source, identity: sourceExactIdentity });
|
|
231
|
-
const native =
|
|
235
|
+
const native = strategy === "rename-noreplace"
|
|
232
236
|
? requireNativeBinding()
|
|
233
237
|
: getNativeBinding();
|
|
234
238
|
if (native) {
|
|
235
239
|
sourceNativeParent = await openNativeParent(sourcePath);
|
|
236
240
|
targetNativeParent = await openNativeParent(targetPath);
|
|
237
241
|
}
|
|
238
|
-
if (
|
|
242
|
+
if (strategy === "rename-noreplace") {
|
|
239
243
|
const binding = requireNativeBinding();
|
|
240
244
|
binding.renameNoReplace(sourceNativeParent.handle.fd, sourceNativeParent.basename, targetNativeParent.handle.fd, targetNativeParent.basename);
|
|
241
245
|
rememberCreatedTarget(failure, sourceExactIdentity, "rename-verify");
|
|
@@ -301,7 +305,7 @@ export async function publishFileExclusive(params) {
|
|
|
301
305
|
catch (error) {
|
|
302
306
|
if (failure.targetCreated ||
|
|
303
307
|
!isHardlinkFallbackError(error) ||
|
|
304
|
-
|
|
308
|
+
strategy === "link-required") {
|
|
305
309
|
throw error;
|
|
306
310
|
}
|
|
307
311
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regular-file.d.ts","sourceRoot":"","sources":["../src/regular-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,KAAK,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,MAAM,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"regular-file.d.ts","sourceRoot":"","sources":["../src/regular-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,KAAK,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,MAAM,MAAM,SAAS,CAAC;AAuB7B,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAExF,KAAK,8BAA8B,GAAG,IAAI,CACxC,OAAO,MAAM,CAAC,SAAS,EACvB,UAAU,GAAG,SAAS,GAAG,UAAU,CACpC,GACC,OAAO,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,SAAS,EAAE,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC;AAEtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,8BAAiD,GAC3D,MAAM,CASR;AAaD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAetF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAe3E;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CA+D3C;AA2DD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;CACb,CAsCA;AAmBD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkFxF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAkF7E"}
|