Commit 035c1b6522
lib/std/tar.zig
@@ -46,6 +46,9 @@ pub const Diagnostics = struct {
file_name: []const u8,
file_type: Header.Kind,
},
+ components_outside_stripped_prefix: struct {
+ file_name: []const u8,
+ },
};
fn findRoot(d: *Diagnostics, path: []const u8) !void {
@@ -97,6 +100,9 @@ pub const Diagnostics = struct {
.unsupported_file_type => |info| {
d.allocator.free(info.file_name);
},
+ .components_outside_stripped_prefix => |info| {
+ d.allocator.free(info.file_name);
+ },
}
}
d.errors.deinit(d.allocator);
@@ -623,18 +629,24 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
while (try iter.next()) |file| {
const file_name = stripComponents(file.name, options.strip_components);
+ if (file_name.len == 0 and file.kind != .directory) {
+ const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix;
+ try d.errors.append(d.allocator, .{ .components_outside_stripped_prefix = .{
+ .file_name = try d.allocator.dupe(u8, file.name),
+ } });
+ continue;
+ }
if (options.diagnostics) |d| {
try d.findRoot(file_name);
}
switch (file.kind) {
.directory => {
- if (file_name.len != 0 and !options.exclude_empty_directories) {
+ if (file_name.len > 0 and !options.exclude_empty_directories) {
try dir.makePath(file_name);
}
},
.file => {
- if (file_name.len == 0) return error.BadFileName;
if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
defer fs_file.close();
try file.writeAll(fs_file);
@@ -647,7 +659,6 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
}
},
.sym_link => {
- if (file_name.len == 0) return error.BadFileName;
const link_name = file.link_name;
createDirAndSymlink(dir, link_name, file_name) catch |err| {
const d = options.diagnostics orelse return error.UnableToCreateSymLink;
@@ -1096,6 +1107,30 @@ test "findRoot without explicit root dir" {
try testing.expectEqualStrings("root", diagnostics.root_dir);
}
+test "pipeToFileSystem strip_components" {
+ const data = @embedFile("tar/testdata/example.tar");
+ var fbs = std.io.fixedBufferStream(data);
+ const reader = fbs.reader();
+
+ var tmp = testing.tmpDir(.{ .no_follow = true });
+ defer tmp.cleanup();
+ var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
+ defer diagnostics.deinit();
+
+ pipeToFileSystem(tmp.dir, reader, .{
+ .strip_components = 3,
+ .diagnostics = &diagnostics,
+ }) catch |err| {
+ // Skip on platform which don't support symlinks
+ if (err == error.UnableToCreateSymLink) return error.SkipZigTest;
+ return err;
+ };
+
+ try testing.expectEqual(2, diagnostics.errors.items.len);
+ try testing.expectEqualStrings("example/b/symlink", diagnostics.errors.items[0].components_outside_stripped_prefix.file_name);
+ try testing.expectEqualStrings("example/a/file", diagnostics.errors.items[1].components_outside_stripped_prefix.file_name);
+}
+
fn normalizePath(bytes: []u8) []u8 {
const canonical_sep = std.fs.path.sep_posix;
if (std.fs.path.sep == canonical_sep) return bytes;
src/Package/Fetch.zig
@@ -1189,6 +1189,7 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes
.unable_to_create_file => |i| res.unableToCreateFile(stripRoot(i.file_name, res.root_dir), i.code),
.unable_to_create_sym_link => |i| res.unableToCreateSymLink(stripRoot(i.file_name, res.root_dir), i.link_name, i.code),
.unsupported_file_type => |i| res.unsupportedFileType(stripRoot(i.file_name, res.root_dir), @intFromEnum(i.file_type)),
+ .components_outside_stripped_prefix => {}, // impossible with strip_components = 0
}
}
}