rubyzip 1.1.7 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubyzip might be problematic. Click here for more details.

Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +87 -45
  3. data/Rakefile +3 -4
  4. data/lib/zip.rb +11 -5
  5. data/lib/zip/central_directory.rb +8 -8
  6. data/lib/zip/compressor.rb +1 -2
  7. data/lib/zip/constants.rb +5 -5
  8. data/lib/zip/crypto/null_encryption.rb +4 -6
  9. data/lib/zip/crypto/traditional_encryption.rb +5 -5
  10. data/lib/zip/decompressor.rb +3 -3
  11. data/lib/zip/deflater.rb +8 -6
  12. data/lib/zip/dos_time.rb +5 -6
  13. data/lib/zip/entry.rb +120 -128
  14. data/lib/zip/entry_set.rb +14 -14
  15. data/lib/zip/errors.rb +1 -0
  16. data/lib/zip/extra_field.rb +8 -8
  17. data/lib/zip/extra_field/generic.rb +8 -8
  18. data/lib/zip/extra_field/ntfs.rb +14 -16
  19. data/lib/zip/extra_field/old_unix.rb +9 -10
  20. data/lib/zip/extra_field/universal_time.rb +14 -14
  21. data/lib/zip/extra_field/unix.rb +8 -9
  22. data/lib/zip/extra_field/zip64.rb +12 -11
  23. data/lib/zip/extra_field/zip64_placeholder.rb +1 -2
  24. data/lib/zip/file.rb +81 -81
  25. data/lib/zip/filesystem.rb +144 -143
  26. data/lib/zip/inflater.rb +5 -5
  27. data/lib/zip/input_stream.rb +22 -13
  28. data/lib/zip/ioextras.rb +1 -3
  29. data/lib/zip/ioextras/abstract_input_stream.rb +6 -10
  30. data/lib/zip/ioextras/abstract_output_stream.rb +3 -5
  31. data/lib/zip/null_compressor.rb +2 -2
  32. data/lib/zip/null_decompressor.rb +3 -3
  33. data/lib/zip/null_input_stream.rb +0 -0
  34. data/lib/zip/output_stream.rb +13 -14
  35. data/lib/zip/pass_thru_compressor.rb +4 -4
  36. data/lib/zip/pass_thru_decompressor.rb +3 -4
  37. data/lib/zip/streamable_directory.rb +2 -2
  38. data/lib/zip/streamable_stream.rb +3 -3
  39. data/lib/zip/version.rb +1 -1
  40. data/samples/example.rb +29 -39
  41. data/samples/example_filesystem.rb +16 -18
  42. data/samples/example_recursive.rb +31 -25
  43. data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +23 -25
  44. data/samples/qtzip.rb +18 -27
  45. data/samples/write_simple.rb +12 -13
  46. data/samples/zipfind.rb +26 -34
  47. data/test/basic_zip_file_test.rb +11 -15
  48. data/test/case_sensitivity_test.rb +69 -0
  49. data/test/central_directory_entry_test.rb +32 -36
  50. data/test/central_directory_test.rb +46 -50
  51. data/test/crypto/null_encryption_test.rb +8 -4
  52. data/test/crypto/traditional_encryption_test.rb +5 -5
  53. data/test/data/gpbit3stored.zip +0 -0
  54. data/test/data/notzippedruby.rb +1 -1
  55. data/test/data/oddExtraField.zip +0 -0
  56. data/test/data/path_traversal/Makefile +10 -0
  57. data/test/data/path_traversal/jwilk/README.md +5 -0
  58. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  59. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  60. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  61. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  62. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  63. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  64. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  65. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  66. data/test/data/path_traversal/relative1.zip +0 -0
  67. data/test/data/path_traversal/tilde.zip +0 -0
  68. data/test/data/path_traversal/tuzovakaoff/README.md +3 -0
  69. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  70. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  71. data/test/data/rubycode.zip +0 -0
  72. data/test/data/test.xls +0 -0
  73. data/test/deflater_test.rb +10 -12
  74. data/test/encryption_test.rb +2 -2
  75. data/test/entry_set_test.rb +50 -25
  76. data/test/entry_test.rb +76 -87
  77. data/test/errors_test.rb +1 -2
  78. data/test/extra_field_test.rb +19 -21
  79. data/test/file_extract_directory_test.rb +12 -14
  80. data/test/file_extract_test.rb +33 -40
  81. data/test/file_permissions_test.rb +65 -0
  82. data/test/file_split_test.rb +24 -27
  83. data/test/file_test.rb +266 -179
  84. data/test/filesystem/dir_iterator_test.rb +13 -17
  85. data/test/filesystem/directory_test.rb +101 -93
  86. data/test/filesystem/file_mutating_test.rb +52 -65
  87. data/test/filesystem/file_nonmutating_test.rb +223 -229
  88. data/test/filesystem/file_stat_test.rb +17 -19
  89. data/test/gentestfiles.rb +54 -62
  90. data/test/inflater_test.rb +1 -1
  91. data/test/input_stream_test.rb +52 -40
  92. data/test/ioextras/abstract_input_stream_test.rb +22 -23
  93. data/test/ioextras/abstract_output_stream_test.rb +33 -33
  94. data/test/ioextras/fake_io_test.rb +1 -1
  95. data/test/local_entry_test.rb +36 -38
  96. data/test/output_stream_test.rb +20 -21
  97. data/test/pass_thru_compressor_test.rb +5 -6
  98. data/test/pass_thru_decompressor_test.rb +0 -1
  99. data/test/path_traversal_test.rb +141 -0
  100. data/test/samples/example_recursive_test.rb +37 -0
  101. data/test/settings_test.rb +18 -15
  102. data/test/test_helper.rb +52 -46
  103. data/test/unicode_file_names_and_comments_test.rb +17 -7
  104. data/test/zip64_full_test.rb +10 -12
  105. data/test/zip64_support_test.rb +0 -1
  106. metadata +94 -65
