Merge pull request #19615 from ianic/tar_diagnostic

std.tar: add strip components error to diagnostics
This commit is contained in:
Andrew Kelley 2024-07-03 21:29:04 -04:00 committed by GitHub
commit 768b17755e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 3 deletions

View File

@ -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;

View File

@ -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 => unreachable, // unreachable with strip_components = 0
}
}
}