|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
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"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. | |
Streaming tar walker: open / next / read over the shared read seam.
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).
Definition in file unarch_tar.c.
|
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.
| [in] | block | The header block to decode. |
| [in] | off | Its absolute offset. |
| [out] | type | Receives the normalised typeflag class. |
| [out] | dsize | Receives the declared data length. |
| [out] | next | Receives the following block's offset. |
| k_ra8_ok | Header decoded. |
| k_ra8_err_validation_failed | Checksum / magic / size failure. |
block is a full block read by internal_read_block. 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().
|
static |
Measure one NUL-terminated-or-full ustar header field.
Scans no farther than capacity bytes from offset.
| [in] | block | Complete ustar header block. |
| [in] | offset | Byte offset of the field within block. |
| [in] | capacity | Maximum field width in bytes. |
| 0 | The first field byte is NUL or capacity is zero. |
block is readable through offset plus capacity bytes. capacity. Definition at line 259 of file unarch_tar.c.
Referenced by internal_ustar_name().
|
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.
| [in,out] | t | Live walker (budget charged). |
| [in] | block | The member's header block. |
| [in] | off | The member header's absolute offset. |
| [in] | type | The member's normalised class. |
| [in] | dsize | The header-declared data length. |
| [in,out] | meta | Accumulated overrides. |
| [out] | out | Entry to populate. |
| k_ra8_ok | Entry populated. |
| k_ra8_err_validation_failed | The data area overruns the archive or the advance would wrap. |
| k_ra8_err_decomp_output_cap | The member exceeds the policy cap. |
| k_ra8_err_decomp_entries | The entry budget is exhausted. |
block passed internal_decode_header. out was zeroed by the caller. out is re-zeroed by the caller's error path. 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().
|
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.
| [in] | t | Live walker. |
| [in] | type | The block's normalised class (pax or longname). |
| [in] | doff | Absolute offset of the meta data area. |
| [in] | dsize | Meta data length in bytes. |
| [in,out] | meta | Override accumulator to update. |
| k_ra8_ok | Meta applied. |
| k_ra8_err_validation_failed | Oversized, truncated, or malformed meta data. |
type is k_ra8_tar_type_pax or k_ra8_tar_type_longname. 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().
|
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.
| [in] | off | Member header offset. |
| [in] | dsize | Member data length in bytes. |
| [out] | next | Receives the following block's offset. |
| k_ra8_ok | next computed. |
| k_ra8_err_validation_failed | The arithmetic would overflow. |
next is a caller-owned local (non-NULL). off is a real block offset (caller-validated). 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().
|
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).
| [in] | t | Live walker. |
| [in] | off | Absolute block offset. |
| [out] | block | Destination (k_unarch_tar_block bytes). |
| k_ra8_ok | Block read whole. |
| k_ra8_err_validation_failed | Partial block or short read. |
block holds a full block of writable bytes. 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().
|
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.
| [in] | block | Complete member header block. |
| [in,out] | meta | Accumulator whose name buffer receives the result. |
block is a full validated header block. meta change. 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().
|
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.
| [in,out] | t | Walker bound by unarch_tar_open (non-NULL). |
| [in] | off | Absolute offset of the member's first block. |
| [out] | name_buf | Buffer for the member name (non-NULL if name_cap > 0). |
| [in] | name_cap | Capacity of name_buf in bytes. |
| [out] | out | Decoded member descriptor (non-NULL). |
| k_ra8_ok | Member decoded; out filled. |
| k_ra8_err_null_ptr | t or out was NULL. |
| k_ra8_err_invalid_state | t was never bound. |
| k_ra8_err_not_found | End of archive (zero block or EOF). |
| k_ra8_err_validation_failed | A truncated / malformed / lying header, checksum failure, or an over-limit meta prelude. |
| k_ra8_err_decomp_entries | The policy entry cap was crossed. |
| k_ra8_err_decomp_iterations | The block-examination budget ran out. |
| k_ra8_err_decomp_output_cap | A member declares more bytes than the policy's per-unit output cap. |
t was populated by unarch_tar_open. off is 0 or a next_off from a previous call. out is left zeroed.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().
|
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.
| [out] | t | Walker to populate (caller-owned). |
| [in] | read | Byte reader over the archive (non-NULL). |
| [in] | ctx | Context passed to read. |
| [in] | size | Archive length in bytes (>= one block). |
| [in] | limits | Policy to enforce, or NULL for the default. |
| k_ra8_ok | Recognised tar archive; t bound. |
| k_ra8_err_null_ptr | t or read was NULL. |
| k_ra8_err_invalid_size | size is smaller than one block. |
| k_ra8_err_invalid_arg | limits has a zero field. |
| k_ra8_err_not_supported | Block 0 is not a tar header. |
read serves offsets [0, size) of the archive. t is a writable unarch_tar_t. t is left dead (live == false).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().
|
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.
| [in] | block | Leading archive bytes (may be NULL). |
| [in] | len | Readable length of block in bytes. |
| true | Magic and checksum both hold. |
| false | block is NULL, short, or not a tar header. |
block holds len readable bytes when non-NULL. len is the true readable length (untrusted values are safe). 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().
|
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.
| [in] | t | Walker bound by unarch_tar_open (non-NULL). |
| [in] | ent | A file member from unarch_tar_next (non-NULL, is_file == 1). |
| [out] | buf | Destination for the member bytes (non-NULL). |
| [in] | cap | Capacity of buf in bytes; must be >= ent->size. |
| [out] | got | Receives the number of bytes written (non-NULL). |
| k_ra8_ok | Member copied; *got == ent->size. |
| k_ra8_err_null_ptr | A required pointer was NULL. |
| k_ra8_err_invalid_state | t was never bound. |
| k_ra8_err_not_supported | ent is not a regular file member. |
| k_ra8_err_no_mem | cap is smaller than ent->size. |
| k_ra8_err_invalid_size | The member overruns the archive, or the reader returned a short read. |
t was populated by unarch_tar_open. ent came from unarch_tar_next on the same t. buf contents are unspecified and *got == 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().
|
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().