Skip to content

Commit

Permalink
use tar.writer instead of tar.output.Header
Browse files Browse the repository at this point in the history
  • Loading branch information
ianic committed Apr 12, 2024
1 parent 4788714 commit 7ac8d0a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 96 deletions.
41 changes: 8 additions & 33 deletions lib/compiler/std-docs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,16 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
},
},
});
const w = response.writer();

var std_dir = try context.lib_dir.openDir("std", .{ .iterate = true });
defer std_dir.close();

var walker = try std_dir.walk(gpa);
defer walker.deinit();

var archiver = std.tar.writer(response.writer());
archiver.prefix = "std";

while (try walker.next()) |entry| {
switch (entry.kind) {
.file => {
Expand All @@ -198,47 +200,20 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
},
else => continue,
}

var file = try std_dir.openFile(entry.path, .{});
defer file.close();

const stat = try file.stat();
const padding = p: {
const remainder = stat.size % 512;
break :p if (remainder > 0) 512 - remainder else 0;
};

var file_header = std.tar.output.Header.init();
file_header.typeflag = .regular;
try file_header.setPath("std", entry.path);
try file_header.setSize(stat.size);
try file_header.updateChecksum();
try w.writeAll(std.mem.asBytes(&file_header));
try w.writeFile(file);
try w.writeByteNTimes(0, padding);
try archiver.addEntry(entry);
}

{
// Since this command is JIT compiled, the builtin module available in
// this source file corresponds to the user's host system.
const builtin_zig = @embedFile("builtin");

var file_header = std.tar.output.Header.init();
file_header.typeflag = .regular;
try file_header.setPath("builtin", "builtin.zig");
try file_header.setSize(builtin_zig.len);
try file_header.updateChecksum();
try w.writeAll(std.mem.asBytes(&file_header));
try w.writeAll(builtin_zig);
const padding = p: {
const remainder = builtin_zig.len % 512;
break :p if (remainder > 0) 512 - remainder else 0;
};
try w.writeByteNTimes(0, padding);
archiver.prefix = "builtin";
var stream = std.io.fixedBufferStream(builtin_zig);
try archiver.addFile("builtin.zig", builtin_zig.len, stream.reader(), .{});
}

// intentionally omitting the pointless trailer
//try w.writeByteNTimes(0, 512 * 2);
//try archiver.finish();
try response.end();
}

Expand Down
57 changes: 29 additions & 28 deletions lib/std/tar/writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ const assert = std.debug.assert;
const testing = std.testing;

