class Minitar::PosixHeader

Implements the POSIX tar header as a Ruby class. The structure of the POSIX tar header is:

struct tarfile_entry_posix
{                      //                               pack/unpack
   char name[100];     // ASCII (+ Z unless filled)     a100/Z100
   char mode[8];       // 0 padded, octal, null         a8  /A8
   char uid[8];        // 0 padded, octal, null         a8  /A8
   char gid[8];        // 0 padded, octal, null         a8  /A8
   char size[12];      // 0 padded, octal, null         a12 /A12
   char mtime[12];     // 0 padded, octal, null         a12 /A12
   char checksum[8];   // 0 padded, octal, null, space  a8  /A8
   char typeflag[1];   // see below                     a   /a
   char linkname[100]; // ASCII + (Z unless filled)     a100/Z100
   char magic[6];      // "ustar\0"                     a6  /A6
   char version[2];    // "00"                          a2  /A2
   char uname[32];     // ASCIIZ                        a32 /Z32
   char gname[32];     // ASCIIZ                        a32 /Z32
   char devmajor[8];   // 0 padded, octal, null         a8  /A8
   char devminor[8];   // 0 padded, octal, null         a8  /A8
   char prefix[155];   // ASCII (+ Z unless filled)     a155/Z155
};

The typeflag is one of several known values.

POSIX indicates that “A POSIX-compliant implementation must treat any unrecognized typeflag value as a regular file.”

Constants

BLOCK_SIZE
FIELDS

All fields available in a POSIX tar(1) header.

HEADER_PACK_FORMAT

The pack format passed to Array#pack for encoding a header.

HEADER_UNPACK_FORMAT

The unpack format passed to String#unpack for decoding a header.

MAGIC_BYTES
OPTIONAL_FIELDS

Fields that may be set in a POSIX tar(1) header.

REQUIRED_FIELDS

Fields that must be set in a POSIX tar(1) header.

Attributes

checksum[R]

The checksum of the file. Stored as an octal integer. Calculated before encoding the header as a string.

devmajor[R]

The major device ID. Not currently used.

devminor[R]

The minor device ID. Not currently used.

gid[R]

The Unix owner group ID of the file. Stored as an octal integer.

gname[R]

The group name of the Unix owner of the file.

linkname[R]

The name of the link stored. Not currently used.

magic[R]

Always “ustar0”.

mode[R]

The Unix file mode of the file. Stored as an octal integer. Required.

mtime[R]

The modification time of the file in epoch seconds. Stored as an octal integer.

name[RW]

The name of the file. By default, limited to 100 bytes. Required. May be longer (up to BLOCK_SIZE bytes) if using the GNU long name tar extension.

prefix[R]

The prefix of the file; the path before name. Limited to 155 bytes. Required.

size[R]

The size of the file. Required.

typeflag[R]

The type of record in the file.

0

Regular file. NULL should be treated as a synonym, for compatibility purposes.

1

Hard link.

2

Symbolic link.

3

Character device node.

4

Block device node.

5

Directory.

6

FIFO node.

7

Reserved.

uid[R]

The Unix owner user ID of the file. Stored as an octal integer.

uname[R]

The user name of the Unix owner of the file.

version[R]

Always “00”

Public Class Methods

from_data(data) click to toggle source

Creates a new PosixHeader from a BLOCK_SIZE-byte data buffer.

