rubyzip 1.3.0 → 3.0.0.alpha

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.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +368 -0
  3. data/README.md +123 -46
  4. data/Rakefile +13 -6
  5. data/lib/zip/central_directory.rb +166 -116
  6. data/lib/zip/compressor.rb +3 -1
  7. data/lib/zip/constants.rb +77 -21
  8. data/lib/zip/crypto/decrypted_io.rb +42 -0
  9. data/lib/zip/crypto/encryption.rb +4 -2
  10. data/lib/zip/crypto/null_encryption.rb +5 -3
  11. data/lib/zip/crypto/traditional_encryption.rb +14 -12
  12. data/lib/zip/decompressor.rb +21 -2
  13. data/lib/zip/deflater.rb +10 -8
  14. data/lib/zip/dirtyable.rb +32 -0
  15. data/lib/zip/dos_time.rb +53 -12
  16. data/lib/zip/entry.rb +306 -184
  17. data/lib/zip/entry_set.rb +11 -7
  18. data/lib/zip/errors.rb +115 -15
  19. data/lib/zip/extra_field/generic.rb +11 -17
  20. data/lib/zip/extra_field/ntfs.rb +8 -2
  21. data/lib/zip/extra_field/old_unix.rb +6 -2
  22. data/lib/zip/extra_field/universal_time.rb +45 -13
  23. data/lib/zip/extra_field/unix.rb +7 -3
  24. data/lib/zip/extra_field/unknown.rb +33 -0
  25. data/lib/zip/extra_field/zip64.rb +16 -7
  26. data/lib/zip/extra_field.rb +22 -26
  27. data/lib/zip/file.rb +196 -240
  28. data/lib/zip/file_split.rb +97 -0
  29. data/lib/zip/filesystem/dir.rb +86 -0
  30. data/lib/zip/filesystem/directory_iterator.rb +48 -0
  31. data/lib/zip/filesystem/file.rb +262 -0
  32. data/lib/zip/filesystem/file_stat.rb +110 -0
  33. data/lib/zip/filesystem/zip_file_name_mapper.rb +81 -0
  34. data/lib/zip/filesystem.rb +31 -584
  35. data/lib/zip/inflater.rb +27 -37
  36. data/lib/zip/input_stream.rb +67 -42
  37. data/lib/zip/ioextras/abstract_input_stream.rb +32 -16
  38. data/lib/zip/ioextras/abstract_output_stream.rb +5 -3
  39. data/lib/zip/ioextras.rb +7 -7
  40. data/lib/zip/null_compressor.rb +3 -1
  41. data/lib/zip/null_decompressor.rb +4 -10
  42. data/lib/zip/null_input_stream.rb +3 -1
  43. data/lib/zip/output_stream.rb +58 -43
  44. data/lib/zip/pass_thru_compressor.rb +5 -3
  45. data/lib/zip/pass_thru_decompressor.rb +16 -23
  46. data/lib/zip/streamable_directory.rb +6 -4
  47. data/lib/zip/streamable_stream.rb +9 -10
  48. data/lib/zip/version.rb +3 -1
  49. data/lib/zip.rb +19 -4
  50. data/rubyzip.gemspec +38 -0
  51. data/samples/example.rb +9 -4
  52. data/samples/example_filesystem.rb +3 -2
  53. data/samples/example_recursive.rb +3 -1
  54. data/samples/gtk_ruby_zip.rb +22 -20
  55. data/samples/qtzip.rb +12 -11
  56. data/samples/write_simple.rb +3 -4
  57. data/samples/zipfind.rb +24 -22
  58. metadata +86 -179
  59. data/TODO +0 -15
  60. data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
  61. data/test/basic_zip_file_test.rb +0 -60
  62. data/test/case_sensitivity_test.rb +0 -69
  63. data/test/central_directory_entry_test.rb +0 -69
  64. data/test/central_directory_test.rb +0 -100
  65. data/test/crypto/null_encryption_test.rb +0 -57
  66. data/test/crypto/traditional_encryption_test.rb +0 -80
  67. data/test/data/WarnInvalidDate.zip +0 -0
  68. data/test/data/file1.txt +0 -46
  69. data/test/data/file1.txt.deflatedData +0 -0
  70. data/test/data/file2.txt +0 -1504
  71. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  72. data/test/data/globTest/foo.txt +0 -0
  73. data/test/data/globTest/food.txt +0 -0
  74. data/test/data/globTest.zip +0 -0
  75. data/test/data/gpbit3stored.zip +0 -0
  76. data/test/data/mimetype +0 -1
  77. data/test/data/notzippedruby.rb +0 -7
  78. data/test/data/ntfs.zip +0 -0
  79. data/test/data/oddExtraField.zip +0 -0
  80. data/test/data/path_traversal/Makefile +0 -10
  81. data/test/data/path_traversal/jwilk/README.md +0 -5
  82. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  83. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  84. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  85. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  86. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  87. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  88. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  89. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  90. data/test/data/path_traversal/relative1.zip +0 -0
  91. data/test/data/path_traversal/tilde.zip +0 -0
  92. data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
  93. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  94. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  95. data/test/data/rubycode.zip +0 -0
  96. data/test/data/rubycode2.zip +0 -0
  97. data/test/data/test.xls +0 -0
  98. data/test/data/testDirectory.bin +0 -0
  99. data/test/data/zip64-sample.zip +0 -0
  100. data/test/data/zipWithDirs.zip +0 -0
  101. data/test/data/zipWithEncryption.zip +0 -0
  102. data/test/deflater_test.rb +0 -65
  103. data/test/encryption_test.rb +0 -42
  104. data/test/entry_set_test.rb +0 -163
  105. data/test/entry_test.rb +0 -154
  106. data/test/errors_test.rb +0 -35
  107. data/test/extra_field_test.rb +0 -76
  108. data/test/file_extract_directory_test.rb +0 -54
  109. data/test/file_extract_test.rb +0 -145
  110. data/test/file_permissions_test.rb +0 -65
  111. data/test/file_split_test.rb +0 -57
  112. data/test/file_test.rb +0 -666
  113. data/test/filesystem/dir_iterator_test.rb +0 -58
  114. data/test/filesystem/directory_test.rb +0 -139
  115. data/test/filesystem/file_mutating_test.rb +0 -87
  116. data/test/filesystem/file_nonmutating_test.rb +0 -508
  117. data/test/filesystem/file_stat_test.rb +0 -64
  118. data/test/gentestfiles.rb +0 -126
  119. data/test/inflater_test.rb +0 -14
  120. data/test/input_stream_test.rb +0 -182
  121. data/test/ioextras/abstract_input_stream_test.rb +0 -102
  122. data/test/ioextras/abstract_output_stream_test.rb +0 -106
  123. data/test/ioextras/fake_io_test.rb +0 -18
  124. data/test/local_entry_test.rb +0 -154
  125. data/test/output_stream_test.rb +0 -128
  126. data/test/pass_thru_compressor_test.rb +0 -30
  127. data/test/pass_thru_decompressor_test.rb +0 -14
  128. data/test/path_traversal_test.rb +0 -141
  129. data/test/samples/example_recursive_test.rb +0 -37
  130. data/test/settings_test.rb +0 -95
  131. data/test/test_helper.rb +0 -234
  132. data/test/unicode_file_names_and_comments_test.rb +0 -62
  133. data/test/zip64_full_test.rb +0 -51
  134. data/test/zip64_support_test.rb +0 -14
