aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-04 15:35:08 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-04 15:35:08 -0700
commite8dab9bfcf4b7822253eaf290cf2f72291b39167 (patch)
tree815f39bcf9e7591b0076a87bbcaa981bd812a68c
parentdc3eee44a928239524133177740addcb14b1b0a4 (diff)
downloadbun-e8dab9bfcf4b7822253eaf290cf2f72291b39167.tar.gz
bun-e8dab9bfcf4b7822253eaf290cf2f72291b39167.tar.zst
bun-e8dab9bfcf4b7822253eaf290cf2f72291b39167.zip
Fix moving files across mount points
-rw-r--r--src/bundler.zig2
-rw-r--r--src/c.zig28
2 files changed, 29 insertions, 1 deletions
diff --git a/src/bundler.zig b/src/bundler.zig
index d1b530c82..472b8bd9f 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -1112,7 +1112,7 @@ pub const Bundler = struct {
// chmod 777
0000010 | 0000100 | 0000001 | 0001000 | 0000040 | 0000004 | 0000002 | 0000400 | 0000200 | 0000020,
);
- try std.os.renameatZ(tmpdir.fd, tmpname, top_dir.fd, destination);
+ try C.moveFileZ(tmpdir.fd, tmpname, top_dir.fd, destination);
// Print any errors at the end
// try this.log.print(Output.errorWriter());
return javascript_bundle_container;
diff --git a/src/c.zig b/src/c.zig
index 967d1dea6..9e07f3082 100644
--- a/src/c.zig
+++ b/src/c.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+const Enviroment = @import("./env.zig");
pub usingnamespace switch (std.Target.current.os.tag) {
.macos => @import("./darwin_c.zig"),
@@ -89,3 +90,30 @@ pub fn lstat_absolute(path: [:0]const u8) StatError!Stat {
.ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
};
}
+
+// renameatZ fails when renaming across mount points
+// we assume that this is relatively uncommon
+pub fn moveFileZ(from_dir: std.os.fd_t, filename: [*:0]const u8, to_dir: std.os.fd_t, destination: [*:0]const u8) !void {
+ std.os.renameatZ(from_dir, filename, to_dir, destination) catch |err| {
+ switch (err) {
+ error.RenameAcrossMountPoints => {
+ try moveFileZSlow(from_dir, filename, to_dir, destination);
+ },
+ else => {
+ return err;
+ },
+ }
+ };
+}
+
+// On Linux, this will be fast because sendfile() supports copying between two file descriptors on disk
+// On macOS & BSDs, this will be slow because it will attempt to copy with sendfile, fail, and then fallback to a copy loop
+pub fn moveFileZSlow(from_dir: std.os.fd_t, filename: [*:0]const u8, to_dir: std.os.fd_t, destination: [*:0]const u8) !void {
+ const flags = std.os.O_RDWR;
+ const in_handle = try std.os.openatZ(from_dir, filename, flags, 0777);
+ defer std.os.close(in_handle);
+ const out_handle = try std.os.openatZ(to_dir, filename, flags | std.os.O_CREAT, 0777);
+ defer std.os.close(out_handle);
+ const written = try std.os.sendfile(out_handle, in_handle, 0, 0, &[_]std.c.iovec_const{}, &[_]std.c.iovec_const{}, 0);
+ try std.os.ftruncate(out_handle, written);
+}