AxlTar — ustar Archive Reader/Writer

A small POSIX ustar codec layered on AxlStream: write a sequence of named byte blobs into a tar archive, or read them back, streaming through any stream — an in-memory buffer (axl_bufopen), a file (axl_fopen), or anything else backing the stream API.

The writer (axl_tar_writer_newaxl_tar_writer_add / axl_tar_writer_add_diraxl_tar_writer_finish) emits standard ustar headers with a correct checksum and block padding; names longer than 100 bytes use the ustar name/prefix split (up to ~255 bytes), and a name that can’t be split is rejected rather than truncated. The reader (axl_tar_reader_newaxl_tar_reader_nextaxl_tar_reader_read) validates each header checksum and streams entry data, stopping at the end-of-archive marker.

It backs the tar host tool and mkfixture’s HTTP write target (which builds a fixture tarball in memory and POSTs it). GNU/PAX long-name and sparse extensions are out of scope.

Header: <axl/axl-tar.h>

API Reference

POSIX ustar archive reader and writer over AxlStream.

A small, dependency-light tar codec: write a sequence of named byte blobs into a ustar archive (or read them back), streaming through any AxlStream — an in-memory buffer (axl_bufopen), a file (axl_fopen), or anything else that backs the stream API. Used by the tar tool and by mkfixture’s HTTP write target (which builds a fixture tarball in memory and POSTs it).

Scope: the ustar format — regular files and directories, names up to 255 bytes via the name/prefix split. GNU/PAX long-name and sparse extensions are out of scope; a name that won’t fit the ustar name(100)+prefix(155) split is rejected rather than silently truncated.

Defines

AXL_TAR_BLOCK

ustar block size; every header and the data of each entry is padded to a multiple of this.

AXL_TAR_NAME_MAX

Max entry-name length: ustar name(100) + ‘/’ + prefix(155), + NUL.

AXL_TAR_TYPE_FILE

Entry type, from the ustar typeflag byte.

regular file (also accepts ‘\0’)

AXL_TAR_TYPE_DIR

directory

Typedefs

typedef struct AxlTarWriter AxlTarWriter

Opaque tar writer. Created by axl_tar_writer_new, destroyed by axl_tar_writer_free. Does NOT own or close the underlying stream.

typedef struct AxlTarReader AxlTarReader

Opaque tar reader. Created by axl_tar_reader_new, destroyed by axl_tar_reader_free. Does NOT own or close the underlying stream.

Functions

AxlTarWriter *axl_tar_writer_new(AxlStream *out)

Create a tar writer that emits to out.

The writer borrows out — the caller keeps ownership and closes it after axl_tar_writer_finish + axl_tar_writer_free.

Parameters:
  • out – destination stream (borrowed)

Returns:

a writer, or NULL on allocation failure or if out is NULL.

int axl_tar_writer_add(AxlTarWriter *w, const char *name, uint32_t mode, const void *data, size_t len)

Append a regular-file entry with in-memory contents.

Writes a ustar header for name (split across the name/prefix fields when longer than 100 bytes) followed by len data bytes zero-padded to the block size.

Parameters:
  • w – writer

  • name – entry path (e.g. “acpi/facp.dat”)

  • mode – permission bits (e.g. 0644)

  • data – file contents (may be NULL iff len is 0)

  • len – content length in bytes

Returns:

AXL_OK on success, AXL_ERR if w / name is NULL, data is NULL with non-zero len, the name is too long for ustar, or the stream write fails.

int axl_tar_writer_add_dir(AxlTarWriter *w, const char *name, uint32_t mode)

Append a directory entry (no data).

Optional — extracting tools create parent directories implicitly, so archives built for the HTTP sink omit these. Provided for the tar tool’s fidelity.

Parameters:
  • w – writer

  • name – directory path (a trailing ‘/’ is added if absent)

  • mode – permission bits (e.g. 0755)

Returns:

AXL_OK on success, AXL_ERR on bad args / name too long / write failure.

int axl_tar_writer_finish(AxlTarWriter *w)

Write the end-of-archive marker (two zero blocks).

Call once after the last entry, before freeing. The stream is flushed by the caller (or by closing it).

Returns:

AXL_OK on success, AXL_ERR on write failure.

void axl_tar_writer_free(AxlTarWriter *w)

Free a tar writer. NULL-safe. Does not close the stream.

AxlTarReader *axl_tar_reader_new(AxlStream *in)

Create a tar reader over in.

The reader borrows in (which must be positioned at the start of an archive).

Parameters:
  • in – source stream (borrowed)

Returns:

a reader, or NULL on allocation failure / NULL in.

int axl_tar_reader_next(AxlTarReader *r, AxlTarEntry *out)

Advance to the next archive entry.

Skips any unread data (and its padding) from the previous entry, reads and parses the next 512-byte header into out, and leaves the stream positioned at the entry’s data — read it with axl_tar_reader_read.

Returns:

AXL_OK with out populated, or AXL_ERR at the end-of-archive marker, on a malformed/short header, or on a stream error (out untouched). A clean end and a truncated archive both stop iteration the same way.

axl_ssize_t axl_tar_reader_read(AxlTarReader *r, void *buf, size_t len)

Read up to len bytes of the current entry’s data.

Reads no further than the current entry’s declared size; returns 0 once the entry is exhausted. Call repeatedly to stream large entries. The entry size is taken from the header and trusted to the stream’s EOF behavior — a truncated archive that over-declares a size simply short-reads here (and the next advance stops), it cannot over-read.

Returns:

bytes read (0 at end of the current entry), or -1 on a stream error.

void axl_tar_reader_free(AxlTarReader *r)

Free a tar reader. NULL-safe. Does not close the stream.

struct AxlTarEntry
#include <axl-tar.h>

One archive entry, as reported by axl_tar_reader_next.

Public Members

char name[257u]

full path (prefix joined with name)

uint64_t size

data byte count (0 for directories)

uint32_t mode

permission bits (low 12)

char type

AXL_TAR_TYPE_FILE / _DIR / raw typeflag.