| ... | @@ -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); |
| 213 | | 220 | |
| 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(); |
| 219 | | 242 | |
| 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); |
| 226 | | 249 | |
| 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(); |
| 280 | | 305 | |
| 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 | } }); |