rubyzip 0.9.4 → 0.9.5
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.
- data/{README → README.md} +16 -17
- data/Rakefile +6 -104
- data/lib/zip/compressor.rb +10 -0
- data/lib/zip/constants.rb +10 -0
- data/lib/zip/decompressor.rb +13 -0
- data/lib/zip/deflater.rb +30 -0
- data/lib/zip/inflater.rb +65 -0
- data/lib/zip/ioextras.rb +35 -36
- data/lib/zip/null_compressor.rb +15 -0
- data/lib/zip/null_decompressor.rb +25 -0
- data/lib/zip/null_input_stream.rb +9 -0
- data/lib/zip/pass_thru_compressor.rb +23 -0
- data/lib/zip/pass_thru_decompressor.rb +40 -0
- data/lib/zip/stdrubyext.rb +10 -44
- data/lib/zip/zip.rb +22 -1848
- data/lib/zip/zip_central_directory.rb +139 -0
- data/lib/zip/zip_entry.rb +639 -0
- data/lib/zip/zip_entry_set.rb +66 -0
- data/lib/zip/zip_extra_field.rb +213 -0
- data/lib/zip/zip_file.rb +318 -0
- data/lib/zip/zip_input_stream.rb +134 -0
- data/lib/zip/zip_output_stream.rb +172 -0
- data/lib/zip/zip_streamable_directory.rb +15 -0
- data/lib/zip/zip_streamable_stream.rb +47 -0
- data/lib/zip/zipfilesystem.rb +90 -88
- data/samples/example_recursive.rb +49 -0
- metadata +54 -60
- data/ChangeLog +0 -1146
- data/install.rb +0 -23
- data/lib/zip/ziprequire.rb +0 -90
- data/test/alltests.rb +0 -9
- 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/notzippedruby.rb +0 -7
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/gentestfiles.rb +0 -157
- data/test/ioextrastest.rb +0 -208
- data/test/stdrubyexttest.rb +0 -52
- data/test/zipfilesystemtest.rb +0 -841
- data/test/ziprequiretest.rb +0 -43
- data/test/ziptest.rb +0 -1620
@@ -0,0 +1,134 @@
|
|
1
|
+
module Zip
|
2
|
+
# ZipInputStream is the basic class for reading zip entries in a
|
3
|
+
# zip file. It is possible to create a ZipInputStream object directly,
|
4
|
+
# passing the zip file name to the constructor, but more often than not
|
5
|
+
# the ZipInputStream will be obtained from a ZipFile (perhaps using the
|
6
|
+
# ZipFileSystem interface) object for a particular entry in the zip
|
7
|
+
# archive.
|
8
|
+
#
|
9
|
+
# A ZipInputStream inherits IOExtras::AbstractInputStream in order
|
10
|
+
# to provide an IO-like interface for reading from a single zip
|
11
|
+
# entry. Beyond methods for mimicking an IO-object it contains
|
12
|
+
# the method get_next_entry for iterating through the entries of
|
13
|
+
# an archive. get_next_entry returns a ZipEntry object that describes
|
14
|
+
# the zip entry the ZipInputStream is currently reading from.
|
15
|
+
#
|
16
|
+
# Example that creates a zip archive with ZipOutputStream and reads it
|
17
|
+
# back again with a ZipInputStream.
|
18
|
+
#
|
19
|
+
# require 'zip/zip'
|
20
|
+
#
|
21
|
+
# Zip::ZipOutputStream::open("my.zip") {
|
22
|
+
# |io|
|
23
|
+
#
|
24
|
+
# io.put_next_entry("first_entry.txt")
|
25
|
+
# io.write "Hello world!"
|
26
|
+
#
|
27
|
+
# io.put_next_entry("adir/first_entry.txt")
|
28
|
+
# io.write "Hello again!"
|
29
|
+
# }
|
30
|
+
#
|
31
|
+
#
|
32
|
+
# Zip::ZipInputStream::open("my.zip") {
|
33
|
+
# |io|
|
34
|
+
#
|
35
|
+
# while (entry = io.get_next_entry)
|
36
|
+
# puts "Contents of #{entry.name}: '#{io.read}'"
|
37
|
+
# end
|
38
|
+
# }
|
39
|
+
#
|
40
|
+
# java.util.zip.ZipInputStream is the original inspiration for this
|
41
|
+
# class.
|
42
|
+
|
43
|
+
class ZipInputStream
|
44
|
+
include IOExtras::AbstractInputStream
|
45
|
+
|
46
|
+
# Opens the indicated zip file. An exception is thrown
|
47
|
+
# if the specified offset in the specified filename is
|
48
|
+
# not a local zip entry header.
|
49
|
+
def initialize(filename, offset = 0)
|
50
|
+
super()
|
51
|
+
@archiveIO = File.open(filename, "rb")
|
52
|
+
@archiveIO.seek(offset, IO::SEEK_SET)
|
53
|
+
@decompressor = NullDecompressor.instance
|
54
|
+
@currentEntry = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def close
|
58
|
+
@archiveIO.close
|
59
|
+
end
|
60
|
+
|
61
|
+
# Same as #initialize but if a block is passed the opened
|
62
|
+
# stream is passed to the block and closed when the block
|
63
|
+
# returns.
|
64
|
+
def ZipInputStream.open(filename)
|
65
|
+
return new(filename) unless block_given?
|
66
|
+
|
67
|
+
zio = new(filename)
|
68
|
+
yield zio
|
69
|
+
ensure
|
70
|
+
zio.close if zio
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns a ZipEntry object. It is necessary to call this
|
74
|
+
# method on a newly created ZipInputStream before reading from
|
75
|
+
# the first entry in the archive. Returns nil when there are
|
76
|
+
# no more entries.
|
77
|
+
|
78
|
+
def get_next_entry
|
79
|
+
@archiveIO.seek(@currentEntry.next_header_offset,
|
80
|
+
IO::SEEK_SET) if @currentEntry
|
81
|
+
open_entry
|
82
|
+
end
|
83
|
+
|
84
|
+
# Rewinds the stream to the beginning of the current entry
|
85
|
+
def rewind
|
86
|
+
return if @currentEntry.nil?
|
87
|
+
@lineno = 0
|
88
|
+
@archiveIO.seek(@currentEntry.localHeaderOffset,
|
89
|
+
IO::SEEK_SET)
|
90
|
+
open_entry
|
91
|
+
end
|
92
|
+
|
93
|
+
# Modeled after IO.sysread
|
94
|
+
def sysread(numberOfBytes = nil, buf = nil)
|
95
|
+
@decompressor.sysread(numberOfBytes, buf)
|
96
|
+
end
|
97
|
+
|
98
|
+
def eof
|
99
|
+
@outputBuffer.empty? && @decompressor.eof
|
100
|
+
end
|
101
|
+
alias :eof? :eof
|
102
|
+
|
103
|
+
protected
|
104
|
+
|
105
|
+
def open_entry
|
106
|
+
@currentEntry = ZipEntry.read_local_entry(@archiveIO)
|
107
|
+
if (@currentEntry == nil)
|
108
|
+
@decompressor = NullDecompressor.instance
|
109
|
+
elsif @currentEntry.compression_method == ZipEntry::STORED
|
110
|
+
@decompressor = PassThruDecompressor.new(@archiveIO,
|
111
|
+
@currentEntry.size)
|
112
|
+
elsif @currentEntry.compression_method == ZipEntry::DEFLATED
|
113
|
+
@decompressor = Inflater.new(@archiveIO)
|
114
|
+
else
|
115
|
+
raise ZipCompressionMethodError,
|
116
|
+
"Unsupported compression method #{@currentEntry.compression_method}"
|
117
|
+
end
|
118
|
+
flush
|
119
|
+
return @currentEntry
|
120
|
+
end
|
121
|
+
|
122
|
+
def produce_input
|
123
|
+
@decompressor.produce_input
|
124
|
+
end
|
125
|
+
|
126
|
+
def input_finished?
|
127
|
+
@decompressor.input_finished?
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
133
|
+
# rubyzip is free software; you can redistribute it and/or
|
134
|
+
# modify it under the terms of the ruby license.
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module Zip
|
2
|
+
# ZipOutputStream is the basic class for writing zip files. It is
|
3
|
+
# possible to create a ZipOutputStream object directly, passing
|
4
|
+
# the zip file name to the constructor, but more often than not
|
5
|
+
# the ZipOutputStream will be obtained from a ZipFile (perhaps using the
|
6
|
+
# ZipFileSystem interface) object for a particular entry in the zip
|
7
|
+
# archive.
|
8
|
+
#
|
9
|
+
# A ZipOutputStream inherits IOExtras::AbstractOutputStream in order
|
10
|
+
# to provide an IO-like interface for writing to a single zip
|
11
|
+
# entry. Beyond methods for mimicking an IO-object it contains
|
12
|
+
# the method put_next_entry that closes the current entry
|
13
|
+
# and creates a new.
|
14
|
+
#
|
15
|
+
# Please refer to ZipInputStream for example code.
|
16
|
+
#
|
17
|
+
# java.util.zip.ZipOutputStream is the original inspiration for this
|
18
|
+
# class.
|
19
|
+
|
20
|
+
class ZipOutputStream
|
21
|
+
include IOExtras::AbstractOutputStream
|
22
|
+
|
23
|
+
attr_accessor :comment
|
24
|
+
|
25
|
+
# Opens the indicated zip file. If a file with that name already
|
26
|
+
# exists it will be overwritten.
|
27
|
+
def initialize(fileName, stream=false)
|
28
|
+
super()
|
29
|
+
@fileName = fileName
|
30
|
+
if stream
|
31
|
+
@outputStream = StringIO.new
|
32
|
+
else
|
33
|
+
@outputStream = File.new(@fileName, "wb")
|
34
|
+
end
|
35
|
+
@entrySet = ZipEntrySet.new
|
36
|
+
@compressor = NullCompressor.instance
|
37
|
+
@closed = false
|
38
|
+
@currentEntry = nil
|
39
|
+
@comment = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# Same as #initialize but if a block is passed the opened
|
43
|
+
# stream is passed to the block and closed when the block
|
44
|
+
# returns.
|
45
|
+
def ZipOutputStream.open(fileName)
|
46
|
+
return new(fileName) unless block_given?
|
47
|
+
zos = new(fileName)
|
48
|
+
yield zos
|
49
|
+
ensure
|
50
|
+
zos.close if zos
|
51
|
+
end
|
52
|
+
|
53
|
+
# Same as #open but writes to a filestream instead
|
54
|
+
def ZipOutputStream.write_buffer
|
55
|
+
zos = new('', true)
|
56
|
+
yield zos
|
57
|
+
return zos.close_buffer
|
58
|
+
end
|
59
|
+
|
60
|
+
# Closes the stream and writes the central directory to the zip file
|
61
|
+
def close
|
62
|
+
return if @closed
|
63
|
+
finalize_current_entry
|
64
|
+
update_local_headers
|
65
|
+
write_central_directory
|
66
|
+
@outputStream.close
|
67
|
+
@closed = true
|
68
|
+
end
|
69
|
+
|
70
|
+
# Closes the stream and writes the central directory to the zip file
|
71
|
+
def close_buffer
|
72
|
+
return @outputStream if @closed
|
73
|
+
finalize_current_entry
|
74
|
+
update_local_headers
|
75
|
+
write_central_directory
|
76
|
+
@closed = true
|
77
|
+
return @outputStream
|
78
|
+
end
|
79
|
+
|
80
|
+
# Closes the current entry and opens a new for writing.
|
81
|
+
# +entry+ can be a ZipEntry object or a string.
|
82
|
+
def put_next_entry(entryname, comment = nil, extra = nil, compression_method = ZipEntry::DEFLATED, level = Zlib::DEFAULT_COMPRESSION)
|
83
|
+
raise ZipError, "zip stream is closed" if @closed
|
84
|
+
new_entry = ZipEntry.new(@fileName, entryname.to_s)
|
85
|
+
new_entry.unix_perms = entryname.unix_perms if entryname.respond_to? :unix_perms
|
86
|
+
new_entry.comment = comment if !comment.nil?
|
87
|
+
if (!extra.nil?)
|
88
|
+
new_entry.extra = ZipExtraField === extra ? extra : ZipExtraField.new(extra.to_s)
|
89
|
+
end
|
90
|
+
new_entry.compression_method = compression_method
|
91
|
+
init_next_entry(new_entry, level)
|
92
|
+
@currentEntry = new_entry
|
93
|
+
end
|
94
|
+
|
95
|
+
def copy_raw_entry(entry)
|
96
|
+
entry = entry.dup
|
97
|
+
raise ZipError, "zip stream is closed" if @closed
|
98
|
+
raise ZipError, "entry is not a ZipEntry" if !entry.kind_of?(ZipEntry)
|
99
|
+
finalize_current_entry
|
100
|
+
@entrySet << entry
|
101
|
+
src_pos = entry.local_entry_offset
|
102
|
+
entry.write_local_entry(@outputStream)
|
103
|
+
@compressor = NullCompressor.instance
|
104
|
+
entry.get_raw_input_stream {
|
105
|
+
|is|
|
106
|
+
is.seek(src_pos, IO::SEEK_SET)
|
107
|
+
IOExtras.copy_stream_n(@outputStream, is, entry.compressed_size)
|
108
|
+
}
|
109
|
+
@compressor = NullCompressor.instance
|
110
|
+
@currentEntry = nil
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def finalize_current_entry
|
115
|
+
return unless @currentEntry
|
116
|
+
finish
|
117
|
+
@currentEntry.compressed_size = @outputStream.tell - @currentEntry.localHeaderOffset -
|
118
|
+
@currentEntry.calculate_local_header_size
|
119
|
+
@currentEntry.size = @compressor.size
|
120
|
+
@currentEntry.crc = @compressor.crc
|
121
|
+
@currentEntry = nil
|
122
|
+
@compressor = NullCompressor.instance
|
123
|
+
end
|
124
|
+
|
125
|
+
def init_next_entry(entry, level = Zlib::DEFAULT_COMPRESSION)
|
126
|
+
finalize_current_entry
|
127
|
+
@entrySet << entry
|
128
|
+
entry.write_local_entry(@outputStream)
|
129
|
+
@compressor = get_compressor(entry, level)
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_compressor(entry, level)
|
133
|
+
case entry.compression_method
|
134
|
+
when ZipEntry::DEFLATED then Deflater.new(@outputStream, level)
|
135
|
+
when ZipEntry::STORED then PassThruCompressor.new(@outputStream)
|
136
|
+
else raise ZipCompressionMethodError,
|
137
|
+
"Invalid compression method: '#{entry.compression_method}'"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def update_local_headers
|
142
|
+
pos = @outputStream.tell
|
143
|
+
@entrySet.each {
|
144
|
+
|entry|
|
145
|
+
@outputStream.pos = entry.localHeaderOffset
|
146
|
+
entry.write_local_entry(@outputStream)
|
147
|
+
}
|
148
|
+
@outputStream.pos = pos
|
149
|
+
end
|
150
|
+
|
151
|
+
def write_central_directory
|
152
|
+
cdir = ZipCentralDirectory.new(@entrySet, @comment)
|
153
|
+
cdir.write_to_stream(@outputStream)
|
154
|
+
end
|
155
|
+
|
156
|
+
protected
|
157
|
+
|
158
|
+
def finish
|
159
|
+
@compressor.finish
|
160
|
+
end
|
161
|
+
|
162
|
+
public
|
163
|
+
# Modeled after IO.<<
|
164
|
+
def << (data)
|
165
|
+
@compressor << data
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
171
|
+
# rubyzip is free software; you can redistribute it and/or
|
172
|
+
# modify it under the terms of the ruby license.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Zip
|
2
|
+
class ZipStreamableDirectory < ZipEntry
|
3
|
+
def initialize(zipfile, entry, srcPath = nil, permissionInt = nil)
|
4
|
+
super(zipfile, entry)
|
5
|
+
|
6
|
+
@ftype = :directory
|
7
|
+
entry.get_extra_attributes_from_path(srcPath) if (srcPath)
|
8
|
+
@unix_perms = permissionInt if (permissionInt)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
14
|
+
# rubyzip is free software; you can redistribute it and/or
|
15
|
+
# modify it under the terms of the ruby license.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Zip
|
2
|
+
class ZipStreamableStream < DelegateClass(ZipEntry) #nodoc:all
|
3
|
+
def initialize(entry)
|
4
|
+
super(entry)
|
5
|
+
@tempFile = Tempfile.new(File.basename(name), File.dirname(zipfile))
|
6
|
+
@tempFile.binmode
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_output_stream
|
10
|
+
if block_given?
|
11
|
+
begin
|
12
|
+
yield(@tempFile)
|
13
|
+
ensure
|
14
|
+
@tempFile.close
|
15
|
+
end
|
16
|
+
else
|
17
|
+
@tempFile
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_input_stream
|
22
|
+
if ! @tempFile.closed?
|
23
|
+
raise StandardError, "cannot open entry for reading while its open for writing - #{name}"
|
24
|
+
end
|
25
|
+
@tempFile.open # reopens tempfile from top
|
26
|
+
@tempFile.binmode
|
27
|
+
if block_given?
|
28
|
+
begin
|
29
|
+
yield(@tempFile)
|
30
|
+
ensure
|
31
|
+
@tempFile.close
|
32
|
+
end
|
33
|
+
else
|
34
|
+
@tempFile
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def write_to_zip_output_stream(aZipOutputStream)
|
39
|
+
aZipOutputStream.put_next_entry(self)
|
40
|
+
get_input_stream { |is| IOExtras.copy_stream(aZipOutputStream, is) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
46
|
+
# rubyzip is free software; you can redistribute it and/or
|
47
|
+
# modify it under the terms of the ruby license.
|
data/lib/zip/zipfilesystem.rb
CHANGED
@@ -50,7 +50,7 @@ module Zip
|
|
50
50
|
def dir
|
51
51
|
@zipFsDir
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
# Returns a ZipFsFile which is much like ruby's builtin File (class)
|
55
55
|
# object, except it works on the ZipFile on which this method is
|
56
56
|
# invoked
|
@@ -74,7 +74,7 @@ module Zip
|
|
74
74
|
@zipFsFile = zipFsFile
|
75
75
|
@entryName = entryName
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
def forward_invoke(msg)
|
79
79
|
@zipFsFile.send(msg, @entryName)
|
80
80
|
end
|
@@ -82,7 +82,7 @@ module Zip
|
|
82
82
|
def kind_of?(t)
|
83
83
|
super || t == ::File::Stat
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
forward_message :forward_invoke, :file?, :directory?, :pipe?, :chardev?
|
87
87
|
forward_message :forward_invoke, :symlink?, :socket?, :blockdev?
|
88
88
|
forward_message :forward_invoke, :readable?, :readable_real?
|
@@ -93,7 +93,7 @@ module Zip
|
|
93
93
|
forward_message :forward_invoke, :zero?
|
94
94
|
forward_message :forward_invoke, :size, :size?
|
95
95
|
forward_message :forward_invoke, :mtime, :atime, :ctime
|
96
|
-
|
96
|
+
|
97
97
|
def blocks; nil; end
|
98
98
|
|
99
99
|
def get_entry
|
@@ -140,7 +140,7 @@ module Zip
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def nlink; 1; end
|
143
|
-
|
143
|
+
|
144
144
|
def blksize; nil; end
|
145
145
|
|
146
146
|
def mode
|
@@ -154,7 +154,7 @@ module Zip
|
|
154
154
|
end
|
155
155
|
|
156
156
|
def initialize(mappedZip)
|
157
|
-
|
157
|
+
@mappedZip = mappedZip
|
158
158
|
end
|
159
159
|
|
160
160
|
def get_entry(fileName)
|
@@ -174,12 +174,12 @@ module Zip
|
|
174
174
|
end
|
175
175
|
end
|
176
176
|
private :unix_mode_cmp
|
177
|
-
|
177
|
+
|
178
178
|
def exists?(fileName)
|
179
179
|
expand_path(fileName) == "/" || @mappedZip.find_entry(fileName) != nil
|
180
180
|
end
|
181
181
|
alias :exist? :exists?
|
182
|
-
|
182
|
+
|
183
183
|
# Permissions not implemented, so if the file exists it is accessible
|
184
184
|
alias owned? exists?
|
185
185
|
alias grpowned? exists?
|
@@ -206,7 +206,7 @@ module Zip
|
|
206
206
|
def setgid?(fileName)
|
207
207
|
unix_mode_cmp(fileName, 02000)
|
208
208
|
end
|
209
|
-
|
209
|
+
|
210
210
|
def sticky?(fileName)
|
211
211
|
unix_mode_cmp(fileName, 01000)
|
212
212
|
end
|
@@ -220,36 +220,36 @@ module Zip
|
|
220
220
|
end
|
221
221
|
|
222
222
|
def directory?(fileName)
|
223
|
-
|
224
|
-
|
223
|
+
entry = @mappedZip.find_entry(fileName)
|
224
|
+
expand_path(fileName) == "/" || (entry != nil && entry.directory?)
|
225
225
|
end
|
226
|
-
|
227
|
-
def open(fileName, openMode = "r", &block)
|
226
|
+
|
227
|
+
def open(fileName, openMode = "r", permissionInt = 0644, &block)
|
228
228
|
openMode.gsub!("b", "") # ignore b option
|
229
229
|
case openMode
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
230
|
+
when "r"
|
231
|
+
@mappedZip.get_input_stream(fileName, &block)
|
232
|
+
when "w"
|
233
|
+
@mappedZip.get_output_stream(fileName, permissionInt, &block)
|
234
|
+
else
|
235
|
+
raise StandardError, "openmode '#{openMode} not supported" unless openMode == "r"
|
236
236
|
end
|
237
237
|
end
|
238
238
|
|
239
239
|
def new(fileName, openMode = "r")
|
240
|
-
|
240
|
+
open(fileName, openMode)
|
241
241
|
end
|
242
|
-
|
242
|
+
|
243
243
|
def size(fileName)
|
244
|
-
|
244
|
+
@mappedZip.get_entry(fileName).size
|
245
245
|
end
|
246
|
-
|
246
|
+
|
247
247
|
# Returns nil for not found and nil for directories
|
248
248
|
def size?(fileName)
|
249
|
-
|
250
|
-
|
249
|
+
entry = @mappedZip.find_entry(fileName)
|
250
|
+
return (entry == nil || entry.directory?) ? nil : entry.size
|
251
251
|
end
|
252
|
-
|
252
|
+
|
253
253
|
def chown(ownerInt, groupInt, *filenames)
|
254
254
|
filenames.each { |fileName|
|
255
255
|
e = get_entry(fileName)
|
@@ -266,39 +266,41 @@ module Zip
|
|
266
266
|
filenames.each { |fileName|
|
267
267
|
e = get_entry(fileName)
|
268
268
|
e.fstype = 3 # force convertion filesystem type to unix
|
269
|
+
e.unix_perms = modeInt
|
269
270
|
e.externalFileAttributes = modeInt << 16
|
271
|
+
e.dirty = true
|
270
272
|
}
|
271
273
|
filenames.size
|
272
274
|
end
|
273
275
|
|
274
276
|
def zero?(fileName)
|
275
|
-
|
276
|
-
|
277
|
+
sz = size(fileName)
|
278
|
+
sz == nil || sz == 0
|
277
279
|
rescue Errno::ENOENT
|
278
|
-
|
280
|
+
false
|
279
281
|
end
|
280
|
-
|
282
|
+
|
281
283
|
def file?(fileName)
|
282
|
-
|
283
|
-
|
284
|
+
entry = @mappedZip.find_entry(fileName)
|
285
|
+
entry != nil && entry.file?
|
284
286
|
end
|
285
|
-
|
287
|
+
|
286
288
|
def dirname(fileName)
|
287
|
-
|
289
|
+
::File.dirname(fileName)
|
288
290
|
end
|
289
|
-
|
291
|
+
|
290
292
|
def basename(fileName)
|
291
|
-
|
293
|
+
::File.basename(fileName)
|
292
294
|
end
|
293
|
-
|
295
|
+
|
294
296
|
def split(fileName)
|
295
|
-
|
297
|
+
::File.split(fileName)
|
296
298
|
end
|
297
|
-
|
299
|
+
|
298
300
|
def join(*fragments)
|
299
|
-
|
301
|
+
::File.join(*fragments)
|
300
302
|
end
|
301
|
-
|
303
|
+
|
302
304
|
def utime(modifiedTime, *fileNames)
|
303
305
|
fileNames.each { |fileName|
|
304
306
|
get_entry(fileName).time = modifiedTime
|
@@ -306,9 +308,9 @@ module Zip
|
|
306
308
|
end
|
307
309
|
|
308
310
|
def mtime(fileName)
|
309
|
-
|
311
|
+
@mappedZip.get_entry(fileName).mtime
|
310
312
|
end
|
311
|
-
|
313
|
+
|
312
314
|
def atime(fileName)
|
313
315
|
e = get_entry(fileName)
|
314
316
|
if e.extra.member? "UniversalTime"
|
@@ -317,7 +319,7 @@ module Zip
|
|
317
319
|
nil
|
318
320
|
end
|
319
321
|
end
|
320
|
-
|
322
|
+
|
321
323
|
def ctime(fileName)
|
322
324
|
e = get_entry(fileName)
|
323
325
|
if e.extra.member? "UniversalTime"
|
@@ -328,43 +330,43 @@ module Zip
|
|
328
330
|
end
|
329
331
|
|
330
332
|
def pipe?(filename)
|
331
|
-
|
333
|
+
false
|
332
334
|
end
|
333
|
-
|
335
|
+
|
334
336
|
def blockdev?(filename)
|
335
|
-
|
337
|
+
false
|
336
338
|
end
|
337
|
-
|
339
|
+
|
338
340
|
def chardev?(filename)
|
339
|
-
|
341
|
+
false
|
340
342
|
end
|
341
|
-
|
343
|
+
|
342
344
|
def symlink?(fileName)
|
343
|
-
|
345
|
+
false
|
344
346
|
end
|
345
|
-
|
347
|
+
|
346
348
|
def socket?(fileName)
|
347
|
-
|
349
|
+
false
|
348
350
|
end
|
349
|
-
|
351
|
+
|
350
352
|
def ftype(fileName)
|
351
|
-
|
353
|
+
@mappedZip.get_entry(fileName).directory? ? "directory" : "file"
|
352
354
|
end
|
353
|
-
|
355
|
+
|
354
356
|
def readlink(fileName)
|
355
|
-
|
357
|
+
raise NotImplementedError, "The readlink() function is not implemented"
|
356
358
|
end
|
357
|
-
|
359
|
+
|
358
360
|
def symlink(fileName, symlinkName)
|
359
|
-
|
361
|
+
raise NotImplementedError, "The symlink() function is not implemented"
|
360
362
|
end
|
361
363
|
|
362
364
|
def link(fileName, symlinkName)
|
363
|
-
|
365
|
+
raise NotImplementedError, "The link() function is not implemented"
|
364
366
|
end
|
365
367
|
|
366
368
|
def pipe
|
367
|
-
|
369
|
+
raise NotImplementedError, "The pipe() function is not implemented"
|
368
370
|
end
|
369
371
|
|
370
372
|
def stat(fileName)
|
@@ -377,7 +379,7 @@ module Zip
|
|
377
379
|
alias lstat stat
|
378
380
|
|
379
381
|
def readlines(fileName)
|
380
|
-
|
382
|
+
open(fileName) { |is| is.readlines }
|
381
383
|
end
|
382
384
|
|
383
385
|
def read(fileName)
|
@@ -385,21 +387,21 @@ module Zip
|
|
385
387
|
end
|
386
388
|
|
387
389
|
def popen(*args, &aProc)
|
388
|
-
|
390
|
+
File.popen(*args, &aProc)
|
389
391
|
end
|
390
392
|
|
391
393
|
def foreach(fileName, aSep = $/, &aProc)
|
392
|
-
|
394
|
+
open(fileName) { |is| is.each_line(aSep, &aProc) }
|
393
395
|
end
|
394
396
|
|
395
397
|
def delete(*args)
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
398
|
+
args.each {
|
399
|
+
|fileName|
|
400
|
+
if directory?(fileName)
|
401
|
+
raise Errno::EISDIR, "Is a directory - \"#{fileName}\""
|
402
|
+
end
|
403
|
+
@mappedZip.remove(fileName)
|
404
|
+
}
|
403
405
|
end
|
404
406
|
|
405
407
|
def rename(fileToRename, newName)
|
@@ -420,11 +422,11 @@ module Zip
|
|
420
422
|
# The individual methods are not documented due to their
|
421
423
|
# similarity with the methods in Dir
|
422
424
|
class ZipFsDir
|
423
|
-
|
425
|
+
|
424
426
|
def initialize(mappedZip)
|
425
427
|
@mappedZip = mappedZip
|
426
428
|
end
|
427
|
-
|
429
|
+
|
428
430
|
attr_writer :file
|
429
431
|
|
430
432
|
def new(aDirectoryName)
|
@@ -446,14 +448,14 @@ module Zip
|
|
446
448
|
|
447
449
|
def pwd; @mappedZip.pwd; end
|
448
450
|
alias getwd pwd
|
449
|
-
|
451
|
+
|
450
452
|
def chdir(aDirectoryName)
|
451
453
|
unless @file.stat(aDirectoryName).directory?
|
452
454
|
raise Errno::EINVAL, "Invalid argument - #{aDirectoryName}"
|
453
455
|
end
|
454
456
|
@mappedZip.pwd = @file.expand_path(aDirectoryName)
|
455
457
|
end
|
456
|
-
|
458
|
+
|
457
459
|
def entries(aDirectoryName)
|
458
460
|
entries = []
|
459
461
|
foreach(aDirectoryName) { |e| entries << e }
|
@@ -465,7 +467,7 @@ module Zip
|
|
465
467
|
raise Errno::ENOTDIR, aDirectoryName
|
466
468
|
end
|
467
469
|
path = @file.expand_path(aDirectoryName).ensure_end("/")
|
468
|
-
|
470
|
+
path = Regexp.escape(path)
|
469
471
|
subDirEntriesRegex = Regexp.new("^#{path}([^/]+)$")
|
470
472
|
@mappedZip.each {
|
471
473
|
|fileName|
|
@@ -482,13 +484,13 @@ module Zip
|
|
482
484
|
end
|
483
485
|
alias rmdir delete
|
484
486
|
alias unlink delete
|
485
|
-
|
487
|
+
|
486
488
|
def mkdir(entryName, permissionInt = 0755)
|
487
489
|
@mappedZip.mkdir(entryName, permissionInt)
|
488
490
|
end
|
489
|
-
|
491
|
+
|
490
492
|
def chroot(*args)
|
491
|
-
|
493
|
+
raise NotImplementedError, "The chroot() function is not implemented"
|
492
494
|
end
|
493
495
|
|
494
496
|
end
|
@@ -540,13 +542,13 @@ module Zip
|
|
540
542
|
@zipFile = zipFile
|
541
543
|
@pwd = "/"
|
542
544
|
end
|
543
|
-
|
545
|
+
|
544
546
|
attr_accessor :pwd
|
545
|
-
|
547
|
+
|
546
548
|
def find_entry(fileName)
|
547
549
|
@zipFile.find_entry(expand_to_entry(fileName))
|
548
550
|
end
|
549
|
-
|
551
|
+
|
550
552
|
def get_entry(fileName)
|
551
553
|
@zipFile.get_entry(expand_to_entry(fileName))
|
552
554
|
end
|
@@ -554,15 +556,15 @@ module Zip
|
|
554
556
|
def get_input_stream(fileName, &aProc)
|
555
557
|
@zipFile.get_input_stream(expand_to_entry(fileName), &aProc)
|
556
558
|
end
|
557
|
-
|
558
|
-
def get_output_stream(fileName, &aProc)
|
559
|
-
@zipFile.get_output_stream(expand_to_entry(fileName), &aProc)
|
559
|
+
|
560
|
+
def get_output_stream(fileName, permissionInt = nil, &aProc)
|
561
|
+
@zipFile.get_output_stream(expand_to_entry(fileName), permissionInt, &aProc)
|
560
562
|
end
|
561
563
|
|
562
564
|
def read(fileName)
|
563
565
|
@zipFile.read(expand_to_entry(fileName))
|
564
566
|
end
|
565
|
-
|
567
|
+
|
566
568
|
def remove(fileName)
|
567
569
|
@zipFile.remove(expand_to_entry(fileName))
|
568
570
|
end
|
@@ -584,9 +586,9 @@ module Zip
|
|
584
586
|
yield("/"+e.to_s.chomp("/"))
|
585
587
|
}
|
586
588
|
end
|
587
|
-
|
589
|
+
|
588
590
|
def expand_path(aPath)
|
589
|
-
expanded = aPath.
|
591
|
+
expanded = aPath.start_with?("/") ? aPath : @pwd.ensure_end("/") + aPath
|
590
592
|
expanded.gsub!(/\/\.(\/|$)/, "")
|
591
593
|
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, "")
|
592
594
|
expanded.empty? ? "/" : expanded
|