@@ -1,4 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zip'
4
+ require_relative 'filesystem/zip_file_name_mapper'
5
+ require_relative 'filesystem/directory_iterator'
6
+ require_relative 'filesystem/dir'
7
+ require_relative 'filesystem/file'
2
8
 
3
9
  module Zip
4
10
  # The ZipFileSystem API provides an API for accessing entries in
@@ -13,607 +19,48 @@ module Zip
13
19
  # <code>first.txt</code>, a directory entry named <code>mydir</code>
14
20
  # and finally another normal entry named <code>second.txt</code>
15
21
  #
16
- # require 'zip/filesystem'
22
+ # ```
23
+ # require 'zip/filesystem'
17
24
  #
18
- # Zip::File.open("my.zip", Zip::File::CREATE) {
19
- # |zipfile|
20
- # zipfile.file.open("first.txt", "w") { |f| f.puts "Hello world" }
21
- # zipfile.dir.mkdir("mydir")
22
- # zipfile.file.open("mydir/second.txt", "w") { |f| f.puts "Hello again" }
23
- # }
25
+ # Zip::File.open('my.zip', create: true) do |zipfile|
26
+ # zipfile.file.open('first.txt', 'w') { |f| f.puts 'Hello world' }
27
+ # zipfile.dir.mkdir('mydir')
28
+ # zipfile.file.open('mydir/second.txt', 'w') { |f| f.puts 'Hello again' }
29
+ # end
30
+ # ```
24
31
  #
