std/archive/lib
std/archive/src/lib.trb
tar archives: Bytes.untarred reads what the tar programs in use write - POSIX ustar, pax (POSIX.1-2001) and GNU
tar - and List.tarred writes ustar, with a pax header in front of an entry whose path or link does not fit ustar's
fields. A package of the registry is a tar inside gzip (std/compression, docs/design/RELEASE.md section 7.2), and
so is a release of the toolchain.
An entry is a regular file, a directory, a symbolic link or a hard link (TarKind), with the permission bits and the
time of modification the archive gives it; a device and a pipe are refused. A path is kept as the archive writes it,
../x and /etc/x included: writing entries out is List.extract of std/archive/extract, which refuses every
entry that would land outside of its directory.
The operations are members of the lists they work on, written where they are imported from: a member another package
names is found in the module of the package that is imported, so use List.tarred, Buffer.untarred from "std/archive"
needs them here.
Examples
use List.tarred, Buffer.untarred from "std/archive"
const entry = TarEntry "src/lib.trb", "public fn one(): Int \{\n 1\n\}\n".bytes()
const archive = List.of(entry).tarred().expect("a path ustar can hold")
print archive.untarred().map({ found => found.map({ _.path }).toList() })
type TarKind
type TarKind with Show, Equals, Hash
What an entry of an archive is.
case File
case File
A regular file: the bytes of the entry.
case Directory
case Directory
A directory. Its entry has no bytes.
case SymbolicLink
case SymbolicLink(target: String)
A symbolic link to target, which the system reads from the directory of the link. Its entry has no bytes.
case HardLink
case HardLink(target: String)
A second name of the file target, a path of the same archive. Its entry has no bytes.
type TarEntry
type TarEntry
One entry of an archive: its path, with / between the directories and without one at the end, its bytes, what it
is, its permission bits the way POSIX writes them (0b111_101_101 is 0755, a program) and the time it was last
written, in seconds since 1970. A file that is only a path and bytes is TarEntry(path, bytes): 0644, time 0.
field path
path: String
The path of the entry, with / between the directories and without one at the end.
field bytes
bytes: Bytes
The bytes of a file; empty for a directory and for a link.
field kind
kind: TarKind = TarKind.File
What the entry is; a file unless it says otherwise.
field mode
mode: Int = 0b110_100_100
The permission bits, the way POSIX writes them: 0b110_100_100 is 0644, which is also the default.
field modified
modified: Int = 0
The time the entry was last written, in seconds since 1970; 0 by default.
fn directory
static fn directory(path: String, mode: Int = 0b111_101_101): Self
A directory, 0755 unless mode says otherwise.
fn symbolicLink
static fn symbolicLink(path: String, target: String): Self
A symbolic link at path to target, 0777 as every system shows one.
type ArchiveError
type ArchiveError with Show, Error
A path an archive cannot hold, or an archive that breaks the format: what, and the byte where it was found.
extend ArchiveError with From<ReadError>
extend ArchiveError with From<ReadError>
A read of std/binary that failed on the bytes of an archive, with its own words and offset.
fn from
static fn from(value: ReadError): Self
extend List<TarEntry>
extend List<TarEntry>
The operations on a list of entries, written where they are imported from (see the top of this file).
fn tarred
fn tarred(): Result<Bytes, ArchiveError>
The entries as a ustar archive, sorted by path - the hard links after the rest, so that what each names is unpacked before it - with nothing of the machine in it but what the entries say: no owner, no group, and every mode and time the entry's own. The same entries give the same bytes everywhere.
A path that fits ustar's fields - at most 100 bytes, or a prefix of 155 and a name of 100 split at a / - is
written in them alone, so an archive of such paths is plain ustar that every tar reads. A longer path, a link target of
more than 100 bytes, a size of 8 GiB or more and a time before 1970 or after 2242 go into a pax header (x) in
front of the entry instead: pax is POSIX, every tar of the last twenty years reads it, and it has no limit of
length - where GNU's own long names are GNU's alone.
Errors
ArchiveErrorfor an empty path, two entries of one path, and a directory or a link with bytes.
extend Bytes
extend Bytes
The operation on the bytes of an archive.
fn untarred
fn untarred(): Result<List<TarEntry>, ArchiveError>
The entries of an archive, in the order it holds them: regular files, directories, symbolic links and hard links,
each with its mode and its time. What the formats add around an entry is read into it - a path of GNU's long names
(L, K), of ustar's prefix, or of a pax header (x for the next entry, g for every one after it: path,
linkpath, size and mtime, every other key ignored) - and is no entry of its own. A trailing / of a
directory is dropped.
Errors
ArchiveErrorfor a header whose checksum does not match, a number that is none, a pax record that is not<length> <key>=<value>, a path that is not UTF-8, an archive that ends inside an entry or without its blocks of zeros, and an entry that is a device, a pipe, a sparse file or of a type this reader does not know.