Simple Uncompressed Interchange Tape Archive: SUITAR

Status: Draft (as of September 2026). There is no compatibility guarantee yet.

Overview

SUITAR is a common-denominator, trivial-to-parse interchange format for “the result of decompressing a compressed file or unpacking an archive file”, such as ZIP, RAR, 7Z, TAR, GZIP, BZIP2, XZ, ZSTD, etc.

SUITAR is to archive files (including foobar.dat.xz compressed files as an archive containing 1 file) as Farbfeld or NIE is to image files: an uncompressed, “designed for Unix pipes” format that is trivial to read or write in a few hundred lines of code, ideally in a memory-safe programming language. It‘s a format for what the Chromium web browser’s “Rule of 2” security advice calls https://chromium.googlesource.com/chromium/src/+/master/docs/security/rule-of-2.md#normalization.

Subset of TAR

SUITAR is a subset of the well-known and widely-used TAR (Tape Archive, with GNU extensions) archive file format. Every valid SUITAR file is also a valid TAR file. These files work with popular tools like /usr/bin/tar and with popular TAR-reading libraries in a variety of programming languages.

SUITAR is a subset of “pure TAR”, not of “TAR wrapped in GZIP”, “TAR wrapped in BZIP2”, etc. A separate compression step wrapping SUITAR is feasible, just like wrapping TAR, but is out of scope of this document.

Like TAR, SUITAR files are a sequence of independent entries (files or directories). Independent means that, like JSON map keys, duplicate names are valid, although some decoders may choose to reject them.

A file‘s entry does not need to be preceded by explicit entries for that file’s parent directories.

Further Restrictions

Compared to plain TAR (and refer to the GNU TAR manual), SUITAR has further restrictions:

  • Entries are either regular files (REGTYPE), sparse files (GNUTYPE_SPARSE) or directories (DIRTYPE). There is no support for hard links, symlinks, device files or other non-standard files.
  • Sparse files must be completely sparse. Their content must be one contiguous span of NUL (zero) bytes that covers the entire file.
  • File and directory names must obey the “File Name Validity” rules, below.
  • These names must be encoded by a GNUTYPE_LONGNAME header block, regardless of whether the name's length is over or under 100 or 255 bytes.
  • File size and modTime (modification time, seconds since Unix epoch) integers must use base-256 encoding (not base-8 octal) and must be non-negative and less than (1 << 53), which is 9007_199254_740992.
  • Mode bits are either 0o644 (rw-r--r--) or 0o755 (rwxr-xr-x), encoded in base-8 octal (not base-256).
  • UID and GID are hard-coded to 65534 (as a number, equivalent to octal 0o0177776) and “nobody” (as a string).
  • Any other fields are unused and must be NUL bytes.
  • Padding bytes (as TAR uses 512-byte blocks) must be NUL bytes.

There is no support for various TAR variants, such as “the PAX extensions to TAR” or “the USTAR extensions to TAR”, other than what's implied by the subset of the GNU extensions that SUITAR explicitly uses.