25
32
  # Reading is as easy as writing, as the following example shows. The
26
33
  # example writes the contents of <code>first.txt</code> from zip archive
27
34
  # <code>my.zip</code> to standard out.
28
35
  #
29
- # require 'zip/filesystem'
36
+ # ```
37
+ # require 'zip/filesystem'
30
38
  #
31
- # Zip::File.open("my.zip") {
32
- # |zipfile|
33
- # puts zipfile.file.read("first.txt")
34
- # }
35
-
39
+ # Zip::File.open('my.zip') do |zipfile|
40
+ # puts zipfile.file.read('first.txt')
41
+ # end
42
+ # ```
36
43
  module FileSystem
37
44
  def initialize # :nodoc:
38
- mappedZip = ZipFileNameMapper.new(self)
39
- @zipFsDir = ZipFsDir.new(mappedZip)
40
- @zipFsFile = ZipFsFile.new(mappedZip)
41
- @zipFsDir.file = @zipFsFile
42
- @zipFsFile.dir = @zipFsDir
45
+ mapped_zip = ZipFileNameMapper.new(self)
46
+ @zip_fs_dir = Dir.new(mapped_zip)
47
+ @zip_fs_file = File.new(mapped_zip)
48
+ @zip_fs_dir.file = @zip_fs_file
49
+ @zip_fs_file.dir = @zip_fs_dir
43
50
  end
44
51
 
45
- # Returns a ZipFsDir which is much like ruby's builtin Dir (class)
46
- # object, except it works on the Zip::File on which this method is
52
+ # Returns a Zip::FileSystem::Dir which is much like ruby's builtin Dir
53
+ # (class) object, except it works on the Zip::File on which this method is
47
54
  # invoked
48
55
  def dir
49
- @zipFsDir
56
+ @zip_fs_dir
50
57
  end
51
58
 
52
- # Returns a ZipFsFile which is much like ruby's builtin File (class)
53
- # object, except it works on the Zip::File on which this method is
59
+ # Returns a Zip::FileSystem::File which is much like ruby's builtin File
60
+ # (class) object, except it works on the Zip::File on which this method is
54
61
  # invoked
55
62
  def file
