Commit 30a319be6d
Changed files (3)
lib
std
tar
lib/std/tar/testdata/pipe_to_file_system_test.tar
Binary file
lib/std/tar/test.zig
@@ -452,3 +452,31 @@ test "tar case sensitivity" {
try testing.expect((try root.dir.statFile("alacritty/darkermatrix.yml")).kind == .file);
try testing.expect((try root.dir.statFile("alacritty/Darkermatrix.yml")).kind == .file);
}
+
+test "tar pipeToFileSystem" {
+ // $ tar tvf
+ // pipe_to_file_system_test/
+ // pipe_to_file_system_test/b/
+ // pipe_to_file_system_test/b/symlink -> ../a/file
+ // pipe_to_file_system_test/a/
+ // pipe_to_file_system_test/a/file
+ // pipe_to_file_system_test/empty/
+ const data = @embedFile("testdata/pipe_to_file_system_test.tar");
+ var fsb = std.io.fixedBufferStream(data);
+
+ var root = std.testing.tmpDir(.{ .no_follow = true });
+ defer root.cleanup();
+
+ try tar.pipeToFileSystem(root.dir, fsb.reader(), .{
+ .mode_mode = .ignore,
+ .strip_components = 1,
+ .exclude_empty_directories = true,
+ });
+
+ try testing.expectError(error.FileNotFound, root.dir.statFile("empty"));
+ try testing.expect((try root.dir.statFile("a/file")).kind == .file);
+ // TODO is there better way to test symlink
+ try testing.expect((try root.dir.statFile("b/symlink")).kind == .file); // statFile follows symlink
+ var buf: [8]u8 = undefined;
+ _ = try root.dir.readLink("b/symlink", &buf);
+}
lib/std/tar.zig
@@ -544,31 +544,15 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
const file_name = stripComponents(file.name, options.strip_components);
if (file_name.len == 0) return error.BadFileName;
- const fs_file = dir.createFile(file_name, .{ .exclusive = true }) catch |err| switch (err) {
- error.FileNotFound => again: {
- const code = code: {
- if (std.fs.path.dirname(file_name)) |dir_name| {
- dir.makePath(dir_name) catch |code| break :code code;
- break :again dir.createFile(file_name, .{ .exclusive = true }) catch |code| {
- break :code code;
- };
- }
- break :code err;
- };
- const d = options.diagnostics orelse return error.UnableToCreateFile;
- try d.errors.append(d.allocator, .{ .unable_to_create_file = .{
- .code = code,
- .file_name = try d.allocator.dupe(u8, file_name),
- } });
- break :again null;
- },
- else => |e| return e,
- };
- defer if (fs_file) |f| f.close();
-
- if (fs_file) |f| {
- try file.write(f);
- } else {
+ if (createDirAndFile(dir, file_name)) |fs_file| {
+ defer fs_file.close();
+ try file.write(fs_file);
+ } else |err| {
+ const d = options.diagnostics orelse return err;
+ try d.errors.append(d.allocator, .{ .unable_to_create_file = .{
+ .code = err,
+ .file_name = try d.allocator.dupe(u8, file_name),
+ } });
try file.skip();
}
},
@@ -579,21 +563,10 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
// The data inside the symbolic link.
const link_name = file.link_name;
- dir.symLink(link_name, file_name, .{}) catch |err| again: {
- const code = code: {
- if (err == error.FileNotFound) {
- if (std.fs.path.dirname(file_name)) |dir_name| {
- dir.makePath(dir_name) catch |code| break :code code;
- break :again dir.symLink(link_name, file_name, .{}) catch |code| {
- break :code code;
- };
- }
- }
- break :code err;
- };
- const d = options.diagnostics orelse return error.UnableToCreateSymLink;
+ createDirAndSymlink(dir, link_name, file_name) catch |err| {
+ const d = options.diagnostics orelse return err;
try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{
- .code = code,
+ .code = err,
.file_name = try d.allocator.dupe(u8, file_name),
.link_name = try d.allocator.dupe(u8, link_name),
} });
@@ -604,6 +577,30 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
}
}
+fn createDirAndFile(dir: std.fs.Dir, file_name: []const u8) !std.fs.File {
+ const fs_file = dir.createFile(file_name, .{ .exclusive = true }) catch |err| {
+ if (err == error.FileNotFound) {
+ if (std.fs.path.dirname(file_name)) |dir_name| {
+ try dir.makePath(dir_name);
+ return try dir.createFile(file_name, .{ .exclusive = true });
+ }
+ }
+ return err;
+ };
+ return fs_file;
+}
+
+fn createDirAndSymlink(dir: std.fs.Dir, link_name: []const u8, file_name: []const u8) !void {
+ dir.symLink(link_name, file_name, .{}) catch |err| {
+ if (err == error.FileNotFound) {
+ if (std.fs.path.dirname(file_name)) |dir_name| {
+ try dir.makePath(dir_name);
+ try dir.symLink(link_name, file_name, .{});
+ }
+ }
+ };
+}
+
fn stripComponents(path: []const u8, count: u32) []const u8 {
var i: usize = 0;
var c = count;