# File lib/minitar/posix_header.rb, line 73
def from_data(data)
  fields = data.unpack(HEADER_UNPACK_FORMAT)
  name = fields.shift
  mode = fields.shift.oct
  uid = fields.shift.oct
  gid = fields.shift.oct
  size = strict_oct(fields.shift)
  mtime = fields.shift.oct
  checksum = fields.shift.oct
  typeflag = fields.shift
  linkname = fields.shift
  magic = fields.shift
  version = fields.shift.oct
  uname = fields.shift
  gname = fields.shift
  devmajor = fields.shift.oct
  devminor = fields.shift.oct
  prefix = fields.shift

  empty = !data.each_byte.any?(&:nonzero?)

  new(
    name: name,
    mode: mode,
    uid: uid,
    gid: gid,
    size: size,
    mtime: mtime,
    checksum: checksum,
    typeflag: typeflag,
    magic: magic,
    version: version,
    uname: uname,
    gname: gname,
    devmajor: devmajor,
    devminor: devminor,
    prefix: prefix,
    empty: empty,
    linkname: linkname
  )
end
from_stream(stream) click to toggle source

Creates a new PosixHeader from a data stream.

# File lib/minitar/posix_header.rb, line 61
def from_stream(stream)
  from_data(stream.read(BLOCK_SIZE))
end
new(v) click to toggle source

Creates a new PosixHeader. A PosixHeader cannot be created unless name, size, prefix, and mode are provided.

# File lib/minitar/posix_header.rb, line 125
def initialize(v)
  REQUIRED_FIELDS.each do |f|
    raise ArgumentError, "Field #{f} is required." unless v.key?(f)
  end

  v[:mtime] = v[:mtime].to_i
  v[:checksum] ||= ""
  v[:typeflag] ||= "0"
  v[:magic] ||= MAGIC_BYTES
  v[:version] ||= "00"

  FIELDS.each do |f|
    instance_variable_set(:"@#{f}", v[f])
  end

  @empty = v[:empty]
end
new_from_stream(stream) click to toggle source

Creates a new PosixHeader from a data stream. Deprecated; use PosixHeader.from_stream instead.

# File lib/minitar/posix_header.rb, line 67
def new_from_stream(stream)
  warn "#{__method__} has been deprecated; use from_stream instead."
  from_stream(stream)
end

Private Class Methods

strict_oct(string) click to toggle source
# File lib/minitar/posix_header.rb, line 117
def strict_oct(string)
  return string.oct if /\A[0-7 ]*\z/.match?(string)
  raise ArgumentError, "#{string.inspect} is not a valid octal string"
end

Public Instance Methods

empty?() click to toggle source

Indicates if the header was an empty header.

# File lib/minitar/posix_header.rb, line 144
def empty?
  @empty
end
long_name?() click to toggle source

Returns true if the header is a long name special header which indicates that the next block of data is the filename.

# File lib/minitar/posix_header.rb, line 155
def long_name?
  typeflag == "L" && name == GNU_EXT_LONG_LINK
end
to_s() click to toggle source

A string representation of the header.

# File lib/minitar/posix_header.rb, line 160
def to_s
  update_checksum
  header(@checksum)
end
Also aliased as: to_str
to_str()
Alias for: to_s
update_checksum() click to toggle source

Update the checksum field.

# File lib/minitar/posix_header.rb, line 167
def update_checksum
  hh = header(" " * 8)
  @checksum = oct(calculate_checksum(hh), 6)
end
valid?() click to toggle source

Indicates if the header has a valid magic value.

# File lib/minitar/posix_header.rb, line 149
def valid?
  empty? || @magic == MAGIC_BYTES
end

Private Instance Methods

calculate_checksum(hdr) click to toggle source
# File lib/minitar/posix_header.rb, line 182
def calculate_checksum(hdr)
  hdr.unpack("C*").inject { |a, e| a + e }
end
header(chksum) click to toggle source
# File lib/minitar/posix_header.rb, line 186
def header(chksum)
  arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),
    oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version,
    uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
  str = arr.pack(HEADER_PACK_FORMAT)
  str + "\0" * ((BLOCK_SIZE - str.bytesize) % BLOCK_SIZE)
end
oct(num, len) click to toggle source
# File lib/minitar/posix_header.rb, line 174
def oct(num, len)
  if num.nil?
    "\0" * (len + 1)
  else
    "%0#{len}o" % num
  end
end