@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
|
@@ -111,7 +111,7 @@ async function observeOwnedAliasUnlink(sourcePath, group) {
|
|
|
111
111
|
function mergeCleanupResults(a, b) {
|
|
112
112
|
return a === "stale" || b === "stale" ? "stale" : "removed";
|
|
113
113
|
}
|
|
114
|
-
export async function cleanupCopiedEntry(sourcePath, manifest, state) {
|
|
114
|
+
export async function cleanupCopiedEntry(sourcePath, manifest, state, assertBeforeMutation) {
|
|
115
115
|
const aliasGroup = manifest.kind === "leaf" ? state.aliasGroups.get(identityKey(manifest)) : undefined;
|
|
116
116
|
if (aliasGroup?.stale) {
|
|
117
117
|
return "stale";
|
|
@@ -134,8 +134,9 @@ export async function cleanupCopiedEntry(sourcePath, manifest, state) {
|
|
|
134
134
|
// clean manifest children so the fallback does not duplicate copied files.
|
|
135
135
|
let result = "removed";
|
|
136
136
|
for (const child of manifest.children) {
|
|
137
|
-
result = mergeCleanupResults(result, await cleanupCopiedEntry(path.join(sourcePath, child.name), child.manifest, state));
|
|
137
|
+
result = mergeCleanupResults(result, await cleanupCopiedEntry(path.join(sourcePath, child.name), child.manifest, state, assertBeforeMutation));
|
|
138
138
|
}
|
|
139
|
+
assertBeforeMutation();
|
|
139
140
|
try {
|
|
140
141
|
await fs.rmdir(sourcePath);
|
|
141
142
|
}
|
|
@@ -152,6 +153,7 @@ export async function cleanupCopiedEntry(sourcePath, manifest, state) {
|
|
|
152
153
|
if (!sameIdentity(expected, entryIdentity(currentStat))) {
|
|
153
154
|
return aliasGroup ? poisonAliasGroup(aliasGroup) : "stale";
|
|
154
155
|
}
|
|
156
|
+
assertBeforeMutation();
|
|
155
157
|
await fs.unlink(sourcePath);
|
|
156
158
|
return aliasGroup
|
|
157
159
|
? await observeOwnedAliasUnlink(sourcePath, aliasGroup)
|
package/dist/move-path.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
export type MovePathPublicationReceipt = Readonly<{
|
|
2
|
+
path: string;
|
|
3
|
+
dev: bigint;
|
|
4
|
+
ino: bigint;
|
|
5
|
+
}>;
|
|
1
6
|
export type MovePathWithCopyFallbackOptions = {
|
|
7
|
+
/** Rechecks authority before each rename and copied-source unlink/rmdir dispatch. */
|
|
8
|
+
assertBeforeMutation?: () => void;
|
|
2
9
|
/** Rechecks caller authority synchronously immediately before each rename dispatch. */
|
|
3
10
|
assertBeforeRename?: () => void;
|
|
11
|
+
/** Reports the committed destination before post-rename checks or source cleanup. */
|
|
12
|
+
onDestinationPublished?: (receipt: MovePathPublicationReceipt) => void;
|
|
4
13
|
from: string;
|
|
5
14
|
sourceHardlinks?: "allow" | "reject";
|
|
6
15
|
to: string;
|
package/dist/move-path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,+BAA+B,GAAG;IAC5C,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,KAAK,sBAAsB,GAAG,cAAc,GAAG,uBAAuB,CAAC;AAEvE,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,sBAAsB,GAAG,SAAS,CASpC;
|
|
1
|
+
{"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAAC;AAEH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,KAAK,sBAAsB,GAAG,cAAc,GAAG,uBAAuB,CAAC;AAEvE,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,sBAAsB,GAAG,SAAS,CASpC;AAsPD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CAqHf"}
|
package/dist/move-path.js
CHANGED
|
@@ -211,24 +211,49 @@ async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
|
211
211
|
});
|
|
212
212
|
return { ...identity, kind: "leaf" };
|
|
213
213
|
}
|
|
214
|
+
function assertSynchronousResult(returned, name) {
|
|
215
|
+
if (returned !== undefined) {
|
|
216
|
+
// TypeScript permits async functions for () => void; consume their rejection.
|
|
217
|
+
void Promise.resolve(returned).catch(() => { });
|
|
218
|
+
throw new TypeError(`${name} must return undefined synchronously`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
214
221
|
export async function movePathWithCopyFallback(options) {
|
|
215
|
-
// Keep the initiating owner's
|
|
216
|
-
const
|
|
222
|
+
// Keep the initiating owner's callbacks across preparation and copy fallback.
|
|
223
|
+
const callerRenameAssert = options.assertBeforeRename;
|
|
224
|
+
const callerMutationAssert = options.assertBeforeMutation;
|
|
225
|
+
const callerPublished = options.onDestinationPublished;
|
|
217
226
|
let assertionRejected = false;
|
|
227
|
+
let destinationPublished = false;
|
|
228
|
+
const assertBeforeMutation = () => {
|
|
229
|
+
assertSynchronousResult(callerMutationAssert?.(), "assertBeforeMutation");
|
|
230
|
+
};
|
|
218
231
|
const assertBeforeRename = () => {
|
|
219
232
|
try {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// TypeScript permits async functions for () => void; they cannot authorize a rename.
|
|
223
|
-
void Promise.resolve(returned).catch(() => { });
|
|
224
|
-
throw new TypeError("assertBeforeRename must return undefined synchronously");
|
|
225
|
-
}
|
|
233
|
+
assertSynchronousResult(callerRenameAssert?.(), "assertBeforeRename");
|
|
234
|
+
assertBeforeMutation();
|
|
226
235
|
}
|
|
227
236
|
catch (error) {
|
|
228
237
|
assertionRejected = true;
|
|
229
238
|
throw error;
|
|
230
239
|
}
|
|
231
240
|
};
|
|
241
|
+
let publicationReceipt;
|
|
242
|
+
const onSourceInspected = callerPublished
|
|
243
|
+
? (identity) => {
|
|
244
|
+
publicationReceipt = Object.freeze({
|
|
245
|
+
path: targetPath,
|
|
246
|
+
dev: identity.dev,
|
|
247
|
+
ino: identity.ino,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
: undefined;
|
|
251
|
+
const onRenamed = () => {
|
|
252
|
+
destinationPublished = true;
|
|
253
|
+
if (publicationReceipt) {
|
|
254
|
+
assertSynchronousResult(callerPublished?.(publicationReceipt), "onDestinationPublished");
|
|
255
|
+
}
|
|
256
|
+
};
|
|
232
257
|
const sourcePath = path.resolve(options.from);
|
|
233
258
|
const targetPath = path.resolve(options.to);
|
|
234
259
|
const rejectHardlinks = options.sourceHardlinks === "reject";
|
|
@@ -237,12 +262,18 @@ export async function movePathWithCopyFallback(options) {
|
|
|
237
262
|
}
|
|
238
263
|
if (!rejectHardlinks) {
|
|
239
264
|
try {
|
|
240
|
-
await guardedRename({
|
|
265
|
+
await guardedRename({
|
|
266
|
+
from: sourcePath,
|
|
267
|
+
to: targetPath,
|
|
268
|
+
assertBeforeRename,
|
|
269
|
+
onSourceInspected,
|
|
270
|
+
onRenamed,
|
|
271
|
+
});
|
|
241
272
|
return;
|
|
242
273
|
}
|
|
243
274
|
catch (error) {
|
|
244
275
|
// An owner's EXDEV/EPERM refusal is not permission to copy instead.
|
|
245
|
-
if (assertionRejected || !moveCopyFallbackReasonForRenameError(error)) {
|
|
276
|
+
if (assertionRejected || destinationPublished || !moveCopyFallbackReasonForRenameError(error)) {
|
|
246
277
|
throw error;
|
|
247
278
|
}
|
|
248
279
|
}
|
|
@@ -256,7 +287,6 @@ export async function movePathWithCopyFallback(options) {
|
|
|
256
287
|
const targetDir = path.dirname(targetPath);
|
|
257
288
|
const staged = path.join(targetDir, `.fs-safe-move-${process.pid}-${randomUUID()}.tmp`);
|
|
258
289
|
const unregisterStaged = registerTempPathForExit(staged, { recursive: true });
|
|
259
|
-
let stagedCommitted = false;
|
|
260
290
|
try {
|
|
261
291
|
const manifest = await copyEntryWithManifest(sourcePath, staged, {
|
|
262
292
|
sourceHardlinks: options.sourceHardlinks ?? "allow",
|
|
@@ -265,16 +295,23 @@ export async function movePathWithCopyFallback(options) {
|
|
|
265
295
|
const cleanupState = createCleanupCopiedEntryState(sourcePath, manifest);
|
|
266
296
|
unregisterStaged.setIdentity(await fs.lstat(staged, { bigint: true }));
|
|
267
297
|
await assertCopyDestinationOutsideSource(sourcePath, targetPath, manifest);
|
|
268
|
-
await guardedRename({
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
298
|
+
await guardedRename({
|
|
299
|
+
from: staged,
|
|
300
|
+
to: targetPath,
|
|
301
|
+
assertBeforeRename,
|
|
302
|
+
onSourceInspected,
|
|
303
|
+
onRenamed: () => {
|
|
304
|
+
unregisterStaged();
|
|
305
|
+
onRenamed();
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
const cleanupResult = await cleanupCopiedEntry(sourcePath, manifest, cleanupState, assertBeforeMutation);
|
|
272
309
|
if (cleanupResult === "stale") {
|
|
273
310
|
throw sourceChangedError(sourcePath);
|
|
274
311
|
}
|
|
275
312
|
}
|
|
276
313
|
finally {
|
|
277
|
-
if (!
|
|
314
|
+
if (!destinationPublished) {
|
|
278
315
|
try {
|
|
279
316
|
const stagedIdentity = await fs.lstat(staged, { bigint: true });
|
|
280
317
|
if (!stagedIdentity.isSymbolicLink())
|
package/dist/native-binding.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TarMeterLimits } from "./archive-limits.js";
|
|
2
|
+
import type { ArchiveMemberKind } from "./archive-plan.js";
|
|
2
3
|
export interface NativeFileHash {
|
|
3
4
|
bytes: number;
|
|
4
5
|
digest: string;
|
|
@@ -16,7 +17,7 @@ export interface NativeFileIdentity {
|
|
|
16
17
|
export interface NativeArchiveEntry {
|
|
17
18
|
index: number;
|
|
18
19
|
path: string;
|
|
19
|
-
kind:
|
|
20
|
+
kind: ArchiveMemberKind;
|
|
20
21
|
size: number;
|
|
21
22
|
mode: number;
|
|
22
23
|
}
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,5 +18,4 @@ export declare function removeNativeCreatedFileIfStillPinned(params: {
|
|
|
18
18
|
created?: BigIntStats;
|
|
19
19
|
}): void;
|
|
20
20
|
export declare function createNativeExclusiveFile(targetPath: string, mode: number): Promise<NativeFileHandle | undefined>;
|
|
21
|
-
export declare function syncNativeFileBestEffort(fd: number): void;
|
|
22
21
|
//# sourceMappingURL=native-operations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-operations.d.ts","sourceRoot":"","sources":["../src/native-operations.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAS5D;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,gBAAgB,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAsBD,wBAAgB,oCAAoC,CAAC,MAAM,EAAE;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,GAAG,IAAI,CAqBP;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAwDvC
|
|
1
|
+
{"version":3,"file":"native-operations.d.ts","sourceRoot":"","sources":["../src/native-operations.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAS5D;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,gBAAgB,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAsBD,wBAAgB,oCAAoC,CAAC,MAAM,EAAE;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,GAAG,IAAI,CAqBP;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAwDvC"}
|
|
@@ -130,13 +130,3 @@ export async function createNativeExclusiveFile(targetPath, mode) {
|
|
|
130
130
|
await parent.close().catch(() => undefined);
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
export function syncNativeFileBestEffort(fd) {
|
|
134
|
-
try {
|
|
135
|
-
fsSync.fsyncSync(fd);
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
if (error.code !== "EPERM") {
|
|
139
|
-
throw error;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-pinned-write-windows.d.ts","sourceRoot":"","sources":["../src/native-pinned-write-windows.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"native-pinned-write-windows.d.ts","sourceRoot":"","sources":["../src/native-pinned-write-windows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,KAAK,CAAC,EAC3C,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,KAAK,CAAC,GAC3C,OAAO,CAET;AAWD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAiF3B"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { syncFileBestEffortSync } from "./file-sync.js";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import fsSync, {} from "node:fs";
|
|
3
4
|
import { FsSafeError } from "./errors.js";
|
|
4
|
-
import { nativeOpenFlags, removeNativeCreatedFileIfStillPinned,
|
|
5
|
+
import { nativeOpenFlags, removeNativeCreatedFileIfStillPinned, writeNativeInput, } from "./native-operations.js";
|
|
5
6
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
6
7
|
export function sameNativeIdentity(left, right) {
|
|
7
8
|
return left.dev === right.dev && left.ino === right.ino;
|
|
@@ -34,7 +35,8 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
|
|
|
34
35
|
// reopenable until the published name has been identity-fenced.
|
|
35
36
|
fsSync.fchmodSync(tempFd, 0o600);
|
|
36
37
|
await writeNativeInput(tempFd, params.input, params.maxBytes);
|
|
37
|
-
|
|
38
|
+
if (params.sync !== false)
|
|
39
|
+
syncFileBestEffortSync(tempFd);
|
|
38
40
|
if (params.overwrite === false) {
|
|
39
41
|
binding.renameNoReplace(parentFd, tempName, parentFd, params.basename);
|
|
40
42
|
}
|
|
@@ -53,7 +55,8 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
|
|
|
53
55
|
// verifiable and so broader modes are never exposed before that fence.
|
|
54
56
|
try {
|
|
55
57
|
fsSync.fchmodSync(targetFd, params.mode);
|
|
56
|
-
|
|
58
|
+
if (params.sync !== false)
|
|
59
|
+
syncFileBestEffortSync(targetFd);
|
|
57
60
|
}
|
|
58
61
|
catch (error) {
|
|
59
62
|
closeWriteFd(targetFd);
|
|
@@ -66,7 +69,8 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
|
|
|
66
69
|
});
|
|
67
70
|
throw error;
|
|
68
71
|
}
|
|
69
|
-
|
|
72
|
+
if (params.sync !== false)
|
|
73
|
+
syncFileBestEffortSync(parentFd);
|
|
70
74
|
// Verification follows publication and final chmod, outside rollback handling.
|
|
71
75
|
await params.verifyPublished?.(targetFd, verificationIdentity, parentGuard);
|
|
72
76
|
completed = true;
|
|
@@ -103,13 +103,13 @@ export async function runPinnedWriteNative(binding, params) {
|
|
|
103
103
|
binding.mkdirBeneath(root.fd, params.relativeParentPath, 0o777);
|
|
104
104
|
}
|
|
105
105
|
parentFd = binding.openBeneath(root.fd, params.relativeParentPath, directoryFlags).fd;
|
|
106
|
-
const parentPath =
|
|
106
|
+
const parentPath = fsSync.realpathSync.native(params.relativeParentPath
|
|
107
107
|
? path.join(params.rootPath, ...params.relativeParentPath.split("/"))
|
|
108
108
|
: params.rootPath);
|
|
109
109
|
const directory = windows ? undefined : describeStagedDirectory(parentFd, parentPath);
|
|
110
110
|
const parentPathStat = exactRoot
|
|
111
111
|
? await inspectDirectoryIdentity(parentPath, inspectFileIdentitySync(() => fsSync.fstatSync(parentFd, { bigint: true })))
|
|
112
|
-
:
|
|
112
|
+
: fsSync.lstatSync(parentPath);
|
|
113
113
|
if (windows && !exactRoot) {
|
|
114
114
|
const parentIdentity = binding.fstatIdentity(parentFd);
|
|
115
115
|
if (parentPathStat.isSymbolicLink() || !sameNativeIdentity(parentPathStat, parentIdentity)) {
|
|
@@ -122,7 +122,7 @@ export async function runPinnedWriteNative(binding, params) {
|
|
|
122
122
|
const verificationGuard = { dir: parentPath, realPath: parentPath, stat: parentPathStat };
|
|
123
123
|
if (params.overwrite === false) {
|
|
124
124
|
try {
|
|
125
|
-
|
|
125
|
+
fsSync.lstatSync(path.join(parentPath, params.basename));
|
|
126
126
|
throw Object.assign(new Error("destination already exists"), { code: "EEXIST" });
|
|
127
127
|
}
|
|
128
128
|
catch (error) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DirectoryReceipt } from "./directory-durability.js";
|
|
1
2
|
import type { AnyAsyncDirectoryGuard } from "./directory-guard.js";
|
|
2
3
|
import type { FileIdentityStat } from "./file-identity.js";
|
|
3
4
|
import type { NativeBinding } from "./native-binding.js";
|
|
@@ -7,8 +8,8 @@ export type NativeStagingBinding = NativeBinding & Required<Pick<NativeBinding,
|
|
|
7
8
|
export declare function assertNativeStaging(binding: NativeBinding): asserts binding is NativeStagingBinding;
|
|
8
9
|
declare class NativeStagedFile implements StagedFile {
|
|
9
10
|
#private;
|
|
10
|
-
constructor(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], portableNames: boolean, publishedMode: number);
|
|
11
|
-
static create(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], input: PinnedWriteInput, mode: number, maxBytes?: number, portableNames?: boolean): Promise<NativeStagedFile>;
|
|
11
|
+
constructor(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], portableNames: boolean, publishedMode: number, sync: boolean);
|
|
12
|
+
static create(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], input: PinnedWriteInput, mode: number, maxBytes?: number, portableNames?: boolean, sync?: boolean): Promise<NativeStagedFile>;
|
|
12
13
|
static write(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], params: PinnedWriteParams, parentGuard: AnyAsyncDirectoryGuard): Promise<FileIdentityStat>;
|
|
13
14
|
get receipt(): StagedFileReceipt;
|
|
14
15
|
assertCurrent(): Promise<void>;
|
|
@@ -20,5 +21,11 @@ declare class NativeStagedFile implements StagedFile {
|
|
|
20
21
|
}
|
|
21
22
|
export declare const createNativeStage: (...args: Parameters<typeof NativeStagedFile.create>) => Promise<StagedFile>;
|
|
22
23
|
export declare const writeNativeStage: typeof NativeStagedFile.write;
|
|
23
|
-
export {};
|
|
24
|
+
export type { PublishedFileReceipt, StagedFile, StagedFileCleanupReceipt, StagedFileFailureDetails, StagedFilePublication, StagedFileReceipt, } from "./staged-file-types.js";
|
|
25
|
+
export declare function stageFileInDirectory(options: {
|
|
26
|
+
directory: string | DirectoryReceipt;
|
|
27
|
+
content: string | Uint8Array;
|
|
28
|
+
/** Published mode; the unpublished stage stays at 0600. Defaults to 0600. */
|
|
29
|
+
mode?: number;
|
|
30
|
+
}): Promise<StagedFile>;
|
|
24
31
|
//# sourceMappingURL=native-staged-file.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-staged-file.d.ts","sourceRoot":"","sources":["../src/native-staged-file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"native-staged-file.d.ts","sourceRoot":"","sources":["../src/native-staged-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAKlE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,EACV,wBAAwB,EAGxB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG,QAAQ,CAAC,IAAI,CAC9D,aAAa,EACb,kBAAkB,GAAG,mBAAmB,GAAG,kBAAkB,CAC9D,CAAC,CAAC;AAEH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,IAAI,oBAAoB,CAUnG;AA6BD,cAAM,gBAAiB,YAAW,UAAU;;IAW1C,YACE,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,OAAO,EAQd;IAGD,OAAa,MAAM,CACjB,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAEjB,aAAa,UAAO,EACpB,IAAI,UAAO,GACV,OAAO,CAAC,gBAAgB,CAAC,CAc3B;IAED,OAAa,KAAK,CAChB,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAU3B;IAED,IAAI,OAAO,IAAI,iBAAiB,CAK/B;IAoFK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnC;IAEK,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqD9F;IA6CK,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAMjD;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAO3C;CACF;AAED,eAAO,MAAM,iBAAiB,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,UAAU,CAClF,CAAC;AAC1B,eAAO,MAAM,gBAAgB,+BAAyB,CAAC;AAEvD,YAAY,EACV,oBAAoB,EAAE,UAAU,EAAE,wBAAwB,EAAE,wBAAwB,EACpF,qBAAqB,EAAE,iBAAiB,GACzC,MAAM,wBAAwB,CAAC;AAEhC,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACrC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,UAAU,CAAC,CAUtB"}
|
|
@@ -50,11 +50,13 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
50
50
|
var e = new Error(message);
|
|
51
51
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
52
|
});
|
|
53
|
+
import { requireNativeBinding } from "./native.js";
|
|
54
|
+
import { syncFileBestEffortSync } from "./file-sync.js";
|
|
53
55
|
import { randomUUID } from "node:crypto";
|
|
54
56
|
import fs from "node:fs";
|
|
55
57
|
import { FsSafeError } from "./errors.js";
|
|
56
|
-
import {
|
|
57
|
-
import { assertStagedDirectoryCurrent } from "./staged-directory.js";
|
|
58
|
+
import { writeNativeInput } from "./native-operations.js";
|
|
59
|
+
import { assertStagedDirectoryCurrent, openStagedDirectory } from "./staged-directory.js";
|
|
58
60
|
export function assertNativeStaging(binding) {
|
|
59
61
|
if ([
|
|
60
62
|
binding.createStagedFile,
|
|
@@ -90,23 +92,25 @@ class NativeStagedFile {
|
|
|
90
92
|
#directory;
|
|
91
93
|
#portableNames;
|
|
92
94
|
#publishedMode;
|
|
95
|
+
#sync;
|
|
93
96
|
#name = `.fs-safe-${randomUUID()}.tmp`;
|
|
94
97
|
#state = { status: "open", publication: NOT_PUBLISHED };
|
|
95
98
|
#receipt;
|
|
96
|
-
constructor(binding, parentFd, directory, portableNames, publishedMode) {
|
|
99
|
+
constructor(binding, parentFd, directory, portableNames, publishedMode, sync) {
|
|
97
100
|
this.#binding = binding;
|
|
98
101
|
this.#parentFd = parentFd;
|
|
99
102
|
this.#directory = directory;
|
|
100
103
|
this.#portableNames = portableNames;
|
|
101
104
|
this.#publishedMode = publishedMode;
|
|
105
|
+
this.#sync = sync;
|
|
102
106
|
}
|
|
103
107
|
// Takes ownership of parentFd, including all construction and preparation failures.
|
|
104
108
|
static async create(binding, parentFd, directory, input, mode, maxBytes,
|
|
105
109
|
// Public staging uses portable names; existing POSIX writes accept literal names.
|
|
106
|
-
portableNames = true) {
|
|
110
|
+
portableNames = true, sync = true) {
|
|
107
111
|
let staged;
|
|
108
112
|
try {
|
|
109
|
-
staged = new NativeStagedFile(binding, parentFd, directory, portableNames, mode);
|
|
113
|
+
staged = new NativeStagedFile(binding, parentFd, directory, portableNames, mode, sync);
|
|
110
114
|
}
|
|
111
115
|
catch (error) {
|
|
112
116
|
try {
|
|
@@ -125,7 +129,7 @@ class NativeStagedFile {
|
|
|
125
129
|
try {
|
|
126
130
|
// This owner never escapes. Only the internal verifier borrows its fd;
|
|
127
131
|
// public descriptor methods remain await-free and cannot race disposal.
|
|
128
|
-
const staged = __addDisposableResource(env_1, await NativeStagedFile.create(binding, parentFd, directory, params.input, params.mode, params.maxBytes, false), true);
|
|
132
|
+
const staged = __addDisposableResource(env_1, await NativeStagedFile.create(binding, parentFd, directory, params.input, params.mode, params.maxBytes, false, params.sync), true);
|
|
129
133
|
const published = await staged.publish(params.basename, { overwrite: params.overwrite !== false });
|
|
130
134
|
const identity = published.staged.identity;
|
|
131
135
|
await params.verifyPublished?.(staged.#file(), identity, parentGuard);
|
|
@@ -162,10 +166,12 @@ class NativeStagedFile {
|
|
|
162
166
|
}
|
|
163
167
|
#assertNamed(name) {
|
|
164
168
|
const fd = this.#file();
|
|
165
|
-
|
|
166
|
-
fs.fstatSync(fd, { bigint: true })
|
|
169
|
+
const stat = this.#binding.stagedFileMatches(this.#parentFd, name, fd)
|
|
170
|
+
? fs.fstatSync(fd, { bigint: true }) : undefined;
|
|
171
|
+
if (!stat || stat.nlink !== 1n) {
|
|
167
172
|
throw new FsSafeError("path-mismatch", "staged entry no longer names the exclusive created file");
|
|
168
173
|
}
|
|
174
|
+
return Number(stat.mode & 4095n);
|
|
169
175
|
}
|
|
170
176
|
#assertCurrent() {
|
|
171
177
|
if (this.#open().publication.status !== "not-published") {
|
|
@@ -188,7 +194,8 @@ class NativeStagedFile {
|
|
|
188
194
|
const fd = state.fileFd;
|
|
189
195
|
fs.fchmodSync(fd, 0o600);
|
|
190
196
|
await writeNativeInput(fd, input, maxBytes);
|
|
191
|
-
|
|
197
|
+
if (this.#sync)
|
|
198
|
+
syncFileBestEffortSync(fd);
|
|
192
199
|
const stat = fs.fstatSync(fd, { bigint: true });
|
|
193
200
|
this.#receipt = Object.freeze({
|
|
194
201
|
directory: this.#directory,
|
|
@@ -255,14 +262,21 @@ class NativeStagedFile {
|
|
|
255
262
|
overwrite,
|
|
256
263
|
});
|
|
257
264
|
state.publication = receipt;
|
|
258
|
-
this.#assertNamed(basename);
|
|
265
|
+
const stagedMode = this.#assertNamed(basename);
|
|
259
266
|
assertStagedDirectoryCurrent(this.#directory);
|
|
260
267
|
// Keep contents private until the published name passes its identity
|
|
261
268
|
// fence. Mode changes use the owned fd, including for final mode 000.
|
|
262
269
|
const fd = this.#file();
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
270
|
+
if (this.#publishedMode !== 0o600 || stagedMode !== 0o600)
|
|
271
|
+
fs.fchmodSync(fd, this.#publishedMode);
|
|
272
|
+
// With sync enabled, content was synced before rename. A lost chmod leaves staged 0600,
|
|
273
|
+
// no wider than modes retaining owner rw. Restrictive modes and observed
|
|
274
|
+
// widening of the stage still need the permission correction made durable.
|
|
275
|
+
if (this.#sync && ((this.#publishedMode & 0o600) !== 0o600 || (stagedMode & ~this.#publishedMode) !== 0)) {
|
|
276
|
+
syncFileBestEffortSync(fd);
|
|
277
|
+
}
|
|
278
|
+
if (this.#sync)
|
|
279
|
+
syncFileBestEffortSync(this.#parentFd);
|
|
266
280
|
this.#assertNamed(basename);
|
|
267
281
|
assertStagedDirectoryCurrent(this.#directory);
|
|
268
282
|
return receipt;
|
|
@@ -335,3 +349,14 @@ class NativeStagedFile {
|
|
|
335
349
|
}
|
|
336
350
|
export const createNativeStage = NativeStagedFile.create;
|
|
337
351
|
export const writeNativeStage = NativeStagedFile.write;
|
|
352
|
+
export async function stageFileInDirectory(options) {
|
|
353
|
+
if (process.platform !== "linux" && process.platform !== "darwin") {
|
|
354
|
+
throw new FsSafeError("unsupported-platform", "retained-directory staging requires Linux or macOS");
|
|
355
|
+
}
|
|
356
|
+
const binding = requireNativeBinding();
|
|
357
|
+
assertNativeStaging(binding);
|
|
358
|
+
const input = { kind: "buffer", data: Buffer.from(options.content) };
|
|
359
|
+
const mode = options.mode ?? 0o600;
|
|
360
|
+
const parent = openStagedDirectory(options.directory);
|
|
361
|
+
return await createNativeStage(binding, parent.fd, parent.receipt, input, mode);
|
|
362
|
+
}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
import type { BigIntStats, Stats } from "node:fs";
|
|
1
2
|
import type { FileHandle } from "node:fs/promises";
|
|
2
3
|
import { type FileIdentityStat } from "./file-identity.js";
|
|
3
4
|
export declare function resolveOpenedFileRealPathForHandle(handle: FileHandle, ioPath: string): Promise<string>;
|
|
4
|
-
export declare function resolveOpenedFileRealPathForFd(fd: number, handleStat:
|
|
5
|
+
export declare function resolveOpenedFileRealPathForFd(fd: number, handleStat: {
|
|
6
|
+
dev: bigint;
|
|
7
|
+
ino: bigint;
|
|
8
|
+
}, ioPath: string): Promise<{
|
|
9
|
+
realPath: string;
|
|
10
|
+
stat: BigIntStats;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function resolveOpenedFileRealPathForFd(fd: number, handleStat: FileIdentityStat, ioPath: string): Promise<{
|
|
13
|
+
realPath: string;
|
|
14
|
+
stat: Stats | BigIntStats;
|
|
15
|
+
}>;
|
|
5
16
|
//# sourceMappingURL=opened-realpath.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opened-realpath.d.ts","sourceRoot":"","sources":["../src/opened-realpath.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"opened-realpath.d.ts","sourceRoot":"","sources":["../src/opened-realpath.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG7E,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,EACV,UAAU,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACxC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC;AACpD,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,gBAAgB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,GAAG,WAAW,CAAA;CAAE,CAAC,CAAC"}
|
package/dist/opened-realpath.js
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
|
+
import fsSync from "node:fs";
|
|
1
2
|
import fs from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { openedPathResolutionError } from "./opened-file-failure.js";
|
|
4
5
|
import { sameFileIdentity } from "./file-identity.js";
|
|
5
6
|
import { isNotFoundPathError } from "./path.js";
|
|
6
7
|
export async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
|
|
7
|
-
const handleStat =
|
|
8
|
-
return await resolveOpenedFileRealPathForFd(handle.fd, handleStat, ioPath);
|
|
8
|
+
const handleStat = fsSync.fstatSync(handle.fd);
|
|
9
|
+
return (await resolveOpenedFileRealPathForFd(handle.fd, handleStat, ioPath)).realPath;
|
|
9
10
|
}
|
|
10
11
|
export async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
|
|
11
12
|
const statOptions = typeof handleStat.dev === "bigint" || typeof handleStat.ino === "bigint"
|
|
12
13
|
? { bigint: true } : undefined;
|
|
13
14
|
const fdCandidates = process.platform === "linux"
|
|
14
15
|
? [`/proc/self/fd/${fd}`, `/dev/fd/${fd}`]
|
|
15
|
-
:
|
|
16
|
-
? []
|
|
17
|
-
: [`/dev/fd/${fd}`];
|
|
16
|
+
: [];
|
|
18
17
|
for (const fdPath of fdCandidates) {
|
|
19
18
|
try {
|
|
20
|
-
const fdRealPath =
|
|
21
|
-
const fdRealStat = statOptions ?
|
|
19
|
+
const fdRealPath = fsSync.realpathSync.native(fdPath);
|
|
20
|
+
const fdRealStat = statOptions ? fsSync.statSync(fdRealPath, statOptions) : fsSync.statSync(fdRealPath);
|
|
22
21
|
if (sameFileIdentity(handleStat, fdRealStat)) {
|
|
23
|
-
return fdRealPath;
|
|
22
|
+
return { realPath: fdRealPath, stat: fdRealStat };
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
25
|
catch {
|
|
@@ -28,10 +27,10 @@ export async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
|
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
try {
|
|
31
|
-
const ioRealPath =
|
|
32
|
-
const ioRealStat = statOptions ?
|
|
30
|
+
const ioRealPath = fsSync.realpathSync.native(ioPath);
|
|
31
|
+
const ioRealStat = statOptions ? fsSync.statSync(ioRealPath, statOptions) : fsSync.statSync(ioRealPath);
|
|
33
32
|
if (sameFileIdentity(handleStat, ioRealStat)) {
|
|
34
|
-
return ioRealPath;
|
|
33
|
+
return { realPath: ioRealPath, stat: ioRealStat };
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
catch (err) {
|
|
@@ -54,7 +53,7 @@ export async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
|
|
|
54
53
|
async function resolveOpenedFileRealPathFromParent(handleStat, ioPath, statOptions) {
|
|
55
54
|
let parentReal;
|
|
56
55
|
try {
|
|
57
|
-
parentReal =
|
|
56
|
+
parentReal = fsSync.realpathSync.native(path.dirname(ioPath));
|
|
58
57
|
}
|
|
59
58
|
catch (err) {
|
|
60
59
|
if (isNotFoundPathError(err)) {
|
|
@@ -75,9 +74,12 @@ async function resolveOpenedFileRealPathFromParent(handleStat, ioPath, statOptio
|
|
|
75
74
|
for (const entry of entries.toSorted()) {
|
|
76
75
|
const candidatePath = path.join(parentReal, entry);
|
|
77
76
|
try {
|
|
78
|
-
const candidateStat = statOptions ?
|
|
77
|
+
const candidateStat = statOptions ? fsSync.lstatSync(candidatePath, statOptions) : fsSync.lstatSync(candidatePath);
|
|
79
78
|
if (candidateStat.isFile() && sameFileIdentity(handleStat, candidateStat)) {
|
|
80
|
-
|
|
79
|
+
const realPath = fsSync.realpathSync.native(candidatePath);
|
|
80
|
+
const stat = statOptions ? fsSync.statSync(realPath, statOptions) : fsSync.statSync(realPath);
|
|
81
|
+
if (sameFileIdentity(handleStat, stat))
|
|
82
|
+
return { realPath, stat };
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
catch (err) {
|
package/dist/output.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,wBAAwB,CAAC,CAAC,GAAG,IAAI,IAAI;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,IAAI,IAAI;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,CAAC;CACX,CAAC;AAyDF,wBAAsB,2BAA2B,CAAC,CAAC,GAAG,IAAI,EACxD,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACnC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAgDrC"}
|
package/dist/output.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { writeCallbackSibling } from "./sibling-staged-file.js";
|
|
1
3
|
import path from "node:path";
|
|
2
4
|
import { normalizeMaxBytes } from "./byte-budget.js";
|
|
3
5
|
import { FsSafeError } from "./errors.js";
|
|
4
|
-
import { sanitizeUntrustedFileName } from "./filename.js";
|
|
6
|
+
import { fitFileNameToPortableComponent, sanitizeUntrustedFileName } from "./filename.js";
|
|
5
7
|
import { isPathInside } from "./path.js";
|
|
6
|
-
import { writeExternalFileViaSibling } from "./output-sibling.js";
|
|
7
8
|
import { root } from "./root.js";
|
|
8
9
|
import { tempFile } from "./temp-target.js";
|
|
9
10
|
const NON_PORTABLE_FILE_NAME_CHARACTERS = /[\u0000-\u001f\u007f-\u009f<>:"/\\|?*]/u;
|
|
@@ -97,3 +98,26 @@ export async function writeExternalFileWithinRoot(options) {
|
|
|
97
98
|
await staged.cleanup();
|
|
98
99
|
}
|
|
99
100
|
}
|
|
101
|
+
function buildSiblingTempPath(targetPath, fallbackFileName) {
|
|
102
|
+
const prefix = `.fs-safe-output-${process.pid}-${randomUUID()}-`;
|
|
103
|
+
const suffix = ".part";
|
|
104
|
+
const safeTail = fitFileNameToPortableComponent({
|
|
105
|
+
prefix,
|
|
106
|
+
fileName: tempFileNameForTarget(targetPath, fallbackFileName),
|
|
107
|
+
suffix,
|
|
108
|
+
});
|
|
109
|
+
return path.join(path.dirname(targetPath), `${prefix}${safeTail}${suffix}`);
|
|
110
|
+
}
|
|
111
|
+
async function writeExternalFileViaSibling(params) {
|
|
112
|
+
const finalPath = path.resolve(params.finalPath);
|
|
113
|
+
const { result } = await writeCallbackSibling({
|
|
114
|
+
tempPath: buildSiblingTempPath(finalPath, params.fallbackFileName),
|
|
115
|
+
write: params.write,
|
|
116
|
+
resolveFinalPath: () => finalPath,
|
|
117
|
+
mode: params.mode,
|
|
118
|
+
maxBytes: params.maxBytes,
|
|
119
|
+
syncTempFile: true,
|
|
120
|
+
syncParentDir: true,
|
|
121
|
+
});
|
|
122
|
+
return result;
|
|
123
|
+
}
|
package/dist/path-policy.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import fs from "node:fs
|
|
1
|
+
import fs from "node:fs";
|
|
2
2
|
import { ROOT_PATH_ALIAS_POLICIES, resolveRootPath, } from "./root-path.js";
|
|
3
3
|
import { isNotFoundPathError } from "./path.js";
|
|
4
|
-
import { shortPath } from "./
|
|
4
|
+
import { shortPath } from "./error-detail.js";
|
|
5
5
|
export const PATH_ALIAS_POLICIES = ROOT_PATH_ALIAS_POLICIES;
|
|
6
6
|
export async function assertNoPathAliasEscape(params) {
|
|
7
7
|
const resolved = await resolveRootPath({
|
|
@@ -27,7 +27,7 @@ export async function assertNoHardlinkedFinalPath(params) {
|
|
|
27
27
|
}
|
|
28
28
|
let stat;
|
|
29
29
|
try {
|
|
30
|
-
stat =
|
|
30
|
+
stat = fs.statSync(params.filePath);
|
|
31
31
|
}
|
|
32
32
|
catch (err) {
|
|
33
33
|
if (isNotFoundPathError(err)) {
|
package/dist/permissions.d.ts
CHANGED
|
@@ -56,4 +56,5 @@ export declare function isWorldWritable(bits: number | null): boolean;
|
|
|
56
56
|
export declare function isGroupWritable(bits: number | null): boolean;
|
|
57
57
|
export declare function isWorldReadable(bits: number | null): boolean;
|
|
58
58
|
export declare function isGroupReadable(bits: number | null): boolean;
|
|
59
|
+
export declare function formatPosixMode(mode: number): string;
|
|
59
60
|
//# sourceMappingURL=permissions.d.ts.map
|