rubyzip 1.1.7 → 1.2.1
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 +4 -4
- data/README.md +75 -40
- data/Rakefile +3 -4
- data/lib/zip.rb +3 -5
- data/lib/zip/central_directory.rb +7 -7
- data/lib/zip/compressor.rb +0 -0
- data/lib/zip/constants.rb +2 -2
- data/lib/zip/crypto/null_encryption.rb +3 -3
- data/lib/zip/crypto/traditional_encryption.rb +5 -5
- data/lib/zip/decompressor.rb +2 -2
- data/lib/zip/deflater.rb +8 -6
- data/lib/zip/dos_time.rb +4 -5
- data/lib/zip/entry.rb +75 -81
- data/lib/zip/entry_set.rb +11 -11
- data/lib/zip/errors.rb +1 -0
- data/lib/zip/extra_field.rb +6 -6
- data/lib/zip/extra_field/generic.rb +7 -7
- data/lib/zip/extra_field/ntfs.rb +14 -16
- data/lib/zip/extra_field/old_unix.rb +9 -10
- 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 +12 -11
- data/lib/zip/extra_field/zip64_placeholder.rb +1 -1
- data/lib/zip/file.rb +47 -60
- data/lib/zip/filesystem.rb +132 -135
- data/lib/zip/inflater.rb +3 -3
- data/lib/zip/input_stream.rb +13 -7
- data/lib/zip/ioextras.rb +1 -3
- data/lib/zip/ioextras/abstract_input_stream.rb +5 -9
- data/lib/zip/ioextras/abstract_output_stream.rb +2 -4
- data/lib/zip/null_compressor.rb +2 -2
- data/lib/zip/null_decompressor.rb +3 -3
- data/lib/zip/null_input_stream.rb +0 -0
- data/lib/zip/output_stream.rb +8 -9
- data/lib/zip/pass_thru_compressor.rb +4 -4
- data/lib/zip/pass_thru_decompressor.rb +2 -3
- data/lib/zip/streamable_directory.rb +2 -2
- data/lib/zip/streamable_stream.rb +2 -2
- data/lib/zip/version.rb +1 -1
- data/samples/example.rb +29 -39
- data/samples/example_filesystem.rb +16 -18
- data/samples/example_recursive.rb +32 -25
- data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +23 -25
- data/samples/qtzip.rb +17 -26
- data/samples/write_simple.rb +12 -13
- data/samples/zipfind.rb +24 -32
- data/test/basic_zip_file_test.rb +11 -15
- data/test/case_sensitivity_test.rb +69 -0
- data/test/central_directory_entry_test.rb +32 -36
- data/test/central_directory_test.rb +46 -50
- data/test/crypto/null_encryption_test.rb +8 -4
- data/test/crypto/traditional_encryption_test.rb +5 -5
- data/test/data/notzippedruby.rb +1 -1
- data/test/data/oddExtraField.zip +0 -0
- data/test/data/test.xls +0 -0
- data/test/deflater_test.rb +10 -12
- data/test/encryption_test.rb +2 -2
- data/test/entry_set_test.rb +50 -25
- data/test/entry_test.rb +76 -87
- data/test/errors_test.rb +0 -2
- data/test/extra_field_test.rb +19 -21
- data/test/file_extract_directory_test.rb +12 -14
- data/test/file_extract_test.rb +33 -40
- data/test/file_permissions_test.rb +69 -0
- data/test/file_split_test.rb +24 -27
- data/test/file_test.rb +196 -172
- data/test/filesystem/dir_iterator_test.rb +13 -17
- data/test/filesystem/directory_test.rb +80 -90
- data/test/filesystem/file_mutating_test.rb +51 -63
- data/test/filesystem/file_nonmutating_test.rb +222 -228
- data/test/filesystem/file_stat_test.rb +17 -19
- data/test/gentestfiles.rb +47 -55
- data/test/inflater_test.rb +1 -1
- data/test/input_stream_test.rb +46 -34
- data/test/ioextras/abstract_input_stream_test.rb +22 -23
- data/test/ioextras/abstract_output_stream_test.rb +32 -32
- data/test/ioextras/fake_io_test.rb +1 -1
- data/test/local_entry_test.rb +36 -38
- data/test/output_stream_test.rb +20 -21
- data/test/pass_thru_compressor_test.rb +5 -6
- data/test/pass_thru_decompressor_test.rb +0 -1
- data/test/samples/example_recursive_test.rb +37 -0
- data/test/settings_test.rb +18 -15
- data/test/test_helper.rb +50 -44
- data/test/unicode_file_names_and_comments_test.rb +5 -7
- data/test/zip64_full_test.rb +9 -11
- data/test/zip64_support_test.rb +0 -1
- metadata +14 -32
data/lib/zip/errors.rb
CHANGED
data/lib/zip/extra_field.rb
CHANGED
@@ -3,7 +3,7 @@ module Zip
|
|
3
3
|
ID_MAP = {}
|
4
4
|
|
5
5
|
def initialize(binstr = nil)
|
6
|
-
binstr
|
6
|
+
merge(binstr) if binstr
|
7
7
|
end
|
8
8
|
|
9
9
|
def extra_field_type_exist(binstr, id, len, i)
|
@@ -51,7 +51,7 @@ module Zip
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def create(name)
|
54
|
-
unless field_class = ID_MAP.values.find { |k| k.name == name }
|
54
|
+
unless (field_class = ID_MAP.values.find { |k| k.name == name })
|
55
55
|
raise Error, "Unknown extra field '#{name}'"
|
56
56
|
end
|
57
57
|
self[name] = field_class.new
|
@@ -61,7 +61,7 @@ module Zip
|
|
61
61
|
# does not prevent known fields from being read back in
|
62
62
|
def ordered_values
|
63
63
|
result = []
|
64
|
-
|
64
|
+
each { |k, v| k == 'Unknown' ? result.push(v) : result.unshift(v) }
|
65
65
|
result
|
66
66
|
end
|
67
67
|
|
@@ -69,7 +69,7 @@ module Zip
|
|
69
69
|
ordered_values.map! { |v| v.to_local_bin.force_encoding('BINARY') }.join
|
70
70
|
end
|
71
71
|
|
72
|
-
alias
|
72
|
+
alias to_s to_local_bin
|
73
73
|
|
74
74
|
def to_c_dir_bin
|
75
75
|
ordered_values.map! { |v| v.to_c_dir_bin.force_encoding('BINARY') }.join
|
@@ -83,8 +83,8 @@ module Zip
|
|
83
83
|
to_local_bin.bytesize
|
84
84
|
end
|
85
85
|
|
86
|
-
alias
|
87
|
-
alias
|
86
|
+
alias length local_size
|
87
|
+
alias size local_size
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
@@ -2,12 +2,12 @@ module Zip
|
|
2
2
|
class ExtraField::Generic
|
3
3
|
def self.register_map
|
4
4
|
if self.const_defined?(:HEADER_ID)
|
5
|
-
::Zip::ExtraField::ID_MAP[
|
5
|
+
::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.name
|
10
|
-
@name ||=
|
10
|
+
@name ||= to_s.split('::')[-1]
|
11
11
|
end
|
12
12
|
|
13
13
|
# return field [size, content] or false
|
@@ -16,28 +16,28 @@ module Zip
|
|
16
16
|
# If nil, start with empty.
|
17
17
|
return false
|
18
18
|
elsif binstr[0, 2] != self.class.const_get(:HEADER_ID)
|
19
|
-
$stderr.puts
|
19
|
+
$stderr.puts 'Warning: weired extra feild header ID. skip parsing'
|
20
20
|
return false
|
21
21
|
end
|
22
|
-
[binstr[2, 2].unpack(
|
22
|
+
[binstr[2, 2].unpack('v')[0], binstr[4..-1]]
|
23
23
|
end
|
24
24
|
|
25
25
|
def ==(other)
|
26
26
|
return false if self.class != other.class
|
27
27
|
each do |k, v|
|
28
|
-
v != other[k]
|
28
|
+
return false if v != other[k]
|
29
29
|
end
|
30
30
|
true
|
31
31
|
end
|
32
32
|
|
33
33
|
def to_local_bin
|
34
34
|
s = pack_for_local
|
35
|
-
self.class.const_get(:HEADER_ID) + [s.bytesize].pack(
|
35
|
+
self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
|
36
36
|
end
|
37
37
|
|
38
38
|
def to_c_dir_bin
|
39
39
|
s = pack_for_c_dir
|
40
|
-
self.class.const_get(:HEADER_ID) + [s.bytesize].pack(
|
40
|
+
self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
data/lib/zip/extra_field/ntfs.rb
CHANGED
@@ -5,14 +5,14 @@ module Zip
|
|
5
5
|
HEADER_ID = [0x000A].pack('v')
|
6
6
|
register_map
|
7
7
|
|
8
|
-
WINDOWS_TICK =
|
9
|
-
SEC_TO_UNIX_EPOCH =
|
8
|
+
WINDOWS_TICK = 10_000_000.0
|
9
|
+
SEC_TO_UNIX_EPOCH = 11_644_473_600
|
10
10
|
|
11
11
|
def initialize(binstr = nil)
|
12
12
|
@ctime = nil
|
13
13
|
@mtime = nil
|
14
14
|
@atime = nil
|
15
|
-
binstr
|
15
|
+
binstr && merge(binstr)
|
16
16
|
end
|
17
17
|
|
18
18
|
attr_accessor :atime, :ctime, :mtime
|
@@ -20,18 +20,17 @@ module Zip
|
|
20
20
|
def merge(binstr)
|
21
21
|
return if binstr.empty?
|
22
22
|
size, content = initial_parse(binstr)
|
23
|
-
(size && content)
|
23
|
+
(size && content) || return
|
24
24
|
|
25
25
|
content = content[4..-1]
|
26
26
|
tags = parse_tags(content)
|
27
27
|
|
28
28
|
tag1 = tags[1]
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
29
|
+
return unless tag1
|
30
|
+
ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
|
31
|
+
ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
|
32
|
+
ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
|
33
|
+
ntfs_ctime && @ctime ||= from_ntfs_time(ntfs_ctime)
|
35
34
|
end
|
36
35
|
|
37
36
|
def ==(other)
|
@@ -48,16 +47,14 @@ module Zip
|
|
48
47
|
# But 7-zip for Windows only stores at central dir
|
49
48
|
def pack_for_c_dir
|
50
49
|
# reserved 0 and tag 1
|
51
|
-
s = [0, 1].pack(
|
50
|
+
s = [0, 1].pack('Vv')
|
52
51
|
|
53
52
|
tag1 = ''.force_encoding(Encoding::BINARY)
|
54
53
|
if @mtime
|
55
54
|
tag1 << [to_ntfs_time(@mtime)].pack('Q<')
|
56
55
|
if @atime
|
57
56
|
tag1 << [to_ntfs_time(@atime)].pack('Q<')
|
58
|
-
if @ctime
|
59
|
-
tag1 << [to_ntfs_time(@ctime)].pack('Q<')
|
60
|
-
end
|
57
|
+
tag1 << [to_ntfs_time(@ctime)].pack('Q<') if @ctime
|
61
58
|
end
|
62
59
|
end
|
63
60
|
s << [tag1.bytesize].pack('v') << tag1
|
@@ -65,11 +62,12 @@ module Zip
|
|
65
62
|
end
|
66
63
|
|
67
64
|
private
|
65
|
+
|
68
66
|
def parse_tags(content)
|
69
67
|
return {} if content.nil?
|
70
68
|
tags = {}
|
71
69
|
i = 0
|
72
|
-
while i < content.bytesize
|
70
|
+
while i < content.bytesize
|
73
71
|
tag, size = content[i, 4].unpack('vv')
|
74
72
|
i += 4
|
75
73
|
break unless tag && size
|
@@ -89,4 +87,4 @@ module Zip
|
|
89
87
|
((time.to_f + SEC_TO_UNIX_EPOCH) * WINDOWS_TICK).to_i
|
90
88
|
end
|
91
89
|
end
|
92
|
-
end
|
90
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Zip
|
2
2
|
# Olf Info-ZIP Extra for UNIX uid/gid and file timestampes
|
3
3
|
class ExtraField::OldUnix < ExtraField::Generic
|
4
|
-
HEADER_ID =
|
4
|
+
HEADER_ID = 'UX'
|
5
5
|
register_map
|
6
6
|
|
7
7
|
def initialize(binstr = nil)
|
@@ -9,7 +9,7 @@ module Zip
|
|
9
9
|
@gid = 0
|
10
10
|
@atime = nil
|
11
11
|
@mtime = nil
|
12
|
-
binstr
|
12
|
+
binstr && merge(binstr)
|
13
13
|
end
|
14
14
|
|
15
15
|
attr_accessor :uid, :gid, :atime, :mtime
|
@@ -18,8 +18,8 @@ module Zip
|
|
18
18
|
return if binstr.empty?
|
19
19
|
size, content = initial_parse(binstr)
|
20
20
|
# size: 0 for central directory. 4 for local header
|
21
|
-
return if
|
22
|
-
atime, mtime, uid, gid = content.unpack(
|
21
|
+
return if !size || size == 0
|
22
|
+
atime, mtime, uid, gid = content.unpack('VVvv')
|
23
23
|
@uid ||= uid
|
24
24
|
@gid ||= gid
|
25
25
|
@atime ||= atime
|
@@ -29,17 +29,16 @@ module Zip
|
|
29
29
|
def ==(other)
|
30
30
|
@uid == other.uid &&
|
31
31
|
@gid == other.gid &&
|
32
|
-
|
33
|
-
|
32
|
+
@atime == other.atime &&
|
33
|
+
@mtime == other.mtime
|
34
34
|
end
|
35
35
|
|
36
36
|
def pack_for_local
|
37
|
-
[@atime, @mtime, @uid, @gid].pack(
|
37
|
+
[@atime, @mtime, @uid, @gid].pack('VVvv')
|
38
38
|
end
|
39
39
|
|
40
40
|
def pack_for_c_dir
|
41
|
-
[@atime, @mtime].pack(
|
41
|
+
[@atime, @mtime].pack('VV')
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
45
|
-
end
|
44
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Zip
|
2
2
|
# Info-ZIP Additional timestamp field
|
3
3
|
class ExtraField::UniversalTime < ExtraField::Generic
|
4
|
-
HEADER_ID =
|
4
|
+
HEADER_ID = 'UT'
|
5
5
|
register_map
|
6
6
|
|
7
7
|
def initialize(binstr = nil)
|
@@ -9,7 +9,7 @@ module Zip
|
|
9
9
|
@mtime = nil
|
10
10
|
@atime = nil
|
11
11
|
@flag = nil
|
12
|
-
binstr
|
12
|
+
binstr && merge(binstr)
|
13
13
|
end
|
14
14
|
|
15
15
|
attr_accessor :atime, :ctime, :mtime, :flag
|
@@ -17,11 +17,11 @@ module Zip
|
|
17
17
|
def merge(binstr)
|
18
18
|
return if binstr.empty?
|
19
19
|
size, content = initial_parse(binstr)
|
20
|
-
size
|
21
|
-
@flag, mtime, atime, ctime = content.unpack(
|
22
|
-
mtime
|
23
|
-
atime
|
24
|
-
ctime
|
20
|
+
size || return
|
21
|
+
@flag, mtime, atime, ctime = content.unpack('CVVV')
|
22
|
+
mtime && @mtime ||= ::Zip::DOSTime.at(mtime)
|
23
|
+
atime && @atime ||= ::Zip::DOSTime.at(atime)
|
24
|
+
ctime && @ctime ||= ::Zip::DOSTime.at(ctime)
|
25
25
|
end
|
26
26
|
|
27
27
|
def ==(other)
|
@@ -31,17 +31,17 @@ module Zip
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def pack_for_local
|
34
|
-
s = [@flag].pack(
|
35
|
-
@flag & 1 != 0
|
36
|
-
@flag & 2 != 0
|
37
|
-
@flag & 4 != 0
|
34
|
+
s = [@flag].pack('C')
|
35
|
+
@flag & 1 != 0 && s << [@mtime.to_i].pack('V')
|
36
|
+
@flag & 2 != 0 && s << [@atime.to_i].pack('V')
|
37
|
+
@flag & 4 != 0 && s << [@ctime.to_i].pack('V')
|
38
38
|
s
|
39
39
|
end
|
40
40
|
|
41
41
|
def pack_for_c_dir
|
42
|
-
s = [@flag].pack(
|
43
|
-
@flag & 1 == 1
|
42
|
+
s = [@flag].pack('C')
|
43
|
+
@flag & 1 == 1 && s << [@mtime.to_i].pack('V')
|
44
44
|
s
|
45
45
|
end
|
46
46
|
end
|
47
|
-
end
|
47
|
+
end
|
data/lib/zip/extra_field/unix.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module Zip
|
2
2
|
# Info-ZIP Extra for UNIX uid/gid
|
3
3
|
class ExtraField::IUnix < ExtraField::Generic
|
4
|
-
HEADER_ID =
|
4
|
+
HEADER_ID = 'Ux'
|
5
5
|
register_map
|
6
6
|
|
7
7
|
def initialize(binstr = nil)
|
8
8
|
@uid = 0
|
9
9
|
@gid = 0
|
10
|
-
binstr
|
10
|
+
binstr && merge(binstr)
|
11
11
|
end
|
12
12
|
|
13
13
|
attr_accessor :uid, :gid
|
@@ -16,10 +16,10 @@ module Zip
|
|
16
16
|
return if binstr.empty?
|
17
17
|
size, content = initial_parse(binstr)
|
18
18
|
# size: 0 for central directory. 4 for local header
|
19
|
-
return if
|
20
|
-
uid, gid = content.unpack(
|
21
|
-
@uid
|
22
|
-
@gid
|
19
|
+
return if !size || size == 0
|
20
|
+
uid, gid = content.unpack('vv')
|
21
|
+
@uid ||= uid
|
22
|
+
@gid ||= gid
|
23
23
|
end
|
24
24
|
|
25
25
|
def ==(other)
|
@@ -27,12 +27,11 @@ module Zip
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def pack_for_local
|
30
|
-
[@uid, @gid].pack(
|
30
|
+
[@uid, @gid].pack('vv')
|
31
31
|
end
|
32
32
|
|
33
33
|
def pack_for_c_dir
|
34
34
|
''
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
38
|
-
end
|
37
|
+
end
|
@@ -6,21 +6,22 @@ module Zip
|
|
6
6
|
register_map
|
7
7
|
|
8
8
|
def initialize(binstr = nil)
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# unparsed binary; we don't actually know what this contains
|
10
|
+
# without looking for FFs in the associated file header
|
11
|
+
# call parse after initializing with a binary string
|
12
|
+
@content = nil
|
12
13
|
@original_size = nil
|
13
14
|
@compressed_size = nil
|
14
15
|
@relative_header_offset = nil
|
15
16
|
@disk_start_number = nil
|
16
|
-
binstr
|
17
|
+
binstr && merge(binstr)
|
17
18
|
end
|
18
19
|
|
19
20
|
def ==(other)
|
20
21
|
other.original_size == @original_size &&
|
21
22
|
other.compressed_size == @compressed_size &&
|
22
|
-
|
23
|
-
|
23
|
+
other.relative_header_offset == @relative_header_offset &&
|
24
|
+
other.disk_start_number == @disk_start_number
|
24
25
|
end
|
25
26
|
|
26
27
|
def merge(binstr)
|
@@ -51,16 +52,16 @@ module Zip
|
|
51
52
|
def pack_for_local
|
52
53
|
# local header entries must contain original size and compressed size; other fields do not apply
|
53
54
|
return '' unless @original_size && @compressed_size
|
54
|
-
[@original_size, @compressed_size].pack(
|
55
|
+
[@original_size, @compressed_size].pack('Q<Q<')
|
55
56
|
end
|
56
57
|
|
57
58
|
def pack_for_c_dir
|
58
59
|
# central directory entries contain only fields that didn't fit in the main entry part
|
59
60
|
packed = ''.force_encoding('BINARY')
|
60
|
-
packed << [@original_size].pack(
|
61
|
-
packed << [@compressed_size].pack(
|
62
|
-
packed << [@relative_header_offset].pack(
|
63
|
-
packed << [@disk_start_number].pack(
|
61
|
+
packed << [@original_size].pack('Q<') if @original_size
|
62
|
+
packed << [@compressed_size].pack('Q<') if @compressed_size
|
63
|
+
packed << [@relative_header_offset].pack('Q<') if @relative_header_offset
|
64
|
+
packed << [@disk_start_number].pack('V') if @disk_start_number
|
64
65
|
packed
|
65
66
|
end
|
66
67
|
end
|
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
|
-
CREATE = 1
|
46
|
+
CREATE = true
|
48
47
|
SPLIT_SIGNATURE = 0x08074b50
|
49
48
|
ZIP64_EOCD_SIGNATURE = 0x06064b50
|
50
|
-
MAX_SEGMENT_SIZE =
|
51
|
-
MIN_SEGMENT_SIZE =
|
49
|
+
MAX_SEGMENT_SIZE = 3_221_225_472
|
50
|
+
MIN_SEGMENT_SIZE = 65_536
|
52
51
|
DATA_BUFFER_SIZE = 8192
|
52
|
+
IO_METHODS = [:tell, :seek, :read, :close]
|
53
53
|
|
54
54
|
attr_reader :name
|
55
55
|
|
@@ -64,20 +64,22 @@ module Zip
|
|
64
64
|
|
65
65
|
# Opens a zip archive. Pass true as the second parameter to create
|
66
66
|
# a new archive if it doesn't exist already.
|
67
|
-
def initialize(file_name, create =
|
67
|
+
def initialize(file_name, create = false, buffer = false, options = {})
|
68
68
|
super()
|
69
69
|
@name = file_name
|
70
70
|
@comment = ''
|
71
|
-
@create = create
|
71
|
+
@create = create ? true : false # allow any truthy value to mean true
|
72
72
|
case
|
73
73
|
when !buffer && ::File.size?(file_name)
|
74
|
-
@create =
|
75
|
-
@
|
74
|
+
@create = false
|
75
|
+
@file_permissions = ::File.stat(file_name).mode
|
76
76
|
::File.open(name, 'rb') do |f|
|
77
77
|
read_from_stream(f)
|
78
78
|
end
|
79
|
-
when create
|
79
|
+
when @create
|
80
80
|
@entry_set = EntrySet.new
|
81
|
+
when ::File.zero?(file_name)
|
82
|
+
raise Error, "File #{file_name} has zero size. Did you mean to pass the create flag?"
|
81
83
|
else
|
82
84
|
raise Error, "File #{file_name} not found"
|
83
85
|
end
|
@@ -92,7 +94,7 @@ module Zip
|
|
92
94
|
# Same as #new. If a block is passed the ZipFile object is passed
|
93
95
|
# to the block and is automatically closed afterwards just as with
|
94
96
|
# ruby's builtin File.open method.
|
95
|
-
def open(file_name, create =
|
97
|
+
def open(file_name, create = false)
|
96
98
|
zf = ::Zip::File.new(file_name, create)
|
97
99
|
return zf unless block_given?
|
98
100
|
begin
|
@@ -115,23 +117,24 @@ module Zip
|
|
115
117
|
# (This can be used to extract data from a
|
116
118
|
# downloaded zip archive without first saving it to disk.)
|
117
119
|
def open_buffer(io, options = {})
|
118
|
-
unless
|
119
|
-
raise "Zip::File.open_buffer expects
|
120
|
+
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
|
121
|
+
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
120
122
|
end
|
121
123
|
if io.is_a?(::String)
|
122
124
|
require 'stringio'
|
123
125
|
io = ::StringIO.new(io)
|
124
|
-
elsif io.
|
126
|
+
elsif io.respond_to?(:binmode)
|
125
127
|
# https://github.com/rubyzip/rubyzip/issues/119
|
126
128
|
io.binmode
|
127
129
|
end
|
128
130
|
zf = ::Zip::File.new(io, true, true, options)
|
129
131
|
zf.read_from_stream(io)
|
132
|
+
return zf unless block_given?
|
130
133
|
yield zf
|
131
134
|
begin
|
132
135
|
zf.write_buffer(io)
|
133
136
|
rescue IOError => e
|
134
|
-
raise unless e.message ==
|
137
|
+
raise unless e.message == 'not opened for writing'
|
135
138
|
end
|
136
139
|
end
|
137
140
|
|
@@ -181,7 +184,7 @@ module Zip
|
|
181
184
|
def save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
|
182
185
|
ssegment_size = zip_file_size - zip_file.pos
|
183
186
|
ssegment_size = segment_size if ssegment_size > segment_size
|
184
|
-
szip_file_name = "#{partial_zip_file_name}.#{'%03d'
|
187
|
+
szip_file_name = "#{partial_zip_file_name}.#{format('%03d', szip_file_index)}"
|
185
188
|
::File.open(szip_file_name, 'wb') do |szip_file|
|
186
189
|
if szip_file_index == 1
|
187
190
|
ssegment_size = put_split_signature(szip_file, segment_size)
|
@@ -191,7 +194,7 @@ module Zip
|
|
191
194
|
segment_bytes_left = ssegment_size - chunk_bytes
|
192
195
|
buffer_size = segment_bytes_left < DATA_BUFFER_SIZE ? segment_bytes_left : DATA_BUFFER_SIZE
|
193
196
|
chunk = zip_file.read(buffer_size)
|
194
|
-
chunk_bytes
|
197
|
+
chunk_bytes += buffer_size
|
195
198
|
szip_file << chunk
|
196
199
|
# Info for track splitting
|
197
200
|
yield segment_count, szip_file_index, chunk_bytes, ssegment_size if block_given?
|
@@ -208,7 +211,7 @@ module Zip
|
|
208
211
|
return if zip_file_size <= segment_size
|
209
212
|
segment_count = get_segment_count_for_split(zip_file_size, segment_size)
|
210
213
|
# Checking for correct zip structure
|
211
|
-
|
214
|
+
open(zip_file_name) {}
|
212
215
|
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
|
213
216
|
szip_file_index = 0
|
214
217
|
::File.open(zip_file_name, 'rb') do |zip_file|
|
@@ -222,7 +225,6 @@ module Zip
|
|
222
225
|
end
|
223
226
|
end
|
224
227
|
|
225
|
-
|
226
228
|
# Returns an input stream to the specified entry. If a block is passed
|
227
229
|
# the stream object is passed to the block and the stream is automatically
|
228
230
|
# closed afterwards just as with ruby's builtin File.open method.
|
@@ -265,7 +267,7 @@ module Zip
|
|
265
267
|
# Convenience method for adding the contents of a file to the archive
|
266
268
|
def add(entry, src_path, &continue_on_exists_proc)
|
267
269
|
continue_on_exists_proc ||= proc { ::Zip.continue_on_exists_proc }
|
268
|
-
check_entry_exists(entry, continue_on_exists_proc,
|
270
|
+
check_entry_exists(entry, continue_on_exists_proc, 'add')
|
269
271
|
new_entry = entry.kind_of?(::Zip::Entry) ? entry : ::Zip::Entry.new(@name, entry.to_s)
|
270
272
|
new_entry.gather_fileinfo_from_srcpath(src_path)
|
271
273
|
new_entry.dirty = true
|
@@ -338,7 +340,7 @@ module Zip
|
|
338
340
|
@entry_set.each do |e|
|
339
341
|
return true if e.dirty
|
340
342
|
end
|
341
|
-
@comment != @stored_comment || @entry_set != @stored_entries || @create
|
343
|
+
@comment != @stored_comment || @entry_set != @stored_entries || @create
|
342
344
|
end
|
343
345
|
|
344
346
|
# Searches for entry with the specified name. Returns nil if
|
@@ -356,9 +358,7 @@ module Zip
|
|
356
358
|
# if no entry is found.
|
357
359
|
def get_entry(entry)
|
358
360
|
selected_entry = find_entry(entry)
|
359
|
-
unless selected_entry
|
360
|
-
raise Errno::ENOENT, entry
|
361
|
-
end
|
361
|
+
raise Errno::ENOENT, entry unless selected_entry
|
362
362
|
selected_entry.restore_ownership = @restore_ownership
|
363
363
|
selected_entry.restore_permissions = @restore_permissions
|
364
364
|
selected_entry.restore_times = @restore_times
|
@@ -367,9 +367,7 @@ module Zip
|
|
367
367
|
|
368
368
|
# Creates a directory
|
369
369
|
def mkdir(entryName, permissionInt = 0755)
|
370
|
-
if find_entry(entryName)
|
371
|
-
raise Errno::EEXIST, "File exists - #{entryName}"
|
372
|
-
end
|
370
|
+
raise Errno::EEXIST, "File exists - #{entryName}" if find_entry(entryName)
|
373
371
|
entryName = entryName.dup.to_s
|
374
372
|
entryName << '/' unless entryName.end_with?('/')
|
375
373
|
@entry_set << ::Zip::StreamableDirectory.new(@name, entryName, nil, permissionInt)
|
@@ -377,57 +375,46 @@ module Zip
|
|
377
375
|
|
378
376
|
private
|
379
377
|
|
380
|
-
def
|
378
|
+
def directory?(newEntry, srcPath)
|
381
379
|
srcPathIsDirectory = ::File.directory?(srcPath)
|
382
|
-
if newEntry.
|
380
|
+
if newEntry.directory? && !srcPathIsDirectory
|
383
381
|
raise ArgumentError,
|
384
|
-
"entry name '#{newEntry}' indicates directory entry, but "
|
385
|
-
|
386
|
-
elsif !newEntry.
|
387
|
-
newEntry.name +=
|
382
|
+
"entry name '#{newEntry}' indicates directory entry, but " \
|
383
|
+
"'#{srcPath}' is not a directory"
|
384
|
+
elsif !newEntry.directory? && srcPathIsDirectory
|
385
|
+
newEntry.name += '/'
|
388
386
|
end
|
389
|
-
newEntry.
|
387
|
+
newEntry.directory? && srcPathIsDirectory
|
390
388
|
end
|
391
389
|
|
392
390
|
def check_entry_exists(entryName, continue_on_exists_proc, procedureName)
|
393
391
|
continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
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"
|
401
398
|
end
|
402
399
|
end
|
403
400
|
|
404
401
|
def check_file(path)
|
405
|
-
unless ::File.readable?(path)
|
406
|
-
raise Errno::ENOENT, path
|
407
|
-
end
|
402
|
+
raise Errno::ENOENT, path unless ::File.readable?(path)
|
408
403
|
end
|
409
404
|
|
410
405
|
def on_success_replace
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
406
|
+
dirname, basename = ::File.split(name)
|
407
|
+
::Dir::Tmpname.create(basename, dirname) do |tmp_filename|
|
408
|
+
begin
|
409
|
+
if yield tmp_filename
|
410
|
+
::File.rename(tmp_filename, name)
|
411
|
+
::File.chmod(@file_permissions, name) unless @create
|
412
|
+
end
|
413
|
+
ensure
|
414
|
+
::File.unlink(tmp_filename) if ::File.exist?(tmp_filename)
|
419
415
|
end
|
420
416
|
end
|
421
|
-
ensure
|
422
|
-
tmpfile.unlink if tmpfile
|
423
417
|
end
|
424
|
-
|
425
|
-
def get_tempfile
|
426
|
-
temp_file = Tempfile.new(::File.basename(name), ::File.dirname(name))
|
427
|
-
temp_file.binmode
|
428
|
-
temp_file
|
429
|
-
end
|
430
|
-
|
431
418
|
end
|
432
419
|
end
|
433
420
|
|