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