diff options
author | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-12-14 15:09:35 +0000 |
---|---|---|
committer | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-12-14 15:09:35 +0000 |
commit | 1a74fa4b04da04bd2bb33103dd3cf431438df38e (patch) | |
tree | f4a1d6c2961339e0c1d653c0f8427a53315080f0 /ruby_2_2/lib/rubygems/package/tar_header.rb | |
parent | a5b755e50e2d9aabf28ba24bf58644ca22b01a4f (diff) |
add tag v2_2_9
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v2_2_9@61257 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ruby_2_2/lib/rubygems/package/tar_header.rb')
-rw-r--r-- | ruby_2_2/lib/rubygems/package/tar_header.rb | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/ruby_2_2/lib/rubygems/package/tar_header.rb b/ruby_2_2/lib/rubygems/package/tar_header.rb new file mode 100644 index 0000000000..f9ab13aca7 --- /dev/null +++ b/ruby_2_2/lib/rubygems/package/tar_header.rb @@ -0,0 +1,229 @@ +# -*- coding: utf-8 -*- +#-- +# Copyright (C) 2004 Mauricio Julio Fernández Pradier +# See LICENSE.txt for additional licensing information. +#++ + +## +#-- +# 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 + +class Gem::Package::TarHeader + + ## + # Fields in the tar header + + FIELDS = [ + :checksum, + :devmajor, + :devminor, + :gid, + :gname, + :linkname, + :magic, + :mode, + :mtime, + :name, + :prefix, + :size, + :typeflag, + :uid, + :uname, + :version, + ] + + ## + # Pack format for a tar header + + PACK_FORMAT = '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' # prefix + + ## + # Unpack format for a tar header + + UNPACK_FORMAT = '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' # prefix + + attr_reader(*FIELDS) + + ## + # Creates a tar header from IO +stream+ + + 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 + + ## + # Creates a new TarHeader using +vals+ + + 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" 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 + + ## + # Is the tar entry empty? + + def empty? + @empty + end + + 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 + + def to_s # :nodoc: + update_checksum + header + end + + ## + # Updates the TarHeader's checksum + + 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 + |