Documentation
¶
Overview ¶
Package cpio reads the records of a cpio archive, in all four variants, and stops there.
It returns records rather than a filesystem, and that is the whole design. Two packages needed this parser -- go-filesystems/unarchive for an initramfs and a .deb's data member, go-filesystems/rpm for a payload -- and they need DIFFERENT filesystems over it: unarchive indexes into an io.ReaderAt it keeps open, rpm has the whole payload decompressed in memory. Sharing the filesystem would have meant one of them accepting the other's shape; sharing the parser costs neither anything.
And the parser is where the defects live. Every trap below was measured, and each one had been got wrong at least once:
- newc pads the name AND the data to four bytes, from the start of the archive. Forgetting either puts every later header one to three bytes out.
- odc pads nothing at all.
- the old binary variant's magic is 0o070707 as a 16-bit WORD, so the same two bytes mean it on the machine that wrote them and 0o143561 on one of the other endianness. Both orders exist and the order is DETECTED, not assumed.
- that variant's 32-bit fields are two words, HIGH WORD FIRST, whatever the byte order of each word -- and it pads to an even length, not to four.
- a reader that returns the next offset as a computed value rather than a parameter returned zero once, and the walk re-read record one for ever. The suite reported a ten-minute timeout, not a failure.
CGO is not used, so this builds for every target Go builds for.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNotCpio = errors.New("cpio: not a cpio archive")
ErrNotCpio is returned when the bytes do not begin with any cpio magic.
var ErrTruncated = errors.New("cpio: the archive ends inside a record")
ErrTruncated is returned when a header or a name runs past the end.
Functions ¶
func FileMode ¶
FileMode turns a POSIX st_mode into an iofs.FileMode.
⛔ The type is in the HIGH bits of the octal value, not in iofs.FileMode's own places: S_IFDIR is 0o040000 while iofs.ModeDir is 1<<31. Narrowing one into the other without this switch leaves every directory looking like a file with peculiar permissions.
Types ¶
type Record ¶
type Record struct {
// Name is the name AS RECORDED, which is not the same as a clean path: GNU
// cpio writes "./real.txt" where other writers write "real.txt", and an
// archive made on Windows can carry backslashes. Normalising is left to the
// caller because both callers already do it, for lookups as well as for
// listing, and a parser that silently rewrote names would make their two
// spellings disagree with this one.
Name string
// Mode carries the permissions AND the type bits, already translated from
// POSIX st_mode -- see FileMode for why that translation is not a cast.
Mode iofs.FileMode
Size int64
// Offset is where this record's data begins in the reader.
Offset int64
// Link is the target of a symbolic link, read from the record's data. A cpio
// stores it there rather than in the header, which is why it is read here and
// not left to the caller.
Link string
MTime time.Time
}
Record is one entry, with its data left where it lies.
Offset points into the reader Records was given, so a caller can hand out a section of it rather than copying anything.
func Records ¶
Records reads every record in the archive.
The variant is decided per record from its own magic, because an archive concatenated from two others is a thing that exists. Trailing padding after the trailer is normal -- an initramfs is padded to a block -- so what follows the trailer is ignored rather than refused.