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

Clean-room, read-only streaming tar walker (POSIX ustar + pax + GNU). More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_decomp_limits.h"
#include "ra8_err.h"
#include "unarch_io.h"
Include dependency graph for unarch_tar.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  unarch_tar_t
 One open tar archive: the backing plus the walk's running budget. More...
struct  unarch_tar_entry_t
 One decoded tar member: a file, a directory, or a skipped block. More...

Enumerations

enum  unarch_tar_dims_t : uint16_t {
  k_unarch_tar_block = 512U ,
  k_unarch_tar_meta_max = 4U ,
  k_unarch_tar_pax_max = 2048U
}
 Fixed sizes of the tar on-disk grammar and the walker's bounds. 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.
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.

Detailed Description

Clean-room, read-only streaming tar walker (POSIX ustar + pax + GNU).

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

A first-party, hand-written tar reader for the comic-book-archive (.cbt) and wrapped-tar (.tar.gz / .tar.xz) use cases. It walks the 512-byte block chain of a POSIX ustar archive one header at a time over the shared seek+read seam (unarch_io.h) and exposes each member (name, size, data offset) without ever materialising the archive. Supported header dialects, all parsed fail-closed:

  • ustar (POSIX.1-1988): the base 512-byte header with the prefix-field long-name split.
  • pax (POSIX.1-2001): x extended headers; the path and size record overrides are applied to the following member, every other record is skipped. g global headers are skipped whole.
  • GNU: L longname data blocks; base-256 (binary) size fields.

Everything else – link/device/fifo members, unknown typeflags – is enumerated as a non-file entry and skipped by size, so the walk never stalls on exotic content.

Clean-room licensing
Written from the POSIX.1-2017 pax Interchange Format specification and the publicly documented GNU tar extensions. It vendors no code from GNU tar, libarchive, or busybox, and is therefore first-party MIT (root LICENSE.txt), not SOUP, and carries no SBOM entry.
Bounded, fail-closed (the archive-hardening contract)
The walker charges every enumerated member and every examined header block against the unified decompression-limits policy (ra8_decomp_limits.h), so the many-tiny-entries bomb and the meta-block-flood bomb both terminate within policy. A member whose declared size breaks the policy's output cap, overruns the archive, or whose header fails the checksum is rejected with a specific error. Resident state is O(one header block); pax data is parsed through a small fixed scratch and rejected when larger.
Note
Not thread-safe; the single-threaded reader loop serialises access.
See also
comic.h The comic facade whose CBT backend drives this.
ra8_decomp_limits.h The policy every walk is charged against.
unarch_io.h The seek+read seam the walker consumes.
Since
Version 0.1.0

Definition in file unarch_tar.h.

Enumeration Type Documentation

◆ unarch_tar_dims_t

enum unarch_tar_dims_t : uint16_t

Fixed sizes of the tar on-disk grammar and the walker's bounds.

The block size is fixed by every tar dialect; the meta and pax bounds are this walker's fail-closed limits on the pax / GNU prelude a single member may carry.

Since
Version 0.1.0
Enumerator
k_unarch_tar_block 

On-disk block / header size.

k_unarch_tar_meta_max 

Max meta (x/g/L/K) blocks per member.

k_unarch_tar_pax_max 

Max pax / longname data bytes.

Definition at line 76 of file unarch_tar.h.

Function Documentation

◆ 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().