authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-03 21:29:04-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-03 21:29:04-04:00
log768b17755e7735b328b92212de2dd7018f78fb4b
tree162e5853959a567ad942fe9b685766292834cf6f
parentefb00c20eefff7bf1ef2d2d7bb9ef16374ebfd27
parente0350859bb88d70b95a6b99932a9a5452f8b6b14
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19615 from ianic/tar_diagnostic

std.tar: add strip components error to diagnostics

2 files changed, 39 insertions(+), 3 deletions(-)

lib/std/tar.zig+38-3
......@@ -46,6 +46,9 @@ pub const Diagnostics = struct {
4646 file_name: []const u8,
4747 file_type: Header.Kind,
4848 },
49 components_outside_stripped_prefix: struct {
50 file_name: []const u8,
51 },
4952 };
5053
5154 fn findRoot(d: *Diagnostics, path: []const u8) !void {
......@@ -97,6 +100,9 @@ pub const Diagnostics = struct {
97100 .unsupported_file_type => |info| {
98101 d.allocator.free(info.file_name);
99102 },
103 .components_outside_stripped_prefix => |info| {
104 d.allocator.free(info.file_name);
105 },
100106 }
101107 }
102108 d.errors.deinit(d.allocator);
......@@ -623,18 +629,24 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
623629
624630 while (try iter.next()) |file| {
625631 const file_name = stripComponents(file.name, options.strip_components);
632 if (file_name.len == 0 and file.kind != .directory) {
633 const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix;
634 try d.errors.append(d.allocator, .{ .components_outside_stripped_prefix = .{
635 .file_name = try d.allocator.dupe(u8, file.name),
636 } });
637 continue;
638 }
626639 if (options.diagnostics) |d| {
627640 try d.findRoot(file_name);
628641 }
629642
630643 switch (file.kind) {
631644 .directory => {
632 if (file_name.len != 0 and !options.exclude_empty_directories) {
645 if (file_name.len > 0 and !options.exclude_empty_directories) {
633646 try dir.makePath(file_name);
634647 }
635648 },
636649 .file => {
637 if (file_name.len == 0) return error.BadFileName;
638650 if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
639651 defer fs_file.close();
640652 try file.writeAll(fs_file);
......@@ -647,7 +659,6 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
647659 }
648660 },
649661 .sym_link => {
650 if (file_name.len == 0) return error.BadFileName;
651662 const link_name = file.link_name;
652663 createDirAndSymlink(dir, link_name, file_name) catch |err| {
653664 const d = options.diagnostics orelse return error.UnableToCreateSymLink;
......@@ -1096,6 +1107,30 @@ test "findRoot without explicit root dir" {
10961107 try testing.expectEqualStrings("root", diagnostics.root_dir);
10971108}
10981109
1110test "pipeToFileSystem strip_components" {
1111 const data = @embedFile("tar/testdata/example.tar");
1112 var fbs = std.io.fixedBufferStream(data);
1113 const reader = fbs.reader();
1114
1115 var tmp = testing.tmpDir(.{ .no_follow = true });
1116 defer tmp.cleanup();
1117 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1118 defer diagnostics.deinit();
1119
1120 pipeToFileSystem(tmp.dir, reader, .{
1121 .strip_components = 3,
1122 .diagnostics = &diagnostics,
1123 }) catch |err| {
1124 // Skip on platform which don't support symlinks
1125 if (err == error.UnableToCreateSymLink) return error.SkipZigTest;
1126 return err;
1127 };
1128
1129 try testing.expectEqual(2, diagnostics.errors.items.len);
1130 try testing.expectEqualStrings("example/b/symlink", diagnostics.errors.items[0].components_outside_stripped_prefix.file_name);
1131 try testing.expectEqualStrings("example/a/file", diagnostics.errors.items[1].components_outside_stripped_prefix.file_name);
1132}
1133
10991134fn normalizePath(bytes: []u8) []u8 {
11001135 const canonical_sep = std.fs.path.sep_posix;
11011136 if (std.fs.path.sep == canonical_sep) return bytes;
src/Package/Fetch.zig+1
......@@ -1189,6 +1189,7 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes
11891189 .unable_to_create_file => |i| res.unableToCreateFile(stripRoot(i.file_name, res.root_dir), i.code),
11901190 .unable_to_create_sym_link => |i| res.unableToCreateSymLink(stripRoot(i.file_name, res.root_dir), i.link_name, i.code),
11911191 .unsupported_file_type => |i| res.unsupportedFileType(stripRoot(i.file_name, res.root_dir), @intFromEnum(i.file_type)),
1192 .components_outside_stripped_prefix => unreachable, // unreachable with strip_components = 0
11921193 }
11931194 }
11941195 }