#define _LUNA_SYSTEM_ERROR_EXTENSIONS #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; } Result TarStream::read_header(TarHeader* out) { if ((m_offset + 512) > m_size) return err(0); memcpy(out, m_pos, sizeof(TarHeader)); m_pos = offset_ptr(m_pos, 512); m_offset += 512; return {}; } Result TarStream::parse_header(const TarStream::TarHeader* hdr) { Entry entry; char size[13]; nullcpy(size, hdr->size, 12); entry.size = parse_unsigned_integer(size, nullptr, 8); entry.pos = m_offset; switch (hdr->typeflag) { case '\0': case '0': entry.type = EntryType::RegularFile; break; case '5': entry.type = EntryType::Directory; break; default: return err(EFIXME); } if (!strlen(hdr->prefix)) { nullcpy(entry.name, hdr->name, 100); } else { return err(EFIXME); } if (entry.size) { m_pos = offset_ptr(m_pos, align_up<512ul>(entry.size)); m_offset += align_up<512ul>(entry.size); } return entry; } Result TarStream::find_valid_header(TarStream::TarHeader* out, bool& success) { success = false; while (true) { TRY(read_header(out)); if (!memcmp(out->magic, "ustar", 5)) { success = true; return {}; } } } // FIXME: How do we know whether an error is an error or just EOF? Returning an error code of 0 as EOF seems a bit // clunky to me... Result TarStream::read_next_entry() { bool success; TarHeader header; auto rc = find_valid_header(&header, success); if (!success) return rc.release_error(); return parse_header(&header); } usize TarStream::read_contents(const Entry& entry, void* buf, usize offset, usize length) const { if (offset >= entry.size) return 0; if ((length + offset) > entry.size) length = entry.size - offset; memcpy(buf, offset_ptr(m_base, entry.pos + offset), length); return length; } Result TarStream::read_contents_as_string(const Entry& entry, usize offset, usize max) const { char* buf = TRY(make_array(max + 1)); usize nread = read_contents(entry, buf, offset, max); buf[nread] = 0; return OwnedStringView { buf }; }