module Tar::Minitar
Synopsis¶ ↑
Using minitar is easy. The simplest case is:
require 'zlib' require 'minitar' # Packs everything that matches Find.find('tests'). # test.tar will automatically be closed by Minitar.pack. Minitar.pack('tests', File.open('test.tar', 'wb')) # Unpacks 'test.tar' to 'x', creating 'x' if necessary. Minitar.unpack('test.tar', 'x')
A gzipped tar can be written with:
# test.tgz will be closed automatically. Minitar.pack('tests', Zlib::GzipWriter.new(File.open('test.tgz', 'wb')) # test.tgz will be closed automatically. Minitar.unpack(Zlib::GzipReader.new(File.open('test.tgz', 'rb')), 'x')
As the case above shows, one need not write to a file. However, it will sometimes require that one dive a little deeper into the API, as in the case of StringIO objects. Note that I’m not providing a block with Minitar::Output
, as Minitar::Output#close
automatically closes both the Output
object and the wrapped data stream object.
begin sgz = Zlib::GzipWriter.new(StringIO.new("")) tar = Output.new(sgz) Find.find('tests') do |entry| Minitar.pack_file(entry, tar) end ensure # Closes both tar and sgz. tar.close end
Constants
- ClosedStream
The exception raised when operations are performed on a stream that has previously been closed.
- Error
The base class for any minitar error.
- FileNameTooLong
The exception raised when a filename exceeds 256 bytes in length, the maximum supported by the standard
Tar
format.- InvalidTarStream
The exception raised when a file contains an invalid Posix header.
- NonSeekableStream
Raised when a wrapped data stream class is not seekable.
- SecureRelativePathError
The exception raised when a file contains a relative path in secure mode (the default for this version).
- UnexpectedEOF
The exception raised when a data stream ends before the amount of data expected in the archive’s
PosixHeader
.
Public Class Methods
Tests if path
refers to a directory. Fixes an apparently corrupted stat()
call on Windows.
# File lib/archive/tar/minitar.rb, line 100 def dir?(path) # rubocop:disable Style/CharacterLiteral File.directory?(path[-1] == ?/ ? path : "#{path}/") # rubocop:enable Style/CharacterLiteral end
A convenience method for wrapping Archive::Tar::Minitar::Input.open (mode r
) and Archive::Tar::Minitar::Output.open (mode w
). No other modes are currently supported.
# File lib/archive/tar/minitar.rb, line 109 def open(dest, mode = 'r', &block) case mode when 'r' Input.open(dest, &block) when 'w' Output.open(dest, &block) else raise 'Unknown open mode for Archive::Tar::Minitar.open.' end end
A convenience method to pack files specified by src
into dest
. If src
is an Array, then each file detailed therein will be packed into the resulting Archive::Tar::Minitar::Output stream; if recurse_dirs
is true, then directories will be recursed.
If src
is an Array, it will be treated as the result of Find.find; all files matching will be packed.
# File lib/archive/tar/minitar.rb, line 224 def pack(src, dest, recurse_dirs = true, &block) require 'find' Output.open(dest) do |outp| if src.kind_of?(Array) src.each do |entry| if dir?(entry) and recurse_dirs Find.find(entry) do |ee| pack_file(ee, outp, &block) end else pack_file(entry, outp, &block) end end else Find.find(src) do |entry| pack_file(entry, outp, &block) end end end end
A convenience method to pack the file provided. entry
may either be a filename (in which case various values for the file (see below) will be obtained from File#stat(entry)
or a Hash with the fields:
:name
-
The filename to be packed into the archive. Required.
:mode
-
The mode to be applied.
:uid
-
The user owner of the file. (Ignored on Windows.)
:gid
-
The group owner of the file. (Ignored on Windows.)
:mtime
-
The modification Time of the file.
During packing, if a block is provided, pack_file yields an action
Symol, the full name of the file being packed, and a Hash of statistical information, just as with Archive::Tar::Minitar::Input#extract_entry.
The action
will be one of:
:dir
-
The
entry
is a directory. :file_start
-
The
entry
is a file; the extract of the file is just beginning. :file_progress
-
Yielded every 4096 bytes during the extract of the
entry
. :file_done
-
Yielded when the
entry
is completed.
The stats
hash contains the following keys:
:current
-
The current total number of bytes read in the
entry
. :currinc
-
The current number of bytes read in this read cycle.
:name
-
The filename to be packed into the tarchive. REQUIRED.
:mode
-
The mode to be applied.
:uid
-
The user owner of the file. (
nil
on Windows.) :gid
-
The group owner of the file. (
nil
on Windows.) :mtime
-
The modification Time of the file.
# File lib/archive/tar/minitar.rb, line 168 def pack_file(entry, outputter) #:yields action, name, stats: if outputter.kind_of?(Archive::Tar::Minitar::Output) outputter = outputter.tar end stats = {} if entry.kind_of?(Hash) name = entry[:name] entry.each { |kk, vv| stats[kk] = vv unless vv.nil? } else name = entry end name = name.sub(%r{\./}, '') stat = File.stat(name) stats[:mode] ||= stat.mode stats[:mtime] ||= stat.mtime stats[:size] = stat.size if windows? stats[:uid] = nil stats[:gid] = nil else stats[:uid] ||= stat.uid stats[:gid] ||= stat.gid end if File.file?(name) outputter.add_file_simple(name, stats) do |os| stats[:current] = 0 yield :file_start, name, stats if block_given? File.open(name, 'rb') do |ff| until ff.eof? stats[:currinc] = os.write(ff.read(4096)) stats[:current] += stats[:currinc] yield :file_progress, name, stats if block_given? end end yield :file_done, name, stats if block_given? end elsif dir?(name) yield :dir, name, stats if block_given? outputter.mkdir(name, stats) else raise %q(Don't yet know how to pack this type of file.) end end
Check whether io
can seek without errors.
# File lib/archive/tar/minitar.rb, line 265 def seekable?(io, methods = nil) # The IO class throws an exception at runtime if we try to change # position on a non-regular file. if io.respond_to?(:stat) io.stat.file? else # Duck-type the rest of this. methods ||= [ :pos, :pos=, :seek, :rewind ] methods = [ methods ] unless methods.kind_of?(Array) methods.all? { |m| io.respond_to?(m) } end end
A convenience method to unpack files from src
into the directory specified by dest
. Only those files named explicitly in files
will be extracted.
# File lib/archive/tar/minitar.rb, line 248 def unpack(src, dest, files = [], options = {}, &block) Input.open(src) do |inp| if File.exist?(dest) and !dir?(dest) raise %q(Can't unpack to a non-directory.) end FileUtils.mkdir_p(dest) unless File.exist?(dest) inp.each do |entry| if files.empty? or files.include?(entry.full_name) inp.extract_entry(dest, entry, options, &block) end end end end
Private Class Methods
# File lib/archive/tar/minitar.rb, line 280 def included(mod) return if modules.include?(mod) warn "Including #{self} has been deprecated (Minitar will become a class)." modules << mod end
# File lib/archive/tar/minitar.rb, line 286 def modules require 'set' @modules ||= Set.new end