| author | |
| committer | |
| log | f16eb18ce8c24ed743aae1faa4980052cb9f4f36 |
| tree | 9927c1ece6299a3b0ad195d7e5f8bdcfd6b9bd48 |
| parent | c91bb87b01f988d2bad4e015f65b0767abcbce36 |
The tar format expects `/`, although some untar implementations do seem to handle Windows-style `\` path separators (7-Zip at least).
The tar.Writer API can't really enforce this, though, as doing so would effectively make `\` an illegal character when it's really not. So, it's up to the user to provide paths with the correct path separators.
`Build/WebServer.zig` will still output tars with `\` as a path separator on Windows, but that's currently only used during fuzzing which is not yet implemented on Windows.5 files changed, 47 insertions(+), 3 deletions(-)
lib/compiler/std-docs.zig+14-1| ... | ... | @@ -208,6 +208,9 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { |
| 208 | 208 | var archiver: std.tar.Writer = .{ .underlying_writer = &response.writer }; |
| 209 | 209 | archiver.prefix = "std"; |
| 210 | 210 | |
| 211 | var path_buf: std.ArrayList(u8) = .empty; | |
| 212 | defer path_buf.deinit(gpa); | |
| 213 | ||
| 211 | 214 | while (try walker.next(io)) |entry| { |
| 212 | 215 | switch (entry.kind) { |
| 213 | 216 | .file => { |
| ... | ... | @@ -227,7 +230,17 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { |
| 227 | 230 | .interface = Io.File.Reader.initInterface(&.{}), |
| 228 | 231 | .size = stat.size, |
| 229 | 232 | }; |
| 230 | try archiver.writeFileTimestamp(entry.path, &file_reader, stat.mtime); | |
| 233 | ||
| 234 | const posix_path = if (comptime std.fs.path.sep == std.fs.path.sep_posix) | |
| 235 | entry.path | |
| 236 | else blk: { | |
| 237 | path_buf.clearRetainingCapacity(); | |
| 238 | try path_buf.appendSlice(gpa, entry.path); | |
| 239 | std.mem.replaceScalar(u8, path_buf.items, std.fs.path.sep, std.fs.path.sep_posix); | |
| 240 | break :blk path_buf.items; | |
| 241 | }; | |
| 242 | ||
| 243 | try archiver.writeFileTimestamp(posix_path, &file_reader, stat.mtime); | |
| 231 | 244 | } |
| 232 | 245 | |
| 233 | 246 | { |
lib/std/Build/WebServer.zig+4| ... | ... | @@ -526,6 +526,10 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons |
| 526 | 526 | // resulting in modules named "" and "src". The compiler needs to tell the build system |
| 527 | 527 | // about the module graph so that the build system can correctly encode this information in |
| 528 | 528 | // the tar file. |
| 529 | // | |
| 530 | // Additionally, this needs to ensure that all path separators for both prefix and | |
| 531 | // sub_path are using the POSIX-style `/` on platforms that don't use it as their native | |
| 532 | // path separator. | |
| 529 | 533 | archiver.prefix = path.root_dir.path orelse graph.cache.cwd; |
| 530 | 534 | try archiver.writeFile(path.sub_path, &file_reader, @intCast(stat.mtime.toSeconds())); |
| 531 | 535 | } |
lib/std/tar/Writer.zig+12-1| ... | ... | @@ -17,6 +17,7 @@ pub const Options = struct { |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | 19 | underlying_writer: *Io.Writer, |
| 20 | /// Assumed to use `/` for any path separators. | |
| 20 | 21 | prefix: []const u8 = "", |
| 21 | 22 | |
| 22 | 23 | const Error = error{ |
| ... | ... | @@ -26,6 +27,7 @@ const Error = error{ |
| 26 | 27 | }; |
| 27 | 28 | |
| 28 | 29 | /// Sets prefix for all other write* method paths. |
| 30 | /// `root` is assumed to use `/` for any path separators. | |
| 29 | 31 | pub fn setRoot(w: *Writer, root: []const u8) Error!void { |
| 30 | 32 | if (root.len > 0) |
| 31 | 33 | try w.writeDir(root, .{}); |
| ... | ... | @@ -41,6 +43,7 @@ pub const WriteFileError = Io.Writer.FileError || Error || Io.File.Reader.SizeEr |
| 41 | 43 | |
| 42 | 44 | pub fn writeFileTimestamp( |
| 43 | 45 | w: *Writer, |
| 46 | /// Assumed to use `/` for any path separators. | |
| 44 | 47 | sub_path: []const u8, |
| 45 | 48 | file_reader: *Io.File.Reader, |
| 46 | 49 | mtime: Io.Timestamp, |
| ... | ... | @@ -50,6 +53,7 @@ pub fn writeFileTimestamp( |
| 50 | 53 | |
| 51 | 54 | pub fn writeFile( |
| 52 | 55 | w: *Writer, |
| 56 | /// Assumed to use `/` for any path separators. | |
| 53 | 57 | sub_path: []const u8, |
| 54 | 58 | file_reader: *Io.File.Reader, |
| 55 | 59 | /// If you want to match the file format's expectations, it wants number of |
| ... | ... | @@ -76,6 +80,7 @@ pub const WriteFileStreamError = Error || Io.Reader.StreamError; |
| 76 | 80 | /// from `reader`, or returns `error.EndOfStream`. |
| 77 | 81 | pub fn writeFileStream( |
| 78 | 82 | w: *Writer, |
| 83 | /// Assumed to use `/` for any path separators. | |
| 79 | 84 | sub_path: []const u8, |
| 80 | 85 | size: u64, |
| 81 | 86 | reader: *Io.Reader, |
| ... | ... | @@ -87,7 +92,13 @@ pub fn writeFileStream( |
| 87 | 92 | } |
| 88 | 93 | |
| 89 | 94 | /// Writes file using bytes buffer `content` for size and file content. |
| 90 | pub fn writeFileBytes(w: *Writer, sub_path: []const u8, content: []const u8, options: Options) Error!void { | |
| 95 | pub fn writeFileBytes( | |
| 96 | w: *Writer, | |
| 97 | /// Assumed to use `/` for all path separators. | |
| 98 | sub_path: []const u8, | |
| 99 | content: []const u8, | |
| 100 | options: Options, | |
| 101 | ) Error!void { | |
| 91 | 102 | try w.writeHeader(.regular, sub_path, "", content.len, options); |
| 92 | 103 | try w.underlying_writer.writeAll(content); |
| 93 | 104 | try w.writePadding(content.len); |
src/Compilation.zig+13-1| ... | ... | @@ -5440,6 +5440,9 @@ fn docsCopyModule( |
| 5440 | 5440 | var archiver: std.tar.Writer = .{ .underlying_writer = &tar_file_writer.interface }; |
| 5441 | 5441 | archiver.prefix = name; |
| 5442 | 5442 | |
| 5443 | var path_buf: std.ArrayList(u8) = .empty; | |
| 5444 | defer path_buf.deinit(comp.gpa); | |
| 5445 | ||
| 5443 | 5446 | var buffer: [1024]u8 = undefined; |
| 5444 | 5447 | |
| 5445 | 5448 | while (try walker.next(io)) |entry| { |
| ... | ... | @@ -5460,7 +5463,16 @@ fn docsCopyModule( |
| 5460 | 5463 | const stat = try file.stat(io); |
| 5461 | 5464 | var file_reader: Io.File.Reader = .initSize(file, io, &buffer, stat.size); |
| 5462 | 5465 | |
| 5463 | archiver.writeFileTimestamp(entry.path, &file_reader, stat.mtime) catch |err| { | |
| 5466 | const posix_path = if (comptime std.fs.path.sep == std.fs.path.sep_posix) | |
| 5467 | entry.path | |
| 5468 | else blk: { | |
| 5469 | path_buf.clearRetainingCapacity(); | |
| 5470 | try path_buf.appendSlice(comp.gpa, entry.path); | |
| 5471 | std.mem.replaceScalar(u8, path_buf.items, std.fs.path.sep, std.fs.path.sep_posix); | |
| 5472 | break :blk path_buf.items; | |
| 5473 | }; | |
| 5474 | ||
| 5475 | archiver.writeFileTimestamp(posix_path, &file_reader, stat.mtime) catch |err| { | |
| 5464 | 5476 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive {f}{s}: {t}", .{ |
| 5465 | 5477 | root.fmt(comp), entry.path, err, |
| 5466 | 5478 | }); |
src/Package/Fetch.zig+4| ... | ... | @@ -402,6 +402,10 @@ pub const JobQueue = struct { |
| 402 | 402 | }, |
| 403 | 403 | } |
| 404 | 404 | const entry_path = try arena.dupe(u8, entry.path); |
| 405 | // If necessary, normalize path separators to POSIX-style since the tar format requires that. | |
| 406 | if (comptime std.fs.path.sep != std.fs.path.sep_posix) { | |
| 407 | std.mem.replaceScalar(u8, entry_path, std.fs.path.sep, std.fs.path.sep_posix); | |
| 408 | } | |
| 405 | 409 | try scanned_files.append(gpa, entry_path); |
| 406 | 410 | } |
| 407 | 411 |