@@ -46,6 +46,9 @@ pub const Diagnostics = struct {
46
46
file_name : []const u8 ,
47
47
file_type : Header.Kind ,
48
48
},
49
+ components_outside_stripped_prefix : struct {
50
+ file_name : []const u8 ,
51
+ },
49
52
};
50
53
51
54
fn findRoot (d : * Diagnostics , path : []const u8 ) ! void {
@@ -97,6 +100,9 @@ pub const Diagnostics = struct {
97
100
.unsupported_file_type = > | info | {
98
101
d .allocator .free (info .file_name );
99
102
},
103
+ .components_outside_stripped_prefix = > | info | {
104
+ d .allocator .free (info .file_name );
105
+ },
100
106
}
101
107
}
102
108
d .errors .deinit (d .allocator );
@@ -623,18 +629,24 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
623
629
624
630
while (try iter .next ()) | file | {
625
631
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
+ }
626
639
if (options .diagnostics ) | d | {
627
640
try d .findRoot (file_name );
628
641
}
629
642
630
643
switch (file .kind ) {
631
644
.directory = > {
632
- if (file_name .len != 0 and ! options .exclude_empty_directories ) {
645
+ if (file_name .len > 0 and ! options .exclude_empty_directories ) {
633
646
try dir .makePath (file_name );
634
647
}
635
648
},
636
649
.file = > {
637
- if (file_name .len == 0 ) return error .BadFileName ;
638
650
if (createDirAndFile (dir , file_name , fileMode (file .mode , options ))) | fs_file | {
639
651
defer fs_file .close ();
640
652
try file .writeAll (fs_file );
@@ -647,7 +659,6 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
647
659
}
648
660
},
649
661
.sym_link = > {
650
- if (file_name .len == 0 ) return error .BadFileName ;
651
662
const link_name = file .link_name ;
652
663
createDirAndSymlink (dir , link_name , file_name ) catch | err | {
653
664
const d = options .diagnostics orelse return error .UnableToCreateSymLink ;
@@ -1096,6 +1107,30 @@ test "findRoot without explicit root dir" {
1096
1107
try testing .expectEqualStrings ("root" , diagnostics .root_dir );
1097
1108
}
1098
1109
1110
+ test "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
+
1099
1134
fn normalizePath (bytes : []u8 ) []u8 {
1100
1135
const canonical_sep = std .fs .path .sep_posix ;
1101
1136
if (std .fs .path .sep == canonical_sep ) return bytes ;
0 commit comments