/// Creates tar Writer which will write tar content to the `underlying_writer`.
/// All paths will be prefixed with `perfix` if it is not empty string.
pub fn writer(underlying_writer: anytype, prefix: []const u8) !Writer(@TypeOf(underlying_writer)) {
return Writer(@TypeOf(underlying_writer)).init(
underlying_writer,
prefix,
);
/// Use setRoot to nest all following entries under single root. If file don't
/// fit into posix header (name+prefix: 100+155 bytes) gnu extented header will
/// be used for long names. Options enables setting file premission mode and
/// mtime. Default is to use current time for mtime and
/// `default_mode`.file/dir/sym_link for mode.
pub fn writer(underlying_writer: anytype) Writer(@TypeOf(underlying_writer)) {
return .{ .underlying_writer = underlying_writer };
}

pub fn Writer(comptime WriterType: type) type {
return struct {
const block_size = @sizeOf(Header);
const zero: [@sizeOf(Header)]u8 = .{0} ** @sizeOf(Header);
pub const Options = struct {
/// File system permission mode.
mode: u32 = 0,
/// File system modification time.
mtime: u64 = 0,
};
const Self = @This();
Expand All @@ -27,21 +30,16 @@ pub fn Writer(comptime WriterType: type) type {
block_buffer: [block_size]u8 = undefined,
mtime_now: u64 = 0,

/// Tar will be written to the `underlying_writer`. All paths will be
/// prefixed with `perfix` if it is not empty string.
pub fn init(underlying_writer: WriterType, prefix: []const u8) !Self {
var self = Self{
.underlying_writer = underlying_writer,
};
if (prefix.len > 0) {
try self.addDir(prefix, .{});
self.prefix = prefix;
/// Sets prefix for all other add* method paths.
pub fn setRoot(self: *Self, root: []const u8) !void {
if (root.len > 0) {
try self.addDir(root, .{});
}
return self;
self.prefix = root;
}

/// Writes directory. If options are omitted `default_mode.dir` is used
/// for mode and current time for mtime.
/// for mode and current time for `mtime`.
pub fn addDir(self: *Self, sub_path: []const u8, opt: Options) !void {
var header = Header.init(.directory);
try self.setPath(&header, sub_path);
Expand Down Expand Up @@ -86,7 +84,7 @@ pub fn Writer(comptime WriterType: type) type {
}

/// Writes symlink. If options are omitted `default_mode.sym_link` is
/// used for mode and current time for mtime.
/// used for mode and current time for `mtime`.
pub fn addLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void {
var header = Header.init(.symbolic_link);
try self.setPath(&header, sub_path);
Expand All @@ -99,8 +97,8 @@ pub fn Writer(comptime WriterType: type) type {
try header.write(self.underlying_writer);
}

/// Writes fs.Dir.WalkerEntry. Uses mtime from file system entry and
/// defaults from `default_mode` for mode.
/// 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));
Expand Down Expand Up @@ -140,6 +138,7 @@ pub fn Writer(comptime WriterType: type) type {
};
}

/// 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|
Expand Down Expand Up @@ -413,11 +412,12 @@ test "write files" {

// with root
{
const prefix = "root";
const root = "root";

var output = std.ArrayList(u8).init(testing.allocator);
defer output.deinit();
var wrt = try writer(output.writer(), prefix);
var wrt = writer(output.writer());
try wrt.setRoot(root);
for (files) |file| {
var content = std.io.fixedBufferStream(file.content);
try wrt.addFile(file.path, file.content.len, content.reader(), .{});
Expand All @@ -432,17 +432,17 @@ test "write files" {
// first entry is directory with prefix
{
const actual = (try iter.next()).?;
try testing.expectEqualStrings(prefix, actual.name);
try testing.expectEqualStrings(root, actual.name);
try testing.expectEqual(std.tar.FileKind.directory, actual.kind);
}

var i: usize = 0;
while (try iter.next()) |actual| {
defer i += 1;
const expected = files[i];
try testing.expectEqualStrings(prefix, actual.name[0..prefix.len]);
try testing.expectEqual('/', actual.name[prefix.len..][0]);
try testing.expectEqualStrings(expected.path, actual.name[prefix.len + 1 ..]);
try testing.expectEqualStrings(root, actual.name[0..root.len]);
try testing.expectEqual('/', actual.name[root.len..][0]);
try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]);

var content = std.ArrayList(u8).init(testing.allocator);
defer content.deinit();
Expand All @@ -454,7 +454,7 @@ test "write files" {
{
var output = std.ArrayList(u8).init(testing.allocator);
defer output.deinit();
var wrt = try writer(output.writer(), "");
var wrt = writer(output.writer());
for (files) |file| {
var content = std.io.fixedBufferStream(file.content);
try wrt.addFile(file.path, file.content.len, content.reader(), .{});
Expand Down Expand Up @@ -592,7 +592,8 @@ test "sourcesTar" {
{
var out_file = try out_dir.createFile("sources_new.tar", .{});
defer out_file.close();
var w = try writer(out_file.writer(), "std");
var w = writer(out_file.writer());
try w.setRoot("std");

var std_dir = try lib_dir.openDir("std", .{ .iterate = true });
defer std_dir.close();
Expand Down
39 changes: 4 additions & 35 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3761,7 +3761,7 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, tar_file: std.fs.
var walker = try mod_dir.walk(comp.gpa);
defer walker.deinit();

const padding_buffer = [1]u8{0} ** 512;
var archiver = std.tar.writer(tar_file.writer());

while (try walker.next()) |entry| {
switch (entry.kind) {
Expand All @@ -3772,43 +3772,12 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, tar_file: std.fs.
},
else => continue,
}

var file = mod_dir.openFile(entry.path, .{}) catch |err| {
return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{}{s}': {s}", .{
root, entry.path, @errorName(err),
});
};
defer file.close();

const stat = file.stat() catch |err| {
return comp.lockAndSetMiscFailure(.docs_copy, "unable to stat '{}{s}': {s}", .{
archiver.prefix = module.fully_qualified_name;
archiver.addEntry(entry) catch |err| {
return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{}{s}': {s}", .{
root, entry.path, @errorName(err),
});
};

var file_header = std.tar.output.Header.init();
file_header.typeflag = .regular;
try file_header.setPath(module.fully_qualified_name, entry.path);
try file_header.setSize(stat.size);
try file_header.updateChecksum();

const header_bytes = std.mem.asBytes(&file_header);
const padding = p: {
const remainder: u16 = @intCast(stat.size % 512);
const n = if (remainder > 0) 512 - remainder else 0;
break :p padding_buffer[0..n];
};

var header_and_trailer: [2]std.posix.iovec_const = .{
.{ .iov_base = header_bytes.ptr, .iov_len = header_bytes.len },
.{ .iov_base = padding.ptr, .iov_len = padding.len },
};

try tar_file.writeFileAll(file, .{
.in_len = stat.size,
.headers_and_trailers = &header_and_trailer,
.header_count = 1,
});
}
}

Expand Down

0 comments on commit 7ac8d0a

Please sign in to comment.