rubyzip 1.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +64 -23
  3. data/Rakefile +3 -0
  4. data/lib/zip.rb +6 -3
  5. data/lib/zip/central_directory.rb +9 -5
  6. data/lib/zip/constants.rb +52 -0
  7. data/lib/zip/crypto/decrypted_io.rb +40 -0
  8. data/lib/zip/crypto/traditional_encryption.rb +9 -9
  9. data/lib/zip/decompressor.rb +19 -1
  10. data/lib/zip/dos_time.rb +12 -7
  11. data/lib/zip/entry.rb +69 -37
  12. data/lib/zip/entry_set.rb +2 -0
  13. data/lib/zip/errors.rb +2 -0
  14. data/lib/zip/extra_field.rb +11 -9
  15. data/lib/zip/extra_field/generic.rb +10 -9
  16. data/lib/zip/extra_field/ntfs.rb +4 -0
  17. data/lib/zip/extra_field/old_unix.rb +3 -1
  18. data/lib/zip/extra_field/universal_time.rb +42 -12
  19. data/lib/zip/extra_field/unix.rb +3 -1
  20. data/lib/zip/extra_field/zip64.rb +4 -2
  21. data/lib/zip/file.rb +115 -70
  22. data/lib/zip/filesystem.rb +193 -177
  23. data/lib/zip/inflater.rb +24 -36
  24. data/lib/zip/input_stream.rb +33 -26
  25. data/lib/zip/ioextras.rb +1 -1
  26. data/lib/zip/ioextras/abstract_input_stream.rb +19 -8
  27. data/lib/zip/ioextras/abstract_output_stream.rb +1 -1
  28. data/lib/zip/null_decompressor.rb +1 -9
  29. data/lib/zip/output_stream.rb +14 -5
  30. data/lib/zip/pass_thru_compressor.rb +2 -2
  31. data/lib/zip/pass_thru_decompressor.rb +13 -22
  32. data/lib/zip/streamable_directory.rb +3 -3
  33. data/lib/zip/streamable_stream.rb +6 -10
  34. data/lib/zip/version.rb +1 -1
  35. data/samples/example.rb +2 -2
  36. data/samples/example_filesystem.rb +1 -1
  37. data/samples/gtk_ruby_zip.rb +19 -19
  38. data/samples/qtzip.rb +6 -6
  39. data/samples/write_simple.rb +2 -4
  40. data/samples/zipfind.rb +23 -22
  41. metadata +32 -167
  42. data/test/basic_zip_file_test.rb +0 -60
  43. data/test/case_sensitivity_test.rb +0 -69
  44. data/test/central_directory_entry_test.rb +0 -69
  45. data/test/central_directory_test.rb +0 -100
  46. data/test/crypto/null_encryption_test.rb +0 -57
  47. data/test/crypto/traditional_encryption_test.rb +0 -80
  48. data/test/data/WarnInvalidDate.zip +0 -0
  49. data/test/data/file1.txt +0 -46
  50. data/test/data/file1.txt.deflatedData +0 -0
  51. data/test/data/file2.txt +0 -1504
  52. data/test/data/globTest.zip +0 -0
  53. data/test/data/globTest/foo.txt +0 -0
  54. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  55. data/test/data/globTest/food.txt +0 -0
  56. data/test/data/gpbit3stored.zip +0 -0
  57. data/test/data/mimetype +0 -1
  58. data/test/data/notzippedruby.rb +0 -7
  59. data/test/data/ntfs.zip +0 -0
  60. data/test/data/oddExtraField.zip +0 -0
  61. data/test/data/path_traversal/Makefile +0 -10
  62. data/test/data/path_traversal/jwilk/README.md +0 -5
  63. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  64. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  65. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  66. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  67. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  68. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  69. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  70. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  71. data/test/data/path_traversal/relative1.zip +0 -0
  72. data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
  73. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  74. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  75. data/test/data/rubycode.zip +0 -0
  76. data/test/data/rubycode2.zip +0 -0
  77. data/test/data/test.xls +0 -0
  78. data/test/data/testDirectory.bin +0 -0
  79. data/test/data/zip64-sample.zip +0 -0
  80. data/test/data/zipWithDirs.zip +0 -0
  81. data/test/data/zipWithEncryption.zip +0 -0
  82. data/test/deflater_test.rb +0 -65
  83. data/test/encryption_test.rb +0 -42
  84. data/test/entry_set_test.rb +0 -163
  85. data/test/entry_test.rb +0 -154
  86. data/test/errors_test.rb +0 -35
  87. data/test/extra_field_test.rb +0 -76
  88. data/test/file_extract_directory_test.rb +0 -54
  89. data/test/file_extract_test.rb +0 -83
  90. data/test/file_permissions_test.rb +0 -65
  91. data/test/file_split_test.rb +0 -57
  92. data/test/file_test.rb +0 -601
  93. data/test/filesystem/dir_iterator_test.rb +0 -58
  94. data/test/filesystem/directory_test.rb +0 -139
  95. data/test/filesystem/file_mutating_test.rb +0 -87
  96. data/test/filesystem/file_nonmutating_test.rb +0 -508
  97. data/test/filesystem/file_stat_test.rb +0 -64
  98. data/test/gentestfiles.rb +0 -126
  99. data/test/inflater_test.rb +0 -14
  100. data/test/input_stream_test.rb +0 -182
  101. data/test/ioextras/abstract_input_stream_test.rb +0 -102
  102. data/test/ioextras/abstract_output_stream_test.rb +0 -106
  103. data/test/ioextras/fake_io_test.rb +0 -18
  104. data/test/local_entry_test.rb +0 -154
  105. data/test/output_stream_test.rb +0 -128
  106. data/test/pass_thru_compressor_test.rb +0 -30
  107. data/test/pass_thru_decompressor_test.rb +0 -14
  108. data/test/path_traversal_test.rb +0 -134
  109. data/test/samples/example_recursive_test.rb +0 -37
  110. data/test/settings_test.rb +0 -95
  111. data/test/test_helper.rb +0 -234
  112. data/test/unicode_file_names_and_comments_test.rb +0 -62
  113. data/test/zip64_full_test.rb +0 -51
  114. data/test/zip64_support_test.rb +0 -14
