rubyzip 1.2.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +64 -23
- data/lib/zip.rb +3 -2
- data/lib/zip/dos_time.rb +5 -0
- data/lib/zip/entry.rb +36 -19
- data/lib/zip/errors.rb +1 -0
- data/lib/zip/extra_field.rb +1 -1
- data/lib/zip/extra_field/generic.rb +1 -1
- data/lib/zip/extra_field/universal_time.rb +39 -12
- data/lib/zip/file.rb +67 -33
- data/lib/zip/inflater.rb +1 -1
- data/lib/zip/input_stream.rb +1 -1
- data/lib/zip/streamable_stream.rb +1 -6
- data/lib/zip/version.rb +1 -1
- metadata +11 -153
- 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/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 -134
- 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
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7befb1c4855935534788418759d90641e37bd31c53428b5ba04c6c8c4bc4a544
|
4
|
+
data.tar.gz: 9b5669fc4b3c8a03cc39c73c7ae0e26ece01a2e51a401274f737a43798592b5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a537f87d0051073f2a31ced8f732d0b3b5c7376e792d02d3c1a52b597133f0f4be16b6c2c2564624104b179e501b7016ec6fecdde3681709d9730b5fb124dc72
|
7
|
+
data.tar.gz: 37ed030e2ffbb243bc639e969d050d21836448f746c1d47a49b8f77417b286438bee60dd80a6ba1e333642db218a56d32908ccbce4b3b6873082c42a709c6c77
|
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,7 +1,6 @@
|
|
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'
|
@@ -42,7 +41,8 @@ module Zip
|
|
42
41
|
:write_zip64_support,
|
43
42
|
:warn_invalid_date,
|
44
43
|
:case_insensitive_match,
|
45
|
-
:force_entry_names_encoding
|
44
|
+
:force_entry_names_encoding,
|
45
|
+
:validate_entry_sizes
|
46
46
|
|
47
47
|
def reset!
|
48
48
|
@_ran_once = false
|
@@ -54,6 +54,7 @@ module Zip
|
|
54
54
|
@write_zip64_support = false
|
55
55
|
@warn_invalid_date = true
|
56
56
|
@case_insensitive_match = false
|
57
|
+
@validate_entry_sizes = true
|
57
58
|
end
|
58
59
|
|
59
60
|
def setup
|
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
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'pathname'
|
1
2
|
module Zip
|
2
3
|
class Entry
|
3
4
|
STORED = 0
|
@@ -33,7 +34,7 @@ module Zip
|
|
33
34
|
end
|
34
35
|
@follow_symlinks = false
|
35
36
|
|
36
|
-
@restore_times =
|
37
|
+
@restore_times = false
|
37
38
|
@restore_permissions = false
|
38
39
|
@restore_ownership = false
|
39
40
|
# BUG: need an extra field to support uid/gid's
|
@@ -117,7 +118,7 @@ module Zip
|
|
117
118
|
return false unless cleanpath.relative?
|
118
119
|
root = ::File::SEPARATOR
|
119
120
|
naive_expanded_path = ::File.join(root, cleanpath.to_s)
|
120
|
-
|
121
|
+
::File.absolute_path(cleanpath.to_s, root) == naive_expanded_path
|
121
122
|
end
|
122
123
|
|
123
124
|
def local_entry_offset #:nodoc:all
|
@@ -162,7 +163,7 @@ module Zip
|
|
162
163
|
# is passed.
|
163
164
|
def extract(dest_path = nil, &block)
|
164
165
|
if dest_path.nil? && !name_safe?
|
165
|
-
|
166
|
+
warn "WARNING: skipped '#{@name}' as unsafe."
|
166
167
|
return self
|
167
168
|
end
|
168
169
|
|
@@ -275,10 +276,10 @@ module Zip
|
|
275
276
|
zip64 = @extra['Zip64']
|
276
277
|
[::Zip::LOCAL_ENTRY_SIGNATURE,
|
277
278
|
@version_needed_to_extract, # version needed to extract
|
278
|
-
@gp_flags, # @gp_flags
|
279
|
+
@gp_flags, # @gp_flags
|
279
280
|
@compression_method,
|
280
|
-
@time.to_binary_dos_time, # @last_mod_time
|
281
|
-
@time.to_binary_dos_date, # @last_mod_date
|
281
|
+
@time.to_binary_dos_time, # @last_mod_time
|
282
|
+
@time.to_binary_dos_date, # @last_mod_date
|
282
283
|
@crc,
|
283
284
|
zip64 && zip64.compressed_size ? 0xFFFFFFFF : @compressed_size,
|
284
285
|
zip64 && zip64.original_size ? 0xFFFFFFFF : @size,
|
@@ -405,16 +406,20 @@ module Zip
|
|
405
406
|
@unix_uid = stat.uid
|
406
407
|
@unix_gid = stat.gid
|
407
408
|
@unix_perms = stat.mode & 0o7777
|
409
|
+
@time = ::Zip::DOSTime.from_time(stat.mtime)
|
408
410
|
end
|
409
411
|
|
410
|
-
def
|
411
|
-
# BUG: does not update timestamps into account
|
412
|
+
def set_unix_attributes_on_path(dest_path)
|
412
413
|
# ignore setuid/setgid bits by default. honor if @restore_ownership
|
413
414
|
unix_perms_mask = 0o1777
|
414
415
|
unix_perms_mask = 0o7777 if @restore_ownership
|
415
416
|
::FileUtils.chmod(@unix_perms & unix_perms_mask, dest_path) if @restore_permissions && @unix_perms
|
416
417
|
::FileUtils.chown(@unix_uid, @unix_gid, dest_path) if @restore_ownership && @unix_uid && @unix_gid && ::Process.egid == 0
|
417
|
-
|
418
|
+
|
419
|
+
# Restore the timestamp on a file. This will either have come from the
|
420
|
+
# original source file that was copied into the archive, or from the
|
421
|
+
# creation date of the archive if there was no original source file.
|
422
|
+
::FileUtils.touch(dest_path, mtime: time) if @restore_times
|
418
423
|
end
|
419
424
|
|
420
425
|
def set_extra_attributes_on_path(dest_path) # :nodoc:
|
@@ -422,7 +427,7 @@ module Zip
|
|
422
427
|
|
423
428
|
case @fstype
|
424
429
|
when ::Zip::FSTYPE_UNIX
|
425
|
-
|
430
|
+
set_unix_attributes_on_path(dest_path)
|
426
431
|
end
|
427
432
|
end
|
428
433
|
|
@@ -432,11 +437,11 @@ module Zip
|
|
432
437
|
@header_signature,
|
433
438
|
@version, # version of encoding software
|
434
439
|
@fstype, # filesystem type
|
435
|
-
@version_needed_to_extract, # @versionNeededToExtract
|
436
|
-
@gp_flags, # @gp_flags
|
440
|
+
@version_needed_to_extract, # @versionNeededToExtract
|
441
|
+
@gp_flags, # @gp_flags
|
437
442
|
@compression_method,
|
438
|
-
@time.to_binary_dos_time, # @last_mod_time
|
439
|
-
@time.to_binary_dos_date, # @last_mod_date
|
443
|
+
@time.to_binary_dos_time, # @last_mod_time
|
444
|
+
@time.to_binary_dos_date, # @last_mod_date
|
440
445
|
@crc,
|
441
446
|
zip64 && zip64.compressed_size ? 0xFFFFFFFF : @compressed_size,
|
442
447
|
zip64 && zip64.original_size ? 0xFFFFFFFF : @size,
|
@@ -590,7 +595,7 @@ module Zip
|
|
590
595
|
def set_time(binary_dos_date, binary_dos_time)
|
591
596
|
@time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
|
592
597
|
rescue ArgumentError
|
593
|
-
warn '
|
598
|
+
warn 'WARNING: invalid date/time in zip entry.' if ::Zip.warn_invalid_date
|
594
599
|
end
|
595
600
|
|
596
601
|
def create_file(dest_path, _continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
|
@@ -600,14 +605,26 @@ module Zip
|
|
600
605
|
end
|
601
606
|
::File.open(dest_path, 'wb') do |os|
|
602
607
|
get_input_stream do |is|
|
603
|
-
|
604
|
-
|
605
|
-
buf = ''
|
608
|
+
bytes_written = 0
|
609
|
+
warned = false
|
610
|
+
buf = ''.dup
|
606
611
|
while (buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf))
|
607
612
|
os << buf
|
613
|
+
bytes_written += buf.bytesize
|
614
|
+
if bytes_written > size && !warned
|
615
|
+
message = "entry '#{name}' should be #{size}B, but is larger when inflated."
|
616
|
+
if ::Zip.validate_entry_sizes
|
617
|
+
raise ::Zip::EntrySizeError, message
|
618
|
+
else
|
619
|
+
warn "WARNING: #{message}"
|
620
|
+
warned = true
|
621
|
+
end
|
622
|
+
end
|
608
623
|
end
|
609
624
|
end
|
610
625
|
end
|
626
|
+
|
627
|
+
set_extra_attributes_on_path(dest_path)
|
611
628
|
end
|
612
629
|
|
613
630
|
def create_directory(dest_path)
|
@@ -629,7 +646,7 @@ module Zip
|
|
629
646
|
def create_symlink(dest_path)
|
630
647
|
# TODO: Symlinks pose security challenges. Symlink support temporarily
|
631
648
|
# removed in view of https://github.com/rubyzip/rubyzip/issues/369 .
|
632
|
-
|
649
|
+
warn "WARNING: skipped symlink '#{dest_path}'."
|
633
650
|
end
|
634
651
|
|
635
652
|
# apply missing data from the zip64 extra information field, if present
|
data/lib/zip/errors.rb
CHANGED
data/lib/zip/extra_field.rb
CHANGED
@@ -16,7 +16,7 @@ module Zip
|
|
16
16
|
# If nil, start with empty.
|
17
17
|
return false
|
18
18
|
elsif binstr[0, 2] != self.class.const_get(:HEADER_ID)
|
19
|
-
|
19
|
+
warn 'WARNING: weird extra field header ID. Skip parsing it.'
|
20
20
|
return false
|
21
21
|
end
|
22
22
|
[binstr[2, 2].unpack('v')[0], binstr[4..-1]]
|
@@ -4,24 +4,51 @@ module Zip
|
|
4
4
|
HEADER_ID = 'UT'
|
5
5
|
register_map
|
6
6
|
|
7
|
+
ATIME_MASK = 0b010
|
8
|
+
CTIME_MASK = 0b100
|
9
|
+
MTIME_MASK = 0b001
|
10
|
+
|
7
11
|
def initialize(binstr = nil)
|
8
12
|
@ctime = nil
|
9
13
|
@mtime = nil
|
10
14
|
@atime = nil
|
11
|
-
@flag =
|
12
|
-
|
15
|
+
@flag = 0
|
16
|
+
|
17
|
+
merge(binstr) unless binstr.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :atime, :ctime, :mtime, :flag
|
21
|
+
|
22
|
+
def atime=(time)
|
23
|
+
@flag = time.nil? ? @flag & ~ATIME_MASK : @flag | ATIME_MASK
|
24
|
+
@atime = time
|
13
25
|
end
|
14
26
|
|
15
|
-
|
27
|
+
def ctime=(time)
|
28
|
+
@flag = time.nil? ? @flag & ~CTIME_MASK : @flag | CTIME_MASK
|
29
|
+
@ctime = time
|
30
|
+
end
|
31
|
+
|
32
|
+
def mtime=(time)
|
33
|
+
@flag = time.nil? ? @flag & ~MTIME_MASK : @flag | MTIME_MASK
|
34
|
+
@mtime = time
|
35
|
+
end
|
16
36
|
|
17
37
|
def merge(binstr)
|
18
38
|
return if binstr.empty?
|
39
|
+
|
19
40
|
size, content = initial_parse(binstr)
|
20
|
-
size ||
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
41
|
+
return if !size || size <= 0
|
42
|
+
|
43
|
+
@flag, *times = content.unpack('Cl<l<l<')
|
44
|
+
|
45
|
+
# Parse the timestamps, in order, based on which flags are set.
|
46
|
+
return if times[0].nil?
|
47
|
+
@mtime ||= ::Zip::DOSTime.at(times.shift) unless @flag & MTIME_MASK == 0
|
48
|
+
return if times[0].nil?
|
49
|
+
@atime ||= ::Zip::DOSTime.at(times.shift) unless @flag & ATIME_MASK == 0
|
50
|
+
return if times[0].nil?
|
51
|
+
@ctime ||= ::Zip::DOSTime.at(times.shift) unless @flag & CTIME_MASK == 0
|
25
52
|
end
|
26
53
|
|
27
54
|
def ==(other)
|
@@ -32,15 +59,15 @@ module Zip
|
|
32
59
|
|
33
60
|
def pack_for_local
|
34
61
|
s = [@flag].pack('C')
|
35
|
-
|
36
|
-
|
37
|
-
|
62
|
+
s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
|
63
|
+
s << [@atime.to_i].pack('l<') unless @flag & ATIME_MASK == 0
|
64
|
+
s << [@ctime.to_i].pack('l<') unless @flag & CTIME_MASK == 0
|
38
65
|
s
|
39
66
|
end
|
40
67
|
|
41
68
|
def pack_for_c_dir
|
42
69
|
s = [@flag].pack('C')
|
43
|
-
|
70
|
+
s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
|
44
71
|
s
|
45
72
|
end
|
46
73
|
end
|