@openclaw/fs-safe 0.16.0 → 0.17.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 +48 -0
- package/README.md +8 -1
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +2 -8
- package/dist/advanced.d.ts +2 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +2 -0
- package/dist/archive-deadline.d.ts.map +1 -1
- package/dist/archive-deadline.js +22 -23
- package/dist/archive-merge.d.ts +1 -0
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +4 -4
- package/dist/archive-native.d.ts +1 -0
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +1 -0
- package/dist/archive-options.d.ts +2 -0
- package/dist/archive-options.d.ts.map +1 -1
- package/dist/archive-parser.wasm +0 -0
- package/dist/archive-zip-count.d.ts.map +1 -1
- package/dist/archive-zip-count.js +21 -1
- package/dist/archive-zip-directory.d.ts.map +1 -1
- package/dist/archive-zip-directory.js +23 -1
- package/dist/archive-zip-loader.d.ts +2 -0
- package/dist/archive-zip-loader.d.ts.map +1 -1
- package/dist/archive-zip-loader.js +7 -0
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +7 -2
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +9 -3
- package/dist/byte-view.d.ts +3 -0
- package/dist/byte-view.d.ts.map +1 -0
- package/dist/byte-view.js +13 -0
- package/dist/creation-darwin.d.ts +0 -1
- package/dist/creation-darwin.d.ts.map +1 -1
- package/dist/creation-darwin.js +0 -9
- package/dist/directory-durability.d.ts +6 -6
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-receipt.d.ts +2 -2
- package/dist/directory-receipt.d.ts.map +1 -1
- package/dist/directory-receipt.js +15 -19
- package/dist/file-cleanup.d.ts +1 -0
- package/dist/file-cleanup.d.ts.map +1 -1
- package/dist/file-cleanup.js +7 -4
- package/dist/file-contents.d.ts +6 -0
- package/dist/file-contents.d.ts.map +1 -0
- package/dist/file-contents.js +40 -0
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +16 -4
- package/dist/file-lock-sync-root-acquire.d.ts.map +1 -1
- package/dist/file-lock-sync-root-acquire.js +3 -0
- package/dist/file-lock-sync-root-held.d.ts +1 -2
- package/dist/file-lock-sync-root-held.d.ts.map +1 -1
- package/dist/file-lock-sync-root-held.js +7 -5
- package/dist/file-lock-sync-stale-admission.d.ts.map +1 -1
- package/dist/file-lock-sync-stale-admission.js +3 -0
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +8 -11
- package/dist/file-store.js +3 -3
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +6 -27
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +2 -5
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +2 -6
- package/dist/json-durable-queue-paths.d.ts.map +1 -1
- package/dist/json-durable-queue-paths.js +2 -24
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +10 -9
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +32 -75
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +19 -21
- package/dist/move-path-cleanup.d.ts +5 -19
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +57 -21
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +62 -39
- package/dist/native-staged-file.d.ts +2 -1
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +8 -5
- package/dist/native.js +2 -2
- package/dist/opened-realpath.d.ts.map +1 -1
- package/dist/opened-realpath.js +11 -2
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +2 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +3 -17
- package/dist/pinned-write-input.d.ts.map +1 -1
- package/dist/pinned-write-input.js +11 -1
- package/dist/pinned-write-mode.d.ts +3 -3
- package/dist/pinned-write-mode.d.ts.map +1 -1
- package/dist/pinned-write-mode.js +15 -8
- package/dist/pinned-write-staged.d.ts.map +1 -1
- package/dist/pinned-write-staged.js +10 -11
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +17 -13
- package/dist/publish-file.d.ts +2 -2
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +56 -96
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +35 -44
- package/dist/replace-file-copy-fallback.d.ts.map +1 -1
- package/dist/replace-file-copy-fallback.js +28 -26
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +13 -22
- package/dist/replace-file-descriptor.d.ts.map +1 -1
- package/dist/replace-file-descriptor.js +10 -16
- package/dist/replace-file-temp-owner.js +6 -6
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +9 -13
- package/dist/root-directory-list.d.ts.map +1 -1
- package/dist/root-directory-list.js +20 -3
- package/dist/root-file-final-admission.d.ts +1 -1
- package/dist/root-file-final-admission.d.ts.map +1 -1
- package/dist/root-file-final-admission.js +5 -2
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +3 -2
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +50 -20
- package/dist/root-move-noreplace.d.ts +2 -0
- package/dist/root-move-noreplace.d.ts.map +1 -1
- package/dist/root-move-noreplace.js +2 -2
- package/dist/root-read-admission.d.ts.map +1 -1
- package/dist/root-read-admission.js +7 -2
- package/dist/root-remove.d.ts.map +1 -1
- package/dist/root-remove.js +15 -1
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +4 -6
- package/dist/sidecar-lock-handle.d.ts +3 -0
- package/dist/sidecar-lock-handle.d.ts.map +1 -1
- package/dist/sidecar-lock-handle.js +6 -0
- package/dist/sidecar-lock-reclaim.d.ts +1 -1
- package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
- package/dist/sidecar-lock-reclaim.js +11 -8
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +3 -5
- package/dist/staged-directory.d.ts +2 -2
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/strict-file-identity.d.ts +1 -1
- package/dist/strict-file-identity.d.ts.map +1 -1
- package/dist/strict-file-identity.js +9 -9
- package/dist/symlink-parents.d.ts.map +1 -1
- package/dist/symlink-parents.js +2 -27
- package/dist/temp-workspace-owner.js +4 -4
- package/dist/unicode-path.d.ts.map +1 -1
- package/dist/unicode-path.js +3 -0
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +4 -2
- package/dist/write-file-handle.d.ts +7 -0
- package/dist/write-file-handle.d.ts.map +1 -1
- package/dist/write-file-handle.js +23 -0
- package/dist/write-open-flags.d.ts.map +1 -1
- package/dist/write-open-flags.js +1 -8
- package/dist/write-queue.d.ts.map +1 -1
- package/dist/write-queue.js +1 -4
- package/docs/advanced.md +68 -1
- package/docs/archive.md +41 -2
- package/docs/atomic.md +29 -5
- package/docs/contributing.md +4 -0
- package/docs/creation.md +8 -4
- package/docs/durability.md +35 -0
- package/docs/file-contents.md +68 -0
- package/docs/json.md +5 -4
- package/docs/local-roots.md +2 -0
- package/docs/mutation-policy-proof.md +5 -3
- package/docs/native.md +9 -8
- package/docs/path.md +4 -4
- package/docs/public-api.md +5 -0
- package/docs/quickstart.md +1 -1
- package/docs/reading.md +2 -2
- package/docs/regular-file.md +3 -0
- package/docs/root.md +9 -0
- package/docs/sidecar-lock.md +9 -1
- package/docs/staged-file.md +4 -3
- package/docs/store.md +3 -1
- package/docs/temp.md +4 -1
- package/docs/types.md +18 -2
- package/docs/walk.md +7 -0
- package/docs/writing.md +9 -2
- package/package.json +8 -8
|
@@ -2,9 +2,8 @@ import { syncFileBestEffort, syncFileBestEffortSync } from "./file-sync.js";
|
|
|
2
2
|
import syncFs, {} from "node:fs";
|
|
3
3
|
import fs, {} from "node:fs/promises";
|
|
4
4
|
import { FsSafeError } from "./errors.js";
|
|
5
|
-
import { sameFileIdentity } from "./file-identity.js";
|
|
6
5
|
import { inspectFileIdentity, inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
7
|
-
import {
|
|
6
|
+
import { ownDirectoryMode } from "./directory-mode-owner.js";
|
|
8
7
|
export async function syncDirectoryBestEffort(fsModule, dirPath) {
|
|
9
8
|
let handle;
|
|
10
9
|
try {
|
|
@@ -48,12 +47,7 @@ function assertDirectory(identity, dirPath) {
|
|
|
48
47
|
if (identity.isSymbolicLink() || !identity.isDirectory()) {
|
|
49
48
|
throw new FsSafeError("not-file", `Atomic replace parent must be a real directory: ${dirPath}`);
|
|
50
49
|
}
|
|
51
|
-
|
|
52
|
-
function assertSameDirectory(expected, opened, dirPath) {
|
|
53
|
-
assertDirectory(opened, dirPath);
|
|
54
|
-
if (!sameFileIdentity(expected, opened)) {
|
|
55
|
-
throw new FsSafeError("path-mismatch", `Atomic replace parent changed before its mode could be applied: ${dirPath}`);
|
|
56
|
-
}
|
|
50
|
+
return identity;
|
|
57
51
|
}
|
|
58
52
|
export async function pinDirectoryForMode(params) {
|
|
59
53
|
// Node does not enforce POSIX directory modes on Windows, and its directory
|
|
@@ -63,15 +57,16 @@ export async function pinDirectoryForMode(params) {
|
|
|
63
57
|
return;
|
|
64
58
|
}
|
|
65
59
|
const expected = params.fsModule === fs
|
|
66
|
-
? syncFs.lstatSync(params.dirPath
|
|
67
|
-
|
|
60
|
+
? inspectFileIdentitySync(() => assertDirectory(syncFs.lstatSync(params.dirPath, { bigint: true }), params.dirPath))
|
|
61
|
+
: await inspectFileIdentity(async () => assertDirectory(await params.fsModule.lstat(params.dirPath, { bigint: true }), params.dirPath));
|
|
68
62
|
const handle = await params.fsModule.open(params.dirPath, directoryOpenFlags());
|
|
69
63
|
try {
|
|
70
64
|
const owner = ownDirectoryMode({
|
|
71
65
|
async inspect() {
|
|
72
|
-
const opened = params.fsModule === fs
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
const opened = params.fsModule === fs
|
|
67
|
+
? inspectFileIdentitySync(() => assertDirectory(syncFs.fstatSync(handle.fd, { bigint: true }), params.dirPath), expected)
|
|
68
|
+
: await inspectFileIdentity(async () => assertDirectory(await handle.stat({ bigint: true }), params.dirPath), expected);
|
|
69
|
+
return Number(opened.mode & 4095n);
|
|
75
70
|
},
|
|
76
71
|
chmod: (mode) => handle.chmod(mode),
|
|
77
72
|
close: () => handle.close(),
|
|
@@ -98,11 +93,10 @@ export function applyDirectoryModeSync(params) {
|
|
|
98
93
|
if (process.platform === "win32") {
|
|
99
94
|
return;
|
|
100
95
|
}
|
|
101
|
-
const expected = params.fsModule.lstatSync(params.dirPath);
|
|
102
|
-
assertDirectory(expected, params.dirPath);
|
|
96
|
+
const expected = inspectFileIdentitySync(() => assertDirectory(params.fsModule.lstatSync(params.dirPath, { bigint: true }), params.dirPath));
|
|
103
97
|
const fd = params.fsModule.openSync(params.dirPath, directoryOpenFlags());
|
|
104
98
|
try {
|
|
105
|
-
|
|
99
|
+
inspectFileIdentitySync(() => assertDirectory(params.fsModule.fstatSync(fd, { bigint: true }), params.dirPath), expected);
|
|
106
100
|
// chmod ignores file-type bits; mask so raw stat modes are tolerated.
|
|
107
101
|
params.fchmodSync?.(fd, params.mode & 0o7777);
|
|
108
102
|
}
|
|
@@ -134,7 +134,7 @@ export class AsyncAtomicTempOwner {
|
|
|
134
134
|
}, opened);
|
|
135
135
|
}
|
|
136
136
|
catch (error) {
|
|
137
|
-
if (error
|
|
137
|
+
if (hasErrorCode(error, "ENOENT")) {
|
|
138
138
|
throw missingOwnedFile(pathname, error);
|
|
139
139
|
}
|
|
140
140
|
throw error;
|
|
@@ -146,7 +146,7 @@ export class AsyncAtomicTempOwner {
|
|
|
146
146
|
return;
|
|
147
147
|
}
|
|
148
148
|
catch (error) {
|
|
149
|
-
if (!(error instanceof FsSafeError) || error
|
|
149
|
+
if (!(error instanceof FsSafeError) || !hasErrorCode(error, "path-mismatch") || !expectedHash) {
|
|
150
150
|
throw error;
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -156,7 +156,7 @@ export class AsyncAtomicTempOwner {
|
|
|
156
156
|
published = await fsModule.open(pathname, PUBLISHED_READ_FLAGS);
|
|
157
157
|
}
|
|
158
158
|
catch (error) {
|
|
159
|
-
if (error
|
|
159
|
+
if (hasErrorCode(error, "ELOOP")) {
|
|
160
160
|
throw new FsSafeError("symlink", `Atomic replace published file became a symlink: ${pathname}`, {
|
|
161
161
|
cause: error,
|
|
162
162
|
});
|
|
@@ -270,7 +270,7 @@ export class SyncAtomicTempOwner {
|
|
|
270
270
|
}, opened);
|
|
271
271
|
}
|
|
272
272
|
catch (error) {
|
|
273
|
-
if (error
|
|
273
|
+
if (hasErrorCode(error, "ENOENT")) {
|
|
274
274
|
throw missingOwnedFile(pathname, error);
|
|
275
275
|
}
|
|
276
276
|
throw error;
|
|
@@ -282,7 +282,7 @@ export class SyncAtomicTempOwner {
|
|
|
282
282
|
return;
|
|
283
283
|
}
|
|
284
284
|
catch (error) {
|
|
285
|
-
if (!(error instanceof FsSafeError) || error
|
|
285
|
+
if (!(error instanceof FsSafeError) || !hasErrorCode(error, "path-mismatch") || !expectedHash) {
|
|
286
286
|
throw error;
|
|
287
287
|
}
|
|
288
288
|
}
|
|
@@ -292,7 +292,7 @@ export class SyncAtomicTempOwner {
|
|
|
292
292
|
publishedFd = fsModule.openSync(pathname, PUBLISHED_READ_FLAGS);
|
|
293
293
|
}
|
|
294
294
|
catch (error) {
|
|
295
|
-
if (error
|
|
295
|
+
if (hasErrorCode(error, "ELOOP")) {
|
|
296
296
|
throw new FsSafeError("symlink", `Atomic replace published file became a symlink: ${pathname}`, {
|
|
297
297
|
cause: error,
|
|
298
298
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace-file.d.ts","sourceRoot":"","sources":["../src/replace-file.ts"],"names":[],"mappings":"AACA,OAAO,MAAwC,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAGlC,OAAO,EAKL,KAAK,+BAA+B,EACpC,KAAK,sCAAsC,EAC3C,KAAK,oCAAoC,EACzC,KAAK,oCAAoC,EAC1C,MAAM,iCAAiC,CAAC;AAWzC,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"replace-file.d.ts","sourceRoot":"","sources":["../src/replace-file.ts"],"names":[],"mappings":"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"}
|
package/dist/replace-file.js
CHANGED
|
@@ -12,13 +12,7 @@ import { assertSafePathPrefix } from "./safe-path-segment.js";
|
|
|
12
12
|
import { admitStandalonePublicationPath } from "./standalone-publication-path.js";
|
|
13
13
|
import { sleep, sleepSync } from "./timing.js";
|
|
14
14
|
import { serializePathWrite } from "./write-queue.js";
|
|
15
|
-
|
|
16
|
-
return error.code === "EBUSY";
|
|
17
|
-
}
|
|
18
|
-
function isPermissionRenameError(error) {
|
|
19
|
-
const code = error.code;
|
|
20
|
-
return code === "EPERM" || code === "EEXIST";
|
|
21
|
-
}
|
|
15
|
+
import { hasErrorCode, readErrorCode } from "./file-cleanup.js";
|
|
22
16
|
async function renameWithRetry(params) {
|
|
23
17
|
for (let attempt = 0; attempt <= params.maxRetries; attempt++) {
|
|
24
18
|
if (attempt > 0)
|
|
@@ -28,11 +22,12 @@ async function renameWithRetry(params) {
|
|
|
28
22
|
return { method: "rename" };
|
|
29
23
|
}
|
|
30
24
|
catch (error) {
|
|
31
|
-
|
|
25
|
+
const code = readErrorCode(error);
|
|
26
|
+
if (code === "EBUSY" && attempt < params.maxRetries) {
|
|
32
27
|
await sleep(params.baseDelayMs * 2 ** attempt);
|
|
33
28
|
continue;
|
|
34
29
|
}
|
|
35
|
-
if (params.copyFallbackOnPermissionError &&
|
|
30
|
+
if (params.copyFallbackOnPermissionError && (code === "EPERM" || code === "EEXIST")) {
|
|
36
31
|
await copyFallbackReplace({
|
|
37
32
|
fsModule: params.fsModule,
|
|
38
33
|
src: params.src,
|
|
@@ -59,11 +54,12 @@ function renameWithRetrySync(params) {
|
|
|
59
54
|
return { method: "rename" };
|
|
60
55
|
}
|
|
61
56
|
catch (error) {
|
|
62
|
-
|
|
57
|
+
const code = readErrorCode(error);
|
|
58
|
+
if (code === "EBUSY" && attempt < params.maxRetries) {
|
|
63
59
|
sleepSync(params.baseDelayMs * 2 ** attempt);
|
|
64
60
|
continue;
|
|
65
61
|
}
|
|
66
|
-
if (params.copyFallbackOnPermissionError &&
|
|
62
|
+
if (params.copyFallbackOnPermissionError && (code === "EPERM" || code === "EEXIST")) {
|
|
67
63
|
copyFallbackReplaceSync({
|
|
68
64
|
fsModule: params.fsModule,
|
|
69
65
|
src: params.src,
|
|
@@ -114,7 +110,7 @@ async function resolveMode(options, filePath) {
|
|
|
114
110
|
stat = fsModule === fs ? syncFs.lstatSync(filePath) : await fsModule.lstat(filePath);
|
|
115
111
|
}
|
|
116
112
|
catch (error) {
|
|
117
|
-
if (error
|
|
113
|
+
if (hasErrorCode(error, "ENOENT")) {
|
|
118
114
|
return defaultMode;
|
|
119
115
|
}
|
|
120
116
|
throw error;
|
|
@@ -132,7 +128,7 @@ function resolveModeSync(options, filePath) {
|
|
|
132
128
|
stat = fsModule.lstatSync(filePath);
|
|
133
129
|
}
|
|
134
130
|
catch (error) {
|
|
135
|
-
if (error
|
|
131
|
+
if (!hasErrorCode(error, "ENOENT")) {
|
|
136
132
|
throw error;
|
|
137
133
|
}
|
|
138
134
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-directory-list.d.ts","sourceRoot":"","sources":["../src/root-directory-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAKvD,OAAO,
|
|
1
|
+
{"version":3,"file":"root-directory-list.d.ts","sourceRoot":"","sources":["../src/root-directory-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAKvD,OAAO,EAML,KAAK,mBAAmB,EAEzB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhF,OAAO,KAAK,EACV,iCAAiC,EACjC,0BAA0B,EAC1B,gCAAgC,EACjC,MAAM,gBAAgB,CAAC;AAKxB,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIrD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,KAAK,GAAG,WAAW,GAAG,QAAQ,CAmBrE;AAED,MAAM,MAAM,6BAA6B,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;AAE7E,wBAAsB,mCAAmC,CACvD,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,6BAA6B,CAAC,CAaxC;AASD,wBAAsB,mCAAmC,CACvD,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,6BAA6B,GAAG,iCAAiC,GACvE,OAAO,CAAC,IAAI,CAAC,CAgCf;AAiCD;;;;;GAKG;AACH,wBAAgB,uCAAuC,CACrD,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,0BAA0B,GAAG,gCAAgC,EACtE,WAAW,CAAC,EAAE,KAAK,GAAG,WAAW,GAChC,IAAI,CAgCN;AAkBD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,IAAI,EACnB,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvB,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,OAAO,EACtB,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;AAoElC,MAAM,MAAM,oBAAoB,GAAG;IACjC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,QAAQ,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC;IAClG,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,IAAI,OAAO,CAAC;CACvB,CAAC;AAEF,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,oBAAoB,CAAC,CA8I/B"}
|
|
@@ -2,7 +2,7 @@ import fsSync from "node:fs";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { setImmediate as yieldToEventLoop } from "node:timers/promises";
|
|
5
|
-
import { assertAsyncDirectoryGuard, assertDirectoryObservationGuardSync, assertDirectoryObservationSync, createAsyncDirectoryGuard, } from "./directory-guard.js";
|
|
5
|
+
import { assertAsyncDirectoryGuard, assertDirectoryObservationGuardSync, assertDirectoryObservationSync, createAsyncDirectoryGuard, extendDirectoryObservationGuard, } from "./directory-guard.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
7
|
import { inspectNativeDirectoryObservation, isNativeDirectoryObservationGuard, } from "./native-directory-observation.js";
|
|
8
8
|
import { isNotFoundPathError } from "./path.js";
|
|
@@ -73,7 +73,18 @@ export async function assertRootDirectoryObservationGuard(root, guard) {
|
|
|
73
73
|
}
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
|
-
|
|
76
|
+
if ("identity" in guard && typeof root.rootIdentity.dev === "bigint" &&
|
|
77
|
+
typeof root.rootIdentity.ino === "bigint") {
|
|
78
|
+
try {
|
|
79
|
+
assertDirectoryObservationSync(root.rootReal, root.rootIdentity);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
throw rootPathChangedError(error instanceof Error ? error : undefined);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
await assertRootIdentityCurrent(root);
|
|
87
|
+
}
|
|
77
88
|
try {
|
|
78
89
|
if ("identity" in guard)
|
|
79
90
|
assertDirectoryObservationGuardSync(guard);
|
|
@@ -215,9 +226,15 @@ async function listGuardedDirectoryPath(root, guard, withFileTypes, receipt) {
|
|
|
215
226
|
return entries;
|
|
216
227
|
}
|
|
217
228
|
export async function openRootDirectoryListing(root, directory, options) {
|
|
218
|
-
const
|
|
229
|
+
const admitted = await createRootDirectoryObservationGuard(root, directory).catch((error) => {
|
|
219
230
|
throw normalizeDirectoryError(error);
|
|
220
231
|
});
|
|
232
|
+
// Retain exact admission identities; metadata rechecks can use numeric Stats
|
|
233
|
+
// only when every identity component is losslessly representable.
|
|
234
|
+
const guard = extendDirectoryObservationGuard({
|
|
235
|
+
stat: admitted.stat,
|
|
236
|
+
identity: { dev: admitted.stat.dev, ino: admitted.stat.ino },
|
|
237
|
+
}, admitted.dir, admitted.realPath);
|
|
221
238
|
const assertCurrent = async () => {
|
|
222
239
|
options.signal?.throwIfAborted();
|
|
223
240
|
await assertRootDirectoryObservationGuard(root, guard);
|
|
@@ -16,6 +16,6 @@ export type CanonicalRootObservation = {
|
|
|
16
16
|
export declare function observeCanonicalRoot(ioFs: RootFileAdmissionFs, rootPath: string): CanonicalRootObservation;
|
|
17
17
|
export declare function createRootFileFinalAdmission(ioFs: RootFileAdmissionFs, root: Extract<CanonicalRootObservation, {
|
|
18
18
|
ok: true;
|
|
19
|
-
}>, boundaryLabel: string): PinnedOpenSyncFinalAdmission;
|
|
19
|
+
}>, boundaryLabel: string, rejectHardlinks?: boolean): PinnedOpenSyncFinalAdmission;
|
|
20
20
|
export {};
|
|
21
21
|
//# sourceMappingURL=root-file-final-admission.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-file-final-admission.d.ts","sourceRoot":"","sources":["../src/root-file-final-admission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"root-file-final-admission.d.ts","sourceRoot":"","sources":["../src/root-file-final-admission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAOrE,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,GAAG,cAAc,CAAC,CAAC;AAEhF,KAAK,aAAa,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE5D,MAAM,MAAM,wBAAwB,GAChC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GACnD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAoClC,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,mBAAmB,EACzB,QAAQ,EAAE,MAAM,GACf,wBAAwB,CAe1B;AAMD,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE,OAAO,CAAC,wBAAwB,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,EACrD,aAAa,EAAE,MAAM,EACrB,eAAe,UAAO,GACrB,4BAA4B,CAuC9B"}
|
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import { FsSafeError } from "./errors.js";
|
|
3
3
|
import { realpathSync } from "./realpath.js";
|
|
4
4
|
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
5
|
+
import { hardlinkedPathNotAllowedError } from "./root-errors.js";
|
|
5
6
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
6
7
|
import { assertNoWindowsPathAlias, pathForWindowsFilesystem } from "./windows-path-alias.js";
|
|
7
8
|
function rootIdentityMismatch(cause) {
|
|
@@ -51,7 +52,7 @@ export function observeCanonicalRoot(ioFs, rootPath) {
|
|
|
51
52
|
function resolveConsumedPath(ioFs, filePath) {
|
|
52
53
|
return ioFs === fs ? realpathSync.native(filePath) : ioFs.realpathSync(filePath);
|
|
53
54
|
}
|
|
54
|
-
export function createRootFileFinalAdmission(ioFs, root, boundaryLabel) {
|
|
55
|
+
export function createRootFileFinalAdmission(ioFs, root, boundaryLabel, rejectHardlinks = true) {
|
|
55
56
|
const inspectRoot = (candidateRootPath, expected) => {
|
|
56
57
|
inspectCanonicalRoot(ioFs, candidateRootPath, expected);
|
|
57
58
|
};
|
|
@@ -69,7 +70,9 @@ export function createRootFileFinalAdmission(ioFs, root, boundaryLabel) {
|
|
|
69
70
|
throw new FsSafeError("outside-workspace", `resolved path escapes ${boundaryLabel}`);
|
|
70
71
|
}
|
|
71
72
|
try {
|
|
72
|
-
inspectFileIdentitySync(() => ioFs.lstatSync(admitted.path, { bigint: true }), descriptorIdentity);
|
|
73
|
+
const current = inspectFileIdentitySync(() => ioFs.lstatSync(admitted.path, { bigint: true }), descriptorIdentity);
|
|
74
|
+
if (rejectHardlinks && current.isFile() && current.nlink > 1n)
|
|
75
|
+
throw hardlinkedPathNotAllowedError();
|
|
73
76
|
}
|
|
74
77
|
catch (error) {
|
|
75
78
|
if (isExpectedPathError(error)) {
|
package/dist/root-file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-file.d.ts","sourceRoot":"","sources":["../src/root-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAOzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EACjC,MAAM,kBAAkB,CAAC;AAS1B,KAAK,cAAc,GAAG,IAAI,CACxB,OAAO,EAAE,EACP,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,UAAU,GACV,cAAc,GACd,cAAc,CACjB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,2BAA2B,GAAG,YAAY,CAAC;AAEnF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,yBAAyB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B,CAAC;AAqBF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAW3D;AASD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,CAwCnF;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE;IACR,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IACjD,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;CAC/C,GACA,CAAC,CAUH;
|
|
1
|
+
{"version":3,"file":"root-file.d.ts","sourceRoot":"","sources":["../src/root-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAOzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EACjC,MAAM,kBAAkB,CAAC;AAS1B,KAAK,cAAc,GAAG,IAAI,CACxB,OAAO,EAAE,EACP,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,UAAU,GACV,cAAc,GACd,cAAc,CACjB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,2BAA2B,GAAG,YAAY,CAAC;AAEnF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,yBAAyB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B,CAAC;AAqBF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAW3D;AASD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,CAwCnF;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE;IACR,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IACjD,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;CAC/C,GACA,CAAC,CAUH;AA+DD,wBAAsB,YAAY,CAChC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,kBAAkB,CAAC,CAmD7B"}
|
package/dist/root-file.js
CHANGED
|
@@ -70,14 +70,15 @@ export function matchRootFileOpenFailure(failure, handlers) {
|
|
|
70
70
|
return handlers.fallback(failure);
|
|
71
71
|
}
|
|
72
72
|
function openRootFileResolved(params) {
|
|
73
|
+
const rejectHardlinks = params.rejectHardlinks ?? true;
|
|
73
74
|
const opened = openPinnedFileSync({
|
|
74
75
|
filePath: params.absolutePath,
|
|
75
76
|
resolvedPath: params.resolvedPath,
|
|
76
|
-
rejectHardlinks
|
|
77
|
+
rejectHardlinks,
|
|
77
78
|
maxBytes: params.maxBytes,
|
|
78
79
|
allowedType: params.allowedType,
|
|
79
80
|
ioFs: params.ioFs,
|
|
80
|
-
finalAdmission: createRootFileFinalAdmission(params.ioFs, params.rootObservation, params.boundaryLabel),
|
|
81
|
+
finalAdmission: createRootFileFinalAdmission(params.ioFs, params.rootObservation, params.boundaryLabel, rejectHardlinks),
|
|
81
82
|
});
|
|
82
83
|
if (!opened.ok) {
|
|
83
84
|
return opened;
|
package/dist/root-impl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAsB7D,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAW9E,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,
|
|
1
|
+
{"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"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"}
|
package/dist/root-impl.js
CHANGED
|
@@ -77,14 +77,14 @@ import { removePathIfIdentityUnchanged } from "./replace-file-temp-owner.js";
|
|
|
77
77
|
import { realpathSync } from "./realpath.js";
|
|
78
78
|
import { mkdirPathFallback, prepareRootWriteTarget, tryMkdirAtExactParent } from "./root-directory-creation.js";
|
|
79
79
|
import { isNonRegularWriteOpenError, resolveNonblockingWriteFlag } from "./write-open-flags.js";
|
|
80
|
-
import { resolveRootPath, resolveRootPathForRemoval } from "./root-path.js";
|
|
80
|
+
import { resolveRootPath, resolveRootPathSync, resolveRootPathForRemoval } from "./root-path.js";
|
|
81
81
|
import { RemovalPathReceipts } from "./root-remove-receipt.js";
|
|
82
82
|
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
83
83
|
import { listDirectoryPath, openRootDirectoryListing } from "./root-directory-list.js";
|
|
84
84
|
import { statResolvedPathInRoot } from "./root-path-stat.js";
|
|
85
85
|
import { entriesInRoot } from "./root-entries.js";
|
|
86
86
|
import { assertMoveMutationAllowed } from "./root-move-preflight.js";
|
|
87
|
-
import { assertRootIdentityCurrent, assertValidRootDestinationPath, assertValidRootRelativePath, ensureTrailingSep, expandRelativePathWithHome, resolvePathInRoot, resolveRootContext, rootRelativeReadPath, } from "./root-context.js";
|
|
87
|
+
import { assertRootIdentityCurrent, assertRootIdentityCurrentSync, assertValidRootDestinationPath, assertValidRootRelativePath, ensureTrailingSep, expandRelativePathWithHome, resolvePathInRoot, resolveRootContext, rootRelativeReadPath, } from "./root-context.js";
|
|
88
88
|
import { fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, normalizePinnedWriteError, outsideWorkspaceError, } from "./root-errors.js";
|
|
89
89
|
import { getFsSafeTestHooks } from "./test-hooks.js";
|
|
90
90
|
import { stringifyJsonDocument } from "./json-stringify.js";
|
|
@@ -99,7 +99,7 @@ import { finishRootFallbackWrite } from "./root-write-publication.js";
|
|
|
99
99
|
import { withRootFallbackCompatibilityLock } from "./root-write-compatibility.js";
|
|
100
100
|
import { assertRootFallbackWritePath } from "./root-write-lock-binding.js";
|
|
101
101
|
import { inspectFileIdentity, inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
102
|
-
import { movePathNoReplaceNative } from "./root-move-noreplace.js";
|
|
102
|
+
import { admitMoveSourceStat, movePathNoReplaceNative } from "./root-move-noreplace.js";
|
|
103
103
|
import { admitRootReadHandle, inspectOpenedPathIdentitySync } from "./root-read-admission.js";
|
|
104
104
|
import { createCopyPublicationObserver, onCopyPublication, onCopySourceAdmission } from "./copy-publication.js";
|
|
105
105
|
import { writeAllToFile } from "./write-file-handle.js";
|
|
@@ -723,8 +723,9 @@ async function appendFileInRoot(root, params) {
|
|
|
723
723
|
if (params.prependNewlineIfNeeded === true &&
|
|
724
724
|
!target.createdForWrite &&
|
|
725
725
|
target.stat.size > 0 &&
|
|
726
|
+
params.data.length > 0 &&
|
|
726
727
|
((typeof params.data === "string" && !params.data.startsWith("\n")) ||
|
|
727
|
-
(Buffer.isBuffer(params.data) && params.data
|
|
728
|
+
(Buffer.isBuffer(params.data) && params.data[0] !== 0x0a))) {
|
|
728
729
|
const newline = Buffer.from("\n", typeof params.data === "string" ? params.encoding : "utf8");
|
|
729
730
|
const tail = Buffer.alloc(newline.length);
|
|
730
731
|
const { bytesRead } = await target.handle.read(tail, 0, tail.length, Math.max(0, target.stat.size - tail.length));
|
|
@@ -1085,6 +1086,8 @@ async function listPathFallback(root, relativePath, withFileTypes) {
|
|
|
1085
1086
|
return await listDirectoryPath(root, resolved.resolved, withFileTypes, resolved.receipt);
|
|
1086
1087
|
}
|
|
1087
1088
|
async function movePathFallback(root, params) {
|
|
1089
|
+
const originalRoutes = params.overwrite && params.assertBeforeMutation
|
|
1090
|
+
? await Promise.all([params.fromRelative, params.toRelative].map(expandRelativePathWithHome)) : undefined;
|
|
1088
1091
|
const source = await resolvePathInRoot(root, params.fromRelative, {
|
|
1089
1092
|
aliasErrorCode: "path-alias",
|
|
1090
1093
|
allowFinalSymlink: true,
|
|
@@ -1120,9 +1123,14 @@ async function movePathFallback(root, params) {
|
|
|
1120
1123
|
targetStat?.isSymbolicLink() === true);
|
|
1121
1124
|
},
|
|
1122
1125
|
});
|
|
1123
|
-
let
|
|
1126
|
+
let sourceIdentity;
|
|
1124
1127
|
try {
|
|
1125
|
-
|
|
1128
|
+
if (params.overwrite && params.assertBeforeMutation) {
|
|
1129
|
+
sourceIdentity = inspectFileIdentitySync(() => admitMoveSourceStat(fsSync.lstatSync(source.resolved, { bigint: true }), true));
|
|
1130
|
+
}
|
|
1131
|
+
else {
|
|
1132
|
+
admitMoveSourceStat(fsSync.lstatSync(source.resolved), params.overwrite);
|
|
1133
|
+
}
|
|
1126
1134
|
}
|
|
1127
1135
|
catch (error) {
|
|
1128
1136
|
if (isNotFoundPathError(error)) {
|
|
@@ -1130,19 +1138,10 @@ async function movePathFallback(root, params) {
|
|
|
1130
1138
|
}
|
|
1131
1139
|
throw error;
|
|
1132
1140
|
}
|
|
1133
|
-
if (
|
|
1134
|
-
throw new FsSafeError("
|
|
1135
|
-
}
|
|
1136
|
-
if (sourceStat.isFile() && sourceStat.nlink > 1) {
|
|
1137
|
-
throw hardlinkedPathNotAllowedError();
|
|
1138
|
-
}
|
|
1139
|
-
if (!params.overwrite && sourceStat.isDirectory()) {
|
|
1140
|
-
throw new FsSafeError("invalid-path", "directory moves require overwrite: true");
|
|
1141
|
+
if (!pinnedTarget) {
|
|
1142
|
+
throw new FsSafeError("path-mismatch", "destination admission was not completed");
|
|
1141
1143
|
}
|
|
1142
1144
|
if (!params.overwrite) {
|
|
1143
|
-
if (!pinnedTarget) {
|
|
1144
|
-
throw new FsSafeError("path-mismatch", "destination admission was not completed");
|
|
1145
|
-
}
|
|
1146
1145
|
await movePathNoReplaceNative(root, params, {
|
|
1147
1146
|
sourcePath: source.resolved,
|
|
1148
1147
|
sourceParentPath: path.dirname(pinnedSource.canonicalPath),
|
|
@@ -1151,8 +1150,9 @@ async function movePathFallback(root, params) {
|
|
|
1151
1150
|
});
|
|
1152
1151
|
return;
|
|
1153
1152
|
}
|
|
1154
|
-
const
|
|
1155
|
-
const
|
|
1153
|
+
const guardOptions = { bigint: sourceIdentity !== undefined };
|
|
1154
|
+
const sourceParentGuard = await createAsyncDirectoryGuard(path.dirname(source.resolved), guardOptions);
|
|
1155
|
+
const targetParentGuard = await createNearestExistingDirectoryGuard(target.rootReal, path.dirname(target.resolved), guardOptions);
|
|
1156
1156
|
await getFsSafeTestHooks()?.beforeRootFallbackMutation?.("move", target.resolved);
|
|
1157
1157
|
await assertAsyncDirectoryGuard(sourceParentGuard);
|
|
1158
1158
|
await assertAsyncDirectoryGuard(targetParentGuard);
|
|
@@ -1160,6 +1160,31 @@ async function movePathFallback(root, params) {
|
|
|
1160
1160
|
assertFinalSymlinkRejected(source.resolved, params.mutationSymlinks !== undefined);
|
|
1161
1161
|
assertFinalSymlinkRejected(target.resolved, params.mutationSymlinks !== undefined);
|
|
1162
1162
|
params.assertBeforeMutation?.();
|
|
1163
|
+
if (sourceIdentity) {
|
|
1164
|
+
assertRootIdentityCurrentSync(root);
|
|
1165
|
+
assertSyncDirectoryGuard(sourceParentGuard);
|
|
1166
|
+
assertSyncDirectoryGuard(targetParentGuard);
|
|
1167
|
+
for (const [route, selected, expected, policy] of [
|
|
1168
|
+
[originalRoutes[0], source.resolved, pinnedSource.canonicalPath, PATH_ALIAS_POLICIES.strict],
|
|
1169
|
+
[originalRoutes[1], target.resolved, pinnedTarget.canonicalPath, PATH_ALIAS_POLICIES.unlinkTarget],
|
|
1170
|
+
]) {
|
|
1171
|
+
for (const absolutePath of new Set([path.isAbsolute(route) ? route : `${root.rootWithSep}${route}`, selected])) {
|
|
1172
|
+
try {
|
|
1173
|
+
const current = resolveRootPathSync({
|
|
1174
|
+
absolutePath, rootPath: root.rootReal, rootCanonicalPath: root.rootReal,
|
|
1175
|
+
rootIdentity: root.rootIdentity, boundaryLabel: "root", policy,
|
|
1176
|
+
...mutationSymlinkResolution(params.mutationSymlinks),
|
|
1177
|
+
});
|
|
1178
|
+
if (current.canonicalPath !== expected)
|
|
1179
|
+
throw new FsSafeError("path-mismatch", "move route changed during authorization");
|
|
1180
|
+
}
|
|
1181
|
+
catch (error) {
|
|
1182
|
+
throw normalizePinnedPathError(error);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
inspectFileIdentitySync(() => admitMoveSourceStat(fsSync.lstatSync(source.resolved, { bigint: true }), true), sourceIdentity);
|
|
1187
|
+
}
|
|
1163
1188
|
await fs.rename(source.resolved, target.resolved);
|
|
1164
1189
|
}
|
|
1165
1190
|
catch (error) {
|
|
@@ -1324,6 +1349,7 @@ async function writeMissingFileFallback(root, params, expectedWritePath) {
|
|
|
1324
1349
|
const parentGuard = pathSelection?.parentGuard ??
|
|
1325
1350
|
await createAsyncDirectoryGuard(path.dirname(targetPath), { bigint: true });
|
|
1326
1351
|
let created = false;
|
|
1352
|
+
let completed = false;
|
|
1327
1353
|
let createdIdentity;
|
|
1328
1354
|
let writtenHandle;
|
|
1329
1355
|
let verifyingPublication = false;
|
|
@@ -1367,6 +1393,7 @@ async function writeMissingFileFallback(root, params, expectedWritePath) {
|
|
|
1367
1393
|
});
|
|
1368
1394
|
if (params.durable !== false)
|
|
1369
1395
|
await syncDirectoryBestEffort(path.dirname(targetPath));
|
|
1396
|
+
completed = true;
|
|
1370
1397
|
}
|
|
1371
1398
|
catch (err) {
|
|
1372
1399
|
if (verifyingPublication)
|
|
@@ -1384,6 +1411,9 @@ async function writeMissingFileFallback(root, params, expectedWritePath) {
|
|
|
1384
1411
|
pathname: targetPath, handle: writtenHandle, identity: createdIdentity, parentGuard,
|
|
1385
1412
|
});
|
|
1386
1413
|
}
|
|
1387
|
-
|
|
1414
|
+
if (completed)
|
|
1415
|
+
await writtenHandle?.close();
|
|
1416
|
+
else
|
|
1417
|
+
await writtenHandle?.close().catch(() => undefined);
|
|
1388
1418
|
}
|
|
1389
1419
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { type BigIntStats, type Stats } from "node:fs";
|
|
1
2
|
import { type DenyMutationPolicy } from "./deny-mutations.js";
|
|
2
3
|
import { type RootContext } from "./root-context.js";
|
|
3
4
|
import { type MutationSymlinkPolicy } from "./root-symlink-policy.js";
|
|
5
|
+
export declare function admitMoveSourceStat<T extends Stats | BigIntStats>(stat: T, overwrite?: boolean): T;
|
|
4
6
|
export declare function movePathNoReplaceNative(root: RootContext, params: {
|
|
5
7
|
assertBeforeMutation?: () => void;
|
|
6
8
|
denyMutations?: DenyMutationPolicy;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-move-noreplace.d.ts","sourceRoot":"","sources":["../src/root-move-noreplace.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-move-noreplace.d.ts","sourceRoot":"","sources":["../src/root-move-noreplace.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAQvF,OAAO,EAA4D,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAU/G,OAAO,EAA8B,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAsDlG,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,KAAK,GAAG,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,UAAQ,GAAG,CAAC,CAWhG;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE;IACN,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;CAC1C,EACD,KAAK,EAAE;IACL,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GACA,OAAO,CAAC,IAAI,CAAC,CAsIf"}
|
|
@@ -58,14 +58,14 @@ function normalizeRenameNoReplaceError(error) {
|
|
|
58
58
|
}
|
|
59
59
|
return normalizeMoveError(error);
|
|
60
60
|
}
|
|
61
|
-
function admitMoveSourceStat(stat) {
|
|
61
|
+
export function admitMoveSourceStat(stat, overwrite = false) {
|
|
62
62
|
if (stat.isSymbolicLink()) {
|
|
63
63
|
throw new FsSafeError("symlink", "symlink not allowed");
|
|
64
64
|
}
|
|
65
65
|
if (stat.isFile() && stat.nlink > 1) {
|
|
66
66
|
throw hardlinkedPathNotAllowedError();
|
|
67
67
|
}
|
|
68
|
-
if (stat.isDirectory()) {
|
|
68
|
+
if (!overwrite && stat.isDirectory()) {
|
|
69
69
|
throw new FsSafeError("invalid-path", "directory moves require overwrite: true");
|
|
70
70
|
}
|
|
71
71
|
return stat;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-read-admission.d.ts","sourceRoot":"","sources":["../src/root-read-admission.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,OAAO,EAAiC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAmB9D,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,aAAa,GAAG,SAAS,GAClC,WAAW,CAQb;
|
|
1
|
+
{"version":3,"file":"root-read-admission.d.ts","sourceRoot":"","sources":["../src/root-read-admission.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,OAAO,EAAiC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAmB9D,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,aAAa,GAAG,SAAS,GAClC,WAAW,CAQb;AAgDD,KAAK,mBAAmB,GAAG;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACzB,CAAC;AAEF,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,mBAAmB,EAAE,MAAM,EAAE;IAC/E,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClF,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACzE,GAAG,OAAO,CAAC,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA+BpC"}
|
|
@@ -35,7 +35,9 @@ function assertRootReadAdmissionCurrent(params) {
|
|
|
35
35
|
assertRootIdentityCurrentSync(params.root);
|
|
36
36
|
const admittedPath = (() => {
|
|
37
37
|
try {
|
|
38
|
-
inspectFileIdentitySync(() => inspectOpenedPathIdentitySync(params.filePath, params.symlinks), params.identity);
|
|
38
|
+
const current = inspectFileIdentitySync(() => inspectOpenedPathIdentitySync(params.filePath, params.symlinks), params.identity);
|
|
39
|
+
if (params.hardlinks !== "allow" && current.nlink > 1n)
|
|
40
|
+
throw hardlinkedPathNotAllowedError();
|
|
39
41
|
const canonicalPath = resolveFinalOpenedRealPath(params.filePath);
|
|
40
42
|
assertNoWindowsPathAlias(canonicalPath, "filesystem", "resolved file path uses a Windows filesystem namespace alias");
|
|
41
43
|
const admittedRealPath = admitPathInsideRoot({
|
|
@@ -48,7 +50,9 @@ function assertRootReadAdmissionCurrent(params) {
|
|
|
48
50
|
}
|
|
49
51
|
// This is a fresh no-follow observation even when canonicalPath and
|
|
50
52
|
// filePath have the same spelling; realpath may have raced a replacement.
|
|
51
|
-
inspectFileIdentitySync(() => inspectOpenedPathIdentitySync(canonicalPath, undefined), params.identity);
|
|
53
|
+
const canonical = inspectFileIdentitySync(() => inspectOpenedPathIdentitySync(canonicalPath, undefined), params.identity);
|
|
54
|
+
if (params.hardlinks !== "allow" && canonical.nlink > 1n)
|
|
55
|
+
throw hardlinkedPathNotAllowedError();
|
|
52
56
|
return admittedRealPath.path;
|
|
53
57
|
}
|
|
54
58
|
catch (error) {
|
|
@@ -75,6 +79,7 @@ export async function admitRootReadHandle(params) {
|
|
|
75
79
|
filePath: params.filePath,
|
|
76
80
|
handle: params.opened.handle,
|
|
77
81
|
identity: params.identity,
|
|
82
|
+
hardlinks: params.hardlinks,
|
|
78
83
|
symlinks: params.symlinks,
|
|
79
84
|
afterPathIdentityCheck: params.afterPathIdentityCheck,
|
|
80
85
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-remove.d.ts","sourceRoot":"","sources":["../src/root-remove.ts"],"names":[],"mappings":"AAeA,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAM3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AASpE,eAAO,MAAM,uBAAuB,EAAE,OAAO,MAA4C,CAAC;AAK1F,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAgBtE;
|
|
1
|
+
{"version":3,"file":"root-remove.d.ts","sourceRoot":"","sources":["../src/root-remove.ts"],"names":[],"mappings":"AAeA,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAM3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AASpE,eAAO,MAAM,uBAAuB,EAAE,OAAO,MAA4C,CAAC;AAK1F,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAgBtE;AAiPD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,CAAC,EAAE,mBAAmB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAkMf"}
|