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 {...@@ -29,7 +29,7 @@ pub const Diagnostics = struct {
29 allocator: std.mem.Allocator,29 allocator: std.mem.Allocator,
30 errors: std.ArrayListUnmanaged(Error) = .{},30 errors: std.ArrayListUnmanaged(Error) = .{},
3131
32 root_entries: usize = 0,32 entries: usize = 0,
33 root_dir: []const u8 = "",33 root_dir: []const u8 = "",
3434
35 pub const Error = union(enum) {35 pub const Error = union(enum) {
...@@ -48,41 +48,40 @@ pub const Diagnostics = struct {...@@ -48,41 +48,40 @@ pub const Diagnostics = struct {
48 },48 },
49 };49 };
5050
51 fn findRoot(d: *Diagnostics, path: []const u8, kind: FileKind) !void {51 fn findRoot(d: *Diagnostics, path: []const u8) !void {
52 if (rootDir(path)) |root_dir| {52 if (path.len == 0) return;
53 d.root_entries += 1;53
54 if (kind == .directory and d.root_entries == 1) {54 d.entries += 1;
55 d.root_dir = try d.allocator.dupe(u8, root_dir);55 const root_dir = rootDir(path);
56 return;56 if (d.entries == 1) {
57 }57 d.root_dir = try d.allocator.dupe(u8, root_dir);
58 d.allocator.free(d.root_dir);58 return;
59 d.root_dir = "";
60 }59 }
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 = "";
61 }64 }
6265
63 // If path is package root returns root_dir name, otherwise null.66 // Returns root dir of the path, assumes non empty path.
64 fn rootDir(path: []const u8) ?[]const u8 {67 fn rootDir(path: []const u8) []const u8 {
65 if (path.len == 0) return null;
66
67 const start_index: usize = if (path[0] == '/') 1 else 0;68 const start_index: usize = if (path[0] == '/') 1 else 0;
68 const end_index: usize = if (path[path.len - 1] == '/') path.len - 1 else path.len;69 const end_index: usize = if (path[path.len - 1] == '/') path.len - 1 else path.len;
69 const buf = path[start_index..end_index];70 const buf = path[start_index..end_index];
70 return if (std.mem.indexOfScalarPos(u8, buf, 0, '/') == null)71 if (std.mem.indexOfScalarPos(u8, buf, 0, '/')) |idx| {
71 buf72 return buf[0..idx];
72 else73 }
73 null;74 return buf;
74 }75 }
7576
76 test rootDir {77 test rootDir {
77 const expectEqualStrings = testing.expectEqualStrings;78 const expectEqualStrings = testing.expectEqualStrings;
78 const expect = testing.expect;79 try expectEqualStrings("a", rootDir("a"));
7980 try expectEqualStrings("b", rootDir("b"));
80 try expectEqualStrings("a", rootDir("a").?);81 try expectEqualStrings("c", rootDir("/c"));
81 try expectEqualStrings("b", rootDir("b").?);82 try expectEqualStrings("d", rootDir("/d/"));
82 try expectEqualStrings("c", rootDir("/c").?);83 try expectEqualStrings("a", rootDir("a/b"));
83 try expectEqualStrings("d", rootDir("/d/").?);84 try expectEqualStrings("a", rootDir("a/b/c"));
84 try expect(rootDir("a/b") == null);
85 try expect(rootDir("") == null);
86 }85 }
8786
88 pub fn deinit(d: *Diagnostics) void {87 pub fn deinit(d: *Diagnostics) void {
...@@ -625,7 +624,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)...@@ -625,7 +624,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
625 while (try iter.next()) |file| {624 while (try iter.next()) |file| {
626 const file_name = stripComponents(file.name, options.strip_components);625 const file_name = stripComponents(file.name, options.strip_components);
627 if (options.diagnostics) |d| {626 if (options.diagnostics) |d| {
628 try d.findRoot(file_name, file.kind);627 try d.findRoot(file_name);
629 }628 }
630629
631 switch (file.kind) {630 switch (file.kind) {
...@@ -1056,7 +1055,7 @@ test "pipeToFileSystem root_dir" {...@@ -1056,7 +1055,7 @@ test "pipeToFileSystem root_dir" {
10561055
1057 // there is no root_dir1056 // there is no root_dir
1058 try testing.expectEqual(0, diagnostics.root_dir.len);1057 try testing.expectEqual(0, diagnostics.root_dir.len);
1059 try testing.expectEqual(3, diagnostics.root_entries);1058 try testing.expectEqual(5, diagnostics.entries);
1060 }1059 }
10611060
1062 // with strip_components = 01061 // with strip_components = 0
...@@ -1078,10 +1077,25 @@ test "pipeToFileSystem root_dir" {...@@ -1078,10 +1077,25 @@ test "pipeToFileSystem root_dir" {
10781077
1079 // root_dir found1078 // root_dir found
1080 try testing.expectEqualStrings("example", diagnostics.root_dir);1079 try testing.expectEqualStrings("example", diagnostics.root_dir);
1081 try testing.expectEqual(1, diagnostics.root_entries);1080 try testing.expectEqual(6, diagnostics.entries);
1082 }1081 }
1083}1082}
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
1085fn normalizePath(bytes: []u8) []u8 {1099fn normalizePath(bytes: []u8) []u8 {
1086 const canonical_sep = std.fs.path.sep_posix;1100 const canonical_sep = std.fs.path.sep_posix;
1087 if (std.fs.path.sep == canonical_sep) return bytes;1101 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