#include #include #include #include #include #include TarStream::TarStream(void* base, usize size) : m_base(base), m_pos(base), m_size(size) { } void TarStream::initialize(void* base, usize size) { m_base = m_pos = base; m_size = size; m_offset = 0; } void TarStream::rewind() { m_pos = m_base; m_offset = 0; } void TarStream::read_header(TarHeader* out, bool& success) { if ((m_offset + 512) > m_size) { success = false; return; }; memcpy(out, m_pos, sizeof(TarHeader)); m_pos = offset_ptr(m_pos, 512); m_offset += 512; success = true; } Result TarStream::parse_header(const TarStream::TarHeader* hdr) { Entry entry; char size[13]; strlcpy(size, hdr->size, 13); entry.size = parse_unsigned_integer(size, nullptr, 8); entry.mode = (mode_t)parse_unsigned_integer(hdr->mode, nullptr, 8); entry.uid = (mode_t)parse_unsigned_integer(hdr->uid, nullptr, 8); entry.gid = (mode_t)parse_unsigned_integer(hdr->gid, nullptr, 8); entry.m_data = (u8*)m_base + m_offset; switch (hdr->typeflag) { case '\0': case '0': entry.type = EntryType::RegularFile; break; case '5': entry.type = EntryType::Directory; break; default: entry.type = EntryType::Unimplemented; break; } if (!strlen(hdr->prefix)) entry.name = TRY(String::from_string_view(StringView::from_fixed_size_cstring(hdr->name, sizeof(hdr->name)))); else { StringBuilder sb; TRY(sb.add(StringView::from_fixed_size_cstring(hdr->prefix, sizeof(hdr->prefix)))); TRY(sb.add('/')); TRY(sb.add(StringView::from_fixed_size_cstring(hdr->name, sizeof(hdr->name)))); entry.name = TRY(sb.string()); } if (entry.size) { m_pos = offset_ptr(m_pos, align_up<512ul>(entry.size)); m_offset += align_up<512ul>(entry.size); } return entry; } void TarStream::find_valid_header(TarStream::TarHeader* out, bool& success) { success = false; while (true) { read_header(out, success); if (!success) return; if (!memcmp(out->magic, "ustar", 5)) { success = true; return; } } } Result TarStream::read_next_entry(Entry& out) { bool success; TarHeader header; find_valid_header(&header, success); if (!success) return false; out = TRY(parse_header(&header)); return true; }