@@ -1,9 +1,9 @@
1
1
  module Zip
2
2
  class ExtraField::Generic
3
3
  def self.register_map
4
- if const_defined?(:HEADER_ID)
5
- ::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
6
- end
4
+ return unless const_defined?(:HEADER_ID)
5
+
6
+ ::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
7
7
  end
8
8
 
9
9
  def self.name
@@ -12,18 +12,19 @@ module Zip
12
12
 
13
13
  # return field [size, content] or false
14
14
  def initial_parse(binstr)
15
- if !binstr
16
- # If nil, start with empty.
17
- return false
18
- elsif binstr[0, 2] != self.class.const_get(:HEADER_ID)
19
- $stderr.puts 'Warning: weired extra feild header ID. skip parsing'
15
+ return false unless binstr
16
+
17
+ if binstr[0, 2] != self.class.const_get(:HEADER_ID)
18
+ warn 'WARNING: weird extra field header ID. Skip parsing it.'
20
19
  return false
21
20
  end
22
- [binstr[2, 2].unpack('v')[0], binstr[4..-1]]
21
+
22
+ [binstr[2, 2].unpack1('v'), binstr[4..-1]]
23
23
  end
24
24
 
25
25
  def ==(other)
26
26
  return false if self.class != other.class
27
+
27
28
  each do |k, v|
28
29
  return false if v != other[k]
29
30
  end
@@ -19,6 +19,7 @@ module Zip
19
19
 
20
20
  def merge(binstr)
21
21
  return if binstr.empty?
22
+
22
23
  size, content = initial_parse(binstr)
23
24
  (size && content) || return
24
25
 
@@ -27,6 +28,7 @@ module Zip
27
28
 
28
29
  tag1 = tags[1]
29
30
  return unless tag1
31
+
30
32
  ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
31
33
  ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
32
34
  ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
@@ -65,12 +67,14 @@ module Zip
65
67
 
66
68
  def parse_tags(content)
67
69
  return {} if content.nil?
70
+
68
71
  tags = {}
69
72
  i = 0
70
73
  while i < content.bytesize
71
74
  tag, size = content[i, 4].unpack('vv')
72
75
  i += 4
73
76
  break unless tag && size
77
+
74
78
  value = content[i, size]
75
79
  i += size
76
80
  tags[tag] = value
@@ -16,14 +16,16 @@ module Zip
16
16
 
17
17
  def merge(binstr)
18
18
  return if binstr.empty?
19
+
19
20
  size, content = initial_parse(binstr)
20
21
  # size: 0 for central directory. 4 for local header