@@ -6,8 +6,7 @@ module Zip
6
6
  HEADER_ID = ['9999'].pack('H*') # this ID is used by other libraries such as .NET's Ionic.zip
7
7
  register_map
8
8
 
9
- def initialize(binstr = nil)
10
- end
9
+ def initialize(_binstr = nil); end
11
10
 
12
11
  def pack_for_local
13
12
  "\x00" * 16
@@ -43,13 +43,13 @@ module Zip
43
43
  # interface for accessing the filesystem, ie. the File and Dir classes.
44
44
 
45
45
  class File < CentralDirectory
46
-
47
- CREATE = 1
46
+ CREATE = true
48
47
  SPLIT_SIGNATURE = 0x08074b50
49
48
  ZIP64_EOCD_SIGNATURE = 0x06064b50
50
- MAX_SEGMENT_SIZE = 3221225472
51
- MIN_SEGMENT_SIZE = 65536
49
+ MAX_SEGMENT_SIZE = 3_221_225_472
50
+ MIN_SEGMENT_SIZE = 65_536
52
51
  DATA_BUFFER_SIZE = 8192
52
+ IO_METHODS = [:tell, :seek, :read, :close]
53
53
 
54
54
  attr_reader :name
55
55
 
@@ -64,23 +64,38 @@ module Zip
64
64
 
65
65
  # Opens a zip archive. Pass true as the second parameter to create
66
66
  # a new archive if it doesn't exist already.
67
- def initialize(file_name, create = nil, buffer = false, options = {})
67
+ def initialize(path_or_io, create = false, buffer = false, options = {})
68
68
  super()
69
- @name = file_name
69
+ @name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
70
70
  @comment = ''
71
- @create = create
72
- case
73
- when !buffer && ::File.size?(file_name)
74
- @create = nil
75
- @exist_file_perms = ::File.stat(file_name).mode
76
- ::File.open(name, 'rb') do |f|
77
- read_from_stream(f)
71
+ @create = create ? true : false # allow any truthy value to mean true
72
+
73
+ if ::File.size?(@name.to_s)
74
+ # There is a file, which exists, that is associated with this zip.
75
+ @create = false
76
+ @file_permissions = ::File.stat(@name).mode
77
+
78
+ if buffer
79
+ read_from_stream(path_or_io)
80
+ else
81
+ ::File.open(@name, 'rb') do |f|
82
+ read_from_stream(f)
83
+ end
78
84
  end
79
- when create
85
+ elsif buffer && path_or_io.size > 0
86
+ # This zip is probably a non-empty StringIO.
87
+ read_from_stream(path_or_io)
88
+ elsif @create
89
+ # This zip is completely new/empty and is to be created.
80
90
  @entry_set = EntrySet.new
91
+ elsif ::File.zero?(@name)
92
+ # A file exists, but it is empty.
93
+ raise Error, "File #{@name} has zero size. Did you mean to pass the create flag?"
81
94
  else
82
- raise Error, "File #{file_name} not found"
95
+ # Everything is wrong.
96
+ raise Error, "File #{@name} not found"
83
97
  end
98
+
84
99
  @stored_entries = @entry_set.dup
85
100
  @stored_comment = @comment
86
101
  @restore_ownership = options[:restore_ownership] || false
@@ -92,7 +107,7 @@ module Zip
92
107
  # Same as #new. If a block is passed the ZipFile object is passed
93
108
  # to the block and is automatically closed afterwards just as with
94
109
  # ruby's builtin File.open method.
95
- def open(file_name, create = nil)
110
+ def open(file_name, create = false)
96
111
  zf = ::Zip::File.new(file_name, create)
97
112
  return zf unless block_given?
98
113
  begin
@@ -115,23 +130,23 @@ module Zip
115
130
  # (This can be used to extract data from a
116
131
  # downloaded zip archive without first saving it to disk.)
117
132
  def open_buffer(io, options = {})
118
- unless io.is_a?(IO) || io.is_a?(String) || io.is_a?(Tempfile)
119
- raise "Zip::File.open_buffer expects an argument of class String, IO, or Tempfile. Found: #{io.class}"
120
- end
121
- if io.is_a?(::String)
122
- require 'stringio'
123
- io = ::StringIO.new(io)
124
- elsif io.is_a?(IO)
125
- # https://github.com/rubyzip/rubyzip/issues/119
126
- io.binmode
133
+ unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
134
+ raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
127
135
  end
136
+
137
+ io = ::StringIO.new(io) if io.is_a?(::String)
138
+
139
+ # https://github.com/rubyzip/rubyzip/issues/119
140
+ io.binmode if io.respond_to?(:binmode)
141
+
128
142
  zf = ::Zip::File.new(io, true, true, options)
129
- zf.read_from_stream(io)
143
+ return zf unless block_given?
130
144
  yield zf
145
+
131
146
  begin
132
147
  zf.write_buffer(io)
133
148
  rescue IOError => e
134
- raise unless e.message == "not opened for writing"
149
+ raise unless e.message == 'not opened for writing'
135
150
  end
136
151
  end
137
152
 
@@ -148,10 +163,9 @@ module Zip
148
163
  end
