rubyzip 2.0.0 → 2.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e2be8aa3dea85f1e99fa26b5b2530ede874228f35379181d5219eb3864a0e33
4
- data.tar.gz: '0985b8cd0b421a0bdf83953ba907ddad52d236948a81a242f322f0f5fa2145a6'
3
+ metadata.gz: 7befb1c4855935534788418759d90641e37bd31c53428b5ba04c6c8c4bc4a544
4
+ data.tar.gz: 9b5669fc4b3c8a03cc39c73c7ae0e26ece01a2e51a401274f737a43798592b5b
5
5
  SHA512:
6
- metadata.gz: c870bef8352ddb4e706a847f66da596fe556938d1b1422c3541f8ab24aa10bbdb6be577cd031853459101e24a4290aa816436834d1cae66dd26238b451f41d15
7
- data.tar.gz: bb5c8ca7d286346bfad64a6e1bd637cb8a40a99974bc62fbd76ea1a5ee139d16dcf52a8480cc219e48e311d84046feafab2c497cfbeb0721940a06a5c7a163a2
6
+ metadata.gz: a537f87d0051073f2a31ced8f732d0b3b5c7376e792d02d3c1a52b597133f0f4be16b6c2c2564624104b179e501b7016ec6fecdde3681709d9730b5fb124dc72
7
+ data.tar.gz: 37ed030e2ffbb243bc639e969d050d21836448f746c1d47a49b8f77417b286438bee60dd80a6ba1e333642db218a56d32908ccbce4b3b6873082c42a709c6c77
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'
@@ -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
@@ -34,7 +34,7 @@ module Zip
34
34
  end
35
35
  @follow_symlinks = false
36
36
 
37
- @restore_times = true
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
@@ -163,7 +163,7 @@ module Zip
163
163
  # is passed.
164
164
  def extract(dest_path = nil, &block)
165
165
  if dest_path.nil? && !name_safe?
166
- puts "WARNING: skipped #{@name} as unsafe"
166
+ warn "WARNING: skipped '#{@name}' as unsafe."
167
167
  return self
168
168
  end
169
169
 
@@ -406,16 +406,20 @@ module Zip
406
406
  @unix_uid = stat.uid
407
407
  @unix_gid = stat.gid
408
408
  @unix_perms = stat.mode & 0o7777
409
+ @time = ::Zip::DOSTime.from_time(stat.mtime)
409
410
  end
410
411
 
411
- def set_unix_permissions_on_path(dest_path)
412
- # BUG: does not update timestamps into account
412
+ def set_unix_attributes_on_path(dest_path)
413
413
  # ignore setuid/setgid bits by default. honor if @restore_ownership
414
414
  unix_perms_mask = 0o1777
415
415
  unix_perms_mask = 0o7777 if @restore_ownership
416
416
  ::FileUtils.chmod(@unix_perms & unix_perms_mask, dest_path) if @restore_permissions && @unix_perms
417
417
  ::FileUtils.chown(@unix_uid, @unix_gid, dest_path) if @restore_ownership && @unix_uid && @unix_gid && ::Process.egid == 0
418
- # File::utimes()
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
419
423
  end
420
424
 
421
425
  def set_extra_attributes_on_path(dest_path) # :nodoc:
@@ -423,7 +427,7 @@ module Zip
423
427
 
424
428
  case @fstype
425
429
  when ::Zip::FSTYPE_UNIX
426
- set_unix_permissions_on_path(dest_path)
430
+ set_unix_attributes_on_path(dest_path)
427
431
  end
428
432
  end
429
433
 
@@ -591,7 +595,7 @@ module Zip
591
595
  def set_time(binary_dos_date, binary_dos_time)
592
596
  @time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
593
597
  rescue ArgumentError
594
- warn 'Invalid date/time in zip entry' if ::Zip.warn_invalid_date
598
+ warn 'WARNING: invalid date/time in zip entry.' if ::Zip.warn_invalid_date
595
599
  end
596
600
 
