diff options
| -rw-r--r-- | bench/copyfile/node.mitata.mjs | 51 | ||||
| m--------- | src/bun.js/WebKit | 0 | ||||
| -rw-r--r-- | src/bun.js/node/node_fs.zig | 92 | ||||
| -rw-r--r-- | src/bun.js/node/syscall.zig | 2 | 
4 files changed, 127 insertions, 18 deletions
| diff --git a/bench/copyfile/node.mitata.mjs b/bench/copyfile/node.mitata.mjs index 93833cfcf..aa77245e1 100644 --- a/bench/copyfile/node.mitata.mjs +++ b/bench/copyfile/node.mitata.mjs @@ -1,23 +1,40 @@ -import { copyFileSync, writeFileSync } from "node:fs"; +import { copyFileSync, writeFileSync, readFileSync, statSync } from "node:fs";  import { bench, run } from "mitata"; -const size = parseInt(process.env.FILE_SIZE, 10) || 1024 * 16; -const rand = new Float64Array(size); -for (let i = 0; i < size; i++) { -  rand[i] = Math.random(); +function runner(ready) { +  for (let size of [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000]) { +    const rand = new Int32Array(size); +    for (let i = 0; i < size; i++) { +      rand[i] = (Math.random() * 1024 * 1024) | 0; +    } +    const dest = `/tmp/fs-test-copy-file-${( +      (Math.random() * 10000000 + 100) | +      0 +    ).toString(32)}`; +    const src = `/tmp/fs-test-copy-file-${( +      (Math.random() * 10000000 + 100) | +      0 +    ).toString(32)}`; +    writeFileSync(src, Buffer.from(rand.buffer), { encoding: "buffer" }); +    const { size: fileSize } = statSync(src); +    if (fileSize !== rand.byteLength) { +      throw new Error("size mismatch"); +    } +    ready(src, dest, new Uint8Array(rand.buffer)); +  }  } -const dest = `/tmp/fs-test-copy-file-${(Math.random() * 100000 + 100).toString( -  32 -)}`; -const src = `/tmp/fs-test-copy-file-${(Math.random() * 100000 + 100).toString( -  32 -)}`; -writeFileSync(src, new Buffer(rand.buffer)); +runner((src, dest, rand) => +  bench(`copyFileSync(${rand.buffer.byteLength} bytes)`, () => { +    copyFileSync(src, dest); +    // const output = readFileSync(dest).buffer; -const srcBuf = new TextEncoder().encode(src); -const destBuf = new TextEncoder().encode(dest); -bench(`copyFileSync(${rand.buffer.byteLength} bytes)`, () => -  copyFileSync(srcBuf, destBuf) +    // for (let i = 0; i < output.length; i++) { +    //   if (output[i] !== rand[i]) { +    //     throw new Error( +    //       "Files are not equal" + " " + output[i] + " " + rand[i] + " " + i +    //     ); +    //   } +    // } +  })  ); -  await run(); diff --git a/src/bun.js/WebKit b/src/bun.js/WebKit -Subproject 4d6ee41032866e63aa43ba007616c632ed1c90a +Subproject 7d9e2ffa4365e676a4aa96a9941154a68e54f0f diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index 440527e8f..af6e95d26 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -2419,6 +2419,98 @@ pub const NodeFS = struct {                      if (args.mode.isForceClone()) {                          // https://www.manpagez.com/man/2/clonefile/                          return ret.errnoSysP(C.clonefile(src, dest, 0), .clonefile, src) orelse ret.success; +                    } else { +                        const stat_ = switch (Syscall.stat(src)) { +                            .result => |result| result, +                            .err => |err| return Maybe(Return.CopyFile){ .err = err.withPath(src) }, +                        }; + +                        if (!os.S.ISREG(stat_.mode)) { +                            return Maybe(Return.CopyFile){ .err = .{ .errno = @enumToInt(C.SystemErrno.ENOTSUP) } }; +                        } + +                        if (stat_.size > 128 * 1024) { +                            if (!args.mode.shouldntOverwrite()) { +                                // clonefile() will fail if it already exists +                                _ = Syscall.unlink(dest); +                            } + +                            if (ret.errnoSysP(C.clonefile(src, dest, 0), .clonefile, src) == null) { +                                _ = C.chmod(dest, stat_.mode); +                                return ret.success; +                            } +                        } else { +                            const src_fd = switch (Syscall.open(src, std.os.O.RDONLY, 0644)) { +                                .result => |result| result, +                                .err => |err| return .{ .err = err.withPath(args.src.slice()) }, +                            }; +                            defer { +                                _ = Syscall.close(src_fd); +                            } + +                            var flags: Mode = std.os.O.CREAT | std.os.O.WRONLY; +                            var wrote: usize = 0; +                            if (args.mode.shouldntOverwrite()) { +                                flags |= std.os.O.EXCL; +                            } + +                            const dest_fd = switch (Syscall.open(dest, flags, JSC.Node.default_permission)) { +                                .result => |result| result, +                                .err => |err| return Maybe(Return.CopyFile){ .err = err }, +                            }; +                            defer { +                                _ = std.c.ftruncate(dest_fd, @intCast(std.c.off_t, @truncate(u63, wrote))); + +                                _ = Syscall.close(dest_fd); +                            } + +                            var buf: [16384]u8 = undefined; +                            var remain = @intCast(u64, @maximum(stat_.size, 0)); +                            toplevel: while (remain > 0) { +                                const amt = switch (Syscall.read(src_fd, buf[0..@minimum(buf.len, remain)])) { +                                    .result => |result| result, +                                    .err => |err| return Maybe(Return.CopyFile){ .err = err.withPath(src) }, +                                }; +                                if (amt == 0) { +                                    break :toplevel; +                                } +                                wrote += amt; +                                remain -|= amt; + +                                var slice = buf[0..amt]; +                                while (slice.len > 0) { +                                    const written = switch (Syscall.write(dest_fd, slice)) { +                                        .result => |result| result, +                                        .err => |err| return Maybe(Return.CopyFile){ .err = err.withPath(dest) }, +                                    }; +                                    if (written == 0) break :toplevel; +                                    slice = slice[written..]; +                                } +                            } else { +                                outer: while (true) { +                                    const amt = switch (Syscall.read(src_fd, &buf)) { +                                        .result => |result| result, +                                        .err => |err| return Maybe(Return.CopyFile){ .err = err.withPath(src) }, +                                    }; +                                    if (amt == 0) { +                                        break; +                                    } +                                    wrote += amt; + +                                    var slice = buf[0..amt]; +                                    while (slice.len > 0) { +                                        const written = switch (Syscall.write(dest_fd, slice)) { +                                            .result => |result| result, +                                            .err => |err| return Maybe(Return.CopyFile){ .err = err.withPath(dest) }, +                                        }; +                                        slice = slice[written..]; +                                        if (written == 0) break :outer; +                                    } +                                } +                            } +                            _ = C.fchmod(dest_fd, stat_.mode); +                            return ret.success; +                        }                      }                      var mode: Mode = C.darwin.COPYFILE_ACL | C.darwin.COPYFILE_DATA; diff --git a/src/bun.js/node/syscall.zig b/src/bun.js/node/syscall.zig index 4378a4762..1f74753d2 100644 --- a/src/bun.js/node/syscall.zig +++ b/src/bun.js/node/syscall.zig @@ -419,7 +419,7 @@ pub fn fcopyfile(fd_in: std.os.fd_t, fd_out: std.os.fd_t, flags: u32) Maybe(void  pub fn unlink(from: [:0]const u8) Maybe(void) {      while (true) { -        if (Maybe(void).errno(sys.unlink(from), .unlink)) |err| { +        if (Maybe(void).errnoSys(sys.unlink(from), .unlink)) |err| {              if (err.getErrno() == .INTR) continue;              return err;          } | 
