mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
std.tar: add strip components error to diagnostics
This was the only kind of error which was raised in pipeToFileSystem and not added to Diagnostics. Shell tar silently ignores paths which are stripped out when used with `--strip-components` switch. This enables that same behavior, errors will be collected in diagnostics but caller is free to ignore that type of diagnostics errors. Enables use case where caller knows structure of the tar file and want to extract only some deeply nested folders ignoring upper files/folders. Fixes: #17620 by giving caller options: - not provide diagnostic and get errors - provide diagnostics and analyze errors - provide diagnostics and ignore errors
This commit is contained in:
parent
fe66a12a23
commit
035c1b6522
@ -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;
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user