Skip to content

Commit d841f84

Browse files
authored
std.tar: fix finding tar root_dir (#19829)
For issue #19820.
1 parent e8dd79c commit d841f84

File tree

2 files changed

+43
-29
lines changed

2 files changed

+43
-29
lines changed

lib/std/tar.zig

+43-29
Original file line numberDiff line numberDiff line change
@@ -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

1084+
test "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+
10851099
fn 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

1 KB
Binary file not shown.

0 commit comments

Comments
 (0)