class Gem::Package::TarHeader
FIELDS = [
:checksum,
:devmajor,
:devminor,
:gid,
:gname,
:linkname,
:magic,
:mode,
:mtime,
:name,
:prefix,
:size,
:typeflag,
:uid,
:uname,
:version,
]
PACK_FORMAT = 'a100' + 'a8' + 'a8' + 'a8' + 'a12' + 'a12' + 'a7a' + 'a' + 'a100' + 'a6' + 'a2' + 'a32' + 'a32' + 'a8' + 'a8' + 'a155'
UNPACK_FORMAT = 'A100' + 'A8' + 'A8' + 'A8' + 'A12' + 'A12' + 'A8' + 'A' + 'A100' + 'A6' + 'A2' + 'A32' + 'A32' + 'A8' + 'A8' + 'A155'
attr_reader(*FIELDS)
def self.from(stream)
header = stream.read 512
empty = (header == "\0" * 512)
fields = header.unpack UNPACK_FORMAT
new :name => fields.shift,
:mode => fields.shift.oct,
:uid => fields.shift.oct,
:gid => fields.shift.oct,
:size => fields.shift.oct,
: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 => empty
end
def initialize(vals)
unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
raise ArgumentError, ":name, :size, :prefix and :mode required"
end
vals[:uid] ||= 0
vals[:gid] ||= 0
vals[:mtime] ||= 0
vals[:checksum] ||= ""
vals[:typeflag] ||= "0"
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
def empty?
@empty
end
def ==(other) 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
def to_s # :nodoc:
update_checksum
header
end
def update_checksum
header = header " " * 8
@checksum = oct calculate_checksum(header), 6
end
private
def calculate_checksum(header)
header.unpack("C*").inject { |a, b| a + b }
end
def header(checksum = @checksum)
header = [
name,
oct(mode, 7),
oct(uid, 7),
oct(gid, 7),
oct(size, 11),
oct(mtime, 11),
checksum,
" ",
typeflag,
linkname,
magic,
oct(version, 2),
uname,
gname,
oct(devmajor, 7),
oct(devminor, 7),
prefix
]
header = header.pack PACK_FORMAT
header << ("\0" * ((512 - header.size) % 512))
end
def oct(num, len)
"%0#{len}o" % num
end
end