149
164
 
150
165
  def get_segment_size_for_split(segment_size)
151
- case
152
- when MIN_SEGMENT_SIZE > segment_size
166
+ if MIN_SEGMENT_SIZE > segment_size
153
167
  MIN_SEGMENT_SIZE
154
- when MAX_SEGMENT_SIZE < segment_size
168
+ elsif MAX_SEGMENT_SIZE < segment_size
155
169
  MAX_SEGMENT_SIZE
156
170
  else
157
171
  segment_size
@@ -159,8 +173,10 @@ module Zip
159
173
  end
160
174
 
161
175
  def get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
162
- partial_zip_file_name = zip_file_name.sub(/#{::File.basename(zip_file_name)}\z/,
163
- partial_zip_file_name + ::File.extname(zip_file_name)) unless partial_zip_file_name.nil?
176
+ unless partial_zip_file_name.nil?
177
+ partial_zip_file_name = zip_file_name.sub(/#{::File.basename(zip_file_name)}\z/,
178
+ partial_zip_file_name + ::File.extname(zip_file_name))
179
+ end
164
180
  partial_zip_file_name ||= zip_file_name
165
181
  partial_zip_file_name
166
182
  end
@@ -181,7 +197,7 @@ module Zip
181
197
  def save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
182
198
  ssegment_size = zip_file_size - zip_file.pos
183
199
  ssegment_size = segment_size if ssegment_size > segment_size
184
- szip_file_name = "#{partial_zip_file_name}.#{'%03d'%(szip_file_index)}"
200
+ szip_file_name = "#{partial_zip_file_name}.#{format('%03d', szip_file_index)}"
185
201
  ::File.open(szip_file_name, 'wb') do |szip_file|
186
202
  if szip_file_index == 1
187
203
  ssegment_size = put_split_signature(szip_file, segment_size)
@@ -191,7 +207,7 @@ module Zip
191
207
  segment_bytes_left = ssegment_size - chunk_bytes
192
208
  buffer_size = segment_bytes_left < DATA_BUFFER_SIZE ? segment_bytes_left : DATA_BUFFER_SIZE
193
209
  chunk = zip_file.read(buffer_size)
194
- chunk_bytes += buffer_size
210
+ chunk_bytes += buffer_size
195
211
  szip_file << chunk
196
212
  # Info for track splitting
197
213
  yield segment_count, szip_file_index, chunk_bytes, ssegment_size if block_given?
@@ -208,7 +224,7 @@ module Zip
208
224
  return if zip_file_size <= segment_size
209
225
  segment_count = get_segment_count_for_split(zip_file_size, segment_size)
210
226
  # Checking for correct zip structure
211
- self.open(zip_file_name) {}
227
+ open(zip_file_name) {}
212
228
  partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
213
229
  szip_file_index = 0
214
230
  ::File.open(zip_file_name, 'rb') do |zip_file|
@@ -222,7 +238,6 @@ module Zip
222
238
  end
223
239
  end
224
240
 
225
-
226
241
  # Returns an input stream to the specified entry. If a block is passed
227
242
  # the stream object is passed to the block and the stream is automatically
228
243
  # closed afterwards just as with ruby's builtin File.open method.
@@ -235,7 +250,7 @@ module Zip
235
250
  # specified. If a block is passed the stream object is passed to the block and
236
251
  # the stream is automatically closed afterwards just as with ruby's builtin
237
252
  # File.open method.
238
- 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)
253
+ 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)
239
254
  new_entry =
240
255
  if entry.kind_of?(Entry)
241
256
  entry
@@ -265,7 +280,7 @@ module Zip
265
280
  # Convenience method for adding the contents of a file to the archive
266
281
  def add(entry, src_path, &continue_on_exists_proc)
267
282
  continue_on_exists_proc ||= proc { ::Zip.continue_on_exists_proc }
268
- check_entry_exists(entry, continue_on_exists_proc, "add")
283
+ check_entry_exists(entry, continue_on_exists_proc, 'add')
269
284
  new_entry = entry.kind_of?(::Zip::Entry) ? entry : ::Zip::Entry.new(@name, entry.to_s)
270
285
  new_entry.gather_fileinfo_from_srcpath(src_path)
271
286
  new_entry.dirty = true
@@ -304,7 +319,7 @@ module Zip
304
319
  # Commits changes that has been made since the previous commit to
305
320
  # the zip archive.
306
321
  def commit
307
- return unless commit_required?
322
+ return if name.is_a?(StringIO) || !commit_required?
308
323
  on_success_replace do |tmp_file|
309
324
  ::Zip::OutputStream.open(tmp_file) do |zos|
310
325
  @entry_set.each do |e|
@@ -338,7 +353,7 @@ module Zip
338
353
  @entry_set.each do |e|
339
354
  return true if e.dirty
340
355
  end
341
- @comment != @stored_comment || @entry_set != @stored_entries || @create == ::Zip::File::CREATE
356
+ @comment != @stored_comment || @entry_set != @stored_entries || @create
342
357
  end
343
358
 
344
359
  # Searches for entry with the specified name. Returns nil if
@@ -356,9 +371,7 @@ module Zip
356
371
  # if no entry is found.
357
372
  def get_entry(entry)
358
373
  selected_entry = find_entry(entry)
359
- unless selected_entry
360
- raise Errno::ENOENT, entry
361
- end
374
+ raise Errno::ENOENT, entry unless selected_entry
362
375
  selected_entry.restore_ownership = @restore_ownership
363
376
  selected_entry.restore_permissions = @restore_permissions
