minitar 0.7 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe4dcb6889d7dd3e767dc3329f8e874d4359577f219b0a76df859617a253c4fb
4
- data.tar.gz: 345a765b717201d0a47dbb4d52572d68d51797fb41f7df0f314e9a43b160e6de
3
+ metadata.gz: 1440e1c57cdd811497e6717a6f81791816bfb2ec5dce0981d9208c41bcd6f09d
4
+ data.tar.gz: e36cf70bd9acc32d73c95a48c1e67f494853f47603032cac05a84bd366417655
5
5
  SHA512:
6
- metadata.gz: faf3628dd94d2a9f85c86a7662b8699911d022d5b7e75ea2f41effd6fd896252721e953203796cd99739f7c9e756066250d78e613ee606271d79c36753836df2
7
- data.tar.gz: b0311f7166e41805adce3709c53a0acda7dcfe5b732abb16d278706b5e54b56cb2477e3e51bc0bf8d5f6143e61421fd11860a3e1fca22c57ea405f751fa8b369
6
+ metadata.gz: b615673d6e6626606e6e858d453af056870f4b8c88dade5641595b35733491e6dfe2ec32e90d28f7585308a4229f2ace63b47224c0b2877b44c5b028ee3c1031
7
+ data.tar.gz: ea2adda3fdcf9314c325cfa69f7ae5bbf6bc02732c8b131acef7406c45c4c53906a5612940fdc6d026d2fcda809b3a095abbe90bcf96a19f4082a653dcf8cbc3
@@ -82,6 +82,8 @@ Thanks to everyone who has contributed to minitar:
82
82
  * Kazuyoshi Kato
83
83
  * dearblue
84
84
  * Kevin McDermott
85
+ * inkstak
86
+ * Akinori MUSHA (knu)
85
87
 
86
88
  [Minitest]: https://github.com/seattlerb/minitest
