minitar 0.5.4 → 0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Code-of-Conduct.md +74 -0
- data/Contributing.md +84 -0
- data/History.md +107 -0
- data/Licence.md +15 -0
- data/Manifest.txt +24 -0
- data/README.rdoc +81 -0
- data/Rakefile +46 -107
- data/docs/bsdl.txt +19 -0
- data/docs/ruby.txt +56 -0
- data/lib/archive-tar-minitar.rb +3 -0
- data/lib/archive/tar/minitar.rb +197 -889
- data/lib/archive/tar/minitar/input.rb +212 -0
- data/lib/archive/tar/minitar/output.rb +69 -0
- data/lib/archive/tar/minitar/posix_header.rb +259 -0
- data/lib/archive/tar/minitar/reader.rb +237 -0
- data/lib/archive/tar/minitar/writer.rb +297 -0
- data/lib/minitar.rb +12 -0
- data/test/minitest_helper.rb +11 -0
- data/test/support/tar_test_helpers.rb +119 -0
- data/test/test_tar_header.rb +74 -0
- data/test/test_tar_input.rb +167 -0
- data/test/test_tar_output.rb +53 -0
- data/test/test_tar_reader.rb +148 -0
- data/test/test_tar_writer.rb +190 -0
- metadata +232 -43
- data/ChangeLog +0 -17
- data/Install +0 -6
- data/README +0 -68
- data/bin/minitar +0 -27
- data/lib/archive/tar/minitar/command.rb +0 -814
- data/tests/tc_tar.rb +0 -629
- data/tests/testall.rb +0 -10
    
        data/lib/minitar.rb
    ADDED
    
    
| @@ -0,0 +1,119 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module TarTestHelpers
         | 
| 4 | 
            +
              Field = Struct.new(:name, :offset, :length)
         | 
| 5 | 
            +
              def self.Field(name, length) # rubocop:disable Style/MethodName
         | 
| 6 | 
            +
                @offset ||= 0
         | 
| 7 | 
            +
                field = Field.new(name, @offset, length)
         | 
| 8 | 
            +
                @offset += length
         | 
| 9 | 
            +
                FIELDS[name] = field
         | 
| 10 | 
            +
                FIELD_ORDER << name
         | 
| 11 | 
            +
                field
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              private
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              FIELDS = {} # rubocop:disable Style/MutableConstant
         | 
| 17 | 
            +
              FIELD_ORDER = [] # rubocop:disable Style/MutableConstant
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              Field('name', 100)
         | 
| 20 | 
            +
              Field('mode', 8)
         | 
| 21 | 
            +
              Field('uid', 8)
         | 
| 22 | 
            +
              Field('gid', 8)
         | 
| 23 | 
            +
              Field('size', 12)
         | 
| 24 | 
            +
              Field('mtime', 12)
         | 
| 25 | 
            +
              Field('checksum', 8)
         | 
| 26 | 
            +
              Field('typeflag', 1)
         | 
| 27 | 
            +
              Field('linkname', 100)
         | 
| 28 | 
            +
              Field('magic', 6)
         | 
| 29 | 
            +
              Field('version', 2)
         | 
| 30 | 
            +
              Field('uname', 32)
         | 
| 31 | 
            +
              Field('gname', 32)
         | 
| 32 | 
            +
              Field('devmajor', 8)
         | 
| 33 | 
            +
              Field('devminor', 8)
         | 
| 34 | 
            +
              Field('prefix', 155)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              BLANK_CHECKSUM = ' ' * 8
         | 
| 37 | 
            +
              NULL_100 = "\0" * 100
         | 
| 38 | 
            +
              USTAR = "ustar\0".freeze
         | 
| 39 | 
            +
              DOUBLE_ZERO = '00'.freeze
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              def assert_headers_equal(expected, actual)
         | 
| 42 | 
            +
                FIELD_ORDER.each do |field|
         | 
| 43 | 
            +
                  message = if field == 'checksum'
         | 
| 44 | 
            +
                              'Header checksums are expected to match.'
         | 
| 45 | 
            +
                            else
         | 
| 46 | 
            +
                              "Header field #{field} is expected to match."
         | 
| 47 | 
            +
                            end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  offset = FIELDS[field].offset
         | 
| 50 | 
            +
                  length = FIELDS[field].length
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  assert_equal(expected[offset, length], actual[offset, length], message)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              def assert_modes_equal(expected, actual, name)
         | 
| 57 | 
            +
                return if Minitar.windows?
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                assert_equal(
         | 
| 60 | 
            +
                  mode_string(expected),
         | 
| 61 | 
            +
                  mode_string(actual),
         | 
| 62 | 
            +
                  "Mode for #{name} does not match"
         | 
| 63 | 
            +
                )
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              def tar_file_header(fname, dname, mode, length)
         | 
| 67 | 
            +
                update_checksum(header('0', fname, dname, length, mode))
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              def tar_dir_header(name, prefix, mode)
         | 
| 71 | 
            +
                update_checksum(header('5', name, prefix, 0, mode))
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              def header(type, fname, dname, length, mode)
         | 
| 75 | 
            +
                arr = [
         | 
| 76 | 
            +
                  asciiz(fname, 100), z(to_oct(mode, 7)), z(to_oct(nil, 7)),
         | 
| 77 | 
            +
                  z(to_oct(nil, 7)), z(to_oct(length, 11)), z(to_oct(0, 11)),
         | 
| 78 | 
            +
                  BLANK_CHECKSUM, type, NULL_100, USTAR, DOUBLE_ZERO, asciiz('', 32),
         | 
| 79 | 
            +
                  asciiz('', 32), z(to_oct(nil, 7)), z(to_oct(nil, 7)), asciiz(dname, 155)
         | 
| 80 | 
            +
                ]
         | 
| 81 | 
            +
                h = arr.join.bytes.to_a.pack('C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155')
         | 
| 82 | 
            +
                ret = h + "\0" * (512 - h.size)
         | 
| 83 | 
            +
                assert_equal(512, ret.size)
         | 
| 84 | 
            +
                ret
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              def update_checksum(header)
         | 
| 88 | 
            +
                header[FIELDS['checksum'].offset, FIELDS['checksum'].length] =
         | 
| 89 | 
            +
                  # inject(:+) was introduced in which version?
         | 
| 90 | 
            +
                  sp(z(to_oct(header.unpack('C*').inject { |a, e| a + e }, 6)))
         | 
| 91 | 
            +
                header
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              def to_oct(n, pad_size)
         | 
| 95 | 
            +
                if n.nil?
         | 
| 96 | 
            +
                  "\0" * pad_size
         | 
| 97 | 
            +
                else
         | 
| 98 | 
            +
                  "%0#{pad_size}o" % n
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              def asciiz(str, length)
         | 
| 103 | 
            +
                str + "\0" * (length - str.length)
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              def sp(s)
         | 
| 107 | 
            +
                s + ' '
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
              def z(s)
         | 
| 111 | 
            +
                s + "\0"
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              def mode_string(value)
         | 
| 115 | 
            +
                '%04o' % (value & 0o777)
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              Minitest::Test.send(:include, self)
         | 
| 119 | 
            +
            end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'minitest_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class TestTarHeader < Minitest::Test
         | 
| 6 | 
            +
              def test_arguments_are_checked
         | 
| 7 | 
            +
                ph = Archive::Tar::Minitar::PosixHeader
         | 
| 8 | 
            +
                assert_raises(ArgumentError) {
         | 
| 9 | 
            +
                  ph.new(:name => '', :size => '', :mode => '')
         | 
| 10 | 
            +
                }
         | 
| 11 | 
            +
                assert_raises(ArgumentError) {
         | 
| 12 | 
            +
                  ph.new(:name => '', :size => '', :prefix => '')
         | 
| 13 | 
            +
                }
         | 
| 14 | 
            +
                assert_raises(ArgumentError) {
         | 
| 15 | 
            +
                  ph.new(:name => '', :prefix => '', :mode => '')
         | 
| 16 | 
            +
                }
         | 
| 17 | 
            +
                assert_raises(ArgumentError) {
         | 
| 18 | 
            +
                  ph.new(:prefix => '', :size => '', :mode => '')
         | 
| 19 | 
            +
                }
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def test_basic_headers
         | 
| 23 | 
            +
                header = {
         | 
| 24 | 
            +
                  :name => 'bla',
         | 
| 25 | 
            +
                  :mode => 0o12345,
         | 
| 26 | 
            +
                  :size => 10,
         | 
| 27 | 
            +
                  :prefix => '',
         | 
| 28 | 
            +
                  :typeflag => '0'
         | 
| 29 | 
            +
                }
         | 
| 30 | 
            +
                assert_headers_equal(tar_file_header('bla', '', 0o12345, 10),
         | 
| 31 | 
            +
                  Archive::Tar::Minitar::PosixHeader.new(header).to_s)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                header = {
         | 
| 34 | 
            +
                  :name => 'bla',
         | 
| 35 | 
            +
                  :mode => 0o12345,
         | 
| 36 | 
            +
                  :size => 0,
         | 
| 37 | 
            +
                  :prefix => '',
         | 
| 38 | 
            +
                  :typeflag => '5'
         | 
| 39 | 
            +
                }
         | 
| 40 | 
            +
                assert_headers_equal(tar_dir_header('bla', '', 0o12345),
         | 
| 41 | 
            +
                  Archive::Tar::Minitar::PosixHeader.new(header).to_s)
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def test_long_name_works
         | 
| 45 | 
            +
                header = {
         | 
| 46 | 
            +
                  :name => 'a' * 100, :mode => 0o12345, :size => 10, :prefix => ''
         | 
| 47 | 
            +
                }
         | 
| 48 | 
            +
                assert_headers_equal(tar_file_header('a' * 100, '', 0o12345, 10),
         | 
| 49 | 
            +
                  Archive::Tar::Minitar::PosixHeader.new(header).to_s)
         | 
| 50 | 
            +
                header = {
         | 
| 51 | 
            +
                  :name => 'a' * 100, :mode => 0o12345, :size => 10, :prefix => 'bb' * 60
         | 
| 52 | 
            +
                }
         | 
| 53 | 
            +
                assert_headers_equal(tar_file_header('a' * 100, 'bb' * 60, 0o12345, 10),
         | 
| 54 | 
            +
                  Archive::Tar::Minitar::PosixHeader.new(header).to_s)
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              def test_from_stream
         | 
| 58 | 
            +
                header = tar_file_header('a' * 100, '', 0o12345, 10)
         | 
| 59 | 
            +
                header = StringIO.new(header)
         | 
| 60 | 
            +
                h = Archive::Tar::Minitar::PosixHeader.from_stream(header)
         | 
| 61 | 
            +
                assert_equal('a' * 100, h.name)
         | 
| 62 | 
            +
                assert_equal(0o12345, h.mode)
         | 
| 63 | 
            +
                assert_equal(10, h.size)
         | 
| 64 | 
            +
                assert_equal('', h.prefix)
         | 
| 65 | 
            +
                assert_equal('ustar', h.magic)
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              def test_from_stream_with_evil_name
         | 
| 69 | 
            +
                header = tar_file_header("a \0" + "\0" * 97, '', 0o12345, 10)
         | 
| 70 | 
            +
                header = StringIO.new(header)
         | 
| 71 | 
            +
                h = Archive::Tar::Minitar::PosixHeader.from_stream header
         | 
| 72 | 
            +
                assert_equal('a ', h.name)
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
| @@ -0,0 +1,167 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'minitar'
         | 
| 4 | 
            +
            require 'minitest_helper'
         | 
| 5 | 
            +
            require 'base64'
         | 
| 6 | 
            +
            require 'zlib'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class TestTarInput < Minitest::Test
         | 
| 9 | 
            +
              TEST_TGZ = Base64.decode64(<<-EOS).freeze
         | 
