authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-07 23:09:39-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-08 16:54:31-07:00
log7b25d050e64fd91ec7df17f29f3a1b84e1431241
tree86458208ef0dc07a626285dfc0424d5b860af7ee
parente5c2a7dbca103b0c61bebaff95c5d5a5b777bd59

std.tar: fix creation of symlinks with omit_empty_directories


2 files changed, 51 insertions(+), 8 deletions(-)

lib/std/tar.zig+44-8
...@@ -31,6 +31,10 @@ pub const Options = struct {...@@ -31,6 +31,10 @@ pub const Options = struct {
31 file_name: []const u8,31 file_name: []const u8,
32 link_name: []const u8,32 link_name: []const u8,
33 },33 },
34 unable_to_create_file: struct {
35 code: anyerror,
36 file_name: []const u8,
37 },
34 unsupported_file_type: struct {38 unsupported_file_type: struct {
35 file_name: []const u8,39 file_name: []const u8,
36 file_type: Header.FileType,40 file_type: Header.FileType,
...@@ -44,6 +48,9 @@ pub const Options = struct {...@@ -44,6 +48,9 @@ pub const Options = struct {
44 d.allocator.free(info.file_name);48 d.allocator.free(info.file_name);
45 d.allocator.free(info.link_name);49 d.allocator.free(info.link_name);
46 },50 },
51 .unable_to_create_file => |info| {
52 d.allocator.free(info.file_name);
53 },
47 .unsupported_file_type => |info| {54 .unsupported_file_type => |info| {
48 d.allocator.free(info.file_name);55 d.allocator.free(info.file_name);
49 },56 },
...@@ -211,18 +218,34 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi...@@ -211,18 +218,34 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
211 if (file_size == 0 and unstripped_file_name.len == 0) return;218 if (file_size == 0 and unstripped_file_name.len == 0) return;
212 const file_name = try stripComponents(unstripped_file_name, options.strip_components);219 const file_name = try stripComponents(unstripped_file_name, options.strip_components);
213220
214 if (std.fs.path.dirname(file_name)) |dir_name| {221 var file = dir.createFile(file_name, .{}) catch |err| switch (err) {
215 try dir.makePath(dir_name);222 error.FileNotFound => again: {
216 }223 const code = code: {
217 var file = try dir.createFile(file_name, .{});224 if (std.fs.path.dirname(file_name)) |dir_name| {
218 defer file.close();225 dir.makePath(dir_name) catch |code| break :code code;
226 break :again dir.createFile(file_name, .{}) catch |code| {
227 break :code code;
228 };
229 }
230 break :code err;
231 };
232 const d = options.diagnostics orelse return error.UnableToCreateFile;
233 try d.errors.append(d.allocator, .{ .unable_to_create_file = .{
234 .code = code,
235 .file_name = try d.allocator.dupe(u8, file_name),
236 } });
237 break :again null;
238 },
239 else => |e| return e,
240 };
241 defer if (file) |f| f.close();
219242
220 var file_off: usize = 0;243 var file_off: usize = 0;
221 while (true) {244 while (true) {
222 const temp = try buffer.readChunk(reader, @intCast(rounded_file_size + 512 - file_off));245 const temp = try buffer.readChunk(reader, @intCast(rounded_file_size + 512 - file_off));
223 if (temp.len == 0) return error.UnexpectedEndOfStream;246 if (temp.len == 0) return error.UnexpectedEndOfStream;
224 const slice = temp[0..@intCast(@min(file_size - file_off, temp.len))];247 const slice = temp[0..@intCast(@min(file_size - file_off, temp.len))];
225 try file.writeAll(slice);248 if (file) |f| try f.writeAll(slice);
226249
227 file_off += slice.len;250 file_off += slice.len;
228 buffer.advance(slice.len);251 buffer.advance(slice.len);
...@@ -275,13 +298,26 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi...@@ -275,13 +298,26 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
275 },298 },
276 .hard_link => return error.TarUnsupportedFileType,299 .hard_link => return error.TarUnsupportedFileType,
277 .symbolic_link => {300 .symbolic_link => {
301 // The file system path of the symbolic link.
278 const file_name = try stripComponents(unstripped_file_name, options.strip_components);302 const file_name = try stripComponents(unstripped_file_name, options.strip_components);
303 // The data inside the symbolic link.
279 const link_name = header.linkName();304 const link_name = header.linkName();
280305
281 dir.symLink(link_name, file_name, .{}) catch |err| {306 dir.symLink(link_name, file_name, .{}) catch |err| again: {
307 const code = code: {
308 if (err == error.FileNotFound) {
309 if (std.fs.path.dirname(file_name)) |dir_name| {
310 dir.makePath(dir_name) catch |code| break :code code;
311 break :again dir.symLink(link_name, file_name, .{}) catch |code| {
312 break :code code;
313 };
314 }
315 }
316 break :code err;
317 };
282 const d = options.diagnostics orelse return error.UnableToCreateSymLink;318 const d = options.diagnostics orelse return error.UnableToCreateSymLink;
283 try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{319 try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{
284 .code = err,320 .code = code,
285 .file_name = try d.allocator.dupe(u8, file_name),321 .file_name = try d.allocator.dupe(u8, file_name),
286 .link_name = try d.allocator.dupe(u8, link_name),322 .link_name = try d.allocator.dupe(u8, link_name),
287 } });323 } });
src/Package/Fetch.zig+7
...@@ -1041,6 +1041,13 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!void {...@@ -1041,6 +1041,13 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!void {
1041 }),1041 }),
1042 }));1042 }));
1043 },1043 },
1044 .unable_to_create_file => |info| {
1045 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1046 .msg = try eb.printString("unable to create file '{s}': {s}", .{
1047 info.file_name, @errorName(info.code),
1048 }),
1049 }));
1050 },
1044 .unsupported_file_type => |info| {1051 .unsupported_file_type => |info| {
1045 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{1052 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1046 .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{1053 .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{