Class: Gem::Package::TarHeader

Inherits:
Object
  • Object
show all
Defined in:
lib/rubygems/package/tar_header.rb

Overview

– struct tarfile_entry_posix

char name[100];     # ASCII + (Z unless filled)
char mode[8];       # 0 padded, octal, null
char uid[8];        # ditto
char gid[8];        # ditto
char size[12];      # 0 padded, octal, null
char mtime[12];     # 0 padded, octal, null
char checksum[8];   # 0 padded, octal, null, space
char typeflag[1];   # file: "0"  dir: "5"
char linkname[100]; # ASCII + (Z unless filled)
char magic[6];      # "ustar\0"
char version[2];    # "00"
char uname[32];     # ASCIIZ
char gname[32];     # ASCIIZ
char devmajor[8];   # 0 padded, octal, null
char devminor[8];   # o padded, octal, null
char prefix[155];   # ASCII + (Z unless filled)

; ++ A header for a tar file

Constant Summary collapse

FIELDS =

Fields in the tar header

[
  :checksum,
  :devmajor,
  :devminor,
  :gid,
  :gname,
  :linkname,
  :magic,
  :mode,
  :mtime,
  :name,
  :prefix,
  :size,
  :typeflag,
  :uid,
  :uname,
  :version,
].freeze
PACK_FORMAT =

Pack format for a tar header

'a100' + # name
'a8'   + # mode
'a8'   + # uid
'a8'   + # gid
'a12'  + # size
'a12'  + # mtime
'a7a'  + # chksum
'a'    + # typeflag
'a100' + # linkname
'a6'   + # magic
'a2'   + # version
'a32'  + # uname
'a32'  + # gname
'a8'   + # devmajor
'a8'   + # devminor
'a155'
UNPACK_FORMAT =

Unpack format for a tar header

'A100' + # name
'A8'   + # mode
'A8'   + # uid
'A8'   + # gid
'A12'  + # size
'A12'  + # mtime
'A8'   + # checksum
'A'    + # typeflag
'A100' + # linkname
'A6'   + # magic
'A2'   + # version
'A32'  + # uname
'A32'  + # gname
'A8'   + # devmajor
'A8'   + # devminor
'A155'
EMPTY_HEADER =

:nodoc:

("\0" * 512).freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(vals) ⇒ TarHeader

Creates a new TarHeader using vals


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/rubygems/package/tar_header.rb', line 145

def initialize(vals)
  unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode]
    raise ArgumentError, ":name, :size, :prefix and :mode required"
  end

  vals[:uid] ||= 0
  vals[:gid] ||= 0
  vals[:mtime] ||= 0
  vals[:checksum] ||= ""
  vals[:typeflag] = "0" if vals[:typeflag].nil? || vals[:typeflag].empty?
  vals[:magic] ||= "ustar"
  vals[:version] ||= "00"
  vals[:uname] ||= "wheel"
  vals[:gname] ||= "wheel"
  vals[:devmajor] ||= 0
  vals[:devminor] ||= 0

  FIELDS.each do |name|
    instance_variable_set "@#{name}", vals[name]
  end

  @empty = vals[:empty]
end

Class Method Details

.from(stream) ⇒ Object

Creates a tar header from IO stream


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rubygems/package/tar_header.rb', line 102

def self.from(stream)
  header = stream.read 512
  empty = (EMPTY_HEADER == header)

  fields = header.unpack UNPACK_FORMAT

  new :name     => fields.shift,
      :mode     => strict_oct(fields.shift),
      :uid      => oct_or_256based(fields.shift),
      :gid      => oct_or_256based(fields.shift),
      :size     => strict_oct(fields.shift),
      :mtime    => strict_oct(fields.shift),
      :checksum => strict_oct(fields.shift),
      :typeflag => fields.shift,
      :linkname => fields.shift,
      :magic    => fields.shift,
      :version  => strict_oct(fields.shift),
      :uname    => fields.shift,
      :gname    => fields.shift,
      :devmajor => strict_oct(fields.shift),
      :devminor => strict_oct(fields.shift),
      :prefix   => fields.shift,

      :empty => empty
end

.oct_or_256based(str) ⇒ Object


133
134
135
136
137
138
139
140
# File 'lib/rubygems/package/tar_header.rb', line 133

def self.oct_or_256based(str)
  # \x80 flags a positive 256-based number
  # \ff flags a negative 256-based number
  # In case we have a match, parse it as a signed binary value
  # in big-endian order, except that the high-order bit is ignored.
  return str.unpack('N2').last if str =~ /\A[\x80\xff]/n
  strict_oct(str)
end

.strict_oct(str) ⇒ Object

Raises:

  • (ArgumentError)

128
129
130
131
# File 'lib/rubygems/package/tar_header.rb', line 128

def self.strict_oct(str)
  return str.oct if str =~ /\A[0-7]*\z/
  raise ArgumentError, "#{str.inspect} is not an octal string"
end

Instance Method Details

#==(other) ⇒ Object

:nodoc:


176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/rubygems/package/tar_header.rb', line 176

def ==(other) # :nodoc:
  self.class === other and
  @checksum == other.checksum and
  @devmajor == other.devmajor and
  @devminor == other.devminor and
  @gid      == other.gid      and
  @gname    == other.gname    and
  @linkname == other.linkname and
  @magic    == other.magic    and
  @mode     == other.mode     and
  @mtime    == other.mtime    and
  @name     == other.name     and
  @prefix   == other.prefix   and
  @size     == other.size     and
  @typeflag == other.typeflag and
  @uid      == other.uid      and
  @uname    == other.uname    and
  @version  == other.version
end

#empty?Boolean

Is the tar entry empty?

Returns:

  • (Boolean)

172
173
174
# File 'lib/rubygems/package/tar_header.rb', line 172

def empty?
  @empty
end

#to_sObject

:nodoc:


196
197
198
199
# File 'lib/rubygems/package/tar_header.rb', line 196

def to_s # :nodoc:
  update_checksum
  header
end

#update_checksumObject

Updates the TarHeader's checksum


204
205
206
207
# File 'lib/rubygems/package/tar_header.rb', line 204

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