| 10 | 
            +
            H4sIAKJpllQAA0tJLEnUK0ks0kuvYqAVMDAwMDMxUQDR5mbmYNrACMIHA2MjIwUDc3NzEzMz
         | 
| 11 | 
            +
            QxMDAwUDQ2NTczMGBQOauQgJlBYDfQ90SiKQkZmHWx1QWVoaHnMgXlGA00MEyHdzMMzOnBbC
         | 
| 12 | 
            +
            wPz28n2uJgOR44Xrq7tsHc/utNe/9FdihkmH3pZ7+zOTRFREzkzYJ99iHHDn4n0/Wb3E8Ceq
         | 
| 13 | 
            +
            S0uOdSyMMg9Z+WVvX0vJucxs77vrvZf2arWcvHP9wa1Yp9lRnJmC59/P9+43PXum+tj7Ga+8
         | 
| 14 | 
            +
            rtT+u3d941e765Y/bOrnvpv8X6jtz+wKqyk/v3n8P5xlO3l/1dn9q9Zotpy5funw/Of77Y/5
         | 
| 15 | 
            +
            LVltz7ToTl7dXf5ppmf3n9p+PPxz/sz/qjZn9yf9Y4R7I2Ft3tqfPTUMGgMYlEMSpGXmpBrT
         | 
| 16 | 
            +
            2A5Qvjc1xZ3/DTDyv5GJmfFo/qcHCMnILFYAIlA6UDDWU+DlGmgXjYJRMApGwSgYBaNgFIyC
         | 
| 17 | 
            +
            UTAKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIwCUgAAGnyo6wAoAAA=
         | 
| 18 | 
            +
              EOS
         | 
| 19 | 
            +
              FILETIMES = Time.utc(2004).to_i
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              TEST_CONTENTS = {
         | 
| 22 | 
            +
                'data.tar.gz' => { :size => 210, :mode => 0o644 },
         | 
| 23 | 
            +
                'file3' => { :size => 18, :mode => 0o755 }
         | 
| 24 | 
            +
              }.freeze
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              TEST_DATA_CONTENTS = {
         | 
| 27 | 
            +
                'data/' => { :size => 0, :mode => 0o755 },
         | 
| 28 | 
            +
                'data/__dir__/' => { :size => 0, :mode => 0o755 },
         | 
| 29 | 
            +
                'data/file1' => { :size => 16, :mode => 0o644 },
         | 
| 30 | 
            +
                'data/file2' => { :size => 16, :mode => 0o644 }
         | 
| 31 | 
            +
              }.freeze
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def setup
         | 
| 34 | 
            +
                FileUtils.mkdir_p('data__')
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              def teardown
         | 
| 38 | 
            +
                FileUtils.rm_rf('data__')
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              def test_each_works
         | 
| 42 | 
            +
                reader = Zlib::GzipReader.new(StringIO.new(TEST_TGZ))
         | 
| 43 | 
            +
                Minitar::Input.open(reader) do |stream|
         | 
| 44 | 
            +
                  outer = 0
         | 
| 45 | 
            +
                  stream.each.with_index do |entry, i|
         | 
| 46 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 47 | 
            +
                    assert TEST_CONTENTS.key?(entry.name)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    assert_equal(TEST_CONTENTS[entry.name][:size], entry.size, entry.name)
         | 
| 50 | 
            +
                    assert_modes_equal(TEST_CONTENTS[entry.name][:mode],
         | 
| 51 | 
            +
                      entry.mode, entry.name)
         | 
| 52 | 
            +
                    assert_equal(FILETIMES, entry.mtime, 'entry.mtime')
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    if i.zero?
         | 
| 55 | 
            +
                      data_reader = Zlib::GzipReader.new(StringIO.new(entry.read))
         | 
| 56 | 
            +
                      Minitar::Input.open(data_reader) do |is2|
         | 
| 57 | 
            +
                        inner = 0
         | 
| 58 | 
            +
                        is2.each_with_index do |entry2, _j|
         | 
