@openclaw/fs-safe 0.5.4 → 0.5.6
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 +16 -0
- package/dist/file-identity.d.ts +1 -0
- package/dist/file-identity.d.ts.map +1 -1
- package/dist/file-identity.js +19 -7
- package/dist/move-path.js +2 -2
- package/dist/native/darwin-arm64/fs-safe-native.node +0 -0
- package/dist/native/darwin-x64/fs-safe-native.node +0 -0
- package/dist/native/linux-arm64-gnu/fs-safe-native.node +0 -0
- package/dist/native/linux-arm64-musl/fs-safe-native.node +0 -0
- package/dist/native/linux-x64-gnu/fs-safe-native.node +0 -0
- package/dist/native/linux-x64-musl/fs-safe-native.node +0 -0
- package/dist/native/win32-x64-msvc/fs-safe-native.node +0 -0
- package/dist/native-operations.js +2 -2
- package/dist/output-sibling.js +3 -3
- package/dist/private-temp-workspace.d.ts.map +1 -1
- package/dist/private-temp-workspace.js +23 -15
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +2 -2
- package/dist/replace-file-descriptor.d.ts +3 -3
- package/dist/replace-file-descriptor.d.ts.map +1 -1
- package/dist/replace-file-descriptor.js +2 -2
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +9 -6
- package/dist/sibling-temp.js +1 -1
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +4 -1
- package/dist/temp-cleanup.d.ts.map +1 -1
- package/dist/temp-cleanup.js +3 -3
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +9 -7
- package/docs/sidecar-lock.md +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.6 - 2026-08-14
|
|
4
|
+
|
|
5
|
+
### Security and Correctness
|
|
6
|
+
|
|
7
|
+
- Treat asynchronous sidecar compromise-check I/O failures as a lost lock and invoke `onCompromised` once, instead of leaking an unhandled rejection from the interval.
|
|
8
|
+
- Preserve replaced temporary paths during Windows cleanup when libuv reports a zero device or inode or a file index exceeds JavaScript's safe integer range, treating unknown or rounded identity as fail-closed instead of authorizing deletion.
|
|
9
|
+
|
|
10
|
+
### Docs and Tooling
|
|
11
|
+
|
|
12
|
+
- Set up Node before pnpm when hydrating Crabbox runners so minimal images without a preinstalled npm can prepare the workspace.
|
|
13
|
+
## 0.5.5 - 2026-08-12
|
|
14
|
+
|
|
15
|
+
### Security and Correctness
|
|
16
|
+
|
|
17
|
+
- Prevent nondeterministic Windows read failures with `path-mismatch` when path-based stat reports zero file identity through libuv's FindFirstFile fallback under antivirus or indexer contention; zero Windows inodes are now treated as unknown identity like zero device serials.
|
|
18
|
+
|
|
3
19
|
## 0.5.4 - 2026-08-10
|
|
4
20
|
|
|
5
21
|
**Highlight:** two security fixes in the publication path. If you run fs-safe on
|
package/dist/file-identity.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ export type FileIdentityStat = {
|
|
|
4
4
|
};
|
|
5
5
|
export declare function sha256Hex(data: string | Buffer, encoding?: BufferEncoding): string;
|
|
6
6
|
export declare function sameFileIdentity(left: FileIdentityStat, right: FileIdentityStat, platform?: NodeJS.Platform): boolean;
|
|
7
|
+
export declare function sameFileIdentityForCleanup(left: FileIdentityStat, right: FileIdentityStat, platform?: NodeJS.Platform): boolean;
|
|
7
8
|
//# sourceMappingURL=file-identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-identity.d.ts","sourceRoot":"","sources":["../src/file-identity.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB,CAAC;
|
|
1
|
+
{"version":3,"file":"file-identity.d.ts","sourceRoot":"","sources":["../src/file-identity.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB,CAAC;AAsBF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAGlF;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAQT;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAWT"}
|
package/dist/file-identity.js
CHANGED
|
@@ -5,18 +5,30 @@ function isZero(value) {
|
|
|
5
5
|
function sameStatValue(left, right) {
|
|
6
6
|
return typeof left === typeof right ? left === right : BigInt(left) === BigInt(right);
|
|
7
7
|
}
|
|
8
|
+
function isStatValueProvablyDifferent(left, right, platform) {
|
|
9
|
+
if (sameStatValue(left, right)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return platform !== "win32" || (!isZero(left) && !isZero(right));
|
|
13
|
+
}
|
|
8
14
|
export function sha256Hex(data, encoding) {
|
|
9
15
|
const buffer = typeof data === "string" ? Buffer.from(data, encoding ?? "utf8") : data;
|
|
10
16
|
return createHash("sha256").update(buffer).digest("hex");
|
|
11
17
|
}
|
|
12
18
|
export function sameFileIdentity(left, right, platform = process.platform) {
|
|
13
|
-
|
|
19
|
+
// When Windows cannot open a path for stat, libuv's FindFirstFile fallback reports dev=0 and
|
|
20
|
+
// ino=0. Treating either unknown value as a mismatch caused nondeterministic path-mismatch
|
|
21
|
+
// failures on legitimate reads under antivirus or indexer contention.
|
|
22
|
+
return (!isStatValueProvablyDifferent(left.dev, right.dev, platform) &&
|
|
23
|
+
!isStatValueProvablyDifferent(left.ino, right.ino, platform));
|
|
24
|
+
}
|
|
25
|
+
export function sameFileIdentityForCleanup(left, right, platform = process.platform) {
|
|
26
|
+
// A zero Windows device or inode is unknown, not proof that a pathname still
|
|
27
|
+
// names the object we created. Cleanup must fail closed rather than delete a
|
|
28
|
+
// replacement that happens to share the known half of the identity.
|
|
29
|
+
if (platform === "win32" &&
|
|
30
|
+
(isZero(left.dev) || isZero(left.ino) || isZero(right.dev) || isZero(right.ino))) {
|
|
14
31
|
return false;
|
|
15
32
|
}
|
|
16
|
-
|
|
17
|
-
// reports a real volume serial; treat either-side dev=0 as "unknown device".
|
|
18
|
-
if (sameStatValue(left.dev, right.dev)) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
return platform === "win32" && (isZero(left.dev) || isZero(right.dev));
|
|
33
|
+
return sameStatValue(left.dev, right.dev) && sameStatValue(left.ino, right.ino);
|
|
22
34
|
}
|
package/dist/move-path.js
CHANGED
|
@@ -299,7 +299,7 @@ export async function movePathWithCopyFallback(options) {
|
|
|
299
299
|
sourceHardlinks: options.sourceHardlinks ?? "allow",
|
|
300
300
|
...(rejectHardlinks ? { budget: { discovered: 1 } } : {}),
|
|
301
301
|
});
|
|
302
|
-
unregisterStaged.setIdentity(await fs.lstat(staged));
|
|
302
|
+
unregisterStaged.setIdentity(await fs.lstat(staged, { bigint: true }));
|
|
303
303
|
await assertCopyDestinationOutsideSource(sourcePath, targetPath);
|
|
304
304
|
await guardedRename({ from: staged, to: targetPath });
|
|
305
305
|
stagedCommitted = true;
|
|
@@ -312,7 +312,7 @@ export async function movePathWithCopyFallback(options) {
|
|
|
312
312
|
finally {
|
|
313
313
|
if (!stagedCommitted) {
|
|
314
314
|
try {
|
|
315
|
-
const stagedIdentity = await fs.lstat(staged);
|
|
315
|
+
const stagedIdentity = await fs.lstat(staged, { bigint: true });
|
|
316
316
|
if (!stagedIdentity.isSymbolicLink())
|
|
317
317
|
unregisterStaged.setIdentity(stagedIdentity);
|
|
318
318
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fsSync, {} from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
5
5
|
import { getNativeBinding } from "./native.js";
|
|
6
6
|
function nativeOpenFlags(flags) {
|
|
7
7
|
const closeOnExec = fsSync.constants.O_CLOEXEC;
|
|
@@ -51,7 +51,7 @@ export function removeNativeCreatedFileIfStillPinned(params) {
|
|
|
51
51
|
parentPathStat.dev === parentFdStat.dev &&
|
|
52
52
|
parentPathStat.ino === parentFdStat.ino &&
|
|
53
53
|
!target.isSymbolicLink() &&
|
|
54
|
-
|
|
54
|
+
sameFileIdentityForCleanup(target, params.created)) {
|
|
55
55
|
fsSync.rmSync(targetPath);
|
|
56
56
|
}
|
|
57
57
|
}
|
package/dist/output-sibling.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
6
6
|
import { syncDirectoryBestEffort } from "./directory-durability.js";
|
|
7
7
|
import { FsSafeError } from "./errors.js";
|
|
8
|
-
import { sameFileIdentity } from "./file-identity.js";
|
|
8
|
+
import { sameFileIdentity, sameFileIdentityForCleanup } from "./file-identity.js";
|
|
9
9
|
import { withAsyncDirectoryGuards } from "./guarded-mutation.js";
|
|
10
10
|
import { sanitizeUntrustedFileName } from "./filename.js";
|
|
11
11
|
import { registerTempPathForExit } from "./temp-cleanup.js";
|
|
@@ -63,7 +63,7 @@ async function syncFile(handle) {
|
|
|
63
63
|
async function cleanupTempPath(tempPath, identity) {
|
|
64
64
|
try {
|
|
65
65
|
const current = await fs.lstat(tempPath);
|
|
66
|
-
if (!identity || (!current.isSymbolicLink() &&
|
|
66
|
+
if (!identity || (!current.isSymbolicLink() && sameFileIdentityForCleanup(current, identity))) {
|
|
67
67
|
await fs.rm(tempPath, { force: true });
|
|
68
68
|
}
|
|
69
69
|
return true;
|
|
@@ -84,7 +84,7 @@ export async function writeExternalFileViaSibling(params) {
|
|
|
84
84
|
const result = await params.write(tempPath);
|
|
85
85
|
const pinned = await openPinnedStagedFile(tempPath, params.maxBytes);
|
|
86
86
|
stagedIdentity = pinned.identity;
|
|
87
|
-
unregisterTempPath.setIdentity(
|
|
87
|
+
unregisterTempPath.setIdentity(await pinned.handle.stat({ bigint: true }));
|
|
88
88
|
try {
|
|
89
89
|
if (params.mode !== undefined) {
|
|
90
90
|
await pinned.handle.chmod(params.mode);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"private-temp-workspace.d.ts","sourceRoot":"","sources":["../src/private-temp-workspace.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAUzB,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,0BAA0B,GAAG,SAAS,GAAG,SAAS,GAAG,mBAAmB,CAAC;AAErF,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,uBAAuB,CAAC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GACtC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC/C,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,uBAAuB,CAAC;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IAC3D,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAClD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAAC;IAC5F,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,OAAO,IAAI,0BAA0B,CAAC;IACtC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B,CAAC;
|
|
1
|
+
{"version":3,"file":"private-temp-workspace.d.ts","sourceRoot":"","sources":["../src/private-temp-workspace.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAUzB,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,0BAA0B,GAAG,SAAS,GAAG,SAAS,GAAG,mBAAmB,CAAC;AAErF,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,uBAAuB,CAAC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GACtC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC/C,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,uBAAuB,CAAC;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IAC3D,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAClD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAAC;IAC5F,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,OAAO,IAAI,0BAA0B,CAAC;IACtC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B,CAAC;AA+KF,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,CAAC,CAExB;AAED,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,OAAO,EAAE,oBAAoB,EAC7B,GAAG,EAAE,CAAC,SAAS,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAC5C,OAAO,CAAC,CAAC,CAAC,CAUZ;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,oBAAoB,GAC5B,iBAAiB,CA8EnB;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,oBAAoB,EAC7B,GAAG,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,CAAC,GACvC,CAAC,CAUH"}
|
|
@@ -4,7 +4,7 @@ import fs from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileStore, fileStoreSync, } from "./file-store.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
|
-
import {
|
|
7
|
+
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
8
8
|
import { isNotFoundPathError } from "./path.js";
|
|
9
9
|
import { throwFsSafeReadError } from "./read-error.js";
|
|
10
10
|
import { matchRootFileOpenFailure, openRootFileSync, } from "./root-file.js";
|
|
@@ -82,12 +82,12 @@ function ensurePrivateDirectorySync(dir, mode) {
|
|
|
82
82
|
async function cleanupWorkspace(dir, identity) {
|
|
83
83
|
let current;
|
|
84
84
|
try {
|
|
85
|
-
current = await fs.lstat(dir);
|
|
85
|
+
current = await fs.lstat(dir, { bigint: true });
|
|
86
86
|
}
|
|
87
87
|
catch (error) {
|
|
88
88
|
return error.code === "ENOENT" ? "missing" : "identity-mismatch";
|
|
89
89
|
}
|
|
90
|
-
if (!
|
|
90
|
+
if (!sameFileIdentityForCleanup(current, identity)) {
|
|
91
91
|
return "identity-mismatch";
|
|
92
92
|
}
|
|
93
93
|
await fs.rm(dir, { recursive: true, force: true });
|
|
@@ -96,12 +96,12 @@ async function cleanupWorkspace(dir, identity) {
|
|
|
96
96
|
function cleanupWorkspaceSync(dir, identity) {
|
|
97
97
|
let current;
|
|
98
98
|
try {
|
|
99
|
-
current = fsSync.lstatSync(dir);
|
|
99
|
+
current = fsSync.lstatSync(dir, { bigint: true });
|
|
100
100
|
}
|
|
101
101
|
catch (error) {
|
|
102
102
|
return error.code === "ENOENT" ? "missing" : "identity-mismatch";
|
|
103
103
|
}
|
|
104
|
-
if (!
|
|
104
|
+
if (!sameFileIdentityForCleanup(current, identity)) {
|
|
105
105
|
return "identity-mismatch";
|
|
106
106
|
}
|
|
107
107
|
fsSync.rmSync(dir, { recursive: true, force: true });
|
|
@@ -115,12 +115,16 @@ async function createTempWorkspace(options) {
|
|
|
115
115
|
await ensurePrivateDirectory(root, dirMode);
|
|
116
116
|
const dir = await fs.mkdtemp(path.join(root, sanitizeTempPrefix(options.prefix)));
|
|
117
117
|
await fs.chmod(dir, dirMode).catch(() => undefined);
|
|
118
|
-
const stat = await fs.lstat(dir);
|
|
118
|
+
const stat = await fs.lstat(dir, { bigint: true });
|
|
119
119
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
120
120
|
throw new Error(`Temp workspace must be a directory: ${dir}`);
|
|
121
121
|
}
|
|
122
|
-
const identity = { dev: stat.dev, ino: stat.ino };
|
|
123
|
-
const
|
|
122
|
+
const identity = { dev: Number(stat.dev), ino: Number(stat.ino) };
|
|
123
|
+
const cleanupIdentity = { dev: stat.dev, ino: stat.ino };
|
|
124
|
+
const unregisterTempDir = registerTempPathForExit(dir, {
|
|
125
|
+
recursive: true,
|
|
126
|
+
identity: cleanupIdentity,
|
|
127
|
+
});
|
|
124
128
|
const store = fileStore({ rootDir: dir, private: true, dirMode, mode });
|
|
125
129
|
return {
|
|
126
130
|
dir,
|
|
@@ -144,7 +148,7 @@ async function createTempWorkspace(options) {
|
|
|
144
148
|
},
|
|
145
149
|
cleanup: async () => {
|
|
146
150
|
try {
|
|
147
|
-
return await cleanupWorkspace(dir,
|
|
151
|
+
return await cleanupWorkspace(dir, cleanupIdentity);
|
|
148
152
|
}
|
|
149
153
|
finally {
|
|
150
154
|
unregisterTempDir();
|
|
@@ -152,7 +156,7 @@ async function createTempWorkspace(options) {
|
|
|
152
156
|
},
|
|
153
157
|
[Symbol.asyncDispose]: async () => {
|
|
154
158
|
try {
|
|
155
|
-
await cleanupWorkspace(dir,
|
|
159
|
+
await cleanupWorkspace(dir, cleanupIdentity);
|
|
156
160
|
}
|
|
157
161
|
finally {
|
|
158
162
|
unregisterTempDir();
|
|
@@ -194,12 +198,16 @@ export function tempWorkspaceSync(options) {
|
|
|
194
198
|
catch {
|
|
195
199
|
// Best-effort on platforms that do not enforce POSIX modes.
|
|
196
200
|
}
|
|
197
|
-
const stat = fsSync.lstatSync(dir);
|
|
201
|
+
const stat = fsSync.lstatSync(dir, { bigint: true });
|
|
198
202
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
199
203
|
throw new Error(`Temp workspace must be a directory: ${dir}`);
|
|
200
204
|
}
|
|
201
|
-
const identity = { dev: stat.dev, ino: stat.ino };
|
|
202
|
-
const
|
|
205
|
+
const identity = { dev: Number(stat.dev), ino: Number(stat.ino) };
|
|
206
|
+
const cleanupIdentity = { dev: stat.dev, ino: stat.ino };
|
|
207
|
+
const unregisterTempDir = registerTempPathForExit(dir, {
|
|
208
|
+
recursive: true,
|
|
209
|
+
identity: cleanupIdentity,
|
|
210
|
+
});
|
|
203
211
|
const store = fileStoreSync({ rootDir: dir, private: true, dirMode, mode });
|
|
204
212
|
return {
|
|
205
213
|
dir,
|
|
@@ -236,7 +244,7 @@ export function tempWorkspaceSync(options) {
|
|
|
236
244
|
},
|
|
237
245
|
cleanup: () => {
|
|
238
246
|
try {
|
|
239
|
-
return cleanupWorkspaceSync(dir,
|
|
247
|
+
return cleanupWorkspaceSync(dir, cleanupIdentity);
|
|
240
248
|
}
|
|
241
249
|
finally {
|
|
242
250
|
unregisterTempDir();
|
|
@@ -244,7 +252,7 @@ export function tempWorkspaceSync(options) {
|
|
|
244
252
|
},
|
|
245
253
|
[Symbol.dispose]: () => {
|
|
246
254
|
try {
|
|
247
|
-
cleanupWorkspaceSync(dir,
|
|
255
|
+
cleanupWorkspaceSync(dir, cleanupIdentity);
|
|
248
256
|
}
|
|
249
257
|
finally {
|
|
250
258
|
unregisterTempDir();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,
|
|
1
|
+
{"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAML,KAAK,qCAAqC,EAC3C,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EACV,2BAA2B,EAC3B,wCAAwC,EACxC,kCAAkC,EAClC,gCAAgC,EAChC,qCAAqC,GACtC,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,4BAA4B,GACpC,cAAc,GACd,eAAe,GACf,kBAAkB,CAAC;AAEvB,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAkBF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE/D;AA2ND,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,gBAAgB,CAAC;IAC1C,QAAQ,EAAE,4BAA4B,CAAC;IACvC,aAAa,CAAC,EAAE,qCAAqC,CAAC;IACtD,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA4MtC"}
|
package/dist/publish-file.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { pinDirectory, } from "./directory-durability.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
7
|
import { hashFileHandle } from "./file-hash.js";
|
|
8
|
-
import { sameFileIdentity } from "./file-identity.js";
|
|
8
|
+
import { sameFileIdentity, sameFileIdentityForCleanup, } from "./file-identity.js";
|
|
9
9
|
import { syncNativeFileBestEffort } from "./native-operations.js";
|
|
10
10
|
import { getNativeBinding, requireNativeBinding } from "./native.js";
|
|
11
11
|
import { directorySyncFailure, publicationFailure, rememberCreatedTarget, } from "./publish-file-failure.js";
|
|
@@ -163,7 +163,7 @@ async function removeCreatedTargetIfUnchanged(targetPath, identity) {
|
|
|
163
163
|
}
|
|
164
164
|
try {
|
|
165
165
|
const current = await fs.lstat(targetPath, { bigint: true });
|
|
166
|
-
if (!current.isSymbolicLink() &&
|
|
166
|
+
if (!current.isSymbolicLink() && sameFileIdentityForCleanup(current, identity)) {
|
|
167
167
|
await fs.rm(targetPath);
|
|
168
168
|
return "removed";
|
|
169
169
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import syncFs, { type
|
|
1
|
+
import syncFs, { type BigIntStats } from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
type AsyncTempFileSystem = Pick<typeof fs, "lstat" | "open" | "writeFile">;
|
|
4
4
|
type SyncTempFileSystem = Pick<typeof syncFs, "closeSync" | "fstatSync" | "fsyncSync" | "lstatSync" | "openSync" | "writeFileSync">;
|
|
@@ -20,7 +20,7 @@ export declare function writeTempFile(params: {
|
|
|
20
20
|
content: string | Uint8Array;
|
|
21
21
|
mode: number;
|
|
22
22
|
sync: boolean;
|
|
23
|
-
}): Promise<
|
|
23
|
+
}): Promise<BigIntStats>;
|
|
24
24
|
export declare function writeTempFileSync(params: {
|
|
25
25
|
fsModule: SyncTempFileSystem;
|
|
26
26
|
tempPath: string;
|
|
@@ -28,6 +28,6 @@ export declare function writeTempFileSync(params: {
|
|
|
28
28
|
mode: number;
|
|
29
29
|
fchmodSync?: SyncFchmod;
|
|
30
30
|
sync: boolean;
|
|
31
|
-
}):
|
|
31
|
+
}): BigIntStats;
|
|
32
32
|
export {};
|
|
33
33
|
//# sourceMappingURL=replace-file-descriptor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace-file-descriptor.d.ts","sourceRoot":"","sources":["../src/replace-file-descriptor.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"replace-file-descriptor.d.ts","sourceRoot":"","sources":["../src/replace-file-descriptor.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,KAAK,WAAW,EAAc,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAuB,MAAM,kBAAkB,CAAC;AAIvD,KAAK,mBAAmB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC;AAC3E,KAAK,kBAAkB,GAAG,IAAI,CAC5B,OAAO,MAAM,EACb,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,eAAe,CACrF,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AA2B5D,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,GAAG,IAAI,CAcP;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,OAAO,CAAC,WAAW,CAAC,CAkBvB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,WAAW,CAkBd"}
|
|
@@ -67,7 +67,7 @@ export async function writeTempFile(params) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
return await handle.stat();
|
|
70
|
+
return await handle.stat({ bigint: true });
|
|
71
71
|
}
|
|
72
72
|
finally {
|
|
73
73
|
await handle.close();
|
|
@@ -88,7 +88,7 @@ export function writeTempFileSync(params) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
return params.fsModule.fstatSync(fd);
|
|
91
|
+
return params.fsModule.fstatSync(fd, { bigint: true });
|
|
92
92
|
}
|
|
93
93
|
finally {
|
|
94
94
|
params.fsModule.closeSync(fd);
|
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,
|
|
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
|
@@ -5,7 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard, createNearestExistingDirectoryGuard } from "./directory-guard.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
7
|
import { syncDirectoryBestEffort } from "./fsync.js";
|
|
8
|
-
import { sameFileIdentity } from "./file-identity.js";
|
|
8
|
+
import { sameFileIdentity, sameFileIdentityForCleanup, } from "./file-identity.js";
|
|
9
9
|
import { mkdirPathComponentsWithGuards } from "./guarded-mkdir.js";
|
|
10
10
|
import { withAsyncDirectoryGuards } from "./guarded-mutation.js";
|
|
11
11
|
import { assertMutationNotDenied, mergeDenyMutationPolicies, } from "./deny-mutations.js";
|
|
@@ -473,7 +473,10 @@ async function writeTempFileForAtomicReplace(params) {
|
|
|
473
473
|
else {
|
|
474
474
|
await tempHandle.writeFile(params.data);
|
|
475
475
|
}
|
|
476
|
-
return
|
|
476
|
+
return {
|
|
477
|
+
identity: await tempHandle.stat(),
|
|
478
|
+
cleanupIdentity: await tempHandle.stat({ bigint: true }),
|
|
479
|
+
};
|
|
477
480
|
}
|
|
478
481
|
finally {
|
|
479
482
|
await tempHandle.close().catch(() => { });
|
|
@@ -807,7 +810,7 @@ async function assertCopySourcePathCurrent(source) {
|
|
|
807
810
|
async function removePathIfIdentityUnchanged(targetPath, identity) {
|
|
808
811
|
const parentGuard = await createAsyncDirectoryGuard(path.dirname(targetPath));
|
|
809
812
|
const current = await fs.lstat(targetPath);
|
|
810
|
-
if (current.isSymbolicLink() || !
|
|
813
|
+
if (current.isSymbolicLink() || !sameFileIdentityForCleanup(current, identity)) {
|
|
811
814
|
return;
|
|
812
815
|
}
|
|
813
816
|
await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
@@ -1108,13 +1111,13 @@ async function writeFileFallback(root, params) {
|
|
|
1108
1111
|
try {
|
|
1109
1112
|
tempPath = buildAtomicWriteTempPath(destinationPath);
|
|
1110
1113
|
unregisterTempPath = registerTempPathForExit(tempPath);
|
|
1111
|
-
const
|
|
1114
|
+
const written = await writeTempFileForAtomicReplace({
|
|
1112
1115
|
tempPath,
|
|
1113
1116
|
data: params.data,
|
|
1114
1117
|
encoding: params.encoding,
|
|
1115
1118
|
mode: mode || 0o600,
|
|
1116
1119
|
});
|
|
1117
|
-
unregisterTempPath.setIdentity(
|
|
1120
|
+
unregisterTempPath.setIdentity(written.cleanupIdentity);
|
|
1118
1121
|
const commitTempPath = tempPath;
|
|
1119
1122
|
await withAsyncDirectoryGuards([destinationGuard], async () => {
|
|
1120
1123
|
await fs.rename(commitTempPath, destinationPath);
|
|
@@ -1126,7 +1129,7 @@ async function writeFileFallback(root, params) {
|
|
|
1126
1129
|
await verifyAtomicWriteResult({
|
|
1127
1130
|
root,
|
|
1128
1131
|
targetPath: destinationPath,
|
|
1129
|
-
expectedIdentity:
|
|
1132
|
+
expectedIdentity: written.identity,
|
|
1130
1133
|
});
|
|
1131
1134
|
}
|
|
1132
1135
|
catch (err) {
|
package/dist/sibling-temp.js
CHANGED
|
@@ -51,7 +51,7 @@ export async function writeSiblingTempFile(options) {
|
|
|
51
51
|
try {
|
|
52
52
|
tempExists = true;
|
|
53
53
|
const result = await options.writeTemp(tempPath);
|
|
54
|
-
unregisterTempPath.setIdentity(await fs.lstat(tempPath));
|
|
54
|
+
unregisterTempPath.setIdentity(await fs.lstat(tempPath, { bigint: true }));
|
|
55
55
|
if (options.mode !== undefined) {
|
|
56
56
|
await fs.chmod(tempPath, options.mode).catch(() => undefined);
|
|
57
57
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar-lock-acquire.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-acquire.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAO3C,OAAO,EAUL,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5F,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;CAClC,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,2BAA2B,IAAI,IAAI,CAAC;IACpC,iBAAiB,CAAC,oBAAoB,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,iBAAiB,CAAC;IAC1F,eAAe,CACb,oBAAoB,EAAE,MAAM,EAC5B,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB,CAAC;AAaF,wBAAsB,kBAAkB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/E,OAAO,EAAE,yBAAyB,CAAC,QAAQ,CAAC,EAC5C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"sidecar-lock-acquire.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-acquire.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAO3C,OAAO,EAUL,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5F,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;CAClC,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,2BAA2B,IAAI,IAAI,CAAC;IACpC,iBAAiB,CAAC,oBAAoB,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,iBAAiB,CAAC;IAC1F,eAAe,CACb,oBAAoB,EAAE,MAAM,EAC5B,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB,CAAC;AAaF,wBAAsB,kBAAkB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/E,OAAO,EAAE,yBAAyB,CAAC,QAAQ,CAAC,EAC5C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAsP5B"}
|
|
@@ -133,7 +133,10 @@ export async function acquireSidecarLock(options, context) {
|
|
|
133
133
|
const interval = options.compromiseCheckIntervalMs;
|
|
134
134
|
if (options.onCompromised && interval !== undefined && interval > 0) {
|
|
135
135
|
createdHeld.compromiseTimer = setInterval(() => {
|
|
136
|
-
void returnedHandle
|
|
136
|
+
void returnedHandle
|
|
137
|
+
.verifyStillHeld()
|
|
138
|
+
.catch(() => false)
|
|
139
|
+
.then((stillHeld) => {
|
|
137
140
|
if (!stillHeld && createdHeld.compromiseTimer) {
|
|
138
141
|
clearInterval(createdHeld.compromiseTimer);
|
|
139
142
|
createdHeld.compromiseTimer = undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temp-cleanup.d.ts","sourceRoot":"","sources":["../src/temp-cleanup.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"temp-cleanup.d.ts","sourceRoot":"","sources":["../src/temp-cleanup.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEvF,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AAEvD,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG;IAChD,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC/C,CAAC;AAsCF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAAE,GAC7D,oBAAoB,CAyBtB;AAED,wBAAgB,mCAAmC,IAAI,IAAI,CAE1D;AAED,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYzE"}
|
package/dist/temp-cleanup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fsSync from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
3
3
|
const tempCleanupEntries = new Map();
|
|
4
4
|
let cleanupRegistered = false;
|
|
5
5
|
function pathStillMatchesReceipt(entry) {
|
|
@@ -7,7 +7,7 @@ function pathStillMatchesReceipt(entry) {
|
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
9
|
try {
|
|
10
|
-
return
|
|
10
|
+
return sameFileIdentityForCleanup(fsSync.lstatSync(entry.path, { bigint: true }), entry.identity);
|
|
11
11
|
}
|
|
12
12
|
catch (error) {
|
|
13
13
|
return error.code === "ENOENT";
|
|
@@ -38,7 +38,7 @@ export function registerTempPathForExit(tempPath, options) {
|
|
|
38
38
|
};
|
|
39
39
|
if (!entry.identity) {
|
|
40
40
|
try {
|
|
41
|
-
entry.identity = fsSync.lstatSync(tempPath);
|
|
41
|
+
entry.identity = fsSync.lstatSync(tempPath, { bigint: true });
|
|
42
42
|
}
|
|
43
43
|
catch {
|
|
44
44
|
// Callers that register before creation set the identity after opening.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temp-target.d.ts","sourceRoot":"","sources":["../src/temp-target.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AA0EF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAaT;AAsCD,wBAAsB,QAAQ,CAAC,MAAM,EAAE;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C,GAAG,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"temp-target.d.ts","sourceRoot":"","sources":["../src/temp-target.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AA0EF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAaT;AAsCD,wBAAsB,QAAQ,CAAC,MAAM,EAAE;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwBpB;AAED,wBAAsB,YAAY,CAAC,CAAC,EAClC,MAAM,EAAE;IACN,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C,EACD,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAClC,OAAO,CAAC,CAAC,CAAC,CAOZ"}
|
package/dist/temp-target.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
-
import
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
5
5
|
import { assertSafePathSegment, sanitizeSafePathSegment } from "./safe-path-segment.js";
|
|
6
6
|
import { resolveSecureTempRoot } from "./secure-temp-dir.js";
|
|
7
7
|
import { registerTempPathForExit } from "./temp-cleanup.js";
|
|
@@ -92,16 +92,16 @@ function isNodeErrorWithCode(err, code) {
|
|
|
92
92
|
}
|
|
93
93
|
async function cleanupTempDir(dir, identity, onCleanupError) {
|
|
94
94
|
try {
|
|
95
|
-
const current = await lstat(dir).catch((error) => {
|
|
95
|
+
const current = await fs.lstat(dir, { bigint: true }).catch((error) => {
|
|
96
96
|
if (isNodeErrorWithCode(error, "ENOENT")) {
|
|
97
97
|
return undefined;
|
|
98
98
|
}
|
|
99
99
|
throw error;
|
|
100
100
|
});
|
|
101
|
-
if (!current || !
|
|
101
|
+
if (!current || !sameFileIdentityForCleanup(current, identity)) {
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
|
-
await rm(dir, { recursive: true, force: true });
|
|
104
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
105
105
|
}
|
|
106
106
|
catch (err) {
|
|
107
107
|
if (!isNodeErrorWithCode(err, "ENOENT")) {
|
|
@@ -115,8 +115,10 @@ function resolveTempRoot(rootDir) {
|
|
|
115
115
|
export async function tempFile(params) {
|
|
116
116
|
const rootDir = resolveTempRoot(params.rootDir);
|
|
117
117
|
const prefix = `${sanitizePrefix(params.prefix)}-`;
|
|
118
|
-
const dir = await mkdtemp(path.join(rootDir, prefix));
|
|
119
|
-
|
|
118
|
+
const dir = await fs.mkdtemp(path.join(rootDir, prefix));
|
|
119
|
+
// Windows file indexes can exceed Number.MAX_SAFE_INTEGER. Cleanup receipts
|
|
120
|
+
// must retain the exact identity or adjacent directories can compare equal.
|
|
121
|
+
const identity = await fs.lstat(dir, { bigint: true });
|
|
120
122
|
const unregisterTempDir = registerTempPathForExit(dir, { recursive: true, identity });
|
|
121
123
|
const file = (fileName) => path.join(dir, sanitizeTempFileName(fileName ?? params.fileName ?? "download.bin"));
|
|
122
124
|
const cleanup = async () => {
|
package/docs/sidecar-lock.md
CHANGED
|
@@ -167,8 +167,8 @@ type FileLockHandle = {
|
|
|
167
167
|
`verifyStillHeld()` compares the current sidecar with the ownership snapshot
|
|
168
168
|
captured at acquisition. Set `compromiseCheckIntervalMs` together with
|
|
169
169
|
`onCompromised` for a cheap periodic check; the callback fires once after the
|
|
170
|
-
sidecar no longer matches
|
|
171
|
-
progress.
|
|
170
|
+
sidecar no longer matches or after a verification I/O failure. This is
|
|
171
|
+
detection, not revocation of work already in progress.
|
|
172
172
|
|
|
173
173
|
## Synchronous locks
|
|
174
174
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/fs-safe",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "Capability-style filesystem roots for Node.js apps that handle untrusted relative paths.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"filesystem",
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
},
|
|
155
155
|
"devDependencies": {
|
|
156
156
|
"@emnapi/runtime": "2.0.0-alpha.3",
|
|
157
|
-
"@napi-rs/cli": "3.8.
|
|
157
|
+
"@napi-rs/cli": "3.8.6",
|
|
158
158
|
"@types/node": "^26.2.0",
|
|
159
159
|
"@vitest/coverage-v8": "4.1.10",
|
|
160
160
|
"fast-check": "^4.9.0",
|