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".freeze
"././@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".freeze
HEADER_UNPACK_FORMAT =

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

"Z100A8A8A8A12A12A8aZ100A6A2Z32Z32A8A8Z155".freeze

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.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# 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

Instance Attribute Details

#nameObject

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.



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

def name
  @name
end

Class Method Details

.from_data(data) ⇒ Object

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



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
109
110
111
112
113
# 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) ⇒ Object

Creates a new PosixHeader from a data stream.



61
62
63
# File 'lib/minitar/posix_header.rb', line 61

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

.new_from_stream(stream) ⇒ Object

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



67
68
69
70
# 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

Instance Method Details

#empty?Boolean

Indicates if the header was an empty header.

Returns:

  • (Boolean)


144
145
146
# File 'lib/minitar/posix_header.rb', line 144

def empty?
  @empty
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)


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

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

#to_sObject Also known as: to_str

A string representation of the header.



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

def to_s
  update_checksum
  header(@checksum)
end

#update_checksumObject

Update the checksum field.



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

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)


149
150
151
# File 'lib/minitar/posix_header.rb', line 149

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