File: test_tar_input.rb

package info (click to toggle)
ruby-minitar 0.9-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 216 kB
  • sloc: ruby: 1,635; makefile: 11
file content (227 lines) | stat: -rw-r--r-- 7,688 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#!/usr/bin/env ruby

require 'minitar'
require 'minitest_helper'
require 'base64'
require 'zlib'

class TestTarInput < Minitest::Test
  TEST_TGZ = Base64.decode64(<<-EOS).freeze
H4sIAKJpllQAA0tJLEnUK0ks0kuvYqAVMDAwMDMxUQDR5mbmYNrACMIHA2MjIwUDc3NzEzMz
QxMDAwUDQ2NTczMGBQOauQgJlBYDfQ90SiKQkZmHWx1QWVoaHnMgXlGA00MEyHdzMMzOnBbC
wPz28n2uJgOR44Xrq7tsHc/utNe/9FdihkmH3pZ7+zOTRFREzkzYJ99iHHDn4n0/Wb3E8Ceq
S0uOdSyMMg9Z+WVvX0vJucxs77vrvZf2arWcvHP9wa1Yp9lRnJmC59/P9+43PXum+tj7Ga+8
rtT+u3d941e765Y/bOrnvpv8X6jtz+wKqyk/v3n8P5xlO3l/1dn9q9Zotpy5funw/Of77Y/5
LVltz7ToTl7dXf5ppmf3n9p+PPxz/sz/qjZn9yf9Y4R7I2Ft3tqfPTUMGgMYlEMSpGXmpBrT
2A5Qvjc1xZ3/DTDyv5GJmfFo/qcHCMnILFYAIlA6UDDWU+DlGmgXjYJRMApGwSgYBaNgFIyC
UTAKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIwCUgAAGnyo6wAoAAA=
  EOS
  FILETIMES = Time.utc(2004).to_i

  TEST_CONTENTS = {
    'data.tar.gz' => { :size => 210, :mode => 0o644 },
    'file3' => { :size => 18, :mode => 0o755 }
  }.freeze

  TEST_DATA_CONTENTS = {
    'data/' => { :size => 0, :mode => 0o755 },
    'data/__dir__/' => { :size => 0, :mode => 0o755 },
    'data/file1' => { :size => 16, :mode => 0o644 },
    'data/file2' => { :size => 16, :mode => 0o644 }
  }.freeze

  def setup
    FileUtils.mkdir_p('data__')
  end

  def teardown
    FileUtils.rm_rf('data__')
  end

  def test_open_no_block
    reader = Zlib::GzipReader.new(StringIO.new(TEST_TGZ))
    input = Minitar::Input.open(reader)
    refute input.closed?
  ensure
    input.close
    assert input.closed?
  end

  def test_each_works
    reader = Zlib::GzipReader.new(StringIO.new(TEST_TGZ))
    Minitar::Input.open(reader) do |stream|
      outer = 0
      stream.each.with_index do |entry, i|
        assert_kind_of(Minitar::Reader::EntryStream, entry)
        assert TEST_CONTENTS.key?(entry.name)

        assert_equal(TEST_CONTENTS[entry.name][:size], entry.size, entry.name)
        assert_modes_equal(TEST_CONTENTS[entry.name][:mode],
          entry.mode, entry.name)
        assert_equal(FILETIMES, entry.mtime, 'entry.mtime')

        if i.zero?
          data_reader = Zlib::GzipReader.new(StringIO.new(entry.read))
          Minitar::Input.open(data_reader) do |is2|
            inner = 0
            is2.each_with_index do |entry2, _j|
              assert_kind_of(Minitar::Reader::EntryStream, entry2)
              assert TEST_DATA_CONTENTS.key?(entry2.name)
              assert_equal(TEST_DATA_CONTENTS[entry2.name][:size], entry2.size,
                entry2.name)
              assert_modes_equal(TEST_DATA_CONTENTS[entry2.name][:mode],
                entry2.mode, entry2.name)
              assert_equal(FILETIMES, entry2.mtime, entry2.name)
              inner += 1
            end
            assert_equal(4, inner)
          end
        end

        outer += 1
      end

      assert_equal(2, outer)
    end
  end

  def test_extract_entry_works
    reader = Zlib::GzipReader.new(StringIO.new(TEST_TGZ))
    Minitar::Input.open(reader) do |stream|
      outer_count = 0
      stream.each_with_index do |entry, i|
        stream.extract_entry('data__', entry)
        name = File.join('data__', entry.name)

        assert TEST_CONTENTS.key?(entry.name)

        if entry.directory?
          assert(File.directory?(name))
        else
          assert(File.file?(name))

          assert_equal(TEST_CONTENTS[entry.name][:size], File.stat(name).size)
        end

        assert_modes_equal(TEST_CONTENTS[entry.name][:mode],
          File.stat(name).mode, entry.name)

        if i.zero?
          begin
            ff = File.open(name, 'rb')
            data_reader = Zlib::GzipReader.new(ff)
            Minitar::Input.open(data_reader) do |is2|
              is2.each_with_index do |entry2, _j|
                is2.extract_entry('data__', entry2)
                name2 = File.join('data__', entry2.name)

                assert TEST_DATA_CONTENTS.key?(entry2.name)

                if entry2.directory?
                  assert(File.directory?(name2))
                else
                  assert(File.file?(name2))
                  assert_equal(TEST_DATA_CONTENTS[entry2.name][:size],
                    File.stat(name2).size)
                end
                assert_modes_equal(TEST_DATA_CONTENTS[entry2.name][:mode],
                  File.stat(name2).mode, name2)
              end
            end
          ensure
            ff.close unless ff.closed?
          end
        end

        outer_count += 1
      end

      assert_equal(2, outer_count)
    end
  end

  def test_extract_entry_breaks_symlinks
    return if Minitar.windows?

    IO.respond_to?(:write) &&
      IO.write('data__/file4', '') ||
      File.open('data__/file4', 'w') { |f| f.write '' }

    File.symlink('data__/file4', 'data__/file3')
    File.symlink('data__/file4', 'data__/data')

    Minitar.unpack(Zlib::GzipReader.new(StringIO.new(TEST_TGZ)), 'data__')
    Minitar.unpack(Zlib::GzipReader.new(File.open('data__/data.tar.gz', 'rb')),
      'data__')

    refute File.symlink?('data__/file3')
    refute File.symlink?('data__/data')
  end

  RELATIVE_DIRECTORY_TGZ = Base64.decode64 <<-EOS
