rubyzip 1.1.7 → 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.

Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +69 -32
  3. data/Rakefile +3 -4
  4. data/lib/zip.rb +3 -5
  5. data/lib/zip/central_directory.rb +7 -7
  6. data/lib/zip/compressor.rb +0 -0
  7. data/lib/zip/constants.rb +2 -2
  8. data/lib/zip/crypto/null_encryption.rb +3 -3
  9. data/lib/zip/crypto/traditional_encryption.rb +5 -5
  10. data/lib/zip/decompressor.rb +2 -2
  11. data/lib/zip/deflater.rb +8 -6
  12. data/lib/zip/dos_time.rb +4 -5
  13. data/lib/zip/entry.rb +68 -80
  14. data/lib/zip/entry_set.rb +11 -11
  15. data/lib/zip/errors.rb +1 -0
  16. data/lib/zip/extra_field.rb +6 -6
  17. data/lib/zip/extra_field/generic.rb +7 -7
  18. data/lib/zip/extra_field/ntfs.rb +14 -16
  19. data/lib/zip/extra_field/old_unix.rb +9 -10
  20. data/lib/zip/extra_field/universal_time.rb +14 -14
  21. data/lib/zip/extra_field/unix.rb +8 -9
  22. data/lib/zip/extra_field/zip64.rb +12 -11
  23. data/lib/zip/extra_field/zip64_placeholder.rb +1 -1
  24. data/lib/zip/file.rb +45 -49
  25. data/lib/zip/filesystem.rb +132 -135
  26. data/lib/zip/inflater.rb +3 -3
  27. data/lib/zip/input_stream.rb +13 -7
  28. data/lib/zip/ioextras.rb +1 -3
  29. data/lib/zip/ioextras/abstract_input_stream.rb +5 -9
  30. data/lib/zip/ioextras/abstract_output_stream.rb +0 -2
  31. data/lib/zip/null_compressor.rb +2 -2
  32. data/lib/zip/null_decompressor.rb +3 -3
  33. data/lib/zip/null_input_stream.rb +0 -0
  34. data/lib/zip/output_stream.rb +8 -9
  35. data/lib/zip/pass_thru_compressor.rb +4 -4
  36. data/lib/zip/pass_thru_decompressor.rb +2 -3
  37. data/lib/zip/streamable_directory.rb +2 -2
  38. data/lib/zip/streamable_stream.rb +2 -2
  39. data/lib/zip/version.rb +1 -1
  40. data/samples/example.rb +29 -39
  41. data/samples/example_filesystem.rb +16 -18
  42. data/samples/example_recursive.rb +33 -24
  43. data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +23 -25
  44. data/samples/qtzip.rb +17 -26
  45. data/samples/write_simple.rb +12 -13
  46. data/samples/zipfind.rb +24 -32
  47. data/test/basic_zip_file_test.rb +11 -15
  48. data/test/case_sensitivity_test.rb +69 -0
  49. data/test/central_directory_entry_test.rb +31 -35
  50. data/test/central_directory_test.rb +46 -50
  51. data/test/crypto/null_encryption_test.rb +2 -2
  52. data/test/crypto/traditional_encryption_test.rb +5 -5
  53. data/test/data/notzippedruby.rb +1 -1
  54. data/test/data/oddExtraField.zip +0 -0
  55. data/test/data/test.xls +0 -0
  56. data/test/deflater_test.rb +10 -12
  57. data/test/encryption_test.rb +2 -2
  58. data/test/entry_set_test.rb +38 -24
  59. data/test/entry_test.rb +76 -78
  60. data/test/errors_test.rb +0 -2
  61. data/test/extra_field_test.rb +19 -21
  62. data/test/file_extract_directory_test.rb +12 -14
  63. data/test/file_extract_test.rb +33 -40
  64. data/test/file_permissions_test.rb +69 -0
  65. data/test/file_split_test.rb +24 -27
  66. data/test/file_test.rb +174 -170
  67. data/test/filesystem/dir_iterator_test.rb +13 -17
  68. data/test/filesystem/directory_test.rb +80 -90
  69. data/test/filesystem/file_mutating_test.rb +51 -63
  70. data/test/filesystem/file_nonmutating_test.rb +222 -228
  71. data/test/filesystem/file_stat_test.rb +17 -19
  72. data/test/gentestfiles.rb +43 -55
  73. data/test/inflater_test.rb +1 -1
  74. data/test/input_stream_test.rb +42 -30
  75. data/test/ioextras/abstract_input_stream_test.rb +21 -22
  76. data/test/ioextras/abstract_output_stream_test.rb +32 -32
  77. data/test/local_entry_test.rb +35 -37
  78. data/test/output_stream_test.rb +20 -21
  79. data/test/pass_thru_compressor_test.rb +5 -6
  80. data/test/pass_thru_decompressor_test.rb +0 -1
  81. data/test/samples/example_recursive_test.rb +37 -0
  82. data/test/settings_test.rb +18 -15
  83. data/test/test_helper.rb +37 -44
  84. data/test/unicode_file_names_and_comments_test.rb +5 -7
  85. data/test/zip64_full_test.rb +9 -11
  86. data/test/zip64_support_test.rb +0 -1
  87. metadata +14 -32