21
22
  return if !size || size == 0
23
+
22
24
  atime, mtime, uid, gid = content.unpack('VVvv')
23
25
  @uid ||= uid
24
26
  @gid ||= gid
25
27
  @atime ||= atime
26
- @mtime ||= mtime
28
+ @mtime ||= mtime # rubocop:disable Naming/MemoizedInstanceVariableName
27
29
  end
28
30
 
29
31
  def ==(other)
@@ -4,24 +4,54 @@ 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
25
+ end
26
+
27
+ def ctime=(time)
28
+ @flag = time.nil? ? @flag & ~CTIME_MASK : @flag | CTIME_MASK
29
+ @ctime = time
13
30
  end
14
31
 
15
- attr_accessor :atime, :ctime, :mtime, :flag
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
+
48
+ @mtime ||= ::Zip::DOSTime.at(times.shift) unless @flag & MTIME_MASK == 0
49
+ return if times[0].nil?
50
+
51
+ @atime ||= ::Zip::DOSTime.at(times.shift) unless @flag & ATIME_MASK == 0
52
+ return if times[0].nil?
53
+
54
+ @ctime ||= ::Zip::DOSTime.at(times.shift) unless @flag & CTIME_MASK == 0
25
55
  end
26
56
 
27
57
  def ==(other)
@@ -32,15 +62,15 @@ module Zip
32
62
 
33
63
  def pack_for_local
34
64
  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')
65
+ s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
66
+ s << [@atime.to_i].pack('l<') unless @flag & ATIME_MASK == 0
67
+ s << [@ctime.to_i].pack('l<') unless @flag & CTIME_MASK == 0
38
68
  s
39
69
  end
40
70
 
41
71
  def pack_for_c_dir
42
72
  s = [@flag].pack('C')
43
- @flag & 1 == 1 && s << [@mtime.to_i].pack('V')
73
+ s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
44
74
  s
45
75
  end
46
76
  end
@@ -14,12 +14,14 @@ module Zip
14
14
 
15
15
  def merge(binstr)
16
16
  return if binstr.empty?
17
+
17
18
  size, content = initial_parse(binstr)
18
19
  # size: 0 for central directory. 4 for local header
19
20
  return if !size || size == 0
21
+
20
22
  uid, gid = content.unpack('vv')
21
23
  @uid ||= uid
22
- @gid ||= gid
24
+ @gid ||= gid # rubocop:disable Naming/MemoizedInstanceVariableName
23
25
  end
24
26
 
25
27
  def ==(other)
@@ -9,7 +9,7 @@ module Zip
9
9
  # unparsed binary; we don't actually know what this contains
10
10
  # without looking for FFs in the associated file header
11
11
  # call parse after initializing with a binary string
12
- @content = nil
12
+ @content = nil
13
13
  @original_size = nil
14
14
  @compressed_size = nil
15
15
  @relative_header_offset = nil
@@ -26,6 +26,7 @@ module Zip
26
26
 
27
27
  def merge(binstr)
28
28
  return if binstr.empty?
29
+
29
30
  _, @content = initial_parse(binstr)
30
31
  end
31
32
 
@@ -45,13 +46,14 @@ module Zip
45
46
  end
46
47
 
47
48
  def extract(size, format)
48
- @content.slice!(0, size).unpack(format)[0]
49
+ @content.slice!(0, size).unpack1(format)
49
50
  end
50
51
  private :extract
51
52
 
52
53
  def pack_for_local
53
54
  # local header entries must contain original size and compressed size; other fields do not apply
54
55
  return '' unless @original_size && @compressed_size
56
+
55
57
  [@original_size, @compressed_size].pack('Q<Q<')
56
58
  end
57
59
 
@@ -49,53 +49,78 @@ module Zip
49
49
  MAX_SEGMENT_SIZE = 3_221_225_472
50
50
  MIN_SEGMENT_SIZE = 65_536
51
51
  DATA_BUFFER_SIZE = 8192
52
- IO_METHODS = [:tell, :seek, :read, :close]
52
+ IO_METHODS = [:tell, :seek, :read, :eof, :close]
53
+
54
+ DEFAULT_OPTIONS = {
55
+ restore_ownership: false,
56
+ restore_permissions: false,
57
+ restore_times: false
58
+ }.freeze
53
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
 
65
74
  # Opens a zip archive. Pass true as the second parameter to create
66
75
  # a new archive if it doesn't exist already.