| 59 | 
            +
                          assert_kind_of(Minitar::Reader::EntryStream, entry2)
         | 
| 60 | 
            +
                          assert TEST_DATA_CONTENTS.key?(entry2.name)
         | 
| 61 | 
            +
                          assert_equal(TEST_DATA_CONTENTS[entry2.name][:size], entry2.size,
         | 
| 62 | 
            +
                            entry2.name)
         | 
| 63 | 
            +
                          assert_modes_equal(TEST_DATA_CONTENTS[entry2.name][:mode],
         | 
| 64 | 
            +
                            entry2.mode, entry2.name)
         | 
| 65 | 
            +
                          assert_equal(FILETIMES, entry2.mtime, entry2.name)
         | 
| 66 | 
            +
                          inner += 1
         | 
| 67 | 
            +
                        end
         | 
| 68 | 
            +
                        assert_equal(4, inner)
         | 
| 69 | 
            +
                      end
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    outer += 1
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  assert_equal(2, outer)
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              def test_extract_entry_works
         | 
| 80 | 
            +
                reader = Zlib::GzipReader.new(StringIO.new(TEST_TGZ))
         | 
| 81 | 
            +
                Minitar::Input.open(reader) do |stream|
         | 
| 82 | 
            +
                  outer_count = 0
         | 
| 83 | 
            +
                  stream.each_with_index do |entry, i|
         | 
| 84 | 
            +
                    stream.extract_entry('data__', entry)
         | 
| 85 | 
            +
                    name = File.join('data__', entry.name)
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    assert TEST_CONTENTS.key?(entry.name)
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    if entry.directory?
         | 
| 90 | 
            +
                      assert(File.directory?(name))
         | 
| 91 | 
            +
                    else
         | 
| 92 | 
            +
                      assert(File.file?(name))
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                      assert_equal(TEST_CONTENTS[entry.name][:size], File.stat(name).size)
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    assert_modes_equal(TEST_CONTENTS[entry.name][:mode],
         | 
| 98 | 
            +
                      File.stat(name).mode, entry.name)
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    if i.zero?
         | 
| 101 | 
            +
                      begin
         | 
| 102 | 
            +
                        ff = File.open(name, 'rb')
         | 
| 103 | 
            +
                        data_reader = Zlib::GzipReader.new(ff)
         | 
| 104 | 
            +
                        Minitar::Input.open(data_reader) do |is2|
         | 
| 105 | 
            +
                          is2.each_with_index do |entry2, _j|
         | 
| 106 | 
            +
                            is2.extract_entry('data__', entry2)
         | 
| 107 | 
            +
                            name2 = File.join('data__', entry2.name)
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                            assert TEST_DATA_CONTENTS.key?(entry2.name)
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                            if entry2.directory?
         | 
| 112 | 
            +
                              assert(File.directory?(name2))
         | 
| 113 | 
            +
                            else
         | 
| 114 | 
            +
                              assert(File.file?(name2))
         | 
| 115 | 
            +
                              assert_equal(TEST_DATA_CONTENTS[entry2.name][:size],
         | 
| 116 | 
            +
                                File.stat(name2).size)
         | 
| 117 | 
            +
                            end
         | 
| 118 | 
            +
                            assert_modes_equal(TEST_DATA_CONTENTS[entry2.name][:mode],
         | 
| 119 | 
            +
                              File.stat(name2).mode, name2)
         | 
| 120 | 
            +
                          end
         | 
| 121 | 
            +
                        end
         | 
| 122 | 
            +
                      ensure
         | 
| 123 | 
            +
                        ff.close unless ff.closed?
         | 
| 124 | 
            +
                      end
         | 
| 125 | 
            +
                    end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                    outer_count += 1
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                  assert_equal(2, outer_count)
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
              def test_extract_entry_breaks_symlinks
         | 
| 135 | 
            +
                return if Minitar.windows?
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                IO.respond_to?(:write) &&
         | 
| 138 | 
            +
                  IO.write('data__/file4', '') ||
         | 
