ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
unarch_tar.c File Reference

Streaming tar walker: open / next / read over the shared read seam. More...

#include "unarch_tar.h"
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "unarch_tar_internal.h"
Include dependency graph for unarch_tar.c:

Go to the source code of this file.

Data Structures

struct  tar_meta_t
 Overrides accumulated over one member's pax / GNU meta prelude. More...

Functions

bool unarch_tar_probe (const uint8_t *block, size_t len)
 Whether a leading header block looks like a tar archive.
ra8_err_t unarch_tar_open (unarch_tar_t *t, unarch_read_fn read, void *ctx, uint64_t size, const ra8_decomp_limits_t *limits)
 Bind a walker to an archive and validate its first header block.
static ra8_err_t internal_read_block (const unarch_tar_t *t, uint64_t off, uint8_t *block)
 Read one full header block at off, bounds-checked.
static ra8_err_t internal_next_off (uint64_t off, uint64_t dsize, uint64_t *next)
 Compute the offset of the block after a member, overflow-checked.
static ra8_err_t internal_meta_consume (const unarch_tar_t *t, ra8_tar_type_t type, uint64_t doff, uint64_t dsize, tar_meta_t *meta)
 Consume one pax / GNU-longname meta block's data area.
static size_t internal_field_length (const uint8_t *block, uint32_t offset, uint32_t capacity)
 Measure one NUL-terminated-or-full ustar header field.
static void internal_ustar_name (const uint8_t *block, tar_meta_t *meta)
 Assemble a ustar member name (prefix + '/' + name), clamped.
static ra8_err_t internal_decode_header (const uint8_t *block, uint64_t off, ra8_tar_type_t *type, uint64_t *dsize, uint64_t *next)
 Validate one header block and decode its size / type / next offset.
static ra8_err_t internal_finish_member (unarch_tar_t *t, const uint8_t *block, uint64_t off, ra8_tar_type_t type, uint64_t dsize, tar_meta_t *meta, unarch_tar_entry_t *out)
 Finish decoding the real member header into the caller entry.
ra8_err_t unarch_tar_next (unarch_tar_t *t, uint64_t off, char *name_buf, uint16_t name_cap, unarch_tar_entry_t *out)
 Decode the member at off and advance to the next member.
ra8_err_t unarch_tar_read (const unarch_tar_t *t, const unarch_tar_entry_t *ent, uint8_t *buf, size_t cap, size_t *got)
 Copy a file member's data area into the caller buffer.

Variables

static const char *const s_tag_tar = "unarch_tar"
 Log tag for tar-walker diagnostics.

Detailed Description

Streaming tar walker: open / next / read over the shared read seam.

Tag
[Ring 4 / Domain] {World: NS}

The block-chain half of the clean-room tar reader (unarch_tar.h); the untrusted-byte field parsers live in unarch_tar_fields.c. One unarch_tar_next call consumes a member's bounded pax / GNU meta prelude and its real header, charging the walker's embedded decompression budget one iteration per examined block and one entry per returned member – so the whole enumeration, not just one call, is policy-bounded. All offset arithmetic is overflow-checked so a hostile size field cannot wrap next_off backwards (the walk strictly advances or dies).

Since
Version 0.1.0

Definition in file unarch_tar.c.

Function Documentation

◆ internal_decode_header()

ra8_err_t internal_decode_header ( const uint8_t * block,
uint64_t off,
ra8_tar_type_t * type,
uint64_t * dsize,
uint64_t * next )
static

Validate one header block and decode its size / type / next offset.

The per-block core of the walk: checksum, magic, numeric size field, and the overflow-checked advance. Shared by the meta prelude and the real member.

Parameters
[in]blockThe header block to decode.
[in]offIts absolute offset.
[out]typeReceives the normalised typeflag class.
[out]dsizeReceives the declared data length.
[out]nextReceives the following block's offset.
Returns
ra8_err_t status.
Return values
k_ra8_okHeader decoded.
k_ra8_err_validation_failedChecksum / magic / size failure.
Precondition
block is a full block read by internal_read_block.
The out-pointers are caller-owned locals.
Postcondition
On k_ra8_ok every output is populated.
On any error the member must be rejected.
Note
Thread-safe: pure computation over the block.
Since
Version 0.1.0

