@openclaw/openshell-sandbox 2026.10.5-beta.4 → 2026.10.10-beta.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/README.md +1 -1
- package/node_modules/@openclaw/fs-safe/CHANGELOG.md +148 -0
- package/node_modules/@openclaw/fs-safe/README.md +20 -4
- package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/advanced.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-merge.js +28 -3
- package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-read.js +11 -5
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-loader.js +4 -2
- package/node_modules/@openclaw/fs-safe/dist/archive.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/atomic-io.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/bounded-read.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read.js +9 -2
- package/node_modules/@openclaw/fs-safe/dist/clone-metadata.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/clone-metadata.js +2 -1
- package/node_modules/@openclaw/fs-safe/dist/config.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/config.js +5 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-file-input.d.ts +3 -1
- package/node_modules/@openclaw/fs-safe/dist/copy-file-input.js +8 -7
- package/node_modules/@openclaw/fs-safe/dist/copy-link.d.ts +26 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-link.js +170 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-metadata.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-metadata.js +39 -0
- package/node_modules/@openclaw/fs-safe/dist/copy-path-admission.js +11 -2
- package/node_modules/@openclaw/fs-safe/dist/copy-root-file-sync.d.ts +2 -4
- package/node_modules/@openclaw/fs-safe/dist/copy-root-file-sync.js +4 -2
- package/node_modules/@openclaw/fs-safe/dist/copy-tree-portable.js +3 -6
- package/node_modules/@openclaw/fs-safe/dist/copy.js +3 -3
- package/node_modules/@openclaw/fs-safe/dist/create.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/creation-boundary.js +7 -4
- package/node_modules/@openclaw/fs-safe/dist/darwin-acl.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/darwin-acl.js +29 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-durability.d.ts +7 -4
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +20 -5
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.js +27 -2
- package/node_modules/@openclaw/fs-safe/dist/directory-receipt.d.ts +7 -7
- package/node_modules/@openclaw/fs-safe/dist/directory-receipt.js +9 -4
- package/node_modules/@openclaw/fs-safe/dist/durability.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/entry-publication.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/exact-identity.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/exact-identity.js +29 -0
- package/node_modules/@openclaw/fs-safe/dist/file-handle-transfer.js +4 -2
- package/node_modules/@openclaw/fs-safe/dist/file-hash.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/file-hash.js +11 -9
- package/node_modules/@openclaw/fs-safe/dist/file-identity.d.ts +7 -1
- package/node_modules/@openclaw/fs-safe/dist/file-identity.js +27 -5
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-admission.js +1 -2
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +8 -1
- package/node_modules/@openclaw/fs-safe/dist/file-lock.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-write-lease.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/file-write-lease.js +42 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.js +22 -15
- package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/hardlink-fallback.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/hardlink-fallback.js +5 -0
- package/node_modules/@openclaw/fs-safe/dist/index.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/index.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-ownership.js +16 -3
- package/node_modules/@openclaw/fs-safe/dist/local-file-descriptor.js +24 -13
- package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +85 -18
- package/node_modules/@openclaw/fs-safe/dist/native-config.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/native-config.js +11 -0
- package/node_modules/@openclaw/fs-safe/dist/native-directory-observation.js +6 -4
- package/node_modules/@openclaw/fs-safe/dist/native-fallback-warning.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/native-fallback-warning.js +26 -2
- package/node_modules/@openclaw/fs-safe/dist/native-guidance.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-guidance.js +21 -0
- package/node_modules/@openclaw/fs-safe/dist/native-move-fallback.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/native-move-fallback.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/native-operations.js +8 -6
- package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.d.ts +44 -4
- package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.js +85 -15
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.d.ts +3 -3
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.js +33 -6
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.d.ts +4 -1
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +22 -3
- package/node_modules/@openclaw/fs-safe/dist/native-policy-directory-observation.js +4 -3
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file-metadata.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file-metadata.js +16 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +15 -5
- package/node_modules/@openclaw/fs-safe/dist/native-stat-identity.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/native-stat-identity.js +7 -0
- package/node_modules/@openclaw/fs-safe/dist/native-status.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/native-status.js +30 -0
- package/node_modules/@openclaw/fs-safe/dist/native.d.ts +31 -4
- package/node_modules/@openclaw/fs-safe/dist/native.js +107 -9
- package/node_modules/@openclaw/fs-safe/dist/opened-realpath.js +9 -1
- package/node_modules/@openclaw/fs-safe/dist/overwrite-file-handle.js +4 -1
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.js +9 -1
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-windows.js +83 -47
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.js +8 -3
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-input.js +13 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-staged.js +10 -8
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-types.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/pinned-write.js +7 -5
- package/node_modules/@openclaw/fs-safe/dist/pipe.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/pipe.js +26 -0
- package/node_modules/@openclaw/fs-safe/dist/private-directory.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/private-producer-handoff.js +2 -5
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.d.ts +3 -2
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.js +38 -10
- package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +92 -10
- package/node_modules/@openclaw/fs-safe/dist/publish-file-failure.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file-failure.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file.d.ts +5 -3
- package/node_modules/@openclaw/fs-safe/dist/publish-file.js +26 -20
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.js +3 -4
- package/node_modules/@openclaw/fs-safe/dist/realpath.js +32 -0
- package/node_modules/@openclaw/fs-safe/dist/regular-file.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/regular-file.js +11 -15
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +3 -2
- package/node_modules/@openclaw/fs-safe/dist/root-copy.d.ts +18 -0
- package/node_modules/@openclaw/fs-safe/dist/root-copy.js +128 -0
- package/node_modules/@openclaw/fs-safe/dist/root-create-native.d.ts +8 -13
- package/node_modules/@openclaw/fs-safe/dist/root-create-native.js +252 -27
- package/node_modules/@openclaw/fs-safe/dist/root-directory-creation.js +5 -1
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.d.ts +11 -8
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +35 -13
- package/node_modules/@openclaw/fs-safe/dist/root-file-open-batch-sync.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file-open-batch-sync.js +108 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.js +15 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.js +154 -175
- package/node_modules/@openclaw/fs-safe/dist/root-mkdir-native.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/root-mkdir-native.js +239 -0
- package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.js +37 -15
- package/node_modules/@openclaw/fs-safe/dist/root-native-creation-path.d.ts +32 -0
- package/node_modules/@openclaw/fs-safe/dist/root-native-creation-path.js +56 -0
- package/node_modules/@openclaw/fs-safe/dist/root-options.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/root-public-types.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-remove-native.js +95 -16
- package/node_modules/@openclaw/fs-safe/dist/root-remove.js +6 -4
- package/node_modules/@openclaw/fs-safe/dist/root-walk.js +23 -19
- package/node_modules/@openclaw/fs-safe/dist/root-write-admission.js +8 -6
- package/node_modules/@openclaw/fs-safe/dist/root-write-publication.js +5 -1
- package/node_modules/@openclaw/fs-safe/dist/secure-file-windows.js +3 -1
- package/node_modules/@openclaw/fs-safe/dist/secure-file.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-file.js +10 -4
- package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-retained.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-target.js +8 -1
- package/node_modules/@openclaw/fs-safe/dist/staged-directory.d.ts +13 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-directory.js +29 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +5 -3
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-descriptor.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-descriptor.js +13 -2
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-owner.js +71 -3
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.js +22 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-types.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/trash.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/types.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-native.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/windows-appcontainer.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-appcontainer.js +39 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.js +25 -36
- package/node_modules/@openclaw/fs-safe/dist/windows-security-command.js +24 -5
- package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.js +4 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-helper.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-helper.exe +0 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-helper.js +7 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-test-hooks.d.ts +16 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-test-hooks.js +51 -0
- package/node_modules/@openclaw/fs-safe/dist/write-file-handle.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/write-file-handle.js +12 -10
- package/node_modules/@openclaw/fs-safe/docs/advanced.md +2 -1
- package/node_modules/@openclaw/fs-safe/docs/archive.md +16 -0
- package/node_modules/@openclaw/fs-safe/docs/config.md +71 -1
- package/node_modules/@openclaw/fs-safe/docs/contributing.md +45 -5
- package/node_modules/@openclaw/fs-safe/docs/copy.md +45 -5
- package/node_modules/@openclaw/fs-safe/docs/durability.md +34 -7
- package/node_modules/@openclaw/fs-safe/docs/errors.md +8 -0
- package/node_modules/@openclaw/fs-safe/docs/guest.md +2 -0
- package/node_modules/@openclaw/fs-safe/docs/install.md +47 -27
- package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.5.md +6 -6
- package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.6.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/native-helper.md +79 -6
- package/node_modules/@openclaw/fs-safe/docs/native.md +279 -8
- package/node_modules/@openclaw/fs-safe/docs/permissions.md +64 -15
- package/node_modules/@openclaw/fs-safe/docs/pipe.md +81 -0
- package/node_modules/@openclaw/fs-safe/docs/platform-capabilities.md +63 -0
- package/node_modules/@openclaw/fs-safe/docs/public-api.md +10 -0
- package/node_modules/@openclaw/fs-safe/docs/queue-link-free-design.md +237 -0
- package/node_modules/@openclaw/fs-safe/docs/quickstart.md +23 -3
- package/node_modules/@openclaw/fs-safe/docs/reading.md +56 -2
- package/node_modules/@openclaw/fs-safe/docs/regular-file.md +2 -0
- package/node_modules/@openclaw/fs-safe/docs/secret-file.md +5 -5
- package/node_modules/@openclaw/fs-safe/docs/secure-file.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/security-model.md +35 -0
- package/node_modules/@openclaw/fs-safe/docs/sidecar-lock.md +31 -13
- package/node_modules/@openclaw/fs-safe/docs/staged-file.md +18 -0
- package/node_modules/@openclaw/fs-safe/docs/store.md +15 -0
- package/node_modules/@openclaw/fs-safe/docs/temp.md +39 -0
- package/node_modules/@openclaw/fs-safe/docs/testing.md +13 -0
- package/node_modules/@openclaw/fs-safe/docs/types.md +51 -81
- package/node_modules/@openclaw/fs-safe/docs/walk.md +4 -1
- package/node_modules/@openclaw/fs-safe/docs/watch.md +3 -2
- package/node_modules/@openclaw/fs-safe/docs/writing.md +121 -14
- package/node_modules/@openclaw/fs-safe/package.json +21 -12
- package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-freebsd-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-freebsd-arm64/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-freebsd-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-freebsd-x64/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-win32-arm64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-arm64-msvc/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
- package/package.json +5 -5
- package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.cs +0 -336
- package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.ps1 +0 -90
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Official NVIDIA OpenShell sandbox backend for OpenClaw.
|
|
|
4
4
|
|
|
5
5
|
This plugin lets OpenClaw use OpenShell-managed local or remote sandboxes with
|
|
6
6
|
SSH command execution. Choose `mirror` mode for a synchronized local workspace
|
|
7
|
-
or `remote` mode for a remote
|
|
7
|
+
or `remote` mode for a workspace managed on the remote host.
|
|
8
8
|
|
|
9
9
|
Mirror operations sharing a workspace run sequentially so concurrent agent
|
|
10
10
|
turns cannot overwrite one another. Outbound attachments resolve against the
|
|
@@ -2,6 +2,154 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.26.5 - 2026-10-14
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
|
|
9
|
+
- **Android/Termux and WSL compatibility:** create temporary workspaces under Android system-owned ancestors and complete short nonblocking reads on WSL/9p filesystems. ([#982](https://github.com/openclaw/fs-safe/pull/982), [#983](https://github.com/openclaw/fs-safe/pull/983))
|
|
10
|
+
- **Windows synchronous read batches:** add `createRootFileOpenBatchSync()` to reuse native root handles while retaining per-file safety checks. ([#984](https://github.com/openclaw/fs-safe/pull/984))
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- **Windows synchronous read batches:** reuse native root handles with `createRootFileOpenBatchSync()` while retaining fresh file identity, reparse, hardlink, byte-limit, and confinement checks. ([#984](https://github.com/openclaw/fs-safe/pull/984))
|
|
15
|
+
|
|
16
|
+
### Fixes
|
|
17
|
+
|
|
18
|
+
- **WSL/9p reads:** finish short nonblocking reads instead of truncating uncapped files, atomic copy fallbacks, or content verification. Thanks @Hawk5150 for [openclaw/openclaw#145589](https://github.com/openclaw/openclaw/issues/145589). ([#983](https://github.com/openclaw/fs-safe/pull/983))
|
|
19
|
+
- **Android/Termux temp workspaces:** admit system-owned ancestors and Android-private writable groups while preserving private roots and full ancestry checks. Thanks @kukirin-ui for [openclaw/openclaw#171406](https://github.com/openclaw/openclaw/issues/171406). ([#982](https://github.com/openclaw/fs-safe/pull/982))
|
|
20
|
+
|
|
21
|
+
## 0.26.4 - 2026-10-13
|
|
22
|
+
|
|
23
|
+
### Fixes
|
|
24
|
+
|
|
25
|
+
- **Windows AppContainers:** private files and directories now work inside a Windows AppContainer: the creating container can reopen them and other containers stay denied. Requires the native addon; folder-mounted volumes fail closed. Behavior outside a container is unchanged. Thanks @jonathanlindsay. Reported in [openclaw/openclaw#160287](https://github.com/openclaw/openclaw/issues/160287); limits are in the [permissions guide](docs/permissions.md#advanced-windows-acl-helpers). ([#980](https://github.com/openclaw/fs-safe/pull/980))
|
|
26
|
+
|
|
27
|
+
### Docs and Tooling
|
|
28
|
+
|
|
29
|
+
- **Windows durability costs:** explain what non-durable writes cost and save on Windows. ([#973](https://github.com/openclaw/fs-safe/pull/973))
|
|
30
|
+
|
|
31
|
+
## 0.26.3 - 2026-10-13
|
|
32
|
+
|
|
33
|
+
### Highlights
|
|
34
|
+
|
|
35
|
+
- **Native health and signed Windows binaries:** inspect runtime native support with `getFsSafeNativeStatus()`; Windows addons and the security helper now carry timestamped OpenClaw Foundation signatures. ([#965](https://github.com/openclaw/fs-safe/pull/965), [#960](https://github.com/openclaw/fs-safe/pull/960))
|
|
36
|
+
- **Linux copy compatibility:** recover from refused reflink I/O, including ZFS block cloning, through a guarded byte copy. ([#972](https://github.com/openclaw/fs-safe/pull/972))
|
|
37
|
+
- **Less native filesystem overhead:** retain directory parents, reuse writable-file admission, batch Root verification, and avoid unrelated macOS watch wakeups. ([#971](https://github.com/openclaw/fs-safe/pull/971), [#959](https://github.com/openclaw/fs-safe/pull/959), [#966](https://github.com/openclaw/fs-safe/pull/966), [#955](https://github.com/openclaw/fs-safe/pull/955), [#968](https://github.com/openclaw/fs-safe/pull/968))
|
|
38
|
+
|
|
39
|
+
### Features
|
|
40
|
+
|
|
41
|
+
- **Native runtime health:** add async `getFsSafeNativeStatus()` with optional probing, path-free load reasons, and actionable guidance, exported from the root and `config` entry points. ([#965](https://github.com/openclaw/fs-safe/pull/965))
|
|
42
|
+
- **Signed Windows binaries:** Authenticode-sign both Windows native addons and the security helper with timestamped OpenClaw Foundation signatures, and verify the signed bytes before publication. ([#960](https://github.com/openclaw/fs-safe/pull/960))
|
|
43
|
+
|
|
44
|
+
### Fixes
|
|
45
|
+
|
|
46
|
+
- **High-bit filesystem identities:** preserve Node's signed bigint stat identities across native directory checks, allowing guarded writes and build locks on filesystems with high-bit inode numbers. ([#979](https://github.com/openclaw/fs-safe/pull/979))
|
|
47
|
+
- **Linux reflink fallback:** fall back to a guarded byte copy when FICLONE refuses I/O with `EIO` or `EAGAIN`, including ZFS block cloning; real copy and cleanup errors remain fatal. Reported in [openclaw/openclaw#169071](https://github.com/openclaw/openclaw/issues/169071). ([#972](https://github.com/openclaw/fs-safe/pull/972))
|
|
48
|
+
- **Native fallback warnings:** explain why native support is unavailable, name the expected package version, and give cause-specific recovery guidance for Windows security and private-creation fallbacks. ([#961](https://github.com/openclaw/fs-safe/pull/961))
|
|
49
|
+
|
|
50
|
+
### Performance
|
|
51
|
+
|
|
52
|
+
- **Native directory creation:** retain parent handles during recursive mkdir, reducing the measured case from 160 to 5 promises and 381 to 74 Linux syscalls; nested mkdir also reuses existing parents. ([#971](https://github.com/openclaw/fs-safe/pull/971), [#959](https://github.com/openclaw/fs-safe/pull/959))
|
|
53
|
+
- **Native writable-file creation:** reuse parent admission, reducing measured direct-root append syscalls from 117 to 36 and `openWritable` syscalls from 115 to 34 while retaining identity and cleanup checks. ([#966](https://github.com/openclaw/fs-safe/pull/966))
|
|
54
|
+
- **Native Root verification:** batch verification and checked close to reduce dispatch overhead while retaining identity checks and close-error handling. ([#955](https://github.com/openclaw/fs-safe/pull/955))
|
|
55
|
+
- **macOS file watching:** avoid JavaScript reconciliation for unrelated sibling writes and child-only changes to directory entry scopes while preserving missing-entry discovery and replacement notifications. ([#968](https://github.com/openclaw/fs-safe/pull/968))
|
|
56
|
+
|
|
57
|
+
### Docs and Tooling
|
|
58
|
+
|
|
59
|
+
- **Durable queue design:** document a link-free ownership protocol and mixed-version boundaries. ([#969](https://github.com/openclaw/fs-safe/pull/969))
|
|
60
|
+
- **Benchmark comparisons:** balance independent build comparisons and restore benchmark setup in relocated checkouts. ([#976](https://github.com/openclaw/fs-safe/pull/976), [#970](https://github.com/openclaw/fs-safe/pull/970))
|
|
61
|
+
|
|
62
|
+
## 0.26.2 - 2026-10-11
|
|
63
|
+
|
|
64
|
+
### Highlights
|
|
65
|
+
|
|
66
|
+
- **Windows receipt round trips:** use exact bigint identities from fs-safe receipts with the fail-closed identity checks introduced in 0.26.1. ([#962](https://github.com/openclaw/fs-safe/pull/962))
|
|
67
|
+
|
|
68
|
+
### Fixes
|
|
69
|
+
|
|
70
|
+
- **Windows file identity:** publication, reads, opens, directory and temporary-workspace receipts, typed listings, and clone metadata now expose bigint `exactIdentity`; publication failures expose `exactTargetIdentity`. Pass the exact form back to identity-checking APIs, including publication and copy expectations, to avoid rejecting rounded legacy Number identities on volumes with large file IDs. Existing exact copy and staged-file receipts remain supported. ([#962](https://github.com/openclaw/fs-safe/pull/962))
|
|
71
|
+
|
|
72
|
+
### Performance
|
|
73
|
+
|
|
74
|
+
- **Windows permission inspection:** avoid PowerShell startup for portable owner and ACL queries, about 8× faster in a Windows x64 probe, while preserving injected executors and .NET ACL semantics; requires .NET Framework 4.6.2+. ([#958](https://github.com/openclaw/fs-safe/pull/958))
|
|
75
|
+
|
|
76
|
+
## 0.26.1 - 2026-10-11
|
|
77
|
+
|
|
78
|
+
### Highlights
|
|
79
|
+
|
|
80
|
+
- **Windows identity checks:** reject rounded file IDs; callers supplying identity stats must use bigint values. ([#949](https://github.com/openclaw/fs-safe/pull/949))
|
|
81
|
+
- **Listings and copies:** measured listings are 38–54% faster on Linux and Windows; direct synchronous file copies are 11–31% faster, with Windows batches up to 48% faster. ([#934](https://github.com/openclaw/fs-safe/pull/934), [#932](https://github.com/openclaw/fs-safe/pull/932))
|
|
82
|
+
- **Windows private creation:** the portable helper is about 5× faster, and private creation works beyond MAX_PATH. ([#930](https://github.com/openclaw/fs-safe/pull/930), [#924](https://github.com/openclaw/fs-safe/pull/924))
|
|
83
|
+
- **Native overhead:** reduce dispatch and repeated admission for direct-child mkdir, removal, moves, existing-file opens, buffered publication, and async temp creation; measured eligible cases reach or improve on fallback performance while retaining native checks. ([#927](https://github.com/openclaw/fs-safe/pull/927), [#928](https://github.com/openclaw/fs-safe/pull/928), [#929](https://github.com/openclaw/fs-safe/pull/929), [#948](https://github.com/openclaw/fs-safe/pull/948), [#953](https://github.com/openclaw/fs-safe/pull/953))
|
|
84
|
+
|
|
85
|
+
### Fixes
|
|
86
|
+
|
|
87
|
+
- **Windows file identity:** stop accepting rounded Number file IDs as matches. Callers supplying identity stats must now pass bigint stats; unsafe Number identities fail with `path-mismatch`. ([#949](https://github.com/openclaw/fs-safe/pull/949))
|
|
88
|
+
- **Windows long paths:** support private directory and file creation beyond MAX_PATH, including internal staging and pathname verification, while preserving ACL, alias, identity, and cleanup checks. ([#924](https://github.com/openclaw/fs-safe/pull/924))
|
|
89
|
+
|
|
90
|
+
### Performance
|
|
91
|
+
|
|
92
|
+
- **Listings and traversal:** avoid per-entry filename buffers for losslessly decoded names, making measured Linux and Windows listings 38–54% faster; halve per-entry promise allocation in complete sorted `Root.walk()` scans, improving measured 50,000-entry Linux walks by 3–4%. ([#934](https://github.com/openclaw/fs-safe/pull/934), [#937](https://github.com/openclaw/fs-safe/pull/937))
|
|
93
|
+
- **File copies and moves:** reuse canonical admission in `copyRootFileSync`, improving measured direct copies by 11–31% on Linux and Windows and batches by up to 47–48% on Windows; reduce ordinary `Root.copyIn()` and same-parent move promise allocation without claiming a reproduced latency gain. ([#932](https://github.com/openclaw/fs-safe/pull/932), [#941](https://github.com/openclaw/fs-safe/pull/941), [#936](https://github.com/openclaw/fs-safe/pull/936))
|
|
94
|
+
- **Reads and hashing:** trim file-admission and bounded-read metadata work for 2–9% faster measured Linux reads; reuse privately owned Windows handles for 42% faster native async SHA-256 on small pathname inputs, retaining borrowed-handle positions. ([#931](https://github.com/openclaw/fs-safe/pull/931), [#938](https://github.com/openclaw/fs-safe/pull/938))
|
|
95
|
+
- **Locks and directories:** reduce uncontended sidecar-lock acquisition overhead by up to 34% with native; remove ordinary mkdir dispatch hops for 37% faster native direct-child creation, 17–22% faster existing-directory admission, and 81% faster native `ensureRoot` in the combined Linux benchmark. ([#939](https://github.com/openclaw/fs-safe/pull/939), [#944](https://github.com/openclaw/fs-safe/pull/944), [#927](https://github.com/openclaw/fs-safe/pull/927))
|
|
96
|
+
- **Temporary workspaces and removal:** make measured empty-workspace cleanup 13–32% faster on Linux, create async workspaces through retained parents, and reduce recursive-removal stat allocation for 2–6% faster measured Linux recursive removal; retain identity-bound cleanup. ([#942](https://github.com/openclaw/fs-safe/pull/942), [#953](https://github.com/openclaw/fs-safe/pull/953), [#933](https://github.com/openclaw/fs-safe/pull/933))
|
|
97
|
+
- **Private and exclusive creation:** run portable Windows security checks in a prebuilt helper for about 5× faster private creation; streamline exclusive-creation metadata and skip redundant Windows write-mode changes without removing flushes or permission checks. ([#930](https://github.com/openclaw/fs-safe/pull/930), [#935](https://github.com/openclaw/fs-safe/pull/935), [#940](https://github.com/openclaw/fs-safe/pull/940))
|
|
98
|
+
- **Native operations:** reuse retained roots for removal and moves, defer parent creation until an opened file is missing, and streamline buffered creation and replacement-write publication; preserve descriptor-relative mutation and exact identity checks. Native non-durable publication reaches fallback parity in the measured cases; durable creation remains slower. ([#928](https://github.com/openclaw/fs-safe/pull/928), [#929](https://github.com/openclaw/fs-safe/pull/929), [#948](https://github.com/openclaw/fs-safe/pull/948))
|
|
99
|
+
|
|
100
|
+
### Docs and Tooling
|
|
101
|
+
|
|
102
|
+
- **Raw Node baseline:** add `pnpm benchmark:node` with alternating raw/safe/control samples and documented operation semantics; raw Node is a performance reference, not a security-equivalent implementation. ([#925](https://github.com/openclaw/fs-safe/pull/925))
|
|
103
|
+
- **Native API reference:** enumerate APIs that require native bindings and their fallback availability. ([#926](https://github.com/openclaw/fs-safe/pull/926))
|
|
104
|
+
|
|
105
|
+
## 0.26.0 - 2026-10-10
|
|
106
|
+
|
|
107
|
+
### Highlights
|
|
108
|
+
|
|
109
|
+
- **New platforms:** native packages for FreeBSD x64/arm64 and Windows ARM64. ([#905](https://github.com/openclaw/fs-safe/pull/905), [#893](https://github.com/openclaw/fs-safe/pull/893))
|
|
110
|
+
- **Native capabilities:** anonymous pipes, Linux write leases, Darwin ACL inspection, ReFS block cloning, and metadata- and link-preserving `Root.copyIn`. ([#892](https://github.com/openclaw/fs-safe/pull/892), [#896](https://github.com/openclaw/fs-safe/pull/896), [#920](https://github.com/openclaw/fs-safe/pull/920), [#921](https://github.com/openclaw/fs-safe/pull/921))
|
|
111
|
+
- **Android/Termux publication:** staged no-replace copies and writes work when the OS refuses hard links. ([#888](https://github.com/openclaw/fs-safe/pull/888))
|
|
112
|
+
- **Performance:** faster deep archive extraction, borrowed-handle copies and overwrites, sidecar locks, and Linux descriptor verification, with identity checks retained. ([#912](https://github.com/openclaw/fs-safe/pull/912), [#906](https://github.com/openclaw/fs-safe/pull/906), [#902](https://github.com/openclaw/fs-safe/pull/902), [#901](https://github.com/openclaw/fs-safe/pull/901), [#899](https://github.com/openclaw/fs-safe/pull/899))
|
|
113
|
+
|
|
114
|
+
### Features
|
|
115
|
+
|
|
116
|
+
- **ReFS file copies:** support guarded `Root.copyIn` block cloning on Windows ReFS and Dev Drive, with exclusive publication, cancellation cleanup, and automatic byte-copy fallback for unavailable clone capabilities. ([#920](https://github.com/openclaw/fs-safe/pull/920))
|
|
117
|
+
- **Guarded file copying:** add `Root.copyIn` metadata preservation and exclusive literal-link copying, including dangling Windows file and directory links; keep permission selection separate from timestamps and attributes. ([#921](https://github.com/openclaw/fs-safe/pull/921))
|
|
118
|
+
|
|
119
|
+
- **Native filesystem capabilities:** add Linux write leases on caller-owned descriptors, no-follow Darwin ACL inspection with separate file and directory inheritance facts, and Windows sharing-lock, attribute, and physical-extent test fixtures. ([#896](https://github.com/openclaw/fs-safe/pull/896))
|
|
120
|
+
- **Anonymous pipes:** add `@openclaw/fs-safe/pipe` with native-owned, reopenable close-on-exec pipe ends for one-shot child input on POSIX, including safe stream closure in Workers. ([#892](https://github.com/openclaw/fs-safe/pull/892))
|
|
121
|
+
|
|
122
|
+
### Fixes
|
|
123
|
+
|
|
124
|
+
- **Windows creation diagnostics:** retain native Win32 error numbers through private directory and file creation failures, including the command fallback, without changing semantic error codes. ([#919](https://github.com/openclaw/fs-safe/pull/919))
|
|
125
|
+
- **FreeBSD native packages:** add x64 and arm64 packages for FreeBSD 14.4+, with native anonymous pipes and canonicalization, and explicit capability absence for unported operations. ([#905](https://github.com/openclaw/fs-safe/pull/905))
|
|
126
|
+
- **Partial native bindings:** select guarded fallbacks when an operation's native capabilities are absent, and report typed capability errors in required mode before mutation. ([#905](https://github.com/openclaw/fs-safe/pull/905))
|
|
127
|
+
- **Android/Termux publication:** publish staged no-replace copies and writes when hardlinks are refused, using a verified empty placeholder before atomic replacement; include `EACCES` in the public hardlink-to-copy fallback classifier. Reported in [openclaw/openclaw#167791](https://github.com/openclaw/openclaw/issues/167791). ([#888](https://github.com/openclaw/fs-safe/pull/888))
|
|
128
|
+
- **Native ZIP names:** preserve CP437 decoding for unflagged legacy filenames after the ZIP 9 upgrade, including collision rejection and bounded entry selection; continue rejecting invalid Unicode Path checksums and encodings before decoder normalization. ([#885](https://github.com/openclaw/fs-safe/pull/885))
|
|
129
|
+
- **Native ZIP Unicode fields:** retain rejection of invalid Unicode Comment CRCs and UTF-8 before callbacks or bounded reads, and validate sequential Unicode fields in decoder order without repeated hashing of the original name. ([#887](https://github.com/openclaw/fs-safe/pull/887))
|
|
130
|
+
- **Portable ZIP extraction:** accept safe relative root-directory markers such as `./` from libarchive and other producers without turning them into absolute paths; root markers remain skipped before callbacks and publication. ([#886](https://github.com/openclaw/fs-safe/pull/886))
|
|
131
|
+
- **Durable JSON queues on Android/Termux:** claim, failed-entry quarantine, and retirement recovery report typed `helper-unavailable` errors when hardlinks are refused, preserving pending, claimed, and retirement evidence for retry. ([#889](https://github.com/openclaw/fs-safe/pull/889))
|
|
132
|
+
- **Windows exclusive publication:** preserve dangling destination symlinks when a refused hard link falls back to placeholder publication. ([#894](https://github.com/openclaw/fs-safe/pull/894))
|
|
133
|
+
- **Native mkdir collisions:** `Root.mkdir` consistently reports `not-file` for an existing regular-file destination in native require mode. ([#895](https://github.com/openclaw/fs-safe/pull/895))
|
|
134
|
+
- **Guest directory publication:** report a changed source identity instead of a false destination collision when a Linux fallback rename refuses a substituted source. ([#898](https://github.com/openclaw/fs-safe/pull/898))
|
|
135
|
+
- **Native recursive removal:** honor a zero entry budget before ignoring a missing target, including with `force`. ([#904](https://github.com/openclaw/fs-safe/pull/904))
|
|
136
|
+
|
|
137
|
+
### Performance
|
|
138
|
+
|
|
139
|
+
- **Linux opened-file verification:** read ordinary procfs descriptor paths directly instead of walking realpath, keeping identity checks and deleted-path canonicalization; `readLocalFileSafely` is 25–28% faster on deep paths. ([#899](https://github.com/openclaw/fs-safe/pull/899))
|
|
140
|
+
- **Borrowed handles and locks:** keep descriptor metadata inspection off the asynchronous I/O queue for small overwrites (26–28% faster) and copies (31–34% faster), and skip a redundant parent `mkdir` when acquiring sidecar locks (15–18% faster). ([#901](https://github.com/openclaw/fs-safe/pull/901), [#902](https://github.com/openclaw/fs-safe/pull/902), [#906](https://github.com/openclaw/fs-safe/pull/906))
|
|
141
|
+
- **Deep archive extraction:** native extraction verifies every retained ancestor through its open descriptor instead of repeated realpath walks: about 16% faster at depth 8 and 5–6% at depth 4, with every ancestor substitution check retained. ([#912](https://github.com/openclaw/fs-safe/pull/912))
|
|
142
|
+
|
|
143
|
+
### Docs and Tooling
|
|
144
|
+
|
|
145
|
+
- **Docs accuracy:** correct native-mode migration guidance for removed Python settings and bundled TAR fallbacks, clarify Root streaming ownership, create-only visibility, and Linux no-clobber move fallback limits, and fix the JSON-store and stale-lock examples so denied process probes keep live locks; README and docs examples are now type-checked in CI. ([#897](https://github.com/openclaw/fs-safe/pull/897), [#900](https://github.com/openclaw/fs-safe/pull/900), [#903](https://github.com/openclaw/fs-safe/pull/903))
|
|
146
|
+
|
|
147
|
+
### Compatibility
|
|
148
|
+
|
|
149
|
+
- **Windows ARM64:** add a native ARM64 package with real Windows 11 ARM64 and x64-emulation validation, including private ACL creation and Worker descriptor ownership. ([#893](https://github.com/openclaw/fs-safe/pull/893))
|
|
150
|
+
|
|
151
|
+
- **Native ZIP metadata:** invalid UTF-8-flagged names now reject instead of decoding lossily or falling back to CP437. Public ZIP extraction, preflight, and reads already reject these names during physical admission. ([#885](https://github.com/openclaw/fs-safe/pull/885))
|
|
152
|
+
|
|
5
153
|
## 0.25.0 - 2026-10-08
|
|
6
154
|
|
|
7
155
|
### Highlights
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
Capability-style filesystem roots for Node.js apps that handle untrusted relative paths.
|
|
12
12
|
|
|
13
|
+
Platform-specific additions include [Linux write leases, Darwin ACL inspection,
|
|
14
|
+
and Windows test fixtures](docs/platform-capabilities.md).
|
|
15
|
+
|
|
13
16
|
Think Go's `os.Root` / `OpenInRoot` or Rust's [`cap-std`](https://github.com/bytecodealliance/cap-std), but for Node. Hand `root()` a trusted directory and you get back a handle whose every method resolves relative paths against it and defends against `..`, symlink swaps, hardlink aliases, and TOCTOU rename races. The exact containment strength is reported per mechanism: Linux `openat2` opens are kernel-atomic; guarded Linux fallback, macOS, Windows, and JavaScript paths are best-effort.
|
|
14
17
|
|
|
15
18
|
```ts
|
|
@@ -81,6 +84,12 @@ kernel-atomic. Read the [native helper policy](docs/native-helper.md) and
|
|
|
81
84
|
[operation/platform matrix](docs/security-model.md#native-root-mutation-capabilities)
|
|
82
85
|
when concurrent mutation is in scope.
|
|
83
86
|
|
|
87
|
+
For doctor/startup checks, use
|
|
88
|
+
[`await getFsSafeNativeStatus({ probe: true })`](docs/config.md#getfssafenativestatus-options)
|
|
89
|
+
from `@openclaw/fs-safe/config` to report whether the native addon is active,
|
|
90
|
+
why it is unavailable, and what to do next. Calling it without options only reads
|
|
91
|
+
the cache. Status is per module instance; Workers must be checked separately.
|
|
92
|
+
|
|
84
93
|
## Migrating from the Python helper
|
|
85
94
|
|
|
86
95
|
Version 0.5 replaced the Python worker with prebuilt native bindings. Follow the
|
|
@@ -113,9 +122,14 @@ operation; per-call options handle exceptions. See the [Root reference](docs/roo
|
|
|
113
122
|
|
|
114
123
|
`write()` replaces contents by default. Use `create()` or `overwrite: false`
|
|
115
124
|
when an existing destination should be an error. `move()` defaults to no clobber
|
|
116
|
-
and requires native support
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
and requires native support. On Linux, `auto` can replace a concurrently created
|
|
126
|
+
empty directory if no-replace rename is unsupported; use native `require` for
|
|
127
|
+
strict refusal. See the [move fallback contract](docs/writing.md#fs-move-from-to-options).
|
|
128
|
+
Pass `overwrite: true` when replacement is intended.
|
|
129
|
+
|
|
130
|
+
Staged JavaScript copies and creates also work when hardlinks are refused
|
|
131
|
+
(including Android/Termux), using a verified empty placeholder before atomic
|
|
132
|
+
replacement. See the [visibility and concurrency tradeoffs](docs/writing.md#publication-without-hardlinks).
|
|
119
133
|
|
|
120
134
|
See [Writing](docs/writing.md) for copy sources, mutation authority, symlink
|
|
121
135
|
policy, writable handles, and bounded removal, and [Creation](docs/creation.md)
|
|
@@ -159,6 +173,8 @@ and error exports. Prefer focused subpaths when a consumer needs a narrower
|
|
|
159
173
|
contract. Low-level helpers that OpenClaw needs to compose higher-level APIs are grouped under
|
|
160
174
|
`@openclaw/fs-safe/advanced` instead of being separate public leaf contracts.
|
|
161
175
|
|
|
176
|
+
Use [`@openclaw/fs-safe/pipe`](docs/pipe.md) for native-owned, reopenable anonymous pipes and one-shot child input.
|
|
177
|
+
|
|
162
178
|
See the [complete subpath catalogue](docs/install.md#subpath-exports) for every entry point and its contents.
|
|
163
179
|
|
|
164
180
|
## Failure semantics in the name
|
|
@@ -236,7 +252,7 @@ updates:
|
|
|
236
252
|
import { fileStore } from "@openclaw/fs-safe/store";
|
|
237
253
|
|
|
238
254
|
const files = fileStore({ rootDir: "/safe/workspace/state", private: true });
|
|
239
|
-
const store = files.json("settings.json", { lock: true });
|
|
255
|
+
const store = files.json<{ enabled: boolean }>("settings.json", { lock: true });
|
|
240
256
|
|
|
241
257
|
await store.updateOr({ enabled: false }, (current) => ({ ...current, enabled: true }));
|
|
242
258
|
```
|
|
@@ -17,7 +17,7 @@ export { readFileWindowFully, readFileWindowFullySync, type ReadFileWindowOption
|
|
|
17
17
|
export { writeFileWindowFully, type WriteFileWindowOptions } from "./write-file-handle.js";
|
|
18
18
|
export { assertNoUnsafeDeviceReadPath, isUnsafeDeviceReadPath, matchUnsafeDeviceReadPath, type UnsafeDeviceReadPathMatch, type UnsafeDeviceReadPathOptions, type UnsafeDeviceReadPathReason, } from "./device-path.js";
|
|
19
19
|
export { assertAbsolutePathInput, canonicalPathFromExistingAncestor, ensureAbsoluteDirectory, findExistingAncestor, resolveAbsolutePathForRead, resolveAbsolutePathForWrite, type AbsolutePathSymlinkPolicy, type EnsureAbsoluteDirectoryOptions, type EnsureAbsoluteDirectoryResult, type ResolvedAbsolutePath, type ResolvedWritableAbsolutePath, } from "./absolute-path.js";
|
|
20
|
-
export { sameFileIdentity, type FileIdentityStat } from "./file-identity.js";
|
|
20
|
+
export { sameFileIdentity, type FileIdentityStat, type FileIdentityInput, type ExactFileIdentity, type ExactIdentityReceipt } from "./file-identity.js";
|
|
21
21
|
export { sanitizeUntrustedFileName } from "./filename.js";
|
|
22
22
|
export { pathExists, pathExistsSync } from "./fs.js";
|
|
23
23
|
export { resolveLocalPathFromRootsSync, readLocalFileFromRoots, type LocalRootsInputOptions, type LocalRootsPathResult, type LocalRootsReadResult, type ReadLocalFileFromRootsOptions, type ResolveLocalPathFromRootsSyncOptions, } from "./local-roots.js";
|
|
@@ -26,6 +26,7 @@ export { formatPosixMode } from "./permissions.js";
|
|
|
26
26
|
export { configureFsSafeLocks, getFsSafeLockConfig, type FsSafeLockConfig, } from "./lock-config.js";
|
|
27
27
|
export { assertNoHardlinkedFinalPath, assertNoPathAliasEscape, PATH_ALIAS_POLICIES, type PathAliasPolicy, } from "./path-policy.js";
|
|
28
28
|
export { openRootFile, openRootFileSync, canUseRootFileOpen, matchRootFileOpenFailure, type OpenRootFileParams, type OpenRootFileSyncParams, type RootFileOpenFailure, type RootFileOpenFailureReason, type RootFileOpenResult, } from "./root-file.js";
|
|
29
|
+
export { createRootFileOpenBatchSync, type RootFileOpenBatchSync } from "./root-file-open-batch-sync.js";
|
|
29
30
|
export { ROOT_PATH_ALIAS_POLICIES, resolvePathViaExistingAncestorSync, resolveRootPath, resolveRootPathSync, type ResolvedRootPath, type RootPathAliasPolicy, } from "./root-path.js";
|
|
30
31
|
export { ensureDirectoryWithinRoot, pathScope, resolveExistingPathsWithinRoot, resolvePathWithinRoot, resolvePathsWithinRoot, resolveStrictExistingPathsWithinRoot, resolveWritablePathWithinRoot, type PathScope, type PathScopeOptions, type PathScopeResolveOptions, } from "./root-paths.js";
|
|
31
32
|
export { safeDirName, safePathSegmentHashed, safePathSegmentHashedV2, resolveSafeInstallDir, assertCanonicalPathWithinBase, } from "./install-path.js";
|
|
@@ -27,6 +27,7 @@ export { formatPosixMode } from "./permissions.js";
|
|
|
27
27
|
export { configureFsSafeLocks, getFsSafeLockConfig, } from "./lock-config.js";
|
|
28
28
|
export { assertNoHardlinkedFinalPath, assertNoPathAliasEscape, PATH_ALIAS_POLICIES, } from "./path-policy.js";
|
|
29
29
|
export { openRootFile, openRootFileSync, canUseRootFileOpen, matchRootFileOpenFailure, } from "./root-file.js";
|
|
30
|
+
export { createRootFileOpenBatchSync } from "./root-file-open-batch-sync.js";
|
|
30
31
|
export { ROOT_PATH_ALIAS_POLICIES, resolvePathViaExistingAncestorSync, resolveRootPath, resolveRootPathSync, } from "./root-path.js";
|
|
31
32
|
export { ensureDirectoryWithinRoot, pathScope, resolveExistingPathsWithinRoot, resolvePathWithinRoot, resolvePathsWithinRoot, resolveStrictExistingPathsWithinRoot, resolveWritablePathWithinRoot, } from "./root-paths.js";
|
|
32
33
|
export { safeDirName, safePathSegmentHashed, safePathSegmentHashedV2, resolveSafeInstallDir, assertCanonicalPathWithinBase, } from "./install-path.js";
|
|
@@ -17,6 +17,7 @@ import { syncFileBestEffortSync } from "./file-sync.js";
|
|
|
17
17
|
import { finalizeArchivePublication } from "./archive-durability.js";
|
|
18
18
|
import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
|
|
19
19
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
20
|
+
import { ArchiveSecurityError } from "./archive-errors.js";
|
|
20
21
|
export async function withStagedArchivePublication(params, extract) {
|
|
21
22
|
await withStagedArchiveDestination({
|
|
22
23
|
destinationRealDir: params.destinationGuard.realPath,
|
|
@@ -101,6 +102,23 @@ async function mergeTree(params, publication, durable = true, entryUmask = 0) {
|
|
|
101
102
|
assertDirectoryIdentityGuard(destinationGuard);
|
|
102
103
|
check();
|
|
103
104
|
for (const ancestor of ancestors) {
|
|
105
|
+
// Verify every retained ancestor, including its current name and physical path.
|
|
106
|
+
// Shallow chains cost less to verify directly than crossing the native bridge.
|
|
107
|
+
if (ancestors.length >= 4 && ancestor.owner.verifyCanonical) {
|
|
108
|
+
let verified;
|
|
109
|
+
try {
|
|
110
|
+
verified = await ancestor.owner.verifyCanonical();
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (error instanceof FsSafeError || isNotFoundPathError(error)) {
|
|
114
|
+
throw createArchiveSymlinkTraversalError(path.relative(destinationDir, ancestor.guard.dir));
|
|
115
|
+
}
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
check();
|
|
119
|
+
if (verified)
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
104
122
|
assertDirectoryIdentityGuard(ancestor.guard);
|
|
105
123
|
check();
|
|
106
124
|
await ancestor.owner.verify(check);
|
|
@@ -156,15 +174,22 @@ async function mergeTree(params, publication, durable = true, entryUmask = 0) {
|
|
|
156
174
|
await ownExtractionDestinationMutation(params.deadline, async () => {
|
|
157
175
|
await assertGuards();
|
|
158
176
|
assertSourceFrontier();
|
|
159
|
-
const
|
|
177
|
+
const guard = await createDirectoryIdentityGuard(destinationPath).catch((error) => {
|
|
178
|
+
if (error instanceof ArchiveSecurityError && error.code === "destination-symlink") {
|
|
179
|
+
throw createArchiveSymlinkTraversalError(originalPath);
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
});
|
|
183
|
+
check();
|
|
184
|
+
const owner = await pinNodeDirectoryForMode(destinationPath, {
|
|
185
|
+
expectedIdentity: guard.stat, canonicalPath: guard.realPath,
|
|
186
|
+
}).catch((error) => {
|
|
160
187
|
if (error instanceof FsSafeError && (error.code === "not-file" || error.code === "path-mismatch")) {
|
|
161
188
|
throw createArchiveSymlinkTraversalError(originalPath);
|
|
162
189
|
}
|
|
163
190
|
throw error;
|
|
164
191
|
});
|
|
165
192
|
try {
|
|
166
|
-
check();
|
|
167
|
-
const guard = await createDirectoryIdentityGuard(destinationPath);
|
|
168
193
|
check();
|
|
169
194
|
await owner.verify(check);
|
|
170
195
|
ancestors.push({ guard, owner });
|
|
Binary file
|
|
@@ -17,7 +17,7 @@ import { FsSafeError } from "./errors.js";
|
|
|
17
17
|
import { inspectFileIdentity } from "./strict-file-identity.js";
|
|
18
18
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
19
19
|
import { realpathSync } from "./realpath.js";
|
|
20
|
-
import { getNativeBinding } from "./native.js";
|
|
20
|
+
import { assertNativeCapabilities, getNativeBinding } from "./native.js";
|
|
21
21
|
import { admitZipBuffer } from "./archive-zip-admission.js";
|
|
22
22
|
import { validateNativeZipManifest } from "./archive-zip-manifest.js";
|
|
23
23
|
import { resolveExtractLimits, resolveTarMeterLimits } from "./archive-limits.js";
|
|
@@ -199,9 +199,15 @@ async function readNativeBufferEntry(native, buffer, kind, requested, displayPat
|
|
|
199
199
|
try {
|
|
200
200
|
const signal = new AbortController().signal;
|
|
201
201
|
const limits = resolveTarMeterLimits();
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
202
|
+
let reader;
|
|
203
|
+
if (kind === "zip") {
|
|
204
|
+
assertNativeCapabilities(native, "openZipBufferNative");
|
|
205
|
+
reader = await native.openZipBufferNative(buffer, limits, AbortSignal.any([signal]));
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
assertNativeCapabilities(native, "openTarBufferNative");
|
|
209
|
+
reader = await native.openTarBufferNative(buffer, kind, limits, AbortSignal.any([signal]));
|
|
210
|
+
}
|
|
205
211
|
const manifest = reader.entries;
|
|
206
212
|
if (kind === "zip")
|
|
207
213
|
validateNativeZipManifest(manifest, zipEntries);
|
|
@@ -227,7 +233,7 @@ export async function readArchiveEntry(archivePath, entryPath, options) {
|
|
|
227
233
|
const zipEntries = [];
|
|
228
234
|
if (kind === "zip")
|
|
229
235
|
admitZipBuffer(buffer, resolveExtractLimits(), entry => { zipEntries.push(entry); });
|
|
230
|
-
const native = getNativeBinding();
|
|
236
|
+
const native = getNativeBinding(kind === "zip" ? "openZipBufferNative" : "openTarBufferNative");
|
|
231
237
|
if (native)
|
|
232
238
|
return await readNativeBufferEntry(native, buffer, kind, requestedEntry, entryPath, maxBytes, zipEntries);
|
|
233
239
|
return kind === "zip" ? await readZipEntry(buffer, requestedEntry, maxBytes, zipEntries)
|
|
@@ -118,11 +118,13 @@ export async function loadAdmittedZipArchive(buffer, admitted) {
|
|
|
118
118
|
const entries = new Map();
|
|
119
119
|
for (const [name, entry, physical] of normalized) {
|
|
120
120
|
const appendSlash = physical.kind === "directory" && !name.endsWith("/");
|
|
121
|
-
|
|
121
|
+
// JSZip reduces a relative root marker such as "./" to an empty name.
|
|
122
|
+
// Keep its directory spelling relative when restoring the terminal slash.
|
|
123
|
+
const normalizedName = appendSlash ? `${name || "."}/` : name;
|
|
122
124
|
if (Object.hasOwn(files, normalizedName))
|
|
123
125
|
collision();
|
|
124
126
|
if (appendSlash) {
|
|
125
|
-
entry.name = `${entry.name}/`;
|
|
127
|
+
entry.name = `${entry.name || "."}/`;
|
|
126
128
|
}
|
|
127
129
|
files[normalizedName] = entry;
|
|
128
130
|
entries.set(physical.portableKey, createAdmittedZipEntry(entry, normalizedName, physical));
|
|
@@ -154,7 +154,7 @@ export async function extractArchive(params) {
|
|
|
154
154
|
const label = kind === "zip" ? "extract zip" : "extract tar";
|
|
155
155
|
const limits = resolveExtractLimits(params.limits);
|
|
156
156
|
const tarLimits = resolveTarMeterLimits(limits);
|
|
157
|
-
const native = getNativeBinding();
|
|
157
|
+
const native = getNativeBinding("inspectArchiveNative", "extractArchiveNative");
|
|
158
158
|
assertNoWindowsPathAlias(archivePath, "filesystem", "archive source uses a Windows filesystem namespace alias");
|
|
159
159
|
assertNoWindowsPathAlias(destDir, "filesystem", "archive destination uses a Windows filesystem namespace alias");
|
|
160
160
|
// Read the declared public fields before private adapters copy options: class
|
|
@@ -282,7 +282,7 @@ export async function inspectTarArchive(params) {
|
|
|
282
282
|
const onFiltered = resolveArchiveFilteredEntryPolicy(params.onFiltered);
|
|
283
283
|
const limits = resolveExtractLimits(params.limits);
|
|
284
284
|
const tarLimits = resolveTarMeterLimits(limits);
|
|
285
|
-
const native = getNativeBinding();
|
|
285
|
+
const native = getNativeBinding("inspectArchiveNative");
|
|
286
286
|
assertNoWindowsPathAlias(archivePath, "filesystem", "archive source uses a Windows filesystem namespace alias");
|
|
287
287
|
return await withExtractionDeadline(params.timeoutMs, "inspect tar", async (deadline) => {
|
|
288
288
|
const staged = await stageArchiveFileForExtraction({ archivePath, limits, deadline });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import syncFs, {} from "node:fs";
|
|
2
2
|
import fs, {} from "node:fs/promises";
|
|
3
|
-
import { readBoundedSync } from "./bounded-read.js";
|
|
3
|
+
import { readBoundedSync, readFileHandleBounded } from "./bounded-read.js";
|
|
4
4
|
import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
|
|
5
5
|
import { inspectFileIdentity, inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
6
6
|
import { sleep, sleepSync } from "./timing.js";
|
|
@@ -207,7 +207,7 @@ export class AtomicFile {
|
|
|
207
207
|
}
|
|
208
208
|
*readFile(sizeHint) {
|
|
209
209
|
if (typeof this.resource !== "number")
|
|
210
|
-
return yield* wait(this.resource
|
|
210
|
+
return yield* wait(readFileHandleBounded(this.resource, Infinity));
|
|
211
211
|
if (sizeHint === undefined)
|
|
212
212
|
return this.io.syncFs.readFileSync(this.resource);
|
|
213
213
|
const fd = this.resource;
|
|
@@ -13,6 +13,7 @@ export declare function readBoundedAsync(maxBytes: number, readChunk: (scratch:
|
|
|
13
13
|
* force an unbounded allocation.
|
|
14
14
|
*/
|
|
15
15
|
export declare function readFileHandleBounded(handle: ReadableFileHandle, maxBytes: number): Promise<Buffer>;
|
|
16
|
+
export declare function readFileHandleBoundedWithSize(handle: ReadableFileHandle, maxBytes: number, initialSize?: number): Promise<Buffer>;
|
|
16
17
|
/** Async bounded read from a numeric descriptor. The caller owns the descriptor. */
|
|
17
18
|
export declare function readFileDescriptorBounded(fd: number, maxBytes: number): Promise<Buffer>;
|
|
18
19
|
export declare function readBoundedSync(maxBytes: number, readChunk: (scratch: Buffer, length: number) => number, options?: {
|
|
@@ -73,11 +73,18 @@ export async function readBoundedAsync(maxBytes, readChunk, options = {}) {
|
|
|
73
73
|
* force an unbounded allocation.
|
|
74
74
|
*/
|
|
75
75
|
export async function readFileHandleBounded(handle, maxBytes) {
|
|
76
|
+
return await readFileHandleBoundedWithSize(handle, maxBytes);
|
|
77
|
+
}
|
|
78
|
+
// Internal: the admitted size bounds the first allocation, never the read.
|
|
79
|
+
export function readFileHandleBoundedWithSize(handle, maxBytes, initialSize) {
|
|
76
80
|
normalizeMaxBytes(maxBytes);
|
|
77
81
|
const fd = "fd" in handle && typeof handle.fd === "number" ? handle.fd : undefined;
|
|
78
|
-
return
|
|
82
|
+
return readBoundedAsync(maxBytes, async (scratch, length) => {
|
|
79
83
|
return (await handle.read(scratch, 0, length, null)).bytesRead;
|
|
80
|
-
}, {
|
|
84
|
+
}, {
|
|
85
|
+
initialSize,
|
|
86
|
+
observeRegularFileSize: fd === undefined ? undefined : () => regularFileSize(fd),
|
|
87
|
+
});
|
|
81
88
|
}
|
|
82
89
|
function regularFileSize(fd) {
|
|
83
90
|
try {
|
|
@@ -6,7 +6,7 @@ import { getNativeBinding, requireNativeBinding } from "./native.js";
|
|
|
6
6
|
*/
|
|
7
7
|
export async function readCloneFileMetadata(files) {
|
|
8
8
|
const paths = files.map(assertAbsolutePathInput);
|
|
9
|
-
const native = process.platform === "darwin" ? requireNativeBinding() : getNativeBinding();
|
|
9
|
+
const native = process.platform === "darwin" ? requireNativeBinding("readCloneFileMetadata") : getNativeBinding("readCloneFileMetadata");
|
|
10
10
|
if (!native)
|
|
11
11
|
return paths.map(() => undefined);
|
|
12
12
|
const results = await native.readCloneFileMetadata(paths);
|
|
@@ -19,6 +19,7 @@ export async function readCloneFileMetadata(files) {
|
|
|
19
19
|
result.readUInt32LE(20) !== 0x100)
|
|
20
20
|
return undefined;
|
|
21
21
|
return {
|
|
22
|
+
exactIdentity: Object.freeze({ dev: BigInt(result.readUInt32LE(24)), ino: result.readBigInt64LE(76) }),
|
|
22
23
|
dev: result.readUInt32LE(24),
|
|
23
24
|
type: result.readUInt32LE(28),
|
|
24
25
|
mtimeSec: Number(result.readBigInt64LE(32)),
|
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
import type { FsSafeNativeStatus } from "./native-status.js";
|
|
1
2
|
export { configureFsSafeNative, getFsSafeNativeConfig, type FsSafeNativeConfig, type FsSafeNativeMode, } from "./native-config.js";
|
|
3
|
+
export type { FsSafeNativeStatus, FsSafeNativeStatusReason, } from "./native-status.js";
|
|
2
4
|
export { configureFsSafeLocks, getFsSafeLockConfig, type FsSafeLockConfig, } from "./lock-config.js";
|
|
5
|
+
/** Read native status without loading the native module on config import. */
|
|
6
|
+
export declare function getFsSafeNativeStatus(options?: {
|
|
7
|
+
probe?: boolean;
|
|
8
|
+
}): Promise<FsSafeNativeStatus>;
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
export { configureFsSafeNative, getFsSafeNativeConfig, } from "./native-config.js";
|
|
2
2
|
export { configureFsSafeLocks, getFsSafeLockConfig, } from "./lock-config.js";
|
|
3
|
+
/** Read native status without loading the native module on config import. */
|
|
4
|
+
export async function getFsSafeNativeStatus(options) {
|
|
5
|
+
const { readFsSafeNativeStatus } = await import("./native-status.js");
|
|
6
|
+
return readFsSafeNativeStatus(options);
|
|
7
|
+
}
|
|
@@ -3,19 +3,21 @@ import type { FileHandle } from "node:fs/promises";
|
|
|
3
3
|
import { type CopyCloneMode } from "./copy-policy.js";
|
|
4
4
|
import { type NativeBinding } from "./native.js";
|
|
5
5
|
import { type NativeFileCopyResult } from "./native-binding.js";
|
|
6
|
+
import type { CopyMetadata } from "./copy-metadata.js";
|
|
6
7
|
export type CopyFileInput = {
|
|
7
8
|
kind: "file";
|
|
8
9
|
handle: FileHandle;
|
|
9
10
|
size: number;
|
|
10
11
|
clone: CopyCloneMode;
|
|
11
12
|
signal?: AbortSignal;
|
|
13
|
+
metadata?: CopyMetadata;
|
|
12
14
|
verifySource(): Promise<void>;
|
|
13
15
|
};
|
|
14
16
|
export declare function resolveFileCopyCloneMode(mode?: CopyCloneMode): CopyCloneMode;
|
|
15
17
|
export declare function assertCopySourceCurrent(source: {
|
|
16
18
|
handle: FileHandle;
|
|
17
19
|
realPath: string;
|
|
18
|
-
}, identity: BigIntStats):
|
|
20
|
+
}, identity: BigIntStats): void;
|
|
19
21
|
export declare function writeCopyFileToFd(fd: number, input: CopyFileInput, maxBytes?: number, assertBeforeMutation?: () => void): Promise<void>;
|
|
20
22
|
export declare function createNativeCopyFile(native: NativeBinding, input: CopyFileInput, parentFd: number, basename: string, maxBytes: number | undefined): Promise<NativeFileCopyResult | undefined>;
|
|
21
23
|
export declare function assertNativeCopyCompleted(input: CopyFileInput, copied?: NativeFileCopyResult): void;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs, {} from "node:fs";
|
|
2
2
|
import { resolveCopyCloneMode } from "./copy-policy.js";
|
|
3
3
|
import { FsSafeError } from "./errors.js";
|
|
4
|
-
import { getNativeBinding } from "./native.js";
|
|
4
|
+
import { getNativeBinding, selectNativeBinding } from "./native.js";
|
|
5
5
|
import { captureNativeFdClose } from "./native-binding.js";
|
|
6
|
-
import {
|
|
6
|
+
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
7
7
|
import { transferFileHandle } from "./file-handle-transfer.js";
|
|
8
8
|
export function resolveFileCopyCloneMode(mode) {
|
|
9
9
|
const clone = resolveCopyCloneMode(mode, "never");
|
|
@@ -12,9 +12,9 @@ export function resolveFileCopyCloneMode(mode) {
|
|
|
12
12
|
}
|
|
13
13
|
return clone;
|
|
14
14
|
}
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
export function assertCopySourceCurrent(source, identity) {
|
|
16
|
+
inspectFileIdentitySync(() => fs.fstatSync(source.handle.fd, { bigint: true }), identity);
|
|
17
|
+
inspectFileIdentitySync(() => {
|
|
18
18
|
const current = fs.lstatSync(source.realPath, { bigint: true });
|
|
19
19
|
if (current.isSymbolicLink() || !current.isFile()) {
|
|
20
20
|
throw new FsSafeError("path-mismatch", "copy source path changed");
|
|
@@ -29,7 +29,8 @@ export async function writeCopyFileToFd(fd, input, maxBytes, assertBeforeMutatio
|
|
|
29
29
|
}
|
|
30
30
|
export async function createNativeCopyFile(native, input, parentFd, basename, maxBytes) {
|
|
31
31
|
input.signal?.throwIfAborted();
|
|
32
|
-
|
|
32
|
+
const copier = selectNativeBinding(native, "copyFileExclusive");
|
|
33
|
+
if (!copier) {
|
|
33
34
|
if (input.clone === "always") {
|
|
34
35
|
throw new FsSafeError("helper-unavailable", "native file cloning is unavailable");
|
|
35
36
|
}
|
|
@@ -39,7 +40,7 @@ export async function createNativeCopyFile(native, input, parentFd, basename, ma
|
|
|
39
40
|
const nativeSignal = input.signal ? AbortSignal.any([input.signal]) : undefined;
|
|
40
41
|
try {
|
|
41
42
|
// The caller adopts this descriptor before observing a later cancellation.
|
|
42
|
-
return await
|
|
43
|
+
return await copier.copyFileExclusive(input.handle.fd, parentFd, basename, input.clone, maxBytes !== undefined && Number.isFinite(maxBytes) ? maxBytes : undefined, nativeSignal);
|
|
43
44
|
}
|
|
44
45
|
catch (error) {
|
|
45
46
|
const code = error?.code;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type BigIntStats } from "node:fs";
|
|
2
|
+
import { type AnyAsyncDirectoryGuard } from "./directory-guard.js";
|
|
3
|
+
import type { NativeBinding } from "./native-binding.js";
|
|
4
|
+
import type { PinnedWriteParams } from "./pinned-write-types.js";
|
|
5
|
+
export type CopyLinkInput = {
|
|
6
|
+
kind: "link";
|
|
7
|
+
stageBeforePublish: true;
|
|
8
|
+
sourcePath: string;
|
|
9
|
+
identity: BigIntStats;
|
|
10
|
+
target?: Buffer;
|
|
11
|
+
preserveMetadata: boolean;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
verifySource(): Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
/** Shared by tree byte copying and per-file copying; never resolves the target. */
|
|
16
|
+
export declare function readCopyLinkTarget(source: string): Promise<Buffer>;
|
|
17
|
+
export declare function assertCopyLinkAvailable(): void;
|
|
18
|
+
export declare function admitCopyLink(sourcePath: string, preserveMetadata: boolean, signal?: AbortSignal): Promise<CopyLinkInput | undefined>;
|
|
19
|
+
/** The caller has admitted the destination parent under Root's mutation policy. */
|
|
20
|
+
export declare function copyLinkAtParent(params: PinnedWriteParams, input: CopyLinkInput, parent: AnyAsyncDirectoryGuard, native?: {
|
|
21
|
+
binding: NativeBinding;
|
|
22
|
+
fd: number;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
dev: bigint;
|
|
25
|
+
ino: bigint;
|
|
26
|
+
}>;
|