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 {
3131 file_name: []const u8,
3232 link_name: []const u8,
3333 },
34 unable_to_create_file: struct {
35 code: anyerror,
36 file_name: []const u8,
37 },
3438 unsupported_file_type: struct {
3539 file_name: []const u8,
3640 file_type: Header.FileType,
......@@ -44,6 +48,9 @@ pub const Options = struct {
4448 d.allocator.free(info.file_name);
4549 d.allocator.free(info.link_name);
4650 },
51 .unable_to_create_file => |info| {
52 d.allocator.free(info.file_name);
53 },
4754 .unsupported_file_type => |info| {
4855 d.allocator.free(info.file_name);
4956 },
......@@ -211,18 +218,34 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
211218 if (file_size == 0 and unstripped_file_name.len == 0) return;
212219 const file_name = try stripComponents(unstripped_file_name, options.strip_components);
213220
214 if (std.fs.path.dirname(file_name)) |dir_name| {
215 try dir.makePath(dir_name);
216 }
217 var file = try dir.createFile(file_name, .{});
218 defer file.close();
221 var file = dir.createFile(file_name, .{}) catch |err| switch (err) {
222 error.FileNotFound => again: {
223 const code = code: {
224 if (std.fs.path.dirname(file_name)) |dir_name| {
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
220243 var file_off: usize = 0;
221244 while (true) {
222245 const temp = try buffer.readChunk(reader, @intCast(rounded_file_size + 512 - file_off));
223246 if (temp.len == 0) return error.UnexpectedEndOfStream;
224247 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
227250 file_off += slice.len;
228251 buffer.advance(slice.len);
......@@ -275,13 +298,26 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
275298 },
276299 .hard_link => return error.TarUnsupportedFileType,
277300 .symbolic_link => {
301 // The file system path of the symbolic link.
278302 const file_name = try stripComponents(unstripped_file_name, options.strip_components);
303 // The data inside the symbolic link.
279304 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 };
282318 const d = options.diagnostics orelse return error.UnableToCreateSymLink;
283319 try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{
284 .code = err,
320 .code = code,
285321 .file_name = try d.allocator.dupe(u8, file_name),
286322 .link_name = try d.allocator.dupe(u8, link_name),
287323 } });
src/Package/Fetch.zig+7
......@@ -1041,6 +1041,13 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!void {
10411041 }),
10421042 }));
10431043 },
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 },
10441051 .unsupported_file_type => |info| {
10451052 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
10461053 .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{