rubyzip 1.2.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +64 -23
- data/lib/zip.rb +5 -3
- data/lib/zip/constants.rb +52 -0
- data/lib/zip/crypto/decrypted_io.rb +39 -0
- data/lib/zip/decompressor.rb +19 -1
- data/lib/zip/dos_time.rb +5 -0
- data/lib/zip/entry.rb +34 -10
- data/lib/zip/errors.rb +2 -0
- data/lib/zip/extra_field/generic.rb +1 -1
- data/lib/zip/extra_field/universal_time.rb +39 -12
- data/lib/zip/file.rb +68 -34
- data/lib/zip/inflater.rb +22 -36
- data/lib/zip/input_stream.rb +28 -24
- data/lib/zip/ioextras/abstract_input_stream.rb +6 -0
- data/lib/zip/null_decompressor.rb +1 -9
- data/lib/zip/pass_thru_decompressor.rb +13 -22
- data/lib/zip/streamable_stream.rb +1 -6
- data/lib/zip/version.rb +1 -1
- metadata +12 -154
- data/test/basic_zip_file_test.rb +0 -60
- data/test/case_sensitivity_test.rb +0 -69
- data/test/central_directory_entry_test.rb +0 -69
- data/test/central_directory_test.rb +0 -100
- data/test/crypto/null_encryption_test.rb +0 -57
- data/test/crypto/traditional_encryption_test.rb +0 -80
- data/test/data/WarnInvalidDate.zip +0 -0
- data/test/data/file1.txt +0 -46
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +0 -1504
- data/test/data/globTest.zip +0 -0
- data/test/data/globTest/foo.txt +0 -0
- data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
- data/test/data/globTest/food.txt +0 -0
- data/test/data/gpbit3stored.zip +0 -0
- data/test/data/mimetype +0 -1
- data/test/data/notzippedruby.rb +0 -7
- data/test/data/ntfs.zip +0 -0
- data/test/data/oddExtraField.zip +0 -0
- data/test/data/path_traversal/Makefile +0 -10
- data/test/data/path_traversal/jwilk/README.md +0 -5
- data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
- data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
- data/test/data/path_traversal/jwilk/relative0.zip +0 -0
- data/test/data/path_traversal/jwilk/relative2.zip +0 -0
- data/test/data/path_traversal/jwilk/symlink.zip +0 -0
- data/test/data/path_traversal/relative1.zip +0 -0
- data/test/data/path_traversal/tilde.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
- data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/test.xls +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zip64-sample.zip +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/data/zipWithEncryption.zip +0 -0
- data/test/deflater_test.rb +0 -65
- data/test/encryption_test.rb +0 -42
- data/test/entry_set_test.rb +0 -163
- data/test/entry_test.rb +0 -154
- data/test/errors_test.rb +0 -35
- data/test/extra_field_test.rb +0 -76
- data/test/file_extract_directory_test.rb +0 -54
- data/test/file_extract_test.rb +0 -83
- data/test/file_permissions_test.rb +0 -65
- data/test/file_split_test.rb +0 -57
- data/test/file_test.rb +0 -601
- data/test/filesystem/dir_iterator_test.rb +0 -58
- data/test/filesystem/directory_test.rb +0 -139
- data/test/filesystem/file_mutating_test.rb +0 -87
- data/test/filesystem/file_nonmutating_test.rb +0 -508
- data/test/filesystem/file_stat_test.rb +0 -64
- data/test/gentestfiles.rb +0 -126
- data/test/inflater_test.rb +0 -14
- data/test/input_stream_test.rb +0 -182
- data/test/ioextras/abstract_input_stream_test.rb +0 -102
- data/test/ioextras/abstract_output_stream_test.rb +0 -106
- data/test/ioextras/fake_io_test.rb +0 -18
- data/test/local_entry_test.rb +0 -154
- data/test/output_stream_test.rb +0 -128
- data/test/pass_thru_compressor_test.rb +0 -30
- data/test/pass_thru_decompressor_test.rb +0 -14
- data/test/path_traversal_test.rb +0 -141
- data/test/samples/example_recursive_test.rb +0 -37
- data/test/settings_test.rb +0 -95
- data/test/test_helper.rb +0 -234
- data/test/unicode_file_names_and_comments_test.rb +0 -62
- data/test/zip64_full_test.rb +0 -51
- data/test/zip64_support_test.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cba65b486ec6325e6623957990539a225398a2b9b665b5814a5c06ba70ea1744
|
4
|
+
data.tar.gz: 37dc716e5d98048e1b0c72165c16deb6a6bfef02556890f783cdc62ff5021f4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45de19fa6e2c549c07830243686d622adb937509a942eeb1412a05ea6d1f4a1bde5d60429446ff64f607f3a55400a38c9ccd2d30380825fb4b6e55618702d802
|
7
|
+
data.tar.gz: 8d22f9bc464d950e9ede9cfc1da1056ba664ede954b93ae12d0af68e1d859600d8cd63ba5768553f3d810a693d38ce912c0c2d0f3b3d130da973c8bd833fb3bc
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# rubyzip
|
2
|
+
|
2
3
|
[![Gem Version](https://badge.fury.io/rb/rubyzip.svg)](http://badge.fury.io/rb/rubyzip)
|
3
4
|
[![Build Status](https://secure.travis-ci.org/rubyzip/rubyzip.svg)](http://travis-ci.org/rubyzip/rubyzip)
|
4
5
|
[![Code Climate](https://codeclimate.com/github/rubyzip/rubyzip.svg)](https://codeclimate.com/github/rubyzip/rubyzip)
|
@@ -19,9 +20,10 @@ gem 'zip-zip' # will load compatibility for old rubyzip API.
|
|
19
20
|
|
20
21
|
## Requirements
|
21
22
|
|
22
|
-
|
23
|
+
- Ruby 2.4 or greater (for rubyzip 2.0; use 1.x for older rubies)
|
23
24
|
|
24
25
|
## Installation
|
26
|
+
|
25
27
|
Rubyzip is available on RubyGems:
|
26
28
|
|
27
29
|
```
|
@@ -59,7 +61,8 @@ end
|
|
59
61
|
```
|
60
62
|
|
61
63
|
### Zipping a directory recursively
|
62
|
-
|
64
|
+
|
65
|
+
Copy from [here](https://github.com/rubyzip/rubyzip/blob/9d891f7353e66052283562d3e252fe380bb4b199/samples/example_recursive.rb)
|
63
66
|
|
64
67
|
```ruby
|
65
68
|
require 'zip'
|
@@ -83,7 +86,7 @@ class ZipFileGenerator
|
|
83
86
|
|
84
87
|
# Zip the input directory.
|
85
88
|
def write
|
86
|
-
entries = Dir.entries(@input_dir) - %w
|
89
|
+
entries = Dir.entries(@input_dir) - %w[. ..]
|
87
90
|
|
88
91
|
::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
|
89
92
|
write_entries entries, '', zipfile
|
@@ -97,7 +100,6 @@ class ZipFileGenerator
|
|
97
100
|
entries.each do |e|
|
98
101
|
zipfile_path = path == '' ? e : File.join(path, e)
|
99
102
|
disk_file_path = File.join(@input_dir, zipfile_path)
|
100
|
-
puts "Deflating #{disk_file_path}"
|
101
103
|
|
102
104
|
if File.directory? disk_file_path
|
103
105
|
recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
|
@@ -109,14 +111,12 @@ class ZipFileGenerator
|
|
109
111
|
|
110
112
|
def recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
|
111
113
|
zipfile.mkdir zipfile_path
|
112
|
-
subdir = Dir.entries(disk_file_path) - %w
|
114
|
+
subdir = Dir.entries(disk_file_path) - %w[. ..]
|
113
115
|
write_entries subdir, zipfile_path, zipfile
|
114
116
|
end
|
115
117
|
|
116
118
|
def put_into_archive(disk_file_path, zipfile, zipfile_path)
|
117
|
-
zipfile.
|
118
|
-
f.write(File.open(disk_file_path, 'rb').read)
|
119
|
-
end
|
119
|
+
zipfile.add(zipfile_path, disk_file_path)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
```
|
@@ -152,12 +152,15 @@ When modifying a zip archive the file permissions of the archive are preserved.
|
|
152
152
|
### Reading a Zip file
|
153
153
|
|
154
154
|
```ruby
|
155
|
+
MAX_SIZE = 1024**2 # 1MiB (but of course you can increase this)
|
155
156
|
Zip::File.open('foo.zip') do |zip_file|
|
156
157
|
# Handle entries one by one
|
157
158
|
zip_file.each do |entry|
|
158
|
-
# Extract to file/directory/symlink
|
159
159
|
puts "Extracting #{entry.name}"
|
160
|
-
entry.
|
160
|
+
raise 'File too large when extracted' if entry.size > MAX_SIZE
|
161
|
+
|
162
|
+
# Extract to file or directory based on name in the archive
|
163
|
+
entry.extract
|
161
164
|
|
162
165
|
# Read into memory
|
163
166
|
content = entry.get_input_stream.read
|
@@ -165,6 +168,7 @@ Zip::File.open('foo.zip') do |zip_file|
|
|
165
168
|
|
166
169
|
# Find specific entry
|
167
170
|
entry = zip_file.glob('*.csv').first
|
171
|
+
raise 'File too large when extracted' if entry.size > MAX_SIZE
|
168
172
|
puts entry.get_input_stream.read
|
169
173
|
end
|
170
174
|
```
|
@@ -177,7 +181,6 @@ But there is one exception when it is not working - General Purpose Flag Bit 3.
|
|
177
181
|
|
178
182
|
> If bit 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written. The fields in the local header are filled with zero, and the CRC-32 and size are appended in a 12-byte structure (optionally preceded by a 4-byte signature) immediately after the compressed data
|
179
183
|
|
180
|
-
|
181
184
|
If `::Zip::InputStream` finds such entry in the zip archive it will raise an exception.
|
182
185
|
|
183
186
|
### Password Protection (Experimental)
|
@@ -220,7 +223,9 @@ File.open(new_path, "wb") {|f| f.write(buffer.string) }
|
|
220
223
|
|
221
224
|
## Configuration
|
222
225
|
|
223
|
-
|
226
|
+
### Existing Files
|
227
|
+
|
228
|
+
By default, rubyzip will not overwrite files if they already exist inside of the extracted path. To change this behavior, you may specify a configuration option like so:
|
224
229
|
|
225
230
|
```ruby
|
226
231
|
Zip.on_exists_proc = true
|
@@ -234,32 +239,76 @@ Additionally, if you want to configure rubyzip to overwrite existing files while
|
|
234
239
|
Zip.continue_on_exists_proc = true
|
235
240
|
```
|
236
241
|
|
242
|
+
### Non-ASCII Names
|
243
|
+
|
237
244
|
If you want to store non-english names and want to open them on Windows(pre 7) you need to set this option:
|
238
245
|
|
239
246
|
```ruby
|
240
247
|
Zip.unicode_names = true
|
241
248
|
```
|
242
249
|
|
250
|
+
Sometimes file names inside zip contain non-ASCII characters. If you can assume which encoding was used for such names and want to be able to find such entries using `find_entry` then you can force assumed encoding like so:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
Zip.force_entry_names_encoding = 'UTF-8'
|
254
|
+
```
|
255
|
+
|
256
|
+
Allowed encoding names are the same as accepted by `String#force_encoding`
|
257
|
+
|
258
|
+
### Date Validation
|
259
|
+
|
243
260
|
Some zip files might have an invalid date format, which will raise a warning. You can hide this warning with the following setting:
|
244
261
|
|
245
262
|
```ruby
|
246
263
|
Zip.warn_invalid_date = false
|
247
264
|
```
|
248
265
|
|
266
|
+
### Size Validation
|
267
|
+
|
268
|
+
By default (in rubyzip >= 2.0), rubyzip's `extract` method checks that an entry's reported uncompressed size is not (significantly) smaller than its actual size. This is to help you protect your application against [zip bombs](https://en.wikipedia.org/wiki/Zip_bomb). Before `extract`ing an entry, you should check that its size is in the range you expect. For example, if your application supports processing up to 100 files at once, each up to 10MiB, your zip extraction code might look like:
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
MAX_FILE_SIZE = 10 * 1024**2 # 10MiB
|
272
|
+
MAX_FILES = 100
|
273
|
+
Zip::File.open('foo.zip') do |zip_file|
|
274
|
+
num_files = 0
|
275
|
+
zip_file.each do |entry|
|
276
|
+
num_files += 1 if entry.file?
|
277
|
+
raise 'Too many extracted files' if num_files > MAX_FILES
|
278
|
+
raise 'File too large when extracted' if entry.size > MAX_FILE_SIZE
|
279
|
+
entry.extract
|
280
|
+
end
|
281
|
+
end
|
282
|
+
```
|
283
|
+
|
284
|
+
If you need to extract zip files that report incorrect uncompressed sizes and you really trust them not too be too large, you can disable this setting with
|
285
|
+
```ruby
|
286
|
+
Zip.validate_entry_sizes = false
|
287
|
+
```
|
288
|
+
|
289
|
+
Note that if you use the lower level `Zip::InputStream` interface, `rubyzip` does *not* check the entry `size`s. In this case, the caller is responsible for making sure it does not read more data than expected from the input stream.
|
290
|
+
|
291
|
+
### Default Compression
|
292
|
+
|
249
293
|
You can set the default compression level like so:
|
250
294
|
|
251
295
|
```ruby
|
252
296
|
Zip.default_compression = Zlib::DEFAULT_COMPRESSION
|
253
297
|
```
|
298
|
+
|
254
299
|
It defaults to `Zlib::DEFAULT_COMPRESSION`. Possible values are `Zlib::BEST_COMPRESSION`, `Zlib::DEFAULT_COMPRESSION` and `Zlib::NO_COMPRESSION`
|
255
300
|
|
256
|
-
|
301
|
+
### Zip64 Support
|
302
|
+
|
303
|
+
By default, Zip64 support is disabled for writing. To enable it do this:
|
257
304
|
|
258
305
|
```ruby
|
259
|
-
Zip.
|
306
|
+
Zip.write_zip64_support = true
|
260
307
|
```
|
261
308
|
|
262
|
-
|
309
|
+
_NOTE_: If you will enable Zip64 writing then you will need zip extractor with Zip64 support to extract archive.
|
310
|
+
|
311
|
+
### Block Form
|
263
312
|
|
264
313
|
You can set multiple settings at the same time by using a block:
|
265
314
|
|
@@ -272,14 +321,6 @@ You can set multiple settings at the same time by using a block:
|
|
272
321
|
end
|
273
322
|
```
|
274
323
|
|
275
|
-
By default, Zip64 support is disabled for writing. To enable it do this:
|
276
|
-
|
277
|
-
```ruby
|
278
|
-
Zip.write_zip64_support = true
|
279
|
-
```
|
280
|
-
|
281
|
-
_NOTE_: If you will enable Zip64 writing then you will need zip extractor with Zip64 support to extract archive.
|
282
|
-
|
283
324
|
## Developing
|
284
325
|
|
285
326
|
To run the test you need to do this:
|
data/lib/zip.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
require 'singleton'
|
3
3
|
require 'tempfile'
|
4
|
-
require 'tmpdir'
|
5
4
|
require 'fileutils'
|
6
5
|
require 'stringio'
|
7
6
|
require 'zlib'
|
7
|
+
require 'zip/constants'
|
8
8
|
require 'zip/dos_time'
|
9
9
|
require 'zip/ioextras'
|
10
10
|
require 'rbconfig'
|
@@ -22,6 +22,7 @@ require 'zip/null_compressor'
|
|
22
22
|
require 'zip/null_input_stream'
|
23
23
|
require 'zip/pass_thru_compressor'
|
24
24
|
require 'zip/pass_thru_decompressor'
|
25
|
+
require 'zip/crypto/decrypted_io'
|
25
26
|
require 'zip/crypto/encryption'
|
26
27
|
require 'zip/crypto/null_encryption'
|
27
28
|
require 'zip/crypto/traditional_encryption'
|
@@ -29,7 +30,6 @@ require 'zip/inflater'
|
|
29
30
|
require 'zip/deflater'
|
30
31
|
require 'zip/streamable_stream'
|
31
32
|
require 'zip/streamable_directory'
|
32
|
-
require 'zip/constants'
|
33
33
|
require 'zip/errors'
|
34
34
|
|
35
35
|
module Zip
|
@@ -42,7 +42,8 @@ module Zip
|
|
42
42
|
:write_zip64_support,
|
43
43
|
:warn_invalid_date,
|
44
44
|
:case_insensitive_match,
|
45
|
-
:force_entry_names_encoding
|
45
|
+
:force_entry_names_encoding,
|
46
|
+
:validate_entry_sizes
|
46
47
|
|
47
48
|
def reset!
|
48
49
|
@_ran_once = false
|
@@ -54,6 +55,7 @@ module Zip
|
|
54
55
|
@write_zip64_support = false
|
55
56
|
@warn_invalid_date = true
|
56
57
|
@case_insensitive_match = false
|
58
|
+
@validate_entry_sizes = true
|
57
59
|
end
|
58
60
|
|
59
61
|
def setup
|
data/lib/zip/constants.rb
CHANGED
@@ -60,4 +60,56 @@ module Zip
|
|
60
60
|
FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.freeze,
|
61
61
|
FSTYPE_ATHEOS => 'AtheOS'.freeze
|
62
62
|
}.freeze
|
63
|
+
|
64
|
+
COMPRESSION_METHOD_STORE = 0
|
65
|
+
COMPRESSION_METHOD_SHRINK = 1
|
66
|
+
COMPRESSION_METHOD_REDUCE_1 = 2
|
67
|
+
COMPRESSION_METHOD_REDUCE_2 = 3
|
68
|
+
COMPRESSION_METHOD_REDUCE_3 = 4
|
69
|
+
COMPRESSION_METHOD_REDUCE_4 = 5
|
70
|
+
COMPRESSION_METHOD_IMPLODE = 6
|
71
|
+
# RESERVED = 7
|
72
|
+
COMPRESSION_METHOD_DEFLATE = 8
|
73
|
+
COMPRESSION_METHOD_DEFLATE_64 = 9
|
74
|
+
COMPRESSION_METHOD_PKWARE_DCLI = 10
|
75
|
+
# RESERVED = 11
|
76
|
+
COMPRESSION_METHOD_BZIP2 = 12
|
77
|
+
# RESERVED = 13
|
78
|
+
COMPRESSION_METHOD_LZMA = 14
|
79
|
+
# RESERVED = 15
|
80
|
+
COMPRESSION_METHOD_IBM_CMPSC = 16
|
81
|
+
# RESERVED = 17
|
82
|
+
COMPRESSION_METHOD_IBM_TERSE = 18
|
83
|
+
COMPRESSION_METHOD_IBM_LZ77 = 19
|
84
|
+
COMPRESSION_METHOD_JPEG = 96
|
85
|
+
COMPRESSION_METHOD_WAVPACK = 97
|
86
|
+
COMPRESSION_METHOD_PPMD = 98
|
87
|
+
COMPRESSION_METHOD_AES = 99
|
88
|
+
|
89
|
+
COMPRESSION_METHODS = {
|
90
|
+
COMPRESSION_METHOD_STORE => 'Store (no compression)',
|
91
|
+
COMPRESSION_METHOD_SHRINK => 'Shrink',
|
92
|
+
COMPRESSION_METHOD_REDUCE_1 => 'Reduce with compression factor 1',
|
93
|
+
COMPRESSION_METHOD_REDUCE_2 => 'Reduce with compression factor 2',
|
94
|
+
COMPRESSION_METHOD_REDUCE_3 => 'Reduce with compression factor 3',
|
95
|
+
COMPRESSION_METHOD_REDUCE_4 => 'Reduce with compression factor 4',
|
96
|
+
COMPRESSION_METHOD_IMPLODE => 'Implode',
|
97
|
+
# RESERVED = 7
|
98
|
+
COMPRESSION_METHOD_DEFLATE => 'Deflate',
|
99
|
+
COMPRESSION_METHOD_DEFLATE_64 => 'Deflate64(tm)',
|
100
|
+
COMPRESSION_METHOD_PKWARE_DCLI => 'PKWARE Data Compression Library Imploding (old IBM TERSE)',
|
101
|
+
# RESERVED = 11
|
102
|
+
COMPRESSION_METHOD_BZIP2 => 'BZIP2',
|
103
|
+
# RESERVED = 13
|
104
|
+
COMPRESSION_METHOD_LZMA => 'LZMA',
|
105
|
+
# RESERVED = 15
|
106
|
+
COMPRESSION_METHOD_IBM_CMPSC => 'IBM z/OS CMPSC Compression',
|
107
|
+
# RESERVED = 17
|
108
|
+
COMPRESSION_METHOD_IBM_TERSE => 'IBM TERSE (new)',
|
109
|
+
COMPRESSION_METHOD_IBM_LZ77 => 'IBM LZ77 z Architecture (PFS)',
|
110
|
+
COMPRESSION_METHOD_JPEG => 'JPEG variant',
|
111
|
+
COMPRESSION_METHOD_WAVPACK => 'WavPack compressed data',
|
112
|
+
COMPRESSION_METHOD_PPMD => 'PPMd version I, Rev 1',
|
113
|
+
COMPRESSION_METHOD_AES => 'AES encryption',
|
114
|
+
}.freeze
|
63
115
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Zip
|
2
|
+
class DecryptedIo #:nodoc:all
|
3
|
+
CHUNK_SIZE = 32_768
|
4
|
+
|
5
|
+
def initialize(io, decrypter)
|
6
|
+
@io = io
|
7
|
+
@decrypter = decrypter
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(length = nil, outbuf = '')
|
11
|
+
return ((length.nil? || length.zero?) ? "" : nil) if eof
|
12
|
+
|
13
|
+
while length.nil? || (buffer.bytesize < length)
|
14
|
+
break if input_finished?
|
15
|
+
buffer << produce_input
|
16
|
+
end
|
17
|
+
|
18
|
+
outbuf.replace(buffer.slice!(0...(length || output_buffer.bytesize)))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def eof
|
24
|
+
buffer.empty? && input_finished?
|
25
|
+
end
|
26
|
+
|
27
|
+
def buffer
|
28
|
+
@buffer ||= ''.dup
|
29
|
+
end
|
30
|
+
|
31
|
+
def input_finished?
|
32
|
+
@io.eof
|
33
|
+
end
|
34
|
+
|
35
|
+
def produce_input
|
36
|
+
@decrypter.decrypt(@io.read(CHUNK_SIZE))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/zip/decompressor.rb
CHANGED
@@ -1,9 +1,27 @@
|
|
1
1
|
module Zip
|
2
2
|
class Decompressor #:nodoc:all
|
3
3
|
CHUNK_SIZE = 32_768
|
4
|
-
|
4
|
+
|
5
|
+
def self.decompressor_classes
|
6
|
+
@decompressor_classes ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.register(compression_method, decompressor_class)
|
10
|
+
decompressor_classes[compression_method] = decompressor_class
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find_by_compression_method(compression_method)
|
14
|
+
decompressor_classes[compression_method]
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :input_stream
|
18
|
+
attr_reader :decompressed_size
|
19
|
+
|
20
|
+
def initialize(input_stream, decompressed_size = nil)
|
5
21
|
super()
|
22
|
+
|
6
23
|
@input_stream = input_stream
|
24
|
+
@decompressed_size = decompressed_size
|
7
25
|
end
|
8
26
|
end
|
9
27
|
end
|
data/lib/zip/dos_time.rb
CHANGED
@@ -29,6 +29,11 @@ module Zip
|
|
29
29
|
to_i / 2 == other.to_i / 2
|
30
30
|
end
|
31
31
|
|
32
|
+
# Create a DOSTime instance from a vanilla Time instance.
|
33
|
+
def self.from_time(time)
|
34
|
+
local(time.year, time.month, time.day, time.hour, time.min, time.sec)
|
35
|
+
end
|
36
|
+
|
32
37
|
def self.parse_binary_dos_format(binaryDosDate, binaryDosTime)
|
33
38
|
second = 2 * (0b11111 & binaryDosTime)
|
34
39
|
minute = (0b11111100000 & binaryDosTime) >> 5
|
data/lib/zip/entry.rb
CHANGED
@@ -34,7 +34,7 @@ module Zip
|
|
34
34
|
end
|
35
35
|
@follow_symlinks = false
|
36
36
|
|
37
|
-
@restore_times =
|
37
|
+
@restore_times = false
|
38
38
|
@restore_permissions = false
|
39
39
|
@restore_ownership = false
|
40
40
|
# BUG: need an extra field to support uid/gid's
|
@@ -72,6 +72,14 @@ module Zip
|
|
72
72
|
@extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.is_a?(::Zip::ExtraField)
|
73
73
|
end
|
74
74
|
|
75
|
+
def encrypted?
|
76
|
+
gp_flags & 1 == 1
|
77
|
+
end
|
78
|
+
|
79
|
+
def incomplete?
|
80
|
+
gp_flags & 8 == 8
|
81
|
+
end
|
82
|
+
|
75
83
|
def time
|
76
84
|
if @extra['UniversalTime']
|
77
85
|
@extra['UniversalTime'].mtime
|
@@ -163,7 +171,7 @@ module Zip
|
|
163
171
|
# is passed.
|
164
172
|
def extract(dest_path = nil, &block)
|
165
173
|
if dest_path.nil? && !name_safe?
|
166
|
-
|
174
|
+
warn "WARNING: skipped '#{@name}' as unsafe."
|
167
175
|
return self
|
168
176
|
end
|
169
177
|
|
@@ -406,16 +414,20 @@ module Zip
|
|
406
414
|
@unix_uid = stat.uid
|
407
415
|
@unix_gid = stat.gid
|
408
416
|
@unix_perms = stat.mode & 0o7777
|
417
|
+
@time = ::Zip::DOSTime.from_time(stat.mtime)
|
409
418
|
end
|
410
419
|
|
411
|
-
def
|
412
|
-
# BUG: does not update timestamps into account
|
420
|
+
def set_unix_attributes_on_path(dest_path)
|
413
421
|
# ignore setuid/setgid bits by default. honor if @restore_ownership
|
414
422
|
unix_perms_mask = 0o1777
|
415
423
|
unix_perms_mask = 0o7777 if @restore_ownership
|
416
424
|
::FileUtils.chmod(@unix_perms & unix_perms_mask, dest_path) if @restore_permissions && @unix_perms
|
417
425
|
::FileUtils.chown(@unix_uid, @unix_gid, dest_path) if @restore_ownership && @unix_uid && @unix_gid && ::Process.egid == 0
|
418
|
-
|
426
|
+
|
427
|
+
# Restore the timestamp on a file. This will either have come from the
|
428
|
+
# original source file that was copied into the archive, or from the
|
429
|
+
# creation date of the archive if there was no original source file.
|
430
|
+
::FileUtils.touch(dest_path, mtime: time) if @restore_times
|
419
431
|
end
|
420
432
|
|
421
433
|
def set_extra_attributes_on_path(dest_path) # :nodoc:
|
@@ -423,7 +435,7 @@ module Zip
|
|
423
435
|
|
424
436
|
case @fstype
|
425
437
|
when ::Zip::FSTYPE_UNIX
|
426
|
-
|
438
|
+
set_unix_attributes_on_path(dest_path)
|
427
439
|
end
|
428
440
|
end
|
429
441
|
|
@@ -591,7 +603,7 @@ module Zip
|
|
591
603
|
def set_time(binary_dos_date, binary_dos_time)
|
592
604
|
@time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
|
593
605
|
rescue ArgumentError
|
594
|
-
warn '
|
606
|
+
warn 'WARNING: invalid date/time in zip entry.' if ::Zip.warn_invalid_date
|
595
607
|
end
|
596
608
|
|
597
609
|
def create_file(dest_path, _continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
|
@@ -601,14 +613,26 @@ module Zip
|
|
601
613
|
end
|
602
614
|
::File.open(dest_path, 'wb') do |os|
|
603
615
|
get_input_stream do |is|
|
604
|
-
|
605
|
-
|
616
|
+
bytes_written = 0
|
617
|
+
warned = false
|
606
618
|
buf = ''.dup
|
607
619
|
while (buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf))
|
608
620
|
os << buf
|
621
|
+
bytes_written += buf.bytesize
|
622
|
+
if bytes_written > size && !warned
|
623
|
+
message = "entry '#{name}' should be #{size}B, but is larger when inflated."
|
624
|
+
if ::Zip.validate_entry_sizes
|
625
|
+
raise ::Zip::EntrySizeError, message
|
626
|
+
else
|
627
|
+
warn "WARNING: #{message}"
|
628
|
+
warned = true
|
629
|
+
end
|
630
|
+
end
|
609
631
|
end
|
610
632
|
end
|
611
633
|
end
|
634
|
+
|
635
|
+
set_extra_attributes_on_path(dest_path)
|
612
636
|
end
|
613
637
|
|
614
638
|
def create_directory(dest_path)
|
@@ -630,7 +654,7 @@ module Zip
|
|
630
654
|
def create_symlink(dest_path)
|
631
655
|
# TODO: Symlinks pose security challenges. Symlink support temporarily
|
632
656
|
# removed in view of https://github.com/rubyzip/rubyzip/issues/369 .
|
633
|
-
|
657
|
+
warn "WARNING: skipped symlink '#{dest_path}'."
|
634
658
|
end
|
635
659
|
|
636
660
|
# apply missing data from the zip64 extra information field, if present
|