@openclaw/openshell-sandbox 2026.10.5-beta.4 → 2026.10.10-beta.2
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
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import fs from "node:fs";
|
|
54
|
+
import path from "node:path";
|
|
55
|
+
import { inspectDirectoryIdentitySync } from "./directory-guard.js";
|
|
56
|
+
import { nodeDirectorySearchOnlyFlags } from "./directory-mode-node.js";
|
|
57
|
+
import { FsSafeError } from "./errors.js";
|
|
58
|
+
import { getNativeBinding } from "./native.js";
|
|
59
|
+
import { captureNativeFdClose } from "./native-binding.js";
|
|
60
|
+
import { openExactNativeRootSync } from "./native-parent-admission.js";
|
|
61
|
+
import { hasNodeErrorCode } from "./path.js";
|
|
62
|
+
import { realpathSync } from "./realpath.js";
|
|
63
|
+
import { assertRootIdentityCurrentSync } from "./root-context.js";
|
|
64
|
+
import { verifyMkdirDirectory } from "./root-create-native.js";
|
|
65
|
+
import { directoryComponentNotDirectoryError } from "./root-errors.js";
|
|
66
|
+
import { isSafePathSegment } from "./safe-path-segment.js";
|
|
67
|
+
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
68
|
+
import { getFsSafeTestHooks } from "./test-hooks.js";
|
|
69
|
+
import { pathForWindowsFilesystem } from "./windows-path-alias.js";
|
|
70
|
+
export function tryMkdirNativeParents(root, relativePath) {
|
|
71
|
+
try {
|
|
72
|
+
return mkdirOrdinaryNativeParents(root, relativePath);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (hasNodeErrorCode(error, "ENOTDIR"))
|
|
76
|
+
throw directoryComponentNotDirectoryError(error);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function mkdirOrdinaryNativeParents(root, relativePath) {
|
|
81
|
+
if (getFsSafeTestHooks()?.beforeRootFallbackMutation)
|
|
82
|
+
return false;
|
|
83
|
+
const segments = relativePath.split(path.sep === "\\" ? /[\\/]/ : "/");
|
|
84
|
+
if (segments.length < 2 || segments.some(segment => !isSafePathSegment(segment, { allowDotPrefix: true }) || segment.endsWith(".")))
|
|
85
|
+
return false;
|
|
86
|
+
let rootStat;
|
|
87
|
+
assertRootIdentityCurrentSync(root, stat => { rootStat = stat; });
|
|
88
|
+
const target = path.join(root.rootReal, ...segments);
|
|
89
|
+
const parentPath = path.dirname(target);
|
|
90
|
+
try {
|
|
91
|
+
const child = fs.lstatSync(pathForWindowsFilesystem(target), { throwIfNoEntry: false });
|
|
92
|
+
if (child && (!child.isDirectory() || realpathSync.native(pathForWindowsFilesystem(target)) !== target))
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
let parentIdentity;
|
|
99
|
+
try {
|
|
100
|
+
parentIdentity = inspectDirectoryIdentitySync(parentPath);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
// Reuse this exact Root snapshot and failed parent observation without an
|
|
104
|
+
// intervening await. All opened ancestors still receive fresh native fences.
|
|
105
|
+
return hasNodeErrorCode(error, "ENOENT") ? mkdirMissingParents(root, segments, rootStat) : false;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
if (realpathSync.native(pathForWindowsFilesystem(parentPath)) !== parentPath)
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return mkdirExistingParent(root, segments, parentIdentity);
|
|
115
|
+
}
|
|
116
|
+
/** Ordinary missing suffixes need no policy callbacks or repeated path resolution. */
|
|
117
|
+
function mkdirMissingParents(root, segments, rootStat) {
|
|
118
|
+
const binding = getNativeBinding("openBeneath", "mkdirChildBeneath");
|
|
119
|
+
if (!binding?.openBeneath || !binding.mkdirOpenChildBeneath)
|
|
120
|
+
return false;
|
|
121
|
+
let parentDepth = segments.length - 2;
|
|
122
|
+
let parentPath;
|
|
123
|
+
let parentIdentity;
|
|
124
|
+
for (;;) {
|
|
125
|
+
parentPath = path.join(root.rootReal, ...segments.slice(0, parentDepth));
|
|
126
|
+
try {
|
|
127
|
+
parentIdentity = inspectDirectoryIdentitySync(parentPath, undefined, parentDepth === 0 ? rootStat : undefined);
|
|
128
|
+
if (realpathSync.native(pathForWindowsFilesystem(parentPath)) !== parentPath)
|
|
129
|
+
return false;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (!hasNodeErrorCode(error, "ENOENT") || parentDepth === 0)
|
|
134
|
+
return false;
|
|
135
|
+
parentDepth--;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
140
|
+
try {
|
|
141
|
+
const rootOwner = __addDisposableResource(env_1, openExactNativeRootSync(binding, {
|
|
142
|
+
rootPath: root.rootReal, rootIdentity: root.rootIdentity,
|
|
143
|
+
}), false);
|
|
144
|
+
const close = captureNativeFdClose(binding);
|
|
145
|
+
const directories = [];
|
|
146
|
+
const directoryOwner = __addDisposableResource(env_1, { [Symbol.dispose]() {
|
|
147
|
+
const errors = [];
|
|
148
|
+
for (const directory of directories.toReversed()) {
|
|
149
|
+
try {
|
|
150
|
+
close(directory.fd);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
errors.push(error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (errors.length)
|
|
157
|
+
throw new AggregateError(errors, "mkdir directory close failed");
|
|
158
|
+
} }, false);
|
|
159
|
+
const flags = (nodeDirectorySearchOnlyFlags()?.flags ?? fs.constants.O_RDONLY) |
|
|
160
|
+
(fs.constants.O_DIRECTORY ?? 0) | (fs.constants.O_NOFOLLOW ?? 0);
|
|
161
|
+
let current = rootOwner.fd;
|
|
162
|
+
if (parentDepth > 0) {
|
|
163
|
+
current = binding.openBeneath(rootOwner.fd, segments.slice(0, parentDepth).join("/"), flags).fd;
|
|
164
|
+
directories.push({ fd: current, pathname: parentPath });
|
|
165
|
+
inspectFileIdentitySync(() => fs.fstatSync(current, { bigint: true }), parentIdentity);
|
|
166
|
+
}
|
|
167
|
+
const assertCurrent = () => {
|
|
168
|
+
assertRootIdentityCurrentSync(root);
|
|
169
|
+
for (const directory of directories)
|
|
170
|
+
verifyMkdirDirectory(binding, directory.fd, directory.pathname);
|
|
171
|
+
verifyMkdirDirectory(binding, rootOwner.fd, root.rootReal);
|
|
172
|
+
};
|
|
173
|
+
assertCurrent();
|
|
174
|
+
for (const segment of segments.slice(parentDepth)) {
|
|
175
|
+
const child = binding.mkdirOpenChildBeneath(current, segment, 0o777, flags);
|
|
176
|
+
parentPath = path.join(parentPath, segment);
|
|
177
|
+
directories.push({ fd: child.fd, pathname: parentPath });
|
|
178
|
+
// Retain every ancestor until the complete suffix is admitted. The
|
|
179
|
+
// post-create fence also precedes the next synchronous child mutation.
|
|
180
|
+
assertCurrent();
|
|
181
|
+
current = child.fd;
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
catch (e_1) {
|
|
186
|
+
env_1.error = e_1;
|
|
187
|
+
env_1.hasError = true;
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
__disposeResources(env_1);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (hasNodeErrorCode(error, "ENOTDIR"))
|
|
195
|
+
throw directoryComponentNotDirectoryError(error);
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function mkdirExistingParent(root, segments, parentIdentity) {
|
|
200
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
201
|
+
try {
|
|
202
|
+
const target = path.join(root.rootReal, ...segments);
|
|
203
|
+
const parentPath = path.dirname(target);
|
|
204
|
+
const binding = getNativeBinding("openBeneath", "mkdirChildBeneath");
|
|
205
|
+
if (!binding?.openBeneath || !binding.mkdirChildBeneath) {
|
|
206
|
+
throw new FsSafeError("helper-unavailable", "native confined creation is unavailable");
|
|
207
|
+
}
|
|
208
|
+
const rootOwner = __addDisposableResource(env_2, openExactNativeRootSync(binding, {
|
|
209
|
+
rootPath: root.rootReal, rootIdentity: root.rootIdentity,
|
|
210
|
+
}), false);
|
|
211
|
+
verifyMkdirDirectory(binding, rootOwner.fd, root.rootReal);
|
|
212
|
+
const flags = (nodeDirectorySearchOnlyFlags()?.flags ?? fs.constants.O_RDONLY) |
|
|
213
|
+
(fs.constants.O_DIRECTORY ?? 0) | (fs.constants.O_NOFOLLOW ?? 0);
|
|
214
|
+
const close = captureNativeFdClose(binding);
|
|
215
|
+
const parent = binding.openBeneath(rootOwner.fd, segments.slice(0, -1).join("/"), flags).fd;
|
|
216
|
+
const parentOwner = __addDisposableResource(env_2, { [Symbol.dispose]() { close(parent); } }, false);
|
|
217
|
+
inspectFileIdentitySync(() => fs.fstatSync(parent, { bigint: true }), parentIdentity);
|
|
218
|
+
verifyMkdirDirectory(binding, parent, parentPath);
|
|
219
|
+
assertRootIdentityCurrentSync(root);
|
|
220
|
+
const name = segments.at(-1);
|
|
221
|
+
const child = binding.mkdirOpenChildBeneath
|
|
222
|
+
? binding.mkdirOpenChildBeneath(parent, name, 0o777, flags).fd
|
|
223
|
+
: (binding.mkdirChildBeneath(parent, name, 0o777), binding.openBeneath(parent, name, flags).fd);
|
|
224
|
+
const childOwner = __addDisposableResource(env_2, { [Symbol.dispose]() { close(child); } }, false);
|
|
225
|
+
assertRootIdentityCurrentSync(root);
|
|
226
|
+
verifyMkdirDirectory(binding, child, target);
|
|
227
|
+
inspectDirectoryIdentitySync(parentPath, parentIdentity);
|
|
228
|
+
verifyMkdirDirectory(binding, parent, parentPath);
|
|
229
|
+
verifyMkdirDirectory(binding, rootOwner.fd, root.rootReal);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
catch (e_2) {
|
|
233
|
+
env_2.error = e_2;
|
|
234
|
+
env_2.hasError = true;
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
__disposeResources(env_2);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import fsSync, {} from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { assertDirectoryGuard, assertSyncDirectoryGuard } from "./directory-guard.js";
|
|
4
4
|
import { FsSafeError } from "./errors.js";
|
|
5
5
|
import { assertMutationNotDenied } from "./deny-mutations.js";
|
|
6
|
-
import { openNativeParentAdmission,
|
|
6
|
+
import { borrowNativeRootParent, openNativeParentAdmission, openExactNativeRootAdmissionSync, } from "./native-parent-admission.js";
|
|
7
7
|
import { requireNativeBinding } from "./native.js";
|
|
8
8
|
import { isNotFoundPathError } from "./path.js";
|
|
9
|
-
import {
|
|
9
|
+
import { assertRootIdentityCurrentSync } from "./root-context.js";
|
|
10
10
|
import { resolveRootPathSync } from "./root-path.js";
|
|
11
11
|
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
12
|
-
import { errorCauseOptions, fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, outsideWorkspaceError, } from "./root-errors.js";
|
|
12
|
+
import { errorCauseOptions, fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, outsideWorkspaceError, rootPathChangedError, } from "./root-errors.js";
|
|
13
13
|
import { assertFinalSymlinkRejected, mutationSymlinkResolution } from "./root-symlink-policy.js";
|
|
14
14
|
import { PATH_ALIAS_POLICIES } from "./path-policy.js";
|
|
15
15
|
import { createSuppressedError } from "./suppressed-error.js";
|
|
@@ -80,15 +80,14 @@ export async function movePathNative(root, params, paths, overwrite = false) {
|
|
|
80
80
|
throw error;
|
|
81
81
|
// Advisory fast rejection only. renameNoReplace owns the collision decision.
|
|
82
82
|
}
|
|
83
|
-
const binding = requireNativeBinding();
|
|
83
|
+
const binding = requireNativeBinding("openBeneath", overwrite ? "renameReplaceWithIdentity" : "renameNoReplace");
|
|
84
84
|
if (typeof (overwrite ? binding.renameReplaceWithIdentity : binding.renameNoReplace) !== "function") {
|
|
85
85
|
throw new FsSafeError("helper-unavailable", "native move is unavailable");
|
|
86
86
|
}
|
|
87
|
-
const rootAdmission =
|
|
87
|
+
const rootAdmission = openExactNativeRootAdmissionSync(binding, {
|
|
88
88
|
rootPath: root.rootReal,
|
|
89
89
|
rootIdentity: root.rootIdentity,
|
|
90
90
|
operation: "native move",
|
|
91
|
-
searchOnly: true,
|
|
92
91
|
});
|
|
93
92
|
let sourceParent;
|
|
94
93
|
let targetParent;
|
|
@@ -96,15 +95,18 @@ export async function movePathNative(root, params, paths, overwrite = false) {
|
|
|
96
95
|
let operationError;
|
|
97
96
|
try {
|
|
98
97
|
const sourceParentRelativePath = nativeParentRelativePath(root.rootReal, paths.sourceParentPath);
|
|
99
|
-
sourceParent = await openNativeParentAdmission(binding, rootAdmission, sourceParentRelativePath);
|
|
98
|
+
sourceParent = sourceParentRelativePath === "" ? borrowNativeRootParent(rootAdmission) : await openNativeParentAdmission(binding, rootAdmission, sourceParentRelativePath, "native-directory");
|
|
100
99
|
const targetParentRelativePath = nativeParentRelativePath(root.rootReal, paths.targetParentPath);
|
|
101
100
|
targetParent = targetParentRelativePath === sourceParentRelativePath
|
|
102
101
|
? sourceParent
|
|
103
|
-
:
|
|
102
|
+
: targetParentRelativePath === "" ? borrowNativeRootParent(rootAdmission)
|
|
103
|
+
: await openNativeParentAdmission(binding, rootAdmission, targetParentRelativePath, "native-directory");
|
|
104
104
|
const parentAdmissions = targetParent === sourceParent
|
|
105
105
|
? [sourceParent]
|
|
106
106
|
: [sourceParent, targetParent];
|
|
107
|
-
|
|
107
|
+
const beforeMutation = getFsSafeTestHooks()?.beforeRootFallbackMutation;
|
|
108
|
+
if (beforeMutation)
|
|
109
|
+
await beforeMutation("move", paths.targetPath);
|
|
108
110
|
const admittedSourcePath = admitMovePath(root, sourceParent, path.basename(paths.sourcePath));
|
|
109
111
|
const admittedTargetPath = admitMovePath(root, targetParent, path.basename(paths.targetPath));
|
|
110
112
|
if (params.denyMutations) {
|
|
@@ -113,9 +115,29 @@ export async function movePathNative(root, params, paths, overwrite = false) {
|
|
|
113
115
|
await assertMutationNotDenied(admittedSourcePath, params.denyMutations, { protectAncestors: true });
|
|
114
116
|
await assertMutationNotDenied(admittedTargetPath, params.denyMutations, { protectAncestors: true });
|
|
115
117
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
const rootParent = sourceParentRelativePath === "" ? sourceParent
|
|
119
|
+
: targetParentRelativePath === "" ? targetParent : undefined;
|
|
120
|
+
if (rootParent) {
|
|
121
|
+
// Borrowing Root already checked this guard in the same synchronous phase.
|
|
122
|
+
const borrowedRootCurrent = sourceParent === targetParent &&
|
|
123
|
+
sourceParentRelativePath === "" && !beforeMutation &&
|
|
124
|
+
params.denyMutations === undefined && params.assertBeforeMutation === undefined;
|
|
125
|
+
if (!borrowedRootCurrent) {
|
|
126
|
+
try {
|
|
127
|
+
assertSyncDirectoryGuard(rootParent.guard);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
throw rootPathChangedError(error instanceof Error ? error : undefined);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
assertRootIdentityCurrentSync(root);
|
|
136
|
+
}
|
|
137
|
+
for (const admission of parentAdmissions) {
|
|
138
|
+
if (admission !== rootParent)
|
|
139
|
+
assertSyncDirectoryGuard(admission.guard);
|
|
140
|
+
}
|
|
119
141
|
// Linux auto fallback needs an exact source even without an authority callback.
|
|
120
142
|
const sourceStat = overwrite || params.assertBeforeMutation || (process.platform === "linux" && !params.requireNative)
|
|
121
143
|
? inspectFileIdentitySync(() => admitMoveSourceStat(fsSync.lstatSync(admittedSourcePath, { bigint: true })), paths.expectedSourceIdentity)
|
|
@@ -185,7 +207,7 @@ export async function movePathNative(root, params, paths, overwrite = false) {
|
|
|
185
207
|
}
|
|
186
208
|
try {
|
|
187
209
|
for (const admission of parentAdmissions)
|
|
188
|
-
|
|
210
|
+
assertDirectoryGuard(admission.guard, "native");
|
|
189
211
|
if (overwrite)
|
|
190
212
|
inspectFileIdentitySync(() => fsSync.lstatSync(admittedTargetPath, { bigint: true }), sourceStat);
|
|
191
213
|
}
|
|
@@ -211,7 +233,7 @@ export async function movePathNative(root, params, paths, overwrite = false) {
|
|
|
211
233
|
}
|
|
212
234
|
}
|
|
213
235
|
try {
|
|
214
|
-
|
|
236
|
+
rootAdmission.root.close();
|
|
215
237
|
}
|
|
216
238
|
catch (error) {
|
|
217
239
|
closeErrors.push(error);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import type { PinnedMutationPolicySnapshot } from "./pinned-mutation-admission.js";
|
|
3
|
+
import { type RootContext } from "./root-context.js";
|
|
4
|
+
export type Creation = {
|
|
5
|
+
root: RootContext;
|
|
6
|
+
directory: string;
|
|
7
|
+
target: string;
|
|
8
|
+
mkdir: boolean;
|
|
9
|
+
private?: boolean;
|
|
10
|
+
policy?: PinnedMutationPolicySnapshot;
|
|
11
|
+
resolveCurrent(): Promise<string>;
|
|
12
|
+
assertBeforeMutation?: () => void;
|
|
13
|
+
originalPath?: string;
|
|
14
|
+
selectedParent?: NonNullable<ReturnType<typeof existingCreationParent>>;
|
|
15
|
+
};
|
|
16
|
+
export declare function existingCreationParent(params: Creation): {
|
|
17
|
+
path: string;
|
|
18
|
+
identity: fs.BigIntStats;
|
|
19
|
+
relative: string;
|
|
20
|
+
flags: number;
|
|
21
|
+
} | undefined;
|
|
22
|
+
export declare function probeNativeCreationPath(root: RootContext, relativePath: string): {
|
|
23
|
+
rootReal: string;
|
|
24
|
+
rootWithSep: string;
|
|
25
|
+
resolved: string;
|
|
26
|
+
parent: {
|
|
27
|
+
path: string;
|
|
28
|
+
identity: fs.BigIntStats;
|
|
29
|
+
relative: string;
|
|
30
|
+
flags: number;
|
|
31
|
+
};
|
|
32
|
+
} | undefined;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { inspectDirectoryIdentitySync } from "./directory-guard.js";
|
|
4
|
+
import { nodeDirectorySearchOnlyFlags } from "./directory-mode-node.js";
|
|
5
|
+
import { assertRootIdentityCurrentSync } from "./root-context.js";
|
|
6
|
+
import { getFsSafeTestHooks } from "./test-hooks.js";
|
|
7
|
+
import { pathForWindowsFilesystem } from "./windows-path-alias.js";
|
|
8
|
+
import { realpathSync } from "./realpath.js";
|
|
9
|
+
import { isSafePathSegment } from "./safe-path-segment.js";
|
|
10
|
+
export function existingCreationParent(params) {
|
|
11
|
+
if (params.private || params.policy || params.assertBeforeMutation !== undefined ||
|
|
12
|
+
getFsSafeTestHooks()?.beforeRootFallbackMutation || !params.originalPath ||
|
|
13
|
+
params.directory !== path.dirname(params.target))
|
|
14
|
+
return undefined;
|
|
15
|
+
const segments = params.originalPath.split(path.sep === "\\" ? /[\\/]/ : "/");
|
|
16
|
+
if (segments.some(segment => !isSafePathSegment(segment, { allowDotPrefix: true }) || segment.endsWith(".")) ||
|
|
17
|
+
path.join(params.root.rootReal, ...segments) !== params.target)
|
|
18
|
+
return undefined;
|
|
19
|
+
let rootStat;
|
|
20
|
+
assertRootIdentityCurrentSync(params.root, stat => { rootStat = stat; });
|
|
21
|
+
try {
|
|
22
|
+
const identity = inspectDirectoryIdentitySync(params.directory, undefined, params.directory === params.root.rootReal ? rootStat : undefined);
|
|
23
|
+
if (realpathSync.native(pathForWindowsFilesystem(params.directory)) !== params.directory)
|
|
24
|
+
return undefined;
|
|
25
|
+
return {
|
|
26
|
+
path: params.directory, identity,
|
|
27
|
+
relative: path.relative(params.root.rootReal, params.directory).split(path.sep).join("/"),
|
|
28
|
+
flags: (nodeDirectorySearchOnlyFlags()?.flags ?? fs.constants.O_RDONLY) |
|
|
29
|
+
(fs.constants.O_DIRECTORY ?? 0) | (fs.constants.O_NOFOLLOW ?? 0),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function probeNativeCreationPath(root, relativePath) {
|
|
37
|
+
if (typeof relativePath !== "string")
|
|
38
|
+
return undefined;
|
|
39
|
+
const segments = relativePath.split(path.sep === "\\" ? /[\\/]/ : "/");
|
|
40
|
+
if (segments.some(segment => !isSafePathSegment(segment, { allowDotPrefix: true }) || segment.endsWith(".")))
|
|
41
|
+
return undefined;
|
|
42
|
+
const target = path.join(root.rootReal, ...segments);
|
|
43
|
+
assertRootIdentityCurrentSync(root);
|
|
44
|
+
try {
|
|
45
|
+
if (fs.lstatSync(pathForWindowsFilesystem(target), { throwIfNoEntry: false }))
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const parent = existingCreationParent({ root, target, directory: path.dirname(target), mkdir: true,
|
|
52
|
+
originalPath: relativePath, resolveCurrent: async () => target });
|
|
53
|
+
if (!parent)
|
|
54
|
+
return undefined;
|
|
55
|
+
return { rootReal: root.rootReal, rootWithSep: root.rootWithSep, resolved: target, parent };
|
|
56
|
+
}
|
|
@@ -38,6 +38,8 @@ export type RootCopyOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyM
|
|
|
38
38
|
clone?: CopyCloneMode;
|
|
39
39
|
signal?: AbortSignal;
|
|
40
40
|
preserveSourceMode?: boolean;
|
|
41
|
+
preserveMetadata?: boolean;
|
|
42
|
+
sourceSymlinks?: "reject" | "copy-link";
|
|
41
43
|
onDestinationPublished?: (receipt: RootCopyPublicationReceipt) => void;
|
|
42
44
|
};
|
|
43
45
|
export type RootCopySource = string | {
|
|
@@ -9,3 +9,4 @@ export type { CopyCloneMode } from "./copy-policy.js";
|
|
|
9
9
|
export type { RootEntriesOptions } from "./root-entries.js";
|
|
10
10
|
export type { ContainmentGuarantee } from "./containment.js";
|
|
11
11
|
export type { RootWalkDataEntry, RootWalkDataEntryKind, RootWalkDirectoryErrorBehavior, RootWalkEntry, RootWalkEntryFilter, RootWalkEntryFilterResult, RootWalkEntryKind, RootWalkLimitBehavior, RootWalkOptions, RootWalkSymlinkPolicy, } from "./root-walk.js";
|
|
12
|
+
export type { ExactFileIdentity } from "./exact-identity.js";
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { scheduler } from "node:timers/promises";
|
|
4
|
-
import { assertSyncDirectoryGuard } from "./directory-guard.js";
|
|
5
4
|
import { assertMutationNotDenied } from "./deny-mutations.js";
|
|
6
5
|
import { FsSafeError } from "./errors.js";
|
|
7
6
|
import { MutationAuthorityError } from "./mutation-authority.js";
|
|
8
7
|
import { getNativeBinding } from "./native.js";
|
|
9
|
-
import { openNativeParentAdmission,
|
|
8
|
+
import { borrowNativeRootParent, openNativeParentAdmission, openExactNativeRootAdmissionSync } from "./native-parent-admission.js";
|
|
10
9
|
import { isNotFoundPathError, isPathInside } from "./path.js";
|
|
11
10
|
import { assertRootIdentityCurrentSync } from "./root-context.js";
|
|
12
11
|
import { normalizeRemoveGuardError, normalizeRemovePathError } from "./root-errors.js";
|
|
13
12
|
import { captureNonrecursiveRemovalAdmission, nonrecursiveRemovalKind } from "./root-remove.js";
|
|
13
|
+
import { assertRemovalDirectoryCurrent, createRemovalDirectoryAssertion } from "./root-remove-identity.js";
|
|
14
14
|
import { createSuppressedError } from "./suppressed-error.js";
|
|
15
15
|
import { getFsSafeTestHooks } from "./test-hooks.js";
|
|
16
16
|
function unavailable() {
|
|
@@ -28,8 +28,73 @@ function normalize(error, details) {
|
|
|
28
28
|
}
|
|
29
29
|
return normalizeRemovePathError(error, details);
|
|
30
30
|
}
|
|
31
|
+
async function removeNativeLeaf(binding, parent, target, options, boundary, rootGuardCurrent) {
|
|
32
|
+
const assertNotAborted = () => {
|
|
33
|
+
try {
|
|
34
|
+
options.signal?.throwIfAborted();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw new MutationAuthorityError(error);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
assertNotAborted();
|
|
41
|
+
const before = getFsSafeTestHooks()?.beforeRootFallbackMutation;
|
|
42
|
+
if (before) {
|
|
43
|
+
try {
|
|
44
|
+
await before("remove", target);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
throw normalizeRemoveGuardError(error);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (options.denyMutations)
|
|
51
|
+
await assertMutationNotDenied(target, options.denyMutations, { protectAncestors: true });
|
|
52
|
+
const name = path.basename(target);
|
|
53
|
+
const observe = (expected) => {
|
|
54
|
+
assertNotAborted();
|
|
55
|
+
if (!rootGuardCurrent)
|
|
56
|
+
boundary.assertCurrent();
|
|
57
|
+
rootGuardCurrent = false;
|
|
58
|
+
try {
|
|
59
|
+
const entry = binding.rootRemovalStat(parent.fd, name);
|
|
60
|
+
if (expected && (entry.dev !== expected.dev || entry.ino !== expected.ino || entry.directory !== expected.directory)) {
|
|
61
|
+
throw new FsSafeError("path-mismatch", "removal entry changed");
|
|
62
|
+
}
|
|
63
|
+
if (entry.symlink && options.mutationSymlinks !== undefined)
|
|
64
|
+
throw new FsSafeError("symlink", "symlink not allowed", {
|
|
65
|
+
details: { operation: "remove", phase: expected ? "remove" : "inspect", relativePath: "" },
|
|
66
|
+
});
|
|
67
|
+
return entry;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (options.force && isNotFoundPathError(error))
|
|
71
|
+
return undefined;
|
|
72
|
+
throw normalize(error, { operation: "remove", phase: expected ? "remove" : "inspect", relativePath: "" });
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const entry = observe();
|
|
76
|
+
if (!entry)
|
|
77
|
+
return;
|
|
78
|
+
if (!entry.directory && options[nonrecursiveRemovalKind] === "directory") {
|
|
79
|
+
throw new FsSafeError("path-mismatch", "store entry is no longer a directory");
|
|
80
|
+
}
|
|
81
|
+
if (options.assertBeforeMutation) {
|
|
82
|
+
options.assertBeforeMutation();
|
|
83
|
+
if (!observe(entry))
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
binding.rootRemovalUnlink(parent.fd, name, entry.dev, entry.ino, entry.directory);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (!(options.force && isNotFoundPathError(error)))
|
|
91
|
+
throw normalize(error, { operation: "remove", phase: "remove", relativePath: "" });
|
|
92
|
+
}
|
|
93
|
+
boundary.assertAfterMutation();
|
|
94
|
+
assertNotAborted();
|
|
95
|
+
}
|
|
31
96
|
export async function removePathInRootNative(root, target, options, receipts) {
|
|
32
|
-
const binding = getNativeBinding();
|
|
97
|
+
const binding = getNativeBinding("openBeneath", "rootRemovalStat", "rootRemovalUnlink");
|
|
33
98
|
if (!binding?.rootRemovalStat || !binding.rootRemovalUnlink) {
|
|
34
99
|
unavailable();
|
|
35
100
|
}
|
|
@@ -39,9 +104,22 @@ export async function removePathInRootNative(root, target, options, receipts) {
|
|
|
39
104
|
const boundary = await captureNonrecursiveRemovalAdmission(root, target, options, receipts);
|
|
40
105
|
if (!boundary)
|
|
41
106
|
return;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
107
|
+
if (options.recursive && options.maxEntries === 0) {
|
|
108
|
+
options.signal?.throwIfAborted();
|
|
109
|
+
boundary.assertCurrent();
|
|
110
|
+
throw new FsSafeError("too-large", "recursive removal budget exceeded", {
|
|
111
|
+
details: { operation: "remove", phase: "inspect", relativePath: "" },
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
let rootAdmission;
|
|
115
|
+
try {
|
|
116
|
+
rootAdmission = openExactNativeRootAdmissionSync(binding, {
|
|
117
|
+
rootPath: root.rootReal, rootIdentity: root.rootIdentity, operation: "remove", reportCloseErrors: true,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw normalizeRemoveGuardError(error);
|
|
122
|
+
}
|
|
45
123
|
let parent;
|
|
46
124
|
let initialEntry;
|
|
47
125
|
let initialDirectory;
|
|
@@ -53,7 +131,7 @@ export async function removePathInRootNative(root, target, options, receipts) {
|
|
|
53
131
|
if (!isPathInside(root.rootReal, parentPath))
|
|
54
132
|
throw new FsSafeError("outside-workspace", "removal parent is outside root");
|
|
55
133
|
try {
|
|
56
|
-
parent = await openNativeParentAdmission(binding, rootAdmission, path.relative(root.rootReal, parentPath).split(path.sep).join("/"));
|
|
134
|
+
parent = parentPath === root.rootReal ? borrowNativeRootParent(rootAdmission) : await openNativeParentAdmission(binding, rootAdmission, path.relative(root.rootReal, parentPath).split(path.sep).join("/"), "native-directory");
|
|
57
135
|
}
|
|
58
136
|
catch (error) {
|
|
59
137
|
assertRootIdentityCurrentSync(root);
|
|
@@ -95,7 +173,13 @@ export async function removePathInRootNative(root, target, options, receipts) {
|
|
|
95
173
|
}
|
|
96
174
|
}
|
|
97
175
|
}
|
|
98
|
-
if (!options.recursive
|
|
176
|
+
if (!options.recursive)
|
|
177
|
+
await removeNativeLeaf(binding, parent, target, options, boundary,
|
|
178
|
+
// The borrowed Root guard is the complete parent fence. Without an
|
|
179
|
+
// intervening callback or await, the first leaf sample shares its phase.
|
|
180
|
+
parentPath === root.rootReal && !options.signal && !options.denyMutations &&
|
|
181
|
+
!options.assertBeforeMutation && !getFsSafeTestHooks()?.beforeRootFallbackMutation);
|
|
182
|
+
else if (initialEntry)
|
|
99
183
|
await removeEntries(parent);
|
|
100
184
|
}
|
|
101
185
|
}
|
|
@@ -159,7 +243,7 @@ export async function removePathInRootNative(root, target, options, receipts) {
|
|
|
159
243
|
function assertTraversalCurrent() {
|
|
160
244
|
for (const guard of guards) {
|
|
161
245
|
try {
|
|
162
|
-
|
|
246
|
+
assertRemovalDirectoryCurrent(guard);
|
|
163
247
|
}
|
|
164
248
|
catch (cause) {
|
|
165
249
|
throw new FsSafeError("path-mismatch", "removal ancestor changed", { cause });
|
|
@@ -196,8 +280,6 @@ export async function removePathInRootNative(root, target, options, receipts) {
|
|
|
196
280
|
}
|
|
197
281
|
if (!counted)
|
|
198
282
|
examined++;
|
|
199
|
-
if (!options.recursive)
|
|
200
|
-
await beforeMutation(entryPath);
|
|
201
283
|
await assertMutationNotDenied(entryPath, options.denyMutations, { protectAncestors: true });
|
|
202
284
|
const initial = observe(fd, name, entryPath, depth === 0 ? initialEntry : undefined);
|
|
203
285
|
if (!initial)
|
|
@@ -234,7 +316,7 @@ export async function removePathInRootNative(root, target, options, receipts) {
|
|
|
234
316
|
throw normalize(error, details(entryPath, "enumerate"));
|
|
235
317
|
}
|
|
236
318
|
};
|
|
237
|
-
guards.push(
|
|
319
|
+
guards.push(createRemovalDirectoryAssertion(entryPath, stat, entryPath));
|
|
238
320
|
try {
|
|
239
321
|
assertCurrent();
|
|
240
322
|
if (options.order === "sorted") {
|
|
@@ -299,10 +381,7 @@ export async function removePathInRootNative(root, target, options, receipts) {
|
|
|
299
381
|
if (!(options.force && isNotFoundPathError(error)))
|
|
300
382
|
throw normalize(error, details(entryPath, "remove"));
|
|
301
383
|
}
|
|
302
|
-
|
|
303
|
-
boundary.assertCurrent();
|
|
304
|
-
else
|
|
305
|
-
boundary.assertAfterMutation();
|
|
384
|
+
boundary.assertCurrent();
|
|
306
385
|
assertTraversalCurrent();
|
|
307
386
|
assertNotAborted();
|
|
308
387
|
}
|