@lousy-agents/mcp 5.14.9 → 5.14.10
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 +106 -87
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -26726,6 +26726,9 @@ function path_isPathInside(root, target) {
|
|
|
26726
26726
|
const firstSegment = relative.split(external_node_path_.posix.sep)[0];
|
|
26727
26727
|
return relative === "" || (firstSegment !== ".." && !external_node_path_.isAbsolute(relative));
|
|
26728
26728
|
}
|
|
26729
|
+
function isPathRelativeEscape(relativePath) {
|
|
26730
|
+
return relativePath === ".." || relativePath.startsWith(`..${external_node_path_.sep}`) || external_node_path_.isAbsolute(relativePath);
|
|
26731
|
+
}
|
|
26729
26732
|
function resolveSafeBaseDir(rootDir) {
|
|
26730
26733
|
const resolved = path.resolve(rootDir);
|
|
26731
26734
|
return resolved.endsWith(path.sep) ? resolved : `${resolved}${path.sep}`;
|
|
@@ -26874,17 +26877,17 @@ function directory_guard_createNearestExistingSyncDirectoryGuard(rootReal, targe
|
|
|
26874
26877
|
|
|
26875
26878
|
|
|
26876
26879
|
|
|
26880
|
+
|
|
26877
26881
|
function isSameOrChildPath(candidate, parent) {
|
|
26878
|
-
|
|
26879
|
-
|
|
26880
|
-
function isPathEscape(relativePath) {
|
|
26881
|
-
return relativePath === ".." || relativePath.startsWith(`..${external_node_path_.sep}`) || external_node_path_.isAbsolute(relativePath);
|
|
26882
|
+
const parentPrefix = parent.endsWith(external_node_path_.sep) ? parent : `${parent}${external_node_path_.sep}`;
|
|
26883
|
+
return candidate === parent || candidate.startsWith(parentPrefix);
|
|
26882
26884
|
}
|
|
26883
26885
|
async function mkdirPathComponentsWithGuards(params) {
|
|
26884
26886
|
const root = external_node_path_.resolve(params.rootReal);
|
|
26887
|
+
const rootCanonical = external_node_path_.resolve(await promises_.realpath(root));
|
|
26885
26888
|
const target = external_node_path_.resolve(params.targetPath);
|
|
26886
26889
|
const relative = external_node_path_.relative(root, target);
|
|
26887
|
-
if (
|
|
26890
|
+
if (isPathRelativeEscape(relative)) {
|
|
26888
26891
|
throw new errors_FsSafeError("outside-workspace", "directory is outside workspace root");
|
|
26889
26892
|
}
|
|
26890
26893
|
let current = root;
|
|
@@ -26907,7 +26910,7 @@ async function mkdirPathComponentsWithGuards(params) {
|
|
|
26907
26910
|
}
|
|
26908
26911
|
// Node's recursive mkdir follows symlinks in missing components. Build one
|
|
26909
26912
|
// segment at a time and realpath-check each segment before descending.
|
|
26910
|
-
if (!isSameOrChildPath(external_node_path_.resolve(await promises_.realpath(next)),
|
|
26913
|
+
if (!isSameOrChildPath(external_node_path_.resolve(await promises_.realpath(next)), rootCanonical)) {
|
|
26911
26914
|
throw new errors_FsSafeError("outside-workspace", "directory escaped workspace root");
|
|
26912
26915
|
}
|
|
26913
26916
|
await directory_guard_createAsyncDirectoryGuard(next);
|
|
@@ -27042,26 +27045,20 @@ var external_node_child_process_ = __webpack_require__(1421);
|
|
|
27042
27045
|
|
|
27043
27046
|
|
|
27044
27047
|
const PINNED_PYTHON_WORKER_SOURCE = String.raw `
|
|
27045
|
-
import base64
|
|
27046
|
-
import errno
|
|
27047
|
-
import json
|
|
27048
|
-
import os
|
|
27049
|
-
import secrets
|
|
27050
|
-
import stat
|
|
27051
|
-
import sys
|
|
27052
|
-
|
|
27048
|
+
import base64, errno, json, os, secrets, stat, sys
|
|
27053
27049
|
DIR_FLAGS = os.O_RDONLY
|
|
27054
27050
|
if hasattr(os, "O_DIRECTORY"):
|
|
27055
27051
|
DIR_FLAGS |= os.O_DIRECTORY
|
|
27056
27052
|
if hasattr(os, "O_NOFOLLOW"):
|
|
27057
27053
|
DIR_FLAGS |= os.O_NOFOLLOW
|
|
27058
27054
|
READ_FLAGS = os.O_RDONLY
|
|
27055
|
+
if hasattr(os, "O_NONBLOCK"):
|
|
27056
|
+
READ_FLAGS |= os.O_NONBLOCK
|
|
27059
27057
|
if hasattr(os, "O_NOFOLLOW"):
|
|
27060
27058
|
READ_FLAGS |= os.O_NOFOLLOW
|
|
27061
27059
|
WRITE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL
|
|
27062
27060
|
if hasattr(os, "O_NOFOLLOW"):
|
|
27063
27061
|
WRITE_FLAGS |= os.O_NOFOLLOW
|
|
27064
|
-
|
|
27065
27062
|
def split_relative(value):
|
|
27066
27063
|
if value in ("", "."):
|
|
27067
27064
|
return []
|
|
@@ -27074,10 +27071,8 @@ def split_relative(value):
|
|
|
27074
27071
|
if part == "..":
|
|
27075
27072
|
raise OSError(errno.EPERM, "path traversal is not allowed")
|
|
27076
27073
|
return parts
|
|
27077
|
-
|
|
27078
27074
|
def open_dir(path_value, dir_fd=None):
|
|
27079
27075
|
return os.open(path_value, DIR_FLAGS, dir_fd=dir_fd)
|
|
27080
|
-
|
|
27081
27076
|
def walk_dir(root_fd, segments, mkdir_enabled=False):
|
|
27082
27077
|
current_fd = os.dup(root_fd)
|
|
27083
27078
|
try:
|
|
@@ -27095,14 +27090,12 @@ def walk_dir(root_fd, segments, mkdir_enabled=False):
|
|
|
27095
27090
|
except Exception:
|
|
27096
27091
|
os.close(current_fd)
|
|
27097
27092
|
raise
|
|
27098
|
-
|
|
27099
27093
|
def parent_and_basename(root_fd, relative):
|
|
27100
27094
|
segments = split_relative(relative)
|
|
27101
27095
|
if not segments:
|
|
27102
27096
|
raise OSError(errno.EPERM, "operation requires a non-root path")
|
|
27103
27097
|
parent_fd = walk_dir(root_fd, segments[:-1])
|
|
27104
27098
|
return parent_fd, segments[-1]
|
|
27105
|
-
|
|
27106
27099
|
def encode_stat(st):
|
|
27107
27100
|
mode = st.st_mode
|
|
27108
27101
|
return {
|
|
@@ -27118,14 +27111,12 @@ def encode_stat(st):
|
|
|
27118
27111
|
"size": st.st_size,
|
|
27119
27112
|
"uid": st.st_uid,
|
|
27120
27113
|
}
|
|
27121
|
-
|
|
27122
27114
|
def reject_unsafe_endpoint(st):
|
|
27123
27115
|
mode = st.st_mode
|
|
27124
27116
|
if stat.S_ISLNK(mode):
|
|
27125
27117
|
raise OSError(errno.ELOOP, "symlink endpoint is not allowed")
|
|
27126
27118
|
if stat.S_ISREG(mode) and st.st_nlink > 1:
|
|
27127
27119
|
raise OSError(errno.EPERM, "hardlinked file endpoint is not allowed")
|
|
27128
|
-
|
|
27129
27120
|
def copy_bytes(source_fd, dest_fd):
|
|
27130
27121
|
while True:
|
|
27131
27122
|
chunk = os.read(source_fd, 65536)
|
|
@@ -27137,7 +27128,6 @@ def copy_bytes(source_fd, dest_fd):
|
|
|
27137
27128
|
if written <= 0:
|
|
27138
27129
|
raise OSError(errno.EIO, "short write")
|
|
27139
27130
|
view = view[written:]
|
|
27140
|
-
|
|
27141
27131
|
def write_all(fd, data):
|
|
27142
27132
|
view = memoryview(data)
|
|
27143
27133
|
while view:
|
|
@@ -27145,11 +27135,9 @@ def write_all(fd, data):
|
|
|
27145
27135
|
if written <= 0:
|
|
27146
27136
|
raise OSError(errno.EIO, "short write")
|
|
27147
27137
|
view = view[written:]
|
|
27148
|
-
|
|
27149
27138
|
def link_unsupported(exc):
|
|
27150
27139
|
unsupported = (errno.EPERM, errno.EOPNOTSUPP, getattr(errno, "ENOTSUP", errno.EOPNOTSUPP))
|
|
27151
27140
|
return getattr(exc, "errno", None) in unsupported
|
|
27152
|
-
|
|
27153
27141
|
def link_no_replace(name, new_name, source_fd, target_fd):
|
|
27154
27142
|
linked = False
|
|
27155
27143
|
try:
|
|
@@ -27164,11 +27152,9 @@ def link_no_replace(name, new_name, source_fd, target_fd):
|
|
|
27164
27152
|
os.fsync(source_fd)
|
|
27165
27153
|
if source_fd != target_fd:
|
|
27166
27154
|
os.fsync(target_fd)
|
|
27167
|
-
|
|
27168
27155
|
def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basename, mode, expected=None, unlink_source=False):
|
|
27169
27156
|
source_fd = os.open(source_name, READ_FLAGS, dir_fd=source_parent_fd)
|
|
27170
|
-
dest_fd = None
|
|
27171
|
-
success = False
|
|
27157
|
+
dest_fd = None; success = False; dest_stat = None
|
|
27172
27158
|
try:
|
|
27173
27159
|
if expected is not None:
|
|
27174
27160
|
source_stat = os.fstat(source_fd)
|
|
@@ -27177,6 +27163,7 @@ def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basena
|
|
|
27177
27163
|
dest_fd = os.open(basename, WRITE_FLAGS, mode, dir_fd=target_parent_fd)
|
|
27178
27164
|
copy_bytes(source_fd, dest_fd)
|
|
27179
27165
|
os.fsync(dest_fd)
|
|
27166
|
+
dest_stat = os.fstat(dest_fd)
|
|
27180
27167
|
success = True
|
|
27181
27168
|
finally:
|
|
27182
27169
|
os.close(source_fd)
|
|
@@ -27192,19 +27179,40 @@ def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basena
|
|
|
27192
27179
|
try: os.unlink(basename, dir_fd=target_parent_fd)
|
|
27193
27180
|
except FileNotFoundError: pass
|
|
27194
27181
|
raise
|
|
27195
|
-
|
|
27196
|
-
def
|
|
27182
|
+
return dest_stat
|
|
27183
|
+
def same_identity(left, right):
|
|
27184
|
+
return left.st_dev == right.st_dev and left.st_ino == right.st_ino
|
|
27185
|
+
def verify_temp_name(parent_fd, temp_name, expected_stat):
|
|
27186
|
+
current_stat = os.lstat(temp_name, dir_fd=parent_fd)
|
|
27187
|
+
if stat.S_ISLNK(current_stat.st_mode) or not same_identity(current_stat, expected_stat):
|
|
27188
|
+
raise RuntimeError("fs-safe-temp-mismatch")
|
|
27189
|
+
def verify_committed_temp(parent_fd, basename, expected_stat):
|
|
27190
|
+
final_stat = os.lstat(basename, dir_fd=parent_fd)
|
|
27191
|
+
if not stat.S_ISLNK(final_stat.st_mode) and same_identity(final_stat, expected_stat):
|
|
27192
|
+
return final_stat
|
|
27193
|
+
try: os.unlink(basename, dir_fd=parent_fd)
|
|
27194
|
+
except FileNotFoundError: pass
|
|
27195
|
+
raise RuntimeError("fs-safe-temp-mismatch")
|
|
27196
|
+
def commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, expected_stat):
|
|
27197
|
+
verify_temp_name(parent_fd, temp_name, expected_stat)
|
|
27197
27198
|
if overwrite:
|
|
27198
27199
|
os.replace(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd)
|
|
27200
|
+
return verify_committed_temp(parent_fd, basename, expected_stat)
|
|
27199
27201
|
else:
|
|
27200
27202
|
try:
|
|
27201
27203
|
os.link(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd, follow_symlinks=False)
|
|
27204
|
+
final_stat = verify_committed_temp(parent_fd, basename, expected_stat)
|
|
27202
27205
|
os.unlink(temp_name, dir_fd=parent_fd)
|
|
27206
|
+
return final_stat
|
|
27203
27207
|
except OSError as exc:
|
|
27204
27208
|
if not link_unsupported(exc):
|
|
27205
27209
|
raise
|
|
27206
|
-
copy_file_no_replace(parent_fd, temp_name, parent_fd, basename, mode,
|
|
27207
|
-
|
|
27210
|
+
return copy_file_no_replace(parent_fd, temp_name, parent_fd, basename, mode, expected_stat, True)
|
|
27211
|
+
def assert_expected_root(root_fd, payload):
|
|
27212
|
+
if "rootDev" in payload or "rootIno" in payload:
|
|
27213
|
+
root_stat = os.fstat(root_fd)
|
|
27214
|
+
if root_stat.st_dev != int(payload["rootDev"]) or root_stat.st_ino != int(payload["rootIno"]):
|
|
27215
|
+
raise RuntimeError("fs-safe-root-mismatch")
|
|
27208
27216
|
def stat_path(root_fd, payload):
|
|
27209
27217
|
relative = payload.get("relativePath", "")
|
|
27210
27218
|
segments = split_relative(relative)
|
|
@@ -27218,7 +27226,6 @@ def stat_path(root_fd, payload):
|
|
|
27218
27226
|
return encode_stat(st)
|
|
27219
27227
|
finally:
|
|
27220
27228
|
os.close(parent_fd)
|
|
27221
|
-
|
|
27222
27229
|
def readdir_path(root_fd, payload):
|
|
27223
27230
|
dir_fd = walk_dir(root_fd, split_relative(payload.get("relativePath", "")))
|
|
27224
27231
|
try:
|
|
@@ -27234,12 +27241,9 @@ def readdir_path(root_fd, payload):
|
|
|
27234
27241
|
return entries
|
|
27235
27242
|
finally:
|
|
27236
27243
|
os.close(dir_fd)
|
|
27237
|
-
|
|
27238
27244
|
def mkdirp_path(root_fd, payload):
|
|
27239
27245
|
dir_fd = walk_dir(root_fd, split_relative(payload.get("relativePath", "")), mkdir_enabled=True)
|
|
27240
|
-
os.close(dir_fd)
|
|
27241
|
-
return None
|
|
27242
|
-
|
|
27246
|
+
os.close(dir_fd); return None
|
|
27243
27247
|
def remove_tree(parent_fd, basename):
|
|
27244
27248
|
st = os.lstat(basename, dir_fd=parent_fd)
|
|
27245
27249
|
if stat.S_ISDIR(st.st_mode) and not stat.S_ISLNK(st.st_mode):
|
|
@@ -27252,7 +27256,6 @@ def remove_tree(parent_fd, basename):
|
|
|
27252
27256
|
os.rmdir(basename, dir_fd=parent_fd)
|
|
27253
27257
|
else:
|
|
27254
27258
|
os.unlink(basename, dir_fd=parent_fd)
|
|
27255
|
-
|
|
27256
27259
|
def remove_path(root_fd, payload):
|
|
27257
27260
|
parent_fd, basename = parent_and_basename(root_fd, payload.get("relativePath", ""))
|
|
27258
27261
|
try:
|
|
@@ -27335,14 +27338,15 @@ def write_path(root_fd, payload):
|
|
|
27335
27338
|
except FileNotFoundError:
|
|
27336
27339
|
pass
|
|
27337
27340
|
temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
|
|
27341
|
+
os.fchmod(temp_fd, mode)
|
|
27338
27342
|
write_all(temp_fd, data)
|
|
27339
27343
|
os.fsync(temp_fd)
|
|
27344
|
+
temp_stat = os.fstat(temp_fd)
|
|
27340
27345
|
os.close(temp_fd)
|
|
27341
27346
|
temp_fd = None
|
|
27342
|
-
commit_temp_file(parent_fd, temp_name, basename, overwrite, mode)
|
|
27347
|
+
result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
|
|
27343
27348
|
temp_name = None
|
|
27344
27349
|
os.fsync(parent_fd)
|
|
27345
|
-
result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
|
|
27346
27350
|
return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
|
|
27347
27351
|
finally:
|
|
27348
27352
|
if temp_fd is not None:
|
|
@@ -27373,6 +27377,7 @@ def copy_path(root_fd, payload):
|
|
|
27373
27377
|
raise RuntimeError("fs-safe-too-large:%d:%d" % (max_bytes, source_stat.st_size))
|
|
27374
27378
|
parent_fd = walk_dir(root_fd, split_relative(payload.get("relativeParentPath", "")), bool(payload.get("mkdir", True)))
|
|
27375
27379
|
temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
|
|
27380
|
+
os.fchmod(temp_fd, mode)
|
|
27376
27381
|
written_bytes = 0
|
|
27377
27382
|
while True:
|
|
27378
27383
|
chunk = os.read(source_fd, 65536)
|
|
@@ -27388,12 +27393,12 @@ def copy_path(root_fd, payload):
|
|
|
27388
27393
|
raise OSError(errno.EIO, "short write")
|
|
27389
27394
|
view = view[written:]
|
|
27390
27395
|
os.fsync(temp_fd)
|
|
27396
|
+
temp_stat = os.fstat(temp_fd)
|
|
27391
27397
|
os.close(temp_fd)
|
|
27392
27398
|
temp_fd = None
|
|
27393
|
-
commit_temp_file(parent_fd, temp_name, basename, overwrite, mode)
|
|
27399
|
+
result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
|
|
27394
27400
|
temp_name = None
|
|
27395
27401
|
os.fsync(parent_fd)
|
|
27396
|
-
result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
|
|
27397
27402
|
return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
|
|
27398
27403
|
finally:
|
|
27399
27404
|
os.close(source_fd)
|
|
@@ -27410,6 +27415,7 @@ def copy_path(root_fd, payload):
|
|
|
27410
27415
|
def run_operation(operation, root_path, payload):
|
|
27411
27416
|
root_fd = open_dir(root_path)
|
|
27412
27417
|
try:
|
|
27418
|
+
assert_expected_root(root_fd, payload)
|
|
27413
27419
|
if operation == "stat":
|
|
27414
27420
|
return stat_path(root_fd, payload)
|
|
27415
27421
|
if operation == "readdir":
|
|
@@ -27514,6 +27520,12 @@ function mapWorkerError(response) {
|
|
|
27514
27520
|
if (message.includes("fs-safe-source-mismatch")) {
|
|
27515
27521
|
return new errors_FsSafeError("path-mismatch", "source path changed during copy");
|
|
27516
27522
|
}
|
|
27523
|
+
if (message.includes("fs-safe-temp-mismatch")) {
|
|
27524
|
+
return new errors_FsSafeError("path-mismatch", "temp path changed during write");
|
|
27525
|
+
}
|
|
27526
|
+
if (message.includes("fs-safe-root-mismatch")) {
|
|
27527
|
+
return new errors_FsSafeError("path-mismatch", "root path changed during operation");
|
|
27528
|
+
}
|
|
27517
27529
|
if (message.includes("fs-safe-directory-noreplace-unsupported")) {
|
|
27518
27530
|
return new errors_FsSafeError("invalid-path", "directory moves require overwrite: true");
|
|
27519
27531
|
}
|
|
@@ -27694,9 +27706,7 @@ function validatePinnedOperationPayload(payload) {
|
|
|
27694
27706
|
}
|
|
27695
27707
|
}
|
|
27696
27708
|
function isPinnedHelperUnavailable(error) {
|
|
27697
|
-
return error instanceof Error &&
|
|
27698
|
-
"code" in error &&
|
|
27699
|
-
error.code === "helper-unavailable";
|
|
27709
|
+
return error instanceof Error && "code" in error && error.code === "helper-unavailable";
|
|
27700
27710
|
}
|
|
27701
27711
|
function validatePinnedRelativePath(relativePath) {
|
|
27702
27712
|
if (relativePath.length === 0 || relativePath === ".") {
|
|
@@ -27794,29 +27804,21 @@ function assertWithinMaxBytes(bytes, maxBytes) {
|
|
|
27794
27804
|
throw new errors_FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`);
|
|
27795
27805
|
}
|
|
27796
27806
|
}
|
|
27797
|
-
function
|
|
27798
|
-
if (maxBytes === undefined) {
|
|
27799
|
-
return undefined;
|
|
27800
|
-
}
|
|
27807
|
+
async function writeStreamToHandle(stream, handle, maxBytes) {
|
|
27801
27808
|
let bytes = 0;
|
|
27802
|
-
|
|
27803
|
-
|
|
27804
|
-
|
|
27805
|
-
|
|
27806
|
-
|
|
27807
|
-
|
|
27809
|
+
for await (const chunk of stream) {
|
|
27810
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
27811
|
+
bytes += buffer.byteLength;
|
|
27812
|
+
assertWithinMaxBytes(bytes, maxBytes);
|
|
27813
|
+
let offset = 0;
|
|
27814
|
+
while (offset < buffer.byteLength) {
|
|
27815
|
+
const { bytesWritten } = await handle.write(buffer, offset, buffer.byteLength - offset);
|
|
27816
|
+
if (bytesWritten <= 0) {
|
|
27817
|
+
throw new errors_FsSafeError("helper-failed", "fallback stream write made no progress");
|
|
27808
27818
|
}
|
|
27809
|
-
|
|
27810
|
-
}
|
|
27811
|
-
});
|
|
27812
|
-
}
|
|
27813
|
-
async function pipelineWithMaxBytes(stream, destination, maxBytes) {
|
|
27814
|
-
const limiter = pinned_write_createMaxBytesTransform(maxBytes);
|
|
27815
|
-
if (limiter) {
|
|
27816
|
-
await (0,external_node_stream_promises_.pipeline)(stream, limiter, destination);
|
|
27817
|
-
return;
|
|
27819
|
+
offset += bytesWritten;
|
|
27820
|
+
}
|
|
27818
27821
|
}
|
|
27819
|
-
await (0,external_node_stream_promises_.pipeline)(stream, destination);
|
|
27820
27822
|
}
|
|
27821
27823
|
async function inputToBase64(input, maxBytes) {
|
|
27822
27824
|
if (input.kind === "buffer") {
|
|
@@ -27841,7 +27843,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27841
27843
|
relativeParentPath: params.relativeParentPath,
|
|
27842
27844
|
});
|
|
27843
27845
|
if (getFsSafePythonConfig().mode === "off") {
|
|
27844
|
-
return await
|
|
27846
|
+
return await runPinnedWriteFallbackOrThrow(params);
|
|
27845
27847
|
}
|
|
27846
27848
|
if (params.input.kind === "stream") {
|
|
27847
27849
|
try {
|
|
@@ -27849,7 +27851,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27849
27851
|
}
|
|
27850
27852
|
catch (error) {
|
|
27851
27853
|
if (canFallbackFromPythonError(error)) {
|
|
27852
|
-
return await
|
|
27854
|
+
return await runPinnedWriteFallbackOrThrow(params, error);
|
|
27853
27855
|
}
|
|
27854
27856
|
throw error;
|
|
27855
27857
|
}
|
|
@@ -27862,6 +27864,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27862
27864
|
mode: params.mode || 0o600,
|
|
27863
27865
|
overwrite: params.overwrite !== false,
|
|
27864
27866
|
relativeParentPath: params.relativeParentPath,
|
|
27867
|
+
...(params.rootIdentity ? { rootDev: params.rootIdentity.dev, rootIno: params.rootIdentity.ino } : {}),
|
|
27865
27868
|
};
|
|
27866
27869
|
try {
|
|
27867
27870
|
return await runPinnedPythonOperation({
|
|
@@ -27872,7 +27875,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27872
27875
|
}
|
|
27873
27876
|
catch (error) {
|
|
27874
27877
|
if (canFallbackFromPythonError(error)) {
|
|
27875
|
-
return await
|
|
27878
|
+
return await runPinnedWriteFallbackOrThrow(params, error);
|
|
27876
27879
|
}
|
|
27877
27880
|
throw error;
|
|
27878
27881
|
}
|
|
@@ -27892,22 +27895,29 @@ async function runPinnedCopyHelper(params) {
|
|
|
27892
27895
|
mode: params.mode || 0o600,
|
|
27893
27896
|
overwrite: params.overwrite !== false,
|
|
27894
27897
|
relativeParentPath: params.relativeParentPath,
|
|
27898
|
+
...(params.rootIdentity ? { rootDev: params.rootIdentity.dev, rootIno: params.rootIdentity.ino } : {}),
|
|
27895
27899
|
sourceDev: params.sourceIdentity.dev,
|
|
27896
27900
|
sourceIno: params.sourceIdentity.ino,
|
|
27897
27901
|
sourcePath: params.sourcePath,
|
|
27898
27902
|
},
|
|
27899
27903
|
});
|
|
27900
27904
|
}
|
|
27905
|
+
async function runPinnedWriteFallbackOrThrow(params, cause) {
|
|
27906
|
+
if (process.platform !== "win32") {
|
|
27907
|
+
throw new errors_FsSafeError("helper-unavailable", "Python helper is required for pinned writes on this platform", { cause });
|
|
27908
|
+
}
|
|
27909
|
+
return await runPinnedWriteFallback(params);
|
|
27910
|
+
}
|
|
27901
27911
|
async function runPinnedWriteFallback(params) {
|
|
27902
27912
|
const parentPath = params.relativeParentPath
|
|
27903
27913
|
? external_node_path_.join(params.rootPath, ...params.relativeParentPath.split("/"))
|
|
27904
27914
|
: params.rootPath;
|
|
27905
|
-
const parentGuard = await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath);
|
|
27906
27915
|
if (params.mkdir) {
|
|
27907
|
-
await
|
|
27908
|
-
await promises_.mkdir(parentPath, { recursive: true });
|
|
27909
|
-
});
|
|
27916
|
+
await mkdirPathComponentsWithGuards({ rootReal: params.rootPath, targetPath: parentPath });
|
|
27910
27917
|
}
|
|
27918
|
+
const parentGuard = params.mkdir
|
|
27919
|
+
? await directory_guard_createAsyncDirectoryGuard(parentPath)
|
|
27920
|
+
: await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath);
|
|
27911
27921
|
const targetPath = external_node_path_.join(parentPath, params.basename);
|
|
27912
27922
|
if (params.overwrite === false) {
|
|
27913
27923
|
let 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), {
|
|
@@ -27929,7 +27939,7 @@ async function runPinnedWriteFallback(params) {
|
|
|
27929
27939
|
}
|
|
27930
27940
|
}
|
|
27931
27941
|
else {
|
|
27932
|
-
await
|
|
27942
|
+
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
27933
27943
|
}
|
|
27934
27944
|
const stat = await handle.stat();
|
|
27935
27945
|
created = false;
|
|
@@ -27950,7 +27960,9 @@ async function runPinnedWriteFallback(params) {
|
|
|
27950
27960
|
? external_node_fs_.constants.O_NOFOLLOW
|
|
27951
27961
|
: 0);
|
|
27952
27962
|
let handle;
|
|
27953
|
-
let
|
|
27963
|
+
let tempStat;
|
|
27964
|
+
let targetStat;
|
|
27965
|
+
let renamed = false;
|
|
27954
27966
|
try {
|
|
27955
27967
|
handle = await promises_.open(tempPath, tempFlags, params.mode);
|
|
27956
27968
|
if (params.input.kind === "buffer") {
|
|
@@ -27963,29 +27975,36 @@ async function runPinnedWriteFallback(params) {
|
|
|
27963
27975
|
}
|
|
27964
27976
|
}
|
|
27965
27977
|
else {
|
|
27966
|
-
|
|
27967
|
-
writable.once("close", () => {
|
|
27968
|
-
handleClosedByStream = true;
|
|
27969
|
-
});
|
|
27970
|
-
await pipelineWithMaxBytes(params.input.stream, writable, params.maxBytes);
|
|
27978
|
+
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
27971
27979
|
}
|
|
27972
|
-
|
|
27973
|
-
|
|
27974
|
-
|
|
27980
|
+
tempStat = await handle.stat();
|
|
27981
|
+
const tempPathStat = await promises_.lstat(tempPath);
|
|
27982
|
+
if (tempPathStat.isSymbolicLink() || !file_identity_sameFileIdentity(tempPathStat, tempStat)) {
|
|
27983
|
+
throw new errors_FsSafeError("path-mismatch", "fallback temp path changed during write");
|
|
27975
27984
|
}
|
|
27985
|
+
const expectedTempStat = tempStat;
|
|
27986
|
+
await handle.close().catch(() => undefined);
|
|
27987
|
+
handle = undefined;
|
|
27976
27988
|
await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
27977
27989
|
await promises_.rename(tempPath, targetPath);
|
|
27990
|
+
renamed = true;
|
|
27991
|
+
targetStat = await promises_.lstat(targetPath);
|
|
27992
|
+
if (targetStat.isSymbolicLink() || !file_identity_sameFileIdentity(targetStat, expectedTempStat)) {
|
|
27993
|
+
throw new errors_FsSafeError("path-mismatch", "fallback target changed during write");
|
|
27994
|
+
}
|
|
27978
27995
|
});
|
|
27979
27996
|
}
|
|
27980
27997
|
catch (error) {
|
|
27981
|
-
|
|
27982
|
-
|
|
27998
|
+
await handle?.close().catch(() => undefined);
|
|
27999
|
+
if (!renamed) {
|
|
28000
|
+
await promises_.rm(tempPath, { force: true }).catch(() => undefined);
|
|
27983
28001
|
}
|
|
27984
|
-
await promises_.rm(tempPath, { force: true }).catch(() => undefined);
|
|
27985
28002
|
throw error;
|
|
27986
28003
|
}
|
|
27987
|
-
|
|
27988
|
-
|
|
28004
|
+
if (!targetStat) {
|
|
28005
|
+
throw new errors_FsSafeError("path-mismatch", "fallback target was not verified");
|
|
28006
|
+
}
|
|
28007
|
+
return { dev: targetStat.dev, ino: targetStat.ino };
|
|
27989
28008
|
}
|
|
27990
28009
|
|
|
27991
28010
|
// EXTERNAL MODULE: external "node:os"
|
|
@@ -28524,7 +28543,7 @@ function relativeInsideRoot(rootPath, targetPath) {
|
|
|
28524
28543
|
if (!relative || relative === ".") {
|
|
28525
28544
|
return "";
|
|
28526
28545
|
}
|
|
28527
|
-
if (
|
|
28546
|
+
if (isPathRelativeEscape(relative)) {
|
|
28528
28547
|
return "";
|
|
28529
28548
|
}
|
|
28530
28549
|
return relative;
|