mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 15:00:44 +00:00
fix: preserve late sandbox rename writes
This commit is contained in:
@@ -65,6 +65,22 @@ const FORCED_EXDEV_MUTATION_PYTHON = SANDBOX_PINNED_MUTATION_PYTHON.replace(
|
||||
" raise OSError(errno.EXDEV, 'forced EXDEV for test')\n os.rename(src_basename, dst_basename, src_dir_fd=src_parent_fd, dst_dir_fd=dst_parent_fd)",
|
||||
);
|
||||
|
||||
const FORCED_EXDEV_WITH_LATE_SOURCE_WRITE_MUTATION_PYTHON = FORCED_EXDEV_MUTATION_PYTHON.replace(
|
||||
" remove_copied_entry(src_parent_fd, src_basename, ('dir', copied_children))",
|
||||
[
|
||||
" late_parent_fd = open_dir(src_basename, dir_fd=src_parent_fd)",
|
||||
" late_fd = None",
|
||||
" try:",
|
||||
" late_fd = os.open('late.txt', WRITE_FLAGS, 0o600, dir_fd=late_parent_fd)",
|
||||
" os.write(late_fd, b'late')",
|
||||
" finally:",
|
||||
" if late_fd is not None:",
|
||||
" os.close(late_fd)",
|
||||
" os.close(late_parent_fd)",
|
||||
" remove_copied_entry(src_parent_fd, src_basename, ('dir', copied_children))",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
describe("sandbox pinned mutation helper", () => {
|
||||
it("writes through a pinned directory fd", async () => {
|
||||
await withTempDir({ prefix: "openclaw-mutation-helper-" }, async (root) => {
|
||||
@@ -365,4 +381,37 @@ describe("sandbox pinned mutation helper", () => {
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.runIf(process.platform !== "win32")(
|
||||
"preserves source entries created after the directory rename fallback copy phase",
|
||||
async () => {
|
||||
await withTempDir({ prefix: "openclaw-mutation-helper-" }, async (root) => {
|
||||
const sourceRoot = path.join(root, "source");
|
||||
const destRoot = path.join(root, "dest");
|
||||
await fs.mkdir(path.join(sourceRoot, "dir", "nested"), { recursive: true });
|
||||
await fs.mkdir(destRoot, { recursive: true });
|
||||
await fs.writeFile(path.join(sourceRoot, "dir", "nested", "file.txt"), "payload", "utf8");
|
||||
|
||||
const result = runMutationWithSource(FORCED_EXDEV_WITH_LATE_SOURCE_WRITE_MUTATION_PYTHON, [
|
||||
"rename",
|
||||
sourceRoot,
|
||||
"",
|
||||
"dir",
|
||||
destRoot,
|
||||
"",
|
||||
"moved",
|
||||
"1",
|
||||
]);
|
||||
|
||||
expect(result.status).not.toBe(0);
|
||||
await expect(
|
||||
fs.readFile(path.join(destRoot, "moved", "nested", "file.txt"), "utf8"),
|
||||
).resolves.toBe("payload");
|
||||
await expect(fs.readFile(path.join(sourceRoot, "dir", "late.txt"), "utf8")).resolves.toBe(
|
||||
"late",
|
||||
);
|
||||
await expect(fs.stat(path.join(sourceRoot, "dir", "nested"))).rejects.toThrow();
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -162,13 +162,14 @@ export const SANDBOX_PINNED_MUTATION_PYTHON = [
|
||||
" src_stat = os.lstat(src_basename, dir_fd=src_parent_fd)",
|
||||
" if stat.S_ISDIR(src_stat.st_mode) and not stat.S_ISLNK(src_stat.st_mode):",
|
||||
" os.mkdir(dst_basename, stat.S_IMODE(src_stat.st_mode) or 0o755, dir_fd=dst_parent_fd)",
|
||||
" copied_children = []",
|
||||
" src_dir_fd = None",
|
||||
" dst_dir_fd = None",
|
||||
" try:",
|
||||
" src_dir_fd = open_dir(src_basename, dir_fd=src_parent_fd)",
|
||||
" dst_dir_fd = open_dir(dst_basename, dir_fd=dst_parent_fd)",
|
||||
" for child in os.listdir(src_dir_fd):",
|
||||
" copy_entry(src_dir_fd, child, dst_dir_fd, child)",
|
||||
" copied_children.append((child, copy_entry(src_dir_fd, child, dst_dir_fd, child)))",
|
||||
" except Exception:",
|
||||
" if dst_dir_fd is not None:",
|
||||
" os.close(dst_dir_fd)",
|
||||
@@ -183,11 +184,11 @@ export const SANDBOX_PINNED_MUTATION_PYTHON = [
|
||||
" os.close(src_dir_fd)",
|
||||
" if dst_dir_fd is not None:",
|
||||
" os.close(dst_dir_fd)",
|
||||
" return",
|
||||
" return ('dir', copied_children)",
|
||||
" if stat.S_ISLNK(src_stat.st_mode):",
|
||||
" link_target = os.readlink(src_basename, dir_fd=src_parent_fd)",
|
||||
" os.symlink(link_target, dst_basename, dir_fd=dst_parent_fd)",
|
||||
" return",
|
||||
" return ('leaf', None)",
|
||||
" src_fd = os.open(src_basename, READ_FLAGS, dir_fd=src_parent_fd)",
|
||||
" dst_fd = None",
|
||||
" try:",
|
||||
@@ -211,6 +212,20 @@ export const SANDBOX_PINNED_MUTATION_PYTHON = [
|
||||
" if dst_fd is not None:",
|
||||
" os.close(dst_fd)",
|
||||
" os.close(src_fd)",
|
||||
" return ('leaf', None)",
|
||||
"",
|
||||
"def remove_copied_entry(parent_fd, basename, manifest):",
|
||||
" kind, children = manifest",
|
||||
" if kind != 'dir':",
|
||||
" os.unlink(basename, dir_fd=parent_fd)",
|
||||
" return",
|
||||
" dir_fd = open_dir(basename, dir_fd=parent_fd)",
|
||||
" try:",
|
||||
" for child, child_manifest in children:",
|
||||
" remove_copied_entry(dir_fd, child, child_manifest)",
|
||||
" finally:",
|
||||
" os.close(dir_fd)",
|
||||
" os.rmdir(basename, dir_fd=parent_fd)",
|
||||
"",
|
||||
"def move_entry(src_parent_fd, src_basename, dst_parent_fd, dst_basename):",
|
||||
" try:",
|
||||
@@ -224,13 +239,14 @@ export const SANDBOX_PINNED_MUTATION_PYTHON = [
|
||||
" src_stat = os.lstat(src_basename, dir_fd=src_parent_fd)",
|
||||
" if stat.S_ISDIR(src_stat.st_mode) and not stat.S_ISLNK(src_stat.st_mode):",
|
||||
" temp_dir_name = create_temp_dir(dst_parent_fd, dst_basename, stat.S_IMODE(src_stat.st_mode) or 0o755)",
|
||||
" copied_children = []",
|
||||
" temp_dir_fd = None",
|
||||
" src_dir_fd = None",
|
||||
" try:",
|
||||
" temp_dir_fd = open_dir(temp_dir_name, dir_fd=dst_parent_fd)",
|
||||
" src_dir_fd = open_dir(src_basename, dir_fd=src_parent_fd)",
|
||||
" for child in os.listdir(src_dir_fd):",
|
||||
" copy_entry(src_dir_fd, child, temp_dir_fd, child)",
|
||||
" copied_children.append((child, copy_entry(src_dir_fd, child, temp_dir_fd, child)))",
|
||||
" os.close(src_dir_fd)",
|
||||
" src_dir_fd = None",
|
||||
" os.close(temp_dir_fd)",
|
||||
@@ -246,7 +262,7 @@ export const SANDBOX_PINNED_MUTATION_PYTHON = [
|
||||
" except FileNotFoundError:",
|
||||
" pass",
|
||||
" raise",
|
||||
" remove_tree(src_parent_fd, src_basename)",
|
||||
" remove_copied_entry(src_parent_fd, src_basename, ('dir', copied_children))",
|
||||
" os.fsync(dst_parent_fd)",
|
||||
" os.fsync(src_parent_fd)",
|
||||
" return",
|
||||
|
||||
Reference in New Issue
Block a user