Definition at line 329 of file unarch_tar.c.

References internal_next_off(), k_ra8_err_validation_failed, k_ra8_ok, k_ra8_tar_len_size, k_ra8_tar_off_size, k_ra8_tar_off_type, priv_unarch_tar_checksum_ok(), priv_unarch_tar_classify(), priv_unarch_tar_magic_ok(), and priv_unarch_tar_num().

Referenced by unarch_tar_next().

◆ internal_field_length()

size_t internal_field_length ( const uint8_t * block,
uint32_t offset,
uint32_t capacity )
static

Measure one NUL-terminated-or-full ustar header field.

Scans no farther than capacity bytes from offset.

Parameters
[in]blockComplete ustar header block.
[in]offsetByte offset of the field within block.
[in]capacityMaximum field width in bytes.
Returns
Field length before the first NUL or the full capacity.
Return values
0The first field byte is NUL or capacity is zero.
Precondition
block is readable through offset plus capacity bytes.
The offset and capacity describe one field within the header block.
Postcondition
No header byte is modified.
The result does not exceed capacity.
Note
Pure and thread-safe for immutable input.
Since
Version 0.1.0

Definition at line 259 of file unarch_tar.c.

Referenced by internal_ustar_name().

◆ internal_finish_member()

ra8_err_t internal_finish_member ( unarch_tar_t * t,
const uint8_t * block,
uint64_t off,
ra8_tar_type_t type,
uint64_t dsize,
tar_meta_t * meta,
unarch_tar_entry_t * out )
static

Finish decoding the real member header into the caller entry.

Applies the accumulated overrides (pax size wins over the header field and re-derives the data span; pax path / longname wins over the ustar name fields), bounds the data area against the archive and the policy's output cap, and charges the entry budget.

Parameters
[in,out]tLive walker (budget charged).
[in]blockThe member's header block.
[in]offThe member header's absolute offset.
[in]typeThe member's normalised class.
[in]dsizeThe header-declared data length.
[in,out]metaAccumulated overrides.
[out]outEntry to populate.
Returns
ra8_err_t status.
Return values
k_ra8_okEntry populated.
k_ra8_err_validation_failedThe data area overruns the archive or the advance would wrap.
k_ra8_err_decomp_output_capThe member exceeds the policy cap.
k_ra8_err_decomp_entriesThe entry budget is exhausted.
Precondition
block passed internal_decode_header.
out was zeroed by the caller.
Postcondition
On k_ra8_ok, out->next_off > off.
On any error out is re-zeroed by the caller's error path.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 378 of file unarch_tar.c.

References unarch_tar_t::budget, unarch_tar_entry_t::data_off, tar_meta_t::have_path, tar_meta_t::have_size, internal_next_off(), internal_ustar_name(), unarch_tar_entry_t::is_dir, unarch_tar_entry_t::is_file, k_ra8_err_validation_failed, k_ra8_ok, k_ra8_tar_type_dir, k_ra8_tar_type_file, k_unarch_tar_block, ra8_decomp_budget_t::limits, tar_meta_t::name_len, unarch_tar_entry_t::name_len, unarch_tar_entry_t::next_off, ra8_decomp_budget_charge_entry(), ra8_decomp_check_declared(), unarch_tar_entry_t::size, unarch_tar_t::size, and tar_meta_t::size_ovr.

Referenced by unarch_tar_next().

◆ internal_meta_consume()

ra8_err_t internal_meta_consume ( const unarch_tar_t * t,
ra8_tar_type_t type,
uint64_t doff,
uint64_t dsize,
tar_meta_t * meta )
static

Consume one pax / GNU-longname meta block's data area.

Bounds the data to k_unarch_tar_pax_max, reads it whole, and applies it: a pax header contributes path / size overrides, a longname contributes the (NUL-stripped) name. Skipped meta kinds ('g', 'K') consume nothing here. A function-local static buffer keeps the frame below the first-party stack budget; the single-threaded tar walker overwrites it for each metadata block.