364
377
  selected_entry.restore_times = @restore_times
@@ -366,10 +379,8 @@ module Zip
366
379
  end
367
380
 
368
381
  # Creates a directory
369
- def mkdir(entryName, permissionInt = 0755)
370
- if find_entry(entryName)
371
- raise Errno::EEXIST, "File exists - #{entryName}"
372
- end
382
+ def mkdir(entryName, permissionInt = 0o755)
383
+ raise Errno::EEXIST, "File exists - #{entryName}" if find_entry(entryName)
373
384
  entryName = entryName.dup.to_s
374
385
  entryName << '/' unless entryName.end_with?('/')
375
386
  @entry_set << ::Zip::StreamableDirectory.new(@name, entryName, nil, permissionInt)
@@ -377,57 +388,46 @@ module Zip
377
388
 
378
389
  private
379
390
 
380
- def is_directory(newEntry, srcPath)
391
+ def directory?(newEntry, srcPath)
381
392
  srcPathIsDirectory = ::File.directory?(srcPath)
382
- if newEntry.is_directory && !srcPathIsDirectory
393
+ if newEntry.directory? && !srcPathIsDirectory
383
394
  raise ArgumentError,
384
- "entry name '#{newEntry}' indicates directory entry, but "+
385
- "'#{srcPath}' is not a directory"
386
- elsif !newEntry.is_directory && srcPathIsDirectory
387
- newEntry.name += "/"
395
+ "entry name '#{newEntry}' indicates directory entry, but " \
396
+ "'#{srcPath}' is not a directory"
397
+ elsif !newEntry.directory? && srcPathIsDirectory
398
+ newEntry.name += '/'
388
399
  end
389
- newEntry.is_directory && srcPathIsDirectory
400
+ newEntry.directory? && srcPathIsDirectory
390
401
  end
391
402
 
392
403
  def check_entry_exists(entryName, continue_on_exists_proc, procedureName)
393
404
  continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
394
- if @entry_set.include?(entryName)
395
- if continue_on_exists_proc.call
396
- remove get_entry(entryName)
397
- else
398
- raise ::Zip::EntryExistsError,
399
- procedureName + " failed. Entry #{entryName} already exists"
400
- end
405
+ return unless @entry_set.include?(entryName)
406
+ if continue_on_exists_proc.call
407
+ remove get_entry(entryName)
408
+ else
409
+ raise ::Zip::EntryExistsError,
410
+ procedureName + " failed. Entry #{entryName} already exists"
401
411
  end
402
412
  end
403
413
 
404
414
  def check_file(path)
405
- unless ::File.readable?(path)
406
- raise Errno::ENOENT, path
407
- end
415
+ raise Errno::ENOENT, path unless ::File.readable?(path)
408
416
  end
409
417
 
410
418
  def on_success_replace
411
- tmpfile = get_tempfile
412
- tmp_filename = tmpfile.path
413
- ObjectSpace.undefine_finalizer(tmpfile)
414
- tmpfile.close
415
- if yield tmp_filename
416
- ::File.rename(tmp_filename, self.name)
417
- if defined?(@exist_file_perms)
418
- ::File.chmod(@exist_file_perms, self.name)
419
+ dirname, basename = ::File.split(name)
420
+ ::Dir::Tmpname.create(basename, dirname) do |tmp_filename|
421
+ begin
422
+ if yield tmp_filename
423
+ ::File.rename(tmp_filename, name)
424
+ ::File.chmod(@file_permissions, name) unless @create
425
+ end
426
+ ensure
427
+ ::File.unlink(tmp_filename) if ::File.exist?(tmp_filename)
419
428
  end
420
429
  end
421
- ensure
422
- tmpfile.unlink if tmpfile
423
430
  end
424
-
425
- def get_tempfile
426
- temp_file = Tempfile.new(::File.basename(name), ::File.dirname(name))
427
- temp_file.binmode
428
- temp_file
429
- end
430
-
431
431
  end
432
432
  end
433
433
 
@@ -1,21 +1,20 @@
1
1
  require 'zip'
2
2
 
3
3
  module Zip
4
-
5
- # The ZipFileSystem API provides an API for accessing entries in
6
- # a zip archive that is similar to ruby's builtin File and Dir
4
+ # The ZipFileSystem API provides an API for accessing entries in
5
+ # a zip archive that is similar to ruby's builtin File and Dir
7
6
  # classes.
8
7
  #
9
8
  # Requiring 'zip/filesystem' includes this module in Zip::File
10
9
  # making the methods in this module available on Zip::File objects.
11
10
  #
12
- # Using this API the following example creates a new zip file
11
+ # Using this API the following example creates a new zip file
13
12
  # <code>my.zip</code> containing a normal entry with the name
14
13
  # <code>first.txt</code>, a directory entry named <code>mydir</code>
15
14
  # and finally another normal entry named <code>second.txt</code>
16
15
  #
17
16
  # require 'zip/filesystem'
18
- #
17
+ #
19
18
  # Zip::File.open("my.zip", Zip::File::CREATE) {
20
19
  # |zipfile|
21
20
  # zipfile.file.open("first.txt", "w") { |f| f.puts "Hello world" }
@@ -23,19 +22,18 @@ module Zip
23
22
  # zipfile.file.open("mydir/second.txt", "w") { |f| f.puts "Hello again" }
24
23
  # }
25
24
  #
26
- # Reading is as easy as writing, as the following example shows. The
25
+ # Reading is as easy as writing, as the following example shows. The
27
26
  # example writes the contents of <code>first.txt</code> from zip archive