| 139 | 
            +
                  File.open('data__/file4', 'w') { |f| f.write '' }
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                File.symlink('data__/file4', 'data__/file3')
         | 
| 142 | 
            +
                File.symlink('data__/file4', 'data__/data')
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                Minitar.unpack(Zlib::GzipReader.new(StringIO.new(TEST_TGZ)), 'data__')
         | 
| 145 | 
            +
                Minitar.unpack(Zlib::GzipReader.new(File.open('data__/data.tar.gz', 'rb')),
         | 
| 146 | 
            +
                  'data__')
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                refute File.symlink?('data__/file3')
         | 
| 149 | 
            +
                refute File.symlink?('data__/data')
         | 
| 150 | 
            +
              end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
              RELATIVE_DIRECTORY_TGZ = Base64.decode64 <<-EOS
         | 
| 153 | 
            +
            H4sICIIoKVgCA2JhZC1kaXIudGFyANPT0y8sTy0qqWSgHTAwMDAzMVEA0eZmpmDawAjChwEFQ2MDQyMg
         | 
| 154 | 
            +
            MDUzVDAwNDY0N2VQMGCgAygtLkksAjolEcjIzMOtDqgsLQ2/J0H+gNOjYBSMglEwyAEA2LchrwAGAAA=
         | 
| 155 | 
            +
              EOS
         | 
| 156 | 
            +
             | 
| 157 | 
            +
              def test_extract_entry_fails_with_relative_directory
         | 
| 158 | 
            +
                reader = Zlib::GzipReader.new(StringIO.new(RELATIVE_DIRECTORY_TGZ))
         | 
| 159 | 
            +
                Minitar::Input.open(reader) do |stream|
         | 
| 160 | 
            +
                  stream.each do |entry|
         | 
| 161 | 
            +
                    assert_raises Archive::Tar::Minitar::SecureRelativePathError do
         | 
| 162 | 
            +
                      stream.extract_entry('data__', entry)
         | 
| 163 | 
            +
                    end
         | 
| 164 | 
            +
                  end
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
              end
         | 
| 167 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'minitar'
         | 
| 4 | 
            +
            require 'minitest_helper'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class TestTarOutput < Minitest::Test
         | 
| 7 | 
            +
              def setup
         | 
| 8 | 
            +
                FileUtils.mkdir_p('data__')
         | 
| 9 | 
            +
                %w(a b c).each do |filename|
         | 
| 10 | 
            +
                  name = File.join('data__', filename)
         | 
| 11 | 
            +
                  File.open(name, 'wb') { |f|
         | 
| 12 | 
            +
                    f.puts "#{name}: 123456789012345678901234567890"
         | 
| 13 | 
            +
                  }
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                @tarfile = 'data__/bla2.tar'
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def teardown
         | 
| 19 | 
            +
                FileUtils.rm_rf('data__')
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def test_file_looks_good
         | 
| 23 | 
            +
                Minitar::Output.open(@tarfile) do |os|
         | 
| 24 | 
            +
                  Dir.chdir('data__') do
         | 
| 25 | 
            +
                    %w(a b c).each do |name|
         | 
| 26 | 
            +
                      stat = File.stat(name)
         | 
| 27 | 
            +
                      opts = { :size => stat.size, :mode => 0o644 }
         | 
| 28 | 
            +
                      os.tar.add_file_simple(name, opts) do |ss|
         | 
| 29 | 
            +
                        File.open(name, 'rb') { |ff| ss.write(ff.read(4096)) until ff.eof? }
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
                ff = File.open(@tarfile, 'rb')
         | 
| 35 | 
            +
                Minitar::Reader.open(ff) do |is|
         | 
| 36 | 
            +
                  ii = 0
         | 
| 37 | 
            +
                  is.each do |entry|
         | 
| 38 | 
            +
                    case ii
         | 
| 39 | 
            +
                    when 0
         | 
| 40 | 
            +
                      assert_equal('a', entry.name)
         | 
| 41 | 
            +
                    when 1
         | 
