authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-05-01 21:03:05+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-05-01 12:03:05-07:00
logd841f84b8b68ee37ccad5ce97b71ea99d2c63c6d
treea274909d4140e61d94a1cb45dbde6ce765ef6e20
parente8dd79ca67ba10daa15bd7c097a702c30a9bf0de
signaturebadge-check Signed by PGP key B5690EEEBB952194

std.tar: fix finding tar root_dir (#19829)

For issue #19820.

2 files changed, 43 insertions(+), 29 deletions(-)

lib/std/tar.zig+43-29
......@@ -29,7 +29,7 @@ pub const Diagnostics = struct {
2929 allocator: std.mem.Allocator,
3030 errors: std.ArrayListUnmanaged(Error) = .{},
3131
32 root_entries: usize = 0,
32 entries: usize = 0,
3333 root_dir: []const u8 = "",
3434
3535 pub const Error = union(enum) {
......@@ -48,41 +48,40 @@ pub const Diagnostics = struct {
4848 },
4949 };
5050
51 fn findRoot(d: *Diagnostics, path: []const u8, kind: FileKind) !void {
52 if (rootDir(path)) |root_dir| {
53 d.root_entries += 1;
54 if (kind == .directory and d.root_entries == 1) {
55 d.root_dir = try d.allocator.dupe(u8, root_dir);
56 return;
57 }
58 d.allocator.free(d.root_dir);
59 d.root_dir = "";
51 fn findRoot(d: *Diagnostics, path: []const u8) !void {
52 if (path.len == 0) return;
53
54 d.entries += 1;
55 const root_dir = rootDir(path);
56 if (d.entries == 1) {
57 d.root_dir = try d.allocator.dupe(u8, root_dir);
58 return;
6059 }
60 if (d.root_dir.len == 0 or std.mem.eql(u8, root_dir, d.root_dir))
61 return;
62 d.allocator.free(d.root_dir);
63 d.root_dir = "";
6164 }
6265
63 // If path is package root returns root_dir name, otherwise null.
64 fn rootDir(path: []const u8) ?[]const u8 {
65 if (path.len == 0) return null;
66
66 // Returns root dir of the path, assumes non empty path.
67 fn rootDir(path: []const u8) []const u8 {
6768 const start_index: usize = if (path[0] == '/') 1 else 0;
6869 const end_index: usize = if (path[path.len - 1] == '/') path.len - 1 else path.len;
6970 const buf = path[start_index..end_index];
70 return if (std.mem.indexOfScalarPos(u8, buf, 0, '/') == null)
71 buf
72 else
73 null;
71 if (std.mem.indexOfScalarPos(u8, buf, 0, '/')) |idx| {
72 return buf[0..idx];
73 }
74 return buf;
7475 }
7576
7677 test rootDir {
7778 const expectEqualStrings = testing.expectEqualStrings;
78 const expect = testing.expect;
79
80 try expectEqualStrings("a", rootDir("a").?);
81 try expectEqualStrings("b", rootDir("b").?);
82 try expectEqualStrings("c", rootDir("/c").?);
83 try expectEqualStrings("d", rootDir("/d/").?);
84 try expect(rootDir("a/b") == null);
85 try expect(rootDir("") == null);
79 try expectEqualStrings("a", rootDir("a"));
80 try expectEqualStrings("b", rootDir("b"));
81 try expectEqualStrings("c", rootDir("/c"));
82 try expectEqualStrings("d", rootDir("/d/"));
83 try expectEqualStrings("a", rootDir("a/b"));
84 try expectEqualStrings("a", rootDir("a/b/c"));
8685 }
8786
8887 pub fn deinit(d: *Diagnostics) void {
......@@ -625,7 +624,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
625624 while (try iter.next()) |file| {
626625 const file_name = stripComponents(file.name, options.strip_components);
627626 if (options.diagnostics) |d| {
628 try d.findRoot(file_name, file.kind);
627 try d.findRoot(file_name);
629628 }
630629
631630 switch (file.kind) {
......@@ -1056,7 +1055,7 @@ test "pipeToFileSystem root_dir" {
10561055
10571056 // there is no root_dir
10581057 try testing.expectEqual(0, diagnostics.root_dir.len);
1059 try testing.expectEqual(3, diagnostics.root_entries);
1058 try testing.expectEqual(5, diagnostics.entries);
10601059 }
10611060
10621061 // with strip_components = 0
......@@ -1078,10 +1077,25 @@ test "pipeToFileSystem root_dir" {
10781077
10791078 // root_dir found
10801079 try testing.expectEqualStrings("example", diagnostics.root_dir);
1081 try testing.expectEqual(1, diagnostics.root_entries);
1080 try testing.expectEqual(6, diagnostics.entries);
10821081 }
10831082}
10841083
1084test "findRoot without explicit root dir" {
1085 const data = @embedFile("tar/testdata/19820.tar");
1086 var fbs = std.io.fixedBufferStream(data);
1087 const reader = fbs.reader();
1088
1089 var tmp = testing.tmpDir(.{});
1090 defer tmp.cleanup();
1091
1092 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1093 defer diagnostics.deinit();
1094 try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics });
1095
1096 try testing.expectEqualStrings("root", diagnostics.root_dir);
1097}
1098
10851099fn normalizePath(bytes: []u8) []u8 {
10861100 const canonical_sep = std.fs.path.sep_posix;
10871101 if (std.fs.path.sep == canonical_sep) return bytes;
lib/std/tar/testdata/19820.tar created
Binary files /dev/null and b/lib/std/tar/testdata/19820.tar differ