Parameters
[in]tLive walker.
[in]typeThe block's normalised class (pax or longname).
[in]doffAbsolute offset of the meta data area.
[in]dsizeMeta data length in bytes.
[in,out]metaOverride accumulator to update.
Returns
ra8_err_t status.
Return values
k_ra8_okMeta applied.
k_ra8_err_validation_failedOversized, truncated, or malformed meta data.
Precondition
type is k_ra8_tar_type_pax or k_ra8_tar_type_longname.
doff + dsize was bounds-checked against the archive by the caller.
Postcondition
On k_ra8_ok the accumulator reflects the meta content.
On any error the member must be rejected.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 201 of file unarch_tar.c.

References unarch_tar_t::ctx, tar_meta_t::have_path, tar_meta_t::have_size, k_ra8_err_validation_failed, k_ra8_ok, k_ra8_tar_type_pax, k_unarch_tar_pax_max, memcpy(), tar_meta_t::name_buf, tar_meta_t::name_cap, tar_meta_t::name_len, priv_unarch_tar_pax_parse(), unarch_tar_t::read, and tar_meta_t::size_ovr.

Referenced by unarch_tar_next().

◆ internal_next_off()

ra8_err_t internal_next_off ( uint64_t off,
uint64_t dsize,
uint64_t * next )
static

Compute the offset of the block after a member, overflow-checked.

next = off + block + ceil(dsize / block) * block. Any step that would wrap uint64 rejects the member – a hostile size field must not move the walk backwards.

Parameters
[in]offMember header offset.
[in]dsizeMember data length in bytes.
[out]nextReceives the following block's offset.
Returns
ra8_err_t status.
Return values
k_ra8_oknext computed.
k_ra8_err_validation_failedThe arithmetic would overflow.
Precondition
next is a caller-owned local (non-NULL).
off is a real block offset (caller-validated).
Postcondition
On k_ra8_ok, *next > off.
On any error *next is unspecified and unused.
Note
Thread-safe: pure computation.
Since
Version 0.1.0

Definition at line 158 of file unarch_tar.c.

References k_ra8_err_validation_failed, k_ra8_ok, and k_unarch_tar_block.

Referenced by internal_decode_header(), and internal_finish_member().

◆ internal_read_block()

ra8_err_t internal_read_block ( const unarch_tar_t * t,
uint64_t off,
uint8_t * block )
static

Read one full header block at off, bounds-checked.

A block that would overrun the archive or a short read from the backing rejects the member (truncation is hostile input).

Parameters
[in]tLive walker.
[in]offAbsolute block offset.
[out]blockDestination (k_unarch_tar_block bytes).
Returns
ra8_err_t status.
Return values
k_ra8_okBlock read whole.
k_ra8_err_validation_failedPartial block or short read.
Precondition
t->live and off < t->size (caller-checked).
block holds a full block of writable bytes.
Postcondition
On k_ra8_ok the block is fully populated.
On any error the member must be rejected.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 126 of file unarch_tar.c.

References unarch_tar_t::ctx, k_ra8_err_validation_failed, k_ra8_ok, k_unarch_tar_block, unarch_tar_t::read, and unarch_tar_t::size.

Referenced by unarch_tar_next().

◆ internal_ustar_name()

void internal_ustar_name ( const uint8_t * block,
tar_meta_t * meta )
static

Assemble a ustar member name (prefix + '/' + name), clamped.

Used when no pax path or longname override exists. A non-empty prefix contributes prefix '/' before the name field.

Parameters
[in]blockComplete member header block.
[in,out]metaAccumulator whose name buffer receives the result.
Precondition
block is a full validated header block.
meta->name_buf holds meta->name_cap writable bytes when capacity is nonzero.
Postcondition
meta->name_len is the clamped assembled length.
Only the name fields of meta change.
Note
Thread-safe: writes only the caller's accumulator.
Since
Version 0.1.0

Definition at line 282 of file unarch_tar.c.

References internal_field_length(), k_ra8_tar_len_name, k_ra8_tar_len_prefix, k_ra8_tar_off_name, k_ra8_tar_off_prefix, memcpy(), tar_meta_t::name_buf, tar_meta_t::name_cap, and tar_meta_t::name_len.

