diff options
Diffstat (limited to 'ruby_2_2/lib/rubygems/package')
-rw-r--r-- | ruby_2_2/lib/rubygems/package/digest_io.rb | 64 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/file_source.rb | 33 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/io_source.rb | 45 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/old.rb | 178 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/source.rb | 3 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/tar_header.rb | 229 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/tar_reader.rb | 123 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/tar_reader/entry.rb | 147 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/tar_test_case.rb | 137 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/package/tar_writer.rb | 326 |
10 files changed, 0 insertions, 1285 deletions
diff --git a/ruby_2_2/lib/rubygems/package/digest_io.rb b/ruby_2_2/lib/rubygems/package/digest_io.rb deleted file mode 100644 index f8bde0f557..0000000000 --- a/ruby_2_2/lib/rubygems/package/digest_io.rb +++ /dev/null @@ -1,64 +0,0 @@ -## -# IO wrapper that creates digests of contents written to the IO it wraps. - -class Gem::Package::DigestIO - - ## - # Collected digests for wrapped writes. - # - # { - # 'SHA1' => #<OpenSSL::Digest: [...]>, - # 'SHA512' => #<OpenSSL::Digest: [...]>, - # } - - attr_reader :digests - - ## - # Wraps +io+ and updates digest for each of the digest algorithms in - # the +digests+ Hash. Returns the digests hash. Example: - # - # io = StringIO.new - # digests = { - # 'SHA1' => OpenSSL::Digest.new('SHA1'), - # 'SHA512' => OpenSSL::Digest.new('SHA512'), - # } - # - # Gem::Package::DigestIO.wrap io, digests do |digest_io| - # digest_io.write "hello" - # end - # - # digests['SHA1'].hexdigest #=> "aaf4c61d[...]" - # digests['SHA512'].hexdigest #=> "9b71d224[...]" - - def self.wrap io, digests - digest_io = new io, digests - - yield digest_io - - return digests - end - - ## - # Creates a new DigestIO instance. Using ::wrap is recommended, see the - # ::wrap documentation for documentation of +io+ and +digests+. - - def initialize io, digests - @io = io - @digests = digests - end - - ## - # Writes +data+ to the underlying IO and updates the digests - - def write data - result = @io.write data - - @digests.each do |_, digest| - digest << data - end - - result - end - -end - diff --git a/ruby_2_2/lib/rubygems/package/file_source.rb b/ruby_2_2/lib/rubygems/package/file_source.rb deleted file mode 100644 index 85316f62e7..0000000000 --- a/ruby_2_2/lib/rubygems/package/file_source.rb +++ /dev/null @@ -1,33 +0,0 @@ -## -# The primary source of gems is a file on disk, including all usages -# internal to rubygems. -# -# This is a private class, do not depend on it directly. Instead, pass a path -# object to `Gem::Package.new`. - -class Gem::Package::FileSource < Gem::Package::Source # :nodoc: all - - attr_reader :path - - def initialize path - @path = path - end - - def start - @start ||= File.read path, 20 - end - - def present? - File.exist? path - end - - def with_write_io &block - open path, 'wb', &block - end - - def with_read_io &block - open path, 'rb', &block - end - -end - diff --git a/ruby_2_2/lib/rubygems/package/io_source.rb b/ruby_2_2/lib/rubygems/package/io_source.rb deleted file mode 100644 index f89593dd2d..0000000000 --- a/ruby_2_2/lib/rubygems/package/io_source.rb +++ /dev/null @@ -1,45 +0,0 @@ -## -# Supports reading and writing gems from/to a generic IO object. This is -# useful for other applications built on top of rubygems, such as -# rubygems.org. -# -# This is a private class, do not depend on it directly. Instead, pass an IO -# object to `Gem::Package.new`. - -class Gem::Package::IOSource < Gem::Package::Source # :nodoc: all - - attr_reader :io - - def initialize io - @io = io - end - - def start - @start ||= begin - if io.pos > 0 - raise Gem::Package::Error, "Cannot read start unless IO is at start" - end - - value = io.read 20 - io.rewind - value - end - end - - def present? - true - end - - def with_read_io - yield io - end - - def with_write_io - yield io - end - - def path - end - -end - diff --git a/ruby_2_2/lib/rubygems/package/old.rb b/ruby_2_2/lib/rubygems/package/old.rb deleted file mode 100644 index 7a9a9015c1..0000000000 --- a/ruby_2_2/lib/rubygems/package/old.rb +++ /dev/null @@ -1,178 +0,0 @@ -#-- -# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. -# All rights reserved. -# See LICENSE.txt for permissions. -#++ - -## -# The format class knows the guts of the ancient .gem file format and provides -# the capability to read such ancient gems. -# -# Please pretend this doesn't exist. - -class Gem::Package::Old < Gem::Package - - undef_method :spec= - - ## - # Creates a new old-format package reader for +gem+. Old-format packages - # cannot be written. - - def initialize gem - require 'fileutils' - require 'zlib' - Gem.load_yaml - - @contents = nil - @gem = gem - @security_policy = nil - @spec = nil - end - - ## - # A list of file names contained in this gem - - def contents - verify - - return @contents if @contents - - @gem.with_read_io do |io| - read_until_dashes io # spec - header = file_list io - - @contents = header.map { |file| file['path'] } - end - end - - ## - # Extracts the files in this package into +destination_dir+ - - def extract_files destination_dir - verify - - errstr = "Error reading files from gem" - - @gem.with_read_io do |io| - read_until_dashes io # spec - header = file_list io - raise Gem::Exception, errstr unless header - - header.each do |entry| - full_name = entry['path'] - - destination = install_location full_name, destination_dir - - file_data = '' - - read_until_dashes io do |line| - file_data << line - end - - file_data = file_data.strip.unpack("m")[0] - file_data = Zlib::Inflate.inflate file_data - - raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if - file_data.length != entry['size'].to_i - - FileUtils.rm_rf destination - - FileUtils.mkdir_p File.dirname destination - - open destination, 'wb', entry['mode'] do |out| - out.write file_data - end - - verbose destination - end - end - rescue Zlib::DataError - raise Gem::Exception, errstr - end - - ## - # Reads the file list section from the old-format gem +io+ - - def file_list io # :nodoc: - header = '' - - read_until_dashes io do |line| - header << line - end - - Gem::SafeYAML.safe_load header - end - - ## - # Reads lines until a "---" separator is found - - def read_until_dashes io # :nodoc: - while (line = io.gets) && line.chomp.strip != "---" do - yield line if block_given? - end - end - - ## - # Skips the Ruby self-install header in +io+. - - def skip_ruby io # :nodoc: - loop do - line = io.gets - - return if line.chomp == '__END__' - break unless line - end - - raise Gem::Exception, "Failed to find end of ruby script while reading gem" - end - - ## - # The specification for this gem - - def spec - verify - - return @spec if @spec - - yaml = '' - - @gem.with_read_io do |io| - skip_ruby io - read_until_dashes io do |line| - yaml << line - end - end - - yaml_error = if RUBY_VERSION < '1.9' then - YAML::ParseError - elsif YAML.const_defined?(:ENGINE) && YAML::ENGINE.yamler == 'syck' then - YAML::ParseError - else - YAML::SyntaxError - end - - begin - @spec = Gem::Specification.from_yaml yaml - rescue yaml_error - raise Gem::Exception, "Failed to parse gem specification out of gem file" - end - rescue ArgumentError - raise Gem::Exception, "Failed to parse gem specification out of gem file" - end - - ## - # Raises an exception if a security policy that verifies data is active. - # Old format gems cannot be verified as signed. - - def verify - return true unless @security_policy - - raise Gem::Security::Exception, - 'old format gems do not contain signatures and cannot be verified' if - @security_policy.verify_data - - true - end - -end - diff --git a/ruby_2_2/lib/rubygems/package/source.rb b/ruby_2_2/lib/rubygems/package/source.rb deleted file mode 100644 index 1f18d479da..0000000000 --- a/ruby_2_2/lib/rubygems/package/source.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Gem::Package::Source # :nodoc: -end - diff --git a/ruby_2_2/lib/rubygems/package/tar_header.rb b/ruby_2_2/lib/rubygems/package/tar_header.rb deleted file mode 100644 index f9ab13aca7..0000000000 --- a/ruby_2_2/lib/rubygems/package/tar_header.rb +++ /dev/null @@ -1,229 +0,0 @@ -# -*- 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 - diff --git a/ruby_2_2/lib/rubygems/package/tar_reader.rb b/ruby_2_2/lib/rubygems/package/tar_reader.rb deleted file mode 100644 index e257fdd846..0000000000 --- a/ruby_2_2/lib/rubygems/package/tar_reader.rb +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: utf-8 -*- -#-- -# Copyright (C) 2004 Mauricio Julio Fernández Pradier -# See LICENSE.txt for additional licensing information. -#++ - -## -# TarReader reads tar files and allows iteration over their items - -class Gem::Package::TarReader - - include Enumerable - - ## - # Raised if the tar IO is not seekable - - class UnexpectedEOF < StandardError; end - - ## - # Creates a new TarReader on +io+ and yields it to the block, if given. - - def self.new(io) - reader = super - - return reader unless block_given? - - begin - yield reader - ensure - reader.close - end - - nil - end - - ## - # Creates a new tar file reader on +io+ which needs to respond to #pos, - # #eof?, #read, #getc and #pos= - - def initialize(io) - @io = io - @init_pos = io.pos - end - - ## - # Close the tar file - - def close - end - - ## - # Iterates over files in the tarball yielding each entry - - def each - return enum_for __method__ unless block_given? - - until @io.eof? do - header = Gem::Package::TarHeader.from @io - return if header.empty? - - entry = Gem::Package::TarReader::Entry.new header, @io - size = entry.header.size - - yield entry - - skip = (512 - (size % 512)) % 512 - pending = size - entry.bytes_read - - begin - # avoid reading... - @io.seek pending, IO::SEEK_CUR - pending = 0 - rescue Errno::EINVAL, NameError - while pending > 0 do - bytes_read = @io.read([pending, 4096].min).size - raise UnexpectedEOF if @io.eof? - pending -= bytes_read - end - end - - @io.read skip # discard trailing zeros - - # make sure nobody can use #read, #getc or #rewind anymore - entry.close - end - end - - alias each_entry each - - ## - # NOTE: Do not call #rewind during #each - - def rewind - if @init_pos == 0 then - raise Gem::Package::NonSeekableIO unless @io.respond_to? :rewind - @io.rewind - else - raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos= - @io.pos = @init_pos - end - end - - ## - # Seeks through the tar file until it finds the +entry+ with +name+ and - # yields it. Rewinds the tar file to the beginning when the block - # terminates. - - def seek name # :yields: entry - found = find do |entry| - entry.full_name == name - end - - return unless found - - return yield found - ensure - rewind - end - -end - -require 'rubygems/package/tar_reader/entry' - diff --git a/ruby_2_2/lib/rubygems/package/tar_reader/entry.rb b/ruby_2_2/lib/rubygems/package/tar_reader/entry.rb deleted file mode 100644 index 737c7639c6..0000000000 --- a/ruby_2_2/lib/rubygems/package/tar_reader/entry.rb +++ /dev/null @@ -1,147 +0,0 @@ -# -*- coding: utf-8 -*- -#++ -# Copyright (C) 2004 Mauricio Julio Fernández Pradier -# See LICENSE.txt for additional licensing information. -#-- - -## -# Class for reading entries out of a tar file - -class Gem::Package::TarReader::Entry - - ## - # Header for this tar entry - - attr_reader :header - - ## - # Creates a new tar entry for +header+ that will be read from +io+ - - def initialize(header, io) - @closed = false - @header = header - @io = io - @orig_pos = @io.pos - @read = 0 - end - - def check_closed # :nodoc: - raise IOError, "closed #{self.class}" if closed? - end - - ## - # Number of bytes read out of the tar entry - - def bytes_read - @read - end - - ## - # Closes the tar entry - - def close - @closed = true - end - - ## - # Is the tar entry closed? - - def closed? - @closed - end - - ## - # Are we at the end of the tar entry? - - def eof? - check_closed - - @read >= @header.size - end - - ## - # Full name of the tar entry - - def full_name - if @header.prefix != "" then - File.join @header.prefix, @header.name - else - @header.name - end - rescue ArgumentError => e - raise unless e.message == 'string contains null byte' - raise Gem::Package::TarInvalidError, - 'tar is corrupt, name contains null byte' - end - - ## - # Read one byte from the tar entry - - def getc - check_closed - - return nil if @read >= @header.size - - ret = @io.getc - @read += 1 if ret - - ret - end - - ## - # Is this tar entry a directory? - - def directory? - @header.typeflag == "5" - end - - ## - # Is this tar entry a file? - - def file? - @header.typeflag == "0" - end - - ## - # The position in the tar entry - - def pos - check_closed - - bytes_read - end - - ## - # Reads +len+ bytes from the tar file entry, or the rest of the entry if - # nil - - def read(len = nil) - check_closed - - return nil if @read >= @header.size - - len ||= @header.size - @read - max_read = [len, @header.size - @read].min - - ret = @io.read max_read - @read += ret.size - - ret - end - - alias readpartial read # :nodoc: - - ## - # Rewinds to the beginning of the tar file entry - - def rewind - check_closed - - raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos= - - @io.pos = @orig_pos - @read = 0 - end - -end - diff --git a/ruby_2_2/lib/rubygems/package/tar_test_case.rb b/ruby_2_2/lib/rubygems/package/tar_test_case.rb deleted file mode 100644 index 5253e32f36..0000000000 --- a/ruby_2_2/lib/rubygems/package/tar_test_case.rb +++ /dev/null @@ -1,137 +0,0 @@ -require 'rubygems/test_case' -require 'rubygems/package' - -## -# A test case for Gem::Package::Tar* classes - -class Gem::Package::TarTestCase < Gem::TestCase - - def ASCIIZ(str, length) - str + "\0" * (length - str.length) - end - - def SP(s) - s + " " - end - - def SP_Z(s) - s + " \0" - end - - def Z(s) - s + "\0" - end - - def assert_headers_equal(expected, actual) - expected = expected.to_s unless String === expected - actual = actual.to_s unless String === actual - - fields = %w[ - name 100 - mode 8 - uid 8 - gid 8 - size 12 - mtime 12 - checksum 8 - typeflag 1 - linkname 100 - magic 6 - version 2 - uname 32 - gname 32 - devmajor 8 - devminor 8 - prefix 155 - ] - - offset = 0 - - until fields.empty? do - name = fields.shift - length = fields.shift.to_i - - if name == "checksum" then - chksum_off = offset - offset += length - next - end - - assert_equal expected[offset, length], actual[offset, length], - "Field #{name} of the tar header differs." - - offset += length - end - - assert_equal expected[chksum_off, 8], actual[chksum_off, 8] - end - - def calc_checksum(header) - sum = header.unpack("C*").inject{|s,a| s + a} - SP(Z(to_oct(sum, 6))) - end - - def header(type, fname, dname, length, mode, mtime, checksum = nil) - checksum ||= " " * 8 - - arr = [ # struct tarfile_entry_posix - ASCIIZ(fname, 100), # char name[100]; ASCII + (Z unless filled) - Z(to_oct(mode, 7)), # char mode[8]; 0 padded, octal null - Z(to_oct(0, 7)), # char uid[8]; ditto - Z(to_oct(0, 7)), # char gid[8]; ditto - Z(to_oct(length, 11)), # char size[12]; 0 padded, octal, null - Z(to_oct(mtime, 11)), # char mtime[12]; 0 padded, octal, null - checksum, # char checksum[8]; 0 padded, octal, null, space - type, # char typeflag[1]; file: "0" dir: "5" - "\0" * 100, # char linkname[100]; ASCII + (Z unless filled) - "ustar\0", # char magic[6]; "ustar\0" - "00", # char version[2]; "00" - ASCIIZ("wheel", 32), # char uname[32]; ASCIIZ - ASCIIZ("wheel", 32), # char gname[32]; ASCIIZ - Z(to_oct(0, 7)), # char devmajor[8]; 0 padded, octal, null - Z(to_oct(0, 7)), # char devminor[8]; 0 padded, octal, null - ASCIIZ(dname, 155) # char prefix[155]; ASCII + (Z unless filled) - ] - - format = "C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155" - h = if RUBY_VERSION >= "1.9" then - arr.join - else - arr = arr.join("").split(//).map{|x| x[0]} - arr.pack format - end - ret = h + "\0" * (512 - h.size) - assert_equal(512, ret.size) - ret - end - - def tar_dir_header(name, prefix, mode, mtime) - h = header("5", name, prefix, 0, mode, mtime) - checksum = calc_checksum(h) - header("5", name, prefix, 0, mode, mtime, checksum) - end - - def tar_file_header(fname, dname, mode, length, mtime) - h = header("0", fname, dname, length, mode, mtime) - checksum = calc_checksum(h) - header("0", fname, dname, length, mode, mtime, checksum) - end - - def to_oct(n, pad_size) - "%0#{pad_size}o" % n - end - - def util_entry(tar) - io = TempIO.new tar - - header = Gem::Package::TarHeader.from io - - Gem::Package::TarReader::Entry.new header, io - end - - def util_dir_entry - util_entry tar_dir_header("foo", "bar", 0, Time.now) - end - -end - diff --git a/ruby_2_2/lib/rubygems/package/tar_writer.rb b/ruby_2_2/lib/rubygems/package/tar_writer.rb deleted file mode 100644 index dfd635724b..0000000000 --- a/ruby_2_2/lib/rubygems/package/tar_writer.rb +++ /dev/null @@ -1,326 +0,0 @@ -# -*- coding: utf-8 -*- -#-- -# Copyright (C) 2004 Mauricio Julio Fernández Pradier -# See LICENSE.txt for additional licensing information. -#++ - -require 'digest' - -## -# Allows writing of tar files - -class Gem::Package::TarWriter - - class FileOverflow < StandardError; end - - ## - # IO wrapper that allows writing a limited amount of data - - class BoundedStream - - ## - # Maximum number of bytes that can be written - - attr_reader :limit - - ## - # Number of bytes written - - attr_reader :written - - ## - # Wraps +io+ and allows up to +limit+ bytes to be written - - def initialize(io, limit) - @io = io - @limit = limit - @written = 0 - end - - ## - # Writes +data+ onto the IO, raising a FileOverflow exception if the - # number of bytes will be more than #limit - - def write(data) - if data.bytesize + @written > @limit - raise FileOverflow, "You tried to feed more data than fits in the file." - end - @io.write data - @written += data.bytesize - data.bytesize - end - - end - - ## - # IO wrapper that provides only #write - - class RestrictedStream - - ## - # Creates a new RestrictedStream wrapping +io+ - - def initialize(io) - @io = io - end - - ## - # Writes +data+ onto the IO - - def write(data) - @io.write data - end - - end - - ## - # Creates a new TarWriter, yielding it if a block is given - - def self.new(io) - writer = super - - return writer unless block_given? - - begin - yield writer - ensure - writer.close - end - - nil - end - - ## - # Creates a new TarWriter that will write to +io+ - - def initialize(io) - @io = io - @closed = false - end - - ## - # Adds file +name+ with permissions +mode+, and yields an IO for writing the - # file to - - def add_file(name, mode) # :yields: io - check_closed - - raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos= - - name, prefix = split_name name - - init_pos = @io.pos - @io.write "\0" * 512 # placeholder for the header - - yield RestrictedStream.new(@io) if block_given? - - size = @io.pos - init_pos - 512 - - remainder = (512 - (size % 512)) % 512 - @io.write "\0" * remainder - - final_pos = @io.pos - @io.pos = init_pos - - header = Gem::Package::TarHeader.new :name => name, :mode => mode, - :size => size, :prefix => prefix, - :mtime => Time.now - - @io.write header - @io.pos = final_pos - - self - end - - ## - # Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing - # the file. The +digest_algorithm+ is written to a read-only +name+.sum - # file following the given file contents containing the digest name and - # hexdigest separated by a tab. - # - # The created digest object is returned. - - def add_file_digest name, mode, digest_algorithms # :yields: io - digests = digest_algorithms.map do |digest_algorithm| - digest = digest_algorithm.new - digest_name = - if digest.respond_to? :name then - digest.name - else - /::([^:]+)$/ =~ digest_algorithm.name - $1 - end - - [digest_name, digest] - end - - digests = Hash[*digests.flatten] - - add_file name, mode do |io| - Gem::Package::DigestIO.wrap io, digests do |digest_io| - yield digest_io - end - end - - digests - end - - ## - # Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing - # the file. The +signer+ is used to add a digest file using its - # digest_algorithm per add_file_digest and a cryptographic signature in - # +name+.sig. If the signer has no key only the checksum file is added. - # - # Returns the digest. - - def add_file_signed name, mode, signer - digest_algorithms = [ - signer.digest_algorithm, - Digest::SHA512, - ].compact.uniq - - digests = add_file_digest name, mode, digest_algorithms do |io| - yield io - end - - signature_digest = digests.values.compact.find do |digest| - digest_name = - if digest.respond_to? :name then - digest.name - else - /::([^:]+)$/ =~ digest.class.name - $1 - end - - digest_name == signer.digest_name - end - - if signer.key then - signature = signer.sign signature_digest.digest - - add_file_simple "#{name}.sig", 0444, signature.length do |io| - io.write signature - end - end - - digests - end - - ## - # Add file +name+ with permissions +mode+ +size+ bytes long. Yields an IO - # to write the file to. - - def add_file_simple(name, mode, size) # :yields: io - check_closed - - name, prefix = split_name name - - header = Gem::Package::TarHeader.new(:name => name, :mode => mode, - :size => size, :prefix => prefix, - :mtime => Time.now).to_s - - @io.write header - os = BoundedStream.new @io, size - - yield os if block_given? - - min_padding = size - os.written - @io.write("\0" * min_padding) - - remainder = (512 - (size % 512)) % 512 - @io.write("\0" * remainder) - - self - end - - ## - # Raises IOError if the TarWriter is closed - - def check_closed - raise IOError, "closed #{self.class}" if closed? - end - - ## - # Closes the TarWriter - - def close - check_closed - - @io.write "\0" * 1024 - flush - - @closed = true - end - - ## - # Is the TarWriter closed? - - def closed? - @closed - end - - ## - # Flushes the TarWriter's IO - - def flush - check_closed - - @io.flush if @io.respond_to? :flush - end - - ## - # Creates a new directory in the tar file +name+ with +mode+ - - def mkdir(name, mode) - check_closed - - name, prefix = split_name(name) - - header = Gem::Package::TarHeader.new :name => name, :mode => mode, - :typeflag => "5", :size => 0, - :prefix => prefix, - :mtime => Time.now - - @io.write header - - self - end - - ## - # Splits +name+ into a name and prefix that can fit in the TarHeader - - def split_name(name) # :nodoc: - if name.bytesize > 256 - raise Gem::Package::TooLongFileName.new("File \"#{name}\" has a too long path (should be 256 or less)") - end - - if name.bytesize <= 100 then - prefix = "" - else - parts = name.split(/\//) - newname = parts.pop - nxt = "" - - loop do - nxt = parts.pop - break if newname.bytesize + 1 + nxt.bytesize > 100 - newname = nxt + "/" + newname - end - - prefix = (parts + [nxt]).join "/" - name = newname - - if name.bytesize > 100 - raise Gem::Package::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long name (should be 100 or less)") - end - - if prefix.bytesize > 155 then - raise Gem::Package::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long base path (should be 155 or less)") - end - end - - return name, prefix - end - -end - |