H4sICIIoKVgCA2JhZC1kaXIudGFyANPT0y8sTy0qqWSgHTAwMDAzMVEA0eZmpmDawAjChwEFQ2MDQyMg
MDUzVDAwNDY0N2VQMGCgAygtLkksAjolEcjIzMOtDqgsLQ2/J0H+gNOjYBSMglEwyAEA2LchrwAGAAA=
  EOS

  def test_extract_entry_fails_with_relative_directory
    reader = Zlib::GzipReader.new(StringIO.new(RELATIVE_DIRECTORY_TGZ))
    Minitar::Input.open(reader) do |stream|
      stream.each do |entry|
        assert_raises Archive::Tar::Minitar::SecureRelativePathError do
          stream.extract_entry('data__', entry)
        end
      end
    end
  end

  NON_STRICT_OCTAL_TGZ = Base64.decode64(<<-EOS).freeze
H4sIAEk55FsAA0tJLEnUK0ks0kuvYqAVMDAwMDMxUQDR5mbmYNrACMjX0zMH
AzMDUwUDIG1iZmZoYmCgYGBobGpuxqBgQDMXIYHSYqDvgU5KBDIy83CrAypL
S8NjjgEYKMDpIQLkuzkYZmdOC2Fgfnv5PleTgcjxwvXVXbaOZ3fa61/6KzHD
pENvy739mUkiKiJnJuyTbzEOuHPxvp+sXmL4E9WlJcc6FkaZh6z8srevpeRc
Zrb33fXeS3u1Wk7euf7gVqzT7CjOTMHz7+d795uePVN97P2MV15Xav/du77x
q911yx829XPfTf4v1PZndoXVlJ/fPP4fzrKdvL/q7P5VazRbzly/dHj+8/32
x/yWrLZnWnQnr+4u/zTTs/tPbT8e/jl/5n9Vm7P7k/4xwr2RsDZv7c+eGgaN
AQzKIQnSMnNSjWlsByjfm5pi5n8DGDAyQsv/RiZmxqP5nx4gJCOzWAGIQOlA
wVhPgZdroF00CkbBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTAKRsEoGAWjYBSM
glEwCkbBKBgFo2AUjIJRMApIAQD0DyzXACgAAA==
  EOS

  def test_extract_with_non_strict_octal
    reader = Zlib::GzipReader.new(StringIO.new(NON_STRICT_OCTAL_TGZ))

    assert_raises(ArgumentError) do
      Minitar.unpack(reader, 'data__')
    end
  end

  OCTAL_WRAPPED_BY_SPACE_TGZ = Base64.decode64(<<-EOS).freeze
H4sIAOQg5FsAA0tJLEnUK0ks0kuvYqAVMDAwMDMxUQDR5mbmYNrACMhXgAJj
IyMFA3NzcxMzM0MTAwMFA0NjU3MzBgUDmrkICZQWA30PdFIikJGZh1sdUFla
Gh5zDMBAAU4PESDfzcEwO3NaCAPz28v3uZoMRI4Xrq/usnU8u9Ne/9JfiRkm
HXpb7u3PTBJRETkzYZ98i3HAnYv3/WT1EsOfqC4tOdaxMMo8ZOWXvX0tJecy
s73vrvde2qvVcvLO9Qe3Yp1mR3FmCp5/P9+73/Tsmepj72e88rpS++/e9Y1f
7a5b/rCpn/tu8n+htj+zK6ym/Pzm8f9wlu3k/VVn969ao9ly5vqlw/Of77c/
5rdktT3Tojt5dXf5p5me3X9q+/Hwz/kz/6vanN2f9I8R7o2EtXlrf/bUMGgM
YFAOSZCWmZNqTGM7QPne1BQz/xvAAEb+NzIxMx7N//QAIRmZxQpABEoHCsZ6
CrxcA+2iUTAKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIyC
UTAKRsEoGAWjYBSMglFACgAAuUHUvwAoAAA=
  EOS

  def test_extract_octal_wrapped_by_space
    reader = Zlib::GzipReader.new(StringIO.new(OCTAL_WRAPPED_BY_SPACE_TGZ))
    header = Archive::Tar::Minitar::PosixHeader.from_stream(reader)
    assert_equal(210, header.size)

    reader = Zlib::GzipReader.new(StringIO.new(OCTAL_WRAPPED_BY_SPACE_TGZ))
    Minitar.unpack(reader, 'data__', [])
  end

  def test_fsync_false
    outer = 0
    Minitar.unpack(Zlib::GzipReader.new(StringIO.new(TEST_TGZ)), 'data__', [], :fsync => false) do |_label, _path, _stats|
      outer += 1
    end
    assert_equal(6, outer)
  end
end