87
89
  [quality commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
data/History.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 0.8 / 2019-01-05
2
+
3
+ * inkstak resolved an issue introduced in the fix for [#31][] by allowing
4
+ spaces to be considered valid characters in strict octal handling. Octal
5
+ conversion ignores leading spaces. Merged from a slightly modified version
6
+ of PR [#35][].
7
+
8
+ * dearblue contributed PR [#32][] providing an explicit call to #bytesize for
9
+ strings that include multibyte characters. The PR has been modified to be
10
+ compatible with older versions of Ruby and extend tests.
11
+
12
+ * Akinori MUSHA (knu) contributed PR [#36][] that treats certain badly
13
+ encoded regular files (with names ending in `/`) as if they were
14
+ directories on decode.
15
+
1
16
  ## 0.7 / 2018-02-19
2
17
 
3
18
  * Fixed issue [#28][] with a modified version of PR [#29][] covering the
@@ -142,4 +157,7 @@
142
157
  [#28]: https://github.com/halostatue/minitar/issues/28
143
158
  [#29]: https://github.com/halostatue/minitar/issues/29
144
159
  [#30]: https://github.com/halostatue/minitar/issues/30
160
+ [#32]: https://github.com/halostatue/minitar/issues/32
145
161
  [#33]: https://github.com/halostatue/minitar/issues/33
162
+ [#35]: https://github.com/halostatue/minitar/issues/35
163
+ [#36]: https://github.com/halostatue/minitar/issues/36
@@ -73,7 +73,7 @@ end
73
73
  # tar.close
74
74
  # end
75
75
  module Archive::Tar::Minitar
76
- VERSION = '0.7'.freeze # :nodoc:
76
+ VERSION = '0.8'.freeze # :nodoc:
77
77
 
78
78
  # The base class for any minitar error.
79
79
  Error = Class.new(::StandardError)
@@ -279,7 +279,7 @@ module Archive::Tar::Minitar
279
279
 
280
280
  def included(mod)
281
281
  return if modules.include?(mod)
282
- warn "Including #{self} has been deprecated."
282
+ warn "Including #{self} has been deprecated (Minitar will become a class)."
283
283
  modules << mod
284
284
  end
285
285
 
@@ -288,6 +288,21 @@ module Archive::Tar::Minitar
288
288
  @modules ||= Set.new
289
289
  end
290
290
  end
291
+
292
+ # This exists to make bytesize implementations work across Ruby versions.
293
+ module ByteSize # :nodoc:
294
+ private
295
+
296
+ if ''.respond_to?(:bytesize)
297
+ def bytesize(item)
298
+ item.bytesize
299
+ end
300
+ else
301
+ def bytesize(item)
302
+ item.size
303
+ end
304
+ end
305
+ end
291
306
  end
292
307
 
293
308
  require 'archive/tar/minitar/posix_header'
@@ -123,7 +123,7 @@ class Archive::Tar::Minitar::PosixHeader
123
123
  private
124
124
 
125
125
  def strict_oct(string)
126
- return string.oct if string =~ /\A[0-7]*\z/
126
+ return string.oct if string =~ /\A[0-7 ]*\z/
127
127
  raise ArgumentError, "#{string.inspect} is not a valid octal string"
128
128
  end
129
129
  end
@@ -179,6 +179,8 @@ class Archive::Tar::Minitar::PosixHeader
179
179
 
180
180
  private
181
181
 
182
+ include Archive::Tar::Minitar::ByteSize
183
+
182
184
  def oct(num, len)
183
185
  if num.nil?
184
186
  "\0" * (len + 1)
@@ -196,7 +198,7 @@ class Archive::Tar::Minitar::PosixHeader
196
198
  oct(mtime, 11), chksum, ' ', typeflag, linkname, magic, version,
197
199
  uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
198
200
  str = arr.pack(HEADER_PACK_FORMAT)
199
- str + "\0" * ((BLOCK_SIZE - str.size) % BLOCK_SIZE)
201
+ str + "\0" * ((BLOCK_SIZE - bytesize(str)) % BLOCK_SIZE)
200
202
  end
201
203
 
202
204
  ##
@@ -6,6 +6,8 @@ module Archive::Tar::Minitar
6
6
  # with random access data streams.
7
7
  class Reader
8
8
  include Enumerable
9
+ include Archive::Tar::Minitar::ByteSize
10
+
9
11
  # This marks the EntryStream closed for reading without closing the
10
12
  # actual data stream.
11
13
  module InvalidEntryStream
@@ -21,6 +23,8 @@ module Archive::Tar::Minitar
21
23
 
22
24
  # EntryStreams are pseudo-streams on top of the main data stream.
23
25
  class EntryStream
26
+ include Archive::Tar::Minitar::ByteSize
27
+
24
28
  Archive::Tar::Minitar::PosixHeader::FIELDS.each do |field|
25
29
  attr_reader field.to_sym
26
30
  end
@@ -59,7 +63,7 @@ module Archive::Tar::Minitar
59
63
  len ||= @size - @read
60
64
  max_read = [len, @size - @read].min
61
65
  ret = @io.read(max_read)
62
- @read += ret.size
66
+ @read += bytesize(ret)
63
67
  ret
64
68
  end
65
69
 
@@ -74,13 +78,24 @@ module Archive::Tar::Minitar
74
78
 
75
79
  # Returns +true+ if the entry represents a directory.
76
80
  def directory?
77
- @typeflag == '5'
81
+ case @typeflag
82
+ when '5'
83
+ true
84
+ when '0', "\0"
85
+ # If the name ends with a slash, treat it as a directory.
86
+ # This is what other major tar implementations do for
87
+ # interoperability and compatibility with older tar variants
88
+ # and some new ones.
89
+ @name.end_with?('/')
90
+ else
91
+ false
92
+ end
78
93
  end
79
94
  alias directory directory?
80
95
 
81
96
  # Returns +true+ if the entry represents a plain file.
82
97
  def file?
83
- @typeflag == '0' || @typeflag == "\0"
98
+ (@typeflag == '0' || @typeflag == "\0") && !@name.end_with?('/')
84
99
  end
85
100
  alias file file?
86
101
 
@@ -233,7 +248,7 @@ module Archive::Tar::Minitar
233
248
  else
234
249
  pending = size - entry.bytes_read
235
250
  while pending > 0
236
- bread = @io.read([pending, 4096].min).size
251
+ bread = bytesize(@io.read([pending, 4096].min))
237
252
  raise UnexpectedEOF if @io.eof?
238
253
  pending -= bread
239
254
  end
@@ -3,6 +3,8 @@
3
3
  module Archive::Tar::Minitar
4
4
  # The class that writes a tar format archive to a data stream.
5
5
  class Writer
6
+ include Archive::Tar::Minitar::ByteSize
7
+
6
8
  # The exception raised when the user attempts to write more data to a
7
9
  # BoundedWriteStream than has been allocated.
8
10
  WriteBoundaryOverflow = Class.new(StandardError)
@@ -23,6 +25,8 @@ module Archive::Tar::Minitar
23
25
 
24
26
  # A WriteOnlyStream that also has a size limit.
25
27
  class BoundedWriteStream < WriteOnlyStream
28
+ include Archive::Tar::Minitar::ByteSize
29
+
26
30
  def self.const_missing(c)
27
31
  case c
28
32
  when :FileOverflow
@@ -48,10 +52,11 @@ module Archive::Tar::Minitar
48
52
  end
49
53
 
50
54
  def write(data)
51
- raise WriteBoundaryOverflow if (data.size + @written) > @limit
55
+ size = bytesize(data)
56
+ raise WriteBoundaryOverflow if (size + @written) > @limit
52
57
  @io.write(data)
53
- @written += data.size
54
- data.size
58
+ @written += size
59
+ size
55
60
  end
56
61
  end
57
62
 
@@ -153,23 +158,24 @@ module Archive::Tar::Minitar
153
158
  else
154
159
  raise ArgumentError, 'No data provided' unless data
155
160
 
156
- size = data.size if size < data.size
161
+ bytes = bytesize(data)
162
+ size = bytes if size.nil? || size < bytes
157
163
  end
158
164
 
159
165
  header[:size] = size
160
166
 
161
167
  write_header(name, header)
162
168
 
163
- os = BoundedWriteStream.new(@io, opts[:size])
169
+ os = BoundedWriteStream.new(@io, size)
164
170
  if block_given?
165
171
  yield os
166
172
  else
167
173
  os.write(data)
168
174
  end
169
175
 
170
- min_padding = opts[:size] - os.written
176
+ min_padding = size - os.written
171
177
  @io.write("\0" * min_padding)
172
- remainder = (512 - (opts[:size] % 512)) % 512
178
+ remainder = (512 - (size % 512)) % 512
173
179
  @io.write("\0" * remainder)
174
180
  end
175
181
 
@@ -286,7 +292,7 @@ module Archive::Tar::Minitar
286
292
  end
287
293
 
288
294
  def split_name(name)
289
- if name.size <= 100
295
+ if bytesize(name) <= 100
290
296
  prefix = ''
291
297
  else
292
298
  parts = name.split(/\//)
@@ -296,7 +302,7 @@ module Archive::Tar::Minitar
296
302
 
297
303
  loop do
298
304
  nxt = parts.pop || ''
299
- break if newname.size + 1 + nxt.size >= 100
305
+ break if bytesize(newname) + 1 + bytesize(nxt) >= 100
300
306
  newname = "#{nxt}/#{newname}"
301
307
  end
302
308
 
@@ -305,7 +311,7 @@ module Archive::Tar::Minitar
305
311
  name = newname
306
312
  end
307
313
 
308
- [ name, prefix, (name.size > 100 || prefix.size > 155) ]
314
+ [ name, prefix, (bytesize(name) > 100 || bytesize(prefix) > 155) ]
309
315
  end
310
316
  end
311
317
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'archive/tar/minitar'
4
4
 
5
- if defined? ::Minitar
5
+ if defined?(::Minitar) && ::Minitar != Archive::Tar::Minitar
6
6
  warn <<-EOS
7
7
  ::Minitar is already defined.
8
8
  This will conflict with future versions of minitar.
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TarTestHelpers
4
+ include Archive::Tar::Minitar::ByteSize
5
+
4
6
  Field = Struct.new(:name, :offset, :length)
5
7
  def self.Field(name, length) # rubocop:disable Style/MethodName
6
8
  @offset ||= 0
@@ -72,15 +74,25 @@ module TarTestHelpers
72
74
  end
73
75
 
74
76
  def header(type, fname, dname, length, mode)
77
+ raw_header(type,
78
+ asciiz(fname, 100),
79
+ asciiz(dname, 155),
80
+ z(to_oct(length, 11)),
81
+ z(to_oct(mode, 7))
82
+ )
83
+ end
84
+
85
+ def raw_header(type, fname, dname, length, mode)
75
86
  arr = [
76
- asciiz(fname, 100), z(to_oct(mode, 7)), z(to_oct(nil, 7)),
77
- z(to_oct(nil, 7)), z(to_oct(length, 11)), z(to_oct(0, 11)),
78
- BLANK_CHECKSUM, type, NULL_100, USTAR, DOUBLE_ZERO, asciiz('', 32),
79
- asciiz('', 32), z(to_oct(nil, 7)), z(to_oct(nil, 7)), asciiz(dname, 155)
87
+ fname, mode, z(to_oct(nil, 7)), z(to_oct(nil, 7)),
88
+ length, z(to_oct(0, 11)), BLANK_CHECKSUM, type,
89
+ NULL_100, USTAR, DOUBLE_ZERO, asciiz('', 32), asciiz('', 32),
90
+ z(to_oct(nil, 7)), z(to_oct(nil, 7)), dname
80
91
  ]
92
+
81
93
  h = arr.join.bytes.to_a.pack('C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155')
82
- ret = h + "\0" * (512 - h.size)
83
- assert_equal(512, ret.size)
94
+ ret = h + "\0" * (512 - bytesize(h))
95
+ assert_equal(512, bytesize(ret))
84
96
  ret
85
97
  end
86
98
 
@@ -100,7 +112,7 @@ module TarTestHelpers
100
112
  end
101
113
 
102
114
  def asciiz(str, length)
103
- str + "\0" * (length - str.length)
115
+ str + "\0" * (length - bytesize(str))
104
116
  end
105
117
 
106
118
  def sp(s)
@@ -80,6 +80,30 @@ class TestTarHeader < Minitest::Test
80
80
  assert(h.valid?)
81
81
  end
82
82
 
83
+ def test_from_stream_with_no_strict_octal
84
+ header = tar_file_header('a' * 100, '', 0o12345, -1213)
85
+ io = StringIO.new(header)
86
+
87
+ assert_raises(ArgumentError) do
88
+ Archive::Tar::Minitar::PosixHeader.from_stream(io)
89
+ end
90
+ end
91
+
92
+ def test_from_stream_with_octal_wrapped_by_spaces
93
+ header = raw_header(0,
94
+ asciiz('a' * 100, 100),
95
+ asciiz('', 155),
96
+ " 1213\0",
97
+ z(to_oct(0o12345, 7))
98
+ )
99
+
100
+ header = update_checksum(header)
101
+ io = StringIO.new(header)
102
+ header = Archive::Tar::Minitar::PosixHeader.from_stream(io)
103
+
104
+ assert_equal(651, header.size)
105
+ end
106
+
83
107
  def test_valid_with_invalid_header
84
108
  header = StringIO.new("testing")
85
109
  h = Archive::Tar::Minitar::PosixHeader.from_stream header
@@ -173,4 +173,47 @@ MDUzVDAwNDY0N2VQMGCgAygtLkksAjolEcjIzMOtDqgsLQ2/J0H+gNOjYBSMglEwyAEA2LchrwAGAAA=
173
173
  end
174
174
  end
175
175
  end
176
+
177
+ NON_STRICT_OCTAL_TGZ = Base64.decode64(<<-EOS).freeze
178
+ H4sIAEk55FsAA0tJLEnUK0ks0kuvYqAVMDAwMDMxUQDR5mbmYNrACMjX0zMH
179
+ AzMDUwUDIG1iZmZoYmCgYGBobGpuxqBgQDMXIYHSYqDvgU5KBDIy83CrAypL
180
+ S8NjjgEYKMDpIQLkuzkYZmdOC2Fgfnv5PleTgcjxwvXVXbaOZ3fa61/6KzHD
181
+ pENvy739mUkiKiJnJuyTbzEOuHPxvp+sXmL4E9WlJcc6FkaZh6z8srevpeRc
182
+ Zrb33fXeS3u1Wk7euf7gVqzT7CjOTMHz7+d795uePVN97P2MV15Xav/du77x
183
+ q911yx829XPfTf4v1PZndoXVlJ/fPP4fzrKdvL/q7P5VazRbzly/dHj+8/32
184
+ x/yWrLZnWnQnr+4u/zTTs/tPbT8e/jl/5n9Vm7P7k/4xwr2RsDZv7c+eGgaN
185
+ AQzKIQnSMnNSjWlsByjfm5pi5n8DGDAyQsv/RiZmxqP5nx4gJCOzWAGIQOlA
186
+ wVhPgZdroF00CkbBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTAKRsEoGAWjYBSM
187
+ glEwCkbBKBgFo2AUjIJRMApIAQD0DyzXACgAAA==
188
+ EOS
189
+
190
+ def test_extract_with_non_strict_octal
191
+ reader = Zlib::GzipReader.new(StringIO.new(NON_STRICT_OCTAL_TGZ))
192
+
193
+ assert_raises(ArgumentError) do
194
+ Minitar.unpack(reader, 'data__')
195
+ end
196
+ end
197
+
198
+ OCTAL_WRAPPED_BY_SPACE_TGZ = Base64.decode64(<<-EOS).freeze
199
+ H4sIAOQg5FsAA0tJLEnUK0ks0kuvYqAVMDAwMDMxUQDR5mbmYNrACMhXgAJj
200
+ IyMFA3NzcxMzM0MTAwMFA0NjU3MzBgUDmrkICZQWA30PdFIikJGZh1sdUFla
201
+ Gh5zDMBAAU4PESDfzcEwO3NaCAPz28v3uZoMRI4Xrq/usnU8u9Ne/9JfiRkm
202
+ HXpb7u3PTBJRETkzYZ98i3HAnYv3/WT1EsOfqC4tOdaxMMo8ZOWXvX0tJecy
203
+ s73vrvde2qvVcvLO9Qe3Yp1mR3FmCp5/P9+73/Tsmepj72e88rpS++/e9Y1f
204
+ 7a5b/rCpn/tu8n+htj+zK6ym/Pzm8f9wlu3k/VVn969ao9ly5vqlw/Of77c/
205
+ 5rdktT3Tojt5dXf5p5me3X9q+/Hwz/kz/6vanN2f9I8R7o2EtXlrf/bUMGgM
206
+ YFAOSZCWmZNqTGM7QPne1BQz/xvAAEb+NzIxMx7N//QAIRmZxQpABEoHCsZ6
207
+ CrxcA+2iUTAKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIyC
208
+ UTAKRsEoGAWjYBSMglFACgAAuUHUvwAoAAA=
209
+ EOS
210
+
211
+ def test_extract_octal_wrapped_by_space
212
+ reader = Zlib::GzipReader.new(StringIO.new(OCTAL_WRAPPED_BY_SPACE_TGZ))
213
+ header = Archive::Tar::Minitar::PosixHeader.from_stream(reader)
214
+ assert_equal(210, header.size)
215
+
216
+ reader = Zlib::GzipReader.new(StringIO.new(OCTAL_WRAPPED_BY_SPACE_TGZ))
217
+ Minitar.unpack(reader, 'data__', [])
218
+ end
176
219
  end
@@ -4,6 +4,8 @@ require 'minitar'
4
4
  require 'minitest_helper'
5
5
 
6
6
  class TestTarReader < Minitest::Test
7
+ include Archive::Tar::Minitar::ByteSize
8
+
7
9
  def test_open_no_block
8
10
  str = tar_file_header('lib/foo', '', 0o10644, 10) + "\0" * 512
9
11
  str += tar_file_header('bar', 'baz', 0o644, 0)
@@ -21,13 +23,14 @@ class TestTarReader < Minitest::Test
21
23
  str = tar_file_header('lib/foo', '', 0o10644, 10) + "\0" * 512
22
24
  str += tar_file_header('bar', 'baz', 0o644, 0)
23
25
  str += tar_dir_header('foo', 'bar', 0o12345)
26
+ str += tar_file_header('src/', '', 0o755, 0) # "file" with a trailing slash
24
27
  str += "\0" * 1024
25
- names = %w(lib/foo bar foo)
26
- prefixes = ['', 'baz', 'bar']
27
- modes = [0o10644, 0o644, 0o12345]
28
- sizes = [10, 0, 0]
29
- isdir = [false, false, true]
30
- isfile = [true, true, false]
28
+ names = %w(lib/foo bar foo src/)
29
+ prefixes = ['', 'baz', 'bar', '']
30
+ modes = [0o10644, 0o644, 0o12345, 0o755]
31
+ sizes = [10, 0, 0, 0]
32
+ isdir = [false, false, true, true]
33
+ isfile = [true, true, false, false]
31
34
  Minitar::Reader.new(StringIO.new(str)) do |is|
32
35
  i = 0
33
36
  is.each_entry do |entry|
@@ -51,15 +54,15 @@ class TestTarReader < Minitest::Test
51
54
 
52
55
  def test_rewind_entry_works
53
56
  content = ('a'..'z').to_a.join(' ')
54
- str = tar_file_header('lib/foo', '', 0o10644, content.size) + content +
55
- "\0" * (512 - content.size)
57
+ str = tar_file_header('lib/foo', '', 0o10644, bytesize(content)) +
58
+ content + "\0" * (512 - bytesize(content))
56
59
  str << "\0" * 1024
57
60
  Minitar::Reader.new(StringIO.new(str)) do |is|
58
61
  is.each_entry do |entry|
59
62
  3.times do
60
63
  entry.rewind
61
64
  assert_equal(content, entry.read)
62
- assert_equal(content.size, entry.pos)
65
+ assert_equal(bytesize(content), entry.pos)
63
66
  end
64
67
  end
65
68
  end
@@ -67,8 +70,8 @@ class TestTarReader < Minitest::Test
67
70
 
68
71
  def test_rewind_works
69
72
  content = ('a'..'z').to_a.join(' ')
70
- str = tar_file_header('lib/foo', '', 0o10644, content.size) + content +
71
- "\0" * (512 - content.size)
73
+ str = tar_file_header('lib/foo', '', 0o10644, bytesize(content)) +
74
+ content + "\0" * (512 - bytesize(content))
72
75
  str << "\0" * 1024
73
76
  Minitar::Reader.new(StringIO.new(str)) do |is|
74
77
  3.times do
@@ -85,12 +88,12 @@ class TestTarReader < Minitest::Test
85
88
 
86
89
  def test_read_works
87
90
  contents = ('a'..'z').inject('') { |a, e| a << e * 100 }
88
- str = tar_file_header('lib/foo', '', 0o10644, contents.size) + contents
89
- str += "\0" * (512 - (str.size % 512))
91
+ str = tar_file_header('lib/foo', '', 0o10644, bytesize(contents)) + contents
92
+ str += "\0" * (512 - (bytesize(str) % 512))
90
93
  Minitar::Reader.new(StringIO.new(str)) do |is|
91
94
  is.each_entry do |entry|
92
95
  assert_kind_of(Minitar::Reader::EntryStream, entry)
93
- data = entry.read(3000) # bigger than contents.size
96
+ data = entry.read(3000) # bigger than bytesize(contents)
94
97
  assert_equal(contents, data)
95
98
  assert_equal(true, entry.eof?)
96
99
  end
@@ -99,7 +102,7 @@ class TestTarReader < Minitest::Test
99
102
  is.each_entry do |entry|
100
103
  assert_kind_of(Minitar::Reader::EntryStream, entry)
101
104
  data = entry.read(100)
102
- (entry.size - data.size).times { data << entry.getc.chr }
105
+ (entry.size - bytesize(data)).times { data << entry.getc.chr }
103
106
  assert_equal(contents, data)
104
107
  assert_equal(nil, entry.read(10))
105
108
  assert_equal(true, entry.eof?)
@@ -4,11 +4,15 @@ require 'minitar'
4
4
  require 'minitest_helper'
5
5
 
6
6
  class TestTarWriter < Minitest::Test
7
+ include Archive::Tar::Minitar::ByteSize
8
+
7
9
  class DummyIO
10
+ include Archive::Tar::Minitar::ByteSize
11
+
8
12
  attr_reader :data
9
13
 
10
14
  def initialize
11
- @data = ''
15
+ reset
12
16
  end
13
17
 
14
18
  def write(dat)
@@ -18,11 +22,14 @@ class TestTarWriter < Minitest::Test
18
22
 
19
23
  def reset
20
24
  @data = ''
25
+ @data.force_encoding('ascii-8bit') if @data.respond_to?(:force_encoding)
21
26
  end
22
27
  end
23
28
 
24
29
  def setup
25
30
  @data = 'a' * 10
31
+ @unicode = [0xc3.chr, 0xa5.chr].join * 10
32
+ @unicode.force_encoding('utf-8') if @unicode.respond_to?(:force_encoding)
26
33
  @dummyos = DummyIO.new
27
34
  @os = Minitar::Writer.new(@dummyos)
28
35
  end
@@ -146,12 +153,12 @@ class TestTarWriter < Minitest::Test
146
153
  offset = 512 * 2
147
154
  [content1, content2, ''].each do |data|
148
155
  assert_headers_equal(tar_file_header('lib/bar/baz', '', 0o644,
149
- data.size), dummyos[offset, 512])
156
+ bytesize(data)), dummyos[offset, 512])
150
157
  offset += 512
151
158
  until !data || data == ''
152
159
  chunk = data[0, 512]
153
160
  data[0, 512] = ''
154
- assert_equal(chunk + "\0" * (512 - chunk.size),
161
+ assert_equal(chunk + "\0" * (512 - bytesize(chunk)),
155
162
  dummyos[offset, 512])
156
163
  offset += 512
157
164
  end
@@ -186,7 +193,26 @@ class TestTarWriter < Minitest::Test
186
193
  f.write @data
187
194
  end
188
195
  @os.flush
189
- assert_equal(@data + ("\0" * (512 - @data.size)),
196
+ assert_equal(@data + ("\0" * (512 - bytesize(@data))),
197
+ @dummyos.data[512, 512])
198
+ end
199
+
200
+ def test_write_unicode_data
201
+ @dummyos.reset
202
+
203
+ if @unicode.respond_to?(:bytesize)
204
+ assert_equal 10, @unicode.size
205
+ assert_equal 20, @unicode.bytesize
206
+ @unicode.force_encoding('ascii-8bit')
207
+ end
208
+
209
+ file = ['lib/foo/b', 0xc3.chr, 0xa5.chr, 'r'].join
210
+
211
+ @os.add_file_simple(file, :mode => 0o644, :size => 20) do |f|
212
+ f.write @unicode
213
+ end
214
+ @os.flush
215
+ assert_equal(@unicode + ("\0" * (512 - bytesize(@unicode))),
190
216
  @dummyos.data[512, 512])
191
217
  end
192
218
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitar
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.7'
4
+ version: '0.8'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Austin Ziegler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-28 00:00:00.000000000 Z
11
+ date: 2019-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest