diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-10-07 23:09:39 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-10-08 16:54:31 -0700 |
| commit | 7b25d050e64fd91ec7df17f29f3a1b84e1431241 (patch) | |
| tree | 86458208ef0dc07a626285dfc0424d5b860af7ee /lib/std | |
| parent | e5c2a7dbca103b0c61bebaff95c5d5a5b777bd59 (diff) | |
| download | zig-7b25d050e64fd91ec7df17f29f3a1b84e1431241.tar.gz zig-7b25d050e64fd91ec7df17f29f3a1b84e1431241.zip | |
std.tar: fix creation of symlinks with omit_empty_directories
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/tar.zig | 52 |
1 files changed, 44 insertions, 8 deletions
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), } }); |