67
- def initialize(file_name, create = false, buffer = false, options = {})
76
+ def initialize(path_or_io, create = false, buffer = false, options = {})
68
77
  super()
69
- @name = file_name
78
+ options = DEFAULT_OPTIONS.merge(options)
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
72
- if !buffer && ::File.size?(file_name)
82
+
83
+ if ::File.size?(@name.to_s)
84
+ # There is a file, which exists, that is associated with this zip.
73
85
  @create = false
74
- @file_permissions = ::File.stat(file_name).mode
75
- ::File.open(name, 'rb') do |f|
76
- read_from_stream(f)
86
+ @file_permissions = ::File.stat(@name).mode
87
+
88
+ if buffer
89
+ read_from_stream(path_or_io)
90
+ else
91
+ ::File.open(@name, 'rb') do |f|
92
+ read_from_stream(f)
93
+ end
77
94
  end
95
+ elsif buffer && path_or_io.size > 0
96
+ # This zip is probably a non-empty StringIO.
97
+ read_from_stream(path_or_io)
78
98
  elsif @create
99
+ # This zip is completely new/empty and is to be created.
79
100
  @entry_set = EntrySet.new
80
- elsif ::File.zero?(file_name)
81
- raise Error, "File #{file_name} has zero size. Did you mean to pass the create flag?"
101
+ elsif ::File.zero?(@name)
102
+ # A file exists, but it is empty.
103
+ raise Error, "File #{@name} has zero size. Did you mean to pass the create flag?"
82
104
  else
83
- raise Error, "File #{file_name} not found"
105
+ # Everything is wrong.
106
+ raise Error, "File #{@name} not found"
84
107
  end
108
+
85
109
  @stored_entries = @entry_set.dup
86
110
  @stored_comment = @comment
87
- @restore_ownership = options[:restore_ownership] || false
88
- @restore_permissions = options[:restore_permissions] || true
89
- @restore_times = options[:restore_times] || true
111
+ @restore_ownership = options[:restore_ownership]
112
+ @restore_permissions = options[:restore_permissions]
113
+ @restore_times = options[:restore_times]
90
114
  end
91
115
 
92
116
  class << self
93
- # Same as #new. If a block is passed the ZipFile object is passed
94
- # to the block and is automatically closed afterwards just as with
95
- # ruby's builtin File.open method.
96
- def open(file_name, create = false)
97
- 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)
98
122
  return zf unless block_given?
123
+
99
124
  begin
100
125
  yield zf
101
126
  ensure
@@ -116,20 +141,20 @@ module Zip
116
141
  # (This can be used to extract data from a
117
142
  # downloaded zip archive without first saving it to disk.)
118
143
  def open_buffer(io, options = {})
119
- unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
144
+ unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
120
145
  raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
121
146
  end
122
- if io.is_a?(::String)
123
- require 'stringio'
124
- io = ::StringIO.new(io)
125
- elsif io.respond_to?(:binmode)
126
- # https://github.com/rubyzip/rubyzip/issues/119
127
- io.binmode
128
- end
147
+
148
+ io = ::StringIO.new(io) if io.kind_of?(::String)
149
+
150
+ # https://github.com/rubyzip/rubyzip/issues/119
151
+ io.binmode if io.respond_to?(:binmode)
152
+
129
153
  zf = ::Zip::File.new(io, true, true, options)
130
- zf.read_from_stream(io)
131
154
  return zf unless block_given?
155
+
132
156
  yield zf
157
+
133
158
  begin
134
159
  zf.write_buffer(io)
135
160
  rescue IOError => e
@@ -143,9 +168,9 @@ module Zip
143
168
  # whereas ZipInputStream jumps through the entire archive accessing the
144
169
  # local entry headers (which contain the same information as the
145
170
  # central directory).
146
- def foreach(aZipFileName, &block)
147
- open(aZipFileName) do |zipFile|
148
- zipFile.each(&block)
171
+ def foreach(zip_file_name, &block)
172
+ ::Zip::File.open(zip_file_name) do |zip_file|
173
+ zip_file.each(&block)
149
174
  end
150
175
  end
151
176
 
@@ -206,12 +231,14 @@ module Zip
206
231
  def split(zip_file_name, segment_size = MAX_SEGMENT_SIZE, delete_zip_file = true, partial_zip_file_name = nil)
207
232
  raise Error, "File #{zip_file_name} not found" unless ::File.exist?(zip_file_name)
