diff --git a/lib/std/tar.zig b/lib/std/tar.zig index 9ed69730aa..bdbec87e39 100644 --- a/lib/std/tar.zig +++ b/lib/std/tar.zig @@ -31,6 +31,10 @@ pub const Options = struct { file_name: []const u8, link_name: []const u8, }, + unable_to_create_file: struct { + code: anyerror, + file_name: []const u8, + }, unsupported_file_type: struct { file_name: []const u8, file_type: Header.FileType, @@ -44,6 +48,9 @@ pub const Options = struct { d.allocator.free(info.file_name); d.allocator.free(info.link_name); }, + .unable_to_create_file => |info| { + d.allocator.free(info.file_name); + }, .unsupported_file_type => |info| { d.allocator.free(info.file_name); }, @@ -211,18 +218,34 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi if (file_size == 0 and unstripped_file_name.len == 0) return; const file_name = try stripComponents(unstripped_file_name, options.strip_components); - if (std.fs.path.dirname(file_name)) |dir_name| { - try dir.makePath(dir_name); - } - var file = try dir.createFile(file_name, .{}); - defer file.close(); + var file = dir.createFile(file_name, .{}) 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, .{}) 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 (file) |f| f.close(); var file_off: usize = 0; while (true) { const temp = try buffer.readChunk(reader, @intCast(rounded_file_size + 512 - file_off)); if (temp.len == 0) return error.UnexpectedEndOfStream; const slice = temp[0..@intCast(@min(file_size - file_off, temp.len))]; - try file.writeAll(slice); + if (file) |f| try f.writeAll(slice); file_off += slice.len; buffer.advance(slice.len); @@ -275,13 +298,26 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi }, .hard_link => return error.TarUnsupportedFileType, .symbolic_link => { + // The file system path of the symbolic link. const file_name = try stripComponents(unstripped_file_name, options.strip_components); + // The data inside the symbolic link. const link_name = header.linkName(); - dir.symLink(link_name, file_name, .{}) catch |err| { + 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; try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{ - .code = err, + .code = code, .file_name = try d.allocator.dupe(u8, file_name), .link_name = try d.allocator.dupe(u8, link_name), } }); diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index ace1871d42..0cbfb973db 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -1041,6 +1041,13 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!void { }), })); }, + .unable_to_create_file => |info| { + eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{ + .msg = try eb.printString("unable to create file '{s}': {s}", .{ + info.file_name, @errorName(info.code), + }), + })); + }, .unsupported_file_type => |info| { eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{ .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{