Luna/libluna/src/TarStream.cpp
apio 77560bbc3e
All checks were successful
continuous-integration/drone/push Build is passing
kernel+tools: Allow loading files with different owners + add a more dynamic install script
2023-05-06 12:11:35 +02:00

106 lines
2.5 KiB
C++

#include <luna/Alignment.h>
#include <luna/Alloc.h>
#include <luna/CString.h>
#include <luna/NumberParsing.h>
#include <luna/StringBuilder.h>
#include <luna/TarStream.h>
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::Entry> 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<bool> 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;
}