28
27
  # <code>my.zip</code> to standard out.
29
28
  #
30
29
  # require 'zip/filesystem'
31
- #
30
+ #
32
31
  # Zip::File.open("my.zip") {
33
32
  # |zipfile|
34
33
  # puts zipfile.file.read("first.txt")
35
34
  # }
36
35
 
37
36
  module FileSystem
38
-
39
37
  def initialize # :nodoc:
40
38
  mappedZip = ZipFileNameMapper.new(self)
41
39
  @zipFsDir = ZipFsDir.new(mappedZip)
@@ -65,24 +63,20 @@ module Zip
65
63
  # The individual methods are not documented due to their
66
64
  # similarity with the methods in File
67
65
  class ZipFsFile
68
-
69
66
  attr_writer :dir
70
- # protected :dir
67
+ # protected :dir
71
68
 
72
69
  class ZipFsStat
73
-
74
70
  class << self
75
-
76
71
  def delegate_to_fs_file(*methods)
77
72
  methods.each do |method|
78
- self.class_eval <<-end_eval, __FILE__, __LINE__ + 1
73
+ class_eval <<-end_eval, __FILE__, __LINE__ + 1
79
74
  def #{method} # def file?
80
75
  @zipFsFile.#{method}(@entryName) # @zipFsFile.file?(@entryName)
81
76
  end # end
82
77
  end_eval
83
78
  end
84
79
  end
85
-
86
80
  end
87
81
 
88
82
  def initialize(zipFsFile, entryName)
@@ -91,15 +85,17 @@ module Zip
91
85
  end
92
86
 
93
87
  def kind_of?(t)
94
- super || t == ::File::Stat
88
+ super || t == ::File::Stat
95
89
  end
96
90
 
97
91
  delegate_to_fs_file :file?, :directory?, :pipe?, :chardev?, :symlink?,
98
- :socket?, :blockdev?, :readable?, :readable_real?, :writable?, :ctime,
99
- :writable_real?, :executable?, :executable_real?, :sticky?, :owned?,
100
- :grpowned?, :setuid?, :setgid?, :zero?, :size, :size?, :mtime, :atime
92
+ :socket?, :blockdev?, :readable?, :readable_real?, :writable?, :ctime,
93
+ :writable_real?, :executable?, :executable_real?, :sticky?, :owned?,
94
+ :grpowned?, :setuid?, :setgid?, :zero?, :size, :size?, :mtime, :atime
101
95
 
102
- def blocks; nil; end
96
+ def blocks
97
+ nil
98
+ end
103
99
 
104
100
  def get_entry
105
101
  @zipFsFile.__send__(:get_entry, @entryName)
@@ -108,8 +104,8 @@ module Zip
108
104
 
109
105
  def gid
110
106
  e = get_entry
111
- if e.extra.member? "IUnix"
112
- e.extra["IUnix"].gid || 0
107
+ if e.extra.member? 'IUnix'
108
+ e.extra['IUnix'].gid || 0
113
109
  else
114
110
  0
115
111
  end
@@ -117,43 +113,57 @@ module Zip
117
113
 
118
114
  def uid
119
115
  e = get_entry
120
- if e.extra.member? "IUnix"
121
- e.extra["IUnix"].uid || 0
116
+ if e.extra.member? 'IUnix'
117
+ e.extra['IUnix'].uid || 0
122
118
  else
123
119
  0
124
120
  end
125
121
  end
126
122
 
127
- def ino; 0; end
123
+ def ino
124
+ 0
125
+ end
128
126
 
129
- def dev; 0; end
127
+ def dev
128
+ 0
129
+ end
130
130
 
131
- def rdev; 0; end
131
+ def rdev
132
+ 0
133
+ end
132
134
 
133
- def rdev_major; 0; end
135
+ def rdev_major
136
+ 0
137
+ end
134
138
 
135
- def rdev_minor; 0; end
139
+ def rdev_minor
140
+ 0
141
+ end
136
142
 
137
143
  def ftype
138
144
  if file?
139
- return "file"
145
+ 'file'
140
146
  elsif directory?
141
- return "directory"
147
+ 'directory'
142
148
  else
143
- raise StandardError, "Unknown file type"
149
+ raise StandardError, 'Unknown file type'
144
150
  end
145
151
  end
146
152
 
147
- def nlink; 1; end
153
+ def nlink
154
+ 1
155
+ end
148
156
 
149
- def blksize; nil; end
157
+ def blksize
158
+ nil
159
+ end
150
160
 
151
161
  def mode
152
162
  e = get_entry
153
163
  if e.fstype == 3
154
164
  e.external_file_attributes >> 16
155
165
  else
156
- 33206 # 33206 is equivalent to -rw-rw-rw-
166
+ 33_206 # 33206 is equivalent to -rw-rw-rw-
157
167
  end
158
168
  end
159
169
  end
@@ -163,7 +173,7 @@ module Zip
163
173
  end
164
174
 
165
175
  def get_entry(fileName)
166
- if ! exists?(fileName)
176
+ unless exists?(fileName)
167
177
  raise Errno::ENOENT, "No such file or directory - #{fileName}"
168
178
  end
169
179
  @mappedZip.find_entry(fileName)
@@ -171,77 +181,75 @@ module Zip
171
181
  private :get_entry
172
182
 
173
183
  def unix_mode_cmp(fileName, mode)