Referenced by internal_finish_member().

◆ unarch_tar_next()

ra8_err_t unarch_tar_next ( unarch_tar_t * t,
uint64_t off,
char * name_buf,
uint16_t name_cap,
unarch_tar_entry_t * out )
nodiscard

Decode the member at off and advance to the next member.

Consumes the member's pax / GNU meta prelude (bounded by k_unarch_tar_meta_max blocks and k_unarch_tar_pax_max data bytes), decodes the real header, applies any path / size overrides, and fills out – including out->next_off, the offset of the following member. The member name (pax path, GNU longname, or prefix-joined ustar name) is copied into name_buf, clamped to name_cap. Every examined block charges the walk's iteration budget and every returned member charges its entry budget; a member whose declared size breaks the policy's output cap or overruns the archive is rejected.

Parameters
[in,out]tWalker bound by unarch_tar_open (non-NULL).
[in]offAbsolute offset of the member's first block.
[out]name_bufBuffer for the member name (non-NULL if name_cap > 0).
[in]name_capCapacity of name_buf in bytes.
[out]outDecoded member descriptor (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okMember decoded; out filled.
k_ra8_err_null_ptrt or out was NULL.
k_ra8_err_invalid_statet was never bound.
k_ra8_err_not_foundEnd of archive (zero block or EOF).
k_ra8_err_validation_failedA truncated / malformed / lying header, checksum failure, or an over-limit meta prelude.
k_ra8_err_decomp_entriesThe policy entry cap was crossed.
k_ra8_err_decomp_iterationsThe block-examination budget ran out.
k_ra8_err_decomp_output_capA member declares more bytes than the policy's per-unit output cap.
Precondition
t was populated by unarch_tar_open.
off is 0 or a next_off from a previous call.
Postcondition
On k_ra8_ok, out->next_off > off (the walk strictly advances).
On any error out is left zeroed.
Note
Not thread-safe (charges the walker's embedded budget).
See also
unarch_tar_read()
Since
Version 0.1.0

Definition at line 419 of file unarch_tar.c.

References unarch_tar_t::budget, internal_decode_header(), internal_finish_member(), internal_meta_consume(), internal_read_block(), k_ra8_err_invalid_state, k_ra8_err_not_found, k_ra8_err_validation_failed, k_ra8_ok, k_ra8_tar_type_longname, k_ra8_tar_type_meta, k_ra8_tar_type_other, k_ra8_tar_type_pax, k_unarch_tar_block, k_unarch_tar_meta_max, unarch_tar_t::live, priv_unarch_tar_block_zero(), RA8_CHECK_NULL_PTR, ra8_decomp_budget_charge_iter(), s_tag_tar, and unarch_tar_t::size.

Referenced by priv_comic_cbt_open().

◆ unarch_tar_open()

ra8_err_t unarch_tar_open ( unarch_tar_t * t,
unarch_read_fn read,
void * ctx,
uint64_t size,
const ra8_decomp_limits_t * limits )
nodiscard

Bind a walker to an archive and validate its first header block.

Reads block 0 through read, requires the ustar/GNU magic and a valid checksum (rejecting non-tar bytes cheaply), and binds the walk's decompression budget to limits (or the default policy). Performs no other I/O; the walk proceeds through unarch_tar_next.

Parameters
[out]tWalker to populate (caller-owned).
[in]readByte reader over the archive (non-NULL).
[in]ctxContext passed to read.
[in]sizeArchive length in bytes (>= one block).
[in]limitsPolicy to enforce, or NULL for the default.
Returns
ra8_err_t Error code.
Return values
k_ra8_okRecognised tar archive; t bound.
k_ra8_err_null_ptrt or read was NULL.
k_ra8_err_invalid_sizesize is smaller than one block.
k_ra8_err_invalid_arglimits has a zero field.
k_ra8_err_not_supportedBlock 0 is not a tar header.
Precondition
read serves offsets [0, size) of the archive.
t is a writable unarch_tar_t.
Postcondition
On k_ra8_ok, t->live is true and the walk starts at offset 0.
On any error t is left dead (live == false).
Note
Not thread-safe.
See also
unarch_tar_next()
Since
Version 0.1.0

Definition at line 74 of file unarch_tar.c.

References unarch_tar_t::budget, unarch_tar_t::ctx, k_ra8_err_invalid_size, k_ra8_err_not_supported, k_ra8_err_null_ptr, k_ra8_ok, k_unarch_tar_block, unarch_tar_t::live, RA8_CHECK_NULL_PTR, ra8_decomp_budget_init(), ra8_log_error, unarch_tar_t::read, s_tag_tar, unarch_tar_t::size, and unarch_tar_probe().

Referenced by internal_open_detect().

◆ unarch_tar_probe()

bool unarch_tar_probe ( const uint8_t * block,
size_t len )
nodiscard

Whether a leading header block looks like a tar archive.

Pure probe over the first k_unarch_tar_block bytes: the ustar/GNU magic at its fixed offset plus a valid header checksum. Used by container detection to route a .cbt without constructing a walker. tar has no leading magic bytes, so both tests are required to keep false positives out of the comic open path.

Parameters
[in]blockLeading archive bytes (may be NULL).
[in]lenReadable length of block in bytes.
Returns
Whether the bytes begin a tar archive.
Return values
trueMagic and checksum both hold.
falseblock is NULL, short, or not a tar header.
Precondition
block holds len readable bytes when non-NULL.
len is the true readable length (untrusted values are safe).
Postcondition
No state is modified (pure read).
The result depends only on the first block.
Note
Thread-safe: pure read.
See also
unarch_tar_open()
Since
Version 0.1.0

Definition at line 60 of file unarch_tar.c.

References k_unarch_tar_block, priv_unarch_tar_checksum_ok(), and priv_unarch_tar_magic_ok().

Referenced by unarch_tar_open().

◆ unarch_tar_read()

ra8_err_t unarch_tar_read ( const unarch_tar_t * t,
const unarch_tar_entry_t * ent,
uint8_t * buf,
size_t cap,
size_t * got )
nodiscard

Copy a file member's data area into the caller buffer.

Streams ent->size verbatim bytes from [ent->data_off, ent->data_off + ent->size) through the archive reader into buf. tar stores members uncompressed, so this is the whole extraction step; the bounds re-checked here make a hand-forged entry harmless.

Parameters
[in]tWalker bound by unarch_tar_open (non-NULL).
[in]entA file member from unarch_tar_next (non-NULL, is_file == 1).
[out]bufDestination for the member bytes (non-NULL).
[in]capCapacity of buf in bytes; must be >= ent->size.
[out]gotReceives the number of bytes written (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okMember copied; *got == ent->size.
k_ra8_err_null_ptrA required pointer was NULL.
k_ra8_err_invalid_statet was never bound.
k_ra8_err_not_supportedent is not a regular file member.
k_ra8_err_no_memcap is smaller than ent->size.
k_ra8_err_invalid_sizeThe member overruns the archive, or the reader returned a short read.
Precondition
t was populated by unarch_tar_open.
ent came from unarch_tar_next on the same t.
Postcondition
On k_ra8_ok, buf[0..*got) holds the member's literal bytes.
On any error buf contents are unspecified and *got == 0.
Note
Not thread-safe.
See also
unarch_tar_next()
Since
Version 0.1.0

Definition at line 486 of file unarch_tar.c.

References unarch_tar_t::ctx, unarch_tar_entry_t::data_off, unarch_tar_entry_t::is_file, k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_err_no_mem, k_ra8_err_not_supported, k_ra8_ok, unarch_tar_t::live, RA8_CHECK_NULL_PTR, unarch_tar_t::read, s_tag_tar, unarch_tar_entry_t::size, and unarch_tar_t::size.

Referenced by priv_comic_cbt_extract().

Variable Documentation

◆ s_tag_tar

const char* const s_tag_tar = "unarch_tar"
static

Log tag for tar-walker diagnostics.

Definition at line 33 of file unarch_tar.c.

Referenced by unarch_tar_next(), unarch_tar_open(), and unarch_tar_read().