@@ -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[self.const_get(:HEADER_ID)] = self
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 ||= self.to_s.split("::")[-1]
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 "Warning: weired extra feild header ID. skip parsing"
19
+ $stderr.puts 'Warning: weired extra feild header ID. skip parsing'
20
20
  return false
21
21
  end
22
- [binstr[2, 2].unpack("v")[0], binstr[4..-1]]
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] and return false
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("v") << s
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("v") << s
40
+ self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
41
41
  end
42
42
  end
43
43
  end
@@ -5,14 +5,14 @@ module Zip
5
5
  HEADER_ID = [0x000A].pack('v')
6
6
  register_map
7
7
 
8
- WINDOWS_TICK = 10000000.0
9
- SEC_TO_UNIX_EPOCH = 11644473600
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 and merge(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) or return
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
- if tag1
30
- ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack("Q<Q<Q<")
31
- ntfs_mtime and @mtime ||= from_ntfs_time(ntfs_mtime)
32
- ntfs_atime and @atime ||= from_ntfs_time(ntfs_atime)
33
- ntfs_ctime and @ctime ||= from_ntfs_time(ntfs_ctime)
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("Vv")
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 do
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 = "UX"
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 and merge(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 (!size || size == 0)
22
- atime, mtime, uid, gid = content.unpack("VVvv")
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
- @atime == other.atime &&
33
- @mtime == other.mtime
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("VVvv")
37
+ [@atime, @mtime, @uid, @gid].pack('VVvv')
38
38
  end
39
39
 
40
40
  def pack_for_c_dir
41
- [@atime, @mtime].pack("VV")
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 = "UT"
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 and merge(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 or return
21
- @flag, mtime, atime, ctime = content.unpack("CVVV")
22
- mtime and @mtime ||= ::Zip::DOSTime.at(mtime)
23
- atime and @atime ||= ::Zip::DOSTime.at(atime)
24
- ctime and @ctime ||= ::Zip::DOSTime.at(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("C")
35
- @flag & 1 != 0 and s << [@mtime.to_i].pack("V")
36
- @flag & 2 != 0 and s << [@atime.to_i].pack("V")
37
- @flag & 4 != 0 and s << [@ctime.to_i].pack("V")
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("C")
43
- @flag & 1 == 1 and s << [@mtime.to_i].pack("V")
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
@@ -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 = "Ux"
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 and merge(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 (!size || size == 0)
20
- uid, gid = content.unpack("vv")
21
- @uid ||= uid
22
- @gid ||= 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("vv")
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
- @content = nil # 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
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 and merge(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
- other.relative_header_offset == @relative_header_offset &&
23
- other.disk_start_number == @disk_start_number
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("Q<Q<")
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("Q<") if @original_size
61
- packed << [@compressed_size].pack("Q<") if @compressed_size
62
- packed << [@relative_header_offset].pack("Q<") if @relative_header_offset
63
- packed << [@disk_start_number].pack("V") if @disk_start_number
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
@@ -6,7 +6,7 @@ module Zip
6
6
  HEADER_ID = ['9999'].pack('H*') # this ID is used by other libraries such as .NET's Ionic.zip
7
7
  register_map
8
8
 
9
- def initialize(binstr = nil)
9
+ def initialize(_binstr = nil)
10
10
  end
11
11
 
12
12
  def pack_for_local
@@ -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
46
  CREATE = 1
48
47
  SPLIT_SIGNATURE = 0x08074b50
49
48
  ZIP64_EOCD_SIGNATURE = 0x06064b50
50
- MAX_SEGMENT_SIZE = 3221225472
51
- MIN_SEGMENT_SIZE = 65536
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
 
@@ -72,12 +72,15 @@ module Zip
72
72
  case
73
73
  when !buffer && ::File.size?(file_name)
74
74
  @create = nil
75
- @exist_file_perms = ::File.stat(file_name).mode
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
79
  when create
80
+ @file_permissions = create_file_permissions
80
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?"
81
84
  else
82
85
  raise Error, "File #{file_name} not found"
83
86
  end
@@ -115,13 +118,13 @@ module Zip
115
118
  # (This can be used to extract data from a
116
119
  # downloaded zip archive without first saving it to disk.)
117
120
  def open_buffer(io, options = {})
118
- unless io.is_a?(IO) || io.is_a?(String) || io.is_a?(Tempfile)
119
- raise "Zip::File.open_buffer expects an argument of class String, IO, or Tempfile. Found: #{io.class}"
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}"
120
123
  end
121
124
  if io.is_a?(::String)
122
125
  require 'stringio'
123
126
  io = ::StringIO.new(io)
124
- elsif io.is_a?(IO)
127
+ elsif io.respond_to?(:binmode)
125
128
  # https://github.com/rubyzip/rubyzip/issues/119
126
129
  io.binmode
127
130
  end
@@ -131,7 +134,7 @@ module Zip
131
134
  begin
132
135
  zf.write_buffer(io)
133
136
  rescue IOError => e
134
- raise unless e.message == "not opened for writing"
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'%(szip_file_index)}"
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 += buffer_size
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
- self.open(zip_file_name) {}
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, "add")
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
@@ -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,55 @@ module Zip
377
375
 
378
376
  private
379
377
 
380
- def is_directory(newEntry, srcPath)
378
+ def directory?(newEntry, srcPath)
381
379
  srcPathIsDirectory = ::File.directory?(srcPath)
382
- if newEntry.is_directory && !srcPathIsDirectory
380
+ if newEntry.directory? && !srcPathIsDirectory
383
381
  raise ArgumentError,
384
- "entry name '#{newEntry}' indicates directory entry, but "+
385
- "'#{srcPath}' is not a directory"
386
- elsif !newEntry.is_directory && srcPathIsDirectory
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.is_directory && srcPathIsDirectory
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
- if @entry_set.include?(entryName)
395
- if continue_on_exists_proc.call
396
- remove get_entry(entryName)
397
- else
398
- raise ::Zip::EntryExistsError,
399
- procedureName + " failed. Entry #{entryName} already exists"
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
- tmpfile = get_tempfile
412
- tmp_filename = tmpfile.path
413
- ObjectSpace.undefine_finalizer(tmpfile)
414
- tmpfile.close
406
+ tmp_filename = create_tmpname
415
407
  if yield tmp_filename
416
- ::File.rename(tmp_filename, self.name)
417
- if defined?(@exist_file_perms)
418
- ::File.chmod(@exist_file_perms, self.name)
419
- end
408
+ ::File.rename(tmp_filename, name)
409
+ ::File.chmod(@file_permissions, name) if defined?(@file_permissions)
420
410
  end
421
411
  ensure
422
- tmpfile.unlink if tmpfile
412
+ ::File.unlink(tmp_filename) if ::File.exist?(tmp_filename)
423
413
  end
424
414
 
425
- def get_tempfile
426
- temp_file = Tempfile.new(::File.basename(name), ::File.dirname(name))
427
- temp_file.binmode
428
- temp_file
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
429
422
  end
430
423
 
424
+ def create_file_permissions
425
+ ::Zip::RUNNING_ON_WINDOWS ? 0644 : 0666 - ::File.umask
426
+ end
431
427
  end
432
428
  end
433
429