module

Fluxion::Executor::Archive

Extracts one named member from a gzipped tar archive.

Written rather than delegated because the safety properties are the point. A release tarball is attacker-influenced input, so this reader:

  • bounds the decompressed stream, not just the compressed file, which is what stops a decompression bomb;
  • bounds each entry individually;
  • selects by an exact post-strip path match, never by basename, because two members can share one;
  • refuses symlinks, hardlinks, and device nodes, so nothing can redirect the extraction outside the destination.

Only tar.gz is handled in-process. .zip and .tar.xz are delegated, rather than growing two more parsers with the same obligations.

Constants

BLOCK_SIZE = 512

Header fields, at their fixed USTAR offsets.

LONG_NAME_TYPE = 'L'

GNU long-name records: the following header's name comes from this entry's body rather than its own name field.

MAX_ENTRY_BYTES = ((1_i64 * 1024) * 1024) * 1024
MAX_STREAM_BYTES = ((2_i64 * 1024) * 1024) * 1024
NAME_LENGTH = 100
NAME_OFFSET = 0
PREFIX_LENGTH = 155
PREFIX_OFFSET = 345
REGULAR_TYPES = {'0', '\0'}

Regular files. \0 is the pre-POSIX spelling of 0.

SIZE_LENGTH = 12
SIZE_OFFSET = 124
TYPE_OFFSET = 156

Instance methods

extract(archive : String, archive_path : String, destination : String, strip_components : Int32 = 0) : String

Extracts the member at archive_path (after stripping strip_components leading path segments) into destination. Returns its SHA-256.

Source
members(archive : String, limit : Int32 = 50) : Array(Member)

Lists the regular-file members, for diagnostics when a path does not match. Bounded like everything else here.

Source
normalize(path : String) : String

GNU tar writes ./bin/rg when archiving a directory's contents, but a profile author writes bin/rg. The prefix carries no meaning, so it is removed rather than made the user's problem.

Source
strip(path : String, count : Int32) : String

Drops count leading path segments. A path with too few segments can never match, which is the honest answer rather than falling back to the unstripped name.

Source

Nested types