mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
fix(runtime): fs.cp edge cases (#4439)
* yippee * enable cpSync tests * much better * that doesnt actually do anything * lose
This commit is contained in:
@@ -564,6 +564,11 @@ pub const AsyncCpTask = struct {
|
||||
}
|
||||
|
||||
this.result = result;
|
||||
|
||||
if (this.result == .err) {
|
||||
this.result.err.path = bun.default_allocator.dupe(u8, this.result.err.path) catch "";
|
||||
}
|
||||
|
||||
this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread));
|
||||
}
|
||||
|
||||
@@ -3584,7 +3589,7 @@ pub const NodeFS = struct {
|
||||
|
||||
const dest_fd = switch (Syscall.open(dest, flags, JSC.Node.default_permission)) {
|
||||
.result => |result| result,
|
||||
.err => |err| return Maybe(Return.CopyFile){ .err = err },
|
||||
.err => |err| return Maybe(Return.CopyFile){ .err = err.withPath(args.dest.slice()) },
|
||||
};
|
||||
defer {
|
||||
_ = std.c.ftruncate(dest_fd, @as(std.c.off_t, @intCast(@as(u63, @truncate(wrote)))));
|
||||
@@ -5392,11 +5397,10 @@ pub const NodeFS = struct {
|
||||
.ACCES,
|
||||
.NAMETOOLONG,
|
||||
.ROFS,
|
||||
.NOENT,
|
||||
.PERM,
|
||||
.INVAL,
|
||||
=> {
|
||||
@memcpy(this.sync_error_buf[0..src.len], dest);
|
||||
@memcpy(this.sync_error_buf[0..src.len], src);
|
||||
return .{ .err = err.err.withPath(this.sync_error_buf[0..src.len]) };
|
||||
},
|
||||
// Other errors may be due to clonefile() not being supported
|
||||
@@ -5792,11 +5796,10 @@ pub const NodeFS = struct {
|
||||
.ACCES,
|
||||
.NAMETOOLONG,
|
||||
.ROFS,
|
||||
.NOENT,
|
||||
.PERM,
|
||||
.INVAL,
|
||||
=> {
|
||||
@memcpy(this.sync_error_buf[0..src.len], dest);
|
||||
@memcpy(this.sync_error_buf[0..src.len], src);
|
||||
task.finishConcurrently(.{ .err = err.err.withPath(this.sync_error_buf[0..src.len]) });
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import { describe, test, expect, jest } from "bun:test";
|
||||
import { tempDirWithFiles } from "harness";
|
||||
|
||||
const impls = [
|
||||
// ["cpSync", fs.cpSync],
|
||||
["cpSync", fs.cpSync],
|
||||
["cp", fs.promises.cp],
|
||||
] as const;
|
||||
|
||||
@@ -40,7 +40,9 @@ for (const [name, copy] of impls) {
|
||||
"from/a.txt": "a",
|
||||
});
|
||||
|
||||
await copyShouldThrow(basename + "/from", basename + "/result");
|
||||
const e = await copyShouldThrow(basename + "/from", basename + "/result");
|
||||
expect(e.code).toBe("EISDIR");
|
||||
expect(e.path).toBe(basename + "/from");
|
||||
});
|
||||
|
||||
test("recursive directory structure - no destination", async () => {
|
||||
@@ -129,7 +131,12 @@ for (const [name, copy] of impls) {
|
||||
"result/a.txt": "win",
|
||||
});
|
||||
|
||||
await copyShouldThrow(basename + "/from/a.txt", basename + "/result/a.txt", { force: false, errorOnExist: true });
|
||||
const e = await copyShouldThrow(basename + "/from/a.txt", basename + "/result/a.txt", {
|
||||
force: false,
|
||||
errorOnExist: true,
|
||||
});
|
||||
expect(e.code).toBe("EEXIST");
|
||||
expect(e.path).toBe(basename + "/result/a.txt");
|
||||
|
||||
assertContent(basename + "/result/a.txt", "win");
|
||||
});
|
||||
@@ -251,5 +258,31 @@ for (const [name, copy] of impls) {
|
||||
[basename + "/from/b.txt", basename + "/result/b.txt"],
|
||||
]);
|
||||
});
|
||||
|
||||
test("trailing slash", async () => {
|
||||
const basename = tempDirWithFiles("cp", {
|
||||
"from/a.txt": "a",
|
||||
"from/b.txt": "b",
|
||||
});
|
||||
|
||||
await copy(basename + "/from/", basename + "/result/", { recursive: true });
|
||||
|
||||
assertContent(basename + "/result/a.txt", "a");
|
||||
assertContent(basename + "/result/b.txt", "b");
|
||||
});
|
||||
|
||||
test("copy directory will ensure directory exists", async () => {
|
||||
const basename = tempDirWithFiles("cp", {
|
||||
"from/a.txt": "a",
|
||||
"from/b.txt": "b",
|
||||
});
|
||||
|
||||
fs.mkdirSync(basename + "/result/");
|
||||
|
||||
await copy(basename + "/from/", basename + "/hello/world/", { recursive: true });
|
||||
|
||||
assertContent(basename + "/hello/world/a.txt", "a");
|
||||
assertContent(basename + "/hello/world/b.txt", "b");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user