Skip to content

Commit

Permalink
std.tar: use writeFile in tar.writer
Browse files Browse the repository at this point in the history
Fixing performance problem:
ziglang#19603 (comment)
  • Loading branch information
ianic committed Apr 12, 2024
1 parent 1aae6d0 commit c53db44
Showing 1 changed file with 27 additions and 11 deletions.
38 changes: 27 additions & 11 deletions lib/std/tar/writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,7 @@ pub fn Writer(comptime WriterType: type) type {
/// reader must be equal to `size`. If options are omitted
/// `default_mode.file` is used for mode and current time for mtime.
pub fn addFile(self: *Self, sub_path: []const u8, size: u64, reader: anytype, opt: Options) !void {
var header = Header.init(.regular);
try self.setPath(&header, sub_path);
try self.setMtime(&header, opt.mtime);
try header.setSize(size);
try header.setMode(opt.mode);
try header.write(self.underlying_writer);
try self.addFileHeader(sub_path, size, opt);

var written: usize = 0;
while (written < size) {
Expand All @@ -70,6 +65,24 @@ pub fn Writer(comptime WriterType: type) type {
}
}

/// Writes file system file.
pub fn addFsFile(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));
try self.addFileHeader(sub_path, stat.size, .{ .mtime = mtime });
try self.underlying_writer.any().writeFile(file);
try self.writePadding(stat.size);
}

fn addFileHeader(self: *Self, sub_path: []const u8, size: u64, opt: Options) !void {
var header = Header.init(.regular);
try self.setPath(&header, sub_path);
try self.setMtime(&header, opt.mtime);
try header.setSize(size);
try header.setMode(opt.mode);
try header.write(self.underlying_writer);
}

fn setMtime(self: *Self, header: *Header, mtime: u64) !void {
const mt = blk: {
if (mtime == 0) {
Expand Down Expand Up @@ -100,28 +113,31 @@ pub fn Writer(comptime WriterType: type) type {
/// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and
/// default from `default_mode` for entry mode.
pub fn addEntry(self: *Self, entry: std.fs.Dir.Walker.WalkerEntry) !void {
const stat = try entry.dir.statFile(entry.basename);
const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
switch (entry.kind) {
.directory => {
try self.addDir(entry.path, .{ .mtime = mtime });
try self.addDir(entry.path, .{ .mtime = try entryMtime(entry) });
},
.file => {
var file = try entry.dir.openFile(entry.basename, .{});
defer file.close();
try self.addFile(entry.path, stat.size, file.reader(), .{ .mtime = mtime });
try self.addFsFile(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.addLink(entry.path, link_name, .{ .mtime = mtime });
try self.addLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
},
else => {
return error.UnsupportedWalkerEntryKind;
},
}
}

fn entryMtime(entry: std.fs.Dir.Walker.WalkerEntry) !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 {
Expand Down

0 comments on commit c53db44

Please sign in to comment.