Skip to content

pack

zpack pack <input-dir> <output.zpak>

Walks input-dir recursively and writes every regular file into a new archive at output.zpak.

Terminal window
$ zpack pack assets/ game.zpak
Packed 56 files (77.2 MiB -> 71.7 MiB, 7.1% smaller)

When compression saved nothing, the summary drops the comparison:

Terminal window
$ zpack pack photos/ photos.zpak
Packed 212 files (1.4 GiB)

Only regular files. Directories are implied by entry paths, so an empty one is not preserved. Symlinks, devices, and sockets are skipped.

Paths are stored relative to input-dir and normalized to / on every platform, so an archive packed on Windows extracts identically on Linux.

Four things are left out:

  1. Anything matching a pattern in input-dir/.zpackignore - see .zpackignore
  2. The .zpackignore file itself; it describes how to build the archive, not what it holds
  3. A file whose relative path equals output.zpak, so zpack pack . out.zpak is repeatable
  4. The temporary file pack builds into, which is created after the scan and so cannot appear in its own archive

Each file is compressed with raw deflate at level 6. If the compressed form is not smaller than the original, pack rewinds and writes the file verbatim, recording it as store. Already-compressed assets therefore never grow.

There is no compression level flag. The rewind costs a second read of the source file, which is the price of never producing a larger archive than the input.

The archive is built in a temporary file beside the destination and moved into place only once it is complete. A run that fails partway - a disk filling up, a source file vanishing - leaves any existing archive at output.zpak untouched, rather than replacing it with a truncated one.

Entries are sorted by path before the index is written, so directory walk order does not leak into the output:

Terminal window
$ zpack pack assets/ a.zpak
$ zpack pack assets/ b.zpak
$ cmp a.zpak b.zpak # identical
Message Cause
cannot open directory '<dir>': FileNotFound input-dir does not exist
cannot pack '<dir>': AssetIdCollision Two paths hash to the same asset id. A build error by design, not a warning - see asset handles
cannot pack '<dir>': InvalidPath A filename that cannot round-trip: non-UTF-8, or containing \, :, or NUL
cannot pack '<dir>': PathTooLong A path over 65535 bytes
cannot pack '<dir>': TooManyFiles More than 4294967295 files
cannot pack '<dir>': TooManyRules More than 1024 rules in .zpackignore
cannot pack '<dir>': SourceChanged A file changed size between being compressed and being re-read for the store fallback

Directory metadata is held in an arena and discarded when the command returns. File contents stream through reused 64 KiB buffers and are never held whole. One deflate compressor - around 230 KB - is allocated once and reused for every file.

Packing a 40 GB tree uses the same working set as packing a 40 MB one.