208
233
  raise Errno::ENOENT, zip_file_name unless ::File.readable?(zip_file_name)
234
+
209
235
  zip_file_size = ::File.size(zip_file_name)
210
236
  segment_size = get_segment_size_for_split(segment_size)
211
237
  return if zip_file_size <= segment_size
238
+
212
239
  segment_count = get_segment_count_for_split(zip_file_size, segment_size)
213
240
  # Checking for correct zip structure
214
- open(zip_file_name) {}
241
+ ::Zip::File.open(zip_file_name) {}
215
242
  partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
216
243
  szip_file_index = 0
217
244
  ::File.open(zip_file_name, 'rb') do |zip_file|
@@ -228,8 +255,8 @@ module Zip
228
255
  # Returns an input stream to the specified entry. If a block is passed
229
256
  # the stream object is passed to the block and the stream is automatically
230
257
  # closed afterwards just as with ruby's builtin File.open method.
231
- def get_input_stream(entry, &aProc)
232
- get_entry(entry).get_input_stream(&aProc)
258
+ def get_input_stream(entry, &a_proc)
259
+ get_entry(entry).get_input_stream(&a_proc)
233
260
  end
234
261
 
235
262
  # Returns an output stream to the specified entry. If entry is not an instance
@@ -237,7 +264,11 @@ module Zip
237
264
  # specified. If a block is passed the stream object is passed to the block and
238
265
  # the stream is automatically closed afterwards just as with ruby's builtin
239
266
  # File.open method.
240
- def get_output_stream(entry, permission_int = nil, comment = nil, extra = nil, compressed_size = nil, crc = nil, compression_method = nil, size = nil, time = nil, &aProc)
267
+ def get_output_stream(entry, permission_int = nil, comment = nil,
268
+ extra = nil, compressed_size = nil, crc = nil,
269
+ compression_method = nil, size = nil, time = nil,
270
+ &a_proc)
271
+
241
272
  new_entry =
242
273
  if entry.kind_of?(Entry)
243
274
  entry
@@ -251,7 +282,7 @@ module Zip
251
282
  new_entry.unix_perms = permission_int
252
283
  zip_streamable_entry = StreamableStream.new(new_entry)
253
284
  @entry_set << zip_streamable_entry
254
- zip_streamable_entry.get_output_stream(&aProc)
285
+ zip_streamable_entry.get_output_stream(&a_proc)
255
286
  end
256
287
 
257
288
  # Returns the name of the zip archive
@@ -261,7 +292,7 @@ module Zip
261
292
 
262
293
  # Returns a string containing the contents of the specified entry
263
294
  def read(entry)
264
- get_input_stream(entry) { |is| is.read }
295
+ get_input_stream(entry, &:read)
265
296
  end
266
297
 
267
298
  # Convenience method for adding the contents of a file to the archive
@@ -274,6 +305,13 @@ module Zip
274
305
  @entry_set << new_entry
275
306
  end
276
307
 
308
+ # Convenience method for adding the contents of a file to the archive
309
+ # in Stored format (uncompressed)
310
+ def add_stored(entry, src_path, &continue_on_exists_proc)
311
+ entry = ::Zip::Entry.new(@name, entry.to_s, nil, nil, nil, nil, ::Zip::Entry::STORED)
312
+ add(entry, src_path, &continue_on_exists_proc)
313
+ end
314
+
277
315
  # Removes the specified entry.
278
316
  def remove(entry)
279
317
  @entry_set.delete(get_entry(entry))
@@ -281,19 +319,19 @@ module Zip
281
319
 
282
320
  # Renames the specified entry.
283
321
  def rename(entry, new_name, &continue_on_exists_proc)
284
- foundEntry = get_entry(entry)
322
+ found_entry = get_entry(entry)
285
323
  check_entry_exists(new_name, continue_on_exists_proc, 'rename')
286
- @entry_set.delete(foundEntry)
287
- foundEntry.name = new_name
288
- @entry_set << foundEntry
324
+ @entry_set.delete(found_entry)
325
+ found_entry.name = new_name
326
+ @entry_set << found_entry
289
327
  end
290
328
 
291
- # Replaces the specified entry with the contents of srcPath (from
329
+ # Replaces the specified entry with the contents of src_path (from
292
330
  # the file system).
293
- def replace(entry, srcPath)
294
- check_file(srcPath)
331
+ def replace(entry, src_path)
332
+ check_file(src_path)
295
333
  remove(entry)
