diff --git a/src/tar.c b/src/tar.c index b812baa5..49c1d00e 100644 --- a/src/tar.c +++ b/src/tar.c @@ -19,8 +19,10 @@ * 'A'-'Z' Vendor specific extensions(POSIX.1 - 1988) */ -#define TAR_TYPE_FILE '0' -#define TAR_TYPE_DIRECTORY '5' +#define TAR_TYPE_FILE '0' +#define TAR_TYPE_DIRECTORY '5' +#define TAR_TYPE_PAX_HEADER_X 'x' +#define TAR_TYPE_PAX_HEADER_G 'g' struct tar_header { /* Pre-posix */ @@ -70,31 +72,25 @@ struct tar_archive tar_parse(struct arena *arena, struct buffer data, struct str struct tar_archive archive = { 0 }; struct byte_reader br = br_create_from_buffer(data); - /* NOTE: For some reason the bottom of the tar is filled with 0s. - * Don't read when bytes left <= 1024. */ u64 num_files = 0; while (br_bytes_left(&br) > 1024) { - struct tar_header *header = br_read_raw(&br, sizeof(*header)); - if (!header) { - /* Overflow */ - ASSERT(false); - continue; - } + struct tar_header header = { 0 }; + br_read_to_struct(&br, &header); - if (!string_eq(STRING_FROM_ARRAY(header->ustar_indicator), STR("ustar\0"))) { + if (!string_eq(STRING_FROM_ARRAY(header.ustar_indicator), STR("ustar\0"))) { /* Invalid header */ ASSERT(false); continue; } - if (header->file_name_prefix[0] != 0) { + if (header.file_name_prefix[0] != 0) { /* Header file name prefix not supported */ ASSERT(false); continue; } - struct string file_size_oct_str = { .len = 11, .text = header->file_size }; + struct string file_size_oct_str = { .len = 11, .text = header.file_size }; u64 file_size = str_oct_to_u64(file_size_oct_str); struct buffer file_data = { @@ -106,14 +102,15 @@ struct tar_archive tar_parse(struct arena *arena, struct buffer data, struct str u64 remaining = (512 - (file_size % 512)) % 512; br_seek(&br, remaining); - b32 is_dir = header->file_type == TAR_TYPE_DIRECTORY; - if (!is_dir && header->file_type != TAR_TYPE_FILE) { + b32 is_dir = header.file_type == TAR_TYPE_DIRECTORY; + if (!is_dir && header.file_type != TAR_TYPE_FILE) { /* Unsupported type */ - ASSERT(false); + ASSERT(header.file_type == TAR_TYPE_PAX_HEADER_X || + header.file_type == TAR_TYPE_PAX_HEADER_G); continue; } - struct string file_name_cstr = string_from_cstr((char *)header->file_name); + struct string file_name_cstr = string_from_cstr((char *)header.file_name); if (file_name_cstr.len >= 2) { /* Chop off './' prefix */ file_name_cstr.len -= 2;