rubyzip 1.3.0 → 3.0.0.alpha

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.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +368 -0
  3. data/README.md +123 -46
  4. data/Rakefile +13 -6
  5. data/lib/zip/central_directory.rb +166 -116
  6. data/lib/zip/compressor.rb +3 -1
  7. data/lib/zip/constants.rb +77 -21
  8. data/lib/zip/crypto/decrypted_io.rb +42 -0
  9. data/lib/zip/crypto/encryption.rb +4 -2
  10. data/lib/zip/crypto/null_encryption.rb +5 -3
  11. data/lib/zip/crypto/traditional_encryption.rb +14 -12
  12. data/lib/zip/decompressor.rb +21 -2
  13. data/lib/zip/deflater.rb +10 -8
  14. data/lib/zip/dirtyable.rb +32 -0
  15. data/lib/zip/dos_time.rb +53 -12
  16. data/lib/zip/entry.rb +306 -184
  17. data/lib/zip/entry_set.rb +11 -7
  18. data/lib/zip/errors.rb +115 -15
  19. data/lib/zip/extra_field/generic.rb +11 -17
  20. data/lib/zip/extra_field/ntfs.rb +8 -2
  21. data/lib/zip/extra_field/old_unix.rb +6 -2
  22. data/lib/zip/extra_field/universal_time.rb +45 -13
  23. data/lib/zip/extra_field/unix.rb +7 -3
  24. data/lib/zip/extra_field/unknown.rb +33 -0
  25. data/lib/zip/extra_field/zip64.rb +16 -7
  26. data/lib/zip/extra_field.rb +22 -26
  27. data/lib/zip/file.rb +196 -240
  28. data/lib/zip/file_split.rb +97 -0
  29. data/lib/zip/filesystem/dir.rb +86 -0
  30. data/lib/zip/filesystem/directory_iterator.rb +48 -0
  31. data/lib/zip/filesystem/file.rb +262 -0
  32. data/lib/zip/filesystem/file_stat.rb +110 -0
  33. data/lib/zip/filesystem/zip_file_name_mapper.rb +81 -0
  34. data/lib/zip/filesystem.rb +31 -584
  35. data/lib/zip/inflater.rb +27 -37
  36. data/lib/zip/input_stream.rb +67 -42
  37. data/lib/zip/ioextras/abstract_input_stream.rb +32 -16
  38. data/lib/zip/ioextras/abstract_output_stream.rb +5 -3
  39. data/lib/zip/ioextras.rb +7 -7
  40. data/lib/zip/null_compressor.rb +3 -1
  41. data/lib/zip/null_decompressor.rb +4 -10
  42. data/lib/zip/null_input_stream.rb +3 -1
  43. data/lib/zip/output_stream.rb +58 -43
  44. data/lib/zip/pass_thru_compressor.rb +5 -3
  45. data/lib/zip/pass_thru_decompressor.rb +16 -23
  46. data/lib/zip/streamable_directory.rb +6 -4
  47. data/lib/zip/streamable_stream.rb +9 -10
  48. data/lib/zip/version.rb +3 -1
  49. data/lib/zip.rb +19 -4
  50. data/rubyzip.gemspec +38 -0
  51. data/samples/example.rb +9 -4
  52. data/samples/example_filesystem.rb +3 -2
  53. data/samples/example_recursive.rb +3 -1
  54. data/samples/gtk_ruby_zip.rb +22 -20
  55. data/samples/qtzip.rb +12 -11
  56. data/samples/write_simple.rb +3 -4
  57. data/samples/zipfind.rb +24 -22
  58. metadata +86 -179
  59. data/TODO +0 -15
  60. data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
  61. data/test/basic_zip_file_test.rb +0 -60
  62. data/test/case_sensitivity_test.rb +0 -69
  63. data/test/central_directory_entry_test.rb +0 -69
  64. data/test/central_directory_test.rb +0 -100
  65. data/test/crypto/null_encryption_test.rb +0 -57
  66. data/test/crypto/traditional_encryption_test.rb +0 -80
  67. data/test/data/WarnInvalidDate.zip +0 -0
  68. data/test/data/file1.txt +0 -46
  69. data/test/data/file1.txt.deflatedData +0 -0
  70. data/test/data/file2.txt +0 -1504
  71. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  72. data/test/data/globTest/foo.txt +0 -0
  73. data/test/data/globTest/food.txt +0 -0
  74. data/test/data/globTest.zip +0 -0
  75. data/test/data/gpbit3stored.zip +0 -0
  76. data/test/data/mimetype +0 -1
  77. data/test/data/notzippedruby.rb +0 -7
  78. data/test/data/ntfs.zip +0 -0
  79. data/test/data/oddExtraField.zip +0 -0
  80. data/test/data/path_traversal/Makefile +0 -10
  81. data/test/data/path_traversal/jwilk/README.md +0 -5
  82. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  83. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  84. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  85. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  86. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  87. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  88. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  89. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  90. data/test/data/path_traversal/relative1.zip +0 -0
  91. data/test/data/path_traversal/tilde.zip +0 -0
  92. data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
  93. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  94. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  95. data/test/data/rubycode.zip +0 -0
  96. data/test/data/rubycode2.zip +0 -0
  97. data/test/data/test.xls +0 -0
  98. data/test/data/testDirectory.bin +0 -0
  99. data/test/data/zip64-sample.zip +0 -0
  100. data/test/data/zipWithDirs.zip +0 -0
  101. data/test/data/zipWithEncryption.zip +0 -0
  102. data/test/deflater_test.rb +0 -65
  103. data/test/encryption_test.rb +0 -42
  104. data/test/entry_set_test.rb +0 -163
  105. data/test/entry_test.rb +0 -154
  106. data/test/errors_test.rb +0 -35
  107. data/test/extra_field_test.rb +0 -76
  108. data/test/file_extract_directory_test.rb +0 -54
  109. data/test/file_extract_test.rb +0 -145
  110. data/test/file_permissions_test.rb +0 -65
  111. data/test/file_split_test.rb +0 -57
  112. data/test/file_test.rb +0 -666
  113. data/test/filesystem/dir_iterator_test.rb +0 -58
  114. data/test/filesystem/directory_test.rb +0 -139
  115. data/test/filesystem/file_mutating_test.rb +0 -87
  116. data/test/filesystem/file_nonmutating_test.rb +0 -508
  117. data/test/filesystem/file_stat_test.rb +0 -64
  118. data/test/gentestfiles.rb +0 -126
  119. data/test/inflater_test.rb +0 -14
  120. data/test/input_stream_test.rb +0 -182
  121. data/test/ioextras/abstract_input_stream_test.rb +0 -102
  122. data/test/ioextras/abstract_output_stream_test.rb +0 -106
  123. data/test/ioextras/fake_io_test.rb +0 -18
  124. data/test/local_entry_test.rb +0 -154
  125. data/test/output_stream_test.rb +0 -128
  126. data/test/pass_thru_compressor_test.rb +0 -30
  127. data/test/pass_thru_decompressor_test.rb +0 -14
  128. data/test/path_traversal_test.rb +0 -141
  129. data/test/samples/example_recursive_test.rb +0 -37
  130. data/test/settings_test.rb +0 -95
  131. data/test/test_helper.rb +0 -234
  132. data/test/unicode_file_names_and_comments_test.rb +0 -62
  133. data/test/zip64_full_test.rb +0 -51
  134. data/test/zip64_support_test.rb +0 -14
