Skip to content

What zpack is

zpack bundles a directory tree into a single .zpak archive. It preserves relative paths, streams file contents instead of buffering them, and guarantees a byte-for-byte round trip.

It is two things sharing one implementation:

  • a CLI, for packing assets in a build script or by hand
  • a Zig library, so a program can open an archive and read from it directly

main.zig contains only argument handling. Everything the CLI does, the library does too.

A round trip is byte identical. Pack a directory, extract it, and diff -r reports nothing. Every entry stores an XxHash64 of its original bytes, and that hash is checked on every read, every verify, and every unpack.

The same tree produces the same archive. Entries are sorted by path before writing, so a repack is reproducible rather than dependent on directory walk order.

Nothing is held whole in memory. File contents move through reused 64 KiB buffers in both directions. A 40 GB asset directory packs in the same working set as a 40 MB one.

A malformed archive never causes an unchecked read. Archive.open validates the entire index up front - every offset, every size, every path - so later lookups work from data that has already been bounds checked. See the security model.

An archive is never half written. pack builds into a temporary file beside the destination and moves it into place only once it is complete, so a failed run leaves any existing archive untouched.

These are choices, not gaps to be filled later:

Not supported Why
Encryption or signing The stored hash detects accidental corruption. It is not a MAC, and zpack does not authenticate archives.
Permissions, mtimes, symlinks Only regular files get entries. An archive describes contents, not a filesystem.
Empty directories Directories are implied by entry paths. One with nothing in it has nothing to imply it.
Appending to an existing archive The index is written before the data, so adding an entry means rewriting the file. Repack instead.
Per-file compression settings Each file is deflated at level 6 and kept only if the result is smaller. There is no knob.
Solid or cross-file compression Each entry compresses independently, which is what makes reading one entry cheap.

zpack targets Zig 0.16.0 and uses the std.Io interfaces introduced there. It does not build on 0.15 or earlier.