From 30a319be6dd14c773094e784c27b89b4f10622b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Anic=CC=81?= Date: Sun, 25 Feb 2024 12:03:23 +0100 Subject: [PATCH] std.tar improve error reporting Report file name which failed to create in all cases. --- lib/std/tar.zig | 75 +++++++++--------- lib/std/tar/test.zig | 28 +++++++ .../tar/testdata/pipe_to_file_system_test.tar | Bin 0 -> 10240 bytes 3 files changed, 64 insertions(+), 39 deletions(-) create mode 100644 lib/std/tar/testdata/pipe_to_file_system_test.tar diff --git a/lib/std/tar.zig b/lib/std/tar.zig index 166adf9908..a5fbbed104 100644 --- a/lib/std/tar.zig +++ b/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; diff --git a/lib/std/tar/test.zig b/lib/std/tar/test.zig index 912d0c3542..e568adb539 100644 --- a/lib/std/tar/test.zig +++ b/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); +} diff --git a/lib/std/tar/testdata/pipe_to_file_system_test.tar b/lib/std/tar/testdata/pipe_to_file_system_test.tar new file mode 100644 index 0000000000000000000000000000000000000000..0c424166ae43d2e56dcbb5410771c58c463aab80 GIT binary patch literal 10240 zcmeH}K@P$o5JfpkPhbneaGa(ZOo&z+!9{N`Q)6^dw24Gr{MnFn+6jGs{=nb|*Tz%3 z^9R?4F+|t5(S=xxa?zx))`+x7YntbkQyfBSLqt+pN_lCdB2k%gTgX?sgxH;{O8D;R zxB1uJ=3jjJ9&|E63Au)vG;*OK*LYv})#wt1m{82f`i?myqgO@I6B`}-W=6vxB= ztiNiMwxUw2Ro&G*nLgh`wgUV=KmWTQ`Cq1U0{+joYw1MR{{@Z51}DXVddhq|e|6M=CvCIr${THAA)BTTBY8Tx9=K2-SKmY_l00ck)1V8`;KmY_l00ck) b1V8`;KmY_l00ck)1V8`;KmY_lAVc5^NJXpY literal 0 HcmV?d00001