@@ -1,54 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ZipFileExtractDirectoryTest < MiniTest::Test
4
- include CommonZipFileFixture
5
-
6
- TEST_OUT_NAME = 'test/data/generated/emptyOutDir'
7
-
8
- def open_zip(&aProc)
9
- assert(!aProc.nil?)
10
- ::Zip::File.open(TestZipFile::TEST_ZIP4.zip_name, &aProc)
11
- end
12
-
13
- def extract_test_dir(&aProc)
14
- open_zip do |zf|
15
- zf.extract(TestFiles::EMPTY_TEST_DIR, TEST_OUT_NAME, &aProc)
16
- end
17
- end
18
-
19
- def setup
20
- super
21
-
22
- Dir.rmdir(TEST_OUT_NAME) if File.directory? TEST_OUT_NAME
23
- File.delete(TEST_OUT_NAME) if File.exist? TEST_OUT_NAME
24
- end
25
-
26
- def test_extract_directory
27
- extract_test_dir
28
- assert(File.directory?(TEST_OUT_NAME))
29
- end
30
-
31
- def test_extract_directory_exists_as_dir
32
- Dir.mkdir TEST_OUT_NAME
33
- extract_test_dir
34
- assert(File.directory?(TEST_OUT_NAME))
35
- end
36
-
37
- def test_extract_directory_exists_as_file
38
- File.open(TEST_OUT_NAME, 'w') { |f| f.puts 'something' }
39
- assert_raises(::Zip::DestinationFileExistsError) { extract_test_dir }
40
- end
41
-
42
- def test_extract_directory_exists_as_file_overwrite
43
- File.open(TEST_OUT_NAME, 'w') { |f| f.puts 'something' }
44
- gotCalled = false
45
- extract_test_dir do |entry, destPath|
46
- gotCalled = true
47
- assert_equal(TEST_OUT_NAME, destPath)
48
- assert(entry.directory?)
49
- true
50
- end
51
- assert(gotCalled)
52
- assert(File.directory?(TEST_OUT_NAME))
53
- end
54
- end
@@ -1,145 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ZipFileExtractTest < MiniTest::Test
4
- include CommonZipFileFixture
5
- EXTRACTED_FILENAME = 'test/data/generated/extEntry'
6
- ENTRY_TO_EXTRACT, *REMAINING_ENTRIES = TEST_ZIP.entry_names.reverse
7
-
8
- def setup
9
- super
10
- ::File.delete(EXTRACTED_FILENAME) if ::File.exist?(EXTRACTED_FILENAME)
11
- end
12
-
13
- def teardown
14
- ::Zip.reset!
15
- end
16
-
17
- def test_extract
18
- ::Zip::File.open(TEST_ZIP.zip_name) do |zf|
19
- zf.extract(ENTRY_TO_EXTRACT, EXTRACTED_FILENAME)
20
-
21
- assert(File.exist?(EXTRACTED_FILENAME))
22
- AssertEntry.assert_contents(EXTRACTED_FILENAME,
23
- zf.get_input_stream(ENTRY_TO_EXTRACT) { |is| is.read })
24
-
25
- ::File.unlink(EXTRACTED_FILENAME)
26
-
27
- entry = zf.get_entry(ENTRY_TO_EXTRACT)
28
- entry.extract(EXTRACTED_FILENAME)
29
-
30
- assert(File.exist?(EXTRACTED_FILENAME))
31
- AssertEntry.assert_contents(EXTRACTED_FILENAME,
32
- entry.get_input_stream { |is| is.read })
33
- end
34
- end
35
-
36
- def test_extract_exists
37
- writtenText = 'written text'
38
- ::File.open(EXTRACTED_FILENAME, 'w') { |f| f.write(writtenText) }
39
-
40
- assert_raises(::Zip::DestinationFileExistsError) do
41
- ::Zip::File.open(TEST_ZIP.zip_name) do |zf|
42
- zf.extract(zf.entries.first, EXTRACTED_FILENAME)
43
- end
44
- end
45
- File.open(EXTRACTED_FILENAME, 'r') do |f|
46
- assert_equal(writtenText, f.read)
47
- end
48
- end
49
-
50
- def test_extract_exists_overwrite
51
- writtenText = 'written text'
52
- ::File.open(EXTRACTED_FILENAME, 'w') { |f| f.write(writtenText) }
53
-
54
- gotCalledCorrectly = false
55
- ::Zip::File.open(TEST_ZIP.zip_name) do |zf|
56
- zf.extract(zf.entries.first, EXTRACTED_FILENAME) do |entry, extractLoc|
57
- gotCalledCorrectly = zf.entries.first == entry &&
58
- extractLoc == EXTRACTED_FILENAME
59
- true
60
- end
61
- end
62
-
63
- assert(gotCalledCorrectly)
64
- ::File.open(EXTRACTED_FILENAME, 'r') do |f|
65
- assert(writtenText != f.read)
66
- end
67
- end
68
-
69
- def test_extract_non_entry
70
- zf = ::Zip::File.new(TEST_ZIP.zip_name)
71
- assert_raises(Errno::ENOENT) { zf.extract('nonExistingEntry', 'nonExistingEntry') }
72
- ensure
73
- zf.close if zf
74
- end
75
-
76
- def test_extract_non_entry_2
77
- outFile = 'outfile'
78
- assert_raises(Errno::ENOENT) do
79
- zf = ::Zip::File.new(TEST_ZIP.zip_name)
80
- nonEntry = 'hotdog-diddelidoo'
81
- assert(!zf.entries.include?(nonEntry))
82
- zf.extract(nonEntry, outFile)
83
- zf.close
84
- end
85
- assert(!File.exist?(outFile))
86
- end
87
-
88
- def test_extract_incorrect_size
89
- # The uncompressed size fields in the zip file cannot be trusted. This makes
90
- # it harder for callers to validate the sizes of the files they are
91
- # extracting, which can lead to denial of service. See also
92
- # https://en.wikipedia.org/wiki/Zip_bomb
93
- Dir.mktmpdir do |tmp|
94
- real_zip = File.join(tmp, 'real.zip')
95
- fake_zip = File.join(tmp, 'fake.zip')
96
- file_name = 'a'
97
- true_size = 500_000
98
- fake_size = 1
99
-
100
- ::Zip::File.open(real_zip, ::Zip::File::CREATE) do |zf|
101
- zf.get_output_stream(file_name) do |os|
102
- os.write 'a' * true_size
103
- end
104
- end
105
-
106
- compressed_size = nil
107
- ::Zip::File.open(real_zip) do |zf|
108
- a_entry = zf.find_entry(file_name)
109
- compressed_size = a_entry.compressed_size
110
- assert_equal true_size, a_entry.size
111
- end
112
-
113
- true_size_bytes = [compressed_size, true_size, file_name.size].pack('LLS')
114
- fake_size_bytes = [compressed_size, fake_size, file_name.size].pack('LLS')
115
-
116
- data = File.binread(real_zip)
117
- assert data.include?(true_size_bytes)
118
- data.gsub! true_size_bytes, fake_size_bytes
119
-
120
- File.open(fake_zip, 'wb') do |file|
121
- file.write data
122
- end
123
-
124
- Dir.chdir tmp do
125
- ::Zip::File.open(fake_zip) do |zf|
126
- a_entry = zf.find_entry(file_name)
127
- assert_equal fake_size, a_entry.size
128
-
129
- ::Zip.validate_entry_sizes = false
130
- a_entry.extract
131
- assert_equal true_size, File.size(file_name)
132
- FileUtils.rm file_name
133
-
134
- ::Zip.validate_entry_sizes = true
135
- error = assert_raises ::Zip::EntrySizeError do
136
- a_entry.extract
137
- end
138
- assert_equal \
139
- 'Entry a should be 1B but is larger when inflated',
140
- error.message
141
- end
142
- end
143
- end
144
- end
145
- end
@@ -1,65 +0,0 @@
1
- require 'test_helper'
2
-
3
- class FilePermissionsTest < MiniTest::Test
4
- ZIPNAME = File.join(File.dirname(__FILE__), 'umask.zip')
5
- FILENAME = File.join(File.dirname(__FILE__), 'umask.txt')
6
-
7
- def teardown
8
- ::File.unlink(ZIPNAME)
9
- ::File.unlink(FILENAME)
10
- end
11
-
12
- def test_current_umask
13
- create_files
14
- assert_matching_permissions FILENAME, ZIPNAME
15
- end
16
-
17
- def test_umask_000
18
- set_umask(0o000) do
19
- create_files
20
- end
21
-
22
- assert_matching_permissions FILENAME, ZIPNAME
23
- end
24
-
25
- def test_umask_066
26
- set_umask(0o066) do
27
- create_files
28
- end
29
-
30
- assert_matching_permissions FILENAME, ZIPNAME
31
- end
32
-
33
- def test_umask_027
34
- set_umask(0o027) do
35
- create_files
36
- end
37
-
38
- assert_matching_permissions FILENAME, ZIPNAME
39
- end
40
-
41
- def assert_matching_permissions(expected_file, actual_file)
42
- assert_equal(
43
- ::File.stat(expected_file).mode.to_s(8).rjust(4, '0'),
44
- ::File.stat(actual_file).mode.to_s(8).rjust(4, '0')
45
- )
46
- end
47
-
48
- def create_files
49
- ::Zip::File.open(ZIPNAME, ::Zip::File::CREATE) do |zip|
50
- zip.comment = 'test'
51
- end
52
-
53
- ::File.open(FILENAME, 'w') do |file|
54
- file << 'test'
55
- end
56
- end
57
-
58
- # If anything goes wrong, make sure the umask is restored.
59
- def set_umask(umask)
60
- saved_umask = ::File.umask(umask)
61
- yield
62
- ensure
63
- ::File.umask(saved_umask)
64
- end
65
- end
@@ -1,57 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ZipFileSplitTest < MiniTest::Test
4
- TEST_ZIP = TestZipFile::TEST_ZIP2.clone
5
- TEST_ZIP.zip_name = 'large_zip_file.zip'
6
- EXTRACTED_FILENAME = 'test/data/generated/extEntrySplit'
7
- UNSPLITTED_FILENAME = 'test/data/generated/unsplitted.zip'
8
- ENTRY_TO_EXTRACT = TEST_ZIP.entry_names.first
9
-
10
- def setup
11
- FileUtils.cp(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name)
12
- end
13
-
14
- def teardown
15
- File.delete(TEST_ZIP.zip_name)
16
- File.delete(UNSPLITTED_FILENAME) if File.exist?(UNSPLITTED_FILENAME)
17
-
18
- Dir["#{TEST_ZIP.zip_name}.*"].each do |zip_file_name|
19
- File.delete(zip_file_name) if File.exist?(zip_file_name)
20
- end
21
- end
22
-
23
- def test_split_method_respond
24
- assert_respond_to ::Zip::File, :split, 'Does not have split class method'
25
- end
26
-
27
- def test_split
28
- result = ::Zip::File.split(TEST_ZIP.zip_name, 65_536, false)
29
-
30
- return if result.nil?
31
- Dir["#{TEST_ZIP.zip_name}.*"].sort.each_with_index do |zip_file_name, index|
32
- File.open(zip_file_name, 'rb') do |zip_file|
33
- zip_file.read([::Zip::File::SPLIT_SIGNATURE].pack('V').size) if index == 0
34
- File.open(UNSPLITTED_FILENAME, 'ab') do |file|
35
- file << zip_file.read
36
- end
37
- end
38
- end
39
-
40
- ::Zip::File.open(UNSPLITTED_FILENAME) do |zf|
41
- zf.extract(ENTRY_TO_EXTRACT, EXTRACTED_FILENAME)
42
-
43
- assert(File.exist?(EXTRACTED_FILENAME))
44
- AssertEntry.assert_contents(EXTRACTED_FILENAME,
45
- zf.get_input_stream(ENTRY_TO_EXTRACT) { |is| is.read })
46
-
47
- File.unlink(EXTRACTED_FILENAME)
48
-
49
- entry = zf.get_entry(ENTRY_TO_EXTRACT)
50
- entry.extract(EXTRACTED_FILENAME)
51
-
52
- assert(File.exist?(EXTRACTED_FILENAME))
53
- AssertEntry.assert_contents(EXTRACTED_FILENAME,
54
- entry.get_input_stream { |is| is.read })
55
- end
56
- end
57
- end