class 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 = Minitar::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
Minitarerror. - 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. - UnsafeFileNameError
-
The exception raised when an entry name cannot be safely written on the current platform (for example, a name containing
:on Windows, which may address an NTFS alternate data stream). - VERSION
Public Class Methods
Source
# File lib/minitar.rb, line 86 def open(dest, mode = "r", &) case mode when "r", "rb" Minitar::Input.open(dest, &) when "w", "wb" Minitar::Output.open(dest, &) else raise ArgumentError, "Unknown open mode #{mode.inspect} for Minitar.open." end end
A convenience method for wrapping Minitar::Input.open (mode r or rb) and Minitar::Output.open (mode w or wb). No other modes are currently supported.
Source
# File lib/minitar.rb, line 247 def pack(src, dest, recurse_dirs = true, &block) require "find" Minitar::Output.open(dest) do |outp| if src.is_a?(Array) src.each do |entry| if dir?(entry) && 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 files specified by src into dest. If src is an Array, then each file detailed therein will be packed into the resulting Minitar::Output stream. If recurse_dirs is true (the default), then directories will be recursed.
If src is not an Array, it will be treated as the source of Find.find; all files matching will be packed.
Source
# File lib/minitar.rb, line 121 def pack_as_file(entry, data, outputter) # :yields: action, name, stats outputter = outputter.tar if outputter.is_a?(Minitar::Output) stats = { gid: nil, uid: nil, mtime: Time.now, size: data&.size || 0, mode: data ? 0o644 : 0o755 } if entry.is_a?(Hash) name = entry[:name] entry.each_pair { next if _1 == :name stats[_1] = _2 unless _2.nil? } else name = entry end if data.nil? # Create a directory yield :dir, name, stats if block_given? outputter.mkdir(name, stats) else outputter.add_file_simple(name, stats) do |os| stats[:current] = 0 yield :file_start, name, stats if block_given? StringIO.open(data, "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 end end
A convenience method to pack the provided data as a file named entry, which may either be a name String or a Hash with the fields described below. When only a name is provided, or only some Hash fields are provided, the default values will apply.
-
:name(required): The filename to be packed into the archive. -
:mode: The mode to be applied. Defaults to0o644for files and0o755for directories. -
:uid: The user owner of the file. Default isnil. -
:gid: The group owner of the file. Default isnil. -
:mtime: The modification Time of the file. Default isTime.now.
If data is nil, a directory will be created. Use an empty String for an empty file.
Source
# File lib/minitar.rb, line 193 def pack_file(entry, outputter) # :yields: action, name, stats outputter = outputter.tar if outputter.is_a?(Minitar::Output) stats = {} if entry.is_a?(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 "Don't yet know how to pack this type of file." end end
A convenience method to pack the file provided. entry may either be a filename string (which will in which case various values for the file will be obtained from File#stat(entry) or a Hash with the fields:
-
:name(required): The filename to be packed into the archive. -
: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 Symbol, the full name of the file being packed, and a Hash of statistical information, just as with Minitar::Input#extract_entry.
The action will be one of:
-
:dir: Theentryis a directory. -
:file_start: Theentryis a file; the extract of the file is just beginning. -
:file_progress: Yielded every 4096 bytes during the extract of the fileentry. -
file_done: Yielded when the fileentryis completed.
The +stats+ hash may contain the following keys:
-
:current: The current total number of bytes read in theentry. -
:currinc: The current number of bytes read in this read cycle. -
:name: The filename packed into the tarchive. -
:mode: The mode to be applied. -
:uid: The user owner of the file,nilon Windows. -
:gid: The group owner of the file,nilon Windows. -
:mtime: The modification Time of the file.
Source
# File lib/minitar.rb, line 272 def unpack(src, dest, files = [], options = {}, &block) Minitar::Input.open(src) do |inp| if File.exist?(dest) && !dir?(dest) raise "Can't unpack to a non-directory." end FileUtils.mkdir_p(dest) unless File.exist?(dest) inp.each do |entry| if files.empty? || files.include?(entry.full_name) inp.extract_entry(dest, entry, options, &block) end end end end
A convenience method to unpack files from src into the directory specified by dest.
If files is not empty, it will act as a full name filter to restrict extraction.