@openclaw/fs-safe 0.8.2 → 0.8.4
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 +19 -0
- package/README.md +1 -1
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +8 -7
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +2 -2
- package/dist/archive-kind.d.ts +1 -0
- package/dist/archive-kind.d.ts.map +1 -1
- package/dist/archive-kind.js +6 -0
- package/dist/archive-limits.d.ts +0 -1
- package/dist/archive-limits.d.ts.map +1 -1
- package/dist/archive-limits.js +0 -3
- package/dist/archive-native.d.ts +1 -0
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +20 -76
- package/dist/archive-parser-errors.d.ts +2 -0
- package/dist/archive-parser-errors.d.ts.map +1 -0
- package/dist/archive-parser-errors.js +12 -0
- package/dist/archive-plan.d.ts +20 -0
- package/dist/archive-plan.d.ts.map +1 -0
- package/dist/archive-plan.js +55 -0
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +7 -13
- package/dist/archive-tar-inspect.d.ts +7 -0
- package/dist/archive-tar-inspect.d.ts.map +1 -0
- package/dist/archive-tar-inspect.js +59 -0
- package/dist/archive-tar-wasm.d.ts +1 -1
- package/dist/archive-tar-wasm.d.ts.map +1 -1
- package/dist/archive-tar-wasm.js +5 -8
- package/dist/archive-tar.d.ts +3 -1
- package/dist/archive-tar.d.ts.map +1 -1
- package/dist/archive-tar.js +12 -49
- package/dist/archive.d.ts +1 -0
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +54 -33
- package/dist/atomic.d.ts +1 -1
- package/dist/atomic.d.ts.map +1 -1
- package/dist/atomic.js +1 -1
- package/dist/bounded-read-stream.d.ts +1 -5
- package/dist/bounded-read-stream.d.ts.map +1 -1
- package/dist/bounded-read-stream.js +5 -13
- package/dist/bounded-read.d.ts.map +1 -1
- package/dist/bounded-read.js +31 -4
- package/dist/byte-budget.d.ts +0 -1
- package/dist/byte-budget.d.ts.map +1 -1
- package/dist/byte-budget.js +1 -1
- package/dist/directory-durability.js +5 -5
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-guard.js +5 -6
- package/dist/directory-mode-owner.d.ts.map +1 -1
- package/dist/directory-mode-owner.js +2 -0
- package/dist/error-detail.d.ts +1 -0
- package/dist/error-detail.d.ts.map +1 -1
- package/dist/error-detail.js +6 -0
- package/dist/file-store-boundary.d.ts +1 -1
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +3 -14
- package/dist/file-store-prune.js +17 -8
- package/dist/file-store.js +3 -3
- package/dist/file-sync.d.ts +5 -0
- package/dist/file-sync.d.ts.map +1 -0
- package/dist/file-sync.js +19 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +5 -4
- package/dist/guarded-mutation.d.ts +3 -0
- package/dist/guarded-mutation.d.ts.map +1 -1
- package/dist/guarded-mutation.js +5 -1
- package/dist/home-dir.d.ts +0 -10
- package/dist/home-dir.d.ts.map +1 -1
- package/dist/home-dir.js +0 -28
- package/dist/json-durable-queue-ownership.d.ts +1 -0
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +139 -18
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +5 -10
- package/dist/json-store.d.ts.map +1 -1
- package/dist/json-store.js +1 -1
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +2 -3
- package/dist/move-path-cleanup.d.ts +1 -1
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +4 -2
- package/dist/move-path.d.ts +9 -0
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +53 -16
- package/dist/native-binding.d.ts +2 -1
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-operations.d.ts +0 -1
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +0 -10
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +8 -4
- package/dist/native-pinned-write.js +3 -3
- package/dist/native-staged-file.d.ts +10 -3
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +38 -13
- package/dist/opened-realpath.d.ts +12 -1
- package/dist/opened-realpath.d.ts.map +1 -1
- package/dist/opened-realpath.js +16 -14
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +26 -2
- package/dist/path-policy.js +3 -3
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +3 -0
- package/dist/pinned-write.d.ts +2 -2
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +17 -22
- package/dist/private-temp-workspace.js +1 -1
- package/dist/publish-file.js +2 -2
- package/dist/regular-file.js +8 -8
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +2 -7
- package/dist/replace-file-descriptor.d.ts.map +1 -1
- package/dist/replace-file-descriptor.js +11 -20
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +15 -14
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +21 -8
- package/dist/root-context.js +5 -5
- package/dist/root-errors.d.ts +1 -0
- package/dist/root-errors.d.ts.map +1 -1
- package/dist/root-errors.js +9 -0
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +17 -28
- package/dist/root-impl.d.ts +2 -1
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +46 -58
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +2 -3
- package/dist/root-path-symlink.d.ts.map +1 -1
- package/dist/root-path-symlink.js +2 -3
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +51 -97
- package/dist/root-paths.d.ts.map +1 -1
- package/dist/root-paths.js +16 -15
- package/dist/root-write-mode.d.ts +6 -0
- package/dist/root-write-mode.d.ts.map +1 -0
- package/dist/root-write-mode.js +61 -0
- package/dist/root-write-verification.js +8 -8
- package/dist/safe-path-segment.d.ts +1 -0
- package/dist/safe-path-segment.d.ts.map +1 -1
- package/dist/safe-path-segment.js +1 -1
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +4 -11
- package/dist/secret-read-async.d.ts.map +1 -1
- package/dist/secret-read-async.js +2 -10
- package/dist/secret-read-policy.d.ts +4 -0
- package/dist/secret-read-policy.d.ts.map +1 -1
- package/dist/secret-read-policy.js +12 -0
- package/dist/sibling-staged-file.d.ts.map +1 -1
- package/dist/sibling-staged-file.js +2 -7
- package/dist/sidecar-lock-policy.d.ts +0 -1
- package/dist/sidecar-lock-policy.d.ts.map +1 -1
- package/dist/sidecar-lock-policy.js +0 -4
- package/dist/strict-file-identity.d.ts +1 -1
- package/dist/strict-file-identity.d.ts.map +1 -1
- package/dist/string-coerce.d.ts +0 -9
- package/dist/string-coerce.d.ts.map +1 -1
- package/dist/string-coerce.js +0 -56
- package/dist/symlink-parents.d.ts.map +1 -1
- package/dist/symlink-parents.js +1 -2
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +1 -12
- package/docs/archive.md +57 -0
- package/docs/atomic.md +53 -19
- package/docs/reading.md +2 -0
- package/docs/root.md +10 -1
- package/docs/staged-file.md +6 -2
- package/docs/types.md +2 -1
- package/docs/writing.md +30 -2
- package/package.json +8 -8
- package/dist/archive-tar-extract.d.ts +0 -11
- package/dist/archive-tar-extract.d.ts.map +0 -1
- package/dist/archive-tar-extract.js +0 -49
- package/dist/fsync.d.ts +0 -2
- package/dist/fsync.d.ts.map +0 -1
- package/dist/fsync.js +0 -1
- package/dist/json-durable-queue-retirement.d.ts +0 -9
- package/dist/json-durable-queue-retirement.d.ts.map +0 -1
- package/dist/json-durable-queue-retirement.js +0 -126
- package/dist/json-durable-queue-transfer-lock.d.ts +0 -2
- package/dist/json-durable-queue-transfer-lock.d.ts.map +0 -1
- package/dist/json-durable-queue-transfer-lock.js +0 -19
- package/dist/mode.d.ts +0 -2
- package/dist/mode.d.ts.map +0 -1
- package/dist/mode.js +0 -3
- package/dist/output-sibling.d.ts +0 -8
- package/dist/output-sibling.d.ts.map +0 -1
- package/dist/output-sibling.js +0 -30
- package/dist/read-error.d.ts +0 -2
- package/dist/read-error.d.ts.map +0 -1
- package/dist/read-error.js +0 -11
- package/dist/short-path.d.ts +0 -2
- package/dist/short-path.d.ts.map +0 -1
- package/dist/short-path.js +0 -7
- package/dist/staged-file.d.ts +0 -10
- package/dist/staged-file.d.ts.map +0 -1
- package/dist/staged-file.js +0 -15
package/dist/root-file.js
CHANGED
|
@@ -14,19 +14,20 @@ export function canUseRootFileOpen(ioFs) {
|
|
|
14
14
|
}
|
|
15
15
|
export function openRootFileSync(params) {
|
|
16
16
|
const ioFs = params.ioFs ?? fs;
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const absolutePath = path.resolve(params.absolutePath);
|
|
18
|
+
let resolved;
|
|
19
|
+
try {
|
|
20
|
+
resolved = mapResolvedRootPath(absolutePath, resolveRootPathSync({
|
|
20
21
|
absolutePath,
|
|
21
22
|
rootPath: params.rootPath,
|
|
22
23
|
rootCanonicalPath: params.rootRealPath,
|
|
23
24
|
boundaryLabel: params.boundaryLabel,
|
|
24
25
|
rejectSymlinks: params.rejectSymlinks ?? true,
|
|
25
26
|
skipLexicalRootCheck: params.skipLexicalRootCheck,
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
resolved = toBoundaryValidationError(error);
|
|
30
31
|
}
|
|
31
32
|
return finalizeRootFileOpen({
|
|
32
33
|
resolved,
|
|
@@ -83,9 +84,10 @@ function finalizeRootFileOpen(params) {
|
|
|
83
84
|
}
|
|
84
85
|
export async function openRootFile(params) {
|
|
85
86
|
const ioFs = params.ioFs ?? fs;
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
const absolutePath = path.resolve(params.absolutePath);
|
|
88
|
+
let resolved;
|
|
89
|
+
try {
|
|
90
|
+
resolved = mapResolvedRootPath(absolutePath, await resolveRootPath({
|
|
89
91
|
absolutePath,
|
|
90
92
|
rootPath: params.rootPath,
|
|
91
93
|
rootCanonicalPath: params.rootRealPath,
|
|
@@ -93,9 +95,11 @@ export async function openRootFile(params) {
|
|
|
93
95
|
policy: params.aliasPolicy,
|
|
94
96
|
rejectSymlinks: params.rejectSymlinks ?? true,
|
|
95
97
|
skipLexicalRootCheck: params.skipLexicalRootCheck,
|
|
96
|
-
})
|
|
97
|
-
}
|
|
98
|
-
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
resolved = toBoundaryValidationError(error);
|
|
102
|
+
}
|
|
99
103
|
return finalizeRootFileOpen({
|
|
100
104
|
resolved,
|
|
101
105
|
maxBytes: params.maxBytes,
|
|
@@ -114,18 +118,3 @@ function mapResolvedRootPath(absolutePath, resolved) {
|
|
|
114
118
|
rootRealPath: resolved.rootCanonicalPath,
|
|
115
119
|
};
|
|
116
120
|
}
|
|
117
|
-
function resolveRootFilePathGeneric(params) {
|
|
118
|
-
const absolutePath = path.resolve(params.absolutePath);
|
|
119
|
-
try {
|
|
120
|
-
const resolved = params.resolve(absolutePath);
|
|
121
|
-
if (resolved instanceof Promise) {
|
|
122
|
-
return resolved
|
|
123
|
-
.then((value) => mapResolvedRootPath(absolutePath, value))
|
|
124
|
-
.catch((error) => toBoundaryValidationError(error));
|
|
125
|
-
}
|
|
126
|
-
return mapResolvedRootPath(absolutePath, resolved);
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
return toBoundaryValidationError(error);
|
|
130
|
-
}
|
|
131
|
-
}
|
package/dist/root-impl.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export type SymlinkPolicy = "reject" | "follow-within-root";
|
|
|
26
26
|
export type HardlinkPolicy = "reject" | "allow";
|
|
27
27
|
export type WritableOpenMode = "replace" | "append" | "update";
|
|
28
28
|
export type RootDefaults = {
|
|
29
|
+
durable?: boolean;
|
|
29
30
|
hardlinks?: HardlinkPolicy;
|
|
30
31
|
maxBytes?: number;
|
|
31
32
|
mkdir?: boolean;
|
|
@@ -37,7 +38,7 @@ export type RootDefaults = {
|
|
|
37
38
|
};
|
|
38
39
|
export type RootReadOptions = Pick<RootDefaults, "hardlinks" | "maxBytes" | "nonBlockingRead" | "symlinks">;
|
|
39
40
|
export type RootOpenOptions = Omit<RootReadOptions, "maxBytes">;
|
|
40
|
-
export type RootWriteOptions = Pick<RootDefaults, "denyMutations" | "mkdir" | "mode" | "renameIdentity"> & {
|
|
41
|
+
export type RootWriteOptions = Pick<RootDefaults, "denyMutations" | "durable" | "mkdir" | "mode" | "renameIdentity"> & {
|
|
41
42
|
encoding?: BufferEncoding;
|
|
42
43
|
overwrite?: boolean;
|
|
43
44
|
};
|
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,KAAK,EAAE,MAAM,SAAS,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAW7D,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,KAAK,oBAAoB,EAG1B,MAAM,mBAAmB,CAAC;AAY3B,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAI9E,OAAO,EASL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAa3B,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAY,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
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
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import fsSync, { constants as fsConstants } from "node:fs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { normalizeMaxBytes } from "./byte-budget.js";
|
|
6
6
|
import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard, createNearestExistingDirectoryGuard } from "./directory-guard.js";
|
|
7
7
|
import { FsSafeError } from "./errors.js";
|
|
8
|
-
import { syncDirectoryBestEffort } from "./
|
|
8
|
+
import { syncDirectoryBestEffort } from "./directory-durability.js";
|
|
9
9
|
import { sameFileIdentity, sameFileIdentityForCleanup, } from "./file-identity.js";
|
|
10
10
|
import { mkdirPathComponentsWithGuards } from "./guarded-mkdir.js";
|
|
11
11
|
import { withAsyncDirectoryGuards } from "./guarded-mutation.js";
|
|
@@ -29,6 +29,7 @@ import { walkRoot } from "./root-walk.js";
|
|
|
29
29
|
import { registerTempPathForExit } from "./temp-cleanup.js";
|
|
30
30
|
import { serializePathWrite } from "./write-queue.js";
|
|
31
31
|
import { verifyAtomicWriteResult } from "./root-write-verification.js";
|
|
32
|
+
import { inheritWriteTargetMode } from "./root-write-mode.js";
|
|
32
33
|
import { inspectFileIdentity } from "./strict-file-identity.js";
|
|
33
34
|
export { resolveOpenedFileRealPathForHandle } from "./opened-realpath.js";
|
|
34
35
|
function logWarn(message) {
|
|
@@ -86,7 +87,7 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
86
87
|
// results that get sent to messaging channels). See openclaw/openclaw#31186.
|
|
87
88
|
try {
|
|
88
89
|
preOpenStat = await inspectFileIdentity(async () => {
|
|
89
|
-
const stat =
|
|
90
|
+
const stat = fsSync.lstatSync(filePath, { bigint: true });
|
|
90
91
|
observedBeforeOpen = true;
|
|
91
92
|
if (stat.isSymbolicLink() && options?.symlinks !== "follow-within-root") {
|
|
92
93
|
throw new FsSafeError("symlink", "symlink not allowed");
|
|
@@ -126,13 +127,13 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
126
127
|
}
|
|
127
128
|
try {
|
|
128
129
|
await fsSafeTestHooks?.afterOpen?.(filePath, handle);
|
|
129
|
-
const stat =
|
|
130
|
+
const stat = fsSync.fstatSync(handle.fd);
|
|
130
131
|
if (!stat.isFile()) {
|
|
131
132
|
throw new FsSafeError("not-file", "not a file");
|
|
132
133
|
}
|
|
133
134
|
// Keep numeric Stats for the public receipt, never for identity verification.
|
|
134
135
|
let openedIdentity;
|
|
135
|
-
const identity = await inspectFileIdentity(async () => (openedIdentity =
|
|
136
|
+
const identity = await inspectFileIdentity(async () => (openedIdentity = fsSync.fstatSync(handle.fd, { bigint: true })), preOpenStat && !preOpenStat.isSymbolicLink() ? preOpenStat : undefined).catch(async (error) => {
|
|
136
137
|
if ([0, 1].includes(stat.nlink)) {
|
|
137
138
|
await recordPreOpenFileChange(error, handle, filePath, preOpenStat, openedIdentity);
|
|
138
139
|
}
|
|
@@ -155,23 +156,28 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
155
156
|
};
|
|
156
157
|
await inspectPathIdentity(async () => {
|
|
157
158
|
const pathStat = options?.symlinks === "follow-within-root"
|
|
158
|
-
?
|
|
159
|
-
:
|
|
159
|
+
? fsSync.statSync(filePath, { bigint: true })
|
|
160
|
+
: fsSync.lstatSync(filePath, { bigint: true });
|
|
160
161
|
if (pathStat.isSymbolicLink() && options?.symlinks !== "follow-within-root") {
|
|
161
162
|
throw new FsSafeError("symlink", "symlink not allowed");
|
|
162
163
|
}
|
|
163
164
|
return pathStat;
|
|
164
165
|
});
|
|
165
166
|
await fsSafeTestHooks?.afterOpenedPathIdentityCheck?.(filePath, handle);
|
|
166
|
-
const
|
|
167
|
+
const resolved = await resolveOpenedFileRealPathForFd(handle.fd, identity, filePath)
|
|
167
168
|
.catch(async (error) => {
|
|
168
169
|
if (stat.nlink <= 1 && (!preOpenStat || preOpenStat.nlink <= 1n)) {
|
|
169
170
|
await recordOpenedFileFailure(error, handle, filePath, identity);
|
|
170
171
|
}
|
|
171
172
|
throw error;
|
|
172
173
|
});
|
|
174
|
+
const { realPath } = resolved;
|
|
175
|
+
let resolvedStat = resolved.stat;
|
|
173
176
|
await inspectPathIdentity(async () => {
|
|
174
|
-
|
|
177
|
+
// Reuse the post-realpath observation; unknown Windows identities still
|
|
178
|
+
// get a fresh observation on inspectFileIdentity's retry.
|
|
179
|
+
const realStat = resolvedStat ?? fsSync.statSync(realPath, { bigint: true });
|
|
180
|
+
resolvedStat = undefined;
|
|
175
181
|
if (options?.hardlinks === "reject" && realStat.nlink > 1n) {
|
|
176
182
|
throw hardlinkedPathNotAllowedError();
|
|
177
183
|
}
|
|
@@ -269,6 +275,7 @@ export class RootHandle {
|
|
|
269
275
|
mkdir: this.defaults.mkdir,
|
|
270
276
|
mode: this.defaults.mode,
|
|
271
277
|
...this.mutationOptions(options),
|
|
278
|
+
durable: options.durable ?? this.defaults.durable ?? true,
|
|
272
279
|
});
|
|
273
280
|
}
|
|
274
281
|
async remove(relativePath, options = {}) {
|
|
@@ -301,6 +308,7 @@ export class RootHandle {
|
|
|
301
308
|
mode: this.defaults.mode,
|
|
302
309
|
renameIdentity: this.defaults.renameIdentity,
|
|
303
310
|
...this.mutationOptions(options),
|
|
311
|
+
durable: options.durable ?? this.defaults.durable ?? true,
|
|
304
312
|
});
|
|
305
313
|
}
|
|
306
314
|
async create(relativePath, data, options = {}) {
|
|
@@ -311,6 +319,7 @@ export class RootHandle {
|
|
|
311
319
|
mkdir: this.defaults.mkdir,
|
|
312
320
|
mode: this.defaults.mode,
|
|
313
321
|
...this.mutationOptions(options),
|
|
322
|
+
durable: options.durable ?? this.defaults.durable ?? true,
|
|
314
323
|
overwrite: false,
|
|
315
324
|
});
|
|
316
325
|
}
|
|
@@ -384,7 +393,6 @@ function readDefaults(defaults) {
|
|
|
384
393
|
return {
|
|
385
394
|
hardlinks: defaults.hardlinks,
|
|
386
395
|
maxBytes: normalizeMaxBytes(defaults.maxBytes, { defaultValue: DEFAULT_ROOT_MAX_BYTES }),
|
|
387
|
-
nonBlockingRead: defaults.nonBlockingRead,
|
|
388
396
|
symlinks: defaults.symlinks,
|
|
389
397
|
};
|
|
390
398
|
}
|
|
@@ -393,8 +401,6 @@ function mergeReadOptions(defaults, options) {
|
|
|
393
401
|
if (options.hardlinks !== undefined)
|
|
394
402
|
merged.hardlinks = options.hardlinks;
|
|
395
403
|
merged.maxBytes = normalizeMaxBytes(options.maxBytes, { defaultValue: merged.maxBytes });
|
|
396
|
-
if (options.nonBlockingRead !== undefined)
|
|
397
|
-
merged.nonBlockingRead = options.nonBlockingRead;
|
|
398
404
|
if (options.symlinks !== undefined)
|
|
399
405
|
merged.symlinks = options.symlinks;
|
|
400
406
|
return merged;
|
|
@@ -410,7 +416,6 @@ async function openFileInRoot(root, params) {
|
|
|
410
416
|
rejectSymlinks: params.symlinks !== "follow-within-root",
|
|
411
417
|
});
|
|
412
418
|
const { opened } = await openVerifiedLocalFile(resolved, {
|
|
413
|
-
nonBlockingRead: params.nonBlockingRead,
|
|
414
419
|
symlinks: params.symlinks,
|
|
415
420
|
});
|
|
416
421
|
if (params.hardlinks !== "allow" && opened.stat.nlink > 1) {
|
|
@@ -438,7 +443,6 @@ async function readPathInRoot(root, params) {
|
|
|
438
443
|
relativePath,
|
|
439
444
|
hardlinks: params.hardlinks,
|
|
440
445
|
maxBytes: params.maxBytes,
|
|
441
|
-
nonBlockingRead: params.nonBlockingRead,
|
|
442
446
|
symlinks: params.symlinks,
|
|
443
447
|
});
|
|
444
448
|
}
|
|
@@ -485,7 +489,7 @@ async function writeTempFileForAtomicReplace(params) {
|
|
|
485
489
|
}
|
|
486
490
|
return {
|
|
487
491
|
handle: tempHandle,
|
|
488
|
-
identity:
|
|
492
|
+
identity: fsSync.fstatSync(tempHandle.fd, { bigint: true }),
|
|
489
493
|
};
|
|
490
494
|
}
|
|
491
495
|
catch (error) {
|
|
@@ -524,7 +528,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
524
528
|
? resolved
|
|
525
529
|
: await prepareRootWriteTarget(rootReal, resolved);
|
|
526
530
|
try {
|
|
527
|
-
const resolvedRealPath =
|
|
531
|
+
const resolvedRealPath = fsSync.realpathSync.native(ioPath);
|
|
528
532
|
if (!isPathInside(rootWithSep, resolvedRealPath)) {
|
|
529
533
|
throw outsideWorkspaceError();
|
|
530
534
|
}
|
|
@@ -573,7 +577,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
573
577
|
let realPathForCleanup = null;
|
|
574
578
|
let createdIdentity = null;
|
|
575
579
|
try {
|
|
576
|
-
const stat =
|
|
580
|
+
const stat = fsSync.fstatSync(handle.fd);
|
|
577
581
|
if (createdForWrite) {
|
|
578
582
|
createdIdentity = stat;
|
|
579
583
|
}
|
|
@@ -584,7 +588,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
584
588
|
throw hardlinkedPathNotAllowedError();
|
|
585
589
|
}
|
|
586
590
|
try {
|
|
587
|
-
const lstat =
|
|
591
|
+
const lstat = fsSync.lstatSync(ioPath);
|
|
588
592
|
if (lstat.isSymbolicLink() || !lstat.isFile()) {
|
|
589
593
|
throw new FsSafeError(lstat.isSymbolicLink() ? "symlink" : "not-file", "path is not a regular file under root");
|
|
590
594
|
}
|
|
@@ -599,7 +603,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
599
603
|
}
|
|
600
604
|
const realPath = await resolveOpenedFileRealPathForHandle(handle, ioPath);
|
|
601
605
|
realPathForCleanup = realPath;
|
|
602
|
-
const realStat =
|
|
606
|
+
const realStat = fsSync.statSync(realPath);
|
|
603
607
|
if (!sameFileIdentity(stat, realStat)) {
|
|
604
608
|
throw new FsSafeError("path-mismatch", "path mismatch");
|
|
605
609
|
}
|
|
@@ -662,8 +666,9 @@ async function appendFileInRoot(root, params) {
|
|
|
662
666
|
const payload = prefix.length > 0 ? Buffer.concat([Buffer.from(prefix, "utf8"), params.data]) : params.data;
|
|
663
667
|
await target.handle.appendFile(payload);
|
|
664
668
|
}
|
|
665
|
-
|
|
666
|
-
|
|
669
|
+
if (params.durable !== false)
|
|
670
|
+
await target.handle.sync();
|
|
671
|
+
if (params.durable !== false && target.createdForWrite) {
|
|
667
672
|
await syncDirectoryBestEffort(path.dirname(target.realPath));
|
|
668
673
|
}
|
|
669
674
|
}
|
|
@@ -719,6 +724,7 @@ async function commitPinnedWriteInRoot(root, pinned, params) {
|
|
|
719
724
|
renameIdentity: params.renameIdentity,
|
|
720
725
|
mkdir: params.mkdir !== false,
|
|
721
726
|
mode: params.mode ?? pinned.mode,
|
|
727
|
+
sync: params.durable !== false,
|
|
722
728
|
overwrite: params.overwrite,
|
|
723
729
|
input: { kind: "buffer", data: params.data, encoding: params.encoding },
|
|
724
730
|
rootIdentity: root.rootIdentity,
|
|
@@ -802,12 +808,12 @@ async function copyFileInRoot(root, params) {
|
|
|
802
808
|
}
|
|
803
809
|
}
|
|
804
810
|
async function assertCopySourceCurrent(source, identity) {
|
|
805
|
-
await inspectFileIdentity(() => source.handle.
|
|
811
|
+
await inspectFileIdentity(() => fsSync.fstatSync(source.handle.fd, { bigint: true }), identity);
|
|
806
812
|
await assertCopySourcePathCurrent(source, identity);
|
|
807
813
|
}
|
|
808
814
|
async function assertCopySourcePathCurrent(source, identity) {
|
|
809
815
|
await inspectFileIdentity(async () => {
|
|
810
|
-
const current =
|
|
816
|
+
const current = fsSync.lstatSync(source.realPath, { bigint: true });
|
|
811
817
|
if (current.isSymbolicLink() || !current.isFile()) {
|
|
812
818
|
throw new FsSafeError("path-mismatch", "copy source path changed");
|
|
813
819
|
}
|
|
@@ -816,7 +822,7 @@ async function assertCopySourcePathCurrent(source, identity) {
|
|
|
816
822
|
}
|
|
817
823
|
async function removePathIfIdentityUnchanged(targetPath, identity) {
|
|
818
824
|
const parentGuard = await createAsyncDirectoryGuard(path.dirname(targetPath));
|
|
819
|
-
const current =
|
|
825
|
+
const current = fsSync.lstatSync(targetPath);
|
|
820
826
|
if (current.isSymbolicLink() || !sameFileIdentityForCleanup(current, identity)) {
|
|
821
827
|
return;
|
|
822
828
|
}
|
|
@@ -846,7 +852,7 @@ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode,
|
|
|
846
852
|
// and alias checks, but never open a competing owner's record just to reject it.
|
|
847
853
|
if (!overwrite) {
|
|
848
854
|
try {
|
|
849
|
-
const existing =
|
|
855
|
+
const existing = fsSync.statSync(resolved);
|
|
850
856
|
if (!existing.isFile())
|
|
851
857
|
throw new FsSafeError("not-file", "not a file");
|
|
852
858
|
if (existing.nlink > 1)
|
|
@@ -858,31 +864,9 @@ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode,
|
|
|
858
864
|
throw error;
|
|
859
865
|
}
|
|
860
866
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
const opened = await openFileInRoot(root, {
|
|
865
|
-
relativePath,
|
|
866
|
-
hardlinks: "reject",
|
|
867
|
-
nonBlockingRead: true,
|
|
868
|
-
symlinks: "follow-within-root",
|
|
869
|
-
});
|
|
870
|
-
try {
|
|
871
|
-
mode = requestedMode ?? (opened.stat.mode & 0o777);
|
|
872
|
-
if (!isPathInside(rootWithSep, opened.realPath)) {
|
|
873
|
-
throw outsideWorkspaceError();
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
finally {
|
|
877
|
-
await opened.handle.close().catch(() => { });
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
catch (err) {
|
|
882
|
-
if (!(err instanceof FsSafeError) || err.code !== "not-found") {
|
|
883
|
-
throw err;
|
|
884
|
-
}
|
|
885
|
-
}
|
|
867
|
+
const mode = overwrite
|
|
868
|
+
? await inheritWriteTargetMode({ targetPath: resolved, rootWithSep, requestedMode })
|
|
869
|
+
: requestedMode ?? 0o600;
|
|
886
870
|
return {
|
|
887
871
|
rootReal,
|
|
888
872
|
targetPath: resolved,
|
|
@@ -966,7 +950,7 @@ async function prepareRemoveGuard(targetPath) {
|
|
|
966
950
|
async function removePathFallback(resolved) {
|
|
967
951
|
const guard = await prepareRemoveGuard(resolved.resolved);
|
|
968
952
|
try {
|
|
969
|
-
await (
|
|
953
|
+
await (fsSync.lstatSync(resolved.resolved).isDirectory() ? fs.rmdir(resolved.resolved) : fs.rm(resolved.resolved));
|
|
970
954
|
}
|
|
971
955
|
catch (error) {
|
|
972
956
|
throw normalizeRemovePathError(error);
|
|
@@ -982,7 +966,7 @@ async function mkdirPathFallback(resolved) {
|
|
|
982
966
|
async function statPathFallback(root, relativePath) {
|
|
983
967
|
const resolved = await resolvePinnedPathInRoot(root, { relativePath, allowRoot: true });
|
|
984
968
|
try {
|
|
985
|
-
const stat = pathStatFromStats(
|
|
969
|
+
const stat = pathStatFromStats(fsSync.lstatSync(resolved.resolved));
|
|
986
970
|
await assertRootIdentityCurrent(root);
|
|
987
971
|
return stat;
|
|
988
972
|
}
|
|
@@ -1006,7 +990,7 @@ async function listPathFallback(root, relativePath, withFileTypes) {
|
|
|
1006
990
|
for (const name of sortedNames) {
|
|
1007
991
|
entries.push({
|
|
1008
992
|
name,
|
|
1009
|
-
...pathStatFromStats(
|
|
993
|
+
...pathStatFromStats(fsSync.lstatSync(path.join(resolved.resolved, name))),
|
|
1010
994
|
});
|
|
1011
995
|
}
|
|
1012
996
|
await assertRootIdentityCurrent(root);
|
|
@@ -1055,7 +1039,11 @@ async function movePathFallback(root, params) {
|
|
|
1055
1039
|
relativePath: params.toRelative,
|
|
1056
1040
|
policy: PATH_ALIAS_POLICIES.unlinkTarget,
|
|
1057
1041
|
});
|
|
1058
|
-
|
|
1042
|
+
let targetStat;
|
|
1043
|
+
try {
|
|
1044
|
+
targetStat = fsSync.lstatSync(resolvedTarget.resolved);
|
|
1045
|
+
}
|
|
1046
|
+
catch { /* Advisory lookup. */ }
|
|
1059
1047
|
return !(process.platform !== "win32" &&
|
|
1060
1048
|
params.overwrite &&
|
|
1061
1049
|
targetStat?.isSymbolicLink() === true);
|
|
@@ -1063,7 +1051,7 @@ async function movePathFallback(root, params) {
|
|
|
1063
1051
|
});
|
|
1064
1052
|
let sourceStat;
|
|
1065
1053
|
try {
|
|
1066
|
-
sourceStat =
|
|
1054
|
+
sourceStat = fsSync.lstatSync(source.resolved);
|
|
1067
1055
|
}
|
|
1068
1056
|
catch (error) {
|
|
1069
1057
|
if (isNotFoundPathError(error)) {
|
|
@@ -1082,7 +1070,7 @@ async function movePathFallback(root, params) {
|
|
|
1082
1070
|
}
|
|
1083
1071
|
if (!params.overwrite) {
|
|
1084
1072
|
try {
|
|
1085
|
-
|
|
1073
|
+
fsSync.lstatSync(target.resolved);
|
|
1086
1074
|
throw new FsSafeError("already-exists", "destination exists");
|
|
1087
1075
|
}
|
|
1088
1076
|
catch (error) {
|
|
@@ -1192,8 +1180,8 @@ async function writeMissingFileFallback(root, params) {
|
|
|
1192
1180
|
const handle = await fs.open(targetPath, OPEN_WRITE_CREATE_FLAGS, params.mode ?? 0o600).catch((error) => recordExclusiveCreateFailure(error, targetPath));
|
|
1193
1181
|
created = true;
|
|
1194
1182
|
try {
|
|
1195
|
-
createdIdentity =
|
|
1196
|
-
const writtenStat =
|
|
1183
|
+
createdIdentity = fsSync.fstatSync(handle.fd);
|
|
1184
|
+
const writtenStat = fsSync.fstatSync(handle.fd, { bigint: true });
|
|
1197
1185
|
if (typeof params.data === "string") {
|
|
1198
1186
|
await handle.writeFile(params.data, params.encoding ?? "utf8");
|
|
1199
1187
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-path-existing.d.ts","sourceRoot":"","sources":["../src/root-path-existing.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-path-existing.d.ts","sourceRoot":"","sources":["../src/root-path-existing.ts"],"names":[],"mappings":"AAoBA,wBAAsB,8BAA8B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BxF;AAED,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA0B7E"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import fsp from "node:fs/promises";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { isNotFoundPathError } from "./path.js";
|
|
5
4
|
function isFilesystemRoot(candidate) {
|
|
@@ -7,7 +6,7 @@ function isFilesystemRoot(candidate) {
|
|
|
7
6
|
}
|
|
8
7
|
async function pathExists(targetPath) {
|
|
9
8
|
try {
|
|
10
|
-
|
|
9
|
+
fs.lstatSync(targetPath);
|
|
11
10
|
return true;
|
|
12
11
|
}
|
|
13
12
|
catch (error) {
|
|
@@ -33,7 +32,7 @@ export async function resolvePathViaExistingAncestor(targetPath) {
|
|
|
33
32
|
return normalized;
|
|
34
33
|
}
|
|
35
34
|
try {
|
|
36
|
-
const resolvedAncestor = path.resolve(
|
|
35
|
+
const resolvedAncestor = path.resolve(fs.realpathSync.native(cursor));
|
|
37
36
|
return missingSuffix.length === 0
|
|
38
37
|
? resolvedAncestor
|
|
39
38
|
: path.resolve(resolvedAncestor, ...missingSuffix);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-path-symlink.d.ts","sourceRoot":"","sources":["../src/root-path-symlink.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-path-symlink.d.ts","sourceRoot":"","sources":["../src/root-path-symlink.ts"],"names":[],"mappings":"AASA,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAiBF,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,MAAM,CAQR"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import fsp from "node:fs/promises";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { FsSafeError } from "./errors.js";
|
|
5
4
|
import { isNotFoundPathError, isSymlinkOpenError } from "./path.js";
|
|
@@ -16,11 +15,11 @@ function normalizeSymlinkResolutionError(error, options) {
|
|
|
16
15
|
}
|
|
17
16
|
export async function resolveSymlinkHopPath(symlinkPath, options = {}) {
|
|
18
17
|
try {
|
|
19
|
-
return path.resolve(
|
|
18
|
+
return path.resolve(fs.realpathSync.native(symlinkPath));
|
|
20
19
|
}
|
|
21
20
|
catch (error) {
|
|
22
21
|
normalizeSymlinkResolutionError(error, options);
|
|
23
|
-
const linkTarget =
|
|
22
|
+
const linkTarget = fs.readlinkSync(symlinkPath);
|
|
24
23
|
return resolvePathViaExistingAncestor(path.resolve(path.dirname(symlinkPath), linkTarget));
|
|
25
24
|
}
|
|
26
25
|
}
|
package/dist/root-path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-path.d.ts","sourceRoot":"","sources":["../src/root-path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-path.d.ts","sourceRoot":"","sources":["../src/root-path.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,kCAAkC,EAAE,MAAM,yBAAyB,CAAC;AAE7E,KAAK,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,wBAAwB;aACnC,MAAM;;;;aAIN,YAAY;;;;CAIJ,CAAC;AAEX,KAAK,qBAAqB,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,oBAAoB,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAEnF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,oBAAoB,CAAC;CAC5B,CAAC;AAEF,wBAAsB,eAAe,CACnC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAM3B;AAsCD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,gBAAgB,CAMnF"}
|