Class: Archive::Tar::Minitar::PosixHeader

Inherits:
Object
  • Object
show all
Includes:
ByteSize
Defined in:
lib/archive/tar/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.



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/archive/tar/minitar/posix_header.rb', line 133

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.



60
61
62
# File 'lib/archive/tar/minitar/posix_header.rb', line 60

def name
  @name
end

Class Method Details

.from_data(data) ⇒ Object

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



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
114
115
116
117
118
119
120
121
# File 'lib/archive/tar/minitar/posix_header.rb', line 81

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.



69
70
71
# File 'lib/archive/tar/minitar/posix_header.rb', line 69

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.



75
76
77
78
# File 'lib/archive/tar/minitar/posix_header.rb', line 75

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)


152
153
154
# File 'lib/archive/tar/minitar/posix_header.rb', line 152

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)


163
164
165
# File 'lib/archive/tar/minitar/posix_header.rb', line 163

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

#to_sObject Also known as: to_str

A string representation of the header.



168
169
170
171
# File 'lib/archive/tar/minitar/posix_header.rb', line 168

def to_s
  update_checksum
  header(@checksum)
end

#update_checksumObject

Update the checksum field.



175
176
177
178
# File 'lib/archive/tar/minitar/posix_header.rb', line 175

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)


157
158
159
# File 'lib/archive/tar/minitar/posix_header.rb', line 157

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