174
- begin
175
- e = get_entry(fileName)
176
- e.fstype == 3 && ((e.external_file_attributes >> 16) & mode ) != 0
177
- rescue Errno::ENOENT
178
- false
179
- end
184
+ e = get_entry(fileName)
185
+ e.fstype == 3 && ((e.external_file_attributes >> 16) & mode) != 0
186
+ rescue Errno::ENOENT
187
+ false
180
188
  end
181
189
  private :unix_mode_cmp
182
190
 
183
191
  def exists?(fileName)
184
- expand_path(fileName) == "/" || @mappedZip.find_entry(fileName) != nil
192
+ expand_path(fileName) == '/' || !@mappedZip.find_entry(fileName).nil?
185
193
  end
186
- alias :exist? :exists?
194
+ alias exist? exists?
187
195
 
188
196
  # Permissions not implemented, so if the file exists it is accessible
189
- alias owned? exists?
190
- alias grpowned? exists?
197
+ alias owned? exists?
198
+ alias grpowned? exists?
191
199
 
192
200
  def readable?(fileName)
193
- unix_mode_cmp(fileName, 0444)
201
+ unix_mode_cmp(fileName, 0o444)
194
202
  end
195
- alias readable_real? readable?
203
+ alias readable_real? readable?
196
204
 
197
205
  def writable?(fileName)
198
- unix_mode_cmp(fileName, 0222)
206
+ unix_mode_cmp(fileName, 0o222)
199
207
  end
200
- alias writable_real? writable?
208
+ alias writable_real? writable?
201
209
 
202
210
  def executable?(fileName)
203
- unix_mode_cmp(fileName, 0111)
211
+ unix_mode_cmp(fileName, 0o111)
204
212
  end
205
213
  alias executable_real? executable?
206
214
 
207
215
  def setuid?(fileName)
208
- unix_mode_cmp(fileName, 04000)
216
+ unix_mode_cmp(fileName, 0o4000)
209
217
  end
210
218
 
211
219
  def setgid?(fileName)
212
- unix_mode_cmp(fileName, 02000)
220
+ unix_mode_cmp(fileName, 0o2000)
213
221
  end
214
222
 
215
223
  def sticky?(fileName)
216
- unix_mode_cmp(fileName, 01000)
224
+ unix_mode_cmp(fileName, 0o1000)
217
225
  end
218
226
 
219
227
  def umask(*args)
220
228
  ::File.umask(*args)
221
229
  end
222
230
 
223
- def truncate(fileName, len)
224
- raise StandardError, "truncate not supported"
231
+ def truncate(_fileName, _len)
232
+ raise StandardError, 'truncate not supported'
225
233
  end
226
234
 
227
235
  def directory?(fileName)
228
236
  entry = @mappedZip.find_entry(fileName)
229
- expand_path(fileName) == "/" || (entry != nil && entry.directory?)
237
+ expand_path(fileName) == '/' || (!entry.nil? && entry.directory?)
230
238
  end
231
239
 
232
- def open(fileName, openMode = "r", permissionInt = 0644, &block)
233
- openMode.gsub!("b", "") # ignore b option
240
+ def open(fileName, openMode = 'r', permissionInt = 0o644, &block)
241
+ openMode.delete!('b') # ignore b option
234
242
  case openMode
235
- when "r"
236
- @mappedZip.get_input_stream(fileName, &block)
237
- when "w"
238
- @mappedZip.get_output_stream(fileName, permissionInt, &block)
239
- else
240
- raise StandardError, "openmode '#{openMode} not supported" unless openMode == "r"
243
+ when 'r'
244
+ @mappedZip.get_input_stream(fileName, &block)
245
+ when 'w'
246
+ @mappedZip.get_output_stream(fileName, permissionInt, &block)
247
+ else
248
+ raise StandardError, "openmode '#{openMode} not supported" unless openMode == 'r'
241
249
  end
242
250
  end
243
251
 
244
- def new(fileName, openMode = "r")
252
+ def new(fileName, openMode = 'r')
245
253
  open(fileName, openMode)
246
254
  end
247
255
 
@@ -252,43 +260,41 @@ module Zip
252
260
  # Returns nil for not found and nil for directories
253
261
  def size?(fileName)
254
262
  entry = @mappedZip.find_entry(fileName)
255
- return (entry == nil || entry.directory?) ? nil : entry.size
263
+ entry.nil? || entry.directory? ? nil : entry.size
256
264
  end
257
265
 
258
266
  def chown(ownerInt, groupInt, *filenames)
259
- filenames.each { |fileName|
267
+ filenames.each do |fileName|
260
268
  e = get_entry(fileName)
261
- unless e.extra.member?("IUnix")
262
- e.extra.create("IUnix")
263
- end
264
- e.extra["IUnix"].uid = ownerInt
265
- e.extra["IUnix"].gid = groupInt
266
- }
269
+ e.extra.create('IUnix') unless e.extra.member?('IUnix')
270
+ e.extra['IUnix'].uid = ownerInt
271
+ e.extra['IUnix'].gid = groupInt
272
+ end
267
273
  filenames.size
268
274
  end
269
275
 
270
- def chmod (modeInt, *filenames)
271
- filenames.each { |fileName|
276
+ def chmod(modeInt, *filenames)
277
+ filenames.each do |fileName|
272
278
  e = get_entry(fileName)
273
279
  e.fstype = 3 # force convertion filesystem type to unix
274
280
  e.unix_perms = modeInt
275
281
  e.external_file_attributes = modeInt << 16
276
282
  e.dirty = true
277
- }
283
+ end
278
284
  filenames.size
279
285
  end
280
286
 
281
287
  def zero?(fileName)
