| ... | ... | @@ -258,10 +258,15 @@ pub fn iterator(reader: anytype, options: IteratorOptions) Iterator(@TypeOf(read |
| 258 | 258 | .file_name_buffer = options.file_name_buffer, |
| 259 | 259 | .link_name_buffer = options.link_name_buffer, |
| 260 | 260 | .padding = 0, |
| 261 | | .file = undefined, |
| 262 | 261 | }; |
| 263 | 262 | } |
| 264 | 263 | |
| 264 | pub const FileKind = enum { |
| 265 | directory, |
| 266 | sym_link, |
| 267 | file, |
| 268 | }; |
| 269 | |
| 265 | 270 | fn Iterator(comptime ReaderType: type) type { |
| 266 | 271 | return struct { |
| 267 | 272 | reader: ReaderType, |
| ... | ... | @@ -274,35 +279,43 @@ fn Iterator(comptime ReaderType: type) type { |
| 274 | 279 | |
| 275 | 280 | // bytes of padding to the end of the block |
| 276 | 281 | padding: usize, |
| 277 | | // current tar file |
| 278 | | file: File, |
| 282 | // not consumed bytes of file from last next iteration |
| 283 | unread_file_bytes: usize = 0, |
| 279 | 284 | |
| 280 | 285 | pub const File = struct { |
| 281 | 286 | name: []const u8, // name of file, symlink or directory |
| 282 | 287 | link_name: []const u8, // target name of symlink |
| 283 | | size: u64, // size of the file in bytes |
| 284 | | mode: u32, |
| 285 | | kind: Header.Kind, |
| 288 | size: u64 = 0, // size of the file in bytes |
| 289 | mode: u32 = 0, |
| 290 | kind: FileKind = .file, |
| 286 | 291 | |
| 292 | unread_bytes: *usize, |
| 287 | 293 | reader: ReaderType, |
| 288 | 294 | |
| 295 | pub const Reader = std.io.Reader(*Self, ReaderType.Error, read); |
| 296 | |
| 297 | pub fn reader(self: *Self) Reader { |
| 298 | return .{ .context = self }; |
| 299 | } |
| 300 | |
| 301 | pub fn read(self: *Self, dest: []u8) ReaderType.Error!usize { |
| 302 | const buf = dest[0..@min(dest.len, self.unread_size.*)]; |
| 303 | const n = try self.reader.read(buf); |
| 304 | self.unread_size.* -= n; |
| 305 | return n; |
| 306 | } |
| 307 | |
| 289 | 308 | // Writes file content to writer. |
| 290 | | pub fn write(self: File, writer: anytype) !void { |
| 309 | pub fn writeAll(self: File, writer: anytype) !void { |
| 291 | 310 | var buffer: [4096]u8 = undefined; |
| 292 | 311 | |
| 293 | | var n: u64 = 0; |
| 294 | | while (n < self.size) { |
| 295 | | const buf = buffer[0..@min(buffer.len, self.size - n)]; |
| 312 | while (self.unread_bytes.* > 0) { |
| 313 | const buf = buffer[0..@min(buffer.len, self.unread_bytes.*)]; |
| 296 | 314 | try self.reader.readNoEof(buf); |
| 297 | 315 | try writer.writeAll(buf); |
| 298 | | n += buf.len; |
| 316 | self.unread_bytes.* -= buf.len; |
| 299 | 317 | } |
| 300 | 318 | } |
| 301 | | |
| 302 | | // Skips file content. Advances reader. |
| 303 | | pub fn skip(self: File) !void { |
| 304 | | try self.reader.skipBytes(self.size, .{}); |
| 305 | | } |
| 306 | 319 | }; |
| 307 | 320 | |
| 308 | 321 | const Self = @This(); |
| ... | ... | @@ -326,14 +339,12 @@ fn Iterator(comptime ReaderType: type) type { |
| 326 | 339 | return nullStr(buf); |
| 327 | 340 | } |
| 328 | 341 | |
| 329 | | fn initFile(self: *Self) void { |
| 330 | | self.file = .{ |
| 342 | fn newFile(self: *Self) File { |
| 343 | return .{ |
| 331 | 344 | .name = self.file_name_buffer[0..0], |
| 332 | 345 | .link_name = self.link_name_buffer[0..0], |
| 333 | | .size = 0, |
| 334 | | .kind = .normal, |
| 335 | | .mode = 0, |
| 336 | 346 | .reader = self.reader, |
| 347 | .unread_bytes = &self.unread_file_bytes, |
| 337 | 348 | }; |
| 338 | 349 | } |
| 339 | 350 | |
| ... | ... | @@ -350,7 +361,12 @@ fn Iterator(comptime ReaderType: type) type { |
| 350 | 361 | /// loop iterates through one or more entries until it collects a all |
| 351 | 362 | /// file attributes. |
| 352 | 363 | pub fn next(self: *Self) !?File { |
| 353 | | self.initFile(); |
| 364 | if (self.unread_file_bytes > 0) { |
| 365 | // If file content was not consumed by caller |
| 366 | try self.reader.skipBytes(self.unread_file_bytes, .{}); |
| 367 | self.unread_file_bytes = 0; |
| 368 | } |
| 369 | var file: File = self.newFile(); |
| 354 | 370 | |
| 355 | 371 | while (try self.readHeader()) |header| { |
| 356 | 372 | const kind = header.kind(); |
| ... | ... | @@ -360,46 +376,52 @@ fn Iterator(comptime ReaderType: type) type { |
| 360 | 376 | switch (kind) { |
| 361 | 377 | // File types to retrun upstream |
| 362 | 378 | .directory, .normal, .symbolic_link => { |
| 363 | | self.file.kind = kind; |
| 364 | | self.file.mode = try header.mode(); |
| 379 | file.kind = switch (kind) { |
| 380 | .directory => .directory, |
| 381 | .normal => .file, |
| 382 | .symbolic_link => .sym_link, |
| 383 | else => unreachable, |
| 384 | }; |
| 385 | file.mode = try header.mode(); |
| 365 | 386 | |
| 366 | 387 | // set file attributes if not already set by prefix/extended headers |
| 367 | | if (self.file.size == 0) { |
| 368 | | self.file.size = size; |
| 388 | if (file.size == 0) { |
| 389 | file.size = size; |
| 369 | 390 | } |
| 370 | | if (self.file.link_name.len == 0) { |
| 371 | | self.file.link_name = try header.linkName(self.link_name_buffer); |
| 391 | if (file.link_name.len == 0) { |
| 392 | file.link_name = try header.linkName(self.link_name_buffer); |
| 372 | 393 | } |
| 373 | | if (self.file.name.len == 0) { |
| 374 | | self.file.name = try header.fullName(self.file_name_buffer); |
| 394 | if (file.name.len == 0) { |
| 395 | file.name = try header.fullName(self.file_name_buffer); |
| 375 | 396 | } |
| 376 | 397 | |
| 377 | | self.padding = blockPadding(self.file.size); |
| 378 | | return self.file; |
| 398 | self.padding = blockPadding(file.size); |
| 399 | self.unread_file_bytes = file.size; |
| 400 | return file; |
| 379 | 401 | }, |
| 380 | 402 | // Prefix header types |
| 381 | 403 | .gnu_long_name => { |
| 382 | | self.file.name = try self.readString(@intCast(size), self.file_name_buffer); |
| 404 | file.name = try self.readString(@intCast(size), self.file_name_buffer); |
| 383 | 405 | }, |
| 384 | 406 | .gnu_long_link => { |
| 385 | | self.file.link_name = try self.readString(@intCast(size), self.link_name_buffer); |
| 407 | file.link_name = try self.readString(@intCast(size), self.link_name_buffer); |
| 386 | 408 | }, |
| 387 | 409 | .extended_header => { |
| 388 | 410 | // Use just attributes from last extended header. |
| 389 | | self.initFile(); |
| 411 | file = self.newFile(); |
| 390 | 412 | |
| 391 | 413 | var rdr = paxIterator(self.reader, @intCast(size)); |
| 392 | 414 | while (try rdr.next()) |attr| { |
| 393 | 415 | switch (attr.kind) { |
| 394 | 416 | .path => { |
| 395 | | self.file.name = try attr.value(self.file_name_buffer); |
| 417 | file.name = try attr.value(self.file_name_buffer); |
| 396 | 418 | }, |
| 397 | 419 | .linkpath => { |
| 398 | | self.file.link_name = try attr.value(self.link_name_buffer); |
| 420 | file.link_name = try attr.value(self.link_name_buffer); |
| 399 | 421 | }, |
| 400 | 422 | .size => { |
| 401 | 423 | var buf: [pax_max_size_attr_len]u8 = undefined; |
| 402 | | self.file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10); |
| 424 | file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10); |
| 403 | 425 | }, |
| 404 | 426 | } |
| 405 | 427 | } |
| ... | ... | @@ -574,24 +596,23 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi |
| 574 | 596 | try dir.makePath(file_name); |
| 575 | 597 | } |
| 576 | 598 | }, |
| 577 | | .normal => { |
| 599 | .file => { |
| 578 | 600 | if (file.size == 0 and file.name.len == 0) return; |
| 579 | 601 | const file_name = stripComponents(file.name, options.strip_components); |
| 580 | 602 | if (file_name.len == 0) return error.BadFileName; |
| 581 | 603 | |
| 582 | 604 | if (createDirAndFile(dir, file_name)) |fs_file| { |
| 583 | 605 | defer fs_file.close(); |
| 584 | | try file.write(fs_file); |
| 606 | try file.writeAll(fs_file); |
| 585 | 607 | } else |err| { |
| 586 | 608 | const d = options.diagnostics orelse return err; |
| 587 | 609 | try d.errors.append(d.allocator, .{ .unable_to_create_file = .{ |
| 588 | 610 | .code = err, |
| 589 | 611 | .file_name = try d.allocator.dupe(u8, file_name), |
| 590 | 612 | } }); |
| 591 | | try file.skip(); |
| 592 | 613 | } |
| 593 | 614 | }, |
| 594 | | .symbolic_link => { |
| 615 | .sym_link => { |
| 595 | 616 | // The file system path of the symbolic link. |
| 596 | 617 | const file_name = stripComponents(file.name, options.strip_components); |
| 597 | 618 | if (file_name.len == 0) return error.BadFileName; |
| ... | ... | @@ -607,7 +628,6 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi |
| 607 | 628 | } }); |
| 608 | 629 | }; |
| 609 | 630 | }, |
| 610 | | else => unreachable, |
| 611 | 631 | } |
| 612 | 632 | } |
| 613 | 633 | } |