| 42 | 
            +
                      assert_equal('b', entry.name)
         | 
| 43 | 
            +
                    when 2
         | 
| 44 | 
            +
                      assert_equal('c', entry.name)
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                    ii += 1
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                  assert_equal(3, ii)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              ensure
         | 
| 51 | 
            +
                ff.close if ff
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,148 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'minitar'
         | 
| 4 | 
            +
            require 'minitest_helper'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class TestTarReader < Minitest::Test
         | 
| 7 | 
            +
              def test_multiple_entries
         | 
| 8 | 
            +
                str = tar_file_header('lib/foo', '', 0o10644, 10) + "\0" * 512
         | 
| 9 | 
            +
                str += tar_file_header('bar', 'baz', 0o644, 0)
         | 
| 10 | 
            +
                str += tar_dir_header('foo', 'bar', 0o12345)
         | 
| 11 | 
            +
                str += "\0" * 1024
         | 
| 12 | 
            +
                names = %w(lib/foo bar foo)
         | 
| 13 | 
            +
                prefixes = ['', 'baz', 'bar']
         | 
| 14 | 
            +
                modes = [0o10644, 0o644, 0o12345]
         | 
| 15 | 
            +
                sizes = [10, 0, 0]
         | 
| 16 | 
            +
                isdir = [false, false, true]
         | 
| 17 | 
            +
                isfile = [true, true, false]
         | 
| 18 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 19 | 
            +
                  i = 0
         | 
| 20 | 
            +
                  is.each_entry do |entry|
         | 
| 21 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 22 | 
            +
                    assert_equal(names[i], entry.name)
         | 
| 23 | 
            +
                    assert_equal(prefixes[i], entry.prefix)
         | 
| 24 | 
            +
                    assert_equal(sizes[i], entry.size)
         | 
| 25 | 
            +
                    assert_equal(modes[i], entry.mode)
         | 
| 26 | 
            +
                    assert_equal(isdir[i], entry.directory?)
         | 
| 27 | 
            +
                    assert_equal(isfile[i], entry.file?)
         | 
| 28 | 
            +
                    if prefixes[i] != ''
         | 
| 29 | 
            +
                      assert_equal(File.join(prefixes[i], names[i]), entry.full_name)
         | 
| 30 | 
            +
                    else
         | 
| 31 | 
            +
                      assert_equal(names[i], entry.name)
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                    i += 1
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                  assert_equal(names.size, i)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def test_rewind_entry_works
         | 
| 40 | 
            +
                content = ('a'..'z').to_a.join(' ')
         | 
| 41 | 
            +
                str = tar_file_header('lib/foo', '', 0o10644, content.size) + content +
         | 
| 42 | 
            +
                  "\0" * (512 - content.size)
         | 
| 43 | 
            +
                str << "\0" * 1024
         | 
| 44 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 45 | 
            +
                  is.each_entry do |entry|
         | 
| 46 | 
            +
                    3.times do
         | 
| 47 | 
            +
                      entry.rewind
         | 
| 48 | 
            +
                      assert_equal(content, entry.read)
         | 
| 49 | 
            +
                      assert_equal(content.size, entry.pos)
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              def test_rewind_works
         | 
| 56 | 
            +
                content = ('a'..'z').to_a.join(' ')
         | 
| 57 | 
            +
                str = tar_file_header('lib/foo', '', 0o10644, content.size) + content +
         | 
| 58 | 
            +
                  "\0" * (512 - content.size)
         | 
| 59 | 
            +
                str << "\0" * 1024
         | 
| 60 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 61 | 
            +
                  3.times do
         | 
| 62 | 
            +
                    is.rewind
         | 
| 63 | 
            +
                    i = 0
         | 
| 64 | 
            +
                    is.each_entry do |entry|
         | 
| 65 | 
            +
                      assert_equal(content, entry.read)
         | 
| 66 | 
            +
                      i += 1
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
                    assert_equal(1, i)
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              def test_read_works
         | 
