| ... | ... | @@ -31,6 +31,10 @@ pub const Options = struct { |
| 31 | 31 | file_name: []const u8, |
| 32 | 32 | link_name: []const u8, |
| 33 | 33 | }, |
| 34 | unable_to_create_file: struct { |
| 35 | code: anyerror, |
| 36 | file_name: []const u8, |
| 37 | }, |
| 34 | 38 | unsupported_file_type: struct { |
| 35 | 39 | file_name: []const u8, |
| 36 | 40 | file_type: Header.FileType, |
| ... | ... | @@ -44,6 +48,9 @@ pub const Options = struct { |
| 44 | 48 | d.allocator.free(info.file_name); |
| 45 | 49 | d.allocator.free(info.link_name); |
| 46 | 50 | }, |
| 51 | .unable_to_create_file => |info| { |
| 52 | d.allocator.free(info.file_name); |
| 53 | }, |
| 47 | 54 | .unsupported_file_type => |info| { |
| 48 | 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 | 218 | if (file_size == 0 and unstripped_file_name.len == 0) return; |
| 212 | 219 | const file_name = try stripComponents(unstripped_file_name, options.strip_components); |
| 213 | 220 | |
| 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(); |
| 219 | 242 | |
| 220 | 243 | var file_off: usize = 0; |
| 221 | 244 | while (true) { |
| 222 | 245 | const temp = try buffer.readChunk(reader, @intCast(rounded_file_size + 512 - file_off)); |
| 223 | 246 | if (temp.len == 0) return error.UnexpectedEndOfStream; |
| 224 | 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 | 250 | file_off += slice.len; |
| 228 | 251 | buffer.advance(slice.len); |
| ... | ... | @@ -275,13 +298,26 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi |
| 275 | 298 | }, |
| 276 | 299 | .hard_link => return error.TarUnsupportedFileType, |
| 277 | 300 | .symbolic_link => { |
| 301 | // The file system path of the symbolic link. |
| 278 | 302 | const file_name = try stripComponents(unstripped_file_name, options.strip_components); |
| 303 | // The data inside the symbolic link. |
| 279 | 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 | 318 | const d = options.diagnostics orelse return error.UnableToCreateSymLink; |
| 283 | 319 | try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{ |
| 284 | | .code = err, |
| 320 | .code = code, |
| 285 | 321 | .file_name = try d.allocator.dupe(u8, file_name), |
| 286 | 322 | .link_name = try d.allocator.dupe(u8, link_name), |
| 287 | 323 | } }); |