From f3be721785013de85faf5d0fa454a7a8bc049c0b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Feb 2025 12:22:24 -0800 Subject: [PATCH] build runner compiling --- lib/std/Build.zig | 2 +- lib/std/Build/Fuzz/WebServer.zig | 3 +- lib/std/Build/Step.zig | 2 +- lib/std/Build/Step/Options.zig | 10 +- lib/std/Target.zig | 4 +- lib/std/debug.zig | 6 +- lib/std/fmt.zig | 2 +- lib/std/fs/File.zig | 7 - lib/std/io/BufferedWriter.zig | 13 +- lib/std/io/CountingWriter.zig | 9 +- lib/std/io/Writer.zig | 13 +- lib/std/process/Child.zig | 2 +- lib/std/tar.zig | 6 +- lib/std/tar/{writer.zig => Writer.zig} | 317 ++++++++++++------------- lib/std/zig.zig | 2 +- lib/std/zig/ErrorBundle.zig | 2 +- 16 files changed, 195 insertions(+), 205 deletions(-) rename lib/std/tar/{writer.zig => Writer.zig} (65%) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 1ebd26a59f..3c2525a07f 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -2803,7 +2803,7 @@ pub fn dumpBadGetPathHelp( src_builder: *Build, asking_step: ?*Step, ) anyerror!void { - var buffered_writer = stderr.unbufferedWriter(); + var buffered_writer = stderr.writer().unbuffered(); const w = &buffered_writer; try w.print( \\getPath() was called on a GeneratedFile that wasn't built yet. diff --git a/lib/std/Build/Fuzz/WebServer.zig b/lib/std/Build/Fuzz/WebServer.zig index ab44d4e7af..d0baa61d18 100644 --- a/lib/std/Build/Fuzz/WebServer.zig +++ b/lib/std/Build/Fuzz/WebServer.zig @@ -522,7 +522,8 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { var cwd_cache: ?[]const u8 = null; - var archiver = std.tar.writer(response.writer()); + var response_writer = response.writer().unbuffered(); + var archiver: std.tar.Writer = .{ .underlying_writer = &response_writer }; for (deduped_paths) |joined_path| { var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| { diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 68dbbcdd18..4d5d8e93e5 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -287,7 +287,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T { /// For debugging purposes, prints identifying information about this Step. pub fn dump(step: *Step, file: std.fs.File) void { - var bw = file.unbufferedWriter(); + var bw = file.writer().unbuffered(); const tty_config = std.io.tty.detectConfig(file); const debug_info = std.debug.getSelfDebugInfo() catch |err| { bw.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{ diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index 7e5dc175ba..6162da9e0d 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -55,14 +55,14 @@ fn printType( switch (T) { []const []const u8 => { if (name) |payload| { - try out.print(gpa, "pub const {}: []const []const u8 = ", .{std.zig.fmtId(payload)}); + try out.print(gpa, "pub const {f}: []const []const u8 = ", .{std.zig.fmtId(payload)}); } try out.appendSlice(gpa, "&[_][]const u8{\n"); for (value) |slice| { try out.appendNTimes(gpa, ' ', indent); - try out.print(gpa, " \"{}\",\n", .{std.zig.fmtEscapes(slice)}); + try out.print(gpa, " \"{f}\",\n", .{std.zig.fmtEscapes(slice)}); } if (name != null) { @@ -75,7 +75,9 @@ fn printType( }, []const u8 => { if (name) |some| { - try out.print(gpa, "pub const {}: []const u8 = \"{}\";", .{ std.zig.fmtId(some), std.zig.fmtEscapes(value) }); + try out.print(gpa, "pub const {f}: []const u8 = \"{f}\";", .{ + std.zig.fmtId(some), std.zig.fmtEscapes(value), + }); } else { try out.print(gpa, "\"{}\",", .{std.zig.fmtEscapes(value)}); } @@ -293,7 +295,7 @@ fn printEnum( inline for (val.fields) |field| { try out.appendNTimes(gpa, ' ', indent); - try out.print(gpa, " {p} = {d},\n", .{ std.zig.fmtId(field.name), field.value }); + try out.print(gpa, " {fp} = {d},\n", .{ std.zig.fmtId(field.name), field.value }); } if (!val.is_exhaustive) { diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 18d37e6bf6..26e5cab182 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -305,8 +305,8 @@ pub const Os = struct { ver: WindowsVersion, comptime fmt_str: []const u8, _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + writer: *std.io.BufferedWriter, + ) anyerror!void { const maybe_name = std.enums.tagName(WindowsVersion, ver); if (comptime std.mem.eql(u8, fmt_str, "s")) { if (maybe_name) |name| diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7614492fed..d0e478b18a 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -212,7 +212,7 @@ pub fn unlockStdErr() void { /// in fact unbuffered and does not need to be flushed. pub fn lockStdErr2() std.io.BufferedWriter { std.Progress.lockStdErr(); - return io.getStdErr().unbufferedWriter(); + return io.getStdErr().writer().unbuffered(); } /// Print to stderr, unbuffered, and silently returning on failure. Intended @@ -1468,7 +1468,7 @@ fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopa } fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) void { - var stderr = io.getStdErr().unbufferedWriter(); + var stderr = io.getStdErr().writer().unbuffered(); _ = switch (sig) { posix.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL // x86_64 doesn't have a full 64-bit virtual address space. @@ -1564,7 +1564,7 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: } fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void { - var stderr = io.getStdErr().unbufferedWriter(); + var stderr = io.getStdErr().writer().unbuffered(); _ = switch (msg) { 0 => stderr.print("{s}\n", .{label.?}), 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index b6568ce008..7016497ff0 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -853,7 +853,7 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr /// Count the characters needed for format. pub fn count(comptime fmt: []const u8, args: anytype) u64 { var counting_writer: std.io.CountingWriter = .{ .child_writer = std.io.null_writer }; - var bw = counting_writer.unbufferedWriter(); + var bw = counting_writer.writer().unbuffered(); bw.print(fmt, args) catch unreachable; return counting_writer.bytes_written; } diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 872b9ba021..8b5f2ffc8e 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1602,13 +1602,6 @@ pub fn writer(file: File) std.io.Writer { }; } -pub fn unbufferedWriter(file: File) std.io.BufferedWriter { - return .{ - .buffer = &.{}, - .unbuffered_writer = writer(file), - }; -} - const interface = struct { /// Number of slices to store on the stack, when trying to send as many byte /// vectors through the underlying write calls as possible. diff --git a/lib/std/io/BufferedWriter.zig b/lib/std/io/BufferedWriter.zig index dfaeb3aaa3..b23e190af3 100644 --- a/lib/std/io/BufferedWriter.zig +++ b/lib/std/io/BufferedWriter.zig @@ -620,13 +620,14 @@ pub fn printValue( } if (std.meta.hasMethod(T, "format")) { - if (fmt.len == 0) { - // @deprecated() - // After 0.14.0 is tagged, uncomment this next line: - //@compileError("ambiguous format string; specify {f} to call print method, or {any} to skip it"); - return value.format(fmt, options, bw); - } else if (fmt[0] == 'f') { + if (fmt.len > 0 and fmt[0] == 'f') { return value.format(fmt[1..], options, bw); + } else { + //@deprecated(); + // After 0.14.0 is tagged, uncomment this next line: + //@compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it"); + //and then delete the `hasMethod` condition + return value.format(fmt, options, bw); } } diff --git a/lib/std/io/CountingWriter.zig b/lib/std/io/CountingWriter.zig index 21e0ac132c..fcc9fdfb62 100644 --- a/lib/std/io/CountingWriter.zig +++ b/lib/std/io/CountingWriter.zig @@ -22,13 +22,6 @@ pub fn writer(cw: *CountingWriter) Writer { }; } -pub fn unbufferedWriter(cw: *CountingWriter) std.io.BufferedWriter { - return .{ - .buffer = &.{}, - .unbuffered_writer = writer(cw), - }; -} - fn passthru_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { const cw: *CountingWriter = @alignCast(@ptrCast(context)); const n = try cw.child_writer.writeSplat(data, splat); @@ -52,7 +45,7 @@ fn passthru_writeFile( test CountingWriter { var cw: CountingWriter = .{ .child_writer = std.io.null_writer }; - var bw = cw.unbufferedWriter(); + var bw = cw.writer().unbuffered(); const bytes = "yay"; try bw.writeAll(bytes); try testing.expect(cw.bytes_written == bytes.len); diff --git a/lib/std/io/Writer.zig b/lib/std/io/Writer.zig index 24254b75d6..75a1668ac9 100644 --- a/lib/std/io/Writer.zig +++ b/lib/std/io/Writer.zig @@ -86,12 +86,6 @@ pub fn writeAll(w: Writer, bytes: []const u8) anyerror!void { while (index < bytes.len) index += try w.vtable.writeSplat(w.context, &.{bytes[index..]}, 1); } -///// Directly calls `writeAll` many times to render the formatted text. To -///// enable buffering, call `std.io.BufferedWriter.print` instead. -//pub fn unbufferedPrint(w: Writer, comptime format: []const u8, args: anytype) anyerror!void { -// return std.fmt.format(w, format, args); -//} - /// The `data` parameter is mutable because this function needs to mutate the /// fields in order to handle partial writes from `VTable.writev`. pub fn writevAll(w: Writer, data: [][]const u8) anyerror!void { @@ -106,3 +100,10 @@ pub fn writevAll(w: Writer, data: [][]const u8) anyerror!void { data[i] = data[i][n..]; } } + +pub fn unbuffered(w: Writer) std.io.BufferedWriter { + return .{ + .buffer = &.{}, + .unbuffered_writer = w, + }; +} diff --git a/lib/std/process/Child.zig b/lib/std/process/Child.zig index ef00319948..b3224525da 100644 --- a/lib/std/process/Child.zig +++ b/lib/std/process/Child.zig @@ -1004,7 +1004,7 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { fn writeIntFd(fd: i32, value: ErrInt) !void { const file: File = .{ .handle = fd }; - var bw = file.unbufferedWriter(); + var bw = file.writer().unbuffered(); bw.writeInt(u64, @intCast(value), .little) catch return error.SystemResources; } diff --git a/lib/std/tar.zig b/lib/std/tar.zig index f3aba4d381..a8b448ffea 100644 --- a/lib/std/tar.zig +++ b/lib/std/tar.zig @@ -19,7 +19,7 @@ const std = @import("std"); const assert = std.debug.assert; const testing = std.testing; -pub const writer = @import("tar/writer.zig").writer; +pub const Writer = @import("tar/Writer.zig"); /// Provide this to receive detailed error messages. /// When this is provided, some errors which would otherwise be returned @@ -604,7 +604,7 @@ fn PaxIterator(comptime ReaderType: type) type { } fn readUntil(self: *Self, delimiter: u8) ![]const u8 { - var fbs = std.io.fixedBufferStream(&self.scratch); + var fbs: std.io.FixedBufferStream = .{ .buffer = &self.scratch }; try self.reader.streamUntilDelimiter(fbs.writer(), delimiter, null); return fbs.getWritten(); } @@ -855,7 +855,7 @@ test PaxIterator { test { _ = @import("tar/test.zig"); - _ = @import("tar/writer.zig"); + _ = Writer; _ = Diagnostics; } diff --git a/lib/std/tar/writer.zig b/lib/std/tar/Writer.zig similarity index 65% rename from lib/std/tar/writer.zig rename to lib/std/tar/Writer.zig index aae368996c..76f017f2dc 100644 --- a/lib/std/tar/writer.zig +++ b/lib/std/tar/Writer.zig @@ -1,177 +1,176 @@ const std = @import("std"); const assert = std.debug.assert; const testing = std.testing; +const Writer = @This(); -pub const Writer = struct { - const block_size = @sizeOf(Header); - const empty_block: [block_size]u8 = [_]u8{0} ** block_size; +const block_size = @sizeOf(Header); +const empty_block: [block_size]u8 = [_]u8{0} ** block_size; - /// Options for writing file/dir/link. If left empty 0o664 is used for - /// file mode and current time for mtime. - pub const Options = struct { - /// File system permission mode. - mode: u32 = 0, - /// File system modification time. - mtime: u64 = 0, - }; - const Self = @This(); +/// Options for writing file/dir/link. If left empty 0o664 is used for +/// file mode and current time for mtime. +pub const Options = struct { + /// File system permission mode. + mode: u32 = 0, + /// File system modification time. + mtime: u64 = 0, +}; +const Self = @This(); - underlying_writer: *std.io.BufferedWriter, - prefix: []const u8 = "", - mtime_now: u64 = 0, +underlying_writer: *std.io.BufferedWriter, +prefix: []const u8 = "", +mtime_now: u64 = 0, - /// Sets prefix for all other write* method paths. - pub fn setRoot(self: *Self, root: []const u8) !void { - if (root.len > 0) - try self.writeDir(root, .{}); +/// Sets prefix for all other write* method paths. +pub fn setRoot(self: *Self, root: []const u8) !void { + if (root.len > 0) + try self.writeDir(root, .{}); - self.prefix = root; + self.prefix = root; +} + +/// Writes directory. +pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void { + try self.writeHeader(.directory, sub_path, "", 0, opt); +} + +/// Writes file system file. +pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void { + const stat = try file.stat(); + const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); + + var header = Header{}; + try self.setPath(&header, sub_path); + try header.setSize(stat.size); + try header.setMtime(mtime); + try header.write(self.underlying_writer); + + try self.underlying_writer.writeFileAll(file, .{ .len = .init(stat.size) }); + try self.writePadding(stat.size); +} + +/// Writes file reading file content from `reader`. Number of bytes in +/// reader must be equal to `size`. +pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void { + try self.writeHeader(.regular, sub_path, "", @intCast(size), opt); + + var counting_reader = std.io.countingReader(reader); + var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); + try fifo.pump(counting_reader.reader(), self.underlying_writer); + if (counting_reader.bytes_read != size) return error.WrongReaderSize; + try self.writePadding(size); +} + +/// Writes file using bytes buffer `content` for size and file content. +pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void { + try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt); + try self.underlying_writer.writeAll(content); + try self.writePadding(content.len); +} + +/// Writes symlink. +pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void { + try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt); +} + +/// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and +/// default for entry mode . +pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void { + switch (entry.kind) { + .directory => { + try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); + }, + .file => { + var file = try entry.dir.openFile(entry.basename, .{}); + defer file.close(); + try self.writeFile(entry.path, file); + }, + .sym_link => { + var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; + const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); + try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); + }, + else => { + return error.UnsupportedWalkerEntryKind; + }, } +} - /// Writes directory. - pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void { - try self.writeHeader(.directory, sub_path, "", 0, opt); - } - - /// Writes file system file. - pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void { - const stat = try file.stat(); - const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); - - var header = Header{}; - try self.setPath(&header, sub_path); - try header.setSize(stat.size); - try header.setMtime(mtime); - try header.write(self.underlying_writer); - - try self.underlying_writer.writeFileAll(file, .{ .len = .init(stat.size) }); - try self.writePadding(stat.size); - } - - /// Writes file reading file content from `reader`. Number of bytes in - /// reader must be equal to `size`. - pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void { - try self.writeHeader(.regular, sub_path, "", @intCast(size), opt); - - var counting_reader = std.io.countingReader(reader); - var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); - try fifo.pump(counting_reader.reader(), self.underlying_writer); - if (counting_reader.bytes_read != size) return error.WrongReaderSize; - try self.writePadding(size); - } - - /// Writes file using bytes buffer `content` for size and file content. - pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void { - try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt); - try self.underlying_writer.writeAll(content); - try self.writePadding(content.len); - } - - /// Writes symlink. - pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void { - try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt); - } - - /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and - /// default for entry mode . - pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void { - switch (entry.kind) { - .directory => { - try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); - }, - .file => { - var file = try entry.dir.openFile(entry.basename, .{}); - defer file.close(); - try self.writeFile(entry.path, file); - }, - .sym_link => { - var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; - const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); - try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); - }, - else => { - return error.UnsupportedWalkerEntryKind; - }, - } - } - - fn writeHeader( - self: *Self, - typeflag: Header.FileType, - sub_path: []const u8, - link_name: []const u8, - size: u64, - opt: Options, - ) !void { - var header = Header.init(typeflag); - try self.setPath(&header, sub_path); - try header.setSize(size); - try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow()); - if (opt.mode != 0) - try header.setMode(opt.mode); - if (typeflag == .symbolic_link) - header.setLinkname(link_name) catch |err| switch (err) { - error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}), - else => return err, - }; - try header.write(self.underlying_writer); - } - - fn mtimeNow(self: *Self) u64 { - if (self.mtime_now == 0) - self.mtime_now = @intCast(std.time.timestamp()); - return self.mtime_now; - } - - fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { - const stat = try entry.dir.statFile(entry.basename); - return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); - } - - /// Writes path in posix header, if don't fit (in name+prefix; 100+155 - /// bytes) writes it in gnu extended header. - fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void { - header.setPath(self.prefix, sub_path) catch |err| switch (err) { - error.NameTooLong => { - // write extended header - const buffers: []const []const u8 = if (self.prefix.len == 0) - &.{sub_path} - else - &.{ self.prefix, "/", sub_path }; - try self.writeExtendedHeader(.gnu_long_name, buffers); - }, +fn writeHeader( + self: *Self, + typeflag: Header.FileType, + sub_path: []const u8, + link_name: []const u8, + size: u64, + opt: Options, +) !void { + var header = Header.init(typeflag); + try self.setPath(&header, sub_path); + try header.setSize(size); + try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow()); + if (opt.mode != 0) + try header.setMode(opt.mode); + if (typeflag == .symbolic_link) + header.setLinkname(link_name) catch |err| switch (err) { + error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}), else => return err, }; - } + try header.write(self.underlying_writer); +} - /// Writes gnu extended header: gnu_long_name or gnu_long_link. - fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void { - var len: usize = 0; - for (buffers) |buf| - len += buf.len; +fn mtimeNow(self: *Self) u64 { + if (self.mtime_now == 0) + self.mtime_now = @intCast(std.time.timestamp()); + return self.mtime_now; +} - var header = Header.init(typeflag); - try header.setSize(len); - try header.write(self.underlying_writer); - for (buffers) |buf| - try self.underlying_writer.writeAll(buf); - try self.writePadding(len); - } +fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { + const stat = try entry.dir.statFile(entry.basename); + return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); +} - fn writePadding(self: *Self, bytes: u64) !void { - const pos: usize = @intCast(bytes % block_size); - if (pos == 0) return; - try self.underlying_writer.writeAll(empty_block[pos..]); - } +/// Writes path in posix header, if don't fit (in name+prefix; 100+155 +/// bytes) writes it in gnu extended header. +fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void { + header.setPath(self.prefix, sub_path) catch |err| switch (err) { + error.NameTooLong => { + // write extended header + const buffers: []const []const u8 = if (self.prefix.len == 0) + &.{sub_path} + else + &.{ self.prefix, "/", sub_path }; + try self.writeExtendedHeader(.gnu_long_name, buffers); + }, + else => return err, + }; +} - /// Tar should finish with two zero blocks, but 'reasonable system must - /// not assume that such a block exists when reading an archive' (from - /// reference). In practice it is safe to skip this finish. - pub fn finish(self: *Self) !void { - try self.underlying_writer.writeAll(&empty_block); - try self.underlying_writer.writeAll(&empty_block); - } -}; +/// Writes gnu extended header: gnu_long_name or gnu_long_link. +fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void { + var len: usize = 0; + for (buffers) |buf| + len += buf.len; + + var header = Header.init(typeflag); + try header.setSize(len); + try header.write(self.underlying_writer); + for (buffers) |buf| + try self.underlying_writer.writeAll(buf); + try self.writePadding(len); +} + +fn writePadding(self: *Self, bytes: u64) !void { + const pos: usize = @intCast(bytes % block_size); + if (pos == 0) return; + try self.underlying_writer.writeAll(empty_block[pos..]); +} + +/// Tar should finish with two zero blocks, but 'reasonable system must +/// not assume that such a block exists when reading an archive' (from +/// reference). In practice it is safe to skip this finish. +pub fn finish(self: *Self) !void { + try self.underlying_writer.writeAll(&empty_block); + try self.underlying_writer.writeAll(&empty_block); +} /// A struct that is exactly 512 bytes and matches tar file format. This is /// intended to be used for outputting tar files; for parsing there is @@ -320,7 +319,7 @@ const Header = extern struct { assert(@sizeOf(Header) == 512); } - test setPath { + test "setPath" { const cases = [_]struct { in: []const []const u8, out: []const []const u8, diff --git a/lib/std/zig.zig b/lib/std/zig.zig index ffc439d967..01951cdd0e 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -416,7 +416,7 @@ fn formatId( bytes: []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, - writer: anytype, + writer: *std.io.BufferedWriter, ) !void { const allow_primitive, const allow_underscore = comptime parse_fmt: { var allow_primitive = false; diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig index 51767ea1de..1022dbf804 100644 --- a/lib/std/zig/ErrorBundle.zig +++ b/lib/std/zig/ErrorBundle.zig @@ -194,7 +194,7 @@ fn renderErrorMessageToWriter( ) anyerror!void { const ttyconf = options.ttyconf; var counting_writer: std.io.CountingWriter = .{ .child_writer = bw.writer() }; - var counting_bw = counting_writer.unbufferedWriter(); + var counting_bw = counting_writer.writer().unbuffered(); const err_msg = eb.getErrorMessage(err_msg_index); if (err_msg.src_loc != .none) { const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));