From f2a3ac7c0534a74ee544fdf6ef9d2176a8d62389 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 12:49:14 -0700 Subject: [PATCH] std.fs.File: delete writeFileAll and friends please use File.Writer for these use cases also breaking API changes to std.fs.AtomicFile --- lib/std/Build/Step/Run.zig | 19 ++- lib/std/fs/AtomicFile.zig | 98 ++++++++-------- lib/std/fs/Dir.zig | 180 ++++++++++++----------------- lib/std/fs/File.zig | 107 ----------------- lib/std/fs/test.zig | 39 +++---- src/Builtin.zig | 4 +- src/Compilation.zig | 230 ++++++++++++++++++------------------- src/fmt.zig | 4 +- src/link/MachO.zig | 1 - src/main.zig | 4 +- 10 files changed, 272 insertions(+), 414 deletions(-) diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index e35b602e06..414f7ccff2 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -169,7 +169,7 @@ pub const Output = struct { pub fn create(owner: *std.Build, name: []const u8) *Run { const run = owner.allocator.create(Run) catch @panic("OOM"); run.* = .{ - .step = Step.init(.{ + .step = .init(.{ .id = base_id, .name = name, .owner = owner, @@ -1769,13 +1769,22 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult { child.stdin = null; }, .lazy_path => |lazy_path| { - const path = lazy_path.getPath2(b, &run.step); - const file = b.build_root.handle.openFile(path, .{}) catch |err| { + const path = lazy_path.getPath3(b, &run.step); + const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| { return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)}); }; defer file.close(); - child.stdin.?.writeFileAll(file, .{}) catch |err| { - return run.step.fail("unable to write file to stdin: {s}", .{@errorName(err)}); + // TODO https://github.com/ziglang/zig/issues/23955 + var buffer: [1024]u8 = undefined; + var file_reader = file.reader(&buffer); + var stdin_writer = child.stdin.?.writer(&.{}); + _ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) { + error.ReadFailed => return run.step.fail("failed to read from {f}: {t}", .{ + path, file_reader.err.?, + }), + error.WriteFailed => return run.step.fail("failed to write to stdin: {t}", .{ + stdin_writer.err.?, + }), }; child.stdin.?.close(); child.stdin = null; diff --git a/lib/std/fs/AtomicFile.zig b/lib/std/fs/AtomicFile.zig index 17a17f8993..96793aec72 100644 --- a/lib/std/fs/AtomicFile.zig +++ b/lib/std/fs/AtomicFile.zig @@ -1,6 +1,13 @@ -file: File, -// TODO either replace this with rand_buf or use []u16 on Windows -tmp_path_buf: [tmp_path_len:0]u8, +const AtomicFile = @This(); +const std = @import("../std.zig"); +const File = std.fs.File; +const Dir = std.fs.Dir; +const fs = std.fs; +const assert = std.debug.assert; +const posix = std.posix; + +file_writer: File.Writer, +random_integer: u64, dest_basename: []const u8, file_open: bool, file_exists: bool, @@ -9,35 +16,24 @@ dir: Dir, pub const InitError = File.OpenError; -pub const random_bytes_len = 12; -const tmp_path_len = fs.base64_encoder.calcSize(random_bytes_len); - /// Note that the `Dir.atomicFile` API may be more handy than this lower-level function. pub fn init( dest_basename: []const u8, mode: File.Mode, dir: Dir, close_dir_on_deinit: bool, + write_buffer: []u8, ) InitError!AtomicFile { - var rand_buf: [random_bytes_len]u8 = undefined; - var tmp_path_buf: [tmp_path_len:0]u8 = undefined; - while (true) { - std.crypto.random.bytes(rand_buf[0..]); - const tmp_path = fs.base64_encoder.encode(&tmp_path_buf, &rand_buf); - tmp_path_buf[tmp_path.len] = 0; - - const file = dir.createFile( - tmp_path, - .{ .mode = mode, .exclusive = true }, - ) catch |err| switch (err) { + const random_integer = std.crypto.random.int(u64); + const tmp_sub_path = std.fmt.hex(random_integer); + const file = dir.createFile(&tmp_sub_path, .{ .mode = mode, .exclusive = true }) catch |err| switch (err) { error.PathAlreadyExists => continue, else => |e| return e, }; - - return AtomicFile{ - .file = file, - .tmp_path_buf = tmp_path_buf, + return .{ + .file_writer = file.writer(write_buffer), + .random_integer = random_integer, .dest_basename = dest_basename, .file_open = true, .file_exists = true, @@ -48,41 +44,51 @@ pub fn init( } /// Always call deinit, even after a successful finish(). -pub fn deinit(self: *AtomicFile) void { - if (self.file_open) { - self.file.close(); - self.file_open = false; +pub fn deinit(af: *AtomicFile) void { + if (af.file_open) { + af.file_writer.file.close(); + af.file_open = false; } - if (self.file_exists) { - self.dir.deleteFile(&self.tmp_path_buf) catch {}; - self.file_exists = false; + if (af.file_exists) { + const tmp_sub_path = std.fmt.hex(af.random_integer); + af.dir.deleteFile(&tmp_sub_path) catch {}; + af.file_exists = false; } - if (self.close_dir_on_deinit) { - self.dir.close(); + if (af.close_dir_on_deinit) { + af.dir.close(); } - self.* = undefined; + af.* = undefined; } -pub const FinishError = posix.RenameError; +pub const FlushError = File.WriteError; + +pub fn flush(af: *AtomicFile) FlushError!void { + af.file_writer.interface.flush() catch |err| switch (err) { + error.WriteFailed => return af.file_writer.err.?, + }; +} + +pub const RenameIntoPlaceError = posix.RenameError; /// On Windows, this function introduces a period of time where some file /// system operations on the destination file will result in /// `error.AccessDenied`, including rename operations (such as the one used in /// this function). -pub fn finish(self: *AtomicFile) FinishError!void { - assert(self.file_exists); - if (self.file_open) { - self.file.close(); - self.file_open = false; +pub fn renameIntoPlace(af: *AtomicFile) RenameIntoPlaceError!void { + assert(af.file_exists); + if (af.file_open) { + af.file_writer.file.close(); + af.file_open = false; } - try posix.renameat(self.dir.fd, self.tmp_path_buf[0..], self.dir.fd, self.dest_basename); - self.file_exists = false; + const tmp_sub_path = std.fmt.hex(af.random_integer); + try posix.renameat(af.dir.fd, &tmp_sub_path, af.dir.fd, af.dest_basename); + af.file_exists = false; } -const AtomicFile = @This(); -const std = @import("../std.zig"); -const File = std.fs.File; -const Dir = std.fs.Dir; -const fs = std.fs; -const assert = std.debug.assert; -const posix = std.posix; +pub const FinishError = FlushError || RenameIntoPlaceError; + +/// Combination of `flush` followed by `renameIntoPlace`. +pub fn finish(af: *AtomicFile) FinishError!void { + try af.flush(); + try af.renameIntoPlace(); +} diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig index 27d97a00cb..16418d216f 100644 --- a/lib/std/fs/Dir.zig +++ b/lib/std/fs/Dir.zig @@ -1,3 +1,20 @@ +const Dir = @This(); +const builtin = @import("builtin"); +const std = @import("../std.zig"); +const File = std.fs.File; +const AtomicFile = std.fs.AtomicFile; +const base64_encoder = fs.base64_encoder; +const posix = std.posix; +const mem = std.mem; +const path = fs.path; +const fs = std.fs; +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const linux = std.os.linux; +const windows = std.os.windows; +const native_os = builtin.os.tag; +const have_flock = @TypeOf(posix.system.flock) != void; + fd: Handle, pub const Handle = posix.fd_t; @@ -1862,9 +1879,10 @@ pub fn symLinkW( /// Same as `symLink`, except tries to create the symbolic link until it /// succeeds or encounters an error other than `error.PathAlreadyExists`. -/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). -/// On WASI, both paths should be encoded as valid UTF-8. -/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. +/// +/// * On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). +/// * On WASI, both paths should be encoded as valid UTF-8. +/// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding. pub fn atomicSymLink( dir: Dir, target_path: []const u8, @@ -1880,9 +1898,8 @@ pub fn atomicSymLink( const dirname = path.dirname(sym_link_path) orelse "."; - var rand_buf: [AtomicFile.random_bytes_len]u8 = undefined; - - const temp_path_len = dirname.len + 1 + base64_encoder.calcSize(rand_buf.len); + const rand_len = @sizeOf(u64) * 2; + const temp_path_len = dirname.len + 1 + rand_len; var temp_path_buf: [fs.max_path_bytes]u8 = undefined; if (temp_path_len > temp_path_buf.len) return error.NameTooLong; @@ -1892,8 +1909,8 @@ pub fn atomicSymLink( const temp_path = temp_path_buf[0..temp_path_len]; while (true) { - crypto.random.bytes(rand_buf[0..]); - _ = base64_encoder.encode(temp_path[dirname.len + 1 ..], rand_buf[0..]); + const random_integer = std.crypto.random.int(u64); + temp_path[dirname.len + 1 ..][0..rand_len].* = std.fmt.hex(random_integer); if (dir.symLink(target_path, temp_path, flags)) { return dir.rename(temp_path, sym_link_path); @@ -2552,25 +2569,42 @@ pub fn updateFile( try dest_dir.makePath(dirname); } - var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode }); + var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available. + var atomic_file = try dest_dir.atomicFile(dest_path, .{ + .mode = actual_mode, + .write_buffer = &buffer, + }); defer atomic_file.deinit(); - try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); - try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); + var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size); + const dest_writer = &atomic_file.file_writer.interface; + + _ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) { + error.ReadFailed => return src_reader.err.?, + error.WriteFailed => return atomic_file.file_writer.err.?, + }; + try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime); try atomic_file.finish(); - return PrevStatus.stale; + return .stale; } pub const CopyFileError = File.OpenError || File.StatError || - AtomicFile.InitError || CopyFileRawError || AtomicFile.FinishError; + AtomicFile.InitError || AtomicFile.FinishError || + File.ReadError || File.WriteError; -/// Guaranteed to be atomic. -/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, -/// there is a possibility of power loss or application termination leaving temporary files present -/// in the same directory as dest_path. -/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). -/// On WASI, both paths should be encoded as valid UTF-8. -/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. +/// Atomically creates a new file at `dest_path` within `dest_dir` with the +/// same contents as `source_path` within `source_dir`, overwriting any already +/// existing file. +/// +/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and +/// readily available, there is a possibility of power loss or application +/// termination leaving temporary files present in the same directory as +/// dest_path. +/// +/// On Windows, both paths should be encoded as +/// [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be +/// encoded as valid UTF-8. On other platforms, both paths are an opaque +/// sequence of bytes with no particular encoding. pub fn copyFile( source_dir: Dir, source_path: []const u8, @@ -2578,79 +2612,34 @@ pub fn copyFile( dest_path: []const u8, options: CopyFileOptions, ) CopyFileError!void { - var in_file = try source_dir.openFile(source_path, .{}); - defer in_file.close(); + var file_reader: File.Reader = .init(try source_dir.openFile(source_path, .{}), &.{}); + defer file_reader.file.close(); - var size: ?u64 = null; const mode = options.override_mode orelse blk: { - const st = try in_file.stat(); - size = st.size; + const st = try file_reader.file.stat(); + file_reader.size = st.size; break :blk st.mode; }; - var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); + var buffer: [1024]u8 = undefined; // Used only when direct fd-to-fd is not available. + var atomic_file = try dest_dir.atomicFile(dest_path, .{ + .mode = mode, + .write_buffer = &buffer, + }); defer atomic_file.deinit(); - try copy_file(in_file.handle, atomic_file.file.handle, size); + _ = atomic_file.file_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) { + error.ReadFailed => return file_reader.err.?, + error.WriteFailed => return atomic_file.file_writer.err.?, + }; + try atomic_file.finish(); } -const CopyFileRawError = error{SystemResources} || posix.CopyFileRangeError || posix.SendFileError; - -// Transfer all the data between two file descriptors in the most efficient way. -// The copy starts at offset 0, the initial offsets are preserved. -// No metadata is transferred over. -fn copy_file(fd_in: posix.fd_t, fd_out: posix.fd_t, maybe_size: ?u64) CopyFileRawError!void { - if (builtin.target.os.tag.isDarwin()) { - const rc = posix.system.fcopyfile(fd_in, fd_out, null, .{ .DATA = true }); - switch (posix.errno(rc)) { - .SUCCESS => return, - .INVAL => unreachable, - .NOMEM => return error.SystemResources, - // The source file is not a directory, symbolic link, or regular file. - // Try with the fallback path before giving up. - .OPNOTSUPP => {}, - else => |err| return posix.unexpectedErrno(err), - } - } - - if (native_os == .linux) { - // Try copy_file_range first as that works at the FS level and is the - // most efficient method (if available). - var offset: u64 = 0; - cfr_loop: while (true) { - // The kernel checks the u64 value `offset+count` for overflow, use - // a 32 bit value so that the syscall won't return EINVAL except for - // impossibly large files (> 2^64-1 - 2^32-1). - const amt = try posix.copy_file_range(fd_in, offset, fd_out, offset, std.math.maxInt(u32), 0); - // Terminate as soon as we have copied size bytes or no bytes - if (maybe_size) |s| { - if (s == amt) break :cfr_loop; - } - if (amt == 0) break :cfr_loop; - offset += amt; - } - return; - } - - // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the - // fallback code will copy the contents chunk by chunk. - const empty_iovec = [0]posix.iovec_const{}; - var offset: u64 = 0; - sendfile_loop: while (true) { - const amt = try posix.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0); - // Terminate as soon as we have copied size bytes or no bytes - if (maybe_size) |s| { - if (s == amt) break :sendfile_loop; - } - if (amt == 0) break :sendfile_loop; - offset += amt; - } -} - pub const AtomicFileOptions = struct { mode: File.Mode = File.default_mode, make_path: bool = false, + write_buffer: []u8, }; /// Directly access the `.file` field, and then call `AtomicFile.finish` to @@ -2668,9 +2657,9 @@ pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) else try self.openDir(dirname, .{}); - return AtomicFile.init(fs.path.basename(dest_path), options.mode, dir, true); + return .init(fs.path.basename(dest_path), options.mode, dir, true, options.write_buffer); } else { - return AtomicFile.init(dest_path, options.mode, self, false); + return .init(dest_path, options.mode, self, false, options.write_buffer); } } @@ -2768,30 +2757,3 @@ pub fn setPermissions(self: Dir, permissions: Permissions) SetPermissionsError!v const file: File = .{ .handle = self.fd }; try file.setPermissions(permissions); } - -const Metadata = File.Metadata; -pub const MetadataError = File.MetadataError; - -/// Returns a `Metadata` struct, representing the permissions on the directory -pub fn metadata(self: Dir) MetadataError!Metadata { - const file: File = .{ .handle = self.fd }; - return try file.metadata(); -} - -const Dir = @This(); -const builtin = @import("builtin"); -const std = @import("../std.zig"); -const File = std.fs.File; -const AtomicFile = std.fs.AtomicFile; -const base64_encoder = fs.base64_encoder; -const crypto = std.crypto; -const posix = std.posix; -const mem = std.mem; -const path = fs.path; -const fs = std.fs; -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; -const linux = std.os.linux; -const windows = std.os.windows; -const native_os = builtin.os.tag; -const have_flock = @TypeOf(posix.system.flock) != void; diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 5b7e0aa570..50f2a30876 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1089,113 +1089,6 @@ pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u return total_bytes_copied; } -/// Deprecated in favor of `Writer`. -pub const WriteFileOptions = struct { - in_offset: u64 = 0, - in_len: ?u64 = null, - headers_and_trailers: []posix.iovec_const = &[0]posix.iovec_const{}, - header_count: usize = 0, -}; - -/// Deprecated in favor of `Writer`. -pub const WriteFileError = ReadError || error{EndOfStream} || WriteError; - -/// Deprecated in favor of `Writer`. -pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { - return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) { - error.Unseekable, - error.FastOpenAlreadyInProgress, - error.MessageTooBig, - error.FileDescriptorNotASocket, - error.NetworkUnreachable, - error.NetworkSubsystemFailed, - error.ConnectionRefused, - => return self.writeFileAllUnseekable(in_file, args), - else => |e| return e, - }; -} - -/// Deprecated in favor of `Writer`. -pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { - const headers = args.headers_and_trailers[0..args.header_count]; - const trailers = args.headers_and_trailers[args.header_count..]; - try self.writevAll(headers); - try in_file.deprecatedReader().skipBytes(args.in_offset, .{ .buf_size = 4096 }); - var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); - if (args.in_len) |len| { - var stream = std.io.limitedReader(in_file.deprecatedReader(), len); - try fifo.pump(stream.reader(), self.deprecatedWriter()); - } else { - try fifo.pump(in_file.deprecatedReader(), self.deprecatedWriter()); - } - try self.writevAll(trailers); -} - -/// Deprecated in favor of `Writer`. -fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix.SendFileError!void { - const count = blk: { - if (args.in_len) |l| { - if (l == 0) { - return self.writevAll(args.headers_and_trailers); - } else { - break :blk l; - } - } else { - break :blk 0; - } - }; - const headers = args.headers_and_trailers[0..args.header_count]; - const trailers = args.headers_and_trailers[args.header_count..]; - const zero_iovec = &[0]posix.iovec_const{}; - // When reading the whole file, we cannot put the trailers in the sendfile() syscall, - // because we have no way to determine whether a partial write is past the end of the file or not. - const trls = if (count == 0) zero_iovec else trailers; - const offset = args.in_offset; - const out_fd = self.handle; - const in_fd = in_file.handle; - const flags = 0; - var amt: usize = 0; - hdrs: { - var i: usize = 0; - while (i < headers.len) { - amt = try posix.sendfile(out_fd, in_fd, offset, count, headers[i..], trls, flags); - while (amt >= headers[i].len) { - amt -= headers[i].len; - i += 1; - if (i >= headers.len) break :hdrs; - } - headers[i].base += amt; - headers[i].len -= amt; - } - } - if (count == 0) { - var off: u64 = amt; - while (true) { - amt = try posix.sendfile(out_fd, in_fd, offset + off, 0, zero_iovec, zero_iovec, flags); - if (amt == 0) break; - off += amt; - } - } else { - var off: u64 = amt; - while (off < count) { - amt = try posix.sendfile(out_fd, in_fd, offset + off, count - off, zero_iovec, trailers, flags); - off += amt; - } - amt = @as(usize, @intCast(off - count)); - } - var i: usize = 0; - while (i < trailers.len) { - while (amt >= trailers[i].len) { - amt -= trailers[i].len; - i += 1; - if (i >= trailers.len) return; - } - trailers[i].base += amt; - trailers[i].len -= amt; - amt = try posix.writev(self.handle, trailers[i..]); - } -} - /// Deprecated in favor of `Reader`. pub const DeprecatedReader = io.GenericReader(File, ReadError, read); diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 50cbccf270..9fe2551738 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -1499,32 +1499,18 @@ test "sendfile" { const header2 = "second header\n"; const trailer1 = "trailer1\n"; const trailer2 = "second trailer\n"; - var hdtr = [_]posix.iovec_const{ - .{ - .base = header1, - .len = header1.len, - }, - .{ - .base = header2, - .len = header2.len, - }, - .{ - .base = trailer1, - .len = trailer1.len, - }, - .{ - .base = trailer2, - .len = trailer2.len, - }, - }; + var headers: [2][]const u8 = .{ header1, header2 }; + var trailers: [2][]const u8 = .{ trailer1, trailer2 }; var written_buf: [100]u8 = undefined; - try dest_file.writeFileAll(src_file, .{ - .in_offset = 1, - .in_len = 10, - .headers_and_trailers = &hdtr, - .header_count = 2, - }); + var file_reader = src_file.reader(&.{}); + var fallback_buffer: [50]u8 = undefined; + var file_writer = dest_file.writer(&fallback_buffer); + try file_writer.interface.writeVecAll(&headers); + try file_reader.seekTo(1); + try testing.expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10))); + try file_writer.interface.writeVecAll(&trailers); + try file_writer.interface.flush(); const amt = try dest_file.preadAll(&written_buf, 0); try testing.expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]); } @@ -1595,9 +1581,10 @@ test "AtomicFile" { ; { - var af = try ctx.dir.atomicFile(test_out_file, .{}); + var buffer: [100]u8 = undefined; + var af = try ctx.dir.atomicFile(test_out_file, .{ .write_buffer = &buffer }); defer af.deinit(); - try af.file.writeAll(test_content); + try af.file_writer.interface.writeAll(test_content); try af.finish(); } const content = try ctx.dir.readFileAlloc(allocator, test_out_file, 9999); diff --git a/src/Builtin.zig b/src/Builtin.zig index b2cb603f53..b4e05a6089 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -342,9 +342,9 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void { } // `make_path` matters because the dir hasn't actually been created yet. - var af = try root_dir.atomicFile(sub_path, .{ .make_path = true }); + var af = try root_dir.atomicFile(sub_path, .{ .make_path = true, .write_buffer = &.{} }); defer af.deinit(); - try af.file.writeAll(file.source.?); + try af.file_writer.interface.writeAll(file.source.?); af.finish() catch |err| switch (err) { error.AccessDenied => switch (builtin.os.tag) { .windows => { diff --git a/src/Compilation.zig b/src/Compilation.zig index b5597017c4..649288dab2 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3382,7 +3382,7 @@ pub fn saveState(comp: *Compilation) !void { const gpa = comp.gpa; - var bufs = std.ArrayList(std.posix.iovec_const).init(gpa); + var bufs = std.ArrayList([]const u8).init(gpa); defer bufs.deinit(); var pt_headers = std.ArrayList(Header.PerThread).init(gpa); @@ -3421,50 +3421,50 @@ pub fn saveState(comp: *Compilation) !void { try bufs.ensureTotalCapacityPrecise(14 + 8 * pt_headers.items.len); addBuf(&bufs, mem.asBytes(&header)); - addBuf(&bufs, mem.sliceAsBytes(pt_headers.items)); + addBuf(&bufs, @ptrCast(pt_headers.items)); - addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.values())); + addBuf(&bufs, @ptrCast(ip.src_hash_deps.keys())); + addBuf(&bufs, @ptrCast(ip.src_hash_deps.values())); + addBuf(&bufs, @ptrCast(ip.nav_val_deps.keys())); + addBuf(&bufs, @ptrCast(ip.nav_val_deps.values())); + addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys())); + addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); + addBuf(&bufs, @ptrCast(ip.interned_deps.keys())); + addBuf(&bufs, @ptrCast(ip.interned_deps.values())); + addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); + addBuf(&bufs, @ptrCast(ip.zon_file_deps.values())); + addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); + addBuf(&bufs, @ptrCast(ip.embed_file_deps.values())); + addBuf(&bufs, @ptrCast(ip.namespace_deps.keys())); + addBuf(&bufs, @ptrCast(ip.namespace_deps.values())); + addBuf(&bufs, @ptrCast(ip.namespace_name_deps.keys())); + addBuf(&bufs, @ptrCast(ip.namespace_name_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.dep_entries.items)); - addBuf(&bufs, mem.sliceAsBytes(ip.free_dep_entries.items)); + addBuf(&bufs, @ptrCast(ip.first_dependency.keys())); + addBuf(&bufs, @ptrCast(ip.first_dependency.values())); + addBuf(&bufs, @ptrCast(ip.dep_entries.items)); + addBuf(&bufs, @ptrCast(ip.free_dep_entries.items)); for (ip.locals, pt_headers.items) |*local, pt_header| { if (pt_header.intern_pool.limbs_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); + addBuf(&bufs, @ptrCast(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); } if (pt_header.intern_pool.extra_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); + addBuf(&bufs, @ptrCast(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); } if (pt_header.intern_pool.items_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); + addBuf(&bufs, @ptrCast(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); + addBuf(&bufs, @ptrCast(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); } if (pt_header.intern_pool.string_bytes_len > 0) { addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]); } if (pt_header.intern_pool.tracked_insts_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); + addBuf(&bufs, @ptrCast(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); } if (pt_header.intern_pool.files_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); + addBuf(&bufs, @ptrCast(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); + addBuf(&bufs, @ptrCast(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); } } @@ -3482,95 +3482,95 @@ pub fn saveState(comp: *Compilation) !void { try bufs.ensureUnusedCapacity(85); addBuf(&bufs, wasm.string_bytes.items); // TODO make it well-defined memory layout - //addBuf(&bufs, mem.sliceAsBytes(wasm.objects.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.func_types.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_functions.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_globals.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_tables.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_memories.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.tag))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.offset))); + //addBuf(&bufs, @ptrCast(wasm.objects.items)); + addBuf(&bufs, @ptrCast(wasm.func_types.keys())); + addBuf(&bufs, @ptrCast(wasm.object_function_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_function_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_functions.items)); + addBuf(&bufs, @ptrCast(wasm.object_global_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_global_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_globals.items)); + addBuf(&bufs, @ptrCast(wasm.object_table_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_table_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_tables.items)); + addBuf(&bufs, @ptrCast(wasm.object_memory_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_memory_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_memories.items)); + addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.tag))); + addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.offset))); // TODO handle the union safety field - //addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.pointee))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.addend))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_init_funcs.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_segments.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_datas.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.values())); + //addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.pointee))); + addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.addend))); + addBuf(&bufs, @ptrCast(wasm.object_init_funcs.items)); + addBuf(&bufs, @ptrCast(wasm.object_data_segments.items)); + addBuf(&bufs, @ptrCast(wasm.object_datas.items)); + addBuf(&bufs, @ptrCast(wasm.object_data_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_data_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_custom_segments.keys())); + addBuf(&bufs, @ptrCast(wasm.object_custom_segments.values())); // TODO make it well-defined memory layout - // addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdats.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.kind))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.index))); - addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.tag))); - addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.offset))); + // addBuf(&bufs, @ptrCast(wasm.object_comdats.items)); + addBuf(&bufs, @ptrCast(wasm.object_relocations_table.keys())); + addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values())); + addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind))); + addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index))); + addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag))); + addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset))); // TODO handle the union safety field - //addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.pointee))); - addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.addend))); - addBuf(&bufs, mem.sliceAsBytes(wasm.uav_fixups.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.nav_fixups.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.func_table_fixups.items)); + //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee))); + addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend))); + addBuf(&bufs, @ptrCast(wasm.uav_fixups.items)); + addBuf(&bufs, @ptrCast(wasm.nav_fixups.items)); + addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items)); if (is_obj) { - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.values())); + addBuf(&bufs, @ptrCast(wasm.navs_obj.keys())); + addBuf(&bufs, @ptrCast(wasm.navs_obj.values())); + addBuf(&bufs, @ptrCast(wasm.uavs_obj.keys())); + addBuf(&bufs, @ptrCast(wasm.uavs_obj.values())); } else { - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.values())); + addBuf(&bufs, @ptrCast(wasm.navs_exe.keys())); + addBuf(&bufs, @ptrCast(wasm.navs_exe.values())); + addBuf(&bufs, @ptrCast(wasm.uavs_exe.keys())); + addBuf(&bufs, @ptrCast(wasm.uavs_exe.values())); } - addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.keys())); + addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.keys())); + addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.values())); + addBuf(&bufs, @ptrCast(wasm.zcu_funcs.keys())); // TODO handle the union safety field - // addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.missing_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.global_exports.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.functions.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.data_segments.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.globals.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.tables.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_indirect_function_set.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_import_set.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_set.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.tag))); + // addBuf(&bufs, @ptrCast(wasm.zcu_funcs.values())); + addBuf(&bufs, @ptrCast(wasm.nav_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.nav_exports.values())); + addBuf(&bufs, @ptrCast(wasm.uav_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.uav_exports.values())); + addBuf(&bufs, @ptrCast(wasm.imports.keys())); + addBuf(&bufs, @ptrCast(wasm.missing_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.function_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.function_exports.values())); + addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.values())); + addBuf(&bufs, @ptrCast(wasm.global_exports.items)); + addBuf(&bufs, @ptrCast(wasm.functions.keys())); + addBuf(&bufs, @ptrCast(wasm.function_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.function_imports.values())); + addBuf(&bufs, @ptrCast(wasm.data_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.data_imports.values())); + addBuf(&bufs, @ptrCast(wasm.data_segments.keys())); + addBuf(&bufs, @ptrCast(wasm.globals.keys())); + addBuf(&bufs, @ptrCast(wasm.global_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.global_imports.values())); + addBuf(&bufs, @ptrCast(wasm.tables.keys())); + addBuf(&bufs, @ptrCast(wasm.table_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.table_imports.values())); + addBuf(&bufs, @ptrCast(wasm.zcu_indirect_function_set.keys())); + addBuf(&bufs, @ptrCast(wasm.object_indirect_function_import_set.keys())); + addBuf(&bufs, @ptrCast(wasm.object_indirect_function_set.keys())); + addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.tag))); // TODO handle the union safety field - //addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.data))); - addBuf(&bufs, mem.sliceAsBytes(wasm.mir_extra.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.mir_locals.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_bytes.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_offs.items)); + //addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.data))); + addBuf(&bufs, @ptrCast(wasm.mir_extra.items)); + addBuf(&bufs, @ptrCast(wasm.mir_locals.items)); + addBuf(&bufs, @ptrCast(wasm.tag_name_bytes.items)); + addBuf(&bufs, @ptrCast(wasm.tag_name_offs.items)); // TODO add as header fields // entry_resolution: FunctionImport.Resolution @@ -3596,16 +3596,16 @@ pub fn saveState(comp: *Compilation) !void { // Using an atomic file prevents a crash or power failure from corrupting // the previous incremental compilation state. - var af = try lf.emit.root_dir.handle.atomicFile(basename, .{}); + var write_buffer: [1024]u8 = undefined; + var af = try lf.emit.root_dir.handle.atomicFile(basename, .{ .write_buffer = &write_buffer }); defer af.deinit(); - try af.file.pwritevAll(bufs.items, 0); + try af.file_writer.interface.writeVecAll(bufs.items); try af.finish(); } -fn addBuf(list: *std.ArrayList(std.posix.iovec_const), buf: []const u8) void { - // Even when len=0, the undefined pointer might cause EFAULT. +fn addBuf(list: *std.ArrayList([]const u8), buf: []const u8) void { if (buf.len == 0) return; - list.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len }); + list.appendAssumeCapacity(buf); } /// This function is temporally single-threaded. diff --git a/src/fmt.zig b/src/fmt.zig index 23e668d245..92ae22e4bc 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -348,10 +348,10 @@ fn fmtPathFile( try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); fmt.any_error = true; } else { - var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode }); + var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode, .write_buffer = &.{} }); defer af.deinit(); - try af.file.writeAll(fmt.out_buffer.getWritten()); + try af.file_writer.interface.writeAll(fmt.out_buffer.getWritten()); try af.finish(); try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 734b4b6a04..5b0e8520d1 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -612,7 +612,6 @@ pub fn flush( }; const emit = self.base.emit; invalidateKernelCache(emit.root_dir.handle, emit.sub_path) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, else => |e| return diags.fail("failed to invalidate kernel cache: {s}", .{@errorName(e)}), }; } diff --git a/src/main.zig b/src/main.zig index 7ad40e1a68..d3655c9d79 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4624,7 +4624,9 @@ fn cmdTranslateC( fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) }); }; defer zig_file.close(); - try fs.File.stdout().writeFileAll(zig_file, .{}); + var stdout_writer = fs.File.stdout().writer(&stdout_buffer); + var file_reader = zig_file.reader(&.{}); + _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited); return cleanExit(); } }