minitar 0.5.4 → 0.6
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 +7 -0
- data/Code-of-Conduct.md +74 -0
- data/Contributing.md +84 -0
- data/History.md +107 -0
- data/Licence.md +15 -0
- data/Manifest.txt +24 -0
- data/README.rdoc +81 -0
- data/Rakefile +46 -107
- data/docs/bsdl.txt +19 -0
- data/docs/ruby.txt +56 -0
- data/lib/archive-tar-minitar.rb +3 -0
- data/lib/archive/tar/minitar.rb +197 -889
- data/lib/archive/tar/minitar/input.rb +212 -0
- data/lib/archive/tar/minitar/output.rb +69 -0
- data/lib/archive/tar/minitar/posix_header.rb +259 -0
- data/lib/archive/tar/minitar/reader.rb +237 -0
- data/lib/archive/tar/minitar/writer.rb +297 -0
- data/lib/minitar.rb +12 -0
- data/test/minitest_helper.rb +11 -0
- data/test/support/tar_test_helpers.rb +119 -0
- data/test/test_tar_header.rb +74 -0
- data/test/test_tar_input.rb +167 -0
- data/test/test_tar_output.rb +53 -0
- data/test/test_tar_reader.rb +148 -0
- data/test/test_tar_writer.rb +190 -0
- metadata +232 -43
- data/ChangeLog +0 -17
- data/Install +0 -6
- data/README +0 -68
- data/bin/minitar +0 -27
- data/lib/archive/tar/minitar/command.rb +0 -814
- data/tests/tc_tar.rb +0 -629
- data/tests/testall.rb +0 -10
@@ -0,0 +1,212 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'archive/tar/minitar/reader'
|
4
|
+
|
5
|
+
module Archive::Tar::Minitar
|
6
|
+
# Wraps a Archive::Tar::Minitar::Reader with convenience methods and wrapped
|
7
|
+
# stream management; Input only works with data streams that can be rewound.
|
8
|
+
class Input
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
# With no associated block, +Input.open+ is a synonym for +Input.new+. If
|
12
|
+
# the optional code block is given, it will be given the new Input as an
|
13
|
+
# argument and the Input object will automatically be closed when the block
|
14
|
+
# terminates (this also closes the wrapped stream object). In this
|
15
|
+
# instance, +Input.open+ returns the value of the block.
|
16
|
+
#
|
17
|
+
# call-seq:
|
18
|
+
# Archive::Tar::Minitar::Input.open(io) -> input
|
19
|
+
# Archive::Tar::Minitar::Input.open(io) { |input| block } -> obj
|
20
|
+
def self.open(input)
|
21
|
+
stream = new(input)
|
22
|
+
return stream unless block_given?
|
23
|
+
yield stream
|
24
|
+
ensure
|
25
|
+
stream.close
|
26
|
+
end
|
27
|
+
|
28
|
+
# Iterates over each entry in the provided input. This wraps the common
|
29
|
+
# pattern of:
|
30
|
+
#
|
31
|
+
# Archive::Tar::Minitar::Input.open(io) do |i|
|
32
|
+
# inp.each do |entry|
|
33
|
+
# # ...
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# If a block is not provided, an enumerator will be created with the same
|
38
|
+
# behaviour.
|
39
|
+
#
|
40
|
+
# call-seq:
|
41
|
+
# Archive::Tar::Minitar::Input.each_entry(io) -> enumerator
|
42
|
+
# Archive::Tar::Minitar::Input.each_entry(io) { |entry| block } -> obj
|
43
|
+
def self.each_entry(input)
|
44
|
+
return to_enum(__method__, input) unless block_given?
|
45
|
+
|
46
|
+
open(input) do |stream|
|
47
|
+
stream.each do |entry|
|
48
|
+
yield entry
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Creates a new Input object. If +input+ is a stream object that responds
|
54
|
+
# to #read, then it will simply be wrapped. Otherwise, one will be created
|
55
|
+
# and opened using Kernel#open. When Input#close is called, the stream
|
56
|
+
# object wrapped will be closed.
|
57
|
+
#
|
58
|
+
# An exception will be raised if the stream that is wrapped does not
|
59
|
+
# support rewinding.
|
60
|
+
#
|
61
|
+
# call-seq:
|
62
|
+
# Archive::Tar::Minitar::Input.new(io) -> input
|
63
|
+
# Archive::Tar::Minitar::Input.new(path) -> input
|
64
|
+
def initialize(input)
|
65
|
+
@io = if input.respond_to?(:read)
|
66
|
+
input
|
67
|
+
else
|
68
|
+
::Kernel.open(input, 'rb')
|
69
|
+
end
|
70
|
+
|
71
|
+
unless Archive::Tar::Minitar.seekable?(@io, :rewind)
|
72
|
+
raise Archive::Tar::Minitar::NonSeekableStream
|
73
|
+
end
|
74
|
+
|
75
|
+
@tar = Reader.new(@io)
|
76
|
+
end
|
77
|
+
|
78
|
+
# When provided a block, iterates through each entry in the archive. When
|
79
|
+
# finished, rewinds to the beginning of the stream.
|
80
|
+
#
|
81
|
+
# If not provided a block, creates an enumerator with the same semantics.
|
82
|
+
def each_entry
|
83
|
+
return to_enum unless block_given?
|
84
|
+
|
85
|
+
@tar.each do |entry|
|
86
|
+
yield entry
|
87
|
+
end
|
88
|
+
ensure
|
89
|
+
@tar.rewind
|
90
|
+
end
|
91
|
+
alias each each_entry
|
92
|
+
|
93
|
+
# Extracts the current +entry+ to +destdir+. If a block is provided, it
|
94
|
+
# yields an +action+ Symbol, the full name of the file being extracted
|
95
|
+
# (+name+), and a Hash of statistical information (+stats+).
|
96
|
+
#
|
97
|
+
# The +action+ will be one of:
|
98
|
+
# <tt>:dir</tt>:: The +entry+ is a directory.
|
99
|
+
# <tt>:file_start</tt>:: The +entry+ is a file; the extract of the
|
100
|
+
# file is just beginning.
|
101
|
+
# <tt>:file_progress</tt>:: Yielded every 4096 bytes during the extract
|
102
|
+
# of the +entry+.
|
103
|
+
# <tt>:file_done</tt>:: Yielded when the +entry+ is completed.
|
104
|
+
#
|
105
|
+
# The +stats+ hash contains the following keys:
|
106
|
+
# <tt>:current</tt>:: The current total number of bytes read in the
|
107
|
+
# +entry+.
|
108
|
+
# <tt>:currinc</tt>:: The current number of bytes read in this read
|
109
|
+
# cycle.
|
110
|
+
# <tt>:entry</tt>:: The entry being extracted; this is a
|
111
|
+
# Reader::EntryStream, with all methods thereof.
|
112
|
+
def extract_entry(destdir, entry) # :yields action, name, stats:
|
113
|
+
stats = {
|
114
|
+
:current => 0,
|
115
|
+
:currinc => 0,
|
116
|
+
:entry => entry
|
117
|
+
}
|
118
|
+
|
119
|
+
# extract_entry is not vulnerable to prefix '/' vulnerabilities, but it
|
120
|
+
# is vulnerable to relative path directories. This code will break this
|
121
|
+
# vulnerability. For this version, we are breaking relative paths HARD by
|
122
|
+
# throwing an exception.
|
123
|
+
#
|
124
|
+
# Future versions may permit relative paths as long as the file does not
|
125
|
+
# leave +destdir+.
|
126
|
+
#
|
127
|
+
# However, squeeze consecutive '/' characters together.
|
128
|
+
full_name = entry.full_name.squeeze('/')
|
129
|
+
|
130
|
+
if full_name =~ /\.{2}(?:\/|\z)/
|
131
|
+
raise SecureRelativePathError, %q(Path contains '..')
|
132
|
+
end
|
133
|
+
|
134
|
+
if entry.directory?
|
135
|
+
dest = File.join(destdir, full_name)
|
136
|
+
|
137
|
+
yield :dir, full_name, stats if block_given?
|
138
|
+
|
139
|
+
if Archive::Tar::Minitar.dir?(dest)
|
140
|
+
begin
|
141
|
+
FileUtils.chmod(entry.mode, dest)
|
142
|
+
rescue
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
else
|
146
|
+
File.unlink(dest.chomp('/')) if File.symlink?(dest.chomp('/'))
|
147
|
+
|
148
|
+
FileUtils.mkdir_p(dest, :mode => entry.mode)
|
149
|
+
FileUtils.chmod(entry.mode, dest)
|
150
|
+
end
|
151
|
+
|
152
|
+
fsync_dir(dest)
|
153
|
+
fsync_dir(File.join(dest, '..'))
|
154
|
+
return
|
155
|
+
else # it's a file
|
156
|
+
destdir = File.join(destdir, File.dirname(full_name))
|
157
|
+
FileUtils.mkdir_p(destdir, :mode => 0o755)
|
158
|
+
|
159
|
+
destfile = File.join(destdir, File.basename(full_name))
|
160
|
+
|
161
|
+
File.unlink(destfile) if File.symlink?(destfile)
|
162
|
+
|
163
|
+
# Errno::ENOENT
|
164
|
+
# rubocop:disable Style/RescueModifier
|
165
|
+
FileUtils.chmod(0o600, destfile) rescue nil
|
166
|
+
# rubocop:enable Style/RescueModifier
|
167
|
+
|
168
|
+
yield :file_start, full_name, stats if block_given?
|
169
|
+
|
170
|
+
File.open(destfile, 'wb', entry.mode) do |os|
|
171
|
+
loop do
|
172
|
+
data = entry.read(4096)
|
173
|
+
break unless data
|
174
|
+
|
175
|
+
stats[:currinc] = os.write(data)
|
176
|
+
stats[:current] += stats[:currinc]
|
177
|
+
|
178
|
+
yield :file_progress, full_name, stats if block_given?
|
179
|
+
end
|
180
|
+
os.fsync
|
181
|
+
end
|
182
|
+
|
183
|
+
FileUtils.chmod(entry.mode, destfile)
|
184
|
+
fsync_dir(File.dirname(destfile))
|
185
|
+
fsync_dir(File.join(File.dirname(destfile), '..'))
|
186
|
+
|
187
|
+
yield :file_done, full_name, stats if block_given?
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Returns the Reader object for direct access.
|
192
|
+
attr_reader :tar
|
193
|
+
|
194
|
+
# Closes both the Reader object and the wrapped data stream.
|
195
|
+
def close
|
196
|
+
@io.close
|
197
|
+
@tar.close
|
198
|
+
end
|
199
|
+
|
200
|
+
private
|
201
|
+
|
202
|
+
def fsync_dir(dirname)
|
203
|
+
# make sure this hits the disc
|
204
|
+
dir = open(dirname, 'rb')
|
205
|
+
dir.fsync
|
206
|
+
rescue # ignore IOError if it's an unpatched (old) Ruby
|
207
|
+
nil
|
208
|
+
ensure
|
209
|
+
dir.close if dir rescue nil # rubocop:disable Style/RescueModifier
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'archive/tar/minitar/writer'
|
4
|
+
|
5
|
+
module Archive::Tar::Minitar
|
6
|
+
# Wraps a Archive::Tar::Minitar::Writer with convenience methods and wrapped
|
7
|
+
# stream management. If the stream provided to Output does not support random
|
8
|
+
# access, only Writer#add_file_simple and Writer#mkdir are guaranteed to
|
9
|
+
# work.
|
10
|
+
class Output
|
11
|
+
# With no associated block, +Output.open+ is a synonym for +Output.new+. If
|
12
|
+
# the optional code block is given, it will be given the new Output as an
|
13
|
+
# argument and the Output object will automatically be closed when the
|
14
|
+
# block terminates (this also closes the wrapped stream object). In this
|
15
|
+
# instance, +Output.open+ returns the value of the block.
|
16
|
+
#
|
17
|
+
# call-seq:
|
18
|
+
# Archive::Tar::Minitar::Output.open(io) -> output
|
19
|
+
# Archive::Tar::Minitar::Output.open(io) { |output| block } -> obj
|
20
|
+
def self.open(output)
|
21
|
+
stream = new(output)
|
22
|
+
return stream unless block_given?
|
23
|
+
yield stream
|
24
|
+
ensure
|
25
|
+
stream.close
|
26
|
+
end
|
27
|
+
|
28
|
+
# Output.tar is a wrapper for Output.open that yields the owned tar object
|
29
|
+
# instead of the Output object. If a block is not provided, an enumerator
|
30
|
+
# will be created with the same behaviour.
|
31
|
+
#
|
32
|
+
# call-seq:
|
33
|
+
# Archive::Tar::Minitar::Output.tar(io) -> enumerator
|
34
|
+
# Archive::Tar::Minitar::Output.tar(io) { |tar| block } -> obj
|
35
|
+
def self.tar(output)
|
36
|
+
return to_enum(__method__, output) unless block_given?
|
37
|
+
|
38
|
+
open(output) do |stream|
|
39
|
+
yield stream.tar
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Creates a new Output object. If +output+ is a stream object that responds
|
44
|
+
# to #write, then it will simply be wrapped. Otherwise, one will be created
|
45
|
+
# and opened using Kernel#open. When Output#close is called, the stream
|
46
|
+
# object wrapped will be closed.
|
47
|
+
#
|
48
|
+
# call-seq:
|
49
|
+
# Archive::Tar::Minitar::Output.new(io) -> output
|
50
|
+
# Archive::Tar::Minitar::Output.new(path) -> output
|
51
|
+
def initialize(output)
|
52
|
+
@io = if output.respond_to?(:write)
|
53
|
+
output
|
54
|
+
else
|
55
|
+
::Kernel.open(output, 'wb')
|
56
|
+
end
|
57
|
+
@tar = Archive::Tar::Minitar::Writer.new(@io)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the Writer object for direct access.
|
61
|
+
attr_reader :tar
|
62
|
+
|
63
|
+
# Closes the Writer object and the wrapped data stream.
|
64
|
+
def close
|
65
|
+
@tar.close
|
66
|
+
@io.close
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
module Archive; end
|
5
|
+
##
|
6
|
+
module Archive::Tar; end
|
7
|
+
##
|
8
|
+
module Archive::Tar::Minitar; end
|
9
|
+
|
10
|
+
# Implements the POSIX tar header as a Ruby class. The structure of
|
11
|
+
# the POSIX tar header is:
|
12
|
+
#
|
13
|
+
# struct tarfile_entry_posix
|
14
|
+
# { // pack/unpack
|
15
|
+
# char name[100]; // ASCII (+ Z unless filled) a100/Z100
|
16
|
+
# char mode[8]; // 0 padded, octal, null a8 /A8
|
17
|
+
# char uid[8]; // 0 padded, octal, null a8 /A8
|
18
|
+
# char gid[8]; // 0 padded, octal, null a8 /A8
|
19
|
+
# char size[12]; // 0 padded, octal, null a12 /A12
|
20
|
+
# char mtime[12]; // 0 padded, octal, null a12 /A12
|
21
|
+
# char checksum[8]; // 0 padded, octal, null, space a8 /A8
|
22
|
+
# char typeflag[1]; // see below a /a
|
23
|
+
# char linkname[100]; // ASCII + (Z unless filled) a100/Z100
|
24
|
+
# char magic[6]; // "ustar\0" a6 /A6
|
25
|
+
# char version[2]; // "00" a2 /A2
|
26
|
+
# char uname[32]; // ASCIIZ a32 /Z32
|
27
|
+
# char gname[32]; // ASCIIZ a32 /Z32
|
28
|
+
# char devmajor[8]; // 0 padded, octal, null a8 /A8
|
29
|
+
# char devminor[8]; // 0 padded, octal, null a8 /A8
|
30
|
+
# char prefix[155]; // ASCII (+ Z unless filled) a155/Z155
|
31
|
+
# };
|
32
|
+
#
|
33
|
+
# The #typeflag is one of several known values.
|
34
|
+
#
|
35
|
+
# POSIX indicates that "A POSIX-compliant implementation must treat any
|
36
|
+
# unrecognized typeflag value as a regular file."
|
37
|
+
class Archive::Tar::Minitar::PosixHeader
|
38
|
+
BLOCK_SIZE = 512
|
39
|
+
|
40
|
+
# Fields that must be set in a POSIX tar(1) header.
|
41
|
+
REQUIRED_FIELDS = [ :name, :size, :prefix, :mode ].freeze
|
42
|
+
# Fields that may be set in a POSIX tar(1) header.
|
43
|
+
OPTIONAL_FIELDS = [
|
44
|
+
:uid, :gid, :mtime, :checksum, :typeflag, :linkname, :magic, :version,
|
45
|
+
:uname, :gname, :devmajor, :devminor
|
46
|
+
].freeze
|
47
|
+
|
48
|
+
# All fields available in a POSIX tar(1) header.
|
49
|
+
FIELDS = (REQUIRED_FIELDS + OPTIONAL_FIELDS).freeze
|
50
|
+
|
51
|
+
FIELDS.each do |f|
|
52
|
+
attr_reader f.to_sym unless f.to_sym == :name
|
53
|
+
end
|
54
|
+
|
55
|
+
# The name of the file. By default, limited to 100 bytes. Required. May be
|
56
|
+
# longer (up to BLOCK_SIZE bytes) if using the GNU long name tar extension.
|
57
|
+
attr_accessor :name
|
58
|
+
|
59
|
+
# The pack format passed to Array#pack for encoding a header.
|
60
|
+
HEADER_PACK_FORMAT = 'a100a8a8a8a12a12a7aaa100a6a2a32a32a8a8a155'.freeze
|
61
|
+
# The unpack format passed to String#unpack for decoding a header.
|
62
|
+
HEADER_UNPACK_FORMAT = 'Z100A8A8A8A12A12A8aZ100A6A2Z32Z32A8A8Z155'.freeze
|
63
|
+
|
64
|
+
class << self
|
65
|
+
# Creates a new PosixHeader from a data stream.
|
66
|
+
def from_stream(stream)
|
67
|
+
from_data(stream.read(BLOCK_SIZE))
|
68
|
+
end
|
69
|
+
|
70
|
+
# Creates a new PosixHeader from a data stream. Deprecated; use
|
71
|
+
# PosixHeader.from_stream instead.
|
72
|
+
def new_from_stream(stream)
|
73
|
+
warn "#{__method__} has been deprecated; use from_stream instead."
|
74
|
+
from_stream(stream)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Creates a new PosixHeader from a BLOCK_SIZE-byte data buffer.
|
78
|
+
def from_data(data)
|
79
|
+
fields = data.unpack(HEADER_UNPACK_FORMAT)
|
80
|
+
name = fields.shift
|
81
|
+
mode = fields.shift.oct
|
82
|
+
uid = fields.shift.oct
|
83
|
+
gid = fields.shift.oct
|
84
|
+
size = fields.shift.oct
|
85
|
+
mtime = fields.shift.oct
|
86
|
+
checksum = fields.shift.oct
|
87
|
+
typeflag = fields.shift
|
88
|
+
linkname = fields.shift
|
89
|
+
magic = fields.shift
|
90
|
+
version = fields.shift.oct
|
91
|
+
uname = fields.shift
|
92
|
+
gname = fields.shift
|
93
|
+
devmajor = fields.shift.oct
|
94
|
+
devminor = fields.shift.oct
|
95
|
+
prefix = fields.shift
|
96
|
+
|
97
|
+
empty = !data.each_byte.any?(&:nonzero?)
|
98
|
+
|
99
|
+
new(
|
100
|
+
:name => name,
|
101
|
+
:mode => mode,
|
102
|
+
:uid => uid,
|
103
|
+
:gid => gid,
|
104
|
+
:size => size,
|
105
|
+
:mtime => mtime,
|
106
|
+
:checksum => checksum,
|
107
|
+
:typeflag => typeflag,
|
108
|
+
:magic => magic,
|
109
|
+
:version => version,
|
110
|
+
:uname => uname,
|
111
|
+
:gname => gname,
|
112
|
+
:devmajor => devmajor,
|
113
|
+
:devminor => devminor,
|
114
|
+
:prefix => prefix,
|
115
|
+
:empty => empty,
|
116
|
+
:linkname => linkname
|
117
|
+
)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Creates a new PosixHeader. A PosixHeader cannot be created unless
|
122
|
+
# +name+, +size+, +prefix+, and +mode+ are provided.
|
123
|
+
def initialize(v)
|
124
|
+
REQUIRED_FIELDS.each do |f|
|
125
|
+
raise ArgumentError, "Field #{f} is required." unless v.key?(f)
|
126
|
+
end
|
127
|
+
|
128
|
+
v[:mtime] = v[:mtime].to_i
|
129
|
+
v[:checksum] ||= ''
|
130
|
+
v[:typeflag] ||= '0'
|
131
|
+
v[:magic] ||= 'ustar'
|
132
|
+
v[:version] ||= '00'
|
133
|
+
|
134
|
+
FIELDS.each do |f|
|
135
|
+
instance_variable_set("@#{f}", v[f])
|
136
|
+
end
|
137
|
+
|
138
|
+
@empty = v[:empty]
|
139
|
+
end
|
140
|
+
|
141
|
+
# Indicates if the header was an empty header.
|
142
|
+
def empty?
|
143
|
+
@empty
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns +true+ if the header is a long name special header which indicates
|
147
|
+
# that the next block of data is the filename.
|
148
|
+
def long_name?
|
149
|
+
typeflag == 'L' && name == '././@LongLink'
|
150
|
+
end
|
151
|
+
|
152
|
+
# A string representation of the header.
|
153
|
+
def to_s
|
154
|
+
update_checksum
|
155
|
+
header(@checksum)
|
156
|
+
end
|
157
|
+
alias to_str to_s
|
158
|
+
|
159
|
+
# Update the checksum field.
|
160
|
+
def update_checksum
|
161
|
+
hh = header(' ' * 8)
|
162
|
+
@checksum = oct(calculate_checksum(hh), 6)
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def oct(num, len)
|
168
|
+
if num.nil?
|
169
|
+
"\0" * (len + 1)
|
170
|
+
else
|
171
|
+
"%0#{len}o" % num
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def calculate_checksum(hdr)
|
176
|
+
hdr.unpack('C*').inject { |a, e| a + e }
|
177
|
+
end
|
178
|
+
|
179
|
+
def header(chksum)
|
180
|
+
arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),
|
181
|
+
oct(mtime, 11), chksum, ' ', typeflag, linkname, magic, version,
|
182
|
+
uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
|
183
|
+
str = arr.pack(HEADER_PACK_FORMAT)
|
184
|
+
str + "\0" * ((BLOCK_SIZE - str.size) % BLOCK_SIZE)
|
185
|
+
end
|
186
|
+
|
187
|
+
##
|
188
|
+
# :attr_reader: size
|
189
|
+
# The size of the file. Required.
|
190
|
+
|
191
|
+
##
|
192
|
+
# :attr_reader: prefix
|
193
|
+
# The prefix of the file; the path before #name. Limited to 155 bytes.
|
194
|
+
# Required.
|
195
|
+
|
196
|
+
##
|
197
|
+
# :attr_reader: mode
|
198
|
+
# The Unix file mode of the file. Stored as an octal integer. Required.
|
199
|
+
|
200
|
+
##
|
201
|
+
# :attr_reader: uid
|
202
|
+
# The Unix owner user ID of the file. Stored as an octal integer.
|
203
|
+
|
204
|
+
##
|
205
|
+
# :attr_reader: uname
|
206
|
+
# The user name of the Unix owner of the file.
|
207
|
+
|
208
|
+
##
|
209
|
+
# :attr_reader: gid
|
210
|
+
# The Unix owner group ID of the file. Stored as an octal integer.
|
211
|
+
|
212
|
+
##
|
213
|
+
# :attr_reader: gname
|
214
|
+
# The group name of the Unix owner of the file.
|
215
|
+
|
216
|
+
##
|
217
|
+
# :attr_reader: mtime
|
218
|
+
# The modification time of the file in epoch seconds. Stored as an
|
219
|
+
# octal integer.
|
220
|
+
|
221
|
+
##
|
222
|
+
# :attr_reader: checksum
|
223
|
+
# The checksum of the file. Stored as an octal integer. Calculated
|
224
|
+
# before encoding the header as a string.
|
225
|
+
|
226
|
+
##
|
227
|
+
# :attr_reader: typeflag
|
228
|
+
# The type of record in the file.
|
229
|
+
#
|
230
|
+
# +0+:: Regular file. NULL should be treated as a synonym, for compatibility
|
231
|
+
# purposes.
|
232
|
+
# +1+:: Hard link.
|
233
|
+
# +2+:: Symbolic link.
|
234
|
+
# +3+:: Character device node.
|
235
|
+
# +4+:: Block device node.
|
236
|
+
# +5+:: Directory.
|
237
|
+
# +6+:: FIFO node.
|
238
|
+
# +7+:: Reserved.
|
239
|
+
|
240
|
+
##
|
241
|
+
# :attr_reader: linkname
|
242
|
+
# The name of the link stored. Not currently used.
|
243
|
+
|
244
|
+
##
|
245
|
+
# :attr_reader: magic
|
246
|
+
# Always "ustar\0".
|
247
|
+
|
248
|
+
##
|
249
|
+
# :attr_reader: version
|
250
|
+
# Always "00"
|
251
|
+
|
252
|
+
##
|
253
|
+
# :attr_reader: devmajor
|
254
|
+
# The major device ID. Not currently used.
|
255
|
+
|
256
|
+
##
|
257
|
+
# :attr_reader: devminor
|
258
|
+
# The minor device ID. Not currently used.
|
259
|
+
end
|