2 # Copyright (C) 2004 Mauricio Julio Fernández Pradier
3 # See LICENSE.txt for additional licensing information.
6 require 'rubygems/package'
10 # struct tarfile_entry_posix {
11 # char name[100]; # ASCII + (Z unless filled)
12 # char mode[8]; # 0 padded, octal, null
13 # char uid[8]; # ditto
14 # char gid[8]; # ditto
15 # char size[12]; # 0 padded, octal, null
16 # char mtime[12]; # 0 padded, octal, null
17 # char checksum[8]; # 0 padded, octal, null, space
18 # char typeflag[1]; # file: "0" dir: "5"
19 # char linkname[100]; # ASCII + (Z unless filled)
20 # char magic[6]; # "ustar\0"
21 # char version[2]; # "00"
22 # char uname[32]; # ASCIIZ
23 # char gname[32]; # ASCIIZ
24 # char devmajor[8]; # 0 padded, octal, null
25 # char devminor[8]; # o padded, octal, null
26 # char prefix[155]; # ASCII + (Z unless filled)
30 class Gem::Package::TarHeader
51 PACK_FORMAT = 'a100' + # name
68 UNPACK_FORMAT = 'A100' + # name
88 header = stream.read 512
89 empty = (header == "\0" * 512)
91 fields = header.unpack UNPACK_FORMAT
94 mode = fields.shift.oct
95 uid = fields.shift.oct
96 gid = fields.shift.oct
97 size = fields.shift.oct
98 mtime = fields.shift.oct
99 checksum = fields.shift.oct
100 typeflag = fields.shift
101 linkname = fields.shift
103 version = fields.shift.oct
106 devmajor = fields.shift.oct
107 devminor = fields.shift.oct
108 prefix = fields.shift
116 :checksum => checksum,
117 :typeflag => typeflag,
118 :linkname => linkname,
123 :devmajor => devmajor,
124 :devminor => devminor,
129 # HACK unfactor for Rubinius
130 #new :name => fields.shift,
131 # :mode => fields.shift.oct,
132 # :uid => fields.shift.oct,
133 # :gid => fields.shift.oct,
134 # :size => fields.shift.oct,
135 # :mtime => fields.shift.oct,
136 # :checksum => fields.shift.oct,
137 # :typeflag => fields.shift,
138 # :linkname => fields.shift,
139 # :magic => fields.shift,
140 # :version => fields.shift.oct,
141 # :uname => fields.shift,
142 # :gname => fields.shift,
143 # :devmajor => fields.shift.oct,
144 # :devminor => fields.shift.oct,
145 # :prefix => fields.shift,
151 unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
152 raise ArgumentError, ":name, :size, :prefix and :mode required"
158 vals[:checksum] ||= ""
159 vals[:typeflag] ||= "0"
160 vals[:magic] ||= "ustar"
161 vals[:version] ||= "00"
162 vals[:uname] ||= "wheel"
163 vals[:gname] ||= "wheel"
164 vals[:devmajor] ||= 0
165 vals[:devminor] ||= 0
167 FIELDS.each do |name|
168 instance_variable_set "@#{name}", vals[name]
171 @empty = vals[:empty]
179 self.class === other and
180 @checksum == other.checksum and
181 @devmajor == other.devmajor and
182 @devminor == other.devminor and
183 @gid == other.gid and
184 @gname == other.gname and
185 @linkname == other.linkname and
186 @magic == other.magic and
187 @mode == other.mode and
188 @mtime == other.mtime and
189 @name == other.name and
190 @prefix == other.prefix and
191 @size == other.size and
192 @typeflag == other.typeflag and
193 @uid == other.uid and
194 @uname == other.uname and
195 @version == other.version
204 header = header " " * 8
205 @checksum = oct calculate_checksum(header), 6
210 def calculate_checksum(header)
211 header.unpack("C*").inject { |a, b| a + b }
214 def header(checksum = @checksum)
235 header = header.pack PACK_FORMAT
237 header << ("\0" * ((512 - header.size) % 512))