rubyzip 1.3.0 → 2.3.0
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 +4 -4
- data/README.md +2 -8
- data/Rakefile +3 -0
- data/lib/zip.rb +4 -3
- data/lib/zip/central_directory.rb +9 -5
- data/lib/zip/constants.rb +52 -0
- data/lib/zip/crypto/decrypted_io.rb +40 -0
- data/lib/zip/crypto/traditional_encryption.rb +9 -9
- data/lib/zip/decompressor.rb +19 -1
- data/lib/zip/dos_time.rb +12 -7
- data/lib/zip/entry.rb +57 -38
- data/lib/zip/entry_set.rb +2 -0
- data/lib/zip/errors.rb +1 -0
- data/lib/zip/extra_field.rb +11 -9
- data/lib/zip/extra_field/generic.rb +10 -9
- data/lib/zip/extra_field/ntfs.rb +4 -0
- data/lib/zip/extra_field/old_unix.rb +3 -1
- data/lib/zip/extra_field/universal_time.rb +42 -12
- data/lib/zip/extra_field/unix.rb +3 -1
- data/lib/zip/extra_field/zip64.rb +4 -2
- data/lib/zip/file.rb +79 -54
- data/lib/zip/filesystem.rb +193 -177
- data/lib/zip/inflater.rb +24 -36
- data/lib/zip/input_stream.rb +33 -26
- data/lib/zip/ioextras.rb +1 -1
- data/lib/zip/ioextras/abstract_input_stream.rb +19 -8
- data/lib/zip/ioextras/abstract_output_stream.rb +1 -1
- data/lib/zip/null_decompressor.rb +1 -9
- data/lib/zip/output_stream.rb +14 -5
- data/lib/zip/pass_thru_compressor.rb +2 -2
- data/lib/zip/pass_thru_decompressor.rb +13 -22
- data/lib/zip/streamable_directory.rb +3 -3
- data/lib/zip/streamable_stream.rb +6 -10
- data/lib/zip/version.rb +1 -1
- data/samples/example.rb +2 -2
- data/samples/example_filesystem.rb +1 -1
- data/samples/gtk_ruby_zip.rb +19 -19
- data/samples/qtzip.rb +6 -6
- data/samples/write_simple.rb +2 -4
- data/samples/zipfind.rb +23 -22
- metadata +28 -169
- data/test/basic_zip_file_test.rb +0 -60
- data/test/case_sensitivity_test.rb +0 -69
- data/test/central_directory_entry_test.rb +0 -69
- data/test/central_directory_test.rb +0 -100
- data/test/crypto/null_encryption_test.rb +0 -57
- 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.zip +0 -0
- data/test/data/globTest/foo.txt +0 -0
- data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
- data/test/data/globTest/food.txt +0 -0
- data/test/data/gpbit3stored.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/oddExtraField.zip +0 -0
- data/test/data/path_traversal/Makefile +0 -10
- data/test/data/path_traversal/jwilk/README.md +0 -5
- data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
- data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
- data/test/data/path_traversal/jwilk/relative0.zip +0 -0
- data/test/data/path_traversal/jwilk/relative2.zip +0 -0
- data/test/data/path_traversal/jwilk/symlink.zip +0 -0
- data/test/data/path_traversal/relative1.zip +0 -0
- data/test/data/path_traversal/tilde.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
- data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/symlink.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 +0 -65
- data/test/encryption_test.rb +0 -42
- data/test/entry_set_test.rb +0 -163
- data/test/entry_test.rb +0 -154
- data/test/errors_test.rb +0 -35
- data/test/extra_field_test.rb +0 -76
- data/test/file_extract_directory_test.rb +0 -54
- data/test/file_extract_test.rb +0 -145
- data/test/file_permissions_test.rb +0 -65
- data/test/file_split_test.rb +0 -57
- data/test/file_test.rb +0 -666
- data/test/filesystem/dir_iterator_test.rb +0 -58
- data/test/filesystem/directory_test.rb +0 -139
- data/test/filesystem/file_mutating_test.rb +0 -87
- data/test/filesystem/file_nonmutating_test.rb +0 -508
- data/test/filesystem/file_stat_test.rb +0 -64
- data/test/gentestfiles.rb +0 -126
- data/test/inflater_test.rb +0 -14
- data/test/input_stream_test.rb +0 -182
- data/test/ioextras/abstract_input_stream_test.rb +0 -102
- 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 -154
- data/test/output_stream_test.rb +0 -128
- data/test/pass_thru_compressor_test.rb +0 -30
- data/test/pass_thru_decompressor_test.rb +0 -14
- data/test/path_traversal_test.rb +0 -141
- data/test/samples/example_recursive_test.rb +0 -37
- data/test/settings_test.rb +0 -95
- data/test/test_helper.rb +0 -234
- data/test/unicode_file_names_and_comments_test.rb +0 -62
- data/test/zip64_full_test.rb +0 -51
- data/test/zip64_support_test.rb +0 -14
data/lib/zip/entry_set.rb
CHANGED
@@ -50,6 +50,7 @@ module Zip
|
|
50
50
|
|
51
51
|
def ==(other)
|
52
52
|
return false unless other.kind_of?(EntrySet)
|
53
|
+
|
53
54
|
@entry_set.values == other.entry_set.values
|
54
55
|
end
|
55
56
|
|
@@ -60,6 +61,7 @@ module Zip
|
|
60
61
|
def glob(pattern, flags = ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH | ::File::FNM_EXTGLOB)
|
61
62
|
entries.map do |entry|
|
62
63
|
next nil unless ::File.fnmatch(pattern, entry.name.chomp('/'), flags)
|
64
|
+
|
63
65
|
yield(entry) if block_given?
|
64
66
|
entry
|
65
67
|
end.compact
|
data/lib/zip/errors.rb
CHANGED
data/lib/zip/extra_field.rb
CHANGED
@@ -6,27 +6,27 @@ module Zip
|
|
6
6
|
merge(binstr) if binstr
|
7
7
|
end
|
8
8
|
|
9
|
-
def extra_field_type_exist(binstr, id, len,
|
9
|
+
def extra_field_type_exist(binstr, id, len, index)
|
10
10
|
field_name = ID_MAP[id].name
|
11
11
|
if member?(field_name)
|
12
|
-
self[field_name].merge(binstr[
|
12
|
+
self[field_name].merge(binstr[index, len + 4])
|
13
13
|
else
|
14
|
-
field_obj = ID_MAP[id].new(binstr[
|
14
|
+
field_obj = ID_MAP[id].new(binstr[index, len + 4])
|
15
15
|
self[field_name] = field_obj
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def extra_field_type_unknown(binstr, len,
|
19
|
+
def extra_field_type_unknown(binstr, len, index)
|
20
20
|
create_unknown_item unless self['Unknown']
|
21
|
-
if !len || len + 4 > binstr[
|
22
|
-
self['Unknown'] << binstr[
|
21
|
+
if !len || len + 4 > binstr[index..-1].bytesize
|
22
|
+
self['Unknown'] << binstr[index..-1]
|
23
23
|
return
|
24
24
|
end
|
25
|
-
self['Unknown'] << binstr[
|
25
|
+
self['Unknown'] << binstr[index, len + 4]
|
26
26
|
end
|
27
27
|
|
28
28
|
def create_unknown_item
|
29
|
-
s = ''
|
29
|
+
s = +''
|
30
30
|
class << s
|
31
31
|
alias_method :to_c_dir_bin, :to_s
|
32
32
|
alias_method :to_local_bin, :to_s
|
@@ -36,10 +36,11 @@ module Zip
|
|
36
36
|
|
37
37
|
def merge(binstr)
|
38
38
|
return if binstr.empty?
|
39
|
+
|
39
40
|
i = 0
|
40
41
|
while i < binstr.bytesize
|
41
42
|
id = binstr[i, 2]
|
42
|
-
len = binstr[i + 2, 2].to_s.
|
43
|
+
len = binstr[i + 2, 2].to_s.unpack1('v')
|
43
44
|
if id && ID_MAP.member?(id)
|
44
45
|
extra_field_type_exist(binstr, id, len, i)
|
45
46
|
elsif id
|
@@ -54,6 +55,7 @@ module Zip
|
|
54
55
|
unless (field_class = ID_MAP.values.find { |k| k.name == name })
|
55
56
|
raise Error, "Unknown extra field '#{name}'"
|
56
57
|
end
|
58
|
+
|
57
59
|
self[name] = field_class.new
|
58
60
|
end
|
59
61
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Zip
|
2
2
|
class ExtraField::Generic
|
3
3
|
def self.register_map
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
return unless const_defined?(:HEADER_ID)
|
5
|
+
|
6
|
+
::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.name
|
@@ -12,18 +12,19 @@ module Zip
|
|
12
12
|
|
13
13
|
# return field [size, content] or false
|
14
14
|
def initial_parse(binstr)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
$stderr.puts 'Warning: weired extra feild header ID. skip parsing'
|
15
|
+
return false unless binstr
|
16
|
+
|
17
|
+
if binstr[0, 2] != self.class.const_get(:HEADER_ID)
|
18
|
+
warn 'WARNING: weird extra field header ID. Skip parsing it.'
|
20
19
|
return false
|
21
20
|
end
|
22
|
-
|
21
|
+
|
22
|
+
[binstr[2, 2].unpack1('v'), binstr[4..-1]]
|
23
23
|
end
|
24
24
|
|
25
25
|
def ==(other)
|
26
26
|
return false if self.class != other.class
|
27
|
+
|
27
28
|
each do |k, v|
|
28
29
|
return false if v != other[k]
|
29
30
|
end
|
data/lib/zip/extra_field/ntfs.rb
CHANGED
@@ -19,6 +19,7 @@ module Zip
|
|
19
19
|
|
20
20
|
def merge(binstr)
|
21
21
|
return if binstr.empty?
|
22
|
+
|
22
23
|
size, content = initial_parse(binstr)
|
23
24
|
(size && content) || return
|
24
25
|
|
@@ -27,6 +28,7 @@ module Zip
|
|
27
28
|
|
28
29
|
tag1 = tags[1]
|
29
30
|
return unless tag1
|
31
|
+
|
30
32
|
ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
|
31
33
|
ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
|
32
34
|
ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
|
@@ -65,12 +67,14 @@ module Zip
|
|
65
67
|
|
66
68
|
def parse_tags(content)
|
67
69
|
return {} if content.nil?
|
70
|
+
|
68
71
|
tags = {}
|
69
72
|
i = 0
|
70
73
|
while i < content.bytesize
|
71
74
|
tag, size = content[i, 4].unpack('vv')
|
72
75
|
i += 4
|
73
76
|
break unless tag && size
|
77
|
+
|
74
78
|
value = content[i, size]
|
75
79
|
i += size
|
76
80
|
tags[tag] = value
|
@@ -16,14 +16,16 @@ module Zip
|
|
16
16
|
|
17
17
|
def merge(binstr)
|
18
18
|
return if binstr.empty?
|
19
|
+
|
19
20
|
size, content = initial_parse(binstr)
|
20
21
|
# size: 0 for central directory. 4 for local header
|
21
22
|
return if !size || size == 0
|
23
|
+
|
22
24
|
atime, mtime, uid, gid = content.unpack('VVvv')
|
23
25
|
@uid ||= uid
|
24
26
|
@gid ||= gid
|
25
27
|
@atime ||= atime
|
26
|
-
@mtime ||= mtime
|
28
|
+
@mtime ||= mtime # rubocop:disable Naming/MemoizedInstanceVariableName
|
27
29
|
end
|
28
30
|
|
29
31
|
def ==(other)
|
@@ -4,24 +4,54 @@ module Zip
|
|
4
4
|
HEADER_ID = 'UT'
|
5
5
|
register_map
|
6
6
|
|
7
|
+
ATIME_MASK = 0b010
|
8
|
+
CTIME_MASK = 0b100
|
9
|
+
MTIME_MASK = 0b001
|
10
|
+
|
7
11
|
def initialize(binstr = nil)
|
8
12
|
@ctime = nil
|
9
13
|
@mtime = nil
|
10
14
|
@atime = nil
|
11
|
-
@flag =
|
12
|
-
|
15
|
+
@flag = 0
|
16
|
+
|
17
|
+
merge(binstr) unless binstr.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :atime, :ctime, :mtime, :flag
|
21
|
+
|
22
|
+
def atime=(time)
|
23
|
+
@flag = time.nil? ? @flag & ~ATIME_MASK : @flag | ATIME_MASK
|
24
|
+
@atime = time
|
25
|
+
end
|
26
|
+
|
27
|
+
def ctime=(time)
|
28
|
+
@flag = time.nil? ? @flag & ~CTIME_MASK : @flag | CTIME_MASK
|
29
|
+
@ctime = time
|
13
30
|
end
|
14
31
|
|
15
|
-
|
32
|
+
def mtime=(time)
|
33
|
+
@flag = time.nil? ? @flag & ~MTIME_MASK : @flag | MTIME_MASK
|
34
|
+
@mtime = time
|
35
|
+
end
|
16
36
|
|
17
37
|
def merge(binstr)
|
18
38
|
return if binstr.empty?
|
39
|
+
|
19
40
|
size, content = initial_parse(binstr)
|
20
|
-
size ||
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
41
|
+
return if !size || size <= 0
|
42
|
+
|
43
|
+
@flag, *times = content.unpack('Cl<l<l<')
|
44
|
+
|
45
|
+
# Parse the timestamps, in order, based on which flags are set.
|
46
|
+
return if times[0].nil?
|
47
|
+
|
48
|
+
@mtime ||= ::Zip::DOSTime.at(times.shift) unless @flag & MTIME_MASK == 0
|
49
|
+
return if times[0].nil?
|
50
|
+
|
51
|
+
@atime ||= ::Zip::DOSTime.at(times.shift) unless @flag & ATIME_MASK == 0
|
52
|
+
return if times[0].nil?
|
53
|
+
|
54
|
+
@ctime ||= ::Zip::DOSTime.at(times.shift) unless @flag & CTIME_MASK == 0
|
25
55
|
end
|
26
56
|
|
27
57
|
def ==(other)
|
@@ -32,15 +62,15 @@ module Zip
|
|
32
62
|
|
33
63
|
def pack_for_local
|
34
64
|
s = [@flag].pack('C')
|
35
|
-
|
36
|
-
|
37
|
-
|
65
|
+
s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
|
66
|
+
s << [@atime.to_i].pack('l<') unless @flag & ATIME_MASK == 0
|
67
|
+
s << [@ctime.to_i].pack('l<') unless @flag & CTIME_MASK == 0
|
38
68
|
s
|
39
69
|
end
|
40
70
|
|
41
71
|
def pack_for_c_dir
|
42
72
|
s = [@flag].pack('C')
|
43
|
-
|
73
|
+
s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
|
44
74
|
s
|
45
75
|
end
|
46
76
|
end
|
data/lib/zip/extra_field/unix.rb
CHANGED
@@ -14,12 +14,14 @@ module Zip
|
|
14
14
|
|
15
15
|
def merge(binstr)
|
16
16
|
return if binstr.empty?
|
17
|
+
|
17
18
|
size, content = initial_parse(binstr)
|
18
19
|
# size: 0 for central directory. 4 for local header
|
19
20
|
return if !size || size == 0
|
21
|
+
|
20
22
|
uid, gid = content.unpack('vv')
|
21
23
|
@uid ||= uid
|
22
|
-
@gid ||= gid
|
24
|
+
@gid ||= gid # rubocop:disable Naming/MemoizedInstanceVariableName
|
23
25
|
end
|
24
26
|
|
25
27
|
def ==(other)
|
@@ -9,7 +9,7 @@ module Zip
|
|
9
9
|
# unparsed binary; we don't actually know what this contains
|
10
10
|
# without looking for FFs in the associated file header
|
11
11
|
# call parse after initializing with a binary string
|
12
|
-
@content
|
12
|
+
@content = nil
|
13
13
|
@original_size = nil
|
14
14
|
@compressed_size = nil
|
15
15
|
@relative_header_offset = nil
|
@@ -26,6 +26,7 @@ module Zip
|
|
26
26
|
|
27
27
|
def merge(binstr)
|
28
28
|
return if binstr.empty?
|
29
|
+
|
29
30
|
_, @content = initial_parse(binstr)
|
30
31
|
end
|
31
32
|
|
@@ -45,13 +46,14 @@ module Zip
|
|
45
46
|
end
|
46
47
|
|
47
48
|
def extract(size, format)
|
48
|
-
@content.slice!(0, size).
|
49
|
+
@content.slice!(0, size).unpack1(format)
|
49
50
|
end
|
50
51
|
private :extract
|
51
52
|
|
52
53
|
def pack_for_local
|
53
54
|
# local header entries must contain original size and compressed size; other fields do not apply
|
54
55
|
return '' unless @original_size && @compressed_size
|
56
|
+
|
55
57
|
[@original_size, @compressed_size].pack('Q<Q<')
|
56
58
|
end
|
57
59
|
|
data/lib/zip/file.rb
CHANGED
@@ -49,16 +49,25 @@ module Zip
|
|
49
49
|
MAX_SEGMENT_SIZE = 3_221_225_472
|
50
50
|
MIN_SEGMENT_SIZE = 65_536
|
51
51
|
DATA_BUFFER_SIZE = 8192
|
52
|
-
IO_METHODS = [:tell, :seek, :read, :close]
|
52
|
+
IO_METHODS = [:tell, :seek, :read, :eof, :close]
|
53
|
+
|
54
|
+
DEFAULT_OPTIONS = {
|
55
|
+
restore_ownership: false,
|
56
|
+
restore_permissions: false,
|
57
|
+
restore_times: false
|
58
|
+
}.freeze
|
53
59
|
|
54
60
|
attr_reader :name
|
55
61
|
|
56
|
-
# default -> false
|
62
|
+
# default -> false.
|
57
63
|
attr_accessor :restore_ownership
|
58
|
-
|
64
|
+
|
65
|
+
# default -> false, but will be set to true in a future version.
|
59
66
|
attr_accessor :restore_permissions
|
60
|
-
|
67
|
+
|
68
|
+
# default -> false, but will be set to true in a future version.
|
61
69
|
attr_accessor :restore_times
|
70
|
+
|
62
71
|
# Returns the zip files comment, if it has one
|
63
72
|
attr_accessor :comment
|
64
73
|
|
@@ -66,6 +75,7 @@ module Zip
|
|
66
75
|
# a new archive if it doesn't exist already.
|
67
76
|
def initialize(path_or_io, create = false, buffer = false, options = {})
|
68
77
|
super()
|
78
|
+
options = DEFAULT_OPTIONS.merge(options)
|
69
79
|
@name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
|
70
80
|
@comment = ''
|
71
81
|
@create = create ? true : false # allow any truthy value to mean true
|
@@ -98,18 +108,19 @@ module Zip
|
|
98
108
|
|
99
109
|
@stored_entries = @entry_set.dup
|
100
110
|
@stored_comment = @comment
|
101
|
-
@restore_ownership = options[:restore_ownership]
|
102
|
-
@restore_permissions = options[:restore_permissions]
|
103
|
-
@restore_times = options[:restore_times]
|
111
|
+
@restore_ownership = options[:restore_ownership]
|
112
|
+
@restore_permissions = options[:restore_permissions]
|
113
|
+
@restore_times = options[:restore_times]
|
104
114
|
end
|
105
115
|
|
106
116
|
class << self
|
107
|
-
#
|
108
|
-
# to the block and is automatically closed afterwards just as with
|
109
|
-
# ruby's builtin File
|
110
|
-
def open(file_name, create = false)
|
111
|
-
zf = ::Zip::File.new(file_name, create)
|
117
|
+
# Similar to ::new. If a block is passed the Zip::File object is passed
|
118
|
+
# to the block and is automatically closed afterwards, just as with
|
119
|
+
# ruby's builtin File::open method.
|
120
|
+
def open(file_name, create = false, options = {})
|
121
|
+
zf = ::Zip::File.new(file_name, create, false, options)
|
112
122
|
return zf unless block_given?
|
123
|
+
|
113
124
|
begin
|
114
125
|
yield zf
|
115
126
|
ensure
|
@@ -130,17 +141,18 @@ module Zip
|
|
130
141
|
# (This can be used to extract data from a
|
131
142
|
# downloaded zip archive without first saving it to disk.)
|
132
143
|
def open_buffer(io, options = {})
|
133
|
-
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.
|
144
|
+
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
|
134
145
|
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
135
146
|
end
|
136
147
|
|
137
|
-
io = ::StringIO.new(io) if io.
|
148
|
+
io = ::StringIO.new(io) if io.kind_of?(::String)
|
138
149
|
|
139
150
|
# https://github.com/rubyzip/rubyzip/issues/119
|
140
151
|
io.binmode if io.respond_to?(:binmode)
|
141
152
|
|
142
153
|
zf = ::Zip::File.new(io, true, true, options)
|
143
154
|
return zf unless block_given?
|
155
|
+
|
144
156
|
yield zf
|
145
157
|
|
146
158
|
begin
|
@@ -156,9 +168,9 @@ module Zip
|
|
156
168
|
# whereas ZipInputStream jumps through the entire archive accessing the
|
157
169
|
# local entry headers (which contain the same information as the
|
158
170
|
# central directory).
|
159
|
-
def foreach(
|
160
|
-
open(
|
161
|
-
|
171
|
+
def foreach(zip_file_name, &block)
|
172
|
+
::Zip::File.open(zip_file_name) do |zip_file|
|
173
|
+
zip_file.each(&block)
|
162
174
|
end
|
163
175
|
end
|
164
176
|
|
@@ -219,12 +231,14 @@ module Zip
|
|
219
231
|
def split(zip_file_name, segment_size = MAX_SEGMENT_SIZE, delete_zip_file = true, partial_zip_file_name = nil)
|
220
232
|
raise Error, "File #{zip_file_name} not found" unless ::File.exist?(zip_file_name)
|
221
233
|
raise Errno::ENOENT, zip_file_name unless ::File.readable?(zip_file_name)
|
234
|
+
|
222
235
|
zip_file_size = ::File.size(zip_file_name)
|
223
236
|
segment_size = get_segment_size_for_split(segment_size)
|
224
237
|
return if zip_file_size <= segment_size
|
238
|
+
|
225
239
|
segment_count = get_segment_count_for_split(zip_file_size, segment_size)
|
226
240
|
# Checking for correct zip structure
|
227
|
-
open(zip_file_name) {}
|
241
|
+
::Zip::File.open(zip_file_name) {}
|
228
242
|
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
|
229
243
|
szip_file_index = 0
|
230
244
|
::File.open(zip_file_name, 'rb') do |zip_file|
|
@@ -241,8 +255,8 @@ module Zip
|
|
241
255
|
# Returns an input stream to the specified entry. If a block is passed
|
242
256
|
# the stream object is passed to the block and the stream is automatically
|
243
257
|
# closed afterwards just as with ruby's builtin File.open method.
|
244
|
-
def get_input_stream(entry, &
|
245
|
-
get_entry(entry).get_input_stream(&
|
258
|
+
def get_input_stream(entry, &a_proc)
|
259
|
+
get_entry(entry).get_input_stream(&a_proc)
|
246
260
|
end
|
247
261
|
|
248
262
|
# Returns an output stream to the specified entry. If entry is not an instance
|
@@ -250,7 +264,11 @@ module Zip
|
|
250
264
|
# specified. If a block is passed the stream object is passed to the block and
|
251
265
|
# the stream is automatically closed afterwards just as with ruby's builtin
|
252
266
|
# File.open method.
|
253
|
-
def get_output_stream(entry, permission_int = nil, comment = nil,
|
267
|
+
def get_output_stream(entry, permission_int = nil, comment = nil,
|
268
|
+
extra = nil, compressed_size = nil, crc = nil,
|
269
|
+
compression_method = nil, size = nil, time = nil,
|
270
|
+
&a_proc)
|
271
|
+
|
254
272
|
new_entry =
|
255
273
|
if entry.kind_of?(Entry)
|
256
274
|
entry
|
@@ -264,7 +282,7 @@ module Zip
|
|
264
282
|
new_entry.unix_perms = permission_int
|
265
283
|
zip_streamable_entry = StreamableStream.new(new_entry)
|
266
284
|
@entry_set << zip_streamable_entry
|
267
|
-
zip_streamable_entry.get_output_stream(&
|
285
|
+
zip_streamable_entry.get_output_stream(&a_proc)
|
268
286
|
end
|
269
287
|
|
270
288
|
# Returns the name of the zip archive
|
@@ -274,7 +292,7 @@ module Zip
|
|
274
292
|
|
275
293
|
# Returns a string containing the contents of the specified entry
|
276
294
|
def read(entry)
|
277
|
-
get_input_stream(entry
|
295
|
+
get_input_stream(entry, &:read)
|
278
296
|
end
|
279
297
|
|
280
298
|
# Convenience method for adding the contents of a file to the archive
|
@@ -301,19 +319,19 @@ module Zip
|
|
301
319
|
|
302
320
|
# Renames the specified entry.
|
303
321
|
def rename(entry, new_name, &continue_on_exists_proc)
|
304
|
-
|
322
|
+
found_entry = get_entry(entry)
|
305
323
|
check_entry_exists(new_name, continue_on_exists_proc, 'rename')
|
306
|
-
@entry_set.delete(
|
307
|
-
|
308
|
-
@entry_set <<
|
324
|
+
@entry_set.delete(found_entry)
|
325
|
+
found_entry.name = new_name
|
326
|
+
@entry_set << found_entry
|
309
327
|
end
|
310
328
|
|
311
|
-
# Replaces the specified entry with the contents of
|
329
|
+
# Replaces the specified entry with the contents of src_path (from
|
312
330
|
# the file system).
|
313
|
-
def replace(entry,
|
314
|
-
check_file(
|
331
|
+
def replace(entry, src_path)
|
332
|
+
check_file(src_path)
|
315
333
|
remove(entry)
|
316
|
-
add(entry,
|
334
|
+
add(entry, src_path)
|
317
335
|
end
|
318
336
|
|
319
337
|
# Extracts entry to file dest_path.
|
@@ -326,7 +344,8 @@ module Zip
|
|
326
344
|
# Commits changes that has been made since the previous commit to
|
327
345
|
# the zip archive.
|
328
346
|
def commit
|
329
|
-
return if name.
|
347
|
+
return if name.kind_of?(StringIO) || !commit_required?
|
348
|
+
|
330
349
|
on_success_replace do |tmp_file|
|
331
350
|
::Zip::OutputStream.open(tmp_file) do |zos|
|
332
351
|
@entry_set.each do |e|
|
@@ -366,7 +385,13 @@ module Zip
|
|
366
385
|
# Searches for entry with the specified name. Returns nil if
|
367
386
|
# no entry is found. See also get_entry
|
368
387
|
def find_entry(entry_name)
|
369
|
-
@entry_set.find_entry(entry_name)
|
388
|
+
selected_entry = @entry_set.find_entry(entry_name)
|
389
|
+
return if selected_entry.nil?
|
390
|
+
|
391
|
+
selected_entry.restore_ownership = @restore_ownership
|
392
|
+
selected_entry.restore_permissions = @restore_permissions
|
393
|
+
selected_entry.restore_times = @restore_times
|
394
|
+
selected_entry
|
370
395
|
end
|
371
396
|
|
372
397
|
# Searches for entries given a glob
|
@@ -378,43 +403,43 @@ module Zip
|
|
378
403
|
# if no entry is found.
|
379
404
|
def get_entry(entry)
|
380
405
|
selected_entry = find_entry(entry)
|
381
|
-
raise Errno::ENOENT, entry
|
382
|
-
|
383
|
-
selected_entry.restore_permissions = @restore_permissions
|
384
|
-
selected_entry.restore_times = @restore_times
|
406
|
+
raise Errno::ENOENT, entry if selected_entry.nil?
|
407
|
+
|
385
408
|
selected_entry
|
386
409
|
end
|
387
410
|
|
388
411
|
# Creates a directory
|
389
|
-
def mkdir(
|
390
|
-
raise Errno::EEXIST, "File exists - #{
|
391
|
-
|
392
|
-
|
393
|
-
|
412
|
+
def mkdir(entry_name, permission = 0o755)
|
413
|
+
raise Errno::EEXIST, "File exists - #{entry_name}" if find_entry(entry_name)
|
414
|
+
|
415
|
+
entry_name = entry_name.dup.to_s
|
416
|
+
entry_name << '/' unless entry_name.end_with?('/')
|
417
|
+
@entry_set << ::Zip::StreamableDirectory.new(@name, entry_name, nil, permission)
|
394
418
|
end
|
395
419
|
|
396
420
|
private
|
397
421
|
|
398
|
-
def directory?(
|
399
|
-
|
400
|
-
if
|
422
|
+
def directory?(new_entry, src_path)
|
423
|
+
path_is_directory = ::File.directory?(src_path)
|
424
|
+
if new_entry.directory? && !path_is_directory
|
401
425
|
raise ArgumentError,
|
402
|
-
"entry name '#{
|
403
|
-
"'#{
|
404
|
-
elsif !
|
405
|
-
|
426
|
+
"entry name '#{new_entry}' indicates directory entry, but " \
|
427
|
+
"'#{src_path}' is not a directory"
|
428
|
+
elsif !new_entry.directory? && path_is_directory
|
429
|
+
new_entry.name += '/'
|
406
430
|
end
|
407
|
-
|
431
|
+
new_entry.directory? && path_is_directory
|
408
432
|
end
|
409
433
|
|
410
|
-
def check_entry_exists(
|
434
|
+
def check_entry_exists(entry_name, continue_on_exists_proc, proc_name)
|
411
435
|
continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
|
412
|
-
return unless @entry_set.include?(
|
436
|
+
return unless @entry_set.include?(entry_name)
|
437
|
+
|
413
438
|
if continue_on_exists_proc.call
|
414
|
-
remove get_entry(
|
439
|
+
remove get_entry(entry_name)
|
415
440
|
else
|
416
441
|
raise ::Zip::EntryExistsError,
|
417
|
-
|
442
|
+
proc_name + " failed. Entry #{entry_name} already exists"
|
418
443
|
end
|
419
444
|
end
|
420
445
|
|