authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-06 19:19:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-10 17:51:06-07:00
log6b84c8e04c9286d072367ae86807fd517c74c479
tree6c45f69b38d992699527db3c8cf976c6a8b0b72e
parentc427685a13a2bb98ccc6944d18bb3e6ee17dcdff

zig std: implement tar format


1 files changed, 91 insertions(+), 3 deletions(-)

lib/compiler/std-docs.zig+91-3
......@@ -1,6 +1,7 @@
11const builtin = @import("builtin");
22const std = @import("std");
33const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;
45
56pub fn main() !void {
67 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
......@@ -140,7 +141,6 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
140141 },
141142 });
142143 const w = response.writer();
143 try w.writeAll("tar header");
144144
145145 var std_dir = try context.lib_dir.openDir("std", .{ .iterate = true });
146146 defer std_dir.close();
......@@ -159,13 +159,27 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
159159 else => continue,
160160 }
161161
162 try w.writeAll(entry.path);
163
164162 var file = try std_dir.openFile(entry.path, .{});
165163 defer file.close();
166164
165 const stat = try file.stat();
166 const padding = p: {
167 const remainder = stat.size % 512;
168 break :p if (remainder > 0) 512 - remainder else 0;
169 };
170 comptime assert(@sizeOf(TarHeader) == 512);
171
172 var file_header = TarHeader.init();
173 file_header.typeflag = .regular;
174 try file_header.setPath("std", entry.path);
175 try file_header.setSize(stat.size);
176 try file_header.updateChecksum();
177 try w.writeAll(std.mem.asBytes(&file_header));
167178 try w.writeFile(file);
179 try w.writeByteNTimes(0, padding);
168180 }
181 // intentionally omitting the pointless trailer
182 //try w.writeByteNTimes(0, 512 * 2);
169183 try response.end();
170184}
171185
......@@ -369,3 +383,77 @@ fn openBrowserTabThread(gpa: Allocator, url: []const u8) !void {
369383 try child.spawn();
370384 _ = try child.wait();
371385}
386
387/// Forked from https://github.com/mattnite/tar/blob/main/src/main.zig which is
388/// MIT licensed.
389pub const TarHeader = extern struct {
390 name: [100]u8,
391 mode: [7:0]u8,
392 uid: [7:0]u8,
393 gid: [7:0]u8,
394 size: [11:0]u8,
395 mtime: [11:0]u8,
396 checksum: [7:0]u8,
397 typeflag: FileType,
398 linkname: [100]u8,
399 magic: [5:0]u8,
400 version: [2]u8,
401 uname: [31:0]u8,
402 gname: [31:0]u8,
403 devmajor: [7:0]u8,
404 devminor: [7:0]u8,
405 prefix: [155]u8,
406 pad: [12]u8,
407
408 const FileType = enum(u8) {
409 regular = '0',
410 hard_link = '1',
411 symbolic_link = '2',
412 character = '3',
413 block = '4',
414 directory = '5',
415 fifo = '6',
416 reserved = '7',
417 pax_global = 'g',
418 extended = 'x',
419 _,
420 };
421
422 fn init() TarHeader {
423 var ret = std.mem.zeroes(TarHeader);
424 ret.magic = [_:0]u8{ 'u', 's', 't', 'a', 'r' };
425 ret.version = [_:0]u8{ '0', '0' };
426 return ret;
427 }
428
429 fn setPath(self: *TarHeader, prefix: []const u8, path: []const u8) !void {
430 if (prefix.len + 1 + path.len > 100) {
431 var i: usize = 0;
432 while (i < path.len and path.len - i > 100) {
433 while (path[i] != '/') : (i += 1) {}
434 }
435
436 _ = try std.fmt.bufPrint(&self.prefix, "{s}/{s}", .{ prefix, path[0..i] });
437 _ = try std.fmt.bufPrint(&self.name, "{s}", .{path[i + 1 ..]});
438 } else {
439 _ = try std.fmt.bufPrint(&self.name, "{s}/{s}", .{ prefix, path });
440 }
441 }
442
443 fn setSize(self: *TarHeader, size: u64) !void {
444 _ = try std.fmt.bufPrint(&self.size, "{o:0>11}", .{size});
445 }
446
447 fn updateChecksum(self: *TarHeader) !void {
448 const offset = @offsetOf(TarHeader, "checksum");
449 var checksum: usize = 0;
450 for (std.mem.asBytes(self), 0..) |val, i| {
451 checksum += if (i >= offset and i < offset + @sizeOf(@TypeOf(self.checksum)))
452 ' '
453 else
454 val;
455 }
456
457 _ = try std.fmt.bufPrint(&self.checksum, "{o:0>7}", .{checksum});
458 }
459};