282
288
  sz = size(fileName)
283
- sz == nil || sz == 0
289
+ sz.nil? || sz == 0
284
290
  rescue Errno::ENOENT
285
291
  false
286
292
  end
287
293
 
288
294
  def file?(fileName)
289
295
  entry = @mappedZip.find_entry(fileName)
290
- entry != nil && entry.file?
291
- end
296
+ !entry.nil? && entry.file?
297
+ end
292
298
 
293
299
  def dirname(fileName)
294
300
  ::File.dirname(fileName)
@@ -307,9 +313,9 @@ module Zip
307
313
  end
308
314
 
309
315
  def utime(modifiedTime, *fileNames)
310
- fileNames.each { |fileName|
316
+ fileNames.each do |fileName|
311
317
  get_entry(fileName).time = modifiedTime
312
- }
318
+ end
313
319
  end
314
320
 
315
321
  def mtime(fileName)
@@ -318,70 +324,64 @@ module Zip
318
324
 
319
325
  def atime(fileName)
320
326
  e = get_entry(fileName)
321
- if e.extra.member? "UniversalTime"
322
- e.extra["UniversalTime"].atime
323
- elsif e.extra.member? "NTFS"
324
- e.extra["NTFS"].atime
325
- else
326
- nil
327
+ if e.extra.member? 'UniversalTime'
328
+ e.extra['UniversalTime'].atime
329
+ elsif e.extra.member? 'NTFS'
330
+ e.extra['NTFS'].atime
327
331
  end
328
332
  end
329
333
 
330
334
  def ctime(fileName)
331
335
  e = get_entry(fileName)
332
- if e.extra.member? "UniversalTime"
333
- e.extra["UniversalTime"].ctime
334
- elsif e.extra.member? "NTFS"
335
- e.extra["NTFS"].ctime
336
- else
337
- nil
336
+ if e.extra.member? 'UniversalTime'
337
+ e.extra['UniversalTime'].ctime
338
+ elsif e.extra.member? 'NTFS'
339
+ e.extra['NTFS'].ctime
338
340
  end
339
341
  end
340
342
 
341
- def pipe?(filename)
343
+ def pipe?(_filename)
342
344
  false
343
345
  end
344
346
 
345
- def blockdev?(filename)
347
+ def blockdev?(_filename)
346
348
  false
347
349
  end
348
350
 
349
- def chardev?(filename)
351
+ def chardev?(_filename)
350
352
  false
351
353
  end
352
354
 
353
- def symlink?(fileName)
355
+ def symlink?(_fileName)
354
356
  false
355
357
  end
356
358
 
357
- def socket?(fileName)
359
+ def socket?(_fileName)
358
360
  false
359
361
  end
360
362
 
361
363
  def ftype(fileName)
362
- @mappedZip.get_entry(fileName).directory? ? "directory" : "file"
364
+ @mappedZip.get_entry(fileName).directory? ? 'directory' : 'file'
363
365
  end
364
366
 
365
- def readlink(fileName)
366
- raise NotImplementedError, "The readlink() function is not implemented"
367
+ def readlink(_fileName)
368
+ raise NotImplementedError, 'The readlink() function is not implemented'
367
369
  end
368
370
 
369
- def symlink(fileName, symlinkName)
370
- raise NotImplementedError, "The symlink() function is not implemented"
371
+ def symlink(_fileName, _symlinkName)
372
+ raise NotImplementedError, 'The symlink() function is not implemented'
371
373
  end
372
374
 
373
- def link(fileName, symlinkName)
374
- raise NotImplementedError, "The link() function is not implemented"
375
+ def link(_fileName, _symlinkName)
376
+ raise NotImplementedError, 'The link() function is not implemented'
375
377
  end
376
378
 
377
379
  def pipe
378
- raise NotImplementedError, "The pipe() function is not implemented"
380
+ raise NotImplementedError, 'The pipe() function is not implemented'
379
381
  end
380
382
 
381
383
  def stat(fileName)
382
- if ! exists?(fileName)
383
- raise Errno::ENOENT, fileName
384
- end
384
+ raise Errno::ENOENT, fileName unless exists?(fileName)
385
385
  ZipFsStat.new(self, fileName)
386
386
  end
387
387
 
@@ -404,20 +404,19 @@ module Zip
404
404
  end
405
405
 
406
406
  def delete(*args)
407
- args.each {
408
- |fileName|
407
+ args.each do |fileName|
409
408
  if directory?(fileName)
410
409
  raise Errno::EISDIR, "Is a directory - \"#{fileName}\""
411
410
  end
412
411
  @mappedZip.remove(fileName)
413
- }
412
+ end
414
413
  end
415
414
 
416
415
  def rename(fileToRename, newName)
417
416
  @mappedZip.rename(fileToRename, newName) { true }
418
417
  end
419
418
 
420
- alias :unlink :delete
419
+ alias unlink delete
421
420
 
422
421
  def expand_path(aPath)
423
422
  @mappedZip.expand_path(aPath)
@@ -431,7 +430,6 @@ module Zip
431
430
  # The individual methods are not documented due to their
432
431
  # similarity with the methods in Dir
433
432
  class ZipFsDir
434
-
435
433
  def initialize(mappedZip)
436
434
  @mappedZip = mappedZip
437
435
  end
@@ -455,7 +453,9 @@ module Zip
455
453
  dirIt
456
454
  end
457
455
 
458
- def pwd; @mappedZip.pwd; end
456
+ def pwd
457
+ @mappedZip.pwd
458
+ end
459
459
  alias getwd pwd
