rubyzip 1.0.0 → 1.2.0
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.
- checksums.yaml +6 -14
- data/README.md +173 -42
- data/Rakefile +10 -5
- data/TODO +0 -1
- data/lib/zip/central_directory.rb +55 -24
- data/lib/zip/compressor.rb +0 -0
- data/lib/zip/constants.rb +4 -2
- data/lib/zip/crypto/encryption.rb +11 -0
- data/lib/zip/crypto/null_encryption.rb +45 -0
- data/lib/zip/crypto/traditional_encryption.rb +99 -0
- data/lib/zip/decompressor.rb +2 -2
- data/lib/zip/deflater.rb +11 -6
- data/lib/zip/dos_time.rb +4 -5
- data/lib/zip/entry.rb +159 -97
- data/lib/zip/entry_set.rb +18 -18
- data/lib/zip/errors.rb +15 -6
- data/lib/zip/extra_field/generic.rb +8 -8
- data/lib/zip/extra_field/ntfs.rb +90 -0
- data/lib/zip/extra_field/old_unix.rb +44 -0
- data/lib/zip/extra_field/universal_time.rb +14 -14
- data/lib/zip/extra_field/unix.rb +8 -9
- data/lib/zip/extra_field/zip64.rb +44 -6
- data/lib/zip/extra_field/zip64_placeholder.rb +16 -0
- data/lib/zip/extra_field.rb +20 -8
- data/lib/zip/file.rb +126 -114
- data/lib/zip/filesystem.rb +140 -139
- data/lib/zip/inflater.rb +10 -9
- data/lib/zip/input_stream.rb +105 -80
- data/lib/zip/ioextras/abstract_input_stream.rb +15 -12
- data/lib/zip/ioextras/abstract_output_stream.rb +0 -2
- data/lib/zip/ioextras.rb +1 -3
- data/lib/zip/null_compressor.rb +2 -2
- data/lib/zip/null_decompressor.rb +4 -4
- data/lib/zip/null_input_stream.rb +2 -1
- data/lib/zip/output_stream.rb +57 -43
- data/lib/zip/pass_thru_compressor.rb +4 -4
- data/lib/zip/pass_thru_decompressor.rb +4 -5
- data/lib/zip/streamable_directory.rb +2 -2
- data/lib/zip/streamable_stream.rb +22 -13
- data/lib/zip/version.rb +1 -1
- data/lib/zip.rb +11 -2
- data/samples/example.rb +30 -40
- data/samples/example_filesystem.rb +16 -18
- data/samples/example_recursive.rb +35 -27
- data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +25 -27
- data/samples/qtzip.rb +19 -28
- data/samples/write_simple.rb +12 -13
- data/samples/zipfind.rb +29 -37
- data/test/basic_zip_file_test.rb +60 -0
- data/test/case_sensitivity_test.rb +69 -0
- data/test/central_directory_entry_test.rb +69 -0
- data/test/central_directory_test.rb +100 -0
- data/test/crypto/null_encryption_test.rb +53 -0
- data/test/crypto/traditional_encryption_test.rb +80 -0
- data/test/data/WarnInvalidDate.zip +0 -0
- data/test/data/file1.txt +46 -0
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +1504 -0
- 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 +1 -0
- data/test/data/notzippedruby.rb +7 -0
- data/test/data/ntfs.zip +0 -0
- data/test/data/oddExtraField.zip +0 -0
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/test.xls +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 +65 -0
- data/test/encryption_test.rb +42 -0
- data/test/entry_set_test.rb +152 -0
- data/test/entry_test.rb +163 -0
- data/test/errors_test.rb +34 -0
- data/test/extra_field_test.rb +76 -0
- data/test/file_extract_directory_test.rb +54 -0
- data/test/file_extract_test.rb +83 -0
- data/test/file_permissions_test.rb +69 -0
- data/test/file_split_test.rb +57 -0
- data/test/file_test.rb +563 -0
- data/test/filesystem/dir_iterator_test.rb +58 -0
- data/test/filesystem/directory_test.rb +121 -0
- data/test/filesystem/file_mutating_test.rb +88 -0
- data/test/filesystem/file_nonmutating_test.rb +508 -0
- data/test/filesystem/file_stat_test.rb +64 -0
- data/test/gentestfiles.rb +122 -0
- data/test/inflater_test.rb +14 -0
- data/test/input_stream_test.rb +182 -0
- data/test/ioextras/abstract_input_stream_test.rb +102 -0
- data/test/ioextras/abstract_output_stream_test.rb +106 -0
- data/test/ioextras/fake_io_test.rb +18 -0
- data/test/local_entry_test.rb +154 -0
- data/test/output_stream_test.rb +128 -0
- data/test/pass_thru_compressor_test.rb +30 -0
- data/test/pass_thru_decompressor_test.rb +14 -0
- data/test/samples/example_recursive_test.rb +37 -0
- data/test/settings_test.rb +95 -0
- data/test/test_helper.rb +221 -0
- data/test/unicode_file_names_and_comments_test.rb +50 -0
- data/test/zip64_full_test.rb +51 -0
- data/test/zip64_support_test.rb +14 -0
- metadata +198 -22
- data/NEWS +0 -182
data/lib/zip/file.rb
CHANGED
@@ -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
|
-
|
48
|
-
SPLIT_SIGNATURE = 0x08074b50
|
46
|
+
CREATE = 1
|
47
|
+
SPLIT_SIGNATURE = 0x08074b50
|
49
48
|
ZIP64_EOCD_SIGNATURE = 0x06064b50
|
50
|
-
MAX_SEGMENT_SIZE
|
51
|
-
MIN_SEGMENT_SIZE
|
52
|
-
DATA_BUFFER_SIZE
|
49
|
+
MAX_SEGMENT_SIZE = 3_221_225_472
|
50
|
+
MIN_SEGMENT_SIZE = 65_536
|
51
|
+
DATA_BUFFER_SIZE = 8192
|
52
|
+
IO_METHODS = [:tell, :seek, :read, :close]
|
53
53
|
|
54
54
|
attr_reader :name
|
55
55
|
|
@@ -64,69 +64,78 @@ 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(
|
67
|
+
def initialize(file_name, create = nil, buffer = false, options = {})
|
68
68
|
super()
|
69
|
-
@name =
|
69
|
+
@name = file_name
|
70
70
|
@comment = ''
|
71
|
-
@create
|
71
|
+
@create = create
|
72
72
|
case
|
73
|
-
when ::File.
|
73
|
+
when !buffer && ::File.size?(file_name)
|
74
74
|
@create = nil
|
75
|
+
@file_permissions = ::File.stat(file_name).mode
|
75
76
|
::File.open(name, 'rb') do |f|
|
76
77
|
read_from_stream(f)
|
77
78
|
end
|
78
79
|
when create
|
80
|
+
@file_permissions = create_file_permissions
|
79
81
|
@entry_set = EntrySet.new
|
82
|
+
when ::File.zero?(file_name)
|
83
|
+
raise Error, "File #{file_name} has zero size. Did you mean to pass the create flag?"
|
80
84
|
else
|
81
|
-
raise
|
85
|
+
raise Error, "File #{file_name} not found"
|
82
86
|
end
|
83
|
-
@
|
84
|
-
@
|
85
|
-
@restore_ownership = false
|
86
|
-
@restore_permissions =
|
87
|
-
@restore_times = true
|
87
|
+
@stored_entries = @entry_set.dup
|
88
|
+
@stored_comment = @comment
|
89
|
+
@restore_ownership = options[:restore_ownership] || false
|
90
|
+
@restore_permissions = options[:restore_permissions] || true
|
91
|
+
@restore_times = options[:restore_times] || true
|
88
92
|
end
|
89
93
|
|
90
94
|
class << self
|
91
95
|
# Same as #new. If a block is passed the ZipFile object is passed
|
92
96
|
# to the block and is automatically closed afterwards just as with
|
93
97
|
# ruby's builtin File.open method.
|
94
|
-
def open(
|
95
|
-
zf = ::Zip::File.new(
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
102
|
-
else
|
103
|
-
zf
|
98
|
+
def open(file_name, create = nil)
|
99
|
+
zf = ::Zip::File.new(file_name, create)
|
100
|
+
return zf unless block_given?
|
101
|
+
begin
|
102
|
+
yield zf
|
103
|
+
ensure
|
104
|
+
zf.close
|
104
105
|
end
|
105
106
|
end
|
106
107
|
|
107
108
|
# Same as #open. But outputs data to a buffer instead of a file
|
108
109
|
def add_buffer
|
109
|
-
|
110
|
+
io = ::StringIO.new('')
|
111
|
+
zf = ::Zip::File.new(io, true, true)
|
110
112
|
yield zf
|
111
|
-
zf.write_buffer
|
113
|
+
zf.write_buffer(io)
|
112
114
|
end
|
113
115
|
|
114
116
|
# Like #open, but reads zip archive contents from a String or open IO
|
115
117
|
# stream, and outputs data to a buffer.
|
116
|
-
# (This can be used to extract data from a
|
118
|
+
# (This can be used to extract data from a
|
117
119
|
# downloaded zip archive without first saving it to disk.)
|
118
|
-
def open_buffer(io)
|
119
|
-
unless io.
|
120
|
-
raise "Zip::
|
120
|
+
def open_buffer(io, options = {})
|
121
|
+
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
|
122
|
+
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
121
123
|
end
|
122
|
-
|
123
|
-
if io.is_a(::String)
|
124
|
+
if io.is_a?(::String)
|
124
125
|
require 'stringio'
|
125
126
|
io = ::StringIO.new(io)
|
127
|
+
elsif io.respond_to?(:binmode)
|
128
|
+
# https://github.com/rubyzip/rubyzip/issues/119
|
129
|
+
io.binmode
|
126
130
|
end
|
131
|
+
zf = ::Zip::File.new(io, true, true, options)
|
127
132
|
zf.read_from_stream(io)
|
128
133
|
yield zf
|
129
|
-
|
134
|
+
begin
|
135
|
+
zf.write_buffer(io)
|
136
|
+
rescue IOError => e
|
137
|
+
raise unless e.message == 'not opened for writing'
|
138
|
+
end
|
130
139
|
end
|
131
140
|
|
132
141
|
# Iterates over the contents of the ZipFile. This is more efficient
|
@@ -173,9 +182,9 @@ module Zip
|
|
173
182
|
# TODO: Make the code more understandable
|
174
183
|
#
|
175
184
|
def save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
|
176
|
-
ssegment_size
|
177
|
-
ssegment_size
|
178
|
-
szip_file_name = "#{partial_zip_file_name}.#{'%03d'
|
185
|
+
ssegment_size = zip_file_size - zip_file.pos
|
186
|
+
ssegment_size = segment_size if ssegment_size > segment_size
|
187
|
+
szip_file_name = "#{partial_zip_file_name}.#{format('%03d', szip_file_index)}"
|
179
188
|
::File.open(szip_file_name, 'wb') do |szip_file|
|
180
189
|
if szip_file_index == 1
|
181
190
|
ssegment_size = put_split_signature(szip_file, segment_size)
|
@@ -185,7 +194,7 @@ module Zip
|
|
185
194
|
segment_bytes_left = ssegment_size - chunk_bytes
|
186
195
|
buffer_size = segment_bytes_left < DATA_BUFFER_SIZE ? segment_bytes_left : DATA_BUFFER_SIZE
|
187
196
|
chunk = zip_file.read(buffer_size)
|
188
|
-
chunk_bytes
|
197
|
+
chunk_bytes += buffer_size
|
189
198
|
szip_file << chunk
|
190
199
|
# Info for track splitting
|
191
200
|
yield segment_count, szip_file_index, chunk_bytes, ssegment_size if block_given?
|
@@ -195,14 +204,14 @@ module Zip
|
|
195
204
|
|
196
205
|
# Splits an archive into parts with segment size
|
197
206
|
def split(zip_file_name, segment_size = MAX_SEGMENT_SIZE, delete_zip_file = true, partial_zip_file_name = nil)
|
198
|
-
raise
|
207
|
+
raise Error, "File #{zip_file_name} not found" unless ::File.exist?(zip_file_name)
|
199
208
|
raise Errno::ENOENT, zip_file_name unless ::File.readable?(zip_file_name)
|
200
209
|
zip_file_size = ::File.size(zip_file_name)
|
201
210
|
segment_size = get_segment_size_for_split(segment_size)
|
202
211
|
return if zip_file_size <= segment_size
|
203
212
|
segment_count = get_segment_count_for_split(zip_file_size, segment_size)
|
204
213
|
# Checking for correct zip structure
|
205
|
-
|
214
|
+
open(zip_file_name) {}
|
206
215
|
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
|
207
216
|
szip_file_index = 0
|
208
217
|
::File.open(zip_file_name, 'rb') do |zip_file|
|
@@ -216,7 +225,6 @@ module Zip
|
|
216
225
|
end
|
217
226
|
end
|
218
227
|
|
219
|
-
|
220
228
|
# Returns an input stream to the specified entry. If a block is passed
|
221
229
|
# the stream object is passed to the block and the stream is automatically
|
222
230
|
# closed afterwards just as with ruby's builtin File.open method.
|
@@ -224,19 +232,26 @@ module Zip
|
|
224
232
|
get_entry(entry).get_input_stream(&aProc)
|
225
233
|
end
|
226
234
|
|
227
|
-
# Returns an output stream to the specified entry. If
|
228
|
-
#
|
229
|
-
#
|
230
|
-
|
231
|
-
|
232
|
-
|
235
|
+
# Returns an output stream to the specified entry. If entry is not an instance
|
236
|
+
# of Zip::Entry, a new Zip::Entry will be initialized using the arguments
|
237
|
+
# specified. If a block is passed the stream object is passed to the block and
|
238
|
+
# the stream is automatically closed afterwards just as with ruby's builtin
|
239
|
+
# File.open method.
|
240
|
+
def get_output_stream(entry, permission_int = nil, comment = nil, extra = nil, compressed_size = nil, crc = nil, compression_method = nil, size = nil, time = nil, &aProc)
|
241
|
+
new_entry =
|
242
|
+
if entry.kind_of?(Entry)
|
243
|
+
entry
|
244
|
+
else
|
245
|
+
Entry.new(@name, entry.to_s, comment, extra, compressed_size, crc, compression_method, size, time)
|
246
|
+
end
|
247
|
+
if new_entry.directory?
|
233
248
|
raise ArgumentError,
|
234
|
-
"cannot open stream to directory entry - '#{
|
249
|
+
"cannot open stream to directory entry - '#{new_entry}'"
|
235
250
|
end
|
236
|
-
|
237
|
-
|
238
|
-
@entry_set <<
|
239
|
-
|
251
|
+
new_entry.unix_perms = permission_int
|
252
|
+
zip_streamable_entry = StreamableStream.new(new_entry)
|
253
|
+
@entry_set << zip_streamable_entry
|
254
|
+
zip_streamable_entry.get_output_stream(&aProc)
|
240
255
|
end
|
241
256
|
|
242
257
|
# Returns the name of the zip archive
|
@@ -250,12 +265,13 @@ module Zip
|
|
250
265
|
end
|
251
266
|
|
252
267
|
# Convenience method for adding the contents of a file to the archive
|
253
|
-
def add(entry,
|
254
|
-
continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
|
255
|
-
check_entry_exists(entry, continue_on_exists_proc,
|
256
|
-
|
257
|
-
|
258
|
-
|
268
|
+
def add(entry, src_path, &continue_on_exists_proc)
|
269
|
+
continue_on_exists_proc ||= proc { ::Zip.continue_on_exists_proc }
|
270
|
+
check_entry_exists(entry, continue_on_exists_proc, 'add')
|
271
|
+
new_entry = entry.kind_of?(::Zip::Entry) ? entry : ::Zip::Entry.new(@name, entry.to_s)
|
272
|
+
new_entry.gather_fileinfo_from_srcpath(src_path)
|
273
|
+
new_entry.dirty = true
|
274
|
+
@entry_set << new_entry
|
259
275
|
end
|
260
276
|
|
261
277
|
# Removes the specified entry.
|
@@ -282,7 +298,7 @@ module Zip
|
|
282
298
|
|
283
299
|
# Extracts entry to file dest_path.
|
284
300
|
def extract(entry, dest_path, &block)
|
285
|
-
block
|
301
|
+
block ||= proc { ::Zip.on_exists_proc }
|
286
302
|
found_entry = get_entry(entry)
|
287
303
|
found_entry.extract(dest_path, &block)
|
288
304
|
end
|
@@ -290,31 +306,27 @@ module Zip
|
|
290
306
|
# Commits changes that has been made since the previous commit to
|
291
307
|
# the zip archive.
|
292
308
|
def commit
|
293
|
-
return
|
294
|
-
on_success_replace
|
295
|
-
|
|
296
|
-
|
297
|
-
|zos|
|
298
|
-
|
299
|
-
@entry_set.each {
|
300
|
-
|e|
|
309
|
+
return unless commit_required?
|
310
|
+
on_success_replace do |tmp_file|
|
311
|
+
::Zip::OutputStream.open(tmp_file) do |zos|
|
312
|
+
@entry_set.each do |e|
|
301
313
|
e.write_to_zip_output_stream(zos)
|
302
314
|
e.dirty = false
|
303
|
-
|
315
|
+
e.clean_up
|
316
|
+
end
|
304
317
|
zos.comment = comment
|
305
|
-
|
318
|
+
end
|
306
319
|
true
|
307
|
-
|
320
|
+
end
|
308
321
|
initialize(name)
|
309
322
|
end
|
310
323
|
|
311
324
|
# Write buffer write changes to buffer and return
|
312
|
-
def write_buffer
|
313
|
-
|
325
|
+
def write_buffer(io = ::StringIO.new(''))
|
326
|
+
::Zip::OutputStream.write_buffer(io) do |zos|
|
314
327
|
@entry_set.each { |e| e.write_to_zip_output_stream(zos) }
|
315
328
|
zos.comment = comment
|
316
329
|
end
|
317
|
-
return buffer
|
318
330
|
end
|
319
331
|
|
320
332
|
# Closes the zip file committing any changes that has been made.
|
@@ -328,7 +340,7 @@ module Zip
|
|
328
340
|
@entry_set.each do |e|
|
329
341
|
return true if e.dirty
|
330
342
|
end
|
331
|
-
@comment != @
|
343
|
+
@comment != @stored_comment || @entry_set != @stored_entries || @create == ::Zip::File::CREATE
|
332
344
|
end
|
333
345
|
|
334
346
|
# Searches for entry with the specified name. Returns nil if
|
@@ -345,73 +357,73 @@ module Zip
|
|
345
357
|
# Searches for an entry just as find_entry, but throws Errno::ENOENT
|
346
358
|
# if no entry is found.
|
347
359
|
def get_entry(entry)
|
348
|
-
|
349
|
-
unless
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
selectedEntry.restore_times = @restore_times
|
355
|
-
selectedEntry
|
360
|
+
selected_entry = find_entry(entry)
|
361
|
+
raise Errno::ENOENT, entry unless selected_entry
|
362
|
+
selected_entry.restore_ownership = @restore_ownership
|
363
|
+
selected_entry.restore_permissions = @restore_permissions
|
364
|
+
selected_entry.restore_times = @restore_times
|
365
|
+
selected_entry
|
356
366
|
end
|
357
367
|
|
358
368
|
# Creates a directory
|
359
369
|
def mkdir(entryName, permissionInt = 0755)
|
360
|
-
if find_entry(entryName)
|
361
|
-
raise Errno::EEXIST, "File exists - #{entryName}"
|
362
|
-
end
|
370
|
+
raise Errno::EEXIST, "File exists - #{entryName}" if find_entry(entryName)
|
363
371
|
entryName = entryName.dup.to_s
|
364
372
|
entryName << '/' unless entryName.end_with?('/')
|
365
|
-
@entry_set << StreamableDirectory.new(@name, entryName, nil, permissionInt)
|
373
|
+
@entry_set << ::Zip::StreamableDirectory.new(@name, entryName, nil, permissionInt)
|
366
374
|
end
|
367
375
|
|
368
376
|
private
|
369
377
|
|
370
|
-
def
|
378
|
+
def directory?(newEntry, srcPath)
|
371
379
|
srcPathIsDirectory = ::File.directory?(srcPath)
|
372
|
-
if newEntry.
|
380
|
+
if newEntry.directory? && !srcPathIsDirectory
|
373
381
|
raise ArgumentError,
|
374
|
-
"entry name '#{newEntry}' indicates directory entry, but "
|
375
|
-
|
376
|
-
elsif !newEntry.
|
377
|
-
newEntry.name +=
|
382
|
+
"entry name '#{newEntry}' indicates directory entry, but " \
|
383
|
+
"'#{srcPath}' is not a directory"
|
384
|
+
elsif !newEntry.directory? && srcPathIsDirectory
|
385
|
+
newEntry.name += '/'
|
378
386
|
end
|
379
|
-
newEntry.
|
387
|
+
newEntry.directory? && srcPathIsDirectory
|
380
388
|
end
|
381
389
|
|
382
390
|
def check_entry_exists(entryName, continue_on_exists_proc, procedureName)
|
383
391
|
continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
end
|
392
|
+
return unless @entry_set.include?(entryName)
|
393
|
+
if continue_on_exists_proc.call
|
394
|
+
remove get_entry(entryName)
|
395
|
+
else
|
396
|
+
raise ::Zip::EntryExistsError,
|
397
|
+
procedureName + " failed. Entry #{entryName} already exists"
|
391
398
|
end
|
392
399
|
end
|
393
400
|
|
394
401
|
def check_file(path)
|
395
|
-
unless ::File.readable?(path)
|
396
|
-
raise Errno::ENOENT, path
|
397
|
-
end
|
402
|
+
raise Errno::ENOENT, path unless ::File.readable?(path)
|
398
403
|
end
|
399
404
|
|
400
|
-
def on_success_replace
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
::File.rename(tmpFilename, name)
|
405
|
+
def on_success_replace
|
406
|
+
tmp_filename = create_tmpname
|
407
|
+
if yield tmp_filename
|
408
|
+
::File.rename(tmp_filename, name)
|
409
|
+
::File.chmod(@file_permissions, name) if defined?(@file_permissions)
|
406
410
|
end
|
411
|
+
ensure
|
412
|
+
::File.unlink(tmp_filename) if ::File.exist?(tmp_filename)
|
407
413
|
end
|
408
414
|
|
409
|
-
def
|
410
|
-
|
411
|
-
|
412
|
-
|
415
|
+
def create_tmpname
|
416
|
+
dirname, basename = ::File.split(name)
|
417
|
+
::Dir::Tmpname.create(basename, dirname) do |tmpname|
|
418
|
+
opts = {perm: 0600, mode: ::File::CREAT | ::File::WRONLY | ::File::EXCL}
|
419
|
+
f = File.open(tmpname, opts)
|
420
|
+
f.close
|
421
|
+
end
|
413
422
|
end
|
414
423
|
|
424
|
+
def create_file_permissions
|
425
|
+
::Zip::RUNNING_ON_WINDOWS ? 0644 : 0666 - ::File.umask
|
426
|
+
end
|
415
427
|
end
|
416
428
|
end
|
417
429
|
|