@openclaw/fs-safe 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/dist/file-store-sync-directory.d.ts.map +1 -1
- package/dist/file-store-sync-directory.js +14 -7
- package/dist/guest-dispatch-python.js +1 -1
- package/dist/native-binding.d.ts +6 -0
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +195 -161
- package/dist/native-policy-directory-observation.d.ts +12 -0
- package/dist/native-policy-directory-observation.d.ts.map +1 -0
- package/dist/native-policy-directory-observation.js +61 -0
- package/dist/pinned-mutation-admission.d.ts.map +1 -1
- package/dist/pinned-mutation-admission.js +13 -24
- package/dist/pinned-mutation-observation.d.ts +7 -1
- package/dist/pinned-mutation-observation.d.ts.map +1 -1
- package/dist/pinned-mutation-observation.js +87 -5
- package/dist/root-directory-creation.d.ts.map +1 -1
- package/dist/root-directory-creation.js +5 -4
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +2 -1
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +1 -2
- package/dist/root-write-compatibility.d.ts +1 -2
- package/dist/root-write-compatibility.d.ts.map +1 -1
- package/dist/root-write-compatibility.js +17 -68
- package/dist/root-write-complete-parent.d.ts.map +1 -1
- package/dist/root-write-complete-parent.js +3 -1
- package/dist/root-write-lock-binding.d.ts +15 -0
- package/dist/root-write-lock-binding.d.ts.map +1 -0
- package/dist/root-write-lock-binding.js +162 -0
- package/dist/staged-directory.d.ts +5 -2
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/staged-directory.js +37 -1
- package/dist/temp-workspace-admission.d.ts.map +1 -1
- package/dist/temp-workspace-admission.js +28 -4
- package/docs/guest.md +1 -1
- package/docs/native.md +8 -0
- package/docs/writing.md +6 -0
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.14.0 - 2026-09-17
|
|
4
|
+
|
|
5
|
+
### Highlights
|
|
6
|
+
|
|
7
|
+
- **Safer guest directory selection:** descriptor-relative listings now report regular files as well as directories without following symlinks, so consumers can select files without reopening path-type checks.
|
|
8
|
+
|
|
9
|
+
### Filesystem boundaries and performance
|
|
10
|
+
|
|
11
|
+
- Report both directory and regular-file kinds from descriptor-relative guest listings. Symlinks and special entries report neither kind.
|
|
12
|
+
- Reduce repeated filesystem observations during policy-bound native parent creation, Windows compatibility writes and metadata reads, synchronous store-directory permission repair, and missing temporary-root creation. Fresh identity, canonical-path, lock-destination, callback, and publication checks remain at mutation boundaries.
|
|
13
|
+
|
|
14
|
+
### Validation
|
|
15
|
+
|
|
16
|
+
- Register the path-prefix and synchronous `lockRoot` performance workflows on the default branch. Their dispatch stubs fail closed without checking out or executing repository code.
|
|
4
17
|
|
|
5
18
|
## 0.13.1 - 2026-09-16
|
|
6
19
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-store-sync-directory.d.ts","sourceRoot":"","sources":["../src/file-store-sync-directory.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAc/C,KAAK,kBAAkB,GAAG,eAAe,GAAG,OAAO,CAAC;AAOpD,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"file-store-sync-directory.d.ts","sourceRoot":"","sources":["../src/file-store-sync-directory.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAc/C,KAAK,kBAAkB,GAAG,eAAe,GAAG,OAAO,CAAC;AAOpD,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC,CAAC;AA0VH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,kBAAkB,CAAC;CACnC,GAAG,yBAAyB,CA4D5B;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAsBN"}
|
|
@@ -11,7 +11,9 @@ function changedStoreDirectory(messagePrefix, cause) {
|
|
|
11
11
|
return new FsSafeError("outside-workspace", `${messagePrefix} directory escapes root`, { cause });
|
|
12
12
|
}
|
|
13
13
|
function storeDirectoryRealPath(dir) {
|
|
14
|
-
const
|
|
14
|
+
const operationPath = pathForWindowsFilesystem(dir);
|
|
15
|
+
const realPath = process.platform === "win32"
|
|
16
|
+
? realpathSync(operationPath) : realpathSync.native(operationPath);
|
|
15
17
|
assertNoWindowsPathAlias(realPath, "filesystem");
|
|
16
18
|
return realPath;
|
|
17
19
|
}
|
|
@@ -72,7 +74,9 @@ function assertAdmittedEdgeCurrent(receipts, rootReal, messagePrefix) {
|
|
|
72
74
|
if (!rootReceipt || !targetReceipt) {
|
|
73
75
|
throw new FsSafeError("helper-failed", "store directory receipt is missing");
|
|
74
76
|
}
|
|
75
|
-
const rootStat =
|
|
77
|
+
const rootStat = rootReal === undefined
|
|
78
|
+
? inspectReceiptCurrent(rootReceipt, messagePrefix, true)
|
|
79
|
+
: assertRootCurrent(rootReceipt, rootReal, messagePrefix);
|
|
76
80
|
if (targetIndex === 0)
|
|
77
81
|
return rootStat;
|
|
78
82
|
const parent = receipts[targetIndex - 1];
|
|
@@ -87,10 +91,13 @@ function assertAdmittedEdgeCurrent(receipts, rootReal, messagePrefix) {
|
|
|
87
91
|
return targetStat;
|
|
88
92
|
}
|
|
89
93
|
function assertModeTargetCurrent(receipts, rootReal, messagePrefix) {
|
|
94
|
+
const root = receipts[0];
|
|
90
95
|
const target = receipts.at(-1);
|
|
91
|
-
if (!target)
|
|
96
|
+
if (!root || !target)
|
|
92
97
|
throw new FsSafeError("helper-failed", "store directory receipt is missing");
|
|
93
|
-
|
|
98
|
+
// The target's canonical observation shares the exact identity fence. Keep
|
|
99
|
+
// the trailing root canonical check: an ancestor relocation can retain IDs.
|
|
100
|
+
assertAdmittedEdgeCurrent(receipts, undefined, messagePrefix);
|
|
94
101
|
let targetReal;
|
|
95
102
|
try {
|
|
96
103
|
targetReal = storeDirectoryRealPath(target.dir);
|
|
@@ -98,10 +105,10 @@ function assertModeTargetCurrent(receipts, rootReal, messagePrefix) {
|
|
|
98
105
|
catch (error) {
|
|
99
106
|
throw changedStoreDirectory(messagePrefix, error);
|
|
100
107
|
}
|
|
101
|
-
if (!isPathInside(rootReal, targetReal))
|
|
108
|
+
if (target === root ? targetReal !== rootReal : !isPathInside(rootReal, targetReal)) {
|
|
102
109
|
throw changedStoreDirectory(messagePrefix);
|
|
103
|
-
|
|
104
|
-
return
|
|
110
|
+
}
|
|
111
|
+
return assertAdmittedEdgeCurrent(receipts, rootReal, messagePrefix);
|
|
105
112
|
}
|
|
106
113
|
function assertReceiptChain(receipts, rootReal, messagePrefix) {
|
|
107
114
|
const rootReceipt = receipts[0];
|
|
@@ -59,7 +59,7 @@ export const GUEST_FILESYSTEM_DISPATCH_PYTHON = [
|
|
|
59
59
|
" try:",
|
|
60
60
|
" target_fd = walk_dir(root_fd, sys.argv[3], False)",
|
|
61
61
|
" with os.scandir(target_fd) as entries:",
|
|
62
|
-
" print(json.dumps([{'name': entry.name, 'isDirectory': entry.is_dir(follow_symlinks=False)} for entry in entries]))",
|
|
62
|
+
" print(json.dumps([{'name': entry.name, 'isDirectory': entry.is_dir(follow_symlinks=False), 'isFile': entry.is_file(follow_symlinks=False)} for entry in entries]))",
|
|
63
63
|
" finally:",
|
|
64
64
|
" if target_fd is not None:",
|
|
65
65
|
" os.close(target_fd)",
|
package/dist/native-binding.d.ts
CHANGED
|
@@ -20,6 +20,10 @@ export interface NativeDirectoryObservation {
|
|
|
20
20
|
ino: bigint;
|
|
21
21
|
realPath: string;
|
|
22
22
|
}
|
|
23
|
+
export interface NativeDirectoryFdObservation extends NativeDirectoryObservation {
|
|
24
|
+
mode: bigint;
|
|
25
|
+
nlink: bigint;
|
|
26
|
+
}
|
|
23
27
|
export interface NativeArchiveEntry {
|
|
24
28
|
index: number;
|
|
25
29
|
path: string;
|
|
@@ -100,6 +104,8 @@ export interface NativeBinding {
|
|
|
100
104
|
};
|
|
101
105
|
/** Internal: exact directory identity and canonical path from one no-follow handle. */
|
|
102
106
|
observeDirectory?(path: string): NativeDirectoryObservation;
|
|
107
|
+
/** Internal POSIX-only exact name/descriptor observation; the caller retains its fd. */
|
|
108
|
+
observeDirectoryFd?(fd: number, expectedPath: string): NativeDirectoryFdObservation;
|
|
103
109
|
/** Linux/Windows byte transfer; callers retain both admitted descriptors until settlement. */
|
|
104
110
|
copyFileContents?(sourceFd: number, targetFd: number, signal?: AbortSignal): Promise<void>;
|
|
105
111
|
/** Internal: same private, immutable input ownership as the ZIP buffer reader. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,4BAA6B,SAAQ,0BAA0B;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;CAAG;AAErE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,GAAG,iBAAiB,GAAG,MAAM,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,eAAe,GAAG,aAAa,CAAC;CAC9C;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,+BAA+B;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,EAAE,OAAO,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,kBAAkB,EAAE,OAAO,CAAC;QAC5B,WAAW,EAAE,OAAO,CAAC;QACrB,SAAS,EAAE,OAAO,CAAC;QACnB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,IAAI,EAAE,+BAA+B,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,oCAAoC;IACnD,8FAA8F;IAC9F,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,0BAA0B,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,8EAA8E;IAC9E,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,oBAAoB,CAAC;IACpD,wFAAwF;IACxF,gBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,uFAAuF;IACvF,gBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,0BAA0B,CAAC;IAC5D,wFAAwF;IACxF,kBAAkB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,4BAA4B,CAAC;IACpF,8FAA8F;IAC9F,gBAAgB,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3F,kFAAkF;IAClF,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QACvG,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC;QACvC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACnF,CAAC,CAAC;IACH,4FAA4F;IAC5F,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QACzF,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC;QACvC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACnF,CAAC,CAAC;IACH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;IACnE,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC;IACnF,SAAS,CACP,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,gBAAgB,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9D,iBAAiB,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAChF,gBAAgB,CAAC,CACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAC3C,iBAAiB,CAAC,CAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1F,sBAAsB,CACpB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC7B,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,oBAAoB,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,sBAAsB,EAAE,EAC9B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAC9C,oBAAoB,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACjC,WAAW,CACT,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,IAAI,CAAC;IACR,oFAAoF;IACpF,iBAAiB,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9E,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAClE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,CAAC;IACrF,sBAAsB,CACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,0BAA0B,CAAC;IAC3D,8EAA8E;IAC9E,8BAA8B,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,oCAAoC,CAAC;IAClF,yBAAyB,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACtD,eAAe,CAAC,CACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,4BAA4B,CAAC,CAAC;IACzC,mBAAmB,CAAC,CAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,4BAA4B,CAAC;IAChC,eAAe,CACb,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,IAAI,CAAC;IACR,aAAa,CACX,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,IAAI,CAAC;IACR,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC1F;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAMjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-pinned-write.d.ts","sourceRoot":"","sources":["../src/native-pinned-write.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"native-pinned-write.d.ts","sourceRoot":"","sources":["../src/native-pinned-write.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAIV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AA8W3B,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAsGvH"}
|
|
@@ -58,6 +58,7 @@ import { runPinnedWriteWindows } from "./native-pinned-write-windows.js";
|
|
|
58
58
|
import { openNativeParentAdmission, openNativeRootAdmission } from "./native-parent-admission.js";
|
|
59
59
|
import { assertNativeStaging, writeNativeStage } from "./native-staged-file.js";
|
|
60
60
|
import { captureNativeFdClose } from "./native-binding.js";
|
|
61
|
+
import { NativePolicyDirectoryMismatch } from "./native-policy-directory-observation.js";
|
|
61
62
|
import { assertPolicyStagedDirectoryCurrent, assertStagedDirectoryCurrent, describePolicyStagedDirectory, describeStagedDirectory, refreshPolicyStagedDirectoryObservation, } from "./staged-directory.js";
|
|
62
63
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
63
64
|
import { realpathSync } from "./realpath.js";
|
|
@@ -118,8 +119,8 @@ async function describePosixParent(parentFd, pathname) {
|
|
|
118
119
|
observation: checkedMutationDirectory(parentPath, directory.realPath, parentPathStat),
|
|
119
120
|
};
|
|
120
121
|
}
|
|
121
|
-
function describePolicyPosixParent(parentFd, pathname) {
|
|
122
|
-
const policyDirectory = describePolicyStagedDirectory(parentFd, pathname);
|
|
122
|
+
function describePolicyPosixParent(binding, parentFd, pathname) {
|
|
123
|
+
const policyDirectory = describePolicyStagedDirectory(parentFd, pathname, binding);
|
|
123
124
|
return {
|
|
124
125
|
parentFd,
|
|
125
126
|
parentPath: policyDirectory.directory.realPath,
|
|
@@ -131,11 +132,12 @@ function describePolicyPosixParent(parentFd, pathname) {
|
|
|
131
132
|
}
|
|
132
133
|
function policyParentCaptureDeopt(error) {
|
|
133
134
|
return error instanceof FsSafeError &&
|
|
135
|
+
!(error instanceof NativePolicyDirectoryMismatch) &&
|
|
134
136
|
(error.code === "path-mismatch" || error.code === "not-file");
|
|
135
137
|
}
|
|
136
|
-
function tryDescribePolicyPosixParent(parentFd, pathname) {
|
|
138
|
+
function tryDescribePolicyPosixParent(binding, parentFd, pathname) {
|
|
137
139
|
try {
|
|
138
|
-
return describePolicyPosixParent(parentFd, pathname);
|
|
140
|
+
return describePolicyPosixParent(binding, parentFd, pathname);
|
|
139
141
|
}
|
|
140
142
|
catch (error) {
|
|
141
143
|
if (!policyParentCaptureDeopt(error))
|
|
@@ -149,183 +151,215 @@ function assertPosixParentCurrent(parent) {
|
|
|
149
151
|
: assertStagedDirectoryCurrent(parent.directory);
|
|
150
152
|
}
|
|
151
153
|
async function capturePolicyAwarePosixParent(binding, params, rootFd, directoryFlags) {
|
|
152
|
-
const
|
|
153
|
-
const segments = relativeParentSegments(params.relativeParentPath);
|
|
154
|
-
const parentSpelling = segments.length
|
|
155
|
-
? path.join(params.rootPath, ...segments)
|
|
156
|
-
: params.rootPath;
|
|
157
|
-
const segmentRoute = createPathSegmentRoute(segments);
|
|
158
|
-
const initialTarget = prospectiveTargetPath(params.rootPath, segmentRoute, 0, params.basename);
|
|
159
|
-
let retainedTargetPath = params.mutationAdmission?.beginParentWalk?.();
|
|
160
|
-
if (retainedTargetPath && !sameAbsolutePath(retainedTargetPath, initialTarget)) {
|
|
161
|
-
retainedTargetPath = undefined;
|
|
162
|
-
}
|
|
163
|
-
// Preserve the one-open hot path when the complete parent still exists.
|
|
164
|
-
// Policy is attached only after the opened descriptor is associated with its
|
|
165
|
-
// current canonical pathname, so a contained redirect cannot retain the old
|
|
166
|
-
// preflight authorization.
|
|
167
|
-
let completeParentFd;
|
|
154
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
168
155
|
try {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const
|
|
156
|
+
const closeFd = captureNativeFdClose(binding);
|
|
157
|
+
const observationDisposers = new Map();
|
|
158
|
+
const disposeObservation = (fd) => {
|
|
159
|
+
const dispose = observationDisposers.get(fd);
|
|
160
|
+
observationDisposers.delete(fd);
|
|
161
|
+
dispose?.();
|
|
162
|
+
};
|
|
163
|
+
const observationScope = __addDisposableResource(env_1, {
|
|
164
|
+
[Symbol.dispose]() { for (const dispose of observationDisposers.values())
|
|
165
|
+
dispose(); },
|
|
166
|
+
}, false);
|
|
167
|
+
const capturePolicyParent = (fd, pathname) => {
|
|
168
|
+
const captured = tryDescribePolicyPosixParent(binding, fd, pathname);
|
|
169
|
+
const dispose = captured?.policyDirectory?.disposeObservation;
|
|
170
|
+
if (dispose)
|
|
171
|
+
observationDisposers.set(fd, dispose);
|
|
172
|
+
return captured;
|
|
173
|
+
};
|
|
174
|
+
const segments = relativeParentSegments(params.relativeParentPath);
|
|
175
|
+
const parentSpelling = segments.length
|
|
176
|
+
? path.join(params.rootPath, ...segments)
|
|
177
|
+
: params.rootPath;
|
|
178
|
+
const segmentRoute = createPathSegmentRoute(segments);
|
|
179
|
+
const initialTarget = prospectiveTargetPath(params.rootPath, segmentRoute, 0, params.basename);
|
|
180
|
+
let retainedTargetPath = params.mutationAdmission?.beginParentWalk?.();
|
|
181
|
+
if (retainedTargetPath && !sameAbsolutePath(retainedTargetPath, initialTarget)) {
|
|
182
|
+
retainedTargetPath = undefined;
|
|
183
|
+
}
|
|
184
|
+
// Preserve the one-open hot path when the complete parent still exists.
|
|
185
|
+
// Policy is attached only after the opened descriptor is associated with its
|
|
186
|
+
// current canonical pathname, so a contained redirect cannot retain the old
|
|
187
|
+
// preflight authorization.
|
|
188
|
+
let completeParentFd;
|
|
177
189
|
try {
|
|
178
|
-
|
|
179
|
-
? tryDescribePolicyPosixParent(parentFd, parentSpelling)
|
|
180
|
-
: undefined;
|
|
181
|
-
if (!admitted) {
|
|
182
|
-
retainedTargetPath = undefined;
|
|
183
|
-
admitted = await describePosixParent(parentFd, parentSpelling);
|
|
184
|
-
}
|
|
185
|
-
const targetPath = path.join(admitted.parentPath, params.basename);
|
|
186
|
-
await authorizePinnedMutation(params, {
|
|
187
|
-
targetPath,
|
|
188
|
-
mutationPath: targetPath,
|
|
189
|
-
phase: "parent",
|
|
190
|
-
});
|
|
191
|
-
assertPosixParentCurrent(admitted);
|
|
192
|
-
return admitted;
|
|
190
|
+
completeParentFd = binding.openBeneath(rootFd, params.relativeParentPath, directoryFlags).fd;
|
|
193
191
|
}
|
|
194
192
|
catch (error) {
|
|
195
|
-
|
|
196
|
-
|
|
193
|
+
if (error?.code !== "ENOENT" || !params.mkdir)
|
|
194
|
+
throw error;
|
|
197
195
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// existing prefix. Walk missing-parent cases one direct child at a time so
|
|
201
|
-
// every existing/opened object is authorized and every mkdir is authorized
|
|
202
|
-
// before dispatch. O_NOFOLLOW makes a concurrently introduced link fail
|
|
203
|
-
// before the next component can be created through it.
|
|
204
|
-
const secureDirectoryFlags = directoryFlags | (fsSync.constants.O_NOFOLLOW ?? 0);
|
|
205
|
-
let currentFd = rootFd;
|
|
206
|
-
let currentOwnedFd;
|
|
207
|
-
let currentPath = params.rootPath;
|
|
208
|
-
let current = retainedTargetPath
|
|
209
|
-
? tryDescribePolicyPosixParent(rootFd, currentPath)
|
|
210
|
-
: undefined;
|
|
211
|
-
if (!current) {
|
|
212
|
-
retainedTargetPath = undefined;
|
|
213
|
-
current = await describePosixParent(rootFd, currentPath);
|
|
214
|
-
}
|
|
215
|
-
try {
|
|
216
|
-
await authorizePinnedMutation(params, {
|
|
217
|
-
targetPath: retainedTargetPath ?? initialTarget,
|
|
218
|
-
mutationPath: retainedTargetPath ?? initialTarget,
|
|
219
|
-
phase: "parent",
|
|
220
|
-
});
|
|
221
|
-
assertPosixParentCurrent(current);
|
|
222
|
-
for (let index = 0; index < segments.length; index += 1) {
|
|
223
|
-
const segment = segments[index];
|
|
224
|
-
const childPath = path.join(currentPath, segment);
|
|
225
|
-
let childFd;
|
|
226
|
-
let createdByMkdir = false;
|
|
227
|
-
let createReceipt;
|
|
196
|
+
if (completeParentFd !== undefined) {
|
|
197
|
+
const parentFd = completeParentFd;
|
|
228
198
|
try {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (!
|
|
233
|
-
|
|
199
|
+
let admitted = retainedTargetPath
|
|
200
|
+
? capturePolicyParent(parentFd, parentSpelling)
|
|
201
|
+
: undefined;
|
|
202
|
+
if (!admitted) {
|
|
203
|
+
retainedTargetPath = undefined;
|
|
204
|
+
admitted = await describePosixParent(parentFd, parentSpelling);
|
|
234
205
|
}
|
|
235
|
-
const targetPath =
|
|
236
|
-
|
|
206
|
+
const targetPath = path.join(admitted.parentPath, params.basename);
|
|
207
|
+
await authorizePinnedMutation(params, {
|
|
237
208
|
targetPath,
|
|
238
|
-
mutationPath:
|
|
239
|
-
phase: "parent
|
|
209
|
+
mutationPath: targetPath,
|
|
210
|
+
phase: "parent",
|
|
240
211
|
});
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
212
|
+
assertPosixParentCurrent(admitted);
|
|
213
|
+
return admitted;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
disposeObservation(parentFd);
|
|
217
|
+
closeFd(parentFd);
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// The canonical preflight spelling has no intentional symlinks in its
|
|
222
|
+
// existing prefix. Walk missing-parent cases one direct child at a time so
|
|
223
|
+
// every existing/opened object is authorized and every mkdir is authorized
|
|
224
|
+
// before dispatch. O_NOFOLLOW makes a concurrently introduced link fail
|
|
225
|
+
// before the next component can be created through it.
|
|
226
|
+
const secureDirectoryFlags = directoryFlags | (fsSync.constants.O_NOFOLLOW ?? 0);
|
|
227
|
+
let currentFd = rootFd;
|
|
228
|
+
let currentOwnedFd;
|
|
229
|
+
let currentPath = params.rootPath;
|
|
230
|
+
let current = retainedTargetPath
|
|
231
|
+
? capturePolicyParent(rootFd, currentPath)
|
|
232
|
+
: undefined;
|
|
233
|
+
if (!current) {
|
|
234
|
+
retainedTargetPath = undefined;
|
|
235
|
+
current = await describePosixParent(rootFd, currentPath);
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
await authorizePinnedMutation(params, {
|
|
239
|
+
targetPath: retainedTargetPath ?? initialTarget,
|
|
240
|
+
mutationPath: retainedTargetPath ?? initialTarget,
|
|
241
|
+
phase: "parent",
|
|
242
|
+
});
|
|
243
|
+
assertPosixParentCurrent(current);
|
|
244
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
245
|
+
const segment = segments[index];
|
|
246
|
+
const childPath = path.join(currentPath, segment);
|
|
247
|
+
let childFd;
|
|
248
|
+
let createdByMkdir = false;
|
|
249
|
+
let createReceipt;
|
|
250
250
|
try {
|
|
251
251
|
childFd = binding.openBeneath(currentFd, segment, secureDirectoryFlags).fd;
|
|
252
252
|
}
|
|
253
|
-
catch (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (createdByMkdir && createReceipt && params.mutationAdmission?.advanceCreatedDirectory) {
|
|
273
|
-
let evidence;
|
|
253
|
+
catch (openError) {
|
|
254
|
+
if (!isNotFoundPathError(openError)) {
|
|
255
|
+
throw normalizePolicyParentOpenError(openError, params);
|
|
256
|
+
}
|
|
257
|
+
const targetPath = retainedTargetPath ?? prospectiveTargetPath(currentPath, segmentRoute, index, params.basename);
|
|
258
|
+
const request = Object.freeze({
|
|
259
|
+
targetPath,
|
|
260
|
+
mutationPath: childPath,
|
|
261
|
+
phase: "parent-create",
|
|
262
|
+
});
|
|
263
|
+
createReceipt = params.mutationAdmission?.tryAuthorizeAtParent?.(request, current.observation);
|
|
264
|
+
if (!createReceipt) {
|
|
265
|
+
createReceipt = await authorizePinnedMutation(params, request);
|
|
266
|
+
assertPosixParentCurrent(current);
|
|
267
|
+
}
|
|
268
|
+
params.assertBeforeMutation?.();
|
|
269
|
+
// Do not carry pathname freshness across the live authority callback.
|
|
270
|
+
assertPosixParentCurrent(current);
|
|
271
|
+
createdByMkdir = mkdirPolicyChild(binding, currentFd, segment, 0o777);
|
|
274
272
|
try {
|
|
275
|
-
|
|
276
|
-
? refreshPolicyStagedDirectoryObservation(current.policyDirectory)
|
|
277
|
-
: checkedMutationDirectory(currentPath, current.directory.realPath, assertStagedDirectoryCurrent(current.directory));
|
|
278
|
-
evidence = Object.freeze({
|
|
279
|
-
admission: createReceipt,
|
|
280
|
-
parent,
|
|
281
|
-
child: child.observation,
|
|
282
|
-
});
|
|
273
|
+
childFd = binding.openBeneath(currentFd, segment, secureDirectoryFlags).fd;
|
|
283
274
|
}
|
|
284
|
-
catch {
|
|
285
|
-
|
|
275
|
+
catch (createdOpenError) {
|
|
276
|
+
throw normalizePolicyParentOpenError(createdOpenError, params);
|
|
286
277
|
}
|
|
287
|
-
|
|
288
|
-
|
|
278
|
+
}
|
|
279
|
+
let child;
|
|
280
|
+
try {
|
|
281
|
+
const acceleratedChild = retainedTargetPath
|
|
282
|
+
? capturePolicyParent(childFd, childPath)
|
|
283
|
+
: undefined;
|
|
284
|
+
if (acceleratedChild) {
|
|
285
|
+
child = acceleratedChild;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
retainedTargetPath = undefined;
|
|
289
|
+
child = await describePosixParent(childFd, childPath);
|
|
290
|
+
}
|
|
291
|
+
if (!sameAbsolutePath(child.parentPath, childPath))
|
|
292
|
+
retainedTargetPath = undefined;
|
|
293
|
+
let childAuthorization;
|
|
294
|
+
if (createdByMkdir && createReceipt && params.mutationAdmission?.advanceCreatedDirectory) {
|
|
295
|
+
let evidence;
|
|
296
|
+
try {
|
|
297
|
+
const parent = current.policyDirectory
|
|
298
|
+
? refreshPolicyStagedDirectoryObservation(current.policyDirectory)
|
|
299
|
+
: checkedMutationDirectory(currentPath, current.directory.realPath, assertStagedDirectoryCurrent(current.directory));
|
|
300
|
+
evidence = Object.freeze({
|
|
301
|
+
admission: createReceipt,
|
|
302
|
+
parent,
|
|
303
|
+
child: child.observation,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
// Leave failed evidence to the full ordered admission below.
|
|
308
|
+
}
|
|
309
|
+
if (evidence) {
|
|
310
|
+
childAuthorization = params.mutationAdmission.advanceCreatedDirectory(evidence);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const targetPath = retainedTargetPath ?? prospectiveTargetPath(child.parentPath, segmentRoute, index + 1, params.basename);
|
|
314
|
+
const request = Object.freeze({
|
|
315
|
+
targetPath,
|
|
316
|
+
mutationPath: targetPath,
|
|
317
|
+
phase: "parent",
|
|
318
|
+
});
|
|
319
|
+
childAuthorization ??= params.mutationAdmission?.tryAuthorizeAtParent?.(request, child.observation);
|
|
320
|
+
if (!childAuthorization) {
|
|
321
|
+
await authorizePinnedMutation(params, request);
|
|
322
|
+
assertPosixParentCurrent(child);
|
|
289
323
|
}
|
|
290
324
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
325
|
+
catch (error) {
|
|
326
|
+
disposeObservation(childFd);
|
|
327
|
+
closeFd(childFd);
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
const previousOwnedFd = currentOwnedFd;
|
|
331
|
+
disposeObservation(current.parentFd);
|
|
332
|
+
currentOwnedFd = child.parentFd;
|
|
333
|
+
currentFd = child.parentFd;
|
|
334
|
+
currentPath = child.parentPath;
|
|
335
|
+
current = child;
|
|
336
|
+
if (previousOwnedFd !== undefined)
|
|
337
|
+
closeFd(previousOwnedFd);
|
|
338
|
+
if (index === segments.length - 1) {
|
|
339
|
+
currentOwnedFd = undefined;
|
|
340
|
+
return child;
|
|
301
341
|
}
|
|
302
342
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
currentPath = child.parentPath;
|
|
311
|
-
current = child;
|
|
312
|
-
if (previousOwnedFd !== undefined)
|
|
313
|
-
closeFd(previousOwnedFd);
|
|
314
|
-
if (index === segments.length - 1) {
|
|
315
|
-
currentOwnedFd = undefined;
|
|
316
|
-
return child;
|
|
343
|
+
// Empty relative parents are handled by the complete-parent fast path.
|
|
344
|
+
throw new FsSafeError("path-mismatch", "native write parent admission did not complete");
|
|
345
|
+
}
|
|
346
|
+
finally {
|
|
347
|
+
if (currentOwnedFd !== undefined) {
|
|
348
|
+
disposeObservation(currentOwnedFd);
|
|
349
|
+
closeFd(currentOwnedFd);
|
|
317
350
|
}
|
|
318
351
|
}
|
|
319
|
-
|
|
320
|
-
|
|
352
|
+
}
|
|
353
|
+
catch (e_1) {
|
|
354
|
+
env_1.error = e_1;
|
|
355
|
+
env_1.hasError = true;
|
|
321
356
|
}
|
|
322
357
|
finally {
|
|
323
|
-
|
|
324
|
-
closeFd(currentOwnedFd);
|
|
358
|
+
__disposeResources(env_1);
|
|
325
359
|
}
|
|
326
360
|
}
|
|
327
361
|
export async function runPinnedWriteNative(binding, params) {
|
|
328
|
-
const
|
|
362
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
329
363
|
try {
|
|
330
364
|
const closeFd = captureNativeFdClose(binding);
|
|
331
365
|
const windows = process.platform === "win32";
|
|
@@ -339,12 +373,12 @@ export async function runPinnedWriteNative(binding, params) {
|
|
|
339
373
|
operation: "native write",
|
|
340
374
|
});
|
|
341
375
|
const root = rootAdmission.root;
|
|
342
|
-
const posixRoot = __addDisposableResource(
|
|
376
|
+
const posixRoot = __addDisposableResource(env_2, windows ? undefined : root, true);
|
|
343
377
|
let parentFd;
|
|
344
378
|
let windowsOwnsDirectories = false;
|
|
345
379
|
// Until stage construction takes ownership, even admission failures must close
|
|
346
380
|
// the raw POSIX parent. Disposal preserves both admission and close failures.
|
|
347
|
-
const parentGuard = __addDisposableResource(
|
|
381
|
+
const parentGuard = __addDisposableResource(env_2, {
|
|
348
382
|
[Symbol.dispose]() {
|
|
349
383
|
if (!windows && parentFd !== undefined) {
|
|
350
384
|
closeFd(parentFd);
|
|
@@ -423,12 +457,12 @@ export async function runPinnedWriteNative(binding, params) {
|
|
|
423
457
|
}
|
|
424
458
|
}
|
|
425
459
|
}
|
|
426
|
-
catch (
|
|
427
|
-
|
|
428
|
-
|
|
460
|
+
catch (e_2) {
|
|
461
|
+
env_2.error = e_2;
|
|
462
|
+
env_2.hasError = true;
|
|
429
463
|
}
|
|
430
464
|
finally {
|
|
431
|
-
const result_1 = __disposeResources(
|
|
465
|
+
const result_1 = __disposeResources(env_2);
|
|
432
466
|
if (result_1)
|
|
433
467
|
await result_1;
|
|
434
468
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FsSafeError } from "./errors.js";
|
|
2
|
+
import type { NativeBinding } from "./native-binding.js";
|
|
3
|
+
import type { MutationDirectoryObserver } from "./pinned-mutation-observation.js";
|
|
4
|
+
export declare class NativePolicyDirectoryMismatch extends FsSafeError {
|
|
5
|
+
constructor(cause?: Error);
|
|
6
|
+
}
|
|
7
|
+
export type NativePolicyDirectoryObserver = MutationDirectoryObserver & {
|
|
8
|
+
dispose(): void;
|
|
9
|
+
};
|
|
10
|
+
/** Fresh name/metadata/canonical facts from a caller-owned POSIX descriptor. */
|
|
11
|
+
export declare function nativePolicyDirectoryObserver(binding: NativeBinding | undefined, fd: number, pathname: string): NativePolicyDirectoryObserver | undefined;
|
|
12
|
+
//# sourceMappingURL=native-policy-directory-observation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-policy-directory-observation.d.ts","sourceRoot":"","sources":["../src/native-policy-directory-observation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAElF,qBAAa,6BAA8B,SAAQ,WAAW;IAC5D,YAAY,KAAK,CAAC,EAAE,KAAK,EAExB;CACF;AAED,MAAM,MAAM,6BAA6B,GAAG,yBAAyB,GAAG;IAAE,OAAO,IAAI,IAAI,CAAA;CAAE,CAAC;AAE5F,gFAAgF;AAChF,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,GACf,6BAA6B,GAAG,SAAS,CA2C3C"}
|