rubyzip 3.0.0.alpha → 3.0.0.rc2
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 +4 -4
- data/Changelog.md +53 -0
- data/LICENSE.md +24 -0
- data/README.md +37 -12
- data/Rakefile +1 -1
- data/lib/zip/central_directory.rb +10 -10
- data/lib/zip/constants.rb +4 -0
- data/lib/zip/crypto/decrypted_io.rb +1 -1
- data/lib/zip/crypto/null_encryption.rb +1 -1
- data/lib/zip/crypto/traditional_encryption.rb +3 -3
- data/lib/zip/dos_time.rb +11 -1
- data/lib/zip/entry.rb +97 -59
- data/lib/zip/entry_set.rb +2 -2
- data/lib/zip/errors.rb +24 -3
- data/lib/zip/extra_field/generic.rb +3 -3
- data/lib/zip/extra_field/ntfs.rb +2 -2
- data/lib/zip/extra_field.rb +2 -2
- data/lib/zip/file.rb +38 -15
- data/lib/zip/file_split.rb +1 -7
- data/lib/zip/filesystem/dir.rb +2 -2
- data/lib/zip/filesystem/zip_file_name_mapper.rb +1 -1
- data/lib/zip/filesystem.rb +1 -1
- data/lib/zip/input_stream.rb +13 -18
- data/lib/zip/ioextras/abstract_input_stream.rb +2 -2
- data/lib/zip/ioextras.rb +1 -1
- data/lib/zip/output_stream.rb +8 -8
- data/lib/zip/version.rb +1 -1
- data/lib/zip.rb +4 -3
- data/rubyzip.gemspec +16 -15
- data/samples/example_filesystem.rb +1 -1
- data/samples/write_simple.rb +1 -1
- metadata +23 -21
data/lib/zip/entry.rb
CHANGED
@@ -9,16 +9,19 @@ module Zip
|
|
9
9
|
class Entry
|
10
10
|
include Dirtyable
|
11
11
|
|
12
|
+
# Constant used to specify that the entry is stored (i.e., not compressed).
|
12
13
|
STORED = ::Zip::COMPRESSION_METHOD_STORE
|
14
|
+
|
15
|
+
# Constant used to specify that the entry is deflated (i.e., compressed).
|
13
16
|
DEFLATED = ::Zip::COMPRESSION_METHOD_DEFLATE
|
14
17
|
|
15
18
|
# Language encoding flag (EFS) bit
|
16
|
-
EFS = 0b100000000000
|
19
|
+
EFS = 0b100000000000 # :nodoc:
|
17
20
|
|
18
21
|
# Compression level flags (used as part of the gp flags).
|
19
|
-
COMPRESSION_LEVEL_SUPERFAST_GPFLAG = 0b110
|
20
|
-
COMPRESSION_LEVEL_FAST_GPFLAG = 0b100
|
21
|
-
COMPRESSION_LEVEL_MAX_GPFLAG = 0b010
|
22
|
+
COMPRESSION_LEVEL_SUPERFAST_GPFLAG = 0b110 # :nodoc:
|
23
|
+
COMPRESSION_LEVEL_FAST_GPFLAG = 0b100 # :nodoc:
|
24
|
+
COMPRESSION_LEVEL_MAX_GPFLAG = 0b010 # :nodoc:
|
22
25
|
|
23
26
|
attr_accessor :comment, :compressed_size, :follow_symlinks, :name,
|
24
27
|
:restore_ownership, :restore_permissions, :restore_times,
|
@@ -35,7 +38,7 @@ module Zip
|
|
35
38
|
:fstype=, :gp_flags=, :name=, :size=,
|
36
39
|
:unix_gid=, :unix_perms=, :unix_uid=
|
37
40
|
|
38
|
-
def set_default_vars_values
|
41
|
+
def set_default_vars_values # :nodoc:
|
39
42
|
@local_header_offset = 0
|
40
43
|
@local_header_size = nil # not known until local entry is created or read
|
41
44
|
@internal_file_attributes = 1
|
@@ -63,11 +66,12 @@ module Zip
|
|
63
66
|
@unix_perms = nil
|
64
67
|
end
|
65
68
|
|
66
|
-
def check_name(name)
|
69
|
+
def check_name(name) # :nodoc:
|
67
70
|
raise EntryNameError, name if name.start_with?('/')
|
68
71
|
raise EntryNameError if name.length > 65_535
|
69
72
|
end
|
70
73
|
|
74
|
+
# Create a new Zip::Entry.
|
71
75
|
def initialize(
|
72
76
|
zipfile = '', name = '',
|
73
77
|
comment: '', size: nil, compressed_size: 0, crc: 0,
|
@@ -103,18 +107,23 @@ module Zip
|
|
103
107
|
set_compression_level_flags
|
104
108
|
end
|
105
109
|
|
110
|
+
# Is this entry encrypted?
|
106
111
|
def encrypted?
|
107
112
|
gp_flags & 1 == 1
|
108
113
|
end
|
109
114
|
|
110
|
-
def incomplete?
|
111
|
-
gp_flags & 8 == 8
|
115
|
+
def incomplete? # :nodoc:
|
116
|
+
(gp_flags & 8 == 8) && (crc == 0 || size == 0 || compressed_size == 0)
|
112
117
|
end
|
113
118
|
|
119
|
+
# The uncompressed size of the entry.
|
114
120
|
def size
|
115
121
|
@size || 0
|
116
122
|
end
|
117
123
|
|
124
|
+
# Get a timestamp component of this entry.
|
125
|
+
#
|
126
|
+
# Returns modification time by default.
|
118
127
|
def time(component: :mtime)
|
119
128
|
time =
|
120
129
|
if @extra['UniversalTime']
|
@@ -130,14 +139,19 @@ module Zip
|
|
130
139
|
|
131
140
|
alias mtime time
|
132
141
|
|
142
|
+
# Get the last access time of this entry, if available.
|
133
143
|
def atime
|
134
144
|
time(component: :atime)
|
135
145
|
end
|
136
146
|
|
147
|
+
# Get the creation time of this entry, if available.
|
137
148
|
def ctime
|
138
149
|
time(component: :ctime)
|
139
150
|
end
|
140
151
|
|
152
|
+
# Set a timestamp component of this entry.
|
153
|
+
#
|
154
|
+
# Sets modification time by default.
|
141
155
|
def time=(value, component: :mtime)
|
142
156
|
@dirty = true
|
143
157
|
unless @extra.member?('UniversalTime') || @extra.member?('NTFS')
|
@@ -152,30 +166,43 @@ module Zip
|
|
152
166
|
|
153
167
|
alias mtime= time=
|
154
168
|
|
169
|
+
# Set the last access time of this entry.
|
155
170
|
def atime=(value)
|
156
171
|
send(:time=, value, component: :atime)
|
157
172
|
end
|
158
173
|
|
174
|
+
# Set the creation time of this entry.
|
159
175
|
def ctime=(value)
|
160
176
|
send(:time=, value, component: :ctime)
|
161
177
|
end
|
162
178
|
|
179
|
+
# Does this entry return time fields with accurate timezone information?
|
180
|
+
def absolute_time?
|
181
|
+
@extra.member?('UniversalTime') || @extra.member?('NTFS')
|
182
|
+
end
|
183
|
+
|
184
|
+
# Return the compression method for this entry.
|
185
|
+
#
|
186
|
+
# Returns STORED if the entry is a directory or if the compression
|
187
|
+
# level is 0.
|
163
188
|
def compression_method
|
164
189
|
return STORED if ftype == :directory || @compression_level == 0
|
165
190
|
|
166
191
|
@compression_method
|
167
192
|
end
|
168
193
|
|
194
|
+
# Set the compression method for this entry.
|
169
195
|
def compression_method=(method)
|
170
196
|
@dirty = true
|
171
197
|
@compression_method = (ftype == :directory ? STORED : method)
|
172
198
|
end
|
173
199
|
|
200
|
+
# Does this entry use the ZIP64 extensions?
|
174
201
|
def zip64?
|
175
202
|
!@extra['Zip64'].nil?
|
176
203
|
end
|
177
204
|
|
178
|
-
def file_type_is?(type)
|
205
|
+
def file_type_is?(type) # :nodoc:
|
179
206
|
ftype == type
|
180
207
|
end
|
181
208
|
|
@@ -185,19 +212,19 @@ module Zip
|
|
185
212
|
|
186
213
|
# Dynamic checkers
|
187
214
|
%w[directory file symlink].each do |k|
|
188
|
-
define_method "#{k}?" do
|
215
|
+
define_method :"#{k}?" do
|
189
216
|
file_type_is?(k.to_sym)
|
190
217
|
end
|
191
218
|
end
|
192
219
|
|
193
|
-
def name_is_directory?
|
220
|
+
def name_is_directory? # :nodoc:
|
194
221
|
@name.end_with?('/')
|
195
222
|
end
|
196
223
|
|
197
224
|
# Is the name a relative path, free of `..` patterns that could lead to
|
198
225
|
# path traversal attacks? This does NOT handle symlinks; if the path
|
199
226
|
# contains symlinks, this check is NOT enough to guarantee safety.
|
200
|
-
def name_safe?
|
227
|
+
def name_safe? # :nodoc:
|
201
228
|
cleanpath = Pathname.new(@name).cleanpath
|
202
229
|
return false unless cleanpath.relative?
|
203
230
|
|
@@ -207,29 +234,29 @@ module Zip
|
|
207
234
|
::File.absolute_path(cleanpath.to_s, root).match?(/([A-Z]:)?#{naive}/i)
|
208
235
|
end
|
209
236
|
|
210
|
-
def local_entry_offset
|
237
|
+
def local_entry_offset # :nodoc:
|
211
238
|
local_header_offset + @local_header_size
|
212
239
|
end
|
213
240
|
|
214
|
-
def name_size
|
241
|
+
def name_size # :nodoc:
|
215
242
|
@name ? @name.bytesize : 0
|
216
243
|
end
|
217
244
|
|
218
|
-
def extra_size
|
245
|
+
def extra_size # :nodoc:
|
219
246
|
@extra ? @extra.local_size : 0
|
220
247
|
end
|
221
248
|
|
222
|
-
def comment_size
|
249
|
+
def comment_size # :nodoc:
|
223
250
|
@comment ? @comment.bytesize : 0
|
224
251
|
end
|
225
252
|
|
226
|
-
def calculate_local_header_size
|
253
|
+
def calculate_local_header_size # :nodoc:
|
227
254
|
LOCAL_ENTRY_STATIC_HEADER_LENGTH + name_size + extra_size
|
228
255
|
end
|
229
256
|
|
230
257
|
# check before rewriting an entry (after file sizes are known)
|
231
258
|
# that we didn't change the header size (and thus clobber file data or something)
|
232
|
-
def verify_local_header_size!
|
259
|
+
def verify_local_header_size! # :nodoc:
|
233
260
|
return if @local_header_size.nil?
|
234
261
|
|
235
262
|
new_size = calculate_local_header_size
|
@@ -239,12 +266,12 @@ module Zip
|
|
239
266
|
"Local header size changed (#{@local_header_size} -> #{new_size})"
|
240
267
|
end
|
241
268
|
|
242
|
-
def cdir_header_size
|
269
|
+
def cdir_header_size # :nodoc:
|
243
270
|
CDIR_ENTRY_STATIC_HEADER_LENGTH + name_size +
|
244
271
|
(@extra ? @extra.c_dir_size : 0) + comment_size
|
245
272
|
end
|
246
273
|
|
247
|
-
def next_header_offset
|
274
|
+
def next_header_offset # :nodoc:
|
248
275
|
local_entry_offset + compressed_size
|
249
276
|
end
|
250
277
|
|
@@ -266,16 +293,16 @@ module Zip
|
|
266
293
|
|
267
294
|
raise "unknown file type #{inspect}" unless directory? || file? || symlink?
|
268
295
|
|
269
|
-
__send__("create_#{ftype}", extract_path, &block)
|
296
|
+
__send__(:"create_#{ftype}", extract_path, &block)
|
270
297
|
self
|
271
298
|
end
|
272
299
|
|
273
|
-
def to_s
|
300
|
+
def to_s # :nodoc:
|
274
301
|
@name
|
275
302
|
end
|
276
303
|
|
277
304
|
class << self
|
278
|
-
def read_c_dir_entry(io)
|
305
|
+
def read_c_dir_entry(io) # :nodoc:
|
279
306
|
path = if io.respond_to?(:path)
|
280
307
|
io.path
|
281
308
|
else
|
@@ -288,7 +315,7 @@ module Zip
|
|
288
315
|
nil
|
289
316
|
end
|
290
317
|
|
291
|
-
def read_local_entry(io)
|
318
|
+
def read_local_entry(io) # :nodoc:
|
292
319
|
entry = new(io)
|
293
320
|
entry.read_local_entry(io)
|
294
321
|
entry
|
@@ -299,7 +326,7 @@ module Zip
|
|
299
326
|
end
|
300
327
|
end
|
301
328
|
|
302
|
-
def unpack_local_entry(buf)
|
329
|
+
def unpack_local_entry(buf) # :nodoc:
|
303
330
|
@header_signature,
|
304
331
|
@version,
|
305
332
|
@fstype,
|
@@ -314,26 +341,27 @@ module Zip
|
|
314
341
|
@extra_length = buf.unpack('VCCvvvvVVVvv')
|
315
342
|
end
|
316
343
|
|
317
|
-
def read_local_entry(io)
|
344
|
+
def read_local_entry(io) # :nodoc:
|
318
345
|
@dirty = false # No changes at this point.
|
319
|
-
|
346
|
+
current_offset = io.tell
|
320
347
|
|
321
|
-
|
348
|
+
read_local_header_fields(io)
|
322
349
|
|
323
|
-
|
324
|
-
raise
|
325
|
-
end
|
350
|
+
if @header_signature == SPLIT_FILE_SIGNATURE
|
351
|
+
raise SplitArchiveError if current_offset.zero?
|
326
352
|
|
327
|
-
|
353
|
+
# Rewind, skipping the data descriptor, then try to read the local header again.
|
354
|
+
current_offset += 16
|
355
|
+
io.seek(current_offset)
|
356
|
+
read_local_header_fields(io)
|
357
|
+
end
|
328
358
|
|
329
359
|
unless @header_signature == LOCAL_ENTRY_SIGNATURE
|
330
|
-
|
331
|
-
raise SplitArchiveError
|
332
|
-
end
|
333
|
-
|
334
|
-
raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
|
360
|
+
raise Error, "Zip local header magic not found at location '#{current_offset}'"
|
335
361
|
end
|
336
362
|
|
363
|
+
@local_header_offset = current_offset
|
364
|
+
|
337
365
|
set_time(@last_mod_date, @last_mod_time)
|
338
366
|
|
339
367
|
@name = io.read(@name_length)
|
@@ -356,7 +384,7 @@ module Zip
|
|
356
384
|
@local_header_size = calculate_local_header_size
|
357
385
|
end
|
358
386
|
|
359
|
-
def pack_local_entry
|
387
|
+
def pack_local_entry # :nodoc:
|
360
388
|
zip64 = @extra['Zip64']
|
361
389
|
[::Zip::LOCAL_ENTRY_SIGNATURE,
|
362
390
|
@version_needed_to_extract, # version needed to extract
|
@@ -371,7 +399,7 @@ module Zip
|
|
371
399
|
@extra ? @extra.local_size : 0].pack('VvvvvvVVVvv')
|
372
400
|
end
|
373
401
|
|
374
|
-
def write_local_entry(io, rewrite: false)
|
402
|
+
def write_local_entry(io, rewrite: false) # :nodoc:
|
375
403
|
prep_local_zip64_extra
|
376
404
|
verify_local_header_size! if rewrite
|
377
405
|
@local_header_offset = io.tell
|
@@ -383,7 +411,7 @@ module Zip
|
|
383
411
|
@local_header_size = io.tell - @local_header_offset
|
384
412
|
end
|
385
413
|
|
386
|
-
def unpack_c_dir_entry(buf)
|
414
|
+
def unpack_c_dir_entry(buf) # :nodoc:
|
387
415
|
@header_signature,
|
388
416
|
@version, # version of encoding software
|
389
417
|
@fstype, # filesystem type
|
@@ -407,7 +435,7 @@ module Zip
|
|
407
435
|
@comment = buf.unpack('VCCvvvvvVVVvvvvvVV')
|
408
436
|
end
|
409
437
|
|
410
|
-
def set_ftype_from_c_dir_entry
|
438
|
+
def set_ftype_from_c_dir_entry # :nodoc:
|
411
439
|
@ftype = case @fstype
|
412
440
|
when ::Zip::FSTYPE_UNIX
|
413
441
|
@unix_perms = (@external_file_attributes >> 16) & 0o7777
|
@@ -437,25 +465,25 @@ module Zip
|
|
437
465
|
end
|
438
466
|
end
|
439
467
|
|
440
|
-
def check_c_dir_entry_static_header_length(buf)
|
468
|
+
def check_c_dir_entry_static_header_length(buf) # :nodoc:
|
441
469
|
return unless buf.nil? || buf.bytesize != ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
|
442
470
|
|
443
471
|
raise Error, 'Premature end of file. Not enough data for zip cdir entry header'
|
444
472
|
end
|
445
473
|
|
446
|
-
def check_c_dir_entry_signature
|
474
|
+
def check_c_dir_entry_signature # :nodoc:
|
447
475
|
return if @header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
|
448
476
|
|
449
477
|
raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
|
450
478
|
end
|
451
479
|
|
452
|
-
def check_c_dir_entry_comment_size
|
480
|
+
def check_c_dir_entry_comment_size # :nodoc:
|
453
481
|
return if @comment && @comment.bytesize == @comment_length
|
454
482
|
|
455
483
|
raise ::Zip::Error, 'Truncated cdir zip entry header'
|
456
484
|
end
|
457
485
|
|
458
|
-
def read_extra_field(buf, local: false)
|
486
|
+
def read_extra_field(buf, local: false) # :nodoc:
|
459
487
|
if @extra.kind_of?(::Zip::ExtraField)
|
460
488
|
@extra.merge(buf, local: local) if buf
|
461
489
|
else
|
@@ -463,7 +491,7 @@ module Zip
|
|
463
491
|
end
|
464
492
|
end
|
465
493
|
|
466
|
-
def read_c_dir_entry(io)
|
494
|
+
def read_c_dir_entry(io) # :nodoc:
|
467
495
|
@dirty = false # No changes at this point.
|
468
496
|
static_sized_fields_buf = io.read(::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH)
|
469
497
|
check_c_dir_entry_static_header_length(static_sized_fields_buf)
|
@@ -503,7 +531,7 @@ module Zip
|
|
503
531
|
end
|
504
532
|
|
505
533
|
# rubocop:disable Style/GuardClause
|
506
|
-
def set_unix_attributes_on_path(dest_path)
|
534
|
+
def set_unix_attributes_on_path(dest_path) # :nodoc:
|
507
535
|
# Ignore setuid/setgid bits by default. Honour if @restore_ownership.
|
508
536
|
unix_perms_mask = (@restore_ownership ? 0o7777 : 0o1777)
|
509
537
|
if @restore_permissions && @unix_perms
|
@@ -529,7 +557,7 @@ module Zip
|
|
529
557
|
::FileUtils.touch(dest_path, mtime: time) if @restore_times
|
530
558
|
end
|
531
559
|
|
532
|
-
def pack_c_dir_entry
|
560
|
+
def pack_c_dir_entry # :nodoc:
|
533
561
|
zip64 = @extra['Zip64']
|
534
562
|
[
|
535
563
|
@header_signature,
|
@@ -556,7 +584,7 @@ module Zip
|
|
556
584
|
].pack('VCCvvvvvVVVvvvvvVV')
|
557
585
|
end
|
558
586
|
|
559
|
-
def write_c_dir_entry(io)
|
587
|
+
def write_c_dir_entry(io) # :nodoc:
|
560
588
|
prep_cdir_zip64_extra
|
561
589
|
|
562
590
|
case @fstype
|
@@ -574,7 +602,7 @@ module Zip
|
|
574
602
|
end
|
575
603
|
|
576
604
|
unless ft.nil?
|
577
|
-
@external_file_attributes = (ft << 12 | (@unix_perms & 0o7777)) << 16
|
605
|
+
@external_file_attributes = ((ft << 12) | (@unix_perms & 0o7777)) << 16
|
578
606
|
end
|
579
607
|
end
|
580
608
|
|
@@ -585,7 +613,7 @@ module Zip
|
|
585
613
|
io << @comment
|
586
614
|
end
|
587
615
|
|
588
|
-
def ==(other)
|
616
|
+
def ==(other) # :nodoc:
|
589
617
|
return false unless other.class == self.class
|
590
618
|
|
591
619
|
# Compares contents of local entry and exposed fields
|
@@ -594,7 +622,7 @@ module Zip
|
|
594
622
|
end
|
595
623
|
end
|
596
624
|
|
597
|
-
def <=>(other)
|
625
|
+
def <=>(other) # :nodoc:
|
598
626
|
to_s <=> other.to_s
|
599
627
|
end
|
600
628
|
|
@@ -639,7 +667,7 @@ module Zip
|
|
639
667
|
if name_is_directory?
|
640
668
|
raise ArgumentError,
|
641
669
|
"entry name '#{newEntry}' indicates directory entry, but " \
|
642
|
-
|
670
|
+
"'#{src_path}' is not a directory"
|
643
671
|
end
|
644
672
|
:file
|
645
673
|
when 'directory'
|
@@ -649,7 +677,7 @@ module Zip
|
|
649
677
|
if name_is_directory?
|
650
678
|
raise ArgumentError,
|
651
679
|
"entry name '#{newEntry}' indicates directory entry, but " \
|
652
|
-
|
680
|
+
"'#{src_path}' is not a directory"
|
653
681
|
end
|
654
682
|
:symlink
|
655
683
|
else
|
@@ -661,7 +689,7 @@ module Zip
|
|
661
689
|
get_extra_attributes_from_path(@filepath)
|
662
690
|
end
|
663
691
|
|
664
|
-
def write_to_zip_output_stream(zip_output_stream)
|
692
|
+
def write_to_zip_output_stream(zip_output_stream) # :nodoc:
|
665
693
|
if ftype == :directory
|
666
694
|
zip_output_stream.put_next_entry(self)
|
667
695
|
elsif @filepath
|
@@ -674,13 +702,13 @@ module Zip
|
|
674
702
|
end
|
675
703
|
end
|
676
704
|
|
677
|
-
def parent_as_string
|
705
|
+
def parent_as_string # :nodoc:
|
678
706
|
entry_name = name.chomp('/')
|
679
707
|
slash_index = entry_name.rindex('/')
|
680
708
|
slash_index ? entry_name.slice(0, slash_index + 1) : nil
|
681
709
|
end
|
682
710
|
|
683
|
-
def get_raw_input_stream(&block)
|
711
|
+
def get_raw_input_stream(&block) # :nodoc:
|
684
712
|
if @zipfile.respond_to?(:seek) && @zipfile.respond_to?(:read)
|
685
713
|
yield @zipfile
|
686
714
|
else
|
@@ -688,12 +716,22 @@ module Zip
|
|
688
716
|
end
|
689
717
|
end
|
690
718
|
|
691
|
-
def clean_up
|
719
|
+
def clean_up # :nodoc:
|
692
720
|
@dirty = false # Any changes are written at this point.
|
693
721
|
end
|
694
722
|
|
695
723
|
private
|
696
724
|
|
725
|
+
def read_local_header_fields(io) # :nodoc:
|
726
|
+
static_sized_fields_buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH) || ''
|
727
|
+
|
728
|
+
unless static_sized_fields_buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
|
729
|
+
raise Error, 'Premature end of file. Not enough data for zip entry local header'
|
730
|
+
end
|
731
|
+
|
732
|
+
unpack_local_entry(static_sized_fields_buf)
|
733
|
+
end
|
734
|
+
|
697
735
|
def set_time(binary_dos_date, binary_dos_time)
|
698
736
|
@time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
|
699
737
|
rescue ArgumentError
|
@@ -749,7 +787,7 @@ module Zip
|
|
749
787
|
|
750
788
|
# apply missing data from the zip64 extra information field, if present
|
751
789
|
# (required when file sizes exceed 2**32, but can be used for all files)
|
752
|
-
def parse_zip64_extra(for_local_header)
|
790
|
+
def parse_zip64_extra(for_local_header) # :nodoc:
|
753
791
|
return unless zip64?
|
754
792
|
|
755
793
|
if for_local_header
|
data/lib/zip/entry_set.rb
CHANGED
@@ -61,12 +61,12 @@ module Zip
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def glob(pattern, flags = ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH | ::File::FNM_EXTGLOB)
|
64
|
-
entries.
|
64
|
+
entries.filter_map do |entry|
|
65
65
|
next nil unless ::File.fnmatch(pattern, entry.name.chomp('/'), flags)
|
66
66
|
|
67
67
|
yield(entry) if block_given?
|
68
68
|
entry
|
69
|
-
end
|
69
|
+
end
|
70
70
|
end
|
71
71
|
|
72
72
|
protected
|
data/lib/zip/errors.rb
CHANGED
@@ -7,13 +7,17 @@ module Zip
|
|
7
7
|
|
8
8
|
# Error raised if an unsupported compression method is used.
|
9
9
|
class CompressionMethodError < Error
|
10
|
+
# The compression method that has caused this error.
|
10
11
|
attr_reader :compression_method
|
11
12
|
|
13
|
+
# Create a new CompressionMethodError with the specified incorrect
|
14
|
+
# compression method.
|
12
15
|
def initialize(method)
|
13
16
|
super()
|
14
17
|
@compression_method = method
|
15
18
|
end
|
16
19
|
|
20
|
+
# The message returned by this error.
|
17
21
|
def message
|
18
22
|
"Unsupported compression method: #{COMPRESSION_METHODS[@compression_method]}."
|
19
23
|
end
|
@@ -21,13 +25,17 @@ module Zip
|
|
21
25
|
|
22
26
|
# Error raised if there is a problem while decompressing an archive entry.
|
23
27
|
class DecompressionError < Error
|
28
|
+
# The error from the underlying Zlib library that caused this error.
|
24
29
|
attr_reader :zlib_error
|
25
30
|
|
31
|
+
# Create a new DecompressionError with the specified underlying Zlib
|
32
|
+
# error.
|
26
33
|
def initialize(zlib_error)
|
27
34
|
super()
|
28
35
|
@zlib_error = zlib_error
|
29
36
|
end
|
30
37
|
|
38
|
+
# The message returned by this error.
|
31
39
|
def message
|
32
40
|
"Zlib error ('#{@zlib_error.message}') while inflating."
|
33
41
|
end
|
@@ -36,26 +44,30 @@ module Zip
|
|
36
44
|
# Error raised when trying to extract an archive entry over an
|
37
45
|
# existing file.
|
38
46
|
class DestinationExistsError < Error
|
47
|
+
# Create a new DestinationExistsError with the clashing destination.
|
39
48
|
def initialize(destination)
|
40
49
|
super()
|
41
50
|
@destination = destination
|
42
51
|
end
|
43
52
|
|
53
|
+
# The message returned by this error.
|
44
54
|
def message
|
45
55
|
"Cannot create file or directory '#{@destination}'. " \
|
46
|
-
|
56
|
+
'A file already exists with that name.'
|
47
57
|
end
|
48
58
|
end
|
49
59
|
|
50
60
|
# Error raised when trying to add an entry to an archive where the
|
51
61
|
# entry name already exists.
|
52
62
|
class EntryExistsError < Error
|
63
|
+
# Create a new EntryExistsError with the specified source and name.
|
53
64
|
def initialize(source, name)
|
54
65
|
super()
|
55
66
|
@source = source
|
56
67
|
@name = name
|
57
68
|
end
|
58
69
|
|
70
|
+
# The message returned by this error.
|
59
71
|
def message
|
60
72
|
"'#{@source}' failed. Entry #{@name} already exists."
|
61
73
|
end
|
@@ -63,11 +75,13 @@ module Zip
|
|
63
75
|
|
64
76
|
# Error raised when an entry name is invalid.
|
65
77
|
class EntryNameError < Error
|
78
|
+
# Create a new EntryNameError with the specified name.
|
66
79
|
def initialize(name = nil)
|
67
80
|
super()
|
68
81
|
@name = name
|
69
82
|
end
|
70
83
|
|
84
|
+
# The message returned by this error.
|
71
85
|
def message
|
72
86
|
if @name.nil?
|
73
87
|
'Illegal entry name. Names must have fewer than 65,536 characters.'
|
@@ -80,13 +94,16 @@ module Zip
|
|
80
94
|
# Error raised if an entry is larger on extraction than it is advertised
|
81
95
|
# to be.
|
82
96
|
class EntrySizeError < Error
|
97
|
+
# The entry that has caused this error.
|
83
98
|
attr_reader :entry
|
84
99
|
|
100
|
+
# Create a new EntrySizeError with the specified entry.
|
85
101
|
def initialize(entry)
|
86
102
|
super()
|
87
103
|
@entry = entry
|
88
104
|
end
|
89
105
|
|
106
|
+
# The message returned by this error.
|
90
107
|
def message
|
91
108
|
"Entry '#{@entry.name}' should be #{@entry.size}B, but is larger when inflated."
|
92
109
|
end
|
@@ -95,6 +112,7 @@ module Zip
|
|
95
112
|
# Error raised if a split archive is read. Rubyzip does not support reading
|
96
113
|
# split archives.
|
97
114
|
class SplitArchiveError < Error
|
115
|
+
# The message returned by this error.
|
98
116
|
def message
|
99
117
|
'Rubyzip cannot extract from split archives at this time.'
|
100
118
|
end
|
@@ -102,17 +120,20 @@ module Zip
|
|
102
120
|
|
103
121
|
# Error raised if there is not enough metadata for the entry to be streamed.
|
104
122
|
class StreamingError < Error
|
123
|
+
# The entry that has caused this error.
|
105
124
|
attr_reader :entry
|
106
125
|
|
126
|
+
# Create a new StreamingError with the specified entry.
|
107
127
|
def initialize(entry)
|
108
128
|
super()
|
109
129
|
@entry = entry
|
110
130
|
end
|
111
131
|
|
132
|
+
# The message returned by this error.
|
112
133
|
def message
|
113
134
|
"The local header of this entry ('#{@entry.name}') does not contain " \
|
114
|
-
|
115
|
-
|
135
|
+
'the correct metadata for `Zip::InputStream` to be able to ' \
|
136
|
+
'uncompress it. Please use `Zip::File` instead of `Zip::InputStream`.'
|
116
137
|
end
|
117
138
|
end
|
118
139
|
end
|
@@ -21,17 +21,17 @@ module Zip
|
|
21
21
|
return false
|
22
22
|
end
|
23
23
|
|
24
|
-
[binstr[2, 2].unpack1('v'), binstr[4
|
24
|
+
[binstr[2, 2].unpack1('v'), binstr[4..]]
|
25
25
|
end
|
26
26
|
|
27
27
|
def to_local_bin
|
28
28
|
s = pack_for_local
|
29
|
-
self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
|
29
|
+
(self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v')) << s
|
30
30
|
end
|
31
31
|
|
32
32
|
def to_c_dir_bin
|
33
33
|
s = pack_for_c_dir
|
34
|
-
self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
|
34
|
+
(self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v')) << s
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/zip/extra_field/ntfs.rb
CHANGED
@@ -25,7 +25,7 @@ module Zip
|
|
25
25
|
size, content = initial_parse(binstr)
|
26
26
|
(size && content) || return
|
27
27
|
|
28
|
-
content = content[4
|
28
|
+
content = content[4..]
|
29
29
|
tags = parse_tags(content)
|
30
30
|
|
31
31
|
tag1 = tags[1]
|
@@ -86,7 +86,7 @@ module Zip
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def from_ntfs_time(ntfs_time)
|
89
|
-
::Zip::DOSTime.at(ntfs_time / WINDOWS_TICK - SEC_TO_UNIX_EPOCH)
|
89
|
+
::Zip::DOSTime.at((ntfs_time / WINDOWS_TICK) - SEC_TO_UNIX_EPOCH)
|
90
90
|
end
|
91
91
|
|
92
92
|
def to_ntfs_time(time)
|
data/lib/zip/extra_field.rb
CHANGED
@@ -21,8 +21,8 @@ module Zip
|
|
21
21
|
def extra_field_type_unknown(binstr, len, index, local)
|
22
22
|
self['Unknown'] ||= Unknown.new
|
23
23
|
|
24
|
-
if !len || len + 4 > binstr[index
|
25
|
-
self['Unknown'].merge(binstr[index
|
24
|
+
if !len || len + 4 > binstr[index..].bytesize
|
25
|
+
self['Unknown'].merge(binstr[index..], local: local)
|
26
26
|
return
|
27
27
|
end
|
28
28
|
|