597
601
  def create_file(dest_path, _continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
@@ -601,8 +605,6 @@ module Zip
601
605
  end
602
606
  ::File.open(dest_path, 'wb') do |os|
603
607
  get_input_stream do |is|
604
- set_extra_attributes_on_path(dest_path)
605
-
606
608
  bytes_written = 0
607
609
  warned = false
608
610
  buf = ''.dup
@@ -610,17 +612,19 @@ module Zip
610
612
  os << buf
611
613
  bytes_written += buf.bytesize
612
614
  if bytes_written > size && !warned
613
- message = "Entry #{name} should be #{size}B but is larger when inflated"
615
+ message = "entry '#{name}' should be #{size}B, but is larger when inflated."
614
616
  if ::Zip.validate_entry_sizes
615
617
  raise ::Zip::EntrySizeError, message
616
618
  else
617
- puts "WARNING: #{message}"
619
+ warn "WARNING: #{message}"
618
620
  warned = true
619
621
  end
620
622
  end
621
623
  end
622
624
  end
623
625
  end
626
+
627
+ set_extra_attributes_on_path(dest_path)
624
628
  end
625
629
 
626
630
  def create_directory(dest_path)
@@ -642,7 +646,7 @@ module Zip
642
646
  def create_symlink(dest_path)
643
647
  # TODO: Symlinks pose security challenges. Symlink support temporarily
644
648
  # removed in view of https://github.com/rubyzip/rubyzip/issues/369 .
645
- puts "WARNING: skipped symlink #{dest_path}"
649
+ warn "WARNING: skipped symlink '#{dest_path}'."
646
650
  end
647
651
 
648
652
  # apply missing data from the zip64 extra information field, if present
@@ -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
- $stderr.puts 'Warning: weired extra feild header ID. skip parsing'
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 = nil
12
- binstr && merge(binstr)
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
- attr_accessor :atime, :ctime, :mtime, :flag
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 || return
21
- @flag, mtime, atime, ctime = content.unpack('CVVV')
22
- mtime && @mtime ||= ::Zip::DOSTime.at(mtime)
23
- atime && @atime ||= ::Zip::DOSTime.at(atime)
24
- ctime && @ctime ||= ::Zip::DOSTime.at(ctime)
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
- @flag & 1 != 0 && s << [@mtime.to_i].pack('V')
36
- @flag & 2 != 0 && s << [@atime.to_i].pack('V')
37
- @flag & 4 != 0 && s << [@ctime.to_i].pack('V')
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
- @flag & 1 == 1 && s << [@mtime.to_i].pack('V')
70
+ s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
44
71
  s
45
72
  end
46
73
  end
@@ -51,14 +51,23 @@ module Zip
51
51
  DATA_BUFFER_SIZE = 8192
52
52
  IO_METHODS = [:tell, :seek, :read, :close]
53
53
 
54
+ DEFAULT_OPTIONS = {
55
+ restore_ownership: false,
56
+ restore_permissions: false,
57
+ restore_times: false
58
+ }.freeze
59
+
54
60
  attr_reader :name
55
61
 
56
- # default -> false
62
+ # default -> false.
57
63
  attr_accessor :restore_ownership
58
- # default -> false
64
+
65
+ # default -> false, but will be set to true in a future version.
59
66
  attr_accessor :restore_permissions
60
- # default -> true
67
+
68
+ # default -> false, but will be set to true in a future version.
61
69
  attr_accessor :restore_times
70
+
62
71
  # Returns the zip files comment, if it has one
63
72
  attr_accessor :comment
64
73
 
@@ -66,6 +75,7 @@ module Zip
66
75
  # a new archive if it doesn't exist already.
67
76
  def initialize(path_or_io, create = false, buffer = false, options = {})
68
77
  super()
78
+ options = DEFAULT_OPTIONS.merge(options)
69
79
  @name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
70
80
  @comment = ''
71
81
  @create = create ? true : false # allow any truthy value to mean true
@@ -98,17 +108,17 @@ module Zip
98
108
 
99
109
  @stored_entries = @entry_set.dup
100
110
  @stored_comment = @comment
101
- @restore_ownership = options[:restore_ownership] || false
102
- @restore_permissions = options[:restore_permissions] || true
103
- @restore_times = options[:restore_times] || true
111
+ @restore_ownership = options[:restore_ownership]
112
+ @restore_permissions = options[:restore_permissions]
113
+ @restore_times = options[:restore_times]
104
114
  end
105
115
 
106
116
  class << self
107
- # Same as #new. If a block is passed the ZipFile object is passed
108
- # to the block and is automatically closed afterwards just as with
109
- # ruby's builtin File.open method.
110
- def open(file_name, create = false)
111
- zf = ::Zip::File.new(file_name, create)
117
+ # Similar to ::new. If a block is passed the Zip::File object is passed
118
+ # to the block and is automatically closed afterwards, just as with
119
+ # ruby's builtin File::open method.
120
+ def open(file_name, create = false, options = {})
121
+ zf = ::Zip::File.new(file_name, create, false, options)
112
122
  return zf unless block_given?
113
123
  begin
114
124
  yield zf
@@ -366,7 +376,13 @@ module Zip
366
376
  # Searches for entry with the specified name. Returns nil if
367
377
  # no entry is found. See also get_entry
368
378
  def find_entry(entry_name)
369
- @entry_set.find_entry(entry_name)
379
+ selected_entry = @entry_set.find_entry(entry_name)
380
+ return if selected_entry.nil?
381
+
382
+ selected_entry.restore_ownership = @restore_ownership
383
+ selected_entry.restore_permissions = @restore_permissions
384
+ selected_entry.restore_times = @restore_times
385
+ selected_entry
370
386
  end
371
387
 
372
388
  # Searches for entries given a glob
@@ -378,10 +394,8 @@ module Zip
378
394
  # if no entry is found.
379
395
  def get_entry(entry)
380
396
  selected_entry = find_entry(entry)
381
- raise Errno::ENOENT, entry unless selected_entry
382
- selected_entry.restore_ownership = @restore_ownership
383
- selected_entry.restore_permissions = @restore_permissions
384
- selected_entry.restore_times = @restore_times
397
+ raise Errno::ENOENT, entry if selected_entry.nil?
398
+
385
399
  selected_entry
386
400
  end
387
401
 
@@ -103,7 +103,7 @@ module Zip
103
103
  end
104
104
 
105
105
  def open_buffer(filename_or_io, offset = 0)
106
- puts 'open_buffer is deprecated!!! Use open instead!'
106
+ warn 'open_buffer is deprecated!!! Use open instead!'
107
107
  open(filename_or_io, offset)
108
108
  end
109
109
  end
@@ -2,12 +2,7 @@ module Zip
2
2
  class StreamableStream < DelegateClass(Entry) # nodoc:all
3
3
  def initialize(entry)
4
4
  super(entry)
5
- dirname = if zipfile.is_a?(::String)
6
- ::File.dirname(zipfile)
7
- else
8
- nil
9
- end
10
- @temp_file = Tempfile.new(::File.basename(name), dirname)
5
+ @temp_file = Tempfile.new(::File.basename(name))
11
6
  @temp_file.binmode
12
7
  end
13
8
 
@@ -1,3 +1,3 @@
1
1
  module Zip
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyzip
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Simonov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-25 00:00:00.000000000 Z
11
+ date: 2020-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -139,9 +139,9 @@ licenses:
139
139
  - BSD 2-Clause
140
140
  metadata:
141
141
  bug_tracker_uri: https://github.com/rubyzip/rubyzip/issues
142
- changelog_uri: https://github.com/rubyzip/rubyzip/blob/v2.0.0/Changelog.md
143
- documentation_uri: https://www.rubydoc.info/gems/rubyzip/2.0.0
144
- source_code_uri: https://github.com/rubyzip/rubyzip/tree/v2.0.0
142
+ changelog_uri: https://github.com/rubyzip/rubyzip/blob/v2.1.0/Changelog.md
143
+ documentation_uri: https://www.rubydoc.info/gems/rubyzip/2.1.0
144
+ source_code_uri: https://github.com/rubyzip/rubyzip/tree/v2.1.0
145
145
  wiki_uri: https://github.com/rubyzip/rubyzip/wiki
146
146
  post_install_message:
147
147
  rdoc_options: []