diff --git a/lib/std/Io/File/Atomic.zig b/lib/std/Io/File/Atomic.zig index 595aa2b08b5d9075960eed1e9c020560e66657c6..1efacf94061f35a2ba59e455868a629337e389b8 100644 --- a/lib/std/Io/File/Atomic.zig +++ b/lib/std/Io/File/Atomic.zig @@ -37,7 +37,7 @@ pub fn deinit(af: *Atomic, io: Io) void { af.* = undefined; } -pub const LinkError = Dir.HardLinkError || Dir.RenamePreserveError; +pub const LinkError = File.HardLinkError || Dir.RenamePreserveError; /// Atomically materializes the file into place, failing with /// `error.PathAlreadyExists` if something already exists there. diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index fa5d425ebc3e2702f95e440a00af4642aa1a5e9e..6547e39c50c78f96686c01bc2a0822e6e65eabe0 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -3525,7 +3525,7 @@ fn dirCreateFileAtomic( if (dest_dirname) |dirname| { // This has a nice side effect of preemptively triggering EISDIR or // ENOENT, avoiding the ambiguity below. - dir.createDirPath(t_io, dirname) catch |err| switch (err) { + if (options.make_path) dir.createDirPath(t_io, dirname) catch |err| switch (err) { // None of these make sense in this context. error.IsDir, error.Streaming, @@ -5254,7 +5254,16 @@ fn fileHardLink( else posix.AT.EMPTY_PATH; - return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags); + return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags) catch |err| switch (err) { + error.FileNotFound => { + if (options.follow_symlinks) return error.FileNotFound; + var proc_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; + const proc_path = std.fmt.bufPrintSentinel(&proc_buf, "/proc/self/fd/{d}", .{file.handle}, 0) catch + unreachable; + return linkat(posix.AT.FDCWD, proc_path, new_dir.handle, new_sub_path_posix, posix.AT.SYMLINK_FOLLOW); + }, + else => |e| return e, + }; } fn linkat(