minitar 0.8 → 0.12
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/Contributing.md +48 -46
- data/History.md +161 -123
- data/Manifest.txt +1 -0
- data/README.rdoc +1 -21
- data/Rakefile +53 -33
- data/lib/archive/tar/minitar/input.rb +96 -75
- data/lib/archive/tar/minitar/output.rb +6 -6
- data/lib/archive/tar/minitar/posix_header.rb +36 -34
- data/lib/archive/tar/minitar/reader.rb +47 -33
- data/lib/archive/tar/minitar/writer.rb +64 -35
- data/lib/archive/tar/minitar.rb +47 -46
- data/lib/archive-tar-minitar.rb +1 -1
- data/lib/minitar.rb +1 -1
- data/support/hoe/deprecated_gem.rb +64 -0
- data/test/minitest_helper.rb +7 -6
- data/test/support/tar_test_helpers.rb +45 -41
- data/test/test_tar_header.rb +30 -31
- data/test/test_tar_input.rb +38 -30
- data/test/test_tar_output.rb +12 -12
- data/test/test_tar_reader.rb +23 -23
- data/test/test_tar_writer.rb +119 -69
- metadata +70 -47
@@ -1,6 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require
|
3
|
+
require "archive/tar/minitar/reader"
|
4
4
|
|
5
5
|
module Archive::Tar::Minitar
|
6
6
|
# Wraps a Archive::Tar::Minitar::Reader with convenience methods and wrapped
|
@@ -19,14 +19,17 @@ module Archive::Tar::Minitar
|
|
19
19
|
# Archive::Tar::Minitar::Input.open(io) { |input| block } -> obj
|
20
20
|
def self.open(input)
|
21
21
|
stream = new(input)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
|
23
|
+
if block_given?
|
24
|
+
# This exception context must remain, otherwise the stream closes on
|
25
|
+
# open even if a block is not given.
|
26
|
+
begin
|
27
|
+
yield stream
|
28
|
+
ensure
|
29
|
+
stream.close
|
30
|
+
end
|
31
|
+
else
|
32
|
+
stream
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
@@ -48,7 +51,7 @@ module Archive::Tar::Minitar
|
|
48
51
|
def self.each_entry(input)
|
49
52
|
return to_enum(__method__, input) unless block_given?
|
50
53
|
|
51
|
-
open(input) do |stream|
|
54
|
+
Input.open(input) do |stream|
|
52
55
|
stream.each do |entry|
|
53
56
|
yield entry
|
54
57
|
end
|
@@ -68,10 +71,10 @@ module Archive::Tar::Minitar
|
|
68
71
|
# Archive::Tar::Minitar::Input.new(path) -> input
|
69
72
|
def initialize(input)
|
70
73
|
@io = if input.respond_to?(:read)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
74
|
+
input
|
75
|
+
else
|
76
|
+
::Kernel.open(input, "rb")
|
77
|
+
end
|
75
78
|
|
76
79
|
unless Archive::Tar::Minitar.seekable?(@io, :rewind)
|
77
80
|
raise Archive::Tar::Minitar::NonSeekableStream
|
@@ -93,7 +96,7 @@ module Archive::Tar::Minitar
|
|
93
96
|
ensure
|
94
97
|
@tar.rewind
|
95
98
|
end
|
96
|
-
|
99
|
+
alias_method :each, :each_entry
|
97
100
|
|
98
101
|
# Extracts the current +entry+ to +destdir+. If a block is provided, it
|
99
102
|
# yields an +action+ Symbol, the full name of the file being extracted
|
@@ -114,11 +117,11 @@ module Archive::Tar::Minitar
|
|
114
117
|
# cycle.
|
115
118
|
# <tt>:entry</tt>:: The entry being extracted; this is a
|
116
119
|
# Reader::EntryStream, with all methods thereof.
|
117
|
-
def extract_entry(destdir, entry) # :yields action, name, stats:
|
120
|
+
def extract_entry(destdir, entry, options = {}, &block) # :yields action, name, stats:
|
118
121
|
stats = {
|
119
|
-
:current
|
120
|
-
:currinc
|
121
|
-
:entry
|
122
|
+
:current => 0,
|
123
|
+
:currinc => 0,
|
124
|
+
:entry => entry
|
122
125
|
}
|
123
126
|
|
124
127
|
# extract_entry is not vulnerable to prefix '/' vulnerabilities, but it
|
@@ -130,66 +133,16 @@ module Archive::Tar::Minitar
|
|
130
133
|
# leave +destdir+.
|
131
134
|
#
|
132
135
|
# However, squeeze consecutive '/' characters together.
|
133
|
-
full_name = entry.full_name.squeeze(
|
136
|
+
full_name = entry.full_name.squeeze("/")
|
134
137
|
|
135
|
-
if
|
136
|
-
raise SecureRelativePathError,
|
138
|
+
if /\.{2}(?:\/|\z)/.match?(full_name)
|
139
|
+
raise SecureRelativePathError, "Path contains '..'"
|
137
140
|
end
|
138
141
|
|
139
142
|
if entry.directory?
|
140
|
-
|
141
|
-
|
142
|
-
yield :dir, full_name, stats if block_given?
|
143
|
-
|
144
|
-
if Archive::Tar::Minitar.dir?(dest)
|
145
|
-
begin
|
146
|
-
FileUtils.chmod(entry.mode, dest)
|
147
|
-
rescue
|
148
|
-
nil
|
149
|
-
end
|
150
|
-
else
|
151
|
-
File.unlink(dest.chomp('/')) if File.symlink?(dest.chomp('/'))
|
152
|
-
|
153
|
-
FileUtils.mkdir_p(dest, :mode => entry.mode)
|
154
|
-
FileUtils.chmod(entry.mode, dest)
|
155
|
-
end
|
156
|
-
|
157
|
-
fsync_dir(dest)
|
158
|
-
fsync_dir(File.join(dest, '..'))
|
159
|
-
return
|
143
|
+
extract_directory(destdir, full_name, entry, stats, options, &block)
|
160
144
|
else # it's a file
|
161
|
-
destdir
|
162
|
-
FileUtils.mkdir_p(destdir, :mode => 0o755)
|
163
|
-
|
164
|
-
destfile = File.join(destdir, File.basename(full_name))
|
165
|
-
|
166
|
-
File.unlink(destfile) if File.symlink?(destfile)
|
167
|
-
|
168
|
-
# Errno::ENOENT
|
169
|
-
# rubocop:disable Style/RescueModifier
|
170
|
-
FileUtils.chmod(0o600, destfile) rescue nil
|
171
|
-
# rubocop:enable Style/RescueModifier
|
172
|
-
|
173
|
-
yield :file_start, full_name, stats if block_given?
|
174
|
-
|
175
|
-
File.open(destfile, 'wb', entry.mode) do |os|
|
176
|
-
loop do
|
177
|
-
data = entry.read(4096)
|
178
|
-
break unless data
|
179
|
-
|
180
|
-
stats[:currinc] = os.write(data)
|
181
|
-
stats[:current] += stats[:currinc]
|
182
|
-
|
183
|
-
yield :file_progress, full_name, stats if block_given?
|
184
|
-
end
|
185
|
-
os.fsync
|
186
|
-
end
|
187
|
-
|
188
|
-
FileUtils.chmod(entry.mode, destfile)
|
189
|
-
fsync_dir(File.dirname(destfile))
|
190
|
-
fsync_dir(File.join(File.dirname(destfile), '..'))
|
191
|
-
|
192
|
-
yield :file_done, full_name, stats if block_given?
|
145
|
+
extract_file(destdir, full_name, entry, stats, options, &block)
|
193
146
|
end
|
194
147
|
end
|
195
148
|
|
@@ -211,12 +164,80 @@ module Archive::Tar::Minitar
|
|
211
164
|
|
212
165
|
def fsync_dir(dirname)
|
213
166
|
# make sure this hits the disc
|
214
|
-
dir = open(dirname,
|
167
|
+
dir = IO.open(dirname, "rb")
|
215
168
|
dir.fsync
|
216
169
|
rescue # ignore IOError if it's an unpatched (old) Ruby
|
217
170
|
nil
|
218
171
|
ensure
|
219
172
|
dir.close if dir rescue nil # rubocop:disable Style/RescueModifier
|
220
173
|
end
|
174
|
+
|
175
|
+
def extract_directory(destdir, full_name, entry, stats, options)
|
176
|
+
dest = File.join(destdir, full_name)
|
177
|
+
|
178
|
+
yield :dir, full_name, stats if block_given?
|
179
|
+
|
180
|
+
if Archive::Tar::Minitar.dir?(dest)
|
181
|
+
begin
|
182
|
+
FileUtils.chmod(entry.mode, dest)
|
183
|
+
rescue
|
184
|
+
nil
|
185
|
+
end
|
186
|
+
else
|
187
|
+
File.unlink(dest.chomp("/")) if File.symlink?(dest.chomp("/"))
|
188
|
+
|
189
|
+
FileUtils.mkdir_p(dest, :mode => entry.mode)
|
190
|
+
FileUtils.chmod(entry.mode, dest)
|
191
|
+
end
|
192
|
+
|
193
|
+
if options.fetch(:fsync, true)
|
194
|
+
fsync_dir(dest)
|
195
|
+
fsync_dir(File.join(dest, ".."))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def extract_file(destdir, full_name, entry, stats, options)
|
200
|
+
destdir = File.join(destdir, File.dirname(full_name))
|
201
|
+
FileUtils.mkdir_p(destdir, :mode => 0o755)
|
202
|
+
|
203
|
+
destfile = File.join(destdir, File.basename(full_name))
|
204
|
+
|
205
|
+
File.unlink(destfile) if File.symlink?(destfile)
|
206
|
+
|
207
|
+
# Errno::ENOENT
|
208
|
+
# rubocop:disable Style/RescueModifier
|
209
|
+
FileUtils.chmod(0o600, destfile) rescue nil
|
210
|
+
# rubocop:enable Style/RescueModifier
|
211
|
+
|
212
|
+
yield :file_start, full_name, stats if block_given?
|
213
|
+
|
214
|
+
File.open(destfile, "wb", entry.mode) do |os|
|
215
|
+
loop do
|
216
|
+
data = entry.read(4096)
|
217
|
+
break unless data
|
218
|
+
|
219
|
+
stats[:currinc] = os.write(data)
|
220
|
+
stats[:current] += stats[:currinc]
|
221
|
+
|
222
|
+
yield :file_progress, full_name, stats if block_given?
|
223
|
+
end
|
224
|
+
|
225
|
+
if options.fetch(:fsync, true)
|
226
|
+
yield :file_fsync, full_name, stats if block_given?
|
227
|
+
os.fsync
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
FileUtils.chmod(entry.mode, destfile)
|
232
|
+
|
233
|
+
if options.fetch(:fsync, true)
|
234
|
+
yield :dir_fsync, full_name, stats if block_given?
|
235
|
+
|
236
|
+
fsync_dir(File.dirname(destfile))
|
237
|
+
fsync_dir(File.join(File.dirname(destfile), ".."))
|
238
|
+
end
|
239
|
+
|
240
|
+
yield :file_done, full_name, stats if block_given?
|
241
|
+
end
|
221
242
|
end
|
222
243
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require
|
3
|
+
require "archive/tar/minitar/writer"
|
4
4
|
|
5
5
|
module Archive::Tar::Minitar
|
6
6
|
# Wraps a Archive::Tar::Minitar::Writer with convenience methods and wrapped
|
@@ -40,7 +40,7 @@ module Archive::Tar::Minitar
|
|
40
40
|
def self.tar(output)
|
41
41
|
return to_enum(__method__, output) unless block_given?
|
42
42
|
|
43
|
-
open(output) do |stream|
|
43
|
+
Output.open(output) do |stream|
|
44
44
|
yield stream.tar
|
45
45
|
end
|
46
46
|
end
|
@@ -55,10 +55,10 @@ module Archive::Tar::Minitar
|
|
55
55
|
# Archive::Tar::Minitar::Output.new(path) -> output
|
56
56
|
def initialize(output)
|
57
57
|
@io = if output.respond_to?(:write)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
output
|
59
|
+
else
|
60
|
+
::Kernel.open(output, "wb")
|
61
|
+
end
|
62
62
|
@tar = Archive::Tar::Minitar::Writer.new(@io)
|
63
63
|
end
|
64
64
|
|
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
##
|
4
4
|
module Archive; end
|
5
|
+
|
5
6
|
##
|
6
7
|
module Archive::Tar; end
|
8
|
+
|
7
9
|
##
|
8
10
|
module Archive::Tar::Minitar; end
|
9
11
|
|
@@ -36,12 +38,12 @@ module Archive::Tar::Minitar; end
|
|
36
38
|
# unrecognized typeflag value as a regular file."
|
37
39
|
class Archive::Tar::Minitar::PosixHeader
|
38
40
|
BLOCK_SIZE = 512
|
39
|
-
MAGIC_BYTES =
|
41
|
+
MAGIC_BYTES = "ustar".freeze
|
40
42
|
|
41
|
-
GNU_EXT_LONG_LINK =
|
43
|
+
GNU_EXT_LONG_LINK = "././@LongLink"
|
42
44
|
|
43
45
|
# Fields that must be set in a POSIX tar(1) header.
|
44
|
-
REQUIRED_FIELDS = [
|
46
|
+
REQUIRED_FIELDS = [:name, :size, :prefix, :mode].freeze
|
45
47
|
# Fields that may be set in a POSIX tar(1) header.
|
46
48
|
OPTIONAL_FIELDS = [
|
47
49
|
:uid, :gid, :mtime, :checksum, :typeflag, :linkname, :magic, :version,
|
@@ -60,9 +62,9 @@ class Archive::Tar::Minitar::PosixHeader
|
|
60
62
|
attr_accessor :name
|
61
63
|
|
62
64
|
# The pack format passed to Array#pack for encoding a header.
|
63
|
-
HEADER_PACK_FORMAT
|
65
|
+
HEADER_PACK_FORMAT = "a100a8a8a8a12a12a7aaa100a6a2a32a32a8a8a155".freeze
|
64
66
|
# The unpack format passed to String#unpack for decoding a header.
|
65
|
-
HEADER_UNPACK_FORMAT
|
67
|
+
HEADER_UNPACK_FORMAT = "Z100A8A8A8A12A12A8aZ100A6A2Z32Z32A8A8Z155".freeze
|
66
68
|
|
67
69
|
class << self
|
68
70
|
# Creates a new PosixHeader from a data stream.
|
@@ -79,23 +81,23 @@ class Archive::Tar::Minitar::PosixHeader
|
|
79
81
|
|
80
82
|
# Creates a new PosixHeader from a BLOCK_SIZE-byte data buffer.
|
81
83
|
def from_data(data)
|
82
|
-
fields
|
83
|
-
name
|
84
|
-
mode
|
85
|
-
uid
|
86
|
-
gid
|
87
|
-
size
|
88
|
-
mtime
|
89
|
-
checksum
|
90
|
-
typeflag
|
91
|
-
linkname
|
92
|
-
magic
|
93
|
-
version
|
94
|
-
uname
|
95
|
-
gname
|
96
|
-
devmajor
|
97
|
-
devminor
|
98
|
-
prefix
|
84
|
+
fields = data.unpack(HEADER_UNPACK_FORMAT)
|
85
|
+
name = fields.shift
|
86
|
+
mode = fields.shift.oct
|
87
|
+
uid = fields.shift.oct
|
88
|
+
gid = fields.shift.oct
|
89
|
+
size = strict_oct(fields.shift)
|
90
|
+
mtime = fields.shift.oct
|
91
|
+
checksum = fields.shift.oct
|
92
|
+
typeflag = fields.shift
|
93
|
+
linkname = fields.shift
|
94
|
+
magic = fields.shift
|
95
|
+
version = fields.shift.oct
|
96
|
+
uname = fields.shift
|
97
|
+
gname = fields.shift
|
98
|
+
devmajor = fields.shift.oct
|
99
|
+
devminor = fields.shift.oct
|
100
|
+
prefix = fields.shift
|
99
101
|
|
100
102
|
empty = !data.each_byte.any?(&:nonzero?)
|
101
103
|
|
@@ -123,7 +125,7 @@ class Archive::Tar::Minitar::PosixHeader
|
|
123
125
|
private
|
124
126
|
|
125
127
|
def strict_oct(string)
|
126
|
-
return string.oct if
|
128
|
+
return string.oct if /\A[0-7 ]*\z/.match?(string)
|
127
129
|
raise ArgumentError, "#{string.inspect} is not a valid octal string"
|
128
130
|
end
|
129
131
|
end
|
@@ -136,13 +138,13 @@ class Archive::Tar::Minitar::PosixHeader
|
|
136
138
|
end
|
137
139
|
|
138
140
|
v[:mtime] = v[:mtime].to_i
|
139
|
-
v[:checksum] ||=
|
140
|
-
v[:typeflag] ||=
|
141
|
-
v[:magic]
|
142
|
-
v[:version]
|
141
|
+
v[:checksum] ||= ""
|
142
|
+
v[:typeflag] ||= "0"
|
143
|
+
v[:magic] ||= MAGIC_BYTES
|
144
|
+
v[:version] ||= "00"
|
143
145
|
|
144
146
|
FIELDS.each do |f|
|
145
|
-
instance_variable_set("@#{f}", v[f])
|
147
|
+
instance_variable_set(:"@#{f}", v[f])
|
146
148
|
end
|
147
149
|
|
148
150
|
@empty = v[:empty]
|
@@ -161,7 +163,7 @@ class Archive::Tar::Minitar::PosixHeader
|
|
161
163
|
# Returns +true+ if the header is a long name special header which indicates
|
162
164
|
# that the next block of data is the filename.
|
163
165
|
def long_name?
|
164
|
-
typeflag ==
|
166
|
+
typeflag == "L" && name == GNU_EXT_LONG_LINK
|
165
167
|
end
|
166
168
|
|
167
169
|
# A string representation of the header.
|
@@ -169,11 +171,11 @@ class Archive::Tar::Minitar::PosixHeader
|
|
169
171
|
update_checksum
|
170
172
|
header(@checksum)
|
171
173
|
end
|
172
|
-
|
174
|
+
alias_method :to_str, :to_s
|
173
175
|
|
174
176
|
# Update the checksum field.
|
175
177
|
def update_checksum
|
176
|
-
hh = header(
|
178
|
+
hh = header(" " * 8)
|
177
179
|
@checksum = oct(calculate_checksum(hh), 6)
|
178
180
|
end
|
179
181
|
|
@@ -190,13 +192,13 @@ class Archive::Tar::Minitar::PosixHeader
|
|
190
192
|
end
|
191
193
|
|
192
194
|
def calculate_checksum(hdr)
|
193
|
-
hdr.unpack(
|
195
|
+
hdr.unpack("C*").inject { |a, e| a + e }
|
194
196
|
end
|
195
197
|
|
196
198
|
def header(chksum)
|
197
199
|
arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),
|
198
|
-
|
199
|
-
|
200
|
+
oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version,
|
201
|
+
uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
|
200
202
|
str = arr.pack(HEADER_PACK_FORMAT)
|
201
203
|
str + "\0" * ((BLOCK_SIZE - bytesize(str)) % BLOCK_SIZE)
|
202
204
|
end
|
@@ -11,14 +11,21 @@ module Archive::Tar::Minitar
|
|
11
11
|
# This marks the EntryStream closed for reading without closing the
|
12
12
|
# actual data stream.
|
13
13
|
module InvalidEntryStream
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
def read(*)
|
15
|
+
raise ClosedStream
|
16
|
+
end
|
17
|
+
|
18
|
+
def getc
|
19
|
+
raise ClosedStream
|
20
|
+
end
|
21
|
+
|
22
|
+
def rewind
|
23
|
+
raise ClosedStream
|
24
|
+
end
|
25
|
+
|
26
|
+
def closed?
|
27
|
+
true
|
28
|
+
end
|
22
29
|
end
|
23
30
|
|
24
31
|
# EntryStreams are pseudo-streams on top of the main data stream.
|
@@ -30,24 +37,24 @@ module Archive::Tar::Minitar
|
|
30
37
|
end
|
31
38
|
|
32
39
|
def initialize(header, io)
|
33
|
-
@io
|
34
|
-
@name
|
35
|
-
@mode
|
36
|
-
@uid
|
37
|
-
@gid
|
38
|
-
@size
|
39
|
-
@mtime
|
40
|
+
@io = io
|
41
|
+
@name = header.name
|
42
|
+
@mode = header.mode
|
43
|
+
@uid = header.uid
|
44
|
+
@gid = header.gid
|
45
|
+
@size = header.size
|
46
|
+
@mtime = header.mtime
|
40
47
|
@checksum = header.checksum
|
41
48
|
@typeflag = header.typeflag
|
42
49
|
@linkname = header.linkname
|
43
|
-
@magic
|
44
|
-
@version
|
45
|
-
@uname
|
46
|
-
@gname
|
50
|
+
@magic = header.magic
|
51
|
+
@version = header.version
|
52
|
+
@uname = header.uname
|
53
|
+
@gname = header.gname
|
47
54
|
@devmajor = header.devmajor
|
48
55
|
@devminor = header.devminor
|
49
|
-
@prefix
|
50
|
-
@read
|
56
|
+
@prefix = header.prefix
|
57
|
+
@read = 0
|
51
58
|
@orig_pos =
|
52
59
|
if Archive::Tar::Minitar.seekable?(@io)
|
53
60
|
@io.pos
|
@@ -79,25 +86,25 @@ module Archive::Tar::Minitar
|
|
79
86
|
# Returns +true+ if the entry represents a directory.
|
80
87
|
def directory?
|
81
88
|
case @typeflag
|
82
|
-
when
|
89
|
+
when "5"
|
83
90
|
true
|
84
|
-
when
|
91
|
+
when "0", "\0"
|
85
92
|
# If the name ends with a slash, treat it as a directory.
|
86
93
|
# This is what other major tar implementations do for
|
87
94
|
# interoperability and compatibility with older tar variants
|
88
95
|
# and some new ones.
|
89
|
-
@name.end_with?(
|
96
|
+
@name.end_with?("/")
|
90
97
|
else
|
91
98
|
false
|
92
99
|
end
|
93
100
|
end
|
94
|
-
|
101
|
+
alias_method :directory, :directory?
|
95
102
|
|
96
103
|
# Returns +true+ if the entry represents a plain file.
|
97
104
|
def file?
|
98
|
-
(@typeflag ==
|
105
|
+
(@typeflag == "0" || @typeflag == "\0") && !@name.end_with?("/")
|
99
106
|
end
|
100
|
-
|
107
|
+
alias_method :file, :file?
|
101
108
|
|
102
109
|
# Returns +true+ if the current read pointer is at the end of the
|
103
110
|
# EntryStream data.
|
@@ -125,7 +132,7 @@ module Archive::Tar::Minitar
|
|
125
132
|
|
126
133
|
# Returns the full and proper name of the entry.
|
127
134
|
def full_name
|
128
|
-
if @prefix !=
|
135
|
+
if @prefix != ""
|
129
136
|
File.join(@prefix, @name)
|
130
137
|
else
|
131
138
|
@name
|
@@ -185,7 +192,7 @@ module Archive::Tar::Minitar
|
|
185
192
|
def self.each_entry(io)
|
186
193
|
return to_enum(__method__, io) unless block_given?
|
187
194
|
|
188
|
-
open(io) do |reader|
|
195
|
+
Input.open(io) do |reader|
|
189
196
|
reader.each_entry do |entry|
|
190
197
|
yield entry
|
191
198
|
end
|
@@ -195,7 +202,11 @@ module Archive::Tar::Minitar
|
|
195
202
|
# Creates and returns a new Reader object.
|
196
203
|
def initialize(io)
|
197
204
|
@io = io
|
198
|
-
@init_pos =
|
205
|
+
@init_pos = begin
|
206
|
+
io.pos
|
207
|
+
rescue
|
208
|
+
nil
|
209
|
+
end
|
199
210
|
end
|
200
211
|
|
201
212
|
# Resets the read pointer to the beginning of data stream. Do not call
|
@@ -229,14 +240,17 @@ module Archive::Tar::Minitar
|
|
229
240
|
raise Archive::Tar::Minitar::InvalidTarStream if header.size < 0
|
230
241
|
|
231
242
|
if header.long_name?
|
232
|
-
|
243
|
+
name_block = (header.size / 512.0).ceil * 512
|
244
|
+
|
245
|
+
name = @io.read(name_block).rstrip
|
233
246
|
header = PosixHeader.from_stream(@io)
|
247
|
+
|
234
248
|
return if header.empty?
|
235
249
|
header.name = name
|
236
250
|
end
|
237
251
|
|
238
252
|
entry = EntryStream.new(header, @io)
|
239
|
-
size
|
253
|
+
size = entry.size
|
240
254
|
|
241
255
|
yield entry
|
242
256
|
|
@@ -259,7 +273,7 @@ module Archive::Tar::Minitar
|
|
259
273
|
entry.close
|
260
274
|
end
|
261
275
|
end
|
262
|
-
|
276
|
+
alias_method :each, :each_entry
|
263
277
|
|
264
278
|
# Returns false if the reader is open (it never closes).
|
265
279
|
def closed?
|