56
- @zipFsFile
57
- end
58
-
59
- # Instances of this class are normally accessed via the accessor
60
- # Zip::File::file. An instance of ZipFsFile behaves like ruby's
61
- # builtin File (class) object, except it works on Zip::File entries.
62
- #
63
- # The individual methods are not documented due to their
64
- # similarity with the methods in File
65
- class ZipFsFile
66
- attr_writer :dir
67
- # protected :dir
68
-
69
- class ZipFsStat
70
- class << self
71
- def delegate_to_fs_file(*methods)
72
- methods.each do |method|
73
- class_eval <<-end_eval, __FILE__, __LINE__ + 1
74
- def #{method} # def file?
75
- @zipFsFile.#{method}(@entryName) # @zipFsFile.file?(@entryName)
76
- end # end
77
- end_eval
78
- end
79
- end
80
- end
81
-
82
- def initialize(zipFsFile, entryName)
83
- @zipFsFile = zipFsFile
84
- @entryName = entryName
85
- end
86
-
87
- def kind_of?(t)
88
- super || t == ::File::Stat
89
- end
90
-
91
- delegate_to_fs_file :file?, :directory?, :pipe?, :chardev?, :symlink?,
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
95
-
96
- def blocks
97
- nil
98
- end
99
-
100
- def get_entry
101
- @zipFsFile.__send__(:get_entry, @entryName)
102
- end
103
- private :get_entry
104
-
105
- def gid
106
- e = get_entry
107
- if e.extra.member? 'IUnix'
108
- e.extra['IUnix'].gid || 0
109
- else
110
- 0
111
- end
112
- end
113
-
114
- def uid
115
- e = get_entry
116
- if e.extra.member? 'IUnix'
117
- e.extra['IUnix'].uid || 0
118
- else
119
- 0
120
- end
121
- end
122
-
123
- def ino
124
- 0
125
- end
126
-
127
- def dev
128
- 0
129
- end
130
-
131
- def rdev
132
- 0
133
- end
134
-
135
- def rdev_major
136
- 0
137
- end
138
-
139
- def rdev_minor
140
- 0
141
- end
142
-
143
- def ftype
144
- if file?
145
- 'file'
146
- elsif directory?
147
- 'directory'
148
- else
149
- raise StandardError, 'Unknown file type'
150
- end
151
- end
152
-
153
- def nlink
154
- 1
155
- end
156
-
157
- def blksize
158
- nil
159
- end
160
-
161
- def mode
162
- e = get_entry
163
- if e.fstype == 3
164
- e.external_file_attributes >> 16
165
- else
166
- 33_206 # 33206 is equivalent to -rw-rw-rw-
167
- end
168
- end
169
- end
170
-
171
- def initialize(mappedZip)
172
- @mappedZip = mappedZip
173
- end
174
-
175
- def get_entry(fileName)
176
- unless exists?(fileName)
177
- raise Errno::ENOENT, "No such file or directory - #{fileName}"
178
- end
179
- @mappedZip.find_entry(fileName)
180
- end
181
- private :get_entry
182
-
183
- def unix_mode_cmp(fileName, mode)
184
- e = get_entry(fileName)
185
- e.fstype == 3 && ((e.external_file_attributes >> 16) & mode) != 0
186
- rescue Errno::ENOENT
187
- false
188
- end
189
- private :unix_mode_cmp
190
-
191
- def exists?(fileName)
192
- expand_path(fileName) == '/' || !@mappedZip.find_entry(fileName).nil?
193
- end
194
- alias exist? exists?
195
-
196
- # Permissions not implemented, so if the file exists it is accessible
197
- alias owned? exists?
198
- alias grpowned? exists?
199
-
200
- def readable?(fileName)
201
- unix_mode_cmp(fileName, 0o444)
202
- end
203
- alias readable_real? readable?
204
-
205
- def writable?(fileName)
206
- unix_mode_cmp(fileName, 0o222)
207
- end
208
- alias writable_real? writable?
209
-
210
- def executable?(fileName)
211
- unix_mode_cmp(fileName, 0o111)
212
- end
213
- alias executable_real? executable?
214
-
215
- def setuid?(fileName)
216
- unix_mode_cmp(fileName, 0o4000)
217
- end
218
-
219
- def setgid?(fileName)
220
- unix_mode_cmp(fileName, 0o2000)
221
- end
222
-
223
- def sticky?(fileName)
224
- unix_mode_cmp(fileName, 0o1000)
225
- end
226
-
227
- def umask(*args)
228
- ::File.umask(*args)
229
- end
230
-
231
- def truncate(_fileName, _len)
232
- raise StandardError, 'truncate not supported'
233
- end
234
-
235
- def directory?(fileName)
236
- entry = @mappedZip.find_entry(fileName)
237
- expand_path(fileName) == '/' || (!entry.nil? && entry.directory?)
238
- end
239
-
240
- def open(fileName, openMode = 'r', permissionInt = 0o644, &block)
241
- openMode.delete!('b') # ignore b option
242
- case openMode
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'
249
- end
250
- end
251
-
252
- def new(fileName, openMode = 'r')
253
- open(fileName, openMode)
254
- end
255
-
256
- def size(fileName)
257
- @mappedZip.get_entry(fileName).size
258
- end
259
-
260
- # Returns nil for not found and nil for directories
261
- def size?(fileName)
262
- entry = @mappedZip.find_entry(fileName)
263
- entry.nil? || entry.directory? ? nil : entry.size
264
- end
265
-
266
- def chown(ownerInt, groupInt, *filenames)
267
- filenames.each do |fileName|
268
- e = get_entry(fileName)
269
- e.extra.create('IUnix') unless e.extra.member?('IUnix')
270
- e.extra['IUnix'].uid = ownerInt
271
- e.extra['IUnix'].gid = groupInt
272
- end
273
- filenames.size
274
- end
275
-
276
- def chmod(modeInt, *filenames)
277
- filenames.each do |fileName|
278
- e = get_entry(fileName)
279
- e.fstype = 3 # force convertion filesystem type to unix
280
- e.unix_perms = modeInt
281
- e.external_file_attributes = modeInt << 16
282
- e.dirty = true
283
- end
284
- filenames.size
285
- end
286
-
287
- def zero?(fileName)
288
- sz = size(fileName)
289
- sz.nil? || sz == 0
290
- rescue Errno::ENOENT
291
- false
292
- end
293
-
294
- def file?(fileName)
295
- entry = @mappedZip.find_entry(fileName)
296
- !entry.nil? && entry.file?
297
- end
298
-
299
- def dirname(fileName)
300
- ::File.dirname(fileName)
301
- end
302
-
303
- def basename(fileName)
304
- ::File.basename(fileName)
305
- end
306
-
307
- def split(fileName)
308
- ::File.split(fileName)
309
- end
310
-
311
- def join(*fragments)
312
- ::File.join(*fragments)
313
- end
314
-
315
- def utime(modifiedTime, *fileNames)
316
- fileNames.each do |fileName|
317
- get_entry(fileName).time = modifiedTime
318
- end
319
- end
320
-
321
- def mtime(fileName)
322
- @mappedZip.get_entry(fileName).mtime
323
- end
324
-
325
- def atime(fileName)
326
- e = get_entry(fileName)
327
- if e.extra.member? 'UniversalTime'
328
- e.extra['UniversalTime'].atime
329
- elsif e.extra.member? 'NTFS'
330
- e.extra['NTFS'].atime
331
- end
332
- end
333
-
334
- def ctime(fileName)
335
- e = get_entry(fileName)
336
- if e.extra.member? 'UniversalTime'
337
- e.extra['UniversalTime'].ctime
338
- elsif e.extra.member? 'NTFS'
339
- e.extra['NTFS'].ctime
340
- end
341
- end
342
-
343
- def pipe?(_filename)
344
- false
345
- end
346
-
347
- def blockdev?(_filename)
348
- false
349
- end
350
-
351
- def chardev?(_filename)
352
- false
353
- end
354
-
355
- def symlink?(_fileName)
356
- false
357
- end
358
-
359
- def socket?(_fileName)
360
- false
361
- end
362
-
363
- def ftype(fileName)
364
- @mappedZip.get_entry(fileName).directory? ? 'directory' : 'file'
365
- end
366
-
367
- def readlink(_fileName)
368
- raise NotImplementedError, 'The readlink() function is not implemented'
369
- end
370
-
371
- def symlink(_fileName, _symlinkName)
372
- raise NotImplementedError, 'The symlink() function is not implemented'
373
- end
374
-
375
- def link(_fileName, _symlinkName)
376
- raise NotImplementedError, 'The link() function is not implemented'
377
- end
378
-
379
- def pipe
380
- raise NotImplementedError, 'The pipe() function is not implemented'
381
- end
382
-
383
- def stat(fileName)
384
- raise Errno::ENOENT, fileName unless exists?(fileName)
385
- ZipFsStat.new(self, fileName)
386
- end
387
-
388
- alias lstat stat
389
-
390
- def readlines(fileName)
391
- open(fileName) { |is| is.readlines }
392
- end
393
-
394
- def read(fileName)
395
- @mappedZip.read(fileName)
396
- end
397
-
398
- def popen(*args, &aProc)
399
- ::File.popen(*args, &aProc)
400
- end
401
-
402
- def foreach(fileName, aSep = $/, &aProc)
403
- open(fileName) { |is| is.each_line(aSep, &aProc) }
404
- end
405
-
406
- def delete(*args)
407
- args.each do |fileName|
408
- if directory?(fileName)
409
- raise Errno::EISDIR, "Is a directory - \"#{fileName}\""
410
- end
411
- @mappedZip.remove(fileName)
412
- end
413
- end
414
-
415
- def rename(fileToRename, newName)
416
- @mappedZip.rename(fileToRename, newName) { true }
417
- end
418
-
419
- alias unlink delete
420
-
421
- def expand_path(aPath)
422
- @mappedZip.expand_path(aPath)
423
- end
424
- end
425
-
426
- # Instances of this class are normally accessed via the accessor
427
- # ZipFile::dir. An instance of ZipFsDir behaves like ruby's
428
- # builtin Dir (class) object, except it works on ZipFile entries.
429
- #
430
- # The individual methods are not documented due to their
431
- # similarity with the methods in Dir
432
- class ZipFsDir
433
- def initialize(mappedZip)
434
- @mappedZip = mappedZip
435
- end
436
-
437
- attr_writer :file
438
-
439
- def new(aDirectoryName)
440
- ZipFsDirIterator.new(entries(aDirectoryName))
441
- end
442
-
443
- def open(aDirectoryName)
444
- dirIt = new(aDirectoryName)
445
- if block_given?
446
- begin
447
- yield(dirIt)
448
- return nil
449
- ensure
450
- dirIt.close
451
- end
452
- end
453
- dirIt
454
- end
455
-
456
- def pwd
457
- @mappedZip.pwd
458
- end
459
- alias getwd pwd
460
-
461
- def chdir(aDirectoryName)
462
- unless @file.stat(aDirectoryName).directory?
463
- raise Errno::EINVAL, "Invalid argument - #{aDirectoryName}"
464
- end
465
- @mappedZip.pwd = @file.expand_path(aDirectoryName)
466
- end
467
-
468
- def entries(aDirectoryName)
469
- entries = []
470
- foreach(aDirectoryName) { |e| entries << e }
471
- entries
472
- end
473
-
474
- def glob(*args, &block)
475
- @mappedZip.glob(*args, &block)
476
- end
477
-
478
- def foreach(aDirectoryName)
479
- unless @file.stat(aDirectoryName).directory?
480
- raise Errno::ENOTDIR, aDirectoryName
481
- end
482
- path = @file.expand_path(aDirectoryName)
483
- path << '/' unless path.end_with?('/')
484
- path = Regexp.escape(path)
485
- subDirEntriesRegex = Regexp.new("^#{path}([^/]+)$")
486
- @mappedZip.each do |fileName|
487
- match = subDirEntriesRegex.match(fileName)
488
- yield(match[1]) unless match.nil?
489
- end
490
- end
491
-
492
- def delete(entryName)
493
- unless @file.stat(entryName).directory?
494
- raise Errno::EINVAL, "Invalid argument - #{entryName}"
495
- end
496
- @mappedZip.remove(entryName)
497
- end
498
- alias rmdir delete
499
- alias unlink delete
500
-
501
- def mkdir(entryName, permissionInt = 0o755)
502
- @mappedZip.mkdir(entryName, permissionInt)
503
- end
504
-
505
- def chroot(*_args)
506
- raise NotImplementedError, 'The chroot() function is not implemented'
507
- end
508
- end
509
-
510
- class ZipFsDirIterator # :nodoc:all
511
- include Enumerable
512
-
513
- def initialize(arrayOfFileNames)
514
- @fileNames = arrayOfFileNames
515
- @index = 0
516
- end
517
-
518
- def close
519
- @fileNames = nil
520
- end
521
-
522
- def each(&aProc)
523
- raise IOError, 'closed directory' if @fileNames.nil?
524
- @fileNames.each(&aProc)
525
- end
526
-
527
- def read
528
- raise IOError, 'closed directory' if @fileNames.nil?
529
- @fileNames[(@index += 1) - 1]
530
- end
531
-
532
- def rewind
533
- raise IOError, 'closed directory' if @fileNames.nil?
534
- @index = 0
535
- end
536
-
537
- def seek(anIntegerPosition)
538
- raise IOError, 'closed directory' if @fileNames.nil?
539
- @index = anIntegerPosition
540
- end
541
-
542
- def tell
543
- raise IOError, 'closed directory' if @fileNames.nil?
544
- @index
545
- end
546
- end
547
-
548
- # All access to Zip::File from ZipFsFile and ZipFsDir goes through a
549
- # ZipFileNameMapper, which has one responsibility: ensure
550
- class ZipFileNameMapper # :nodoc:all
551
- include Enumerable
552
-
553
- def initialize(zipFile)
554
- @zipFile = zipFile
555
- @pwd = '/'
556
- end
557
-
558
- attr_accessor :pwd
559
-
560
- def find_entry(fileName)
561
- @zipFile.find_entry(expand_to_entry(fileName))
562
- end
563
-
564
- def get_entry(fileName)
565
- @zipFile.get_entry(expand_to_entry(fileName))
566
- end
567
-
568
- def get_input_stream(fileName, &aProc)
569
- @zipFile.get_input_stream(expand_to_entry(fileName), &aProc)
570
- end
571
-
572
- def get_output_stream(fileName, permissionInt = nil, &aProc)
573
- @zipFile.get_output_stream(expand_to_entry(fileName), permissionInt, &aProc)
574
- end
575
-
576
- def glob(pattern, *flags, &block)
577
- @zipFile.glob(expand_to_entry(pattern), *flags, &block)
578
- end
579
-
580
- def read(fileName)
581
- @zipFile.read(expand_to_entry(fileName))
582
- end
583
-
584
- def remove(fileName)
585
- @zipFile.remove(expand_to_entry(fileName))
586
- end
587
-
588
- def rename(fileName, newName, &continueOnExistsProc)
589
- @zipFile.rename(expand_to_entry(fileName), expand_to_entry(newName),
590
- &continueOnExistsProc)
591
- end
592
-
593
- def mkdir(fileName, permissionInt = 0o755)
594
- @zipFile.mkdir(expand_to_entry(fileName), permissionInt)
595
- end
596
-
597
- # Turns entries into strings and adds leading /
598
- # and removes trailing slash on directories
599
- def each
600
- @zipFile.each do |e|
601
- yield('/' + e.to_s.chomp('/'))
602
- end
603
- end
604
-
605
- def expand_path(aPath)
606
- expanded = aPath.start_with?('/') ? aPath : ::File.join(@pwd, aPath)
607
- expanded.gsub!(/\/\.(\/|$)/, '')
608
- expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '')
609
- expanded.empty? ? '/' : expanded
610
- end
611
-
612
- private
613
-
614
- def expand_to_entry(aPath)
615
- expand_path(aPath)[1..-1]
616
- end
63
+ @zip_fs_file
617
64
  end
618
65
  end
619
66