Class: Minitar::PosixHeader

Inherits:
Object
  • Object
show all
Defined in:
lib/minitar/posix_header.rb

Overview

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.”

Constant Summary collapse

BLOCK_SIZE =
512
MAGIC_BYTES =
"ustar"
"././@LongLink"
REQUIRED_FIELDS =

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

[:name, :size, :prefix, :mode].freeze
OPTIONAL_FIELDS =

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

[
  :uid, :gid, :mtime, :checksum, :typeflag, :linkname, :magic, :version, :uname,
  :gname, :devmajor, :devminor
].freeze
FIELDS =

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

(REQUIRED_FIELDS + OPTIONAL_FIELDS).freeze
HEADER_PACK_FORMAT =

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

"a100a8a8a8a12a12a7aaa100a6a2a32a32a8a8a155"
HEADER_UNPACK_FORMAT =

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

"Z100A8A8A8a12A12A8aZ100A6A2Z32Z32A8A8Z155"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(v) ⇒ PosixHeader

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



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/minitar/posix_header.rb', line 136

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]

  valid_name!(v[:name]) unless v[:empty]
end

Instance Attribute Details

#size=(value) ⇒ Object (writeonly)

Sets the attribute size

Parameters:

  • value

    the value to set the attribute size to.



56
57
58
# File 'lib/minitar/posix_header.rb', line 56

def size=(value)
  @size = value
end

Class Method Details

.from_data(data) ⇒ Object

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



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/minitar/posix_header.rb', line 68

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 = parse_numeric_field(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) ⇒ Object

Creates a new PosixHeader from a data stream.



65
# File 'lib/minitar/posix_header.rb', line 65

def from_stream(stream) = from_data(stream.read(BLOCK_SIZE))

Instance Method Details

#empty?Boolean

Indicates if the header was an empty header.

Returns:

  • (Boolean)


157
# File 'lib/minitar/posix_header.rb', line 157

def empty? = @empty

#long_name=(value) ⇒ Object

Sets the name to the value provided and clears prefix.

Used by Minitar::Reader#each_entry to set the long name when processing GNU long filename extensions.

The value must be the complete name, including leading directory components.



176
177
178
179
180
181
# File 'lib/minitar/posix_header.rb', line 176

def long_name=(value)
  valid_name!(value)

  @prefix = ""
  @name = value
end

#long_name?Boolean

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

Returns:

  • (Boolean)


164
# File 'lib/minitar/posix_header.rb', line 164

def long_name? = typeflag == "L" && name == GNU_EXT_LONG_LINK

#name=(value) ⇒ Object



51
52
53
54
# File 'lib/minitar/posix_header.rb', line 51

def name=(value)
  valid_name!(value)
  @name = value
end

#pax_header?Boolean

Returns true if the header is a PAX extended header which contains metadata for the next file entry.

Returns:

  • (Boolean)


168
# File 'lib/minitar/posix_header.rb', line 168

def pax_header? = typeflag == "x"

#to_sObject Also known as: to_str

A string representation of the header.



184
185
186
187
# File 'lib/minitar/posix_header.rb', line 184

def to_s
  update_checksum
  header(@checksum)
end

#update_checksumObject

Update the checksum field.



193
194
195
196
# File 'lib/minitar/posix_header.rb', line 193

def update_checksum
  hh = header(" " * 8)
  @checksum = oct(calculate_checksum(hh), 6)
end

#valid?Boolean

Indicates if the header has a valid magic value.

Returns:

  • (Boolean)


160
# File 'lib/minitar/posix_header.rb', line 160

def valid? = empty? || @magic == MAGIC_BYTES