@lousy-agents/mcp 5.21.6 → 5.21.8
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/dist/mcp-server.js +1352 -472
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -6559,7 +6559,7 @@ function escapeJsonPtr(str) {
|
|
|
6559
6559
|
|
|
6560
6560
|
|
|
6561
6561
|
},
|
|
6562
|
-
|
|
6562
|
+
6732(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
|
|
6563
6563
|
// NAMESPACE OBJECT: ../../node_modules/micromark/lib/constructs.js
|
|
6564
6564
|
var constructs_namespaceObject = {};
|
|
6565
6565
|
__webpack_require__.r(constructs_namespaceObject);
|
|
@@ -37057,7 +37057,7 @@ function byte_budget_normalizeMaxBytes(value, options = {}) {
|
|
|
37057
37057
|
if (selected === undefined || selected === Number.POSITIVE_INFINITY)
|
|
37058
37058
|
return selected;
|
|
37059
37059
|
if (!Number.isSafeInteger(selected) || selected < 0) {
|
|
37060
|
-
throw new RangeError(
|
|
37060
|
+
throw new RangeError("maxBytes must be a non-negative safe integer or Infinity");
|
|
37061
37061
|
}
|
|
37062
37062
|
return selected;
|
|
37063
37063
|
}
|
|
@@ -37076,7 +37076,7 @@ function isStatValueProvablyDifferent(left, right, platform) {
|
|
|
37076
37076
|
}
|
|
37077
37077
|
return platform !== "win32" || (!isZero(left) && !isZero(right));
|
|
37078
37078
|
}
|
|
37079
|
-
function
|
|
37079
|
+
function file_identity_sha256Hex(data, encoding) {
|
|
37080
37080
|
const buffer = typeof data === "string" ? Buffer.from(data, encoding ?? "utf8") : data;
|
|
37081
37081
|
return (0,external_node_crypto_.createHash)("sha256").update(buffer).digest("hex");
|
|
37082
37082
|
}
|
|
@@ -37087,7 +37087,7 @@ function file_identity_sameFileIdentity(left, right, platform = process.platform
|
|
|
37087
37087
|
return (!isStatValueProvablyDifferent(left.dev, right.dev, platform) &&
|
|
37088
37088
|
!isStatValueProvablyDifferent(left.ino, right.ino, platform));
|
|
37089
37089
|
}
|
|
37090
|
-
function
|
|
37090
|
+
function file_identity_sameFileIdentityForCleanup(left, right, platform = process.platform) {
|
|
37091
37091
|
// A zero Windows device or inode is unknown, not proof that a pathname still
|
|
37092
37092
|
// names the object we created. Cleanup must fail closed rather than delete a
|
|
37093
37093
|
// replacement that happens to share the known half of the identity.
|
|
@@ -37158,7 +37158,7 @@ function identityCheck(expected, platform) {
|
|
|
37158
37158
|
}
|
|
37159
37159
|
// Retry only unknown Windows identities, retaining every known component so a
|
|
37160
37160
|
// later observation cannot erase a definite mismatch. Never reopen the file.
|
|
37161
|
-
async function
|
|
37161
|
+
async function strict_file_identity_inspectFileIdentity(inspect, expected, platform = process.platform) {
|
|
37162
37162
|
const check = identityCheck(expected, platform);
|
|
37163
37163
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
37164
37164
|
const stat = await inspect();
|
|
@@ -37167,7 +37167,7 @@ async function inspectFileIdentity(inspect, expected, platform = process.platfor
|
|
|
37167
37167
|
}
|
|
37168
37168
|
throw identityMismatch();
|
|
37169
37169
|
}
|
|
37170
|
-
function
|
|
37170
|
+
function strict_file_identity_inspectFileIdentitySync(inspect, expected, platform = process.platform) {
|
|
37171
37171
|
const check = identityCheck(expected, platform);
|
|
37172
37172
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
37173
37173
|
const stat = inspect();
|
|
@@ -37198,11 +37198,11 @@ function normalizeWindowsPathForComparison(input) {
|
|
|
37198
37198
|
// whitespace is part of the path and must not be trimmed away.
|
|
37199
37199
|
return normalized.replaceAll("/", "\\").toLowerCase();
|
|
37200
37200
|
}
|
|
37201
|
-
function
|
|
37201
|
+
function path_isNodeError(value) {
|
|
37202
37202
|
return Boolean(value && typeof value === "object" && "code" in value);
|
|
37203
37203
|
}
|
|
37204
37204
|
function hasNodeErrorCode(value, code) {
|
|
37205
|
-
return
|
|
37205
|
+
return path_isNodeError(value) && value.code === code;
|
|
37206
37206
|
}
|
|
37207
37207
|
function path_assertNoNulPathInput(filePath, message = "path contains a NUL byte") {
|
|
37208
37208
|
if (filePath.includes("\0")) {
|
|
@@ -37210,10 +37210,10 @@ function path_assertNoNulPathInput(filePath, message = "path contains a NUL byte
|
|
|
37210
37210
|
}
|
|
37211
37211
|
}
|
|
37212
37212
|
function path_isNotFoundPathError(value) {
|
|
37213
|
-
return
|
|
37213
|
+
return path_isNodeError(value) && typeof value.code === "string" && NOT_FOUND_CODES.has(value.code);
|
|
37214
37214
|
}
|
|
37215
37215
|
function isSymlinkOpenError(value) {
|
|
37216
|
-
return
|
|
37216
|
+
return path_isNodeError(value) && typeof value.code === "string" && SYMLINK_OPEN_CODES.has(value.code);
|
|
37217
37217
|
}
|
|
37218
37218
|
function path_isPathInside(root, target) {
|
|
37219
37219
|
if (process.platform === "win32") {
|
|
@@ -37370,7 +37370,7 @@ function normalizeRemovePathError(error) {
|
|
|
37370
37370
|
if (error instanceof errors_FsSafeError) {
|
|
37371
37371
|
return error;
|
|
37372
37372
|
}
|
|
37373
|
-
if (!
|
|
37373
|
+
if (!path_isNodeError(error) || typeof error.code !== "string") {
|
|
37374
37374
|
return normalizePinnedPathError(error);
|
|
37375
37375
|
}
|
|
37376
37376
|
const cause = error instanceof Error ? error : undefined;
|
|
@@ -37382,6 +37382,15 @@ function normalizeRemovePathError(error) {
|
|
|
37382
37382
|
}
|
|
37383
37383
|
return new errors_FsSafeError("not-removable", "path could not be removed", { cause });
|
|
37384
37384
|
}
|
|
37385
|
+
function throwFsSafeReadError(error, label) {
|
|
37386
|
+
if (error instanceof FsSafeError) {
|
|
37387
|
+
throw error;
|
|
37388
|
+
}
|
|
37389
|
+
if (isNodeError(error)) {
|
|
37390
|
+
throw new FsSafeError("read-failed", `${label} target could not be read`, { cause: error });
|
|
37391
|
+
}
|
|
37392
|
+
throw error;
|
|
37393
|
+
}
|
|
37385
37394
|
|
|
37386
37395
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/directory-guard.js
|
|
37387
37396
|
|
|
@@ -37391,20 +37400,21 @@ function normalizeRemovePathError(error) {
|
|
|
37391
37400
|
|
|
37392
37401
|
|
|
37393
37402
|
|
|
37394
|
-
|
|
37395
|
-
|
|
37396
|
-
const stat = await promises_.lstat(dir);
|
|
37403
|
+
async function directory_guard_createAsyncDirectoryGuard(dir, options) {
|
|
37404
|
+
const stat = options?.bigint ? await inspectDirectoryIdentity(dir) : external_node_fs_.lstatSync(dir);
|
|
37397
37405
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
37398
37406
|
throw root_errors_directoryComponentNotDirectoryError();
|
|
37399
37407
|
}
|
|
37400
|
-
return { dir, realPath:
|
|
37408
|
+
return { dir, realPath: external_node_fs_.realpathSync.native(dir), stat };
|
|
37401
37409
|
}
|
|
37402
|
-
async function
|
|
37403
|
-
const stat =
|
|
37410
|
+
async function directory_guard_assertAsyncDirectoryGuard(guard) {
|
|
37411
|
+
const stat = typeof guard.stat.dev === "bigint" && typeof guard.stat.ino === "bigint"
|
|
37412
|
+
? await inspectDirectoryIdentity(guard.dir, { dev: guard.stat.dev, ino: guard.stat.ino })
|
|
37413
|
+
: external_node_fs_.lstatSync(guard.dir);
|
|
37404
37414
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
37405
37415
|
throw root_errors_directoryComponentNotDirectoryError();
|
|
37406
37416
|
}
|
|
37407
|
-
if (!file_identity_sameFileIdentity(stat, guard.stat) ||
|
|
37417
|
+
if (!file_identity_sameFileIdentity(stat, guard.stat) || external_node_fs_.realpathSync.native(guard.dir) !== guard.realPath) {
|
|
37408
37418
|
throw new errors_FsSafeError("path-mismatch", "directory changed during operation");
|
|
37409
37419
|
}
|
|
37410
37420
|
}
|
|
@@ -37424,12 +37434,12 @@ function directory_guard_assertSyncDirectoryGuard(guard) {
|
|
|
37424
37434
|
throw new FsSafeError("path-mismatch", "directory changed during operation");
|
|
37425
37435
|
}
|
|
37426
37436
|
}
|
|
37427
|
-
async function directory_guard_createNearestExistingDirectoryGuard(rootReal, targetPath) {
|
|
37437
|
+
async function directory_guard_createNearestExistingDirectoryGuard(rootReal, targetPath, options = { bigint: false }) {
|
|
37428
37438
|
let current = external_node_path_.resolve(targetPath);
|
|
37429
37439
|
const root = external_node_path_.resolve(rootReal);
|
|
37430
37440
|
while (current !== root) {
|
|
37431
37441
|
try {
|
|
37432
|
-
return await directory_guard_createAsyncDirectoryGuard(current);
|
|
37442
|
+
return await directory_guard_createAsyncDirectoryGuard(current, options);
|
|
37433
37443
|
}
|
|
37434
37444
|
catch (error) {
|
|
37435
37445
|
if (!path_isNotFoundPathError(error)) {
|
|
@@ -37438,7 +37448,7 @@ async function directory_guard_createNearestExistingDirectoryGuard(rootReal, tar
|
|
|
37438
37448
|
current = external_node_path_.dirname(current);
|
|
37439
37449
|
}
|
|
37440
37450
|
}
|
|
37441
|
-
return await directory_guard_createAsyncDirectoryGuard(root);
|
|
37451
|
+
return await directory_guard_createAsyncDirectoryGuard(root, options);
|
|
37442
37452
|
}
|
|
37443
37453
|
function directory_guard_createNearestExistingSyncDirectoryGuard(rootReal, targetPath) {
|
|
37444
37454
|
let current = path.resolve(targetPath);
|
|
@@ -37458,8 +37468,8 @@ function directory_guard_createNearestExistingSyncDirectoryGuard(rootReal, targe
|
|
|
37458
37468
|
}
|
|
37459
37469
|
// Recovery receipts must retain every identity bit, including on Windows.
|
|
37460
37470
|
async function inspectDirectoryIdentity(dir, expected) {
|
|
37461
|
-
return await
|
|
37462
|
-
const stat =
|
|
37471
|
+
return await strict_file_identity_inspectFileIdentity(async () => {
|
|
37472
|
+
const stat = external_node_fs_.lstatSync(dir, { bigint: true });
|
|
37463
37473
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
37464
37474
|
throw root_errors_directoryComponentNotDirectoryError();
|
|
37465
37475
|
return stat;
|
|
@@ -37512,11 +37522,11 @@ function assertDirectory(identity, pathname, label) {
|
|
|
37512
37522
|
}
|
|
37513
37523
|
async function createDirectoryReceipt(directoryPath, label) {
|
|
37514
37524
|
const resolvedPath = external_node_path_.resolve(directoryPath);
|
|
37515
|
-
const identity =
|
|
37525
|
+
const identity = external_node_fs_.lstatSync(resolvedPath);
|
|
37516
37526
|
assertDirectory(identity, resolvedPath, label);
|
|
37517
37527
|
return {
|
|
37518
37528
|
path: resolvedPath,
|
|
37519
|
-
realPath:
|
|
37529
|
+
realPath: external_node_fs_.realpathSync.native(resolvedPath),
|
|
37520
37530
|
identity,
|
|
37521
37531
|
};
|
|
37522
37532
|
}
|
|
@@ -37531,10 +37541,10 @@ function createDirectoryReceiptSync(directoryPath, label) {
|
|
|
37531
37541
|
};
|
|
37532
37542
|
}
|
|
37533
37543
|
async function assertDirectoryReceiptCurrent(receipt, label) {
|
|
37534
|
-
const currentIdentity =
|
|
37544
|
+
const currentIdentity = external_node_fs_.lstatSync(receipt.path);
|
|
37535
37545
|
assertDirectory(currentIdentity, receipt.path, label);
|
|
37536
37546
|
if (!file_identity_sameFileIdentity(receipt.identity, currentIdentity) ||
|
|
37537
|
-
(
|
|
37547
|
+
(external_node_fs_.realpathSync.native(receipt.path)) !== receipt.realPath) {
|
|
37538
37548
|
throw new errors_FsSafeError("path-mismatch", `${label} changed during durable directory operation: ${receipt.path}`);
|
|
37539
37549
|
}
|
|
37540
37550
|
}
|
|
@@ -37547,7 +37557,7 @@ function assertDirectoryReceiptCurrentSync(receipt, label) {
|
|
|
37547
37557
|
}
|
|
37548
37558
|
}
|
|
37549
37559
|
async function assertOpenDirectoryCurrent(handle, receipt, label) {
|
|
37550
|
-
const openedIdentity =
|
|
37560
|
+
const openedIdentity = external_node_fs_.fstatSync(handle.fd);
|
|
37551
37561
|
assertDirectory(openedIdentity, receipt.path, label);
|
|
37552
37562
|
if (!file_identity_sameFileIdentity(receipt.identity, openedIdentity)) {
|
|
37553
37563
|
throw new errors_FsSafeError("path-mismatch", `${label} handle changed during directory sync: ${receipt.path}`);
|
|
@@ -37774,13 +37784,14 @@ async function ensureDurableDirectory(options) {
|
|
|
37774
37784
|
|
|
37775
37785
|
|
|
37776
37786
|
|
|
37787
|
+
|
|
37777
37788
|
function isSameOrChildPath(candidate, parent) {
|
|
37778
37789
|
const parentPrefix = parent.endsWith(external_node_path_.sep) ? parent : `${parent}${external_node_path_.sep}`;
|
|
37779
37790
|
return candidate === parent || candidate.startsWith(parentPrefix);
|
|
37780
37791
|
}
|
|
37781
37792
|
async function realpathOrThrowNotFile(target) {
|
|
37782
37793
|
try {
|
|
37783
|
-
return external_node_path_.resolve(
|
|
37794
|
+
return external_node_path_.resolve(external_node_fs_.realpathSync.native(target));
|
|
37784
37795
|
}
|
|
37785
37796
|
catch (error) {
|
|
37786
37797
|
if (path_isNotFoundPathError(error)) {
|
|
@@ -37799,7 +37810,7 @@ async function realpathOrThrowNotFile(target) {
|
|
|
37799
37810
|
*/
|
|
37800
37811
|
async function mkdirPathComponentsWithGuards(params) {
|
|
37801
37812
|
const root = external_node_path_.resolve(params.rootReal);
|
|
37802
|
-
const rootCanonical = external_node_path_.resolve(
|
|
37813
|
+
const rootCanonical = external_node_path_.resolve(external_node_fs_.realpathSync.native(root));
|
|
37803
37814
|
const target = external_node_path_.resolve(params.targetPath);
|
|
37804
37815
|
const relative = external_node_path_.relative(root, target);
|
|
37805
37816
|
if (isPathRelativeEscape(relative)) {
|
|
@@ -37809,18 +37820,18 @@ async function mkdirPathComponentsWithGuards(params) {
|
|
|
37809
37820
|
for (const part of relative.split(external_node_path_.sep).filter(Boolean)) {
|
|
37810
37821
|
const next = external_node_path_.join(current, part);
|
|
37811
37822
|
const parentGuard = await directory_guard_createAsyncDirectoryGuard(current);
|
|
37812
|
-
await
|
|
37823
|
+
await directory_guard_assertAsyncDirectoryGuard(parentGuard);
|
|
37813
37824
|
await params.beforeComponent?.(next);
|
|
37814
37825
|
try {
|
|
37815
|
-
await promises_.mkdir(next);
|
|
37826
|
+
await promises_.mkdir(next, { mode: params.mode });
|
|
37816
37827
|
}
|
|
37817
37828
|
catch (error) {
|
|
37818
37829
|
if (!error || typeof error !== "object" || !("code" in error) || error.code !== "EEXIST") {
|
|
37819
37830
|
throw error;
|
|
37820
37831
|
}
|
|
37821
37832
|
}
|
|
37822
|
-
const stat =
|
|
37823
|
-
if (!stat.isSymbolicLink() && !stat.isDirectory()) {
|
|
37833
|
+
const stat = external_node_fs_.lstatSync(next);
|
|
37834
|
+
if ((params.rejectSymlinks && stat.isSymbolicLink()) || (!stat.isSymbolicLink() && !stat.isDirectory())) {
|
|
37824
37835
|
throw root_errors_directoryComponentNotDirectoryError();
|
|
37825
37836
|
}
|
|
37826
37837
|
// Node's recursive mkdir follows symlinks in missing components. Build one
|
|
@@ -37839,17 +37850,17 @@ async function mkdirPathComponentsWithGuards(params) {
|
|
|
37839
37850
|
// every subsequent segment. Callers that need the final directory
|
|
37840
37851
|
// (e.g. to guard it themselves after this function returns) must use
|
|
37841
37852
|
// the returned resolved path, not their own lexical parent path.
|
|
37842
|
-
const targetStat =
|
|
37853
|
+
const targetStat = external_node_fs_.statSync(nextReal);
|
|
37843
37854
|
if (!targetStat.isDirectory()) {
|
|
37844
37855
|
throw root_errors_directoryComponentNotDirectoryError();
|
|
37845
37856
|
}
|
|
37846
37857
|
await directory_guard_createAsyncDirectoryGuard(nextReal);
|
|
37847
|
-
await
|
|
37858
|
+
await directory_guard_assertAsyncDirectoryGuard(parentGuard);
|
|
37848
37859
|
current = nextReal;
|
|
37849
37860
|
continue;
|
|
37850
37861
|
}
|
|
37851
37862
|
await directory_guard_createAsyncDirectoryGuard(next);
|
|
37852
|
-
await
|
|
37863
|
+
await directory_guard_assertAsyncDirectoryGuard(parentGuard);
|
|
37853
37864
|
current = next;
|
|
37854
37865
|
}
|
|
37855
37866
|
return current;
|
|
@@ -37862,13 +37873,13 @@ async function mkdirPathComponentsWithGuards(params) {
|
|
|
37862
37873
|
|
|
37863
37874
|
async function withAsyncDirectoryGuards(guards, mutate, options = {}) {
|
|
37864
37875
|
for (const guard of guards) {
|
|
37865
|
-
await
|
|
37876
|
+
await directory_guard_assertAsyncDirectoryGuard(guard);
|
|
37866
37877
|
}
|
|
37867
37878
|
const result = await mutate();
|
|
37868
37879
|
if (options.verifyAfter !== false) {
|
|
37869
37880
|
try {
|
|
37870
37881
|
for (const guard of guards) {
|
|
37871
|
-
await
|
|
37882
|
+
await directory_guard_assertAsyncDirectoryGuard(guard);
|
|
37872
37883
|
}
|
|
37873
37884
|
}
|
|
37874
37885
|
catch (error) {
|
|
@@ -37906,9 +37917,13 @@ async function guardedRename(params) {
|
|
|
37906
37917
|
? await createNearestExistingDirectoryGuard(params.targetRoot, path.dirname(params.to))
|
|
37907
37918
|
: await createAsyncDirectoryGuard(path.dirname(params.to));
|
|
37908
37919
|
await withAsyncDirectoryGuards([sourceGuard, targetGuard], async () => {
|
|
37920
|
+
if (params.onSourceInspected) {
|
|
37921
|
+
params.onSourceInspected(fsSync.lstatSync(params.from, { bigint: true }));
|
|
37922
|
+
}
|
|
37909
37923
|
// Authority must survive all awaited guards; do not yield before rename dispatch.
|
|
37910
37924
|
params.assertBeforeRename?.();
|
|
37911
37925
|
await fs.rename(params.from, params.to);
|
|
37926
|
+
params.onRenamed?.();
|
|
37912
37927
|
}, { verifyAfter: params.verifyAfter });
|
|
37913
37928
|
}
|
|
37914
37929
|
function guardedRenameSync(params) {
|
|
@@ -37939,13 +37954,12 @@ function guardedRmSync(params) {
|
|
|
37939
37954
|
|
|
37940
37955
|
|
|
37941
37956
|
|
|
37942
|
-
|
|
37943
37957
|
function isFilesystemRoot(candidate) {
|
|
37944
37958
|
return external_node_path_.parse(candidate).root === candidate;
|
|
37945
37959
|
}
|
|
37946
|
-
async function
|
|
37960
|
+
async function root_path_existing_pathExists(targetPath) {
|
|
37947
37961
|
try {
|
|
37948
|
-
|
|
37962
|
+
external_node_fs_.lstatSync(targetPath);
|
|
37949
37963
|
return true;
|
|
37950
37964
|
}
|
|
37951
37965
|
catch (error) {
|
|
@@ -37959,7 +37973,7 @@ async function resolvePathViaExistingAncestor(targetPath) {
|
|
|
37959
37973
|
const normalized = external_node_path_.resolve(targetPath);
|
|
37960
37974
|
let cursor = normalized;
|
|
37961
37975
|
const missingSuffix = [];
|
|
37962
|
-
while (!isFilesystemRoot(cursor) && !(await
|
|
37976
|
+
while (!isFilesystemRoot(cursor) && !(await root_path_existing_pathExists(cursor))) {
|
|
37963
37977
|
missingSuffix.unshift(external_node_path_.basename(cursor));
|
|
37964
37978
|
const parent = external_node_path_.dirname(cursor);
|
|
37965
37979
|
if (parent === cursor) {
|
|
@@ -37967,11 +37981,11 @@ async function resolvePathViaExistingAncestor(targetPath) {
|
|
|
37967
37981
|
}
|
|
37968
37982
|
cursor = parent;
|
|
37969
37983
|
}
|
|
37970
|
-
if (!(await
|
|
37984
|
+
if (!(await root_path_existing_pathExists(cursor))) {
|
|
37971
37985
|
return normalized;
|
|
37972
37986
|
}
|
|
37973
37987
|
try {
|
|
37974
|
-
const resolvedAncestor = external_node_path_.resolve(
|
|
37988
|
+
const resolvedAncestor = external_node_path_.resolve(external_node_fs_.realpathSync.native(cursor));
|
|
37975
37989
|
return missingSuffix.length === 0
|
|
37976
37990
|
? resolvedAncestor
|
|
37977
37991
|
: external_node_path_.resolve(resolvedAncestor, ...missingSuffix);
|
|
@@ -38081,10 +38095,15 @@ function mergeDenyMutationPolicies(defaultPolicy, callPolicy) {
|
|
|
38081
38095
|
|
|
38082
38096
|
|
|
38083
38097
|
|
|
38098
|
+
|
|
38084
38099
|
function recordFileOpenFailure(error, filePath) {
|
|
38085
38100
|
recordFileObservationFailure(error, `open:${filePath}`);
|
|
38086
38101
|
throw error;
|
|
38087
38102
|
}
|
|
38103
|
+
function recordExclusiveCreateFailure(error, filePath) {
|
|
38104
|
+
recordFileObservationFailure(error, `exclusive-create:${filePath}`);
|
|
38105
|
+
throw error;
|
|
38106
|
+
}
|
|
38088
38107
|
function openedPathResolutionError(error = new errors_FsSafeError("path-mismatch", "unable to resolve opened file path")) {
|
|
38089
38108
|
recordFileObservationFailure(error, "resolution");
|
|
38090
38109
|
return error;
|
|
@@ -38094,8 +38113,8 @@ async function recordPreOpenFileChange(error, handle, filePath, before, opened)
|
|
|
38094
38113
|
![0n, 1n].includes(before.nlink) || ![0n, 1n].includes(opened.nlink))
|
|
38095
38114
|
return;
|
|
38096
38115
|
try {
|
|
38097
|
-
await
|
|
38098
|
-
const current = await
|
|
38116
|
+
await strict_file_identity_inspectFileIdentity(async () => before);
|
|
38117
|
+
const current = await strict_file_identity_inspectFileIdentity(() => external_node_fs_.fstatSync(handle.fd, { bigint: true }), opened);
|
|
38099
38118
|
if (current.isFile() && [0n, 1n].includes(current.nlink) &&
|
|
38100
38119
|
(before.dev !== current.dev || before.ino !== current.ino)) {
|
|
38101
38120
|
// A stale pathname sample is not proof that its former inode was unlinked.
|
|
@@ -38111,7 +38130,7 @@ async function recordOpenedFileFailure(error, handle, filePath, identity) {
|
|
|
38111
38130
|
!identity.isFile() || identity.nlink > 1n)
|
|
38112
38131
|
return;
|
|
38113
38132
|
try {
|
|
38114
|
-
const current = await
|
|
38133
|
+
const current = await strict_file_identity_inspectFileIdentity(() => external_node_fs_.fstatSync(handle.fd, { bigint: true }), identity);
|
|
38115
38134
|
if (current.isFile() && current.nlink === 0n)
|
|
38116
38135
|
recordFileObservationFailure(error, `unlinked:${filePath}`);
|
|
38117
38136
|
}
|
|
@@ -38126,24 +38145,23 @@ async function recordOpenedFileFailure(error, handle, filePath, identity) {
|
|
|
38126
38145
|
|
|
38127
38146
|
|
|
38128
38147
|
|
|
38148
|
+
|
|
38129
38149
|
async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
|
|
38130
|
-
const handleStat =
|
|
38131
|
-
return await resolveOpenedFileRealPathForFd(handle.fd, handleStat, ioPath);
|
|
38150
|
+
const handleStat = external_node_fs_.fstatSync(handle.fd);
|
|
38151
|
+
return (await resolveOpenedFileRealPathForFd(handle.fd, handleStat, ioPath)).realPath;
|
|
38132
38152
|
}
|
|
38133
38153
|
async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
|
|
38134
38154
|
const statOptions = typeof handleStat.dev === "bigint" || typeof handleStat.ino === "bigint"
|
|
38135
38155
|
? { bigint: true } : undefined;
|
|
38136
38156
|
const fdCandidates = process.platform === "linux"
|
|
38137
38157
|
? [`/proc/self/fd/${fd}`, `/dev/fd/${fd}`]
|
|
38138
|
-
:
|
|
38139
|
-
? []
|
|
38140
|
-
: [`/dev/fd/${fd}`];
|
|
38158
|
+
: [];
|
|
38141
38159
|
for (const fdPath of fdCandidates) {
|
|
38142
38160
|
try {
|
|
38143
|
-
const fdRealPath =
|
|
38144
|
-
const fdRealStat = statOptions ?
|
|
38161
|
+
const fdRealPath = external_node_fs_.realpathSync.native(fdPath);
|
|
38162
|
+
const fdRealStat = statOptions ? external_node_fs_.statSync(fdRealPath, statOptions) : external_node_fs_.statSync(fdRealPath);
|
|
38145
38163
|
if (file_identity_sameFileIdentity(handleStat, fdRealStat)) {
|
|
38146
|
-
return fdRealPath;
|
|
38164
|
+
return { realPath: fdRealPath, stat: fdRealStat };
|
|
38147
38165
|
}
|
|
38148
38166
|
}
|
|
38149
38167
|
catch {
|
|
@@ -38151,10 +38169,10 @@ async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
|
|
|
38151
38169
|
}
|
|
38152
38170
|
}
|
|
38153
38171
|
try {
|
|
38154
|
-
const ioRealPath =
|
|
38155
|
-
const ioRealStat = statOptions ?
|
|
38172
|
+
const ioRealPath = external_node_fs_.realpathSync.native(ioPath);
|
|
38173
|
+
const ioRealStat = statOptions ? external_node_fs_.statSync(ioRealPath, statOptions) : external_node_fs_.statSync(ioRealPath);
|
|
38156
38174
|
if (file_identity_sameFileIdentity(handleStat, ioRealStat)) {
|
|
38157
|
-
return ioRealPath;
|
|
38175
|
+
return { realPath: ioRealPath, stat: ioRealStat };
|
|
38158
38176
|
}
|
|
38159
38177
|
}
|
|
38160
38178
|
catch (err) {
|
|
@@ -38177,7 +38195,7 @@ async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
|
|
|
38177
38195
|
async function resolveOpenedFileRealPathFromParent(handleStat, ioPath, statOptions) {
|
|
38178
38196
|
let parentReal;
|
|
38179
38197
|
try {
|
|
38180
|
-
parentReal =
|
|
38198
|
+
parentReal = external_node_fs_.realpathSync.native(external_node_path_.dirname(ioPath));
|
|
38181
38199
|
}
|
|
38182
38200
|
catch (err) {
|
|
38183
38201
|
if (path_isNotFoundPathError(err)) {
|
|
@@ -38198,9 +38216,12 @@ async function resolveOpenedFileRealPathFromParent(handleStat, ioPath, statOptio
|
|
|
38198
38216
|
for (const entry of entries.toSorted()) {
|
|
38199
38217
|
const candidatePath = external_node_path_.join(parentReal, entry);
|
|
38200
38218
|
try {
|
|
38201
|
-
const candidateStat = statOptions ?
|
|
38219
|
+
const candidateStat = statOptions ? external_node_fs_.lstatSync(candidatePath, statOptions) : external_node_fs_.lstatSync(candidatePath);
|
|
38202
38220
|
if (candidateStat.isFile() && file_identity_sameFileIdentity(handleStat, candidateStat)) {
|
|
38203
|
-
|
|
38221
|
+
const realPath = external_node_fs_.realpathSync.native(candidatePath);
|
|
38222
|
+
const stat = statOptions ? external_node_fs_.statSync(realPath, statOptions) : external_node_fs_.statSync(realPath);
|
|
38223
|
+
if (file_identity_sameFileIdentity(handleStat, stat))
|
|
38224
|
+
return { realPath, stat };
|
|
38204
38225
|
}
|
|
38205
38226
|
}
|
|
38206
38227
|
catch (err) {
|
|
@@ -38212,6 +38233,27 @@ async function resolveOpenedFileRealPathFromParent(handleStat, ioPath, statOptio
|
|
|
38212
38233
|
return null;
|
|
38213
38234
|
}
|
|
38214
38235
|
|
|
38236
|
+
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/file-sync.js
|
|
38237
|
+
|
|
38238
|
+
async function syncFileBestEffort(handle) {
|
|
38239
|
+
try {
|
|
38240
|
+
await handle.sync();
|
|
38241
|
+
}
|
|
38242
|
+
catch (error) {
|
|
38243
|
+
if (error?.code !== "EPERM")
|
|
38244
|
+
throw error;
|
|
38245
|
+
}
|
|
38246
|
+
}
|
|
38247
|
+
function syncFileBestEffortSync(fd, fsModule = external_node_fs_) {
|
|
38248
|
+
try {
|
|
38249
|
+
fsModule.fsyncSync(fd);
|
|
38250
|
+
}
|
|
38251
|
+
catch (error) {
|
|
38252
|
+
if (error?.code !== "EPERM")
|
|
38253
|
+
throw error;
|
|
38254
|
+
}
|
|
38255
|
+
}
|
|
38256
|
+
|
|
38215
38257
|
// EXTERNAL MODULE: external "node:module"
|
|
38216
38258
|
var external_node_module_ = __webpack_require__(8995);
|
|
38217
38259
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/native-config.js
|
|
@@ -38471,7 +38513,7 @@ function getNativeBinding() {
|
|
|
38471
38513
|
}
|
|
38472
38514
|
return undefined;
|
|
38473
38515
|
}
|
|
38474
|
-
function
|
|
38516
|
+
function native_requireNativeBinding() {
|
|
38475
38517
|
const native = getNativeBinding();
|
|
38476
38518
|
if (!native) {
|
|
38477
38519
|
throw new FsSafeError("helper-unavailable", "native fs-safe helper is unavailable", {
|
|
@@ -38558,15 +38600,14 @@ function removeNativeCreatedFileIfStillPinned(params) {
|
|
|
38558
38600
|
return;
|
|
38559
38601
|
}
|
|
38560
38602
|
try {
|
|
38561
|
-
const parentPathStat = external_node_fs_.lstatSync(params.parentPath);
|
|
38562
|
-
const parentFdStat =
|
|
38603
|
+
const parentPathStat = external_node_fs_.lstatSync(params.parentPath, { bigint: true });
|
|
38604
|
+
const parentFdStat = external_node_fs_.fstatSync(params.parentFd, { bigint: true });
|
|
38563
38605
|
const targetPath = external_node_path_.join(params.parentPath, params.basename);
|
|
38564
|
-
const target = external_node_fs_.lstatSync(targetPath);
|
|
38565
|
-
if (!parentPathStat.isSymbolicLink() &&
|
|
38566
|
-
parentPathStat
|
|
38567
|
-
|
|
38568
|
-
|
|
38569
|
-
sameFileIdentityForCleanup(target, params.created)) {
|
|
38606
|
+
const target = external_node_fs_.lstatSync(targetPath, { bigint: true });
|
|
38607
|
+
if (!parentPathStat.isSymbolicLink() && parentPathStat.isDirectory() &&
|
|
38608
|
+
file_identity_sameFileIdentityForCleanup(parentPathStat, parentFdStat) &&
|
|
38609
|
+
!target.isSymbolicLink() && target.isFile() &&
|
|
38610
|
+
file_identity_sameFileIdentityForCleanup(target, params.created)) {
|
|
38570
38611
|
external_node_fs_.rmSync(targetPath);
|
|
38571
38612
|
}
|
|
38572
38613
|
}
|
|
@@ -38603,7 +38644,7 @@ async function createNativeExclusiveFile(targetPath, mode) {
|
|
|
38603
38644
|
}
|
|
38604
38645
|
fd = opened.fd;
|
|
38605
38646
|
external_node_fs_.fchmodSync(fd, mode);
|
|
38606
|
-
created = external_node_fs_.fstatSync(fd);
|
|
38647
|
+
created = external_node_fs_.fstatSync(fd, { bigint: true });
|
|
38607
38648
|
return wrapNativeFd(fd, opened.containment);
|
|
38608
38649
|
}
|
|
38609
38650
|
catch (error) {
|
|
@@ -38615,7 +38656,6 @@ async function createNativeExclusiveFile(targetPath, mode) {
|
|
|
38615
38656
|
// Preserve the original error.
|
|
38616
38657
|
}
|
|
38617
38658
|
removeNativeCreatedFileIfStillPinned({
|
|
38618
|
-
binding,
|
|
38619
38659
|
parentPath,
|
|
38620
38660
|
parentFd: parent.fd,
|
|
38621
38661
|
basename,
|
|
@@ -38628,22 +38668,14 @@ async function createNativeExclusiveFile(targetPath, mode) {
|
|
|
38628
38668
|
await parent.close().catch(() => undefined);
|
|
38629
38669
|
}
|
|
38630
38670
|
}
|
|
38631
|
-
function syncNativeFileBestEffort(fd) {
|
|
38632
|
-
try {
|
|
38633
|
-
external_node_fs_.fsyncSync(fd);
|
|
38634
|
-
}
|
|
38635
|
-
catch (error) {
|
|
38636
|
-
if (error.code !== "EPERM") {
|
|
38637
|
-
throw error;
|
|
38638
|
-
}
|
|
38639
|
-
}
|
|
38640
|
-
}
|
|
38641
38671
|
|
|
38642
38672
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.js
|
|
38643
38673
|
|
|
38644
38674
|
|
|
38645
38675
|
|
|
38646
38676
|
|
|
38677
|
+
|
|
38678
|
+
|
|
38647
38679
|
function sameNativeIdentity(left, right) {
|
|
38648
38680
|
return left.dev === right.dev && left.ino === right.ino;
|
|
38649
38681
|
}
|
|
@@ -38668,14 +38700,15 @@ async function runPinnedWriteWindows(binding, params, root, parentFd, parentGuar
|
|
|
38668
38700
|
try {
|
|
38669
38701
|
tempName = `.fs-safe-${(0,external_node_crypto_.randomUUID)()}.tmp`;
|
|
38670
38702
|
tempFd = binding.openBeneath(parentFd, tempName, nativeOpenFlags(external_node_fs_.constants.O_WRONLY | external_node_fs_.constants.O_CREAT | external_node_fs_.constants.O_EXCL)).fd;
|
|
38671
|
-
|
|
38672
|
-
|
|
38703
|
+
const verificationIdentity = strict_file_identity_inspectFileIdentitySync(() => external_node_fs_.fstatSync(tempFd, { bigint: true }));
|
|
38704
|
+
tempIdentity = verificationIdentity;
|
|
38673
38705
|
// Creation is requested at 0600 in the binding, but a restrictive umask
|
|
38674
38706
|
// can remove owner access. Keep the unpublished inode private and
|
|
38675
38707
|
// reopenable until the published name has been identity-fenced.
|
|
38676
38708
|
external_node_fs_.fchmodSync(tempFd, 0o600);
|
|
38677
38709
|
await writeNativeInput(tempFd, params.input, params.maxBytes);
|
|
38678
|
-
|
|
38710
|
+
if (params.sync !== false)
|
|
38711
|
+
syncFileBestEffortSync(tempFd);
|
|
38679
38712
|
if (params.overwrite === false) {
|
|
38680
38713
|
binding.renameNoReplace(parentFd, tempName, parentFd, params.basename);
|
|
38681
38714
|
}
|
|
@@ -38684,8 +38717,9 @@ async function runPinnedWriteWindows(binding, params, root, parentFd, parentGuar
|
|
|
38684
38717
|
}
|
|
38685
38718
|
renamed = true;
|
|
38686
38719
|
targetFd = binding.openBeneath(parentFd, params.basename, nativeOpenFlags(external_node_fs_.constants.O_RDONLY)).fd;
|
|
38720
|
+
const targetStat = strict_file_identity_inspectFileIdentitySync(() => external_node_fs_.fstatSync(targetFd, { bigint: true }), verificationIdentity);
|
|
38687
38721
|
const targetIdentity = binding.fstatIdentity(targetFd);
|
|
38688
|
-
if (!
|
|
38722
|
+
if (!targetStat.isFile()) {
|
|
38689
38723
|
throw new errors_FsSafeError("path-mismatch", "native write target changed after rename");
|
|
38690
38724
|
}
|
|
38691
38725
|
// Native exclusive creation starts at 0600. Apply the requested mode only
|
|
@@ -38693,13 +38727,13 @@ async function runPinnedWriteWindows(binding, params, root, parentFd, parentGuar
|
|
|
38693
38727
|
// verifiable and so broader modes are never exposed before that fence.
|
|
38694
38728
|
try {
|
|
38695
38729
|
external_node_fs_.fchmodSync(targetFd, params.mode);
|
|
38696
|
-
|
|
38730
|
+
if (params.sync !== false)
|
|
38731
|
+
syncFileBestEffortSync(targetFd);
|
|
38697
38732
|
}
|
|
38698
38733
|
catch (error) {
|
|
38699
38734
|
closeWriteFd(targetFd);
|
|
38700
38735
|
targetFd = undefined;
|
|
38701
38736
|
removeNativeCreatedFileIfStillPinned({
|
|
38702
|
-
binding,
|
|
38703
38737
|
parentPath,
|
|
38704
38738
|
parentFd,
|
|
38705
38739
|
basename: params.basename,
|
|
@@ -38707,7 +38741,8 @@ async function runPinnedWriteWindows(binding, params, root, parentFd, parentGuar
|
|
|
38707
38741
|
});
|
|
38708
38742
|
throw error;
|
|
38709
38743
|
}
|
|
38710
|
-
|
|
38744
|
+
if (params.sync !== false)
|
|
38745
|
+
syncFileBestEffortSync(parentFd);
|
|
38711
38746
|
// Verification follows publication and final chmod, outside rollback handling.
|
|
38712
38747
|
await params.verifyPublished?.(targetFd, verificationIdentity, parentGuard);
|
|
38713
38748
|
completed = true;
|
|
@@ -38718,7 +38753,6 @@ async function runPinnedWriteWindows(binding, params, root, parentFd, parentGuar
|
|
|
38718
38753
|
const tempCloseError = closeWriteFd(tempFd);
|
|
38719
38754
|
if (!renamed) {
|
|
38720
38755
|
removeNativeCreatedFileIfStillPinned({
|
|
38721
|
-
binding,
|
|
38722
38756
|
parentPath,
|
|
38723
38757
|
parentFd,
|
|
38724
38758
|
basename: tempName,
|
|
@@ -38763,7 +38797,7 @@ function assertStagedDirectoryCurrent(receipt) {
|
|
|
38763
38797
|
throw new errors_FsSafeError("path-mismatch", "staging directory pathname changed");
|
|
38764
38798
|
}
|
|
38765
38799
|
}
|
|
38766
|
-
function
|
|
38800
|
+
function staged_directory_openStagedDirectory(directory) {
|
|
38767
38801
|
// Copy supplied facts before any asynchronous work; receipts are not authority.
|
|
38768
38802
|
const pathname = path.resolve(typeof directory === "string" ? directory : directory.path);
|
|
38769
38803
|
const expected = typeof directory === "string" ? undefined : {
|
|
@@ -38853,6 +38887,8 @@ var __disposeResources = (undefined && undefined.__disposeResources) || (functio
|
|
|
38853
38887
|
|
|
38854
38888
|
|
|
38855
38889
|
|
|
38890
|
+
|
|
38891
|
+
|
|
38856
38892
|
function assertNativeStaging(binding) {
|
|
38857
38893
|
if ([
|
|
38858
38894
|
binding.createStagedFile,
|
|
@@ -38888,23 +38924,25 @@ class NativeStagedFile {
|
|
|
38888
38924
|
#directory;
|
|
38889
38925
|
#portableNames;
|
|
38890
38926
|
#publishedMode;
|
|
38927
|
+
#sync;
|
|
38891
38928
|
#name = `.fs-safe-${(0,external_node_crypto_.randomUUID)()}.tmp`;
|
|
38892
38929
|
#state = { status: "open", publication: NOT_PUBLISHED };
|
|
38893
38930
|
#receipt;
|
|
38894
|
-
constructor(binding, parentFd, directory, portableNames, publishedMode) {
|
|
38931
|
+
constructor(binding, parentFd, directory, portableNames, publishedMode, sync) {
|
|
38895
38932
|
this.#binding = binding;
|
|
38896
38933
|
this.#parentFd = parentFd;
|
|
38897
38934
|
this.#directory = directory;
|
|
38898
38935
|
this.#portableNames = portableNames;
|
|
38899
38936
|
this.#publishedMode = publishedMode;
|
|
38937
|
+
this.#sync = sync;
|
|
38900
38938
|
}
|
|
38901
38939
|
// Takes ownership of parentFd, including all construction and preparation failures.
|
|
38902
38940
|
static async create(binding, parentFd, directory, input, mode, maxBytes,
|
|
38903
38941
|
// Public staging uses portable names; existing POSIX writes accept literal names.
|
|
38904
|
-
portableNames = true) {
|
|
38942
|
+
portableNames = true, sync = true) {
|
|
38905
38943
|
let staged;
|
|
38906
38944
|
try {
|
|
38907
|
-
staged = new NativeStagedFile(binding, parentFd, directory, portableNames, mode);
|
|
38945
|
+
staged = new NativeStagedFile(binding, parentFd, directory, portableNames, mode, sync);
|
|
38908
38946
|
}
|
|
38909
38947
|
catch (error) {
|
|
38910
38948
|
try {
|
|
@@ -38923,7 +38961,7 @@ class NativeStagedFile {
|
|
|
38923
38961
|
try {
|
|
38924
38962
|
// This owner never escapes. Only the internal verifier borrows its fd;
|
|
38925
38963
|
// public descriptor methods remain await-free and cannot race disposal.
|
|
38926
|
-
const staged = __addDisposableResource(env_1, await NativeStagedFile.create(binding, parentFd, directory, params.input, params.mode, params.maxBytes, false), true);
|
|
38964
|
+
const staged = __addDisposableResource(env_1, await NativeStagedFile.create(binding, parentFd, directory, params.input, params.mode, params.maxBytes, false, params.sync), true);
|
|
38927
38965
|
const published = await staged.publish(params.basename, { overwrite: params.overwrite !== false });
|
|
38928
38966
|
const identity = published.staged.identity;
|
|
38929
38967
|
await params.verifyPublished?.(staged.#file(), identity, parentGuard);
|
|
@@ -38960,10 +38998,12 @@ class NativeStagedFile {
|
|
|
38960
38998
|
}
|
|
38961
38999
|
#assertNamed(name) {
|
|
38962
39000
|
const fd = this.#file();
|
|
38963
|
-
|
|
38964
|
-
external_node_fs_.fstatSync(fd, { bigint: true })
|
|
39001
|
+
const stat = this.#binding.stagedFileMatches(this.#parentFd, name, fd)
|
|
39002
|
+
? external_node_fs_.fstatSync(fd, { bigint: true }) : undefined;
|
|
39003
|
+
if (!stat || stat.nlink !== 1n) {
|
|
38965
39004
|
throw new errors_FsSafeError("path-mismatch", "staged entry no longer names the exclusive created file");
|
|
38966
39005
|
}
|
|
39006
|
+
return Number(stat.mode & 4095n);
|
|
38967
39007
|
}
|
|
38968
39008
|
#assertCurrent() {
|
|
38969
39009
|
if (this.#open().publication.status !== "not-published") {
|
|
@@ -38986,7 +39026,8 @@ class NativeStagedFile {
|
|
|
38986
39026
|
const fd = state.fileFd;
|
|
38987
39027
|
external_node_fs_.fchmodSync(fd, 0o600);
|
|
38988
39028
|
await writeNativeInput(fd, input, maxBytes);
|
|
38989
|
-
|
|
39029
|
+
if (this.#sync)
|
|
39030
|
+
syncFileBestEffortSync(fd);
|
|
38990
39031
|
const stat = external_node_fs_.fstatSync(fd, { bigint: true });
|
|
38991
39032
|
this.#receipt = Object.freeze({
|
|
38992
39033
|
directory: this.#directory,
|
|
@@ -39053,14 +39094,21 @@ class NativeStagedFile {
|
|
|
39053
39094
|
overwrite,
|
|
39054
39095
|
});
|
|
39055
39096
|
state.publication = receipt;
|
|
39056
|
-
this.#assertNamed(basename);
|
|
39097
|
+
const stagedMode = this.#assertNamed(basename);
|
|
39057
39098
|
assertStagedDirectoryCurrent(this.#directory);
|
|
39058
39099
|
// Keep contents private until the published name passes its identity
|
|
39059
39100
|
// fence. Mode changes use the owned fd, including for final mode 000.
|
|
39060
39101
|
const fd = this.#file();
|
|
39061
|
-
|
|
39062
|
-
|
|
39063
|
-
|
|
39102
|
+
if (this.#publishedMode !== 0o600 || stagedMode !== 0o600)
|
|
39103
|
+
external_node_fs_.fchmodSync(fd, this.#publishedMode);
|
|
39104
|
+
// With sync enabled, content was synced before rename. A lost chmod leaves staged 0600,
|
|
39105
|
+
// no wider than modes retaining owner rw. Restrictive modes and observed
|
|
39106
|
+
// widening of the stage still need the permission correction made durable.
|
|
39107
|
+
if (this.#sync && ((this.#publishedMode & 0o600) !== 0o600 || (stagedMode & ~this.#publishedMode) !== 0)) {
|
|
39108
|
+
syncFileBestEffortSync(fd);
|
|
39109
|
+
}
|
|
39110
|
+
if (this.#sync)
|
|
39111
|
+
syncFileBestEffortSync(this.#parentFd);
|
|
39064
39112
|
this.#assertNamed(basename);
|
|
39065
39113
|
assertStagedDirectoryCurrent(this.#directory);
|
|
39066
39114
|
return receipt;
|
|
@@ -39133,6 +39181,17 @@ class NativeStagedFile {
|
|
|
39133
39181
|
}
|
|
39134
39182
|
const createNativeStage = NativeStagedFile.create;
|
|
39135
39183
|
const writeNativeStage = NativeStagedFile.write;
|
|
39184
|
+
async function stageFileInDirectory(options) {
|
|
39185
|
+
if (process.platform !== "linux" && process.platform !== "darwin") {
|
|
39186
|
+
throw new FsSafeError("unsupported-platform", "retained-directory staging requires Linux or macOS");
|
|
39187
|
+
}
|
|
39188
|
+
const binding = requireNativeBinding();
|
|
39189
|
+
assertNativeStaging(binding);
|
|
39190
|
+
const input = { kind: "buffer", data: Buffer.from(options.content) };
|
|
39191
|
+
const mode = options.mode ?? 0o600;
|
|
39192
|
+
const parent = openStagedDirectory(options.directory);
|
|
39193
|
+
return await createNativeStage(binding, parent.fd, parent.receipt, input, mode);
|
|
39194
|
+
}
|
|
39136
39195
|
|
|
39137
39196
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/native-pinned-write.js
|
|
39138
39197
|
var native_pinned_write_addDisposableResource = (undefined && undefined.__addDisposableResource) || function (env, value, async) {
|
|
@@ -39194,6 +39253,8 @@ var native_pinned_write_disposeResources = (undefined && undefined.__disposeReso
|
|
|
39194
39253
|
|
|
39195
39254
|
|
|
39196
39255
|
|
|
39256
|
+
|
|
39257
|
+
|
|
39197
39258
|
async function runPinnedWriteNative(binding, params) {
|
|
39198
39259
|
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
39199
39260
|
try {
|
|
@@ -39216,8 +39277,14 @@ async function runPinnedWriteNative(binding, params) {
|
|
|
39216
39277
|
},
|
|
39217
39278
|
}, false);
|
|
39218
39279
|
try {
|
|
39280
|
+
const exactRoot = typeof params.rootIdentity?.dev === "bigint" && typeof params.rootIdentity.ino === "bigint"
|
|
39281
|
+
? { dev: params.rootIdentity.dev, ino: params.rootIdentity.ino } : undefined;
|
|
39219
39282
|
let rootMatches;
|
|
39220
|
-
if (
|
|
39283
|
+
if (exactRoot) {
|
|
39284
|
+
strict_file_identity_inspectFileIdentitySync(() => external_node_fs_.fstatSync(root.fd, { bigint: true }), exactRoot);
|
|
39285
|
+
rootMatches = true;
|
|
39286
|
+
}
|
|
39287
|
+
else if (windows) {
|
|
39221
39288
|
const identity = binding.fstatIdentity(root.fd);
|
|
39222
39289
|
rootMatches = !params.rootIdentity || sameNativeIdentity(params.rootIdentity, identity);
|
|
39223
39290
|
}
|
|
@@ -39232,24 +39299,26 @@ async function runPinnedWriteNative(binding, params) {
|
|
|
39232
39299
|
binding.mkdirBeneath(root.fd, params.relativeParentPath, 0o777);
|
|
39233
39300
|
}
|
|
39234
39301
|
parentFd = binding.openBeneath(root.fd, params.relativeParentPath, directoryFlags).fd;
|
|
39235
|
-
const parentPath =
|
|
39302
|
+
const parentPath = external_node_fs_.realpathSync.native(params.relativeParentPath
|
|
39236
39303
|
? external_node_path_.join(params.rootPath, ...params.relativeParentPath.split("/"))
|
|
39237
39304
|
: params.rootPath);
|
|
39238
39305
|
const directory = windows ? undefined : describeStagedDirectory(parentFd, parentPath);
|
|
39239
|
-
const parentPathStat =
|
|
39240
|
-
|
|
39306
|
+
const parentPathStat = exactRoot
|
|
39307
|
+
? await inspectDirectoryIdentity(parentPath, strict_file_identity_inspectFileIdentitySync(() => external_node_fs_.fstatSync(parentFd, { bigint: true })))
|
|
39308
|
+
: external_node_fs_.lstatSync(parentPath);
|
|
39309
|
+
if (windows && !exactRoot) {
|
|
39241
39310
|
const parentIdentity = binding.fstatIdentity(parentFd);
|
|
39242
39311
|
if (parentPathStat.isSymbolicLink() || !sameNativeIdentity(parentPathStat, parentIdentity)) {
|
|
39243
39312
|
throw new errors_FsSafeError("path-mismatch", "native write parent changed during resolution");
|
|
39244
39313
|
}
|
|
39245
39314
|
}
|
|
39246
|
-
else if (parentPathStat.isSymbolicLink() || !exactIdentityMatches(parentPathStat, directory.identity)) {
|
|
39315
|
+
else if (!windows && (parentPathStat.isSymbolicLink() || !exactIdentityMatches(parentPathStat, directory.identity))) {
|
|
39247
39316
|
throw new errors_FsSafeError("path-mismatch", "native write parent changed during resolution");
|
|
39248
39317
|
}
|
|
39249
39318
|
const verificationGuard = { dir: parentPath, realPath: parentPath, stat: parentPathStat };
|
|
39250
39319
|
if (params.overwrite === false) {
|
|
39251
39320
|
try {
|
|
39252
|
-
|
|
39321
|
+
external_node_fs_.lstatSync(external_node_path_.join(parentPath, params.basename));
|
|
39253
39322
|
throw Object.assign(new Error("destination already exists"), { code: "EEXIST" });
|
|
39254
39323
|
}
|
|
39255
39324
|
catch (error) {
|
|
@@ -39339,6 +39408,384 @@ function read_open_flags_resolveReadOpenFlags(options) {
|
|
|
39339
39408
|
return constants.O_RDONLY | noFollow | nonBlocking;
|
|
39340
39409
|
}
|
|
39341
39410
|
|
|
39411
|
+
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.js
|
|
39412
|
+
|
|
39413
|
+
|
|
39414
|
+
|
|
39415
|
+
|
|
39416
|
+
|
|
39417
|
+
|
|
39418
|
+
|
|
39419
|
+
|
|
39420
|
+
const PUBLISHED_READ_FLAGS = read_open_flags_resolveReadOpenFlags();
|
|
39421
|
+
function assertOwnedFile(stat, pathname, pathnameEntry) {
|
|
39422
|
+
if (stat.isSymbolicLink()) {
|
|
39423
|
+
throw new FsSafeError("symlink", `Atomic replace owned file became a symlink: ${pathname}`);
|
|
39424
|
+
}
|
|
39425
|
+
if (!stat.isFile()) {
|
|
39426
|
+
throw new FsSafeError("not-file", `Atomic replace owned file must remain regular: ${pathname}`);
|
|
39427
|
+
}
|
|
39428
|
+
if (stat.nlink > 1n || (pathnameEntry && stat.nlink !== 1n)) {
|
|
39429
|
+
throw new FsSafeError("hardlink", `Atomic replace owned file must retain one link: ${pathname}`);
|
|
39430
|
+
}
|
|
39431
|
+
}
|
|
39432
|
+
function missingOwnedFile(pathname, cause) {
|
|
39433
|
+
return new FsSafeError("path-mismatch", `Atomic replace owned file disappeared: ${pathname}`, {
|
|
39434
|
+
cause,
|
|
39435
|
+
});
|
|
39436
|
+
}
|
|
39437
|
+
function cleanupFailure(originalError, cleanupError) {
|
|
39438
|
+
if (originalError !== undefined) {
|
|
39439
|
+
return new Error(`Atomic file replace failed (${String(originalError)}); cleanup also failed (${String(cleanupError)})`, { cause: originalError });
|
|
39440
|
+
}
|
|
39441
|
+
return cleanupError instanceof Error ? cleanupError : new Error(String(cleanupError));
|
|
39442
|
+
}
|
|
39443
|
+
async function cleanupOwnedPath(params) {
|
|
39444
|
+
if (!params.identity)
|
|
39445
|
+
return true;
|
|
39446
|
+
try {
|
|
39447
|
+
const current = params.fsModule === promises_
|
|
39448
|
+
? external_node_fs_.lstatSync(params.pathname, { bigint: true })
|
|
39449
|
+
: await params.fsModule.lstat(params.pathname, { bigint: true });
|
|
39450
|
+
if (current.isSymbolicLink() ||
|
|
39451
|
+
!current.isFile() ||
|
|
39452
|
+
current.nlink !== 1n ||
|
|
39453
|
+
!file_identity_sameFileIdentityForCleanup(current, params.identity)) {
|
|
39454
|
+
return true;
|
|
39455
|
+
}
|
|
39456
|
+
await params.fsModule.unlink(params.pathname);
|
|
39457
|
+
return true;
|
|
39458
|
+
}
|
|
39459
|
+
catch (cleanupError) {
|
|
39460
|
+
if (cleanupError.code === "ENOENT")
|
|
39461
|
+
return true;
|
|
39462
|
+
if (params.throwOnCleanupError) {
|
|
39463
|
+
throw cleanupFailure(params.originalError, cleanupError);
|
|
39464
|
+
}
|
|
39465
|
+
return false;
|
|
39466
|
+
}
|
|
39467
|
+
}
|
|
39468
|
+
// Borrowed handle: the caller retains it until this best-effort cleanup finishes.
|
|
39469
|
+
async function cleanupPinnedFilePath(params) {
|
|
39470
|
+
if (!params.identity)
|
|
39471
|
+
return;
|
|
39472
|
+
try {
|
|
39473
|
+
const guard = params.parentGuard;
|
|
39474
|
+
if ([guard.stat.dev, guard.stat.ino].some((value) => typeof value === "number" && !Number.isSafeInteger(value)))
|
|
39475
|
+
return;
|
|
39476
|
+
await directory_guard_assertAsyncDirectoryGuard(guard);
|
|
39477
|
+
const parent = external_node_fs_.lstatSync(guard.dir, { bigint: true });
|
|
39478
|
+
if (parent.isSymbolicLink() || !parent.isDirectory() ||
|
|
39479
|
+
!file_identity_sameFileIdentityForCleanup(parent, guard.stat))
|
|
39480
|
+
return;
|
|
39481
|
+
const opened = external_node_fs_.fstatSync(params.handle.fd, { bigint: true });
|
|
39482
|
+
if (!opened.isFile() || opened.nlink !== 1n ||
|
|
39483
|
+
!file_identity_sameFileIdentityForCleanup(opened, params.identity))
|
|
39484
|
+
return;
|
|
39485
|
+
await cleanupOwnedPath({
|
|
39486
|
+
fsModule: promises_,
|
|
39487
|
+
pathname: params.pathname,
|
|
39488
|
+
identity: params.identity,
|
|
39489
|
+
throwOnCleanupError: false,
|
|
39490
|
+
});
|
|
39491
|
+
}
|
|
39492
|
+
catch {
|
|
39493
|
+
// Unverifiable authority must preserve the path and the original write failure.
|
|
39494
|
+
}
|
|
39495
|
+
}
|
|
39496
|
+
function cleanupOwnedPathSync(params) {
|
|
39497
|
+
if (!params.identity)
|
|
39498
|
+
return true;
|
|
39499
|
+
try {
|
|
39500
|
+
const current = params.fsModule.lstatSync(params.pathname, { bigint: true });
|
|
39501
|
+
if (current.isSymbolicLink() ||
|
|
39502
|
+
!current.isFile() ||
|
|
39503
|
+
current.nlink !== 1n ||
|
|
39504
|
+
!sameFileIdentityForCleanup(current, params.identity)) {
|
|
39505
|
+
return true;
|
|
39506
|
+
}
|
|
39507
|
+
params.fsModule.unlinkSync(params.pathname);
|
|
39508
|
+
return true;
|
|
39509
|
+
}
|
|
39510
|
+
catch (cleanupError) {
|
|
39511
|
+
if (cleanupError.code === "ENOENT")
|
|
39512
|
+
return true;
|
|
39513
|
+
if (params.throwOnCleanupError) {
|
|
39514
|
+
throw cleanupFailure(params.originalError, cleanupError);
|
|
39515
|
+
}
|
|
39516
|
+
return false;
|
|
39517
|
+
}
|
|
39518
|
+
}
|
|
39519
|
+
class AsyncAtomicTempOwner {
|
|
39520
|
+
pathname;
|
|
39521
|
+
#handle;
|
|
39522
|
+
#identity;
|
|
39523
|
+
#exists = false;
|
|
39524
|
+
#unregister;
|
|
39525
|
+
constructor(pathname) {
|
|
39526
|
+
this.pathname = pathname;
|
|
39527
|
+
this.#unregister = registerTempPathForExit(pathname, { singleLinkFile: true });
|
|
39528
|
+
}
|
|
39529
|
+
start() {
|
|
39530
|
+
this.#exists = true;
|
|
39531
|
+
}
|
|
39532
|
+
onIdentity = (identity) => {
|
|
39533
|
+
this.#identity = identity;
|
|
39534
|
+
this.#unregister.setIdentity(identity);
|
|
39535
|
+
};
|
|
39536
|
+
adopt(temp) {
|
|
39537
|
+
this.#handle = temp.handle;
|
|
39538
|
+
this.onIdentity(temp.identity);
|
|
39539
|
+
}
|
|
39540
|
+
get identity() {
|
|
39541
|
+
if (!this.#identity)
|
|
39542
|
+
throw new Error("Atomic temp owner has no identity");
|
|
39543
|
+
return this.#identity;
|
|
39544
|
+
}
|
|
39545
|
+
async assertCurrent(fsModule, pathname = this.pathname) {
|
|
39546
|
+
const opened = await inspectFileIdentity(async () => {
|
|
39547
|
+
const stat = fsModule === fs ? syncFs.fstatSync(this.#handle.fd, { bigint: true })
|
|
39548
|
+
: await this.#handle.stat({ bigint: true });
|
|
39549
|
+
assertOwnedFile(stat, pathname, false);
|
|
39550
|
+
return stat;
|
|
39551
|
+
}, this.identity);
|
|
39552
|
+
try {
|
|
39553
|
+
await inspectFileIdentity(async () => {
|
|
39554
|
+
const stat = fsModule === fs ? syncFs.lstatSync(pathname, { bigint: true })
|
|
39555
|
+
: await fsModule.lstat(pathname, { bigint: true });
|
|
39556
|
+
assertOwnedFile(stat, pathname, true);
|
|
39557
|
+
return stat;
|
|
39558
|
+
}, opened);
|
|
39559
|
+
}
|
|
39560
|
+
catch (error) {
|
|
39561
|
+
if (error.code === "ENOENT") {
|
|
39562
|
+
throw missingOwnedFile(pathname, error);
|
|
39563
|
+
}
|
|
39564
|
+
throw error;
|
|
39565
|
+
}
|
|
39566
|
+
}
|
|
39567
|
+
async assertPublished(fsModule, pathname, expectedHash) {
|
|
39568
|
+
try {
|
|
39569
|
+
await this.assertCurrent(fsModule, pathname);
|
|
39570
|
+
return;
|
|
39571
|
+
}
|
|
39572
|
+
catch (error) {
|
|
39573
|
+
if (!(error instanceof FsSafeError) || error.code !== "path-mismatch" || !expectedHash) {
|
|
39574
|
+
throw error;
|
|
39575
|
+
}
|
|
39576
|
+
}
|
|
39577
|
+
let published;
|
|
39578
|
+
try {
|
|
39579
|
+
try {
|
|
39580
|
+
published = await fsModule.open(pathname, PUBLISHED_READ_FLAGS);
|
|
39581
|
+
}
|
|
39582
|
+
catch (error) {
|
|
39583
|
+
if (error.code === "ELOOP") {
|
|
39584
|
+
throw new FsSafeError("symlink", `Atomic replace published file became a symlink: ${pathname}`, {
|
|
39585
|
+
cause: error,
|
|
39586
|
+
});
|
|
39587
|
+
}
|
|
39588
|
+
throw error;
|
|
39589
|
+
}
|
|
39590
|
+
const identity = await inspectFileIdentity(async () => {
|
|
39591
|
+
const stat = fsModule === fs ? syncFs.fstatSync(published.fd, { bigint: true })
|
|
39592
|
+
: await published.stat({ bigint: true });
|
|
39593
|
+
assertOwnedFile(stat, pathname, false);
|
|
39594
|
+
return stat;
|
|
39595
|
+
});
|
|
39596
|
+
await inspectFileIdentity(async () => {
|
|
39597
|
+
const stat = fsModule === fs ? syncFs.lstatSync(pathname, { bigint: true })
|
|
39598
|
+
: await fsModule.lstat(pathname, { bigint: true });
|
|
39599
|
+
assertOwnedFile(stat, pathname, true);
|
|
39600
|
+
return stat;
|
|
39601
|
+
}, identity);
|
|
39602
|
+
if (sha256Hex(await published.readFile()) !== expectedHash) {
|
|
39603
|
+
throw new FsSafeError("path-mismatch", `Atomic replace published content changed: ${pathname}`);
|
|
39604
|
+
}
|
|
39605
|
+
await this.#handle?.close();
|
|
39606
|
+
this.#handle = published;
|
|
39607
|
+
this.#identity = identity;
|
|
39608
|
+
published = undefined;
|
|
39609
|
+
}
|
|
39610
|
+
finally {
|
|
39611
|
+
await published?.close().catch(() => undefined);
|
|
39612
|
+
}
|
|
39613
|
+
}
|
|
39614
|
+
markRenamed() {
|
|
39615
|
+
this.#exists = false;
|
|
39616
|
+
this.#unregister();
|
|
39617
|
+
}
|
|
39618
|
+
async finish(params) {
|
|
39619
|
+
let deferredError;
|
|
39620
|
+
let cleanupComplete = !this.#exists;
|
|
39621
|
+
if (this.#exists) {
|
|
39622
|
+
try {
|
|
39623
|
+
cleanupComplete = await cleanupOwnedPath({
|
|
39624
|
+
fsModule: params.fsModule,
|
|
39625
|
+
pathname: this.pathname,
|
|
39626
|
+
identity: this.#identity,
|
|
39627
|
+
originalError: params.originalError,
|
|
39628
|
+
throwOnCleanupError: params.throwOnCleanupError,
|
|
39629
|
+
});
|
|
39630
|
+
}
|
|
39631
|
+
catch (error) {
|
|
39632
|
+
deferredError = error;
|
|
39633
|
+
}
|
|
39634
|
+
}
|
|
39635
|
+
if (cleanupComplete)
|
|
39636
|
+
this.#unregister();
|
|
39637
|
+
try {
|
|
39638
|
+
await this.#handle?.close();
|
|
39639
|
+
}
|
|
39640
|
+
catch (closeError) {
|
|
39641
|
+
deferredError = deferredError
|
|
39642
|
+
? new AggregateError([deferredError, closeError], "Atomic temp cleanup and close failed")
|
|
39643
|
+
: params.originalError !== undefined
|
|
39644
|
+
? new AggregateError([params.originalError, closeError], "Atomic file replace and close failed")
|
|
39645
|
+
: closeError;
|
|
39646
|
+
}
|
|
39647
|
+
if (deferredError)
|
|
39648
|
+
throw deferredError;
|
|
39649
|
+
}
|
|
39650
|
+
}
|
|
39651
|
+
class SyncAtomicTempOwner {
|
|
39652
|
+
pathname;
|
|
39653
|
+
#fd;
|
|
39654
|
+
#identity;
|
|
39655
|
+
#exists = false;
|
|
39656
|
+
#unregister;
|
|
39657
|
+
constructor(pathname) {
|
|
39658
|
+
this.pathname = pathname;
|
|
39659
|
+
this.#unregister = registerTempPathForExit(pathname, { singleLinkFile: true });
|
|
39660
|
+
}
|
|
39661
|
+
start() {
|
|
39662
|
+
this.#exists = true;
|
|
39663
|
+
}
|
|
39664
|
+
onIdentity = (identity) => {
|
|
39665
|
+
this.#identity = identity;
|
|
39666
|
+
this.#unregister.setIdentity(identity);
|
|
39667
|
+
};
|
|
39668
|
+
adopt(temp) {
|
|
39669
|
+
this.#fd = temp.fd;
|
|
39670
|
+
this.onIdentity(temp.identity);
|
|
39671
|
+
}
|
|
39672
|
+
get identity() {
|
|
39673
|
+
if (!this.#identity)
|
|
39674
|
+
throw new Error("Atomic temp owner has no identity");
|
|
39675
|
+
return this.#identity;
|
|
39676
|
+
}
|
|
39677
|
+
assertCurrent(fsModule, pathname = this.pathname) {
|
|
39678
|
+
const opened = inspectFileIdentitySync(() => {
|
|
39679
|
+
const stat = fsModule.fstatSync(this.#fd, { bigint: true });
|
|
39680
|
+
assertOwnedFile(stat, pathname, false);
|
|
39681
|
+
return stat;
|
|
39682
|
+
}, this.identity);
|
|
39683
|
+
try {
|
|
39684
|
+
inspectFileIdentitySync(() => {
|
|
39685
|
+
const stat = fsModule.lstatSync(pathname, { bigint: true });
|
|
39686
|
+
assertOwnedFile(stat, pathname, true);
|
|
39687
|
+
return stat;
|
|
39688
|
+
}, opened);
|
|
39689
|
+
}
|
|
39690
|
+
catch (error) {
|
|
39691
|
+
if (error.code === "ENOENT") {
|
|
39692
|
+
throw missingOwnedFile(pathname, error);
|
|
39693
|
+
}
|
|
39694
|
+
throw error;
|
|
39695
|
+
}
|
|
39696
|
+
}
|
|
39697
|
+
assertPublished(fsModule, pathname, expectedHash) {
|
|
39698
|
+
try {
|
|
39699
|
+
this.assertCurrent(fsModule, pathname);
|
|
39700
|
+
return;
|
|
39701
|
+
}
|
|
39702
|
+
catch (error) {
|
|
39703
|
+
if (!(error instanceof FsSafeError) || error.code !== "path-mismatch" || !expectedHash) {
|
|
39704
|
+
throw error;
|
|
39705
|
+
}
|
|
39706
|
+
}
|
|
39707
|
+
let publishedFd;
|
|
39708
|
+
try {
|
|
39709
|
+
try {
|
|
39710
|
+
publishedFd = fsModule.openSync(pathname, PUBLISHED_READ_FLAGS);
|
|
39711
|
+
}
|
|
39712
|
+
catch (error) {
|
|
39713
|
+
if (error.code === "ELOOP") {
|
|
39714
|
+
throw new FsSafeError("symlink", `Atomic replace published file became a symlink: ${pathname}`, {
|
|
39715
|
+
cause: error,
|
|
39716
|
+
});
|
|
39717
|
+
}
|
|
39718
|
+
throw error;
|
|
39719
|
+
}
|
|
39720
|
+
const identity = inspectFileIdentitySync(() => {
|
|
39721
|
+
const stat = fsModule.fstatSync(publishedFd, { bigint: true });
|
|
39722
|
+
assertOwnedFile(stat, pathname, false);
|
|
39723
|
+
return stat;
|
|
39724
|
+
});
|
|
39725
|
+
inspectFileIdentitySync(() => {
|
|
39726
|
+
const stat = fsModule.lstatSync(pathname, { bigint: true });
|
|
39727
|
+
assertOwnedFile(stat, pathname, true);
|
|
39728
|
+
return stat;
|
|
39729
|
+
}, identity);
|
|
39730
|
+
if (sha256Hex(fsModule.readFileSync(publishedFd)) !== expectedHash) {
|
|
39731
|
+
throw new FsSafeError("path-mismatch", `Atomic replace published content changed: ${pathname}`);
|
|
39732
|
+
}
|
|
39733
|
+
fsModule.closeSync(this.#fd);
|
|
39734
|
+
this.#fd = publishedFd;
|
|
39735
|
+
this.#identity = identity;
|
|
39736
|
+
publishedFd = undefined;
|
|
39737
|
+
}
|
|
39738
|
+
finally {
|
|
39739
|
+
if (publishedFd !== undefined) {
|
|
39740
|
+
try {
|
|
39741
|
+
fsModule.closeSync(publishedFd);
|
|
39742
|
+
}
|
|
39743
|
+
catch {
|
|
39744
|
+
// Best-effort close after a rejected content verification.
|
|
39745
|
+
}
|
|
39746
|
+
}
|
|
39747
|
+
}
|
|
39748
|
+
}
|
|
39749
|
+
markRenamed() {
|
|
39750
|
+
this.#exists = false;
|
|
39751
|
+
this.#unregister();
|
|
39752
|
+
}
|
|
39753
|
+
finish(params) {
|
|
39754
|
+
let deferredError;
|
|
39755
|
+
let cleanupComplete = !this.#exists;
|
|
39756
|
+
if (this.#exists) {
|
|
39757
|
+
try {
|
|
39758
|
+
cleanupComplete = cleanupOwnedPathSync({
|
|
39759
|
+
fsModule: params.fsModule,
|
|
39760
|
+
pathname: this.pathname,
|
|
39761
|
+
identity: this.#identity,
|
|
39762
|
+
originalError: params.originalError,
|
|
39763
|
+
throwOnCleanupError: params.throwOnCleanupError,
|
|
39764
|
+
});
|
|
39765
|
+
}
|
|
39766
|
+
catch (error) {
|
|
39767
|
+
deferredError = error;
|
|
39768
|
+
}
|
|
39769
|
+
}
|
|
39770
|
+
if (cleanupComplete)
|
|
39771
|
+
this.#unregister();
|
|
39772
|
+
if (this.#fd !== undefined) {
|
|
39773
|
+
try {
|
|
39774
|
+
params.fsModule.closeSync(this.#fd);
|
|
39775
|
+
}
|
|
39776
|
+
catch (closeError) {
|
|
39777
|
+
deferredError = deferredError
|
|
39778
|
+
? new AggregateError([deferredError, closeError], "Atomic temp cleanup and close failed")
|
|
39779
|
+
: params.originalError !== undefined
|
|
39780
|
+
? new AggregateError([params.originalError, closeError], "Atomic file replace and close failed")
|
|
39781
|
+
: closeError;
|
|
39782
|
+
}
|
|
39783
|
+
}
|
|
39784
|
+
if (deferredError)
|
|
39785
|
+
throw deferredError;
|
|
39786
|
+
}
|
|
39787
|
+
}
|
|
39788
|
+
|
|
39342
39789
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/bounded-read.js
|
|
39343
39790
|
|
|
39344
39791
|
|
|
@@ -39363,11 +39810,24 @@ function appendChunk(params) {
|
|
|
39363
39810
|
params.chunks.push(Buffer.from(params.scratch.subarray(0, params.bytesRead)));
|
|
39364
39811
|
return total;
|
|
39365
39812
|
}
|
|
39366
|
-
async function readBoundedAsync(maxBytes, readChunk) {
|
|
39813
|
+
async function readBoundedAsync(maxBytes, readChunk, observeRegularFileSize) {
|
|
39367
39814
|
byte_budget_normalizeMaxBytes(maxBytes);
|
|
39368
39815
|
const chunks = [];
|
|
39369
|
-
const scratch = createScratchBuffer(maxBytes);
|
|
39370
39816
|
let total = 0;
|
|
39817
|
+
const size = observeRegularFileSize?.();
|
|
39818
|
+
if (size !== undefined) {
|
|
39819
|
+
const first = Buffer.allocUnsafe(Math.min(maxBytes, size) + 1);
|
|
39820
|
+
const bytesRead = await readChunk(first, first.length);
|
|
39821
|
+
if (bytesRead === 0)
|
|
39822
|
+
return first.subarray(0, 0);
|
|
39823
|
+
// Short reads can occur before EOF. Only accept one when a fresh fd size
|
|
39824
|
+
// observation proves we consumed at least the entire current file size.
|
|
39825
|
+
const currentSize = bytesRead < first.length ? observeRegularFileSize?.() : undefined;
|
|
39826
|
+
if (currentSize !== undefined && bytesRead >= currentSize)
|
|
39827
|
+
return first.subarray(0, bytesRead);
|
|
39828
|
+
total = appendChunk({ chunks, scratch: first, bytesRead, total, maxBytes });
|
|
39829
|
+
}
|
|
39830
|
+
const scratch = createScratchBuffer(maxBytes);
|
|
39371
39831
|
while (true) {
|
|
39372
39832
|
const length = nextReadLength(total, maxBytes, scratch.length);
|
|
39373
39833
|
const bytesRead = await readChunk(scratch, length);
|
|
@@ -39383,9 +39843,22 @@ async function readBoundedAsync(maxBytes, readChunk) {
|
|
|
39383
39843
|
* force an unbounded allocation.
|
|
39384
39844
|
*/
|
|
39385
39845
|
async function readFileHandleBounded(handle, maxBytes) {
|
|
39846
|
+
byte_budget_normalizeMaxBytes(maxBytes);
|
|
39847
|
+
const fd = "fd" in handle && typeof handle.fd === "number" ? handle.fd : undefined;
|
|
39386
39848
|
return await readBoundedAsync(maxBytes, async (scratch, length) => {
|
|
39387
39849
|
return (await handle.read(scratch, 0, length, null)).bytesRead;
|
|
39388
|
-
});
|
|
39850
|
+
}, fd === undefined ? undefined : () => regularFileSize(fd));
|
|
39851
|
+
}
|
|
39852
|
+
function regularFileSize(fd) {
|
|
39853
|
+
try {
|
|
39854
|
+
const stat = external_node_fs_.fstatSync(fd);
|
|
39855
|
+
return stat.isFile() && Number.isSafeInteger(stat.size) && stat.size >= 0
|
|
39856
|
+
? stat.size : undefined;
|
|
39857
|
+
}
|
|
39858
|
+
catch {
|
|
39859
|
+
// Size is only an optimization hint; retain the reader's original errors.
|
|
39860
|
+
return undefined;
|
|
39861
|
+
}
|
|
39389
39862
|
}
|
|
39390
39863
|
function readDescriptorChunk(fd, scratch, length) {
|
|
39391
39864
|
return new Promise((resolve, reject) => {
|
|
@@ -39400,9 +39873,10 @@ function readDescriptorChunk(fd, scratch, length) {
|
|
|
39400
39873
|
}
|
|
39401
39874
|
/** Async bounded read from a numeric descriptor. The caller owns the descriptor. */
|
|
39402
39875
|
async function readFileDescriptorBounded(fd, maxBytes) {
|
|
39876
|
+
normalizeMaxBytes(maxBytes);
|
|
39403
39877
|
return await readBoundedAsync(maxBytes, async (scratch, length) => {
|
|
39404
39878
|
return await readDescriptorChunk(fd, scratch, length);
|
|
39405
|
-
});
|
|
39879
|
+
}, () => regularFileSize(fd));
|
|
39406
39880
|
}
|
|
39407
39881
|
/** Sync bounded read from a numeric descriptor. The caller owns the descriptor. */
|
|
39408
39882
|
function bounded_read_readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
@@ -39420,11 +39894,19 @@ function bounded_read_readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
39420
39894
|
}
|
|
39421
39895
|
}
|
|
39422
39896
|
|
|
39897
|
+
// EXTERNAL MODULE: external "node:os"
|
|
39898
|
+
var external_node_os_ = __webpack_require__(8161);
|
|
39423
39899
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/error-detail.js
|
|
39900
|
+
|
|
39424
39901
|
const UNSAFE_ERROR_DETAIL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/gu;
|
|
39425
39902
|
function formatErrorDetail(value) {
|
|
39426
39903
|
return value.replace(UNSAFE_ERROR_DETAIL_CHARACTERS, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
39427
39904
|
}
|
|
39905
|
+
function shortPath(value) {
|
|
39906
|
+
const home = external_node_os_.homedir();
|
|
39907
|
+
const shortened = value.startsWith(home) ? `~${value.slice(home.length)}` : value;
|
|
39908
|
+
return formatErrorDetail(shortened);
|
|
39909
|
+
}
|
|
39428
39910
|
|
|
39429
39911
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/root-path-symlink.js
|
|
39430
39912
|
|
|
@@ -39432,9 +39914,9 @@ function formatErrorDetail(value) {
|
|
|
39432
39914
|
|
|
39433
39915
|
|
|
39434
39916
|
|
|
39435
|
-
|
|
39436
|
-
|
|
39437
|
-
|
|
39917
|
+
function normalizeSymlinkResolutionError(error, options) {
|
|
39918
|
+
if (isSymlinkOpenError(error) ||
|
|
39919
|
+
(options.rejectUnresolved && path_isNotFoundPathError(error))) {
|
|
39438
39920
|
throw new errors_FsSafeError("symlink", "symlink path could not be resolved", {
|
|
39439
39921
|
cause: error instanceof Error ? error : undefined,
|
|
39440
39922
|
});
|
|
@@ -39442,22 +39924,22 @@ function normalizeSymlinkResolutionError(error) {
|
|
|
39442
39924
|
if (!path_isNotFoundPathError(error))
|
|
39443
39925
|
throw error;
|
|
39444
39926
|
}
|
|
39445
|
-
async function resolveSymlinkHopPath(symlinkPath) {
|
|
39927
|
+
async function resolveSymlinkHopPath(symlinkPath, options = {}) {
|
|
39446
39928
|
try {
|
|
39447
|
-
return external_node_path_.resolve(
|
|
39929
|
+
return external_node_path_.resolve(external_node_fs_.realpathSync.native(symlinkPath));
|
|
39448
39930
|
}
|
|
39449
39931
|
catch (error) {
|
|
39450
|
-
normalizeSymlinkResolutionError(error);
|
|
39451
|
-
const linkTarget =
|
|
39932
|
+
normalizeSymlinkResolutionError(error, options);
|
|
39933
|
+
const linkTarget = external_node_fs_.readlinkSync(symlinkPath);
|
|
39452
39934
|
return resolvePathViaExistingAncestor(external_node_path_.resolve(external_node_path_.dirname(symlinkPath), linkTarget));
|
|
39453
39935
|
}
|
|
39454
39936
|
}
|
|
39455
|
-
function root_path_symlink_resolveSymlinkHopPathSync(symlinkPath) {
|
|
39937
|
+
function root_path_symlink_resolveSymlinkHopPathSync(symlinkPath, options = {}) {
|
|
39456
39938
|
try {
|
|
39457
39939
|
return path.resolve(fs.realpathSync(symlinkPath));
|
|
39458
39940
|
}
|
|
39459
39941
|
catch (error) {
|
|
39460
|
-
normalizeSymlinkResolutionError(error);
|
|
39942
|
+
normalizeSymlinkResolutionError(error, options);
|
|
39461
39943
|
const linkTarget = fs.readlinkSync(symlinkPath);
|
|
39462
39944
|
return resolvePathViaExistingAncestorSync(path.resolve(path.dirname(symlinkPath), linkTarget));
|
|
39463
39945
|
}
|
|
@@ -39540,17 +40022,6 @@ function assertSafePathPrefix(prefix, options = {}) {
|
|
|
39540
40022
|
});
|
|
39541
40023
|
}
|
|
39542
40024
|
|
|
39543
|
-
// EXTERNAL MODULE: external "node:os"
|
|
39544
|
-
var external_node_os_ = __webpack_require__(8161);
|
|
39545
|
-
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/short-path.js
|
|
39546
|
-
|
|
39547
|
-
|
|
39548
|
-
function shortPath(value) {
|
|
39549
|
-
const home = external_node_os_.homedir();
|
|
39550
|
-
const shortened = value.startsWith(home) ? `~${value.slice(home.length)}` : value;
|
|
39551
|
-
return formatErrorDetail(shortened);
|
|
39552
|
-
}
|
|
39553
|
-
|
|
39554
40025
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/root-path.js
|
|
39555
40026
|
|
|
39556
40027
|
|
|
@@ -39561,8 +40032,6 @@ function shortPath(value) {
|
|
|
39561
40032
|
|
|
39562
40033
|
|
|
39563
40034
|
|
|
39564
|
-
|
|
39565
|
-
|
|
39566
40035
|
const ROOT_PATH_ALIAS_POLICIES = {
|
|
39567
40036
|
strict: Object.freeze({
|
|
39568
40037
|
allowFinalSymlinkForUnlink: false,
|
|
@@ -39573,7 +40042,7 @@ const ROOT_PATH_ALIAS_POLICIES = {
|
|
|
39573
40042
|
allowFinalHardlinkForUnlink: true,
|
|
39574
40043
|
}),
|
|
39575
40044
|
};
|
|
39576
|
-
async function
|
|
40045
|
+
async function root_path_resolveRootPath(params) {
|
|
39577
40046
|
try {
|
|
39578
40047
|
return await resolveRootPathInternal(params);
|
|
39579
40048
|
}
|
|
@@ -39674,12 +40143,6 @@ function assertNoEmbeddedDriveRelativeSegment(filePath, label) {
|
|
|
39674
40143
|
const root = external_node_path_.parse(filePath).root;
|
|
39675
40144
|
assertNoDriveRelativePathSegments(filePath.slice(root.length).replaceAll("\\", "/"), label);
|
|
39676
40145
|
}
|
|
39677
|
-
function isPromiseLike(value) {
|
|
39678
|
-
return Boolean(value &&
|
|
39679
|
-
(typeof value === "object" || typeof value === "function") &&
|
|
39680
|
-
"then" in value &&
|
|
39681
|
-
typeof value.then === "function");
|
|
39682
|
-
}
|
|
39683
40146
|
function createLexicalTraversalState(params) {
|
|
39684
40147
|
const rawAbsolutePath = params.params.absolutePath;
|
|
39685
40148
|
const rawRelativePath = rawPathRelativeToRoot(params.rootPath, rawAbsolutePath);
|
|
@@ -39759,26 +40222,13 @@ function handleLexicalLstatFailure(context, error, missingFromIndex) {
|
|
|
39759
40222
|
applyMissingSuffixToCanonicalCursor(context, missingFromIndex);
|
|
39760
40223
|
return true;
|
|
39761
40224
|
}
|
|
39762
|
-
function
|
|
39763
|
-
if (
|
|
39764
|
-
return null;
|
|
39765
|
-
}
|
|
39766
|
-
throw error;
|
|
39767
|
-
}
|
|
39768
|
-
function handleLexicalStatDisposition(context, params) {
|
|
39769
|
-
if (!params.isSymbolicLink) {
|
|
39770
|
-
advanceCanonicalCursorForSegment(context, params.segment);
|
|
40225
|
+
function lexicalStatDisposition(params) {
|
|
40226
|
+
if (!params.isSymbolicLink)
|
|
39771
40227
|
return "continue";
|
|
39772
|
-
|
|
39773
|
-
if (context.resolveParams.rejectSymlinks === true && params.isLast) {
|
|
40228
|
+
if (params.rejectSymlinks === true && params.isLast) {
|
|
39774
40229
|
throw new errors_FsSafeError("symlink", "symlink path component not allowed");
|
|
39775
40230
|
}
|
|
39776
|
-
|
|
39777
|
-
context.state.preserveFinalSymlink = true;
|
|
39778
|
-
advanceCanonicalCursorForSegment(context, params.segment);
|
|
39779
|
-
return "break";
|
|
39780
|
-
}
|
|
39781
|
-
return "resolve-link";
|
|
40231
|
+
return params.allowFinalSymlink && params.isLast ? "break" : "resolve-link";
|
|
39782
40232
|
}
|
|
39783
40233
|
function applyResolvedSymlinkHop(context, linkCanonical) {
|
|
39784
40234
|
if (!path_isPathInside(context.rootCanonicalPath, linkCanonical)) {
|
|
@@ -39791,68 +40241,48 @@ function applyResolvedSymlinkHop(context, linkCanonical) {
|
|
|
39791
40241
|
context.state.canonicalCursor = linkCanonical;
|
|
39792
40242
|
context.state.lexicalCursor = linkCanonical;
|
|
39793
40243
|
}
|
|
39794
|
-
function readLexicalStat(context, params) {
|
|
39795
|
-
try {
|
|
39796
|
-
const stat = params.read(context.state.lexicalCursor);
|
|
39797
|
-
if (isPromiseLike(stat)) {
|
|
39798
|
-
return Promise.resolve(stat).catch((error) => handleLexicalStatReadFailure(context, error, params.missingFromIndex));
|
|
39799
|
-
}
|
|
39800
|
-
return stat;
|
|
39801
|
-
}
|
|
39802
|
-
catch (error) {
|
|
39803
|
-
return handleLexicalStatReadFailure(context, error, params.missingFromIndex);
|
|
39804
|
-
}
|
|
39805
|
-
}
|
|
39806
|
-
function resolveAndApplySymlinkHop(context, params) {
|
|
39807
|
-
const linkCanonical = params.resolveLinkCanonical(context.state.lexicalCursor);
|
|
39808
|
-
if (isPromiseLike(linkCanonical)) {
|
|
39809
|
-
return Promise.resolve(linkCanonical).then((value) => {
|
|
39810
|
-
applyResolvedSymlinkHop(context, value);
|
|
39811
|
-
});
|
|
39812
|
-
}
|
|
39813
|
-
applyResolvedSymlinkHop(context, linkCanonical);
|
|
39814
|
-
}
|
|
39815
40244
|
function applyParentTraversalStep(context) {
|
|
39816
40245
|
context.state.lexicalCursor = external_node_path_.resolve(context.state.lexicalCursor, "..");
|
|
39817
40246
|
advanceCanonicalCursorForSegment(context, "..");
|
|
39818
40247
|
}
|
|
39819
|
-
function* iterateLexicalTraversal(state) {
|
|
39820
|
-
for (let idx = 0; idx < state.segments.length; idx += 1) {
|
|
39821
|
-
const segment = state.segments[idx] ?? "";
|
|
39822
|
-
const isLast = idx === state.segments.length - 1;
|
|
39823
|
-
yield { idx, segment, isLast };
|
|
39824
|
-
}
|
|
39825
|
-
}
|
|
39826
40248
|
async function resolveRootPathLexicalAsync(params) {
|
|
39827
40249
|
const context = createLexicalTraversalContext(params);
|
|
39828
40250
|
const { state } = context;
|
|
39829
|
-
for (
|
|
40251
|
+
for (let idx = 0; idx < state.segments.length; idx += 1) {
|
|
40252
|
+
const segment = state.segments[idx] ?? "";
|
|
40253
|
+
const isLast = idx === state.segments.length - 1;
|
|
39830
40254
|
if (segment === "..") {
|
|
39831
40255
|
applyParentTraversalStep(context);
|
|
39832
40256
|
continue;
|
|
39833
40257
|
}
|
|
39834
40258
|
state.lexicalCursor = external_node_path_.join(state.lexicalCursor, segment);
|
|
39835
|
-
|
|
39836
|
-
|
|
39837
|
-
|
|
39838
|
-
});
|
|
39839
|
-
if (!stat) {
|
|
39840
|
-
break;
|
|
40259
|
+
let stat;
|
|
40260
|
+
try {
|
|
40261
|
+
stat = external_node_fs_.lstatSync(state.lexicalCursor);
|
|
39841
40262
|
}
|
|
39842
|
-
|
|
39843
|
-
|
|
39844
|
-
|
|
40263
|
+
catch (error) {
|
|
40264
|
+
if (handleLexicalLstatFailure(context, error, idx))
|
|
40265
|
+
break;
|
|
40266
|
+
throw error;
|
|
40267
|
+
}
|
|
40268
|
+
const isSymbolicLink = stat.isSymbolicLink();
|
|
40269
|
+
const disposition = lexicalStatDisposition({
|
|
40270
|
+
isSymbolicLink,
|
|
39845
40271
|
isLast,
|
|
40272
|
+
rejectSymlinks: isSymbolicLink ? context.resolveParams.rejectSymlinks : undefined,
|
|
40273
|
+
allowFinalSymlink: state.allowFinalSymlink,
|
|
39846
40274
|
});
|
|
39847
|
-
if (disposition
|
|
40275
|
+
if (disposition !== "resolve-link") {
|
|
40276
|
+
state.preserveFinalSymlink = disposition === "break";
|
|
40277
|
+
advanceCanonicalCursorForSegment(context, segment);
|
|
40278
|
+
if (state.preserveFinalSymlink)
|
|
40279
|
+
break;
|
|
39848
40280
|
continue;
|
|
39849
40281
|
}
|
|
39850
|
-
|
|
39851
|
-
|
|
39852
|
-
}
|
|
39853
|
-
await resolveAndApplySymlinkHop(context, {
|
|
39854
|
-
resolveLinkCanonical: (cursor) => resolveSymlinkHopPath(cursor),
|
|
40282
|
+
const linkCanonical = await resolveSymlinkHopPath(state.lexicalCursor, {
|
|
40283
|
+
rejectUnresolved: context.resolveParams.rejectUnresolvedSymlinks,
|
|
39855
40284
|
});
|
|
40285
|
+
applyResolvedSymlinkHop(context, linkCanonical);
|
|
39856
40286
|
if (context.resolveParams.rejectSymlinks === true) {
|
|
39857
40287
|
throw new errors_FsSafeError("symlink", "symlink path component not allowed");
|
|
39858
40288
|
}
|
|
@@ -39871,34 +40301,33 @@ function resolveRootPathLexicalSync(params) {
|
|
|
39871
40301
|
continue;
|
|
39872
40302
|
}
|
|
39873
40303
|
state.lexicalCursor = path.join(state.lexicalCursor, segment);
|
|
39874
|
-
|
|
39875
|
-
|
|
39876
|
-
|
|
39877
|
-
});
|
|
39878
|
-
if (isPromiseLike(maybeStat)) {
|
|
39879
|
-
throw new Error("Unexpected async lexical stat");
|
|
40304
|
+
let stat;
|
|
40305
|
+
try {
|
|
40306
|
+
stat = fs.lstatSync(state.lexicalCursor);
|
|
39880
40307
|
}
|
|
39881
|
-
|
|
39882
|
-
|
|
39883
|
-
|
|
40308
|
+
catch (error) {
|
|
40309
|
+
if (handleLexicalLstatFailure(context, error, idx))
|
|
40310
|
+
break;
|
|
40311
|
+
throw error;
|
|
39884
40312
|
}
|
|
39885
|
-
const
|
|
39886
|
-
|
|
39887
|
-
|
|
40313
|
+
const isSymbolicLink = stat.isSymbolicLink();
|
|
40314
|
+
const disposition = lexicalStatDisposition({
|
|
40315
|
+
isSymbolicLink,
|
|
39888
40316
|
isLast,
|
|
40317
|
+
rejectSymlinks: isSymbolicLink ? context.resolveParams.rejectSymlinks : undefined,
|
|
40318
|
+
allowFinalSymlink: state.allowFinalSymlink,
|
|
39889
40319
|
});
|
|
39890
|
-
if (disposition
|
|
40320
|
+
if (disposition !== "resolve-link") {
|
|
40321
|
+
state.preserveFinalSymlink = disposition === "break";
|
|
40322
|
+
advanceCanonicalCursorForSegment(context, segment);
|
|
40323
|
+
if (state.preserveFinalSymlink)
|
|
40324
|
+
break;
|
|
39891
40325
|
continue;
|
|
39892
40326
|
}
|
|
39893
|
-
|
|
39894
|
-
|
|
39895
|
-
}
|
|
39896
|
-
const maybeApplied = resolveAndApplySymlinkHop(context, {
|
|
39897
|
-
resolveLinkCanonical: (cursor) => resolveSymlinkHopPathSync(cursor),
|
|
40327
|
+
const linkCanonical = resolveSymlinkHopPathSync(state.lexicalCursor, {
|
|
40328
|
+
rejectUnresolved: context.resolveParams.rejectUnresolvedSymlinks,
|
|
39898
40329
|
});
|
|
39899
|
-
|
|
39900
|
-
throw new Error("Unexpected async symlink resolution");
|
|
39901
|
-
}
|
|
40330
|
+
applyResolvedSymlinkHop(context, linkCanonical);
|
|
39902
40331
|
if (context.resolveParams.rejectSymlinks === true) {
|
|
39903
40332
|
throw new FsSafeError("symlink", "symlink path component not allowed");
|
|
39904
40333
|
}
|
|
@@ -40018,8 +40447,8 @@ function buildResolvedRootPath(params) {
|
|
|
40018
40447
|
async function getPathKind(absolutePath, preserveFinalSymlink) {
|
|
40019
40448
|
try {
|
|
40020
40449
|
const stat = preserveFinalSymlink
|
|
40021
|
-
?
|
|
40022
|
-
:
|
|
40450
|
+
? external_node_fs_.lstatSync(absolutePath)
|
|
40451
|
+
: external_node_fs_.statSync(absolutePath);
|
|
40023
40452
|
return { exists: true, kind: toResolvedKind(stat) };
|
|
40024
40453
|
}
|
|
40025
40454
|
catch (error) {
|
|
@@ -40085,7 +40514,7 @@ function symlinkEscapeError(params) {
|
|
|
40085
40514
|
|
|
40086
40515
|
async function openSidecarRoot(lockRoot, relative, discardObservation, onOpenFailure) {
|
|
40087
40516
|
const resolved = await lockRoot.resolve(relative);
|
|
40088
|
-
const canonicalPath = async () => (await
|
|
40517
|
+
const canonicalPath = async () => (await root_path_resolveRootPath({
|
|
40089
40518
|
absolutePath: resolved,
|
|
40090
40519
|
rootPath: lockRoot.rootReal,
|
|
40091
40520
|
rootCanonicalPath: lockRoot.rootReal,
|
|
@@ -40202,10 +40631,12 @@ function readSidecarLockOwnershipToken(raw) {
|
|
|
40202
40631
|
}
|
|
40203
40632
|
function serializeSidecarLockPayload(payload) {
|
|
40204
40633
|
const ownershipToken = createSidecarLockOwnershipToken();
|
|
40205
|
-
|
|
40206
|
-
|
|
40207
|
-
|
|
40208
|
-
|
|
40634
|
+
const raw = `${JSON.stringify(payload, null, 2)}\n${ownershipToken}\n`;
|
|
40635
|
+
const bytes = Buffer.byteLength(raw, "utf8");
|
|
40636
|
+
if (bytes > MAX_LOCK_PAYLOAD_BYTES) {
|
|
40637
|
+
throw new errors_FsSafeError("too-large", `sidecar lock payload exceeds limit of ${MAX_LOCK_PAYLOAD_BYTES} bytes (got ${bytes})`);
|
|
40638
|
+
}
|
|
40639
|
+
return { raw, ownershipToken };
|
|
40209
40640
|
}
|
|
40210
40641
|
function relativeSidecarLockPath(lockRoot, lockPath) {
|
|
40211
40642
|
const resolved = external_node_path_.resolve(lockPath);
|
|
@@ -40260,7 +40691,13 @@ async function readSidecarLockRawSnapshot(lockPath, options = {}) {
|
|
|
40260
40691
|
await opened.handle.close().catch(() => undefined);
|
|
40261
40692
|
}
|
|
40262
40693
|
}
|
|
40263
|
-
|
|
40694
|
+
let before;
|
|
40695
|
+
try {
|
|
40696
|
+
before = external_node_fs_.lstatSync(lockPath);
|
|
40697
|
+
}
|
|
40698
|
+
catch (error) {
|
|
40699
|
+
before = missingSnapshotPath(error);
|
|
40700
|
+
}
|
|
40264
40701
|
if (!before)
|
|
40265
40702
|
return null;
|
|
40266
40703
|
if (!before.isFile() || before.isSymbolicLink()) {
|
|
@@ -40289,7 +40726,7 @@ async function readSidecarLockRawSnapshot(lockPath, options = {}) {
|
|
|
40289
40726
|
options.onOpenFailure?.(error);
|
|
40290
40727
|
throw error;
|
|
40291
40728
|
}
|
|
40292
|
-
const opened =
|
|
40729
|
+
const opened = external_node_fs_.fstatSync(handle.fd);
|
|
40293
40730
|
if (!opened.isFile()) {
|
|
40294
40731
|
if (options.rejectNonFile) {
|
|
40295
40732
|
throw new errors_FsSafeError("not-file", `sidecar lock is not a regular file: ${lockPath}`);
|
|
@@ -40299,7 +40736,13 @@ async function readSidecarLockRawSnapshot(lockPath, options = {}) {
|
|
|
40299
40736
|
if (!options.allowDescriptorIdentityDrift && !file_identity_sameFileIdentity(before, opened))
|
|
40300
40737
|
return null;
|
|
40301
40738
|
const raw = (await readFileHandleBounded(handle, MAX_LOCK_PAYLOAD_BYTES)).toString("utf8");
|
|
40302
|
-
|
|
40739
|
+
let after;
|
|
40740
|
+
try {
|
|
40741
|
+
after = external_node_fs_.lstatSync(lockPath);
|
|
40742
|
+
}
|
|
40743
|
+
catch (error) {
|
|
40744
|
+
after = missingSnapshotPath(error);
|
|
40745
|
+
}
|
|
40303
40746
|
if (!after || !after.isFile() || !file_identity_sameFileIdentity(before, after))
|
|
40304
40747
|
return null;
|
|
40305
40748
|
return { raw, stat: after };
|
|
@@ -40411,7 +40854,7 @@ async function sidecarLockSnapshotStillPresent(lockPath, observed, options = {})
|
|
|
40411
40854
|
}
|
|
40412
40855
|
async function sidecarReclaimGuardExists(pathname) {
|
|
40413
40856
|
try {
|
|
40414
|
-
|
|
40857
|
+
external_node_fs_.lstatSync(pathname);
|
|
40415
40858
|
return true;
|
|
40416
40859
|
}
|
|
40417
40860
|
catch (err) {
|
|
@@ -40474,6 +40917,315 @@ async function removeStaleSidecarLockIfAllowed(params) {
|
|
|
40474
40917
|
}
|
|
40475
40918
|
}
|
|
40476
40919
|
|
|
40920
|
+
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/absolute-path.js
|
|
40921
|
+
|
|
40922
|
+
|
|
40923
|
+
|
|
40924
|
+
|
|
40925
|
+
|
|
40926
|
+
|
|
40927
|
+
|
|
40928
|
+
function resolveSymlinkPolicy(policy) {
|
|
40929
|
+
if (policy === undefined)
|
|
40930
|
+
return "reject";
|
|
40931
|
+
if (policy !== "reject" && policy !== "follow") {
|
|
40932
|
+
throw new TypeError(`invalid absolute path symlink policy: ${String(policy)}`);
|
|
40933
|
+
}
|
|
40934
|
+
return policy;
|
|
40935
|
+
}
|
|
40936
|
+
function ensureDirectoryFailure(code, message, cause) {
|
|
40937
|
+
return {
|
|
40938
|
+
ok: false,
|
|
40939
|
+
code,
|
|
40940
|
+
error: new FsSafeError(code, message, { cause }),
|
|
40941
|
+
};
|
|
40942
|
+
}
|
|
40943
|
+
async function assertGuardResult(guard, scopeLabel) {
|
|
40944
|
+
try {
|
|
40945
|
+
await assertAsyncDirectoryGuard(guard);
|
|
40946
|
+
return { ok: true };
|
|
40947
|
+
}
|
|
40948
|
+
catch (err) {
|
|
40949
|
+
if (err instanceof FsSafeError) {
|
|
40950
|
+
return await directoryGuardFailure(err, guard.dir, scopeLabel);
|
|
40951
|
+
}
|
|
40952
|
+
throw err;
|
|
40953
|
+
}
|
|
40954
|
+
}
|
|
40955
|
+
async function createDirectoryGuardResult(dir, scopeLabel) {
|
|
40956
|
+
try {
|
|
40957
|
+
return { ok: true, guard: await createAsyncDirectoryGuard(dir) };
|
|
40958
|
+
}
|
|
40959
|
+
catch (err) {
|
|
40960
|
+
if (err instanceof FsSafeError) {
|
|
40961
|
+
return await directoryGuardFailure(err, dir, scopeLabel);
|
|
40962
|
+
}
|
|
40963
|
+
throw err;
|
|
40964
|
+
}
|
|
40965
|
+
}
|
|
40966
|
+
function classifyDirectoryLookupError(err, scopeLabel) {
|
|
40967
|
+
const code = err.code;
|
|
40968
|
+
if (code === "ENOENT") {
|
|
40969
|
+
return ensureDirectoryFailure("not-found", `directory path must have a real existing ancestor within ${scopeLabel}`, err);
|
|
40970
|
+
}
|
|
40971
|
+
if (code === "ENOTDIR") {
|
|
40972
|
+
return ensureDirectoryFailure("not-file", `path must be a real directory within ${scopeLabel}`, err);
|
|
40973
|
+
}
|
|
40974
|
+
return null;
|
|
40975
|
+
}
|
|
40976
|
+
function classifyExistingDirectorySegment(stat, scopeLabel) {
|
|
40977
|
+
if (stat.isSymbolicLink()) {
|
|
40978
|
+
return ensureDirectoryFailure("symlink", `directory path traverses a symlink within ${scopeLabel}`);
|
|
40979
|
+
}
|
|
40980
|
+
if (!stat.isDirectory()) {
|
|
40981
|
+
return ensureDirectoryFailure("not-file", `path must be a real directory within ${scopeLabel}`);
|
|
40982
|
+
}
|
|
40983
|
+
return null;
|
|
40984
|
+
}
|
|
40985
|
+
async function directoryGuardFailure(err, dir, scopeLabel) {
|
|
40986
|
+
if (err.code !== "not-file") {
|
|
40987
|
+
return { ok: false, code: err.code, error: err };
|
|
40988
|
+
}
|
|
40989
|
+
try {
|
|
40990
|
+
const stat = fsSync.lstatSync(dir);
|
|
40991
|
+
const failure = classifyExistingDirectorySegment(stat, scopeLabel);
|
|
40992
|
+
if (failure) {
|
|
40993
|
+
return failure;
|
|
40994
|
+
}
|
|
40995
|
+
}
|
|
40996
|
+
catch (lookupErr) {
|
|
40997
|
+
const failure = classifyDirectoryLookupError(lookupErr, scopeLabel);
|
|
40998
|
+
if (failure) {
|
|
40999
|
+
return failure;
|
|
41000
|
+
}
|
|
41001
|
+
throw lookupErr;
|
|
41002
|
+
}
|
|
41003
|
+
return { ok: false, code: err.code, error: err };
|
|
41004
|
+
}
|
|
41005
|
+
async function resolveTrustedDirectoryPrefix(targetPath, scopeLabel) {
|
|
41006
|
+
const root = path.parse(targetPath).root;
|
|
41007
|
+
let current = root;
|
|
41008
|
+
let currentStat;
|
|
41009
|
+
try {
|
|
41010
|
+
currentStat = fsSync.lstatSync(current);
|
|
41011
|
+
}
|
|
41012
|
+
catch (err) {
|
|
41013
|
+
const failure = classifyDirectoryLookupError(err, scopeLabel);
|
|
41014
|
+
if (failure) {
|
|
41015
|
+
return failure;
|
|
41016
|
+
}
|
|
41017
|
+
throw err;
|
|
41018
|
+
}
|
|
41019
|
+
const rootFailure = classifyExistingDirectorySegment(currentStat, scopeLabel);
|
|
41020
|
+
if (rootFailure) {
|
|
41021
|
+
return rootFailure;
|
|
41022
|
+
}
|
|
41023
|
+
// Walk forward with lstat. Looking backward for the "nearest existing
|
|
41024
|
+
// ancestor" can cross an existing suffix through a symlinked parent before
|
|
41025
|
+
// this helper gets a chance to reject that parent.
|
|
41026
|
+
const segments = path.relative(root, targetPath).split(path.sep).filter(Boolean);
|
|
41027
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
41028
|
+
const segment = segments[index];
|
|
41029
|
+
if (!segment) {
|
|
41030
|
+
continue;
|
|
41031
|
+
}
|
|
41032
|
+
const next = path.join(current, segment);
|
|
41033
|
+
try {
|
|
41034
|
+
const nextStat = fsSync.lstatSync(next);
|
|
41035
|
+
const segmentFailure = classifyExistingDirectorySegment(nextStat, scopeLabel);
|
|
41036
|
+
if (segmentFailure) {
|
|
41037
|
+
return segmentFailure;
|
|
41038
|
+
}
|
|
41039
|
+
current = next;
|
|
41040
|
+
currentStat = nextStat;
|
|
41041
|
+
}
|
|
41042
|
+
catch (err) {
|
|
41043
|
+
const code = err.code;
|
|
41044
|
+
if (code === "ENOENT") {
|
|
41045
|
+
return {
|
|
41046
|
+
ok: true,
|
|
41047
|
+
ancestorPath: current,
|
|
41048
|
+
missingSegments: segments.slice(index),
|
|
41049
|
+
};
|
|
41050
|
+
}
|
|
41051
|
+
const failure = classifyDirectoryLookupError(err, scopeLabel);
|
|
41052
|
+
if (failure) {
|
|
41053
|
+
return failure;
|
|
41054
|
+
}
|
|
41055
|
+
throw err;
|
|
41056
|
+
}
|
|
41057
|
+
}
|
|
41058
|
+
return { ok: true, ancestorPath: current, missingSegments: [] };
|
|
41059
|
+
}
|
|
41060
|
+
function assertAbsolutePathInput(filePath) {
|
|
41061
|
+
if (!filePath) {
|
|
41062
|
+
throw new FsSafeError("invalid-path", "path is required");
|
|
41063
|
+
}
|
|
41064
|
+
if (filePath.includes("\0")) {
|
|
41065
|
+
throw new FsSafeError("invalid-path", "path must not contain NUL bytes");
|
|
41066
|
+
}
|
|
41067
|
+
if (!path.isAbsolute(filePath)) {
|
|
41068
|
+
throw new FsSafeError("invalid-path", "path must be absolute");
|
|
41069
|
+
}
|
|
41070
|
+
return path.normalize(filePath);
|
|
41071
|
+
}
|
|
41072
|
+
async function findExistingAncestor(filePath) {
|
|
41073
|
+
return (await findExistingAncestorWithStat(filePath))?.path ?? null;
|
|
41074
|
+
}
|
|
41075
|
+
async function findExistingAncestorWithStat(filePath) {
|
|
41076
|
+
let current = external_node_path_.resolve(filePath);
|
|
41077
|
+
while (true) {
|
|
41078
|
+
try {
|
|
41079
|
+
return { path: current, stat: external_node_fs_.lstatSync(current) };
|
|
41080
|
+
}
|
|
41081
|
+
catch (err) {
|
|
41082
|
+
if (err.code !== "ENOENT") {
|
|
41083
|
+
throw err;
|
|
41084
|
+
}
|
|
41085
|
+
}
|
|
41086
|
+
const parent = external_node_path_.dirname(current);
|
|
41087
|
+
if (parent === current) {
|
|
41088
|
+
return null;
|
|
41089
|
+
}
|
|
41090
|
+
current = parent;
|
|
41091
|
+
}
|
|
41092
|
+
}
|
|
41093
|
+
async function absolute_path_ensureAbsoluteDirectory(dirPath, options = {}) {
|
|
41094
|
+
const scopeLabel = options.scopeLabel ?? "directory";
|
|
41095
|
+
let targetPath;
|
|
41096
|
+
try {
|
|
41097
|
+
targetPath = assertAbsolutePathInput(dirPath);
|
|
41098
|
+
}
|
|
41099
|
+
catch (err) {
|
|
41100
|
+
if (err instanceof FsSafeError) {
|
|
41101
|
+
return { ok: false, code: err.code, error: err };
|
|
41102
|
+
}
|
|
41103
|
+
throw err;
|
|
41104
|
+
}
|
|
41105
|
+
const prefix = await resolveTrustedDirectoryPrefix(targetPath, scopeLabel);
|
|
41106
|
+
if (!prefix.ok) {
|
|
41107
|
+
return prefix;
|
|
41108
|
+
}
|
|
41109
|
+
let current = prefix.ancestorPath;
|
|
41110
|
+
const initialGuard = await createDirectoryGuardResult(prefix.ancestorPath, scopeLabel);
|
|
41111
|
+
if (!initialGuard.ok) {
|
|
41112
|
+
return initialGuard;
|
|
41113
|
+
}
|
|
41114
|
+
let currentGuard = initialGuard.guard;
|
|
41115
|
+
for (const segment of prefix.missingSegments) {
|
|
41116
|
+
current = path.join(current, segment);
|
|
41117
|
+
while (true) {
|
|
41118
|
+
const guardResult = await assertGuardResult(currentGuard, scopeLabel);
|
|
41119
|
+
if (!guardResult.ok) {
|
|
41120
|
+
return guardResult;
|
|
41121
|
+
}
|
|
41122
|
+
try {
|
|
41123
|
+
const stat = fsSync.lstatSync(current);
|
|
41124
|
+
if (stat.isSymbolicLink()) {
|
|
41125
|
+
return ensureDirectoryFailure("symlink", `directory path traverses a symlink within ${scopeLabel}`);
|
|
41126
|
+
}
|
|
41127
|
+
if (!stat.isDirectory()) {
|
|
41128
|
+
return ensureDirectoryFailure("not-file", `path must be a real directory within ${scopeLabel}`);
|
|
41129
|
+
}
|
|
41130
|
+
break;
|
|
41131
|
+
}
|
|
41132
|
+
catch (err) {
|
|
41133
|
+
if (err.code !== "ENOENT") {
|
|
41134
|
+
throw err;
|
|
41135
|
+
}
|
|
41136
|
+
const parentStillValid = await assertGuardResult(currentGuard, scopeLabel);
|
|
41137
|
+
if (!parentStillValid.ok) {
|
|
41138
|
+
return parentStillValid;
|
|
41139
|
+
}
|
|
41140
|
+
try {
|
|
41141
|
+
await fs.mkdir(current, { mode: options.mode });
|
|
41142
|
+
}
|
|
41143
|
+
catch (mkdirErr) {
|
|
41144
|
+
if (mkdirErr.code === "EEXIST") {
|
|
41145
|
+
continue;
|
|
41146
|
+
}
|
|
41147
|
+
throw mkdirErr;
|
|
41148
|
+
}
|
|
41149
|
+
}
|
|
41150
|
+
}
|
|
41151
|
+
const nextGuard = await createDirectoryGuardResult(current, scopeLabel);
|
|
41152
|
+
if (!nextGuard.ok) {
|
|
41153
|
+
return nextGuard;
|
|
41154
|
+
}
|
|
41155
|
+
const previousGuardStillValid = await assertGuardResult(currentGuard, scopeLabel);
|
|
41156
|
+
if (!previousGuardStillValid.ok) {
|
|
41157
|
+
return previousGuardStillValid;
|
|
41158
|
+
}
|
|
41159
|
+
currentGuard = nextGuard.guard;
|
|
41160
|
+
}
|
|
41161
|
+
const finalGuardResult = await assertGuardResult(currentGuard, scopeLabel);
|
|
41162
|
+
if (!finalGuardResult.ok) {
|
|
41163
|
+
return finalGuardResult;
|
|
41164
|
+
}
|
|
41165
|
+
return { ok: true, path: targetPath };
|
|
41166
|
+
}
|
|
41167
|
+
async function canonicalPathFromExistingAncestor(filePath) {
|
|
41168
|
+
const ancestor = await findExistingAncestor(filePath);
|
|
41169
|
+
if (!ancestor) {
|
|
41170
|
+
return external_node_path_.resolve(filePath);
|
|
41171
|
+
}
|
|
41172
|
+
let canonicalAncestor = ancestor;
|
|
41173
|
+
try {
|
|
41174
|
+
canonicalAncestor = external_node_fs_.realpathSync.native(ancestor);
|
|
41175
|
+
}
|
|
41176
|
+
catch {
|
|
41177
|
+
// Keep lexical path when the existing ancestor cannot be canonicalized.
|
|
41178
|
+
}
|
|
41179
|
+
const relative = external_node_path_.relative(ancestor, filePath);
|
|
41180
|
+
return relative ? external_node_path_.join(canonicalAncestor, relative) : canonicalAncestor;
|
|
41181
|
+
}
|
|
41182
|
+
async function resolveAbsolutePathForRead(filePath, options = {}) {
|
|
41183
|
+
const symlinks = resolveSymlinkPolicy(options.symlinks);
|
|
41184
|
+
const normalized = assertAbsolutePathInput(filePath);
|
|
41185
|
+
let canonicalPath;
|
|
41186
|
+
try {
|
|
41187
|
+
canonicalPath = fsSync.realpathSync.native(normalized);
|
|
41188
|
+
}
|
|
41189
|
+
catch (err) {
|
|
41190
|
+
if (err.code === "ENOENT") {
|
|
41191
|
+
throw new FsSafeError("not-found", "path not found", { cause: err });
|
|
41192
|
+
}
|
|
41193
|
+
throw err;
|
|
41194
|
+
}
|
|
41195
|
+
if (symlinks === "reject" && canonicalPath !== normalized) {
|
|
41196
|
+
throw new FsSafeError("symlink", "path traverses a symlink", { cause: { canonicalPath } });
|
|
41197
|
+
}
|
|
41198
|
+
return { path: normalized, canonicalPath };
|
|
41199
|
+
}
|
|
41200
|
+
async function resolveAbsolutePathForWrite(filePath, options = {}) {
|
|
41201
|
+
const symlinks = resolveSymlinkPolicy(options.symlinks);
|
|
41202
|
+
const normalized = assertAbsolutePathInput(filePath);
|
|
41203
|
+
const parentDir = path.dirname(normalized);
|
|
41204
|
+
const parentExists = await pathExists(parentDir);
|
|
41205
|
+
if (symlinks === "reject") {
|
|
41206
|
+
const filesystemRoot = path.parse(normalized).root;
|
|
41207
|
+
await resolveRootPath({
|
|
41208
|
+
absolutePath: normalized,
|
|
41209
|
+
rootPath: filesystemRoot,
|
|
41210
|
+
rootCanonicalPath: filesystemRoot,
|
|
41211
|
+
boundaryLabel: "absolute path",
|
|
41212
|
+
rejectSymlinks: true,
|
|
41213
|
+
});
|
|
41214
|
+
}
|
|
41215
|
+
const canonicalPath = await canonicalPathFromExistingAncestor(normalized);
|
|
41216
|
+
if (symlinks === "reject" && canonicalPath !== normalized) {
|
|
41217
|
+
throw new FsSafeError("symlink", "path traverses a symlink", {
|
|
41218
|
+
cause: { canonicalPath },
|
|
41219
|
+
});
|
|
41220
|
+
}
|
|
41221
|
+
return {
|
|
41222
|
+
path: normalized,
|
|
41223
|
+
canonicalPath,
|
|
41224
|
+
parentDir,
|
|
41225
|
+
parentExists,
|
|
41226
|
+
};
|
|
41227
|
+
}
|
|
41228
|
+
|
|
40477
41229
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/sidecar-lock-policy.js
|
|
40478
41230
|
|
|
40479
41231
|
function assertFiniteNonNegative(value, label) {
|
|
@@ -40525,10 +41277,6 @@ function isTransientLockFileDenial(error, lockPath) {
|
|
|
40525
41277
|
const denial = error;
|
|
40526
41278
|
return process.platform === "win32" && denial?.code === "EPERM" && denial.path === lockPath;
|
|
40527
41279
|
}
|
|
40528
|
-
function sidecarLockPayloadIsStale(payload, staleMs, nowMs) {
|
|
40529
|
-
const createdAtMs = sidecarLockPayloadCreatedAtMs(payload);
|
|
40530
|
-
return createdAtMs !== null && nowMs - createdAtMs > staleMs;
|
|
40531
|
-
}
|
|
40532
41280
|
function sidecarLockPayloadCreatedAtMs(payload) {
|
|
40533
41281
|
const createdAt = payload &&
|
|
40534
41282
|
typeof payload === "object" &&
|
|
@@ -40544,7 +41292,7 @@ async function defaultSidecarLockShouldReclaim(params) {
|
|
|
40544
41292
|
if (createdAtMs !== null)
|
|
40545
41293
|
return params.nowMs - createdAtMs > params.staleMs;
|
|
40546
41294
|
try {
|
|
40547
|
-
return params.nowMs -
|
|
41295
|
+
return params.nowMs - external_node_fs_.statSync(params.lockPath).mtimeMs > params.staleMs;
|
|
40548
41296
|
}
|
|
40549
41297
|
catch {
|
|
40550
41298
|
return true;
|
|
@@ -40578,12 +41326,23 @@ function createSuppressedError(error, suppressed, message) {
|
|
|
40578
41326
|
|
|
40579
41327
|
|
|
40580
41328
|
|
|
40581
|
-
|
|
41329
|
+
|
|
41330
|
+
|
|
41331
|
+
|
|
41332
|
+
async function resolveNormalizedTargetPath(targetPath, lockRoot) {
|
|
40582
41333
|
const resolved = external_node_path_.resolve(targetPath);
|
|
40583
41334
|
const dir = external_node_path_.dirname(resolved);
|
|
41335
|
+
if (lockRoot) {
|
|
41336
|
+
// The target is an arbitration key, not necessarily inside the lock Root.
|
|
41337
|
+
// Leave parent creation to the Root-backed sidecar write.
|
|
41338
|
+
await lockRoot.resolve(".");
|
|
41339
|
+
const parent = await canonicalPathFromExistingAncestor(dir);
|
|
41340
|
+
await lockRoot.resolve(".");
|
|
41341
|
+
return external_node_path_.join(parent, external_node_path_.basename(resolved));
|
|
41342
|
+
}
|
|
40584
41343
|
await promises_.mkdir(dir, { recursive: true });
|
|
40585
41344
|
try {
|
|
40586
|
-
return external_node_path_.join(
|
|
41345
|
+
return external_node_path_.join(external_node_fs_.realpathSync.native(dir), external_node_path_.basename(resolved));
|
|
40587
41346
|
}
|
|
40588
41347
|
catch {
|
|
40589
41348
|
return resolved;
|
|
@@ -40594,7 +41353,7 @@ async function acquireSidecarLock(options, context) {
|
|
|
40594
41353
|
validateSidecarLockRetryOptions(retry);
|
|
40595
41354
|
validateSidecarLockTimeoutMs(options.timeoutMs);
|
|
40596
41355
|
context.ensureExitCleanupRegistered();
|
|
40597
|
-
const normalizedTargetPath = await resolveNormalizedTargetPath(options.targetPath);
|
|
41356
|
+
const normalizedTargetPath = await resolveNormalizedTargetPath(options.targetPath, options.lockRoot);
|
|
40598
41357
|
const lockPath = options.lockPath ?? `${normalizedTargetPath}.lock`;
|
|
40599
41358
|
let held = context.held.get(normalizedTargetPath);
|
|
40600
41359
|
if (held &&
|
|
@@ -40614,11 +41373,15 @@ async function acquireSidecarLock(options, context) {
|
|
|
40614
41373
|
held.reentrantOwner !== undefined &&
|
|
40615
41374
|
options.reentrantOwner === held.reentrantOwner) {
|
|
40616
41375
|
held.refCount += 1;
|
|
41376
|
+
// Retention is monotonic: any same-owner request to keep the sidecar on
|
|
41377
|
+
// exit upgrades the held lock; a later default acquisition never revokes it.
|
|
41378
|
+
if (options.retainOnExit === true) {
|
|
41379
|
+
held.retainOnExit = true;
|
|
41380
|
+
}
|
|
40617
41381
|
return context.handleForHeldLock(normalizedTargetPath, held);
|
|
40618
41382
|
}
|
|
40619
41383
|
}
|
|
40620
41384
|
const startedAt = Date.now();
|
|
40621
|
-
const maxRetries = options.timeoutMs === Number.POSITIVE_INFINITY ? undefined : retry.retries;
|
|
40622
41385
|
const reclaimGuardPath = `${lockPath}.reclaim`;
|
|
40623
41386
|
let ownsReclaimGuard = false;
|
|
40624
41387
|
let attempt = 0;
|
|
@@ -40630,7 +41393,7 @@ async function acquireSidecarLock(options, context) {
|
|
|
40630
41393
|
if ((options.timeoutMs !== undefined &&
|
|
40631
41394
|
options.timeoutMs !== Number.POSITIVE_INFINITY &&
|
|
40632
41395
|
elapsed >= options.timeoutMs) ||
|
|
40633
|
-
(
|
|
41396
|
+
(retry.retries !== undefined && attempt >= retry.retries)) {
|
|
40634
41397
|
throw Object.assign(new Error(`file lock timeout for ${normalizedTargetPath}`), {
|
|
40635
41398
|
code: "file_lock_timeout",
|
|
40636
41399
|
lockPath,
|
|
@@ -40672,10 +41435,14 @@ async function acquireSidecarLock(options, context) {
|
|
|
40672
41435
|
if (options.lockRoot) {
|
|
40673
41436
|
const lockRoot = options.lockRoot;
|
|
40674
41437
|
const relativeLockPath = relativeSidecarLockPath(lockRoot, lockPath);
|
|
41438
|
+
const observation = fileObservation();
|
|
40675
41439
|
try {
|
|
40676
|
-
await lockRoot.create(relativeLockPath, raw, { mkdir: true, mode: 0o600 });
|
|
41440
|
+
await observation.run(() => lockRoot.create(relativeLockPath, raw, { mkdir: true, mode: 0o600 }));
|
|
40677
41441
|
}
|
|
40678
41442
|
catch (error) {
|
|
41443
|
+
// Only this invocation's failed exclusive open grants denial retry authority.
|
|
41444
|
+
lockFileCreateDenied = observation.has(error, `exclusive-create:${lockPath}`) &&
|
|
41445
|
+
isTransientLockFileDenial(error, lockPath);
|
|
40679
41446
|
if (error instanceof errors_FsSafeError && error.code === "already-exists") {
|
|
40680
41447
|
throw Object.assign(new Error("sidecar lock exists"), { code: "EEXIST" });
|
|
40681
41448
|
}
|
|
@@ -40712,7 +41479,7 @@ async function acquireSidecarLock(options, context) {
|
|
|
40712
41479
|
}
|
|
40713
41480
|
await handle.writeFile(raw, "utf8");
|
|
40714
41481
|
}
|
|
40715
|
-
const snapshot = { raw, payload, stat:
|
|
41482
|
+
const snapshot = { raw, payload, stat: external_node_fs_.fstatSync(handle.fd), ownershipToken };
|
|
40716
41483
|
if (snapshot.stat.nlink === 0) {
|
|
40717
41484
|
await handle.close();
|
|
40718
41485
|
handle = null;
|
|
@@ -40728,6 +41495,7 @@ async function acquireSidecarLock(options, context) {
|
|
|
40728
41495
|
acquiredAt: Date.now(),
|
|
40729
41496
|
metadata: options.metadata ?? {},
|
|
40730
41497
|
lockRoot: options.lockRoot,
|
|
41498
|
+
retainOnExit: options.retainOnExit,
|
|
40731
41499
|
parsePayload: options.parsePayload,
|
|
40732
41500
|
};
|
|
40733
41501
|
context.held.set(normalizedTargetPath, createdHeld);
|
|
@@ -40765,7 +41533,7 @@ async function acquireSidecarLock(options, context) {
|
|
|
40765
41533
|
if (handle) {
|
|
40766
41534
|
const failedSnapshot = createdSnapshot ?? { payload: null };
|
|
40767
41535
|
try {
|
|
40768
|
-
failedSnapshot.stat =
|
|
41536
|
+
failedSnapshot.stat = external_node_fs_.fstatSync(handle.fd);
|
|
40769
41537
|
}
|
|
40770
41538
|
catch {
|
|
40771
41539
|
// Best-effort cleanup of a failed exclusive create.
|
|
@@ -40938,9 +41706,15 @@ function createHeldSidecarLockHandle(params) {
|
|
|
40938
41706
|
|
|
40939
41707
|
|
|
40940
41708
|
|
|
41709
|
+
|
|
40941
41710
|
const GLOBAL_STATE_KEY = Symbol.for("fsSafe.sidecarLockManagers");
|
|
40942
41711
|
const GLOBAL_CLEANUP_KEY = Symbol.for("fsSafe.sidecarLockCleanupRegistered");
|
|
40943
41712
|
const GLOBAL_CLEANUP_HANDLER_KEY = Symbol.for("fsSafe.sidecarLockCleanupHandler");
|
|
41713
|
+
const GLOBAL_BEFORE_EXIT_KEY = Symbol.for("fsSafe.sidecarLockBeforeExitCleanup");
|
|
41714
|
+
// Set by copies whose exit handlers honor retainOnExit. When an older package
|
|
41715
|
+
// copy registered the handlers first, this marker stays absent and retained
|
|
41716
|
+
// acquisitions must fail closed rather than silently lose the guarantee.
|
|
41717
|
+
const GLOBAL_RETAIN_AWARE_KEY = Symbol.for("fsSafe.sidecarLockRetainAwareCleanup");
|
|
40944
41718
|
function getGlobalManagers() {
|
|
40945
41719
|
const globalWithState = globalThis;
|
|
40946
41720
|
if (!globalWithState[GLOBAL_STATE_KEY]) {
|
|
@@ -41013,7 +41787,8 @@ function snapshotMatchesSync(lockPath, observed) {
|
|
|
41013
41787
|
}
|
|
41014
41788
|
}
|
|
41015
41789
|
function releaseAllReclaimGuardsSync(state) {
|
|
41016
|
-
|
|
41790
|
+
// Exit cleanup also visits managers created by older copies and never reopened here.
|
|
41791
|
+
for (const reclaimGuardPath of state.reclaimGuards ?? []) {
|
|
41017
41792
|
try {
|
|
41018
41793
|
external_node_fs_.rmdirSync(reclaimGuardPath);
|
|
41019
41794
|
state.reclaimGuards.delete(reclaimGuardPath);
|
|
@@ -41023,11 +41798,12 @@ function releaseAllReclaimGuardsSync(state) {
|
|
|
41023
41798
|
}
|
|
41024
41799
|
}
|
|
41025
41800
|
}
|
|
41026
|
-
function releaseAllLocksSync(state) {
|
|
41801
|
+
function releaseAllLocksSync(state, options) {
|
|
41027
41802
|
for (const [normalizedTargetPath, held] of state.held) {
|
|
41028
41803
|
void held.handle.close().catch(() => undefined);
|
|
41029
41804
|
try {
|
|
41030
|
-
|
|
41805
|
+
const retained = options?.preserveRetained === true && held.retainOnExit;
|
|
41806
|
+
if (!retained && !held.lockRoot && snapshotMatchesSync(held.lockPath, held.snapshot)) {
|
|
41031
41807
|
external_node_fs_.rmSync(held.lockPath, { force: true });
|
|
41032
41808
|
}
|
|
41033
41809
|
}
|
|
@@ -41043,14 +41819,43 @@ function ensureGlobalExitCleanupRegistered() {
|
|
|
41043
41819
|
if (globalWithCleanup[GLOBAL_CLEANUP_KEY])
|
|
41044
41820
|
return;
|
|
41045
41821
|
globalWithCleanup[GLOBAL_CLEANUP_KEY] = true;
|
|
41822
|
+
globalWithCleanup[GLOBAL_RETAIN_AWARE_KEY] = true;
|
|
41046
41823
|
const cleanup = () => {
|
|
41047
41824
|
for (const state of getGlobalManagers().values()) {
|
|
41048
|
-
releaseAllLocksSync(state);
|
|
41825
|
+
releaseAllLocksSync(state, { preserveRetained: true });
|
|
41049
41826
|
}
|
|
41050
41827
|
};
|
|
41051
41828
|
globalWithCleanup[GLOBAL_CLEANUP_HANDLER_KEY] = cleanup;
|
|
41052
41829
|
process.on("exit", cleanup);
|
|
41053
41830
|
}
|
|
41831
|
+
/** True when a retain-unaware package copy registered the process-exit handlers first. */
|
|
41832
|
+
function exitCleanupCannotRetain() {
|
|
41833
|
+
const globalWithCleanup = globalThis;
|
|
41834
|
+
return globalWithCleanup[GLOBAL_CLEANUP_KEY] === true && globalWithCleanup[GLOBAL_RETAIN_AWARE_KEY] !== true;
|
|
41835
|
+
}
|
|
41836
|
+
function ensureGlobalBeforeExitCleanupRegistered() {
|
|
41837
|
+
const globalWithCleanup = globalThis;
|
|
41838
|
+
if (globalWithCleanup[GLOBAL_BEFORE_EXIT_KEY]) {
|
|
41839
|
+
return globalWithCleanup[GLOBAL_BEFORE_EXIT_KEY];
|
|
41840
|
+
}
|
|
41841
|
+
// Independent of the exit registration, which an older package copy may own.
|
|
41842
|
+
const lifecycle = { armed: false };
|
|
41843
|
+
globalWithCleanup[GLOBAL_BEFORE_EXIT_KEY] = lifecycle;
|
|
41844
|
+
process.on("beforeExit", () => {
|
|
41845
|
+
if (!lifecycle.armed)
|
|
41846
|
+
return;
|
|
41847
|
+
// Cleanup itself schedules I/O; retry only after another acquisition.
|
|
41848
|
+
lifecycle.armed = false;
|
|
41849
|
+
for (const state of getGlobalManagers().values()) {
|
|
41850
|
+
for (const [normalizedTargetPath, held] of Array.from(state.held.entries())) {
|
|
41851
|
+
if (held.lockRoot && !held.retainOnExit) {
|
|
41852
|
+
void releaseHeldLock(state, normalizedTargetPath, held, { force: true }).catch(() => undefined);
|
|
41853
|
+
}
|
|
41854
|
+
}
|
|
41855
|
+
}
|
|
41856
|
+
});
|
|
41857
|
+
return lifecycle;
|
|
41858
|
+
}
|
|
41054
41859
|
async function releaseHeldLock(state, normalizedTargetPath, held, options = {}) {
|
|
41055
41860
|
const current = state.held.get(normalizedTargetPath);
|
|
41056
41861
|
if (current !== held) {
|
|
@@ -41092,6 +41897,7 @@ async function releaseHeldLock(state, normalizedTargetPath, held, options = {})
|
|
|
41092
41897
|
}
|
|
41093
41898
|
}
|
|
41094
41899
|
function handleForHeldLock(state, normalizedTargetPath, held) {
|
|
41900
|
+
ensureGlobalBeforeExitCleanupRegistered().armed = true;
|
|
41095
41901
|
return createHeldSidecarLockHandle({
|
|
41096
41902
|
normalizedTargetPath,
|
|
41097
41903
|
held,
|
|
@@ -41104,8 +41910,12 @@ function createSidecarLockManager(key) {
|
|
|
41104
41910
|
state.cleanupRegistered = true;
|
|
41105
41911
|
state.reclaimCleanupRegistered = true;
|
|
41106
41912
|
ensureGlobalExitCleanupRegistered();
|
|
41913
|
+
ensureGlobalBeforeExitCleanupRegistered().armed = true;
|
|
41107
41914
|
}
|
|
41108
41915
|
async function acquire(options) {
|
|
41916
|
+
if (options.retainOnExit === true && exitCleanupCannotRetain()) {
|
|
41917
|
+
throw new errors_FsSafeError("helper-unavailable", "retainOnExit requires this process's exit handlers to be retain-aware; an older package copy registered them first");
|
|
41918
|
+
}
|
|
41109
41919
|
return await acquireSidecarLock(options, {
|
|
41110
41920
|
held: state.held,
|
|
41111
41921
|
reclaimGuards: state.reclaimGuards,
|
|
@@ -41175,6 +41985,8 @@ async function withSidecarLock(targetPath, options, fn) {
|
|
|
41175
41985
|
|
|
41176
41986
|
|
|
41177
41987
|
|
|
41988
|
+
|
|
41989
|
+
|
|
41178
41990
|
function pinned_write_byteLength(input, encoding) {
|
|
41179
41991
|
return typeof input === "string"
|
|
41180
41992
|
? Buffer.byteLength(input, encoding ?? "utf8")
|
|
@@ -41194,16 +42006,6 @@ function assertWithinMaxBytes(bytes, maxBytes) {
|
|
|
41194
42006
|
throw new errors_FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`);
|
|
41195
42007
|
}
|
|
41196
42008
|
}
|
|
41197
|
-
async function syncFileBestEffort(handle) {
|
|
41198
|
-
try {
|
|
41199
|
-
await handle.sync();
|
|
41200
|
-
}
|
|
41201
|
-
catch (error) {
|
|
41202
|
-
if (error?.code !== "EPERM") {
|
|
41203
|
-
throw error;
|
|
41204
|
-
}
|
|
41205
|
-
}
|
|
41206
|
-
}
|
|
41207
42009
|
async function writeStreamToHandle(stream, handle, maxBytes) {
|
|
41208
42010
|
let bytes = 0;
|
|
41209
42011
|
for await (const chunk of stream) {
|
|
@@ -41245,7 +42047,7 @@ async function runPinnedWriteWithRenamePolicy(params) {
|
|
|
41245
42047
|
const relativeTargetPath = writeParams.relativeParentPath
|
|
41246
42048
|
? `${writeParams.relativeParentPath}/${writeParams.basename}`
|
|
41247
42049
|
: writeParams.basename;
|
|
41248
|
-
const lockPath = external_node_path_.join(writeParams.rootPath, `.fs-safe-write-${
|
|
42050
|
+
const lockPath = external_node_path_.join(writeParams.rootPath, `.fs-safe-write-${file_identity_sha256Hex(relativeTargetPath)}.lock`);
|
|
41249
42051
|
return await withSidecarLock(writeParams.rootPath, {
|
|
41250
42052
|
managerKey: `fs-safe.write:${targetPath}`,
|
|
41251
42053
|
lockPath,
|
|
@@ -41259,6 +42061,11 @@ async function runPinnedWriteWithRenamePolicy(params) {
|
|
|
41259
42061
|
}));
|
|
41260
42062
|
}
|
|
41261
42063
|
async function runPinnedWriteFallback(params) {
|
|
42064
|
+
const exactRoot = typeof params.rootIdentity?.dev === "bigint" && typeof params.rootIdentity.ino === "bigint"
|
|
42065
|
+
? { dev: params.rootIdentity.dev, ino: params.rootIdentity.ino } : undefined;
|
|
42066
|
+
if (exactRoot)
|
|
42067
|
+
await inspectDirectoryIdentity(params.rootPath, exactRoot);
|
|
42068
|
+
const guardOptions = { bigint: exactRoot !== undefined };
|
|
41262
42069
|
let parentPath = params.relativeParentPath
|
|
41263
42070
|
? external_node_path_.join(params.rootPath, ...params.relativeParentPath.split("/"))
|
|
41264
42071
|
: params.rootPath;
|
|
@@ -41274,8 +42081,8 @@ async function runPinnedWriteFallback(params) {
|
|
|
41274
42081
|
});
|
|
41275
42082
|
}
|
|
41276
42083
|
const parentGuard = params.mkdir
|
|
41277
|
-
? await directory_guard_createAsyncDirectoryGuard(parentPath)
|
|
41278
|
-
: await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath);
|
|
42084
|
+
? await directory_guard_createAsyncDirectoryGuard(parentPath, guardOptions)
|
|
42085
|
+
: await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath, guardOptions);
|
|
41279
42086
|
const targetPath = external_node_path_.join(parentPath, params.basename);
|
|
41280
42087
|
if (params.overwrite === false) {
|
|
41281
42088
|
const handle = await withAsyncDirectoryGuards([parentGuard], async () => await promises_.open(targetPath, external_node_fs_.constants.O_WRONLY | external_node_fs_.constants.O_CREAT | external_node_fs_.constants.O_EXCL, params.mode), {
|
|
@@ -41286,9 +42093,10 @@ async function runPinnedWriteFallback(params) {
|
|
|
41286
42093
|
},
|
|
41287
42094
|
});
|
|
41288
42095
|
let created = true;
|
|
42096
|
+
let createdIdentity;
|
|
41289
42097
|
try {
|
|
41290
|
-
const verificationIdentity =
|
|
41291
|
-
|
|
42098
|
+
const verificationIdentity = external_node_fs_.fstatSync(handle.fd, { bigint: true });
|
|
42099
|
+
createdIdentity = verificationIdentity;
|
|
41292
42100
|
if (params.input.kind === "buffer") {
|
|
41293
42101
|
assertWithinMaxBytes(pinned_write_byteLength(params.input.data, params.input.encoding), params.maxBytes);
|
|
41294
42102
|
if (typeof params.input.data === "string") {
|
|
@@ -41301,18 +42109,26 @@ async function runPinnedWriteFallback(params) {
|
|
|
41301
42109
|
else {
|
|
41302
42110
|
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
41303
42111
|
}
|
|
41304
|
-
|
|
41305
|
-
|
|
41306
|
-
|
|
42112
|
+
// Content writes may clear set-ID bits; finalize them through the owned fd.
|
|
42113
|
+
await handle.chmod(params.mode);
|
|
42114
|
+
if (params.sync !== false)
|
|
42115
|
+
await syncFileBestEffort(handle);
|
|
42116
|
+
const stat = external_node_fs_.fstatSync(handle.fd);
|
|
42117
|
+
if (params.sync !== false)
|
|
42118
|
+
await syncDirectoryBestEffort(parentPath);
|
|
41307
42119
|
// Publication is complete. A failed outer check must not remove its target.
|
|
41308
42120
|
created = false;
|
|
41309
42121
|
await params.verifyPublished?.(handle.fd, verificationIdentity, parentGuard);
|
|
41310
42122
|
return { dev: stat.dev, ino: stat.ino };
|
|
41311
42123
|
}
|
|
41312
42124
|
finally {
|
|
41313
|
-
|
|
41314
|
-
|
|
41315
|
-
|
|
42125
|
+
try {
|
|
42126
|
+
if (created) {
|
|
42127
|
+
await cleanupPinnedFilePath({ pathname: targetPath, handle, identity: createdIdentity, parentGuard });
|
|
42128
|
+
}
|
|
42129
|
+
}
|
|
42130
|
+
finally {
|
|
42131
|
+
await handle.close().catch(() => undefined);
|
|
41316
42132
|
}
|
|
41317
42133
|
}
|
|
41318
42134
|
}
|
|
@@ -41326,12 +42142,13 @@ async function runPinnedWriteFallback(params) {
|
|
|
41326
42142
|
: 0);
|
|
41327
42143
|
let handle;
|
|
41328
42144
|
let tempStat;
|
|
42145
|
+
let tempIdentity;
|
|
41329
42146
|
let readHandle;
|
|
41330
42147
|
let renamed = false;
|
|
41331
42148
|
try {
|
|
41332
42149
|
handle = await promises_.open(tempPath, tempFlags, params.mode);
|
|
41333
|
-
let verificationIdentity =
|
|
41334
|
-
|
|
42150
|
+
let verificationIdentity = external_node_fs_.fstatSync(handle.fd, { bigint: true });
|
|
42151
|
+
tempIdentity = verificationIdentity;
|
|
41335
42152
|
if (params.input.kind === "buffer") {
|
|
41336
42153
|
assertWithinMaxBytes(pinned_write_byteLength(params.input.data, params.input.encoding), params.maxBytes);
|
|
41337
42154
|
if (typeof params.input.data === "string") {
|
|
@@ -41344,20 +42161,23 @@ async function runPinnedWriteFallback(params) {
|
|
|
41344
42161
|
else {
|
|
41345
42162
|
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
41346
42163
|
}
|
|
41347
|
-
tempStat =
|
|
41348
|
-
const tempPathStat =
|
|
42164
|
+
tempStat = external_node_fs_.fstatSync(handle.fd);
|
|
42165
|
+
const tempPathStat = external_node_fs_.lstatSync(tempPath);
|
|
41349
42166
|
if (tempPathStat.isSymbolicLink() || !file_identity_sameFileIdentity(tempPathStat, tempStat)) {
|
|
41350
42167
|
throw new errors_FsSafeError("path-mismatch", "fallback temp path changed during write");
|
|
41351
42168
|
}
|
|
41352
42169
|
const expectedTempStat = tempStat;
|
|
41353
|
-
await
|
|
42170
|
+
await handle.chmod(params.mode);
|
|
42171
|
+
if (params.sync !== false)
|
|
42172
|
+
await syncFileBestEffort(handle);
|
|
41354
42173
|
let verifiedIdentity = expectedTempStat;
|
|
41355
42174
|
await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
41356
42175
|
await promises_.rename(tempPath, targetPath);
|
|
41357
42176
|
renamed = true;
|
|
41358
42177
|
await getFsSafeTestHooks()?.afterPinnedWriteFallbackRename?.(targetPath);
|
|
41359
|
-
|
|
41360
|
-
|
|
42178
|
+
if (params.sync !== false)
|
|
42179
|
+
await syncDirectoryBestEffort(parentPath);
|
|
42180
|
+
const targetStat = external_node_fs_.lstatSync(targetPath);
|
|
41361
42181
|
if (targetStat.isSymbolicLink()) {
|
|
41362
42182
|
throw new errors_FsSafeError("path-mismatch", "fallback target changed during write");
|
|
41363
42183
|
}
|
|
@@ -41372,10 +42192,10 @@ async function runPinnedWriteFallback(params) {
|
|
|
41372
42192
|
if (params.input.kind !== "buffer") {
|
|
41373
42193
|
throw new errors_FsSafeError("path-mismatch", "fallback target changed during write");
|
|
41374
42194
|
}
|
|
41375
|
-
const expectedHash =
|
|
42195
|
+
const expectedHash = file_identity_sha256Hex(params.input.data, params.input.encoding);
|
|
41376
42196
|
readHandle = await promises_.open(targetPath, read_open_flags_resolveReadOpenFlags());
|
|
41377
|
-
const readHandleStat =
|
|
41378
|
-
const actualHash =
|
|
42197
|
+
const readHandleStat = external_node_fs_.fstatSync(readHandle.fd, { bigint: true });
|
|
42198
|
+
const actualHash = file_identity_sha256Hex(await readHandle.readFile());
|
|
41379
42199
|
if (actualHash !== expectedHash) {
|
|
41380
42200
|
throw new errors_FsSafeError("path-mismatch", "fallback target changed during write");
|
|
41381
42201
|
}
|
|
@@ -41389,10 +42209,14 @@ async function runPinnedWriteFallback(params) {
|
|
|
41389
42209
|
return { dev: verifiedIdentity.dev, ino: verifiedIdentity.ino };
|
|
41390
42210
|
}
|
|
41391
42211
|
finally {
|
|
41392
|
-
|
|
41393
|
-
|
|
41394
|
-
|
|
41395
|
-
|
|
42212
|
+
try {
|
|
42213
|
+
if (!renamed && handle) {
|
|
42214
|
+
await cleanupPinnedFilePath({ pathname: tempPath, handle, identity: tempIdentity, parentGuard });
|
|
42215
|
+
}
|
|
42216
|
+
}
|
|
42217
|
+
finally {
|
|
42218
|
+
await readHandle?.close().catch(() => undefined);
|
|
42219
|
+
await handle?.close().catch(() => undefined);
|
|
41396
42220
|
}
|
|
41397
42221
|
}
|
|
41398
42222
|
}
|
|
@@ -41404,7 +42228,7 @@ async function runPinnedWriteFallback(params) {
|
|
|
41404
42228
|
|
|
41405
42229
|
const PATH_ALIAS_POLICIES = ROOT_PATH_ALIAS_POLICIES;
|
|
41406
42230
|
async function assertNoPathAliasEscape(params) {
|
|
41407
|
-
const resolved = await
|
|
42231
|
+
const resolved = await root_path_resolveRootPath({
|
|
41408
42232
|
absolutePath: params.absolutePath,
|
|
41409
42233
|
rootPath: params.rootPath,
|
|
41410
42234
|
boundaryLabel: params.boundaryLabel,
|
|
@@ -41427,7 +42251,7 @@ async function assertNoHardlinkedFinalPath(params) {
|
|
|
41427
42251
|
}
|
|
41428
42252
|
let stat;
|
|
41429
42253
|
try {
|
|
41430
|
-
stat =
|
|
42254
|
+
stat = external_node_fs_.statSync(params.filePath);
|
|
41431
42255
|
}
|
|
41432
42256
|
catch (err) {
|
|
41433
42257
|
if (path_isNotFoundPathError(err)) {
|
|
@@ -41446,9 +42270,6 @@ async function assertNoHardlinkedFinalPath(params) {
|
|
|
41446
42270
|
// EXTERNAL MODULE: external "node:url"
|
|
41447
42271
|
var external_node_url_ = __webpack_require__(3136);
|
|
41448
42272
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/string-coerce.js
|
|
41449
|
-
function readStringValue(value) {
|
|
41450
|
-
return typeof value === "string" ? value : undefined;
|
|
41451
|
-
}
|
|
41452
42273
|
function normalizeNullableString(value) {
|
|
41453
42274
|
if (typeof value !== "string") {
|
|
41454
42275
|
return null;
|
|
@@ -41459,65 +42280,12 @@ function normalizeNullableString(value) {
|
|
|
41459
42280
|
function normalizeOptionalString(value) {
|
|
41460
42281
|
return normalizeNullableString(value) ?? undefined;
|
|
41461
42282
|
}
|
|
41462
|
-
function normalizeStringifiedOptionalString(value) {
|
|
41463
|
-
if (typeof value === "string") {
|
|
41464
|
-
return normalizeOptionalString(value);
|
|
41465
|
-
}
|
|
41466
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
41467
|
-
return normalizeOptionalString(String(value));
|
|
41468
|
-
}
|
|
41469
|
-
return undefined;
|
|
41470
|
-
}
|
|
41471
42283
|
function normalizeOptionalLowercaseString(value) {
|
|
41472
42284
|
return normalizeOptionalString(value)?.toLowerCase();
|
|
41473
42285
|
}
|
|
41474
42286
|
function normalizeLowercaseStringOrEmpty(value) {
|
|
41475
42287
|
return normalizeOptionalLowercaseString(value) ?? "";
|
|
41476
42288
|
}
|
|
41477
|
-
function normalizeFastMode(raw) {
|
|
41478
|
-
if (typeof raw === "boolean") {
|
|
41479
|
-
return raw;
|
|
41480
|
-
}
|
|
41481
|
-
if (!raw) {
|
|
41482
|
-
return undefined;
|
|
41483
|
-
}
|
|
41484
|
-
const key = normalizeLowercaseStringOrEmpty(raw);
|
|
41485
|
-
if (["off", "false", "no", "0", "disable", "disabled", "normal"].includes(key)) {
|
|
41486
|
-
return false;
|
|
41487
|
-
}
|
|
41488
|
-
if (["on", "true", "yes", "1", "enable", "enabled", "fast"].includes(key)) {
|
|
41489
|
-
return true;
|
|
41490
|
-
}
|
|
41491
|
-
return undefined;
|
|
41492
|
-
}
|
|
41493
|
-
function lowercasePreservingWhitespace(value) {
|
|
41494
|
-
return value.toLowerCase();
|
|
41495
|
-
}
|
|
41496
|
-
function localeLowercasePreservingWhitespace(value) {
|
|
41497
|
-
return value.toLocaleLowerCase();
|
|
41498
|
-
}
|
|
41499
|
-
function resolvePrimaryStringValue(value) {
|
|
41500
|
-
if (typeof value === "string") {
|
|
41501
|
-
return normalizeOptionalString(value);
|
|
41502
|
-
}
|
|
41503
|
-
if (!value || typeof value !== "object") {
|
|
41504
|
-
return undefined;
|
|
41505
|
-
}
|
|
41506
|
-
return normalizeOptionalString(value.primary);
|
|
41507
|
-
}
|
|
41508
|
-
function normalizeOptionalThreadValue(value) {
|
|
41509
|
-
if (typeof value === "number") {
|
|
41510
|
-
return Number.isFinite(value) ? Math.trunc(value) : undefined;
|
|
41511
|
-
}
|
|
41512
|
-
return normalizeOptionalString(value);
|
|
41513
|
-
}
|
|
41514
|
-
function normalizeOptionalStringifiedId(value) {
|
|
41515
|
-
const normalized = normalizeOptionalThreadValue(value);
|
|
41516
|
-
return normalized == null ? undefined : String(normalized);
|
|
41517
|
-
}
|
|
41518
|
-
function hasNonEmptyString(value) {
|
|
41519
|
-
return normalizeOptionalString(value) !== undefined;
|
|
41520
|
-
}
|
|
41521
42289
|
|
|
41522
42290
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/local-file-access.js
|
|
41523
42291
|
|
|
@@ -41709,8 +42477,11 @@ function normalizeWindowsDeviceBaseName(filePath) {
|
|
|
41709
42477
|
const normalized = trimTrailingWindowsSeparators(filePath.replace(/\//g, "\\"));
|
|
41710
42478
|
const lastSegment = normalized.split("\\").filter(Boolean).at(-1) ?? normalized;
|
|
41711
42479
|
const withoutStream = lastSegment.split(":")[0] ?? lastSegment;
|
|
41712
|
-
const
|
|
41713
|
-
return (
|
|
42480
|
+
const stem = withoutStream.split(".")[0] ?? withoutStream;
|
|
42481
|
+
return trimTrailingWindowsIgnoredChars(stem).toUpperCase();
|
|
42482
|
+
}
|
|
42483
|
+
function isWindowsReservedDeviceName(name) {
|
|
42484
|
+
return name.length > 0 && WINDOWS_RESERVED_DEVICE_NAMES.has(normalizeWindowsDeviceBaseName(name));
|
|
41714
42485
|
}
|
|
41715
42486
|
function matchWindowsDeviceReadPath(filePath) {
|
|
41716
42487
|
const normalized = filePath.replace(/\//g, "\\");
|
|
@@ -41764,6 +42535,42 @@ async function read_opened_file_readOpenedFileSafely(params) {
|
|
|
41764
42535
|
};
|
|
41765
42536
|
}
|
|
41766
42537
|
|
|
42538
|
+
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/write-open-flags.js
|
|
42539
|
+
|
|
42540
|
+
|
|
42541
|
+
function resolveNonblockingWriteFlag(constants = external_node_fs_.constants) {
|
|
42542
|
+
return process.platform !== "win32" && typeof constants.O_NONBLOCK === "number"
|
|
42543
|
+
? constants.O_NONBLOCK
|
|
42544
|
+
: 0;
|
|
42545
|
+
}
|
|
42546
|
+
function isNonblockingWriteEnxio(error, flags) {
|
|
42547
|
+
return hasNodeErrorCode(error, "ENXIO") &&
|
|
42548
|
+
(flags & (external_node_fs_.constants.O_WRONLY | external_node_fs_.constants.O_RDWR)) === external_node_fs_.constants.O_WRONLY &&
|
|
42549
|
+
(flags & resolveNonblockingWriteFlag()) !== 0;
|
|
42550
|
+
}
|
|
42551
|
+
// A no-reader FIFO rejects a nonblocking write-only open before fstat is possible.
|
|
42552
|
+
// Reclassify only a confirmed non-regular path; inconclusive races keep the errno.
|
|
42553
|
+
async function isNonRegularWriteOpenError(error, filePath, flags) {
|
|
42554
|
+
if (!isNonblockingWriteEnxio(error, flags))
|
|
42555
|
+
return false;
|
|
42556
|
+
try {
|
|
42557
|
+
return !external_node_fs_.lstatSync(filePath).isFile();
|
|
42558
|
+
}
|
|
42559
|
+
catch {
|
|
42560
|
+
return false;
|
|
42561
|
+
}
|
|
42562
|
+
}
|
|
42563
|
+
function isNonRegularWriteOpenErrorSync(error, filePath, flags) {
|
|
42564
|
+
if (!isNonblockingWriteEnxio(error, flags))
|
|
42565
|
+
return false;
|
|
42566
|
+
try {
|
|
42567
|
+
return !fsSync.lstatSync(filePath).isFile();
|
|
42568
|
+
}
|
|
42569
|
+
catch {
|
|
42570
|
+
return false;
|
|
42571
|
+
}
|
|
42572
|
+
}
|
|
42573
|
+
|
|
41767
42574
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/home-dir.js
|
|
41768
42575
|
|
|
41769
42576
|
|
|
@@ -41782,10 +42589,6 @@ function resolveEffectiveHomeDir(env = process.env, homedir = external_node_os_.
|
|
|
41782
42589
|
const raw = resolveRawHomeDir(env, homedir);
|
|
41783
42590
|
return raw ? external_node_path_.resolve(raw) : undefined;
|
|
41784
42591
|
}
|
|
41785
|
-
function resolveOsHomeDir(env = process.env, homedir = os.homedir) {
|
|
41786
|
-
const raw = resolveRawOsHomeDir(env, homedir);
|
|
41787
|
-
return raw ? path.resolve(raw) : undefined;
|
|
41788
|
-
}
|
|
41789
42592
|
function resolveRawHomeDir(env, homedir) {
|
|
41790
42593
|
const explicitHome = normalize(env.OPENCLAW_HOME);
|
|
41791
42594
|
if (!explicitHome) {
|
|
@@ -41826,9 +42629,6 @@ function normalizeSafe(homedir) {
|
|
|
41826
42629
|
function resolveRequiredHomeDir(env = process.env, homedir = os.homedir) {
|
|
41827
42630
|
return resolveEffectiveHomeDir(env, homedir) ?? path.resolve(process.cwd());
|
|
41828
42631
|
}
|
|
41829
|
-
function resolveRequiredOsHomeDir(env = process.env, homedir = os.homedir) {
|
|
41830
|
-
return resolveOsHomeDir(env, homedir) ?? path.resolve(process.cwd());
|
|
41831
|
-
}
|
|
41832
42632
|
function expandHomePrefix(input, opts) {
|
|
41833
42633
|
const segments = external_node_path_.normalize(input).split(external_node_path_.sep);
|
|
41834
42634
|
if (segments[0] !== "~") {
|
|
@@ -41856,27 +42656,6 @@ function resolveHomeRelativePath(input, opts) {
|
|
|
41856
42656
|
});
|
|
41857
42657
|
return path.resolve(expanded);
|
|
41858
42658
|
}
|
|
41859
|
-
function resolveUserPath(input, optsOrEnv, homedir) {
|
|
41860
|
-
const opts = optsOrEnv && ("env" in optsOrEnv || "homedir" in optsOrEnv)
|
|
41861
|
-
? optsOrEnv
|
|
41862
|
-
: { env: optsOrEnv, homedir };
|
|
41863
|
-
return resolveHomeRelativePath(input, opts);
|
|
41864
|
-
}
|
|
41865
|
-
function resolveOsHomeRelativePath(input, opts) {
|
|
41866
|
-
if (!input) {
|
|
41867
|
-
return input;
|
|
41868
|
-
}
|
|
41869
|
-
const segments = path.normalize(input).split(path.sep);
|
|
41870
|
-
if (segments[0] !== "~") {
|
|
41871
|
-
return path.resolve(input);
|
|
41872
|
-
}
|
|
41873
|
-
const expanded = expandHomePrefix(input, {
|
|
41874
|
-
home: resolveRequiredOsHomeDir(opts?.env ?? process.env, opts?.homedir ?? os.homedir),
|
|
41875
|
-
env: opts?.env,
|
|
41876
|
-
homedir: opts?.homedir,
|
|
41877
|
-
});
|
|
41878
|
-
return path.resolve(expanded);
|
|
41879
|
-
}
|
|
41880
42659
|
|
|
41881
42660
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/root-context.js
|
|
41882
42661
|
|
|
@@ -41889,6 +42668,7 @@ function resolveOsHomeRelativePath(input, opts) {
|
|
|
41889
42668
|
|
|
41890
42669
|
|
|
41891
42670
|
|
|
42671
|
+
|
|
41892
42672
|
const ensureTrailingSep = (value) => value.endsWith(external_node_path_.sep) ? value : value + external_node_path_.sep;
|
|
41893
42673
|
function assertValidRootRelativePath(relativePath) {
|
|
41894
42674
|
path_assertNoNulPathInput(relativePath, "relative path contains a NUL byte");
|
|
@@ -41905,7 +42685,7 @@ async function expandRelativePathWithHome(relativePath) {
|
|
|
41905
42685
|
if (cachedHomePath?.raw !== rawHome) {
|
|
41906
42686
|
let realHome = rawHome;
|
|
41907
42687
|
try {
|
|
41908
|
-
realHome =
|
|
42688
|
+
realHome = external_node_fs_.realpathSync.native(rawHome);
|
|
41909
42689
|
}
|
|
41910
42690
|
catch {
|
|
41911
42691
|
// If the home dir cannot be canonicalized, keep lexical expansion behavior.
|
|
@@ -41919,8 +42699,8 @@ async function resolveRootContext(rootDir) {
|
|
|
41919
42699
|
let rootReal;
|
|
41920
42700
|
let rootIdentity;
|
|
41921
42701
|
try {
|
|
41922
|
-
rootReal =
|
|
41923
|
-
const rootStat =
|
|
42702
|
+
rootReal = external_node_fs_.realpathSync.native(rootDir);
|
|
42703
|
+
const rootStat = external_node_fs_.statSync(rootReal);
|
|
41924
42704
|
if (!rootStat.isDirectory()) {
|
|
41925
42705
|
throw new errors_FsSafeError("invalid-path", "root dir is not a directory");
|
|
41926
42706
|
}
|
|
@@ -41942,10 +42722,28 @@ async function resolveRootContext(rootDir) {
|
|
|
41942
42722
|
rootWithSep: ensureTrailingSep(rootReal),
|
|
41943
42723
|
};
|
|
41944
42724
|
}
|
|
42725
|
+
function rootRelativeReadPath(root, filePath) {
|
|
42726
|
+
const absoluteInput = external_node_path_.isAbsolute(filePath);
|
|
42727
|
+
const candidatePath = absoluteInput
|
|
42728
|
+
? external_node_path_.resolve(filePath)
|
|
42729
|
+
: external_node_path_.resolve(root.rootDir, filePath);
|
|
42730
|
+
let relativeBase = root.rootDir;
|
|
42731
|
+
if (absoluteInput &&
|
|
42732
|
+
!path_isPathInside(root.rootDir, candidatePath) &&
|
|
42733
|
+
path_isPathInside(root.rootReal, candidatePath)) {
|
|
42734
|
+
// A Root created through an alias has two valid in-root absolute spellings.
|
|
42735
|
+
relativeBase = root.rootReal;
|
|
42736
|
+
}
|
|
42737
|
+
return external_node_path_.relative(relativeBase, candidatePath);
|
|
42738
|
+
}
|
|
41945
42739
|
async function assertRootIdentityCurrent(root) {
|
|
41946
42740
|
let current;
|
|
41947
42741
|
try {
|
|
41948
|
-
|
|
42742
|
+
if (typeof root.rootIdentity.dev === "bigint" && typeof root.rootIdentity.ino === "bigint") {
|
|
42743
|
+
await inspectDirectoryIdentity(root.rootReal, { dev: root.rootIdentity.dev, ino: root.rootIdentity.ino });
|
|
42744
|
+
return;
|
|
42745
|
+
}
|
|
42746
|
+
current = external_node_fs_.lstatSync(root.rootReal);
|
|
41949
42747
|
}
|
|
41950
42748
|
catch (error) {
|
|
41951
42749
|
throw new errors_FsSafeError("path-mismatch", "root path changed during operation", {
|
|
@@ -41973,7 +42771,7 @@ async function resolvePathInRoot(root, relativePath, options) {
|
|
|
41973
42771
|
? expanded
|
|
41974
42772
|
: `${root.rootWithSep}${expanded}`;
|
|
41975
42773
|
try {
|
|
41976
|
-
await
|
|
42774
|
+
await root_path_resolveRootPath({
|
|
41977
42775
|
absolutePath: rawAbsolutePath,
|
|
41978
42776
|
rootPath: root.rootReal,
|
|
41979
42777
|
rootCanonicalPath: root.rootReal,
|
|
@@ -42051,17 +42849,19 @@ async function* walkRoot(root, relativePath, options) {
|
|
|
42051
42849
|
const maxEntries = validateBudget("maxEntries", options.maxEntries);
|
|
42052
42850
|
const visitedDirectories = new Set();
|
|
42053
42851
|
let examined = 0;
|
|
42852
|
+
let truncated = false;
|
|
42054
42853
|
const onLimit = (atPath) => {
|
|
42055
42854
|
if ((options.limitBehavior ?? "truncate") === "throw") {
|
|
42056
42855
|
throw new errors_FsSafeError("too-large", `root walk budget exceeded at ${atPath || "."}`);
|
|
42057
42856
|
}
|
|
42857
|
+
truncated = true;
|
|
42058
42858
|
return limitEntry(atPath);
|
|
42059
42859
|
};
|
|
42060
42860
|
async function* visit(directory, depth) {
|
|
42061
42861
|
options.signal?.throwIfAborted();
|
|
42062
42862
|
let entries;
|
|
42063
42863
|
try {
|
|
42064
|
-
const resolvedDirectory = await
|
|
42864
|
+
const resolvedDirectory = await root_path_resolveRootPath({
|
|
42065
42865
|
absolutePath: external_node_path_.resolve(root.rootReal, directory),
|
|
42066
42866
|
rootPath: root.rootReal,
|
|
42067
42867
|
rootCanonicalPath: root.rootReal,
|
|
@@ -42105,7 +42905,7 @@ async function* walkRoot(root, relativePath, options) {
|
|
|
42105
42905
|
if (options.symlinkPolicy === "skip") {
|
|
42106
42906
|
continue;
|
|
42107
42907
|
}
|
|
42108
|
-
const resolved = await
|
|
42908
|
+
const resolved = await root_path_resolveRootPath({
|
|
42109
42909
|
absolutePath: external_node_path_.resolve(root.rootReal, child),
|
|
42110
42910
|
rootPath: root.rootReal,
|
|
42111
42911
|
rootCanonicalPath: root.rootReal,
|
|
@@ -42136,6 +42936,8 @@ async function* walkRoot(root, relativePath, options) {
|
|
|
42136
42936
|
return;
|
|
42137
42937
|
}
|
|
42138
42938
|
yield* visit(child, depth + 1);
|
|
42939
|
+
if (truncated)
|
|
42940
|
+
return;
|
|
42139
42941
|
}
|
|
42140
42942
|
}
|
|
42141
42943
|
yield* visit(relativePath, 0);
|
|
@@ -42153,7 +42955,7 @@ function pathStillMatchesReceipt(entry) {
|
|
|
42153
42955
|
try {
|
|
42154
42956
|
const current = external_node_fs_.lstatSync(entry.path, { bigint: true });
|
|
42155
42957
|
return (!entry.singleLinkFile || (current.isFile() && current.nlink === 1n)) &&
|
|
42156
|
-
|
|
42958
|
+
file_identity_sameFileIdentityForCleanup(current, entry.identity);
|
|
42157
42959
|
}
|
|
42158
42960
|
catch (error) {
|
|
42159
42961
|
return !entry.singleLinkFile && error.code === "ENOENT";
|
|
@@ -42184,7 +42986,7 @@ function cleanupRegisteredTempPathsSync() {
|
|
|
42184
42986
|
}
|
|
42185
42987
|
tempCleanupEntries.clear();
|
|
42186
42988
|
}
|
|
42187
|
-
function
|
|
42989
|
+
function temp_cleanup_registerTempPathForExit(tempPath, options) {
|
|
42188
42990
|
if (!cleanupRegistered) {
|
|
42189
42991
|
cleanupRegistered = true;
|
|
42190
42992
|
process.once("exit", cleanupRegisteredTempPathsSync);
|
|
@@ -42288,21 +43090,27 @@ async function verifyAtomicWriteResult(params) {
|
|
|
42288
43090
|
throw new errors_FsSafeError("path-mismatch", "descriptor changed during write");
|
|
42289
43091
|
}
|
|
42290
43092
|
assertFile(stat);
|
|
43093
|
+
if (process.platform !== "win32" && params.expectedMode !== undefined) {
|
|
43094
|
+
const actualMode = Number(stat.mode & 4095n);
|
|
43095
|
+
if (actualMode !== params.expectedMode) {
|
|
43096
|
+
throw new Error(`Private secret file ${params.targetPath} has insecure permissions ${actualMode.toString(8)}.`);
|
|
43097
|
+
}
|
|
43098
|
+
}
|
|
42291
43099
|
return stat;
|
|
42292
43100
|
};
|
|
42293
43101
|
try {
|
|
42294
43102
|
// This descriptor remains owned by the writer, even when final mode forbids opens.
|
|
42295
43103
|
const stat = assertDescriptor();
|
|
42296
|
-
assertPath(
|
|
42297
|
-
const realPath = await resolveOpenedFileRealPathForFd(params.fd, stat, params.targetPath);
|
|
42298
|
-
assertPath(
|
|
43104
|
+
assertPath(external_node_fs_.lstatSync(params.targetPath, { bigint: true }));
|
|
43105
|
+
const { realPath } = await resolveOpenedFileRealPathForFd(params.fd, stat, params.targetPath);
|
|
43106
|
+
assertPath(external_node_fs_.statSync(realPath, { bigint: true }));
|
|
42299
43107
|
if (!path_isPathInside(params.root.rootWithSep, realPath)) {
|
|
42300
43108
|
throw outsideWorkspaceError();
|
|
42301
43109
|
}
|
|
42302
|
-
await
|
|
43110
|
+
await directory_guard_assertAsyncDirectoryGuard(params.parentGuard);
|
|
42303
43111
|
await assertRootIdentityCurrent(params.root);
|
|
42304
43112
|
// Recheck after canonical resolution and directory checks, including late links.
|
|
42305
|
-
assertPath(
|
|
43113
|
+
assertPath(external_node_fs_.lstatSync(params.targetPath, { bigint: true }));
|
|
42306
43114
|
assertDescriptor();
|
|
42307
43115
|
if (needsPathOpen) {
|
|
42308
43116
|
// A retained fd cannot prove that an opaque Windows pathname still names it.
|
|
@@ -42320,15 +43128,15 @@ async function verifyAtomicWriteResult(params) {
|
|
|
42320
43128
|
});
|
|
42321
43129
|
try {
|
|
42322
43130
|
const reopenedStat = assertDescriptor(opened.fd);
|
|
42323
|
-
assertPath(
|
|
42324
|
-
const reopenedPath = await resolveOpenedFileRealPathForFd(opened.fd, reopenedStat, params.targetPath);
|
|
42325
|
-
assertPath(
|
|
43131
|
+
assertPath(external_node_fs_.lstatSync(params.targetPath, { bigint: true }));
|
|
43132
|
+
const { realPath: reopenedPath } = await resolveOpenedFileRealPathForFd(opened.fd, reopenedStat, params.targetPath);
|
|
43133
|
+
assertPath(external_node_fs_.statSync(reopenedPath, { bigint: true }));
|
|
42326
43134
|
if (!path_isPathInside(params.root.rootWithSep, reopenedPath)) {
|
|
42327
43135
|
throw outsideWorkspaceError();
|
|
42328
43136
|
}
|
|
42329
|
-
await
|
|
43137
|
+
await directory_guard_assertAsyncDirectoryGuard(params.parentGuard);
|
|
42330
43138
|
await assertRootIdentityCurrent(params.root);
|
|
42331
|
-
assertPath(
|
|
43139
|
+
assertPath(external_node_fs_.lstatSync(params.targetPath, { bigint: true }));
|
|
42332
43140
|
assertDescriptor(opened.fd);
|
|
42333
43141
|
}
|
|
42334
43142
|
finally {
|
|
@@ -42343,6 +43151,74 @@ async function verifyAtomicWriteResult(params) {
|
|
|
42343
43151
|
}
|
|
42344
43152
|
}
|
|
42345
43153
|
|
|
43154
|
+
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/root-write-mode.js
|
|
43155
|
+
|
|
43156
|
+
|
|
43157
|
+
|
|
43158
|
+
|
|
43159
|
+
|
|
43160
|
+
|
|
43161
|
+
|
|
43162
|
+
|
|
43163
|
+
// The caller has already resolved and guarded this write target.
|
|
43164
|
+
async function inheritWriteTargetMode(params) {
|
|
43165
|
+
try {
|
|
43166
|
+
const existing = await strict_file_identity_inspectFileIdentity(() => external_node_fs_.lstatSync(params.targetPath, { bigint: true }));
|
|
43167
|
+
if (existing.isSymbolicLink())
|
|
43168
|
+
throw new errors_FsSafeError("path-alias", "path alias escape blocked");
|
|
43169
|
+
if (!existing.isFile())
|
|
43170
|
+
throw new errors_FsSafeError("not-file", "not a file");
|
|
43171
|
+
if (existing.nlink > 1n)
|
|
43172
|
+
throw hardlinkedPathNotAllowedError();
|
|
43173
|
+
if (!path_isPathInside(params.rootWithSep, params.targetPath))
|
|
43174
|
+
throw outsideWorkspaceError();
|
|
43175
|
+
// Preserve read-open admission of the pre-existing destination. access(2)
|
|
43176
|
+
// is not equivalent: it ignores ACLs on Windows and capabilities on Linux.
|
|
43177
|
+
const handle = await promises_.open(params.targetPath, read_open_flags_resolveReadOpenFlags());
|
|
43178
|
+
try {
|
|
43179
|
+
// Bind admission to the inode whose metadata is inherited.
|
|
43180
|
+
if (!file_identity_sameFileIdentity(external_node_fs_.fstatSync(handle.fd, { bigint: true }), existing)) {
|
|
43181
|
+
throw new errors_FsSafeError("path-mismatch", "write target changed during mode inheritance");
|
|
43182
|
+
}
|
|
43183
|
+
}
|
|
43184
|
+
finally {
|
|
43185
|
+
await handle.close().catch(() => undefined);
|
|
43186
|
+
}
|
|
43187
|
+
try {
|
|
43188
|
+
// A parent can change after guarded resolution. Do not inherit metadata
|
|
43189
|
+
// from an outside inode, even if the parent is restored before publication.
|
|
43190
|
+
const realPath = external_node_fs_.realpathSync.native(params.targetPath);
|
|
43191
|
+
if (!path_isPathInside(params.rootWithSep, realPath))
|
|
43192
|
+
throw outsideWorkspaceError();
|
|
43193
|
+
await strict_file_identity_inspectFileIdentity(async () => {
|
|
43194
|
+
const current = external_node_fs_.statSync(realPath, { bigint: true });
|
|
43195
|
+
if (!current.isFile())
|
|
43196
|
+
throw new errors_FsSafeError("not-file", "not a file");
|
|
43197
|
+
if (current.nlink > 1n)
|
|
43198
|
+
throw hardlinkedPathNotAllowedError();
|
|
43199
|
+
return current;
|
|
43200
|
+
}, existing);
|
|
43201
|
+
}
|
|
43202
|
+
catch (error) {
|
|
43203
|
+
if (path_isNotFoundPathError(error)) {
|
|
43204
|
+
throw new errors_FsSafeError("path-mismatch", "write target changed during mode inheritance", { cause: error });
|
|
43205
|
+
}
|
|
43206
|
+
throw error;
|
|
43207
|
+
}
|
|
43208
|
+
return params.requestedMode ?? Number(existing.mode & 511n);
|
|
43209
|
+
}
|
|
43210
|
+
catch (error) {
|
|
43211
|
+
if (!path_isNotFoundPathError(error))
|
|
43212
|
+
throw error;
|
|
43213
|
+
return params.requestedMode ?? 0o600;
|
|
43214
|
+
}
|
|
43215
|
+
}
|
|
43216
|
+
|
|
43217
|
+
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/copy-publication.js
|
|
43218
|
+
// Internal composition hook; the descriptor is borrowed until the callback returns.
|
|
43219
|
+
// Kept off RootCopyOptions and all public package exports.
|
|
43220
|
+
const onCopyPublication = Symbol("onCopyPublication");
|
|
43221
|
+
|
|
42346
43222
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/root-impl.js
|
|
42347
43223
|
|
|
42348
43224
|
|
|
@@ -42372,6 +43248,9 @@ async function verifyAtomicWriteResult(params) {
|
|
|
42372
43248
|
|
|
42373
43249
|
|
|
42374
43250
|
|
|
43251
|
+
|
|
43252
|
+
|
|
43253
|
+
|
|
42375
43254
|
|
|
42376
43255
|
|
|
42377
43256
|
|
|
@@ -42384,12 +43263,14 @@ function logWarn(message) {
|
|
|
42384
43263
|
const SUPPORTS_NOFOLLOW = process.platform !== "win32" && "O_NOFOLLOW" in external_node_fs_.constants;
|
|
42385
43264
|
const OPEN_READ_FLAGS = read_open_flags_resolveReadOpenFlags();
|
|
42386
43265
|
const OPEN_READ_FOLLOW_FLAGS = read_open_flags_resolveReadOpenFlags({ followSymlinks: true });
|
|
42387
|
-
const OPEN_WRITE_EXISTING_FLAGS = external_node_fs_.constants.O_WRONLY | (SUPPORTS_NOFOLLOW ? external_node_fs_.constants.O_NOFOLLOW : 0)
|
|
43266
|
+
const OPEN_WRITE_EXISTING_FLAGS = external_node_fs_.constants.O_WRONLY | (SUPPORTS_NOFOLLOW ? external_node_fs_.constants.O_NOFOLLOW : 0) |
|
|
43267
|
+
resolveNonblockingWriteFlag();
|
|
42388
43268
|
const OPEN_WRITE_CREATE_FLAGS = external_node_fs_.constants.O_WRONLY |
|
|
42389
43269
|
external_node_fs_.constants.O_CREAT |
|
|
42390
43270
|
external_node_fs_.constants.O_EXCL |
|
|
42391
43271
|
(SUPPORTS_NOFOLLOW ? external_node_fs_.constants.O_NOFOLLOW : 0);
|
|
42392
|
-
const OPEN_APPEND_EXISTING_FLAGS = external_node_fs_.constants.O_RDWR | external_node_fs_.constants.O_APPEND | (SUPPORTS_NOFOLLOW ? external_node_fs_.constants.O_NOFOLLOW : 0)
|
|
43272
|
+
const OPEN_APPEND_EXISTING_FLAGS = external_node_fs_.constants.O_RDWR | external_node_fs_.constants.O_APPEND | (SUPPORTS_NOFOLLOW ? external_node_fs_.constants.O_NOFOLLOW : 0) |
|
|
43273
|
+
resolveNonblockingWriteFlag();
|
|
42393
43274
|
const OPEN_APPEND_CREATE_FLAGS = external_node_fs_.constants.O_RDWR |
|
|
42394
43275
|
external_node_fs_.constants.O_APPEND |
|
|
42395
43276
|
external_node_fs_.constants.O_CREAT |
|
|
@@ -42428,8 +43309,8 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
42428
43309
|
// Reject directories before opening so we never surface EISDIR to callers (e.g. tool
|
|
42429
43310
|
// results that get sent to messaging channels). See openclaw/openclaw#31186.
|
|
42430
43311
|
try {
|
|
42431
|
-
preOpenStat = await
|
|
42432
|
-
const stat =
|
|
43312
|
+
preOpenStat = await strict_file_identity_inspectFileIdentity(async () => {
|
|
43313
|
+
const stat = external_node_fs_.lstatSync(filePath, { bigint: true });
|
|
42433
43314
|
observedBeforeOpen = true;
|
|
42434
43315
|
if (stat.isSymbolicLink() && options?.symlinks !== "follow-within-root") {
|
|
42435
43316
|
throw new errors_FsSafeError("symlink", "symlink not allowed");
|
|
@@ -42469,13 +43350,13 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
42469
43350
|
}
|
|
42470
43351
|
try {
|
|
42471
43352
|
await fsSafeTestHooks?.afterOpen?.(filePath, handle);
|
|
42472
|
-
const stat =
|
|
43353
|
+
const stat = external_node_fs_.fstatSync(handle.fd);
|
|
42473
43354
|
if (!stat.isFile()) {
|
|
42474
43355
|
throw new errors_FsSafeError("not-file", "not a file");
|
|
42475
43356
|
}
|
|
42476
43357
|
// Keep numeric Stats for the public receipt, never for identity verification.
|
|
42477
43358
|
let openedIdentity;
|
|
42478
|
-
const identity = await
|
|
43359
|
+
const identity = await strict_file_identity_inspectFileIdentity(async () => (openedIdentity = external_node_fs_.fstatSync(handle.fd, { bigint: true })), preOpenStat && !preOpenStat.isSymbolicLink() ? preOpenStat : undefined).catch(async (error) => {
|
|
42479
43360
|
if ([0, 1].includes(stat.nlink)) {
|
|
42480
43361
|
await recordPreOpenFileChange(error, handle, filePath, preOpenStat, openedIdentity);
|
|
42481
43362
|
}
|
|
@@ -42486,7 +43367,7 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
42486
43367
|
}
|
|
42487
43368
|
const inspectPathIdentity = async (inspect) => {
|
|
42488
43369
|
try {
|
|
42489
|
-
return await
|
|
43370
|
+
return await strict_file_identity_inspectFileIdentity(inspect, identity);
|
|
42490
43371
|
}
|
|
42491
43372
|
catch (error) {
|
|
42492
43373
|
const failure = path_isNotFoundPathError(error) ? openedPathResolutionError(fileNotFoundError()) : error;
|
|
@@ -42498,23 +43379,28 @@ async function openVerifiedLocalFile(filePath, options) {
|
|
|
42498
43379
|
};
|
|
42499
43380
|
await inspectPathIdentity(async () => {
|
|
42500
43381
|
const pathStat = options?.symlinks === "follow-within-root"
|
|
42501
|
-
?
|
|
42502
|
-
:
|
|
43382
|
+
? external_node_fs_.statSync(filePath, { bigint: true })
|
|
43383
|
+
: external_node_fs_.lstatSync(filePath, { bigint: true });
|
|
42503
43384
|
if (pathStat.isSymbolicLink() && options?.symlinks !== "follow-within-root") {
|
|
42504
43385
|
throw new errors_FsSafeError("symlink", "symlink not allowed");
|
|
42505
43386
|
}
|
|
42506
43387
|
return pathStat;
|
|
42507
43388
|
});
|
|
42508
43389
|
await fsSafeTestHooks?.afterOpenedPathIdentityCheck?.(filePath, handle);
|
|
42509
|
-
const
|
|
43390
|
+
const resolved = await resolveOpenedFileRealPathForFd(handle.fd, identity, filePath)
|
|
42510
43391
|
.catch(async (error) => {
|
|
42511
43392
|
if (stat.nlink <= 1 && (!preOpenStat || preOpenStat.nlink <= 1n)) {
|
|
42512
43393
|
await recordOpenedFileFailure(error, handle, filePath, identity);
|
|
42513
43394
|
}
|
|
42514
43395
|
throw error;
|
|
42515
43396
|
});
|
|
43397
|
+
const { realPath } = resolved;
|
|
43398
|
+
let resolvedStat = resolved.stat;
|
|
42516
43399
|
await inspectPathIdentity(async () => {
|
|
42517
|
-
|
|
43400
|
+
// Reuse the post-realpath observation; unknown Windows identities still
|
|
43401
|
+
// get a fresh observation on inspectFileIdentity's retry.
|
|
43402
|
+
const realStat = resolvedStat ?? external_node_fs_.statSync(realPath, { bigint: true });
|
|
43403
|
+
resolvedStat = undefined;
|
|
42518
43404
|
if (options?.hardlinks === "reject" && realStat.nlink > 1n) {
|
|
42519
43405
|
throw hardlinkedPathNotAllowedError();
|
|
42520
43406
|
}
|
|
@@ -42612,6 +43498,7 @@ class RootHandle {
|
|
|
42612
43498
|
mkdir: this.defaults.mkdir,
|
|
42613
43499
|
mode: this.defaults.mode,
|
|
42614
43500
|
...this.mutationOptions(options),
|
|
43501
|
+
durable: options.durable ?? this.defaults.durable ?? true,
|
|
42615
43502
|
});
|
|
42616
43503
|
}
|
|
42617
43504
|
async remove(relativePath, options = {}) {
|
|
@@ -42644,6 +43531,7 @@ class RootHandle {
|
|
|
42644
43531
|
mode: this.defaults.mode,
|
|
42645
43532
|
renameIdentity: this.defaults.renameIdentity,
|
|
42646
43533
|
...this.mutationOptions(options),
|
|
43534
|
+
durable: options.durable ?? this.defaults.durable ?? true,
|
|
42647
43535
|
});
|
|
42648
43536
|
}
|
|
42649
43537
|
async create(relativePath, data, options = {}) {
|
|
@@ -42654,6 +43542,7 @@ class RootHandle {
|
|
|
42654
43542
|
mkdir: this.defaults.mkdir,
|
|
42655
43543
|
mode: this.defaults.mode,
|
|
42656
43544
|
...this.mutationOptions(options),
|
|
43545
|
+
durable: options.durable ?? this.defaults.durable ?? true,
|
|
42657
43546
|
overwrite: false,
|
|
42658
43547
|
});
|
|
42659
43548
|
}
|
|
@@ -42677,6 +43566,8 @@ class RootHandle {
|
|
|
42677
43566
|
mkdir: this.defaults.mkdir,
|
|
42678
43567
|
mode: this.defaults.mode,
|
|
42679
43568
|
...copyOptions,
|
|
43569
|
+
durable: options.durable ?? this.defaults.durable ?? true,
|
|
43570
|
+
verifyPublished: options[onCopyPublication],
|
|
42680
43571
|
});
|
|
42681
43572
|
}
|
|
42682
43573
|
async exists(relativePath) {
|
|
@@ -42727,7 +43618,6 @@ function readDefaults(defaults) {
|
|
|
42727
43618
|
return {
|
|
42728
43619
|
hardlinks: defaults.hardlinks,
|
|
42729
43620
|
maxBytes: byte_budget_normalizeMaxBytes(defaults.maxBytes, { defaultValue: DEFAULT_ROOT_MAX_BYTES }),
|
|
42730
|
-
nonBlockingRead: defaults.nonBlockingRead,
|
|
42731
43621
|
symlinks: defaults.symlinks,
|
|
42732
43622
|
};
|
|
42733
43623
|
}
|
|
@@ -42736,8 +43626,6 @@ function mergeReadOptions(defaults, options) {
|
|
|
42736
43626
|
if (options.hardlinks !== undefined)
|
|
42737
43627
|
merged.hardlinks = options.hardlinks;
|
|
42738
43628
|
merged.maxBytes = byte_budget_normalizeMaxBytes(options.maxBytes, { defaultValue: merged.maxBytes });
|
|
42739
|
-
if (options.nonBlockingRead !== undefined)
|
|
42740
|
-
merged.nonBlockingRead = options.nonBlockingRead;
|
|
42741
43629
|
if (options.symlinks !== undefined)
|
|
42742
43630
|
merged.symlinks = options.symlinks;
|
|
42743
43631
|
return merged;
|
|
@@ -42753,7 +43641,6 @@ async function openFileInRoot(root, params) {
|
|
|
42753
43641
|
rejectSymlinks: params.symlinks !== "follow-within-root",
|
|
42754
43642
|
});
|
|
42755
43643
|
const { opened } = await openVerifiedLocalFile(resolved, {
|
|
42756
|
-
nonBlockingRead: params.nonBlockingRead,
|
|
42757
43644
|
symlinks: params.symlinks,
|
|
42758
43645
|
});
|
|
42759
43646
|
if (params.hardlinks !== "allow" && opened.stat.nlink > 1) {
|
|
@@ -42776,16 +43663,11 @@ async function readFileInRoot(root, params) {
|
|
|
42776
43663
|
}
|
|
42777
43664
|
}
|
|
42778
43665
|
async function readPathInRoot(root, params) {
|
|
42779
|
-
const
|
|
42780
|
-
const candidatePath = external_node_path_.isAbsolute(params.filePath)
|
|
42781
|
-
? external_node_path_.resolve(params.filePath)
|
|
42782
|
-
: external_node_path_.resolve(rootDir, params.filePath);
|
|
42783
|
-
const relativePath = external_node_path_.relative(rootDir, candidatePath);
|
|
43666
|
+
const relativePath = rootRelativeReadPath(root, params.filePath);
|
|
42784
43667
|
return await readFileInRoot(root, {
|
|
42785
43668
|
relativePath,
|
|
42786
43669
|
hardlinks: params.hardlinks,
|
|
42787
43670
|
maxBytes: params.maxBytes,
|
|
42788
|
-
nonBlockingRead: params.nonBlockingRead,
|
|
42789
43671
|
symlinks: params.symlinks,
|
|
42790
43672
|
});
|
|
42791
43673
|
}
|
|
@@ -42832,7 +43714,7 @@ async function writeTempFileForAtomicReplace(params) {
|
|
|
42832
43714
|
}
|
|
42833
43715
|
return {
|
|
42834
43716
|
handle: tempHandle,
|
|
42835
|
-
identity:
|
|
43717
|
+
identity: external_node_fs_.fstatSync(tempHandle.fd, { bigint: true }),
|
|
42836
43718
|
};
|
|
42837
43719
|
}
|
|
42838
43720
|
catch (error) {
|
|
@@ -42871,7 +43753,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
42871
43753
|
? resolved
|
|
42872
43754
|
: await prepareRootWriteTarget(rootReal, resolved);
|
|
42873
43755
|
try {
|
|
42874
|
-
const resolvedRealPath =
|
|
43756
|
+
const resolvedRealPath = external_node_fs_.realpathSync.native(ioPath);
|
|
42875
43757
|
if (!path_isPathInside(rootWithSep, resolvedRealPath)) {
|
|
42876
43758
|
throw outsideWorkspaceError();
|
|
42877
43759
|
}
|
|
@@ -42895,6 +43777,9 @@ async function openWritableFileInRoot(root, params) {
|
|
|
42895
43777
|
handle = await promises_.open(ioPath, existingFlags, mode);
|
|
42896
43778
|
}
|
|
42897
43779
|
catch (err) {
|
|
43780
|
+
if (await isNonRegularWriteOpenError(err, ioPath, existingFlags)) {
|
|
43781
|
+
throw new errors_FsSafeError("not-file", "path is not a regular file under root");
|
|
43782
|
+
}
|
|
42898
43783
|
if (!path_isNotFoundPathError(err)) {
|
|
42899
43784
|
throw err;
|
|
42900
43785
|
}
|
|
@@ -42917,7 +43802,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
42917
43802
|
let realPathForCleanup = null;
|
|
42918
43803
|
let createdIdentity = null;
|
|
42919
43804
|
try {
|
|
42920
|
-
const stat =
|
|
43805
|
+
const stat = external_node_fs_.fstatSync(handle.fd);
|
|
42921
43806
|
if (createdForWrite) {
|
|
42922
43807
|
createdIdentity = stat;
|
|
42923
43808
|
}
|
|
@@ -42928,7 +43813,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
42928
43813
|
throw hardlinkedPathNotAllowedError();
|
|
42929
43814
|
}
|
|
42930
43815
|
try {
|
|
42931
|
-
const lstat =
|
|
43816
|
+
const lstat = external_node_fs_.lstatSync(ioPath);
|
|
42932
43817
|
if (lstat.isSymbolicLink() || !lstat.isFile()) {
|
|
42933
43818
|
throw new errors_FsSafeError(lstat.isSymbolicLink() ? "symlink" : "not-file", "path is not a regular file under root");
|
|
42934
43819
|
}
|
|
@@ -42943,7 +43828,7 @@ async function openWritableFileInRoot(root, params) {
|
|
|
42943
43828
|
}
|
|
42944
43829
|
const realPath = await resolveOpenedFileRealPathForHandle(handle, ioPath);
|
|
42945
43830
|
realPathForCleanup = realPath;
|
|
42946
|
-
const realStat =
|
|
43831
|
+
const realStat = external_node_fs_.statSync(realPath);
|
|
42947
43832
|
if (!file_identity_sameFileIdentity(stat, realStat)) {
|
|
42948
43833
|
throw new errors_FsSafeError("path-mismatch", "path mismatch");
|
|
42949
43834
|
}
|
|
@@ -43006,8 +43891,9 @@ async function appendFileInRoot(root, params) {
|
|
|
43006
43891
|
const payload = prefix.length > 0 ? Buffer.concat([Buffer.from(prefix, "utf8"), params.data]) : params.data;
|
|
43007
43892
|
await target.handle.appendFile(payload);
|
|
43008
43893
|
}
|
|
43009
|
-
|
|
43010
|
-
|
|
43894
|
+
if (params.durable !== false)
|
|
43895
|
+
await target.handle.sync();
|
|
43896
|
+
if (params.durable !== false && target.createdForWrite) {
|
|
43011
43897
|
await syncDirectoryBestEffort(external_node_path_.dirname(target.realPath));
|
|
43012
43898
|
}
|
|
43013
43899
|
}
|
|
@@ -43063,6 +43949,7 @@ async function commitPinnedWriteInRoot(root, pinned, params) {
|
|
|
43063
43949
|
renameIdentity: params.renameIdentity,
|
|
43064
43950
|
mkdir: params.mkdir !== false,
|
|
43065
43951
|
mode: params.mode ?? pinned.mode,
|
|
43952
|
+
sync: params.durable !== false,
|
|
43066
43953
|
overwrite: params.overwrite,
|
|
43067
43954
|
input: { kind: "buffer", data: params.data, encoding: params.encoding },
|
|
43068
43955
|
rootIdentity: root.rootIdentity,
|
|
@@ -43124,6 +44011,8 @@ async function copyFileInRoot(root, params) {
|
|
|
43124
44011
|
mode: pinned.mode,
|
|
43125
44012
|
overwrite: true,
|
|
43126
44013
|
maxBytes: params.maxBytes,
|
|
44014
|
+
sync: params.durable !== false,
|
|
44015
|
+
verifyPublished: params.verifyPublished,
|
|
43127
44016
|
input: { kind: "stream", stream: source.handle.createReadStream() },
|
|
43128
44017
|
rootIdentity: root.rootIdentity,
|
|
43129
44018
|
});
|
|
@@ -43146,12 +44035,12 @@ async function copyFileInRoot(root, params) {
|
|
|
43146
44035
|
}
|
|
43147
44036
|
}
|
|
43148
44037
|
async function assertCopySourceCurrent(source, identity) {
|
|
43149
|
-
await
|
|
44038
|
+
await strict_file_identity_inspectFileIdentity(() => external_node_fs_.fstatSync(source.handle.fd, { bigint: true }), identity);
|
|
43150
44039
|
await assertCopySourcePathCurrent(source, identity);
|
|
43151
44040
|
}
|
|
43152
44041
|
async function assertCopySourcePathCurrent(source, identity) {
|
|
43153
|
-
await
|
|
43154
|
-
const current =
|
|
44042
|
+
await strict_file_identity_inspectFileIdentity(async () => {
|
|
44043
|
+
const current = external_node_fs_.lstatSync(source.realPath, { bigint: true });
|
|
43155
44044
|
if (current.isSymbolicLink() || !current.isFile()) {
|
|
43156
44045
|
throw new errors_FsSafeError("path-mismatch", "copy source path changed");
|
|
43157
44046
|
}
|
|
@@ -43160,8 +44049,8 @@ async function assertCopySourcePathCurrent(source, identity) {
|
|
|
43160
44049
|
}
|
|
43161
44050
|
async function removePathIfIdentityUnchanged(targetPath, identity) {
|
|
43162
44051
|
const parentGuard = await directory_guard_createAsyncDirectoryGuard(external_node_path_.dirname(targetPath));
|
|
43163
|
-
const current =
|
|
43164
|
-
if (current.isSymbolicLink() || !
|
|
44052
|
+
const current = external_node_fs_.lstatSync(targetPath);
|
|
44053
|
+
if (current.isSymbolicLink() || !file_identity_sameFileIdentityForCleanup(current, identity)) {
|
|
43165
44054
|
return;
|
|
43166
44055
|
}
|
|
43167
44056
|
await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
@@ -43190,7 +44079,7 @@ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode,
|
|
|
43190
44079
|
// and alias checks, but never open a competing owner's record just to reject it.
|
|
43191
44080
|
if (!overwrite) {
|
|
43192
44081
|
try {
|
|
43193
|
-
const existing =
|
|
44082
|
+
const existing = external_node_fs_.statSync(resolved);
|
|
43194
44083
|
if (!existing.isFile())
|
|
43195
44084
|
throw new errors_FsSafeError("not-file", "not a file");
|
|
43196
44085
|
if (existing.nlink > 1)
|
|
@@ -43202,31 +44091,9 @@ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode,
|
|
|
43202
44091
|
throw error;
|
|
43203
44092
|
}
|
|
43204
44093
|
}
|
|
43205
|
-
|
|
43206
|
-
|
|
43207
|
-
|
|
43208
|
-
const opened = await openFileInRoot(root, {
|
|
43209
|
-
relativePath,
|
|
43210
|
-
hardlinks: "reject",
|
|
43211
|
-
nonBlockingRead: true,
|
|
43212
|
-
symlinks: "follow-within-root",
|
|
43213
|
-
});
|
|
43214
|
-
try {
|
|
43215
|
-
mode = requestedMode ?? (opened.stat.mode & 0o777);
|
|
43216
|
-
if (!path_isPathInside(rootWithSep, opened.realPath)) {
|
|
43217
|
-
throw outsideWorkspaceError();
|
|
43218
|
-
}
|
|
43219
|
-
}
|
|
43220
|
-
finally {
|
|
43221
|
-
await opened.handle.close().catch(() => { });
|
|
43222
|
-
}
|
|
43223
|
-
}
|
|
43224
|
-
}
|
|
43225
|
-
catch (err) {
|
|
43226
|
-
if (!(err instanceof errors_FsSafeError) || err.code !== "not-found") {
|
|
43227
|
-
throw err;
|
|
43228
|
-
}
|
|
43229
|
-
}
|
|
44094
|
+
const mode = overwrite
|
|
44095
|
+
? await inheritWriteTargetMode({ targetPath: resolved, rootWithSep, requestedMode })
|
|
44096
|
+
: requestedMode ?? 0o600;
|
|
43230
44097
|
return {
|
|
43231
44098
|
rootReal,
|
|
43232
44099
|
targetPath: resolved,
|
|
@@ -43276,7 +44143,7 @@ async function resolvePinnedRootPathInRoot(root, params) {
|
|
|
43276
44143
|
let resolved;
|
|
43277
44144
|
try {
|
|
43278
44145
|
const expandedPath = await expandRelativePathWithHome(params.relativePath);
|
|
43279
|
-
resolved = await
|
|
44146
|
+
resolved = await root_path_resolveRootPath({
|
|
43280
44147
|
absolutePath: external_node_path_.isAbsolute(expandedPath)
|
|
43281
44148
|
? expandedPath
|
|
43282
44149
|
: `${ensureTrailingSep(rootReal)}${expandedPath}`,
|
|
@@ -43300,7 +44167,7 @@ async function prepareRemoveGuard(targetPath) {
|
|
|
43300
44167
|
try {
|
|
43301
44168
|
const guard = await directory_guard_createAsyncDirectoryGuard(external_node_path_.dirname(targetPath));
|
|
43302
44169
|
await getFsSafeTestHooks()?.beforeRootFallbackMutation?.("remove", targetPath);
|
|
43303
|
-
await
|
|
44170
|
+
await directory_guard_assertAsyncDirectoryGuard(guard);
|
|
43304
44171
|
return guard;
|
|
43305
44172
|
}
|
|
43306
44173
|
catch (error) {
|
|
@@ -43310,12 +44177,12 @@ async function prepareRemoveGuard(targetPath) {
|
|
|
43310
44177
|
async function removePathFallback(resolved) {
|
|
43311
44178
|
const guard = await prepareRemoveGuard(resolved.resolved);
|
|
43312
44179
|
try {
|
|
43313
|
-
await (
|
|
44180
|
+
await (external_node_fs_.lstatSync(resolved.resolved).isDirectory() ? promises_.rmdir(resolved.resolved) : promises_.rm(resolved.resolved));
|
|
43314
44181
|
}
|
|
43315
44182
|
catch (error) {
|
|
43316
44183
|
throw normalizeRemovePathError(error);
|
|
43317
44184
|
}
|
|
43318
|
-
await
|
|
44185
|
+
await directory_guard_assertAsyncDirectoryGuard(guard).catch(() => undefined);
|
|
43319
44186
|
}
|
|
43320
44187
|
async function mkdirPathFallback(resolved) {
|
|
43321
44188
|
await mkdirPathComponentsWithGuards({
|
|
@@ -43326,7 +44193,7 @@ async function mkdirPathFallback(resolved) {
|
|
|
43326
44193
|
async function statPathFallback(root, relativePath) {
|
|
43327
44194
|
const resolved = await resolvePinnedPathInRoot(root, { relativePath, allowRoot: true });
|
|
43328
44195
|
try {
|
|
43329
|
-
const stat = pathStatFromStats(
|
|
44196
|
+
const stat = pathStatFromStats(external_node_fs_.lstatSync(resolved.resolved));
|
|
43330
44197
|
await assertRootIdentityCurrent(root);
|
|
43331
44198
|
return stat;
|
|
43332
44199
|
}
|
|
@@ -43350,7 +44217,7 @@ async function listPathFallback(root, relativePath, withFileTypes) {
|
|
|
43350
44217
|
for (const name of sortedNames) {
|
|
43351
44218
|
entries.push({
|
|
43352
44219
|
name,
|
|
43353
|
-
...pathStatFromStats(
|
|
44220
|
+
...pathStatFromStats(external_node_fs_.lstatSync(external_node_path_.join(resolved.resolved, name))),
|
|
43354
44221
|
});
|
|
43355
44222
|
}
|
|
43356
44223
|
await assertRootIdentityCurrent(root);
|
|
@@ -43399,7 +44266,11 @@ async function movePathFallback(root, params) {
|
|
|
43399
44266
|
relativePath: params.toRelative,
|
|
43400
44267
|
policy: PATH_ALIAS_POLICIES.unlinkTarget,
|
|
43401
44268
|
});
|
|
43402
|
-
|
|
44269
|
+
let targetStat;
|
|
44270
|
+
try {
|
|
44271
|
+
targetStat = external_node_fs_.lstatSync(resolvedTarget.resolved);
|
|
44272
|
+
}
|
|
44273
|
+
catch { /* Advisory lookup. */ }
|
|
43403
44274
|
return !(process.platform !== "win32" &&
|
|
43404
44275
|
params.overwrite &&
|
|
43405
44276
|
targetStat?.isSymbolicLink() === true);
|
|
@@ -43407,7 +44278,7 @@ async function movePathFallback(root, params) {
|
|
|
43407
44278
|
});
|
|
43408
44279
|
let sourceStat;
|
|
43409
44280
|
try {
|
|
43410
|
-
sourceStat =
|
|
44281
|
+
sourceStat = external_node_fs_.lstatSync(source.resolved);
|
|
43411
44282
|
}
|
|
43412
44283
|
catch (error) {
|
|
43413
44284
|
if (path_isNotFoundPathError(error)) {
|
|
@@ -43426,7 +44297,7 @@ async function movePathFallback(root, params) {
|
|
|
43426
44297
|
}
|
|
43427
44298
|
if (!params.overwrite) {
|
|
43428
44299
|
try {
|
|
43429
|
-
|
|
44300
|
+
external_node_fs_.lstatSync(target.resolved);
|
|
43430
44301
|
throw new errors_FsSafeError("already-exists", "destination exists");
|
|
43431
44302
|
}
|
|
43432
44303
|
catch (error) {
|
|
@@ -43441,8 +44312,8 @@ async function movePathFallback(root, params) {
|
|
|
43441
44312
|
const sourceParentGuard = await directory_guard_createAsyncDirectoryGuard(external_node_path_.dirname(source.resolved));
|
|
43442
44313
|
const targetParentGuard = await directory_guard_createNearestExistingDirectoryGuard(target.rootReal, external_node_path_.dirname(target.resolved));
|
|
43443
44314
|
await getFsSafeTestHooks()?.beforeRootFallbackMutation?.("move", target.resolved);
|
|
43444
|
-
await
|
|
43445
|
-
await
|
|
44315
|
+
await directory_guard_assertAsyncDirectoryGuard(sourceParentGuard);
|
|
44316
|
+
await directory_guard_assertAsyncDirectoryGuard(targetParentGuard);
|
|
43446
44317
|
try {
|
|
43447
44318
|
await promises_.rename(source.resolved, target.resolved);
|
|
43448
44319
|
}
|
|
@@ -43457,7 +44328,7 @@ async function movePathFallback(root, params) {
|
|
|
43457
44328
|
}
|
|
43458
44329
|
throw error;
|
|
43459
44330
|
}
|
|
43460
|
-
await
|
|
44331
|
+
await directory_guard_assertAsyncDirectoryGuard(targetParentGuard).catch(() => undefined);
|
|
43461
44332
|
}
|
|
43462
44333
|
async function writeFileFallback(root, params) {
|
|
43463
44334
|
if (params.overwrite === false) {
|
|
@@ -43467,7 +44338,8 @@ async function writeFileFallback(root, params) {
|
|
|
43467
44338
|
const target = await openWritableFileInRoot(root, {
|
|
43468
44339
|
relativePath: params.relativePath,
|
|
43469
44340
|
mkdir: params.mkdir,
|
|
43470
|
-
|
|
44341
|
+
// Private, writable placeholder: Windows cannot rename over a read-only file.
|
|
44342
|
+
mode: 0o600,
|
|
43471
44343
|
denyMutations: params.denyMutations,
|
|
43472
44344
|
truncateExisting: false,
|
|
43473
44345
|
});
|
|
@@ -43480,12 +44352,12 @@ async function writeFileFallback(root, params) {
|
|
|
43480
44352
|
let writtenHandle;
|
|
43481
44353
|
try {
|
|
43482
44354
|
tempPath = buildAtomicWriteTempPath(destinationPath);
|
|
43483
|
-
unregisterTempPath =
|
|
44355
|
+
unregisterTempPath = temp_cleanup_registerTempPathForExit(tempPath);
|
|
43484
44356
|
const written = await writeTempFileForAtomicReplace({
|
|
43485
44357
|
tempPath,
|
|
43486
44358
|
data: params.data,
|
|
43487
44359
|
encoding: params.encoding,
|
|
43488
|
-
mode,
|
|
44360
|
+
mode: 0o600,
|
|
43489
44361
|
});
|
|
43490
44362
|
writtenHandle = written.handle;
|
|
43491
44363
|
unregisterTempPath.setIdentity(written.identity);
|
|
@@ -43496,6 +44368,14 @@ async function writeFileFallback(root, params) {
|
|
|
43496
44368
|
});
|
|
43497
44369
|
unregisterTempPath();
|
|
43498
44370
|
unregisterTempPath = null;
|
|
44371
|
+
// Final mode via the retained handle after publication, as the native writer does.
|
|
44372
|
+
try {
|
|
44373
|
+
await written.handle.chmod(mode);
|
|
44374
|
+
}
|
|
44375
|
+
catch (error) {
|
|
44376
|
+
await removePathIfIdentityUnchanged(destinationPath, written.identity).catch(() => { });
|
|
44377
|
+
throw error;
|
|
44378
|
+
}
|
|
43499
44379
|
try {
|
|
43500
44380
|
await verifyAtomicWriteResult({
|
|
43501
44381
|
root,
|
|
@@ -43533,11 +44413,11 @@ async function writeMissingFileFallback(root, params) {
|
|
|
43533
44413
|
let verifyingPublication = false;
|
|
43534
44414
|
try {
|
|
43535
44415
|
const { handle, writtenStat } = await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
43536
|
-
const handle = await promises_.open(targetPath, OPEN_WRITE_CREATE_FLAGS, params.mode ?? 0o600);
|
|
44416
|
+
const handle = await promises_.open(targetPath, OPEN_WRITE_CREATE_FLAGS, params.mode ?? 0o600).catch((error) => recordExclusiveCreateFailure(error, targetPath));
|
|
43537
44417
|
created = true;
|
|
43538
44418
|
try {
|
|
43539
|
-
createdIdentity =
|
|
43540
|
-
const writtenStat =
|
|
44419
|
+
createdIdentity = external_node_fs_.fstatSync(handle.fd);
|
|
44420
|
+
const writtenStat = external_node_fs_.fstatSync(handle.fd, { bigint: true });
|
|
43541
44421
|
if (typeof params.data === "string") {
|
|
43542
44422
|
await handle.writeFile(params.data, params.encoding ?? "utf8");
|
|
43543
44423
|
}
|
|
@@ -92069,4 +92949,4 @@ if (installedChunkData !== 0) { // 0 means "already installed".'
|
|
|
92069
92949
|
// module factories are used so entry inlining is disabled
|
|
92070
92950
|
// startup
|
|
92071
92951
|
// Load entry module and return exports
|
|
92072
|
-
var __webpack_exports__ = __webpack_require__(
|
|
92952
|
+
var __webpack_exports__ = __webpack_require__(6732);
|