Encoders have no meaningful choices, bar one exception. There is only one valid SUITAR encoding (unlike full TAR's backwards-compatible choice between base-8 or base-256 encoding of various sufficiently small numbers) for any given file or directory entry (its combination of type, name, size, mode, modTime and contents).

The one exception is that, if a file's contents are all NUL bytes (including zero-sized files), an encoder can choose between a REGTYPE regular file (with explicit NULs) or a GNUTYPE_SPARSE sparse file (with implicit NULs).

File Name Validity

These rules apply to both file names and directory names.

  • Names must be valid UTF-8.
  • Names must not contain any ASCII control characters, including '\n' or '\x00', the “new line” or NUL bytes.
  • Names must not contain the '\x7F' ASCII DEL byte.
  • Names must be no longer than 4095 bytes, excluding a trailing NUL.
  • Names must not be "", "." or "..".
  • Names must not start or end with "/", "./" or "../".
  • Names must not contain "//", "/./" or "/../" as substrings.

For example, when converting from ZIP (with Japanese file names) to SUITAR, it is the SUITAR producer‘s responsibility, not the SUITAR consumer’s, to detect and transform Shift-JIS encoded names to equivalent and valid UTF-8.

File Structure

SUITAR files are a sequence of entries, followed by a 1024-byte “End Of File” marker. The EOF marker's bytes are all NUL. Each entry occupies an integer number of 512-byte blocks:

  • 1 GNUTYPE_LONGNAME header block.
  • 1 or more payload blocks containing the file or directory name.
  • 1 REGTYPE, GNUTYPE_SPARSE or DIRTYPE header block.
  • If REGTYPE, 0 or more payload blocks containing the file contents.
  • If not REGTYPE, no further blocks.

Header Blocks

Like all blocks, each header block is 512 bytes long. Each header block also starts with a 12-byte magic signature (that is not valid UTF-8), identifying SUITAR version 1. There are no other versions at this time.

The first 384 out of 512 bytes must match this template (arranged as 24 rows of 16 bytes per row, plus commentary):

@@@@@@@@@@@@....   @@@@@@@@@@@@ = "\x13sUItAR\x00\xFE\xFDv1".
................
................
................
................
................
....0000???.0177   ??? = mode.
776.0177776.$...
????????$...????   ???????? = physical size, ???????? = modTime.
??????????. ?...   ?????? = checksum, ? = type.
................
................
................
................
................
................
.ustar  .nobody.
................
.........nobody.
................
................
................
................
................

In this template, @ indicates the magic signature, . indicates a 0x00 NUL byte, $ indicates a 0x80 byte and ? indicates parts of the template that are variable, not hard-coded.

These ? bytes are the 3-byte mode ("644" or "755"), physical size or modTime as an 8-byte big-endian uint64, 6-byte checksum (see below) or 1-byte type, which must be one of:

  • '0' for REGTYPE.
  • '5' for DIRTYPE, in which case mode must be "755" and physical size must be all zeroes.
  • 'L' for GNUTYPE_LONGNAME, in which case mode must be "644" and modTime must be all zeroes.
  • 'S' for GNUTYPE_SPARSE, in which case physical size must be all zeroes and offset and logical size (see below) must be the same number and, again, within the half-open range 0 .. (1 << 53).

The last 128 out of 512 bytes (8 rows of 16 bytes per row) must be all NUL bytes unless the type is GNUTYPE_SPARSE, in which case it must match this template (and ? again indicates an 8-byte big-endian uint64):

..$...????????$.   ???????? = sparse offset.
................
................
................
................
................
...$...????????.   ???????? = sparse logical size.
................

Header Checksum

A 512-byte header block's checksum value is simply the sum of each byte (after converting from uint8 to uint32, to avoid overflow) in the block, at offsets in the two half-open ranges 0 .. 148 and 156 .. 512, which excludes the 8 bytes for the 6-byte checksum itself plus another two hard-coded bytes "\x00\x20".

That checksum value is written as a 6-byte ASCII octal number in the header. For example, 4853 (decimal) would be encoded as "011365" (octal).

Payload Blocks

Each entry has one or more payload blocks, between its two header blocks, containing the file or directory name. The name length (including a trailing NUL byte) is the first header block‘s physical size value, and must be within the half-open range 2 .. 4096, and so the excluding-a-trailing-NUL length must range within 1 .. 4095. Rounding up that including-a-trailing-NUL length to a multiple of 512 gives the number of 512-byte payload blocks that contain the name. All padding bytes in the name’s final payload block must be NUL.

For REGTYPE entries, the second header block‘s physical size value gives the reconstructed file’s size and rounding that up to a multiple of 512 gives the number of 512-byte payload blocks that contain the file contents. Again, all padding bytes in the contents' final payload block must be NUL.

For other entries (DIRTYPE or GNUTYPE_SPARSE), there are no further payload blocks after the second header block.

For GNUTYPE_SPARSE entries, the second header block‘s logical size value gives the reconstructed file’s size and its contents are all NUL bytes.

Reference Implementation

The google/wuffs repository, which holds this specification document, also holds a suitar Go package and some test/data/*.suitar example files, readable by that Go package but also by /usr/bin/tar.


Updated on September 2026.