296
- add(entry, srcPath)
334
+ add(entry, src_path)
297
335
  end
298
336
 
299
337
  # Extracts entry to file dest_path.
@@ -306,7 +344,8 @@ module Zip
306
344
  # Commits changes that has been made since the previous commit to
307
345
  # the zip archive.
308
346
  def commit
309
- return if name.is_a?(StringIO) || !commit_required?
347
+ return if name.kind_of?(StringIO) || !commit_required?
348
+
310
349
  on_success_replace do |tmp_file|
311
350
  ::Zip::OutputStream.open(tmp_file) do |zos|
312
351
  @entry_set.each do |e|
@@ -346,7 +385,13 @@ module Zip
346
385
  # Searches for entry with the specified name. Returns nil if
347
386
  # no entry is found. See also get_entry
348
387
  def find_entry(entry_name)
349
- @entry_set.find_entry(entry_name)
388
+ selected_entry = @entry_set.find_entry(entry_name)
389
+ return if selected_entry.nil?
390
+
391
+ selected_entry.restore_ownership = @restore_ownership
392
+ selected_entry.restore_permissions = @restore_permissions
393
+ selected_entry.restore_times = @restore_times
394
+ selected_entry
350
395
  end
351
396
 
352
397
  # Searches for entries given a glob
@@ -358,43 +403,43 @@ module Zip
358
403
  # if no entry is found.
359
404
  def get_entry(entry)
360
405
  selected_entry = find_entry(entry)
361
- raise Errno::ENOENT, entry unless selected_entry
362
- selected_entry.restore_ownership = @restore_ownership
363
- selected_entry.restore_permissions = @restore_permissions
364
- selected_entry.restore_times = @restore_times
406
+ raise Errno::ENOENT, entry if selected_entry.nil?
407
+
365
408
  selected_entry
366
409
  end
367
410
 
368
411
  # Creates a directory
369
- def mkdir(entryName, permissionInt = 0o755)
370
- raise Errno::EEXIST, "File exists - #{entryName}" if find_entry(entryName)
371
- entryName = entryName.dup.to_s
372
- entryName << '/' unless entryName.end_with?('/')
373
- @entry_set << ::Zip::StreamableDirectory.new(@name, entryName, nil, permissionInt)
412
+ def mkdir(entry_name, permission = 0o755)
413
+ raise Errno::EEXIST, "File exists - #{entry_name}" if find_entry(entry_name)
414
+
415
+ entry_name = entry_name.dup.to_s
416
+ entry_name << '/' unless entry_name.end_with?('/')
417
+ @entry_set << ::Zip::StreamableDirectory.new(@name, entry_name, nil, permission)
374
418
  end
375
419
 
376
420
  private
377
421
 
378
- def directory?(newEntry, srcPath)
379
- srcPathIsDirectory = ::File.directory?(srcPath)
380
- if newEntry.directory? && !srcPathIsDirectory
422
+ def directory?(new_entry, src_path)
423
+ path_is_directory = ::File.directory?(src_path)
424
+ if new_entry.directory? && !path_is_directory
381
425
  raise ArgumentError,
382
- "entry name '#{newEntry}' indicates directory entry, but " \
383
- "'#{srcPath}' is not a directory"
384
- elsif !newEntry.directory? && srcPathIsDirectory
385
- newEntry.name += '/'
426
+ "entry name '#{new_entry}' indicates directory entry, but " \
427
+ "'#{src_path}' is not a directory"
428
+ elsif !new_entry.directory? && path_is_directory
429
+ new_entry.name += '/'
386
430
  end
387
- newEntry.directory? && srcPathIsDirectory
431
+ new_entry.directory? && path_is_directory
388
432
  end
389
433
 
390
- def check_entry_exists(entryName, continue_on_exists_proc, procedureName)
434
+ def check_entry_exists(entry_name, continue_on_exists_proc, proc_name)
391
435
  continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
392
- return unless @entry_set.include?(entryName)
436
+ return unless @entry_set.include?(entry_name)
437
+
393
438
  if continue_on_exists_proc.call
394
- remove get_entry(entryName)
439
+ remove get_entry(entry_name)
395
440
  else
396
441
  raise ::Zip::EntryExistsError,
397
- procedureName + " failed. Entry #{entryName} already exists"
442
+ proc_name + " failed. Entry #{entry_name} already exists"
398
443
  end
399
444
  end
400
445