460
460
 
461
461
  def chdir(aDirectoryName)
@@ -471,8 +471,8 @@ module Zip
471
471
  entries
472
472
  end
473
473
 
474
- def glob(*args,&block)
475
- @mappedZip.glob(*args,&block)
474
+ def glob(*args, &block)
475
+ @mappedZip.glob(*args, &block)
476
476
  end
477
477
 
478
478
  def foreach(aDirectoryName)
@@ -483,11 +483,10 @@ module Zip
483
483
  path << '/' unless path.end_with?('/')
484
484
  path = Regexp.escape(path)
485
485
  subDirEntriesRegex = Regexp.new("^#{path}([^/]+)$")
486
- @mappedZip.each {
487
- |fileName|
486
+ @mappedZip.each do |fileName|
488
487
  match = subDirEntriesRegex.match(fileName)
489
- yield(match[1]) unless match == nil
490
- }
488
+ yield(match[1]) unless match.nil?
489
+ end
491
490
  end
492
491
 
493
492
  def delete(entryName)
@@ -496,17 +495,16 @@ module Zip
496
495
  end
497
496
  @mappedZip.remove(entryName)
498
497
  end
499
- alias rmdir delete
498
+ alias rmdir delete
500
499
  alias unlink delete
501
500
 
502
- def mkdir(entryName, permissionInt = 0755)
501
+ def mkdir(entryName, permissionInt = 0o755)
503
502
  @mappedZip.mkdir(entryName, permissionInt)
504
503
  end
505
504
 
506
- def chroot(*args)
507
- raise NotImplementedError, "The chroot() function is not implemented"
505
+ def chroot(*_args)
506
+ raise NotImplementedError, 'The chroot() function is not implemented'
508
507
  end
509
-
510
508
  end
511
509
 
512
510
  class ZipFsDirIterator # :nodoc:all
@@ -522,27 +520,27 @@ module Zip
522
520
  end
523
521
 
524
522
  def each(&aProc)
525
- raise IOError, "closed directory" if @fileNames == nil
523
+ raise IOError, 'closed directory' if @fileNames.nil?
526
524
  @fileNames.each(&aProc)
527
525
  end
528
526
 
529
527
  def read
530
- raise IOError, "closed directory" if @fileNames == nil
531
- @fileNames[(@index+=1)-1]
528
+ raise IOError, 'closed directory' if @fileNames.nil?
529
+ @fileNames[(@index += 1) - 1]
532
530
  end
533
531
 
534
532
  def rewind
535
- raise IOError, "closed directory" if @fileNames == nil
533
+ raise IOError, 'closed directory' if @fileNames.nil?
536
534
  @index = 0
537
535
  end
538
536
 
539
537
  def seek(anIntegerPosition)
540
- raise IOError, "closed directory" if @fileNames == nil
538
+ raise IOError, 'closed directory' if @fileNames.nil?
541
539
  @index = anIntegerPosition
542
540
  end
543
541
 
544
542
  def tell
545
- raise IOError, "closed directory" if @fileNames == nil
543
+ raise IOError, 'closed directory' if @fileNames.nil?
546
544
  @index
547
545
  end
548
546
  end
@@ -554,7 +552,7 @@ module Zip
554
552
 
555
553
  def initialize(zipFile)
556
554
  @zipFile = zipFile
557
- @pwd = "/"
555
+ @pwd = '/'
558
556
  end
559
557
 
560
558
  attr_accessor :pwd
@@ -575,6 +573,10 @@ module Zip
575
573
  @zipFile.get_output_stream(expand_to_entry(fileName), permissionInt, &aProc)
576
574
  end
577
575
 
576
+ def glob(pattern, *flags, &block)
577
+ @zipFile.glob(expand_to_entry(pattern), *flags, &block)
578
+ end
579
+
578
580
  def read(fileName)
579
581
  @zipFile.read(expand_to_entry(fileName))
580
582
  end
@@ -584,28 +586,27 @@ module Zip
584
586
  end
585
587
 
586
588
  def rename(fileName, newName, &continueOnExistsProc)
587
- @zipFile.rename(expand_to_entry(fileName), expand_to_entry(newName),
589
+ @zipFile.rename(expand_to_entry(fileName), expand_to_entry(newName),
588
590
  &continueOnExistsProc)
589
591
  end
590
592
 
591
- def mkdir(fileName, permissionInt = 0755)
593
+ def mkdir(fileName, permissionInt = 0o755)
592
594
  @zipFile.mkdir(expand_to_entry(fileName), permissionInt)
593
595
  end
594
596
 
595
597
  # Turns entries into strings and adds leading /
596
598
  # and removes trailing slash on directories
597
599
  def each
598
- @zipFile.each {
599
- |e|
600
- yield("/"+e.to_s.chomp("/"))
601
- }
600
+ @zipFile.each do |e|
601
+ yield('/' + e.to_s.chomp('/'))
602
+ end
602
603
  end
603
604
 
604
605
  def expand_path(aPath)
605
- expanded = aPath.start_with?("/") ? aPath : ::File.join(@pwd, aPath)
606
- expanded.gsub!(/\/\.(\/|$)/, "")
607
- expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, "")
608
- expanded.empty? ? "/" : expanded
606
+ expanded = aPath.start_with?('/') ? aPath : ::File.join(@pwd, aPath)
607
+ expanded.gsub!(/\/\.(\/|$)/, '')
608
+ expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '')
609
+ expanded.empty? ? '/' : expanded
609
610
  end
610
611
 
611
612
  private