const std = @import("std"); const io = std.io; const os = std.os; const fs = std.fs; const mem = std.mem; const Header = std.tar.Header; const assert = std.debug.assert; const zero_iovec = &[0]os.iovec_const{}; const Method = enum { sendfile, copy_file_range, }; pub fn main() !u8 { const method = std.meta.stringToEnum(Method, mem.sliceTo(os.argv[1], 0)) orelse { std.debug.print("usage: ./fast ball.tar\n", .{}); return 1; }; var infile = try fs.cwd().openFile(mem.sliceTo(std.os.argv[2], 0), .{}); defer infile.close(); var file_name_buffer: [255]u8 = undefined; var header_buffer: [512]u8 = undefined; var off_in: usize = 0; while (true) { const got_header = try os.pread(infile.handle, header_buffer[0..], off_in); switch (got_header) { 0 => return 0, 512 => {}, else => return error.UnexpectedEndOfStream, } off_in += got_header; const header: Header = .{ .bytes = &header_buffer }; const file_size = try header.fileSize(); const rounded_file_size = std.mem.alignForwardGeneric(u64, file_size, 512); const pad_len = @intCast(usize, rounded_file_size - file_size); const file_name = try header.fullFileName(&file_name_buffer); switch (header.fileType()) { .directory => { if (file_name.len != 0) try fs.cwd().makeDir(file_name); }, .normal => { if (file_size == 0 and file_name.len == 0) return 0; var outfile = try fs.cwd().createFile(file_name, .{}); defer outfile.close(); if (file_size == 0) continue; var total_written: usize = 0; cfr_loop: while (true) { const amt = switch (method) { .copy_file_range => try os.copy_file_range( infile.handle, off_in, outfile.handle, total_written, file_size - total_written, 0, ), .sendfile => try os.sendfile( outfile.handle, infile.handle, off_in, file_size - total_written, zero_iovec, zero_iovec, 0, ), }; total_written += amt; off_in += amt; if (file_size == total_written or amt == 0) break :cfr_loop; } off_in += pad_len; }, // skip pax headers .global_extended_header, .extended_header => { off_in += rounded_file_size; }, .hard_link => return error.TarUnsupportedFileType, .symbolic_link => return error.TarUnsupportedFileType, else => return error.TarUnsupportedFileType, } } return 0; }