Debkit.Tar (Debkit v0.1.1)

Copy Markdown View Source

Read and write tar archives — the middle layer of a .deb.

Inside a .deb, both control.tar.* and data.tar.* are tar archives (once decompressed). This module reads regular-file entries into {name, bytes} pairs and writes entries back out as a deterministic ustar archive.

Regular files only

read/1 returns regular file entries. Directory, symlink, hardlink, and device entries are skipped — .deb control tars are all regular files, which is the case this library targets. (Data tars you typically store and serve verbatim rather than read through here.)

Determinism

write/1 emits ustar entries with mtime 0, uid 0, and gid 0, so equal input yields equal output — the basis for reproducible packages.

Example

iex> tar = Debkit.Tar.write!([
...>   {"./control", "Package: hello\n"},
...>   {"./md5sums", "", 0o644}
...> ])
iex> {:ok, entries} = Debkit.Tar.read(tar)
iex> Enum.map(entries, &elem(&1, 0))
["./control", "./md5sums"]

Summary

Types

An entry read from an archive: its name and contents.

An entry to write. The 2-tuple form defaults the file mode to 0o644; the 3-tuple form sets it explicitly.

Functions

Reads a tar archive into its regular-file entries, in archive order.

Like read/1 but returns the entries directly, raising Debkit.Error on failure.

Writes entries to a deterministic ustar archive.

Like write/1 but returns the bytes directly, raising Debkit.Error on failure.

Types

entry()

@type entry() :: {name :: String.t(), contents :: binary()}

An entry read from an archive: its name and contents.

write_entry()

@type write_entry() ::
  {name :: String.t(), contents :: binary()}
  | {name :: String.t(), contents :: binary(), mode :: non_neg_integer()}

An entry to write. The 2-tuple form defaults the file mode to 0o644; the 3-tuple form sets it explicitly.

Functions

read(binary)

@spec read(binary()) :: {:ok, [entry()]} | {:error, Debkit.error()}

Reads a tar archive into its regular-file entries, in archive order.

Returns {:error, :corrupt} if binary is not a well-formed tar archive.

Examples

iex> {:ok, entries} = Debkit.Tar.read(Debkit.Tar.write!([{"./x", "hi"}]))
iex> entries
[{"./x", "hi"}]

read!(binary)

@spec read!(binary()) :: [entry()]

Like read/1 but returns the entries directly, raising Debkit.Error on failure.

write(entries)

@spec write([write_entry()]) :: {:ok, binary()} | {:error, Debkit.error()}

Writes entries to a deterministic ustar archive.

Each entry is {name, contents} (mode defaults to 0o644) or {name, contents, mode}. Entries are written in the order given.

Examples

iex> {:ok, tar} = Debkit.Tar.write([{"./control", "Package: hello\n", 0o644}])
iex> is_binary(tar)
true

write!(entries)

@spec write!([write_entry()]) :: binary()

Like write/1 but returns the bytes directly, raising Debkit.Error on failure.