summaryrefslogtreecommitdiff
path: root/jni/ruby/lib/rubygems/package/tar_header.rb
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-16 18:49:26 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-30 00:39:06 +0900
commitfcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch)
tree64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/lib/rubygems/package/tar_header.rb
Fresh start
Diffstat (limited to 'jni/ruby/lib/rubygems/package/tar_header.rb')
-rw-r--r--jni/ruby/lib/rubygems/package/tar_header.rb229
1 files changed, 229 insertions, 0 deletions
diff --git a/jni/ruby/lib/rubygems/package/tar_header.rb b/jni/ruby/lib/rubygems/package/tar_header.rb
new file mode 100644
index 0000000..f9ab13a
--- /dev/null
+++ b/jni/ruby/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
+