| 74 | 
            +
                contents = ('a'..'z').inject('') { |a, e| a << e * 100 }
         | 
| 75 | 
            +
                str = tar_file_header('lib/foo', '', 0o10644, contents.size) + contents
         | 
| 76 | 
            +
                str += "\0" * (512 - (str.size % 512))
         | 
| 77 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 78 | 
            +
                  is.each_entry do |entry|
         | 
| 79 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 80 | 
            +
                    data = entry.read(3000) # bigger than contents.size
         | 
| 81 | 
            +
                    assert_equal(contents, data)
         | 
| 82 | 
            +
                    assert_equal(true, entry.eof?)
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 86 | 
            +
                  is.each_entry do |entry|
         | 
| 87 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 88 | 
            +
                    data = entry.read(100)
         | 
| 89 | 
            +
                    (entry.size - data.size).times { data << entry.getc.chr }
         | 
| 90 | 
            +
                    assert_equal(contents, data)
         | 
| 91 | 
            +
                    assert_equal(nil, entry.read(10))
         | 
| 92 | 
            +
                    assert_equal(true, entry.eof?)
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 96 | 
            +
                  is.each_entry do |entry|
         | 
| 97 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 98 | 
            +
                    data = entry.read
         | 
| 99 | 
            +
                    assert_equal(contents, data)
         | 
| 100 | 
            +
                    assert_equal(nil, entry.read(10))
         | 
| 101 | 
            +
                    assert_equal(nil, entry.read)
         | 
| 102 | 
            +
                    assert_equal(nil, entry.getc)
         | 
| 103 | 
            +
                    assert_equal(true, entry.eof?)
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              def test_eof_works
         | 
| 109 | 
            +
                str = tar_file_header('bar', 'baz', 0o644, 0)
         | 
| 110 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 111 | 
            +
                  is.each_entry do |entry|
         | 
| 112 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 113 | 
            +
                    data = entry.read
         | 
| 114 | 
            +
                    assert_equal(nil, data)
         | 
| 115 | 
            +
                    assert_equal(nil, entry.read(10))
         | 
| 116 | 
            +
                    assert_equal(nil, entry.read)
         | 
| 117 | 
            +
                    assert_equal(nil, entry.getc)
         | 
| 118 | 
            +
                    assert_equal(true, entry.eof?)
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
                str = tar_dir_header('foo', 'bar', 0o12345)
         | 
| 122 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 123 | 
            +
                  is.each_entry do |entry|
         | 
| 124 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 125 | 
            +
                    data = entry.read
         | 
| 126 | 
            +
                    assert_equal(nil, data)
         | 
| 127 | 
            +
                    assert_equal(nil, entry.read(10))
         | 
| 128 | 
            +
                    assert_equal(nil, entry.read)
         | 
| 129 | 
            +
                    assert_equal(nil, entry.getc)
         | 
| 130 | 
            +
                    assert_equal(true, entry.eof?)
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
                str = tar_dir_header('foo', 'bar', 0o12345)
         | 
| 134 | 
            +
                str += tar_file_header('bar', 'baz', 0o644, 0)
         | 
| 135 | 
            +
                str += tar_file_header('bar', 'baz', 0o644, 0)
         | 
| 136 | 
            +
                Minitar::Reader.new(StringIO.new(str)) do |is|
         | 
| 137 | 
            +
                  is.each_entry do |entry|
         | 
| 138 | 
            +
                    assert_kind_of(Minitar::Reader::EntryStream, entry)
         | 
| 139 | 
            +
                    data = entry.read
         | 
| 140 | 
            +
                    assert_equal(nil, data)
         | 
| 141 | 
            +
                    assert_equal(nil, entry.read(10))
         | 
| 142 | 
            +
                    assert_equal(nil, entry.read)
         | 
| 143 | 
            +
                    assert_equal(nil, entry.getc)
         | 
| 144 | 
            +
                    assert_equal(true, entry.eof?)
         | 
| 145 | 
            +
                  end
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
              end
         | 
| 148 | 
            +
            end
         |