class Archive::Tar::PosixHeader

Archive::Tar::PosixHeader

Implements the POSIX tar header as a Ruby class. The structure of the POSIX tar header is:

struct tarfile_entry_posix
{                      //                               pack/unpack
   char name[100];     // ASCII (+ Z unless filled)     a100/Z100
   char mode[8];       // 0 padded, octal, null         a8  /A8
   char uid[8];        // ditto                         a8  /A8
   char gid[8];        // ditto                         a8  /A8
   char size[12];      // 0 padded, octal, null         a12 /A12
   char mtime[12];     // 0 padded, octal, null         a12 /A12
   char checksum[8];   // 0 padded, octal, null, space  a8  /A8
   char typeflag[1];   // see below                     a   /a
   char linkname[100]; // ASCII + (Z unless filled)     a100/Z100
   char magic[6];      // "ustar\0"                     a6  /A6
   char version[2];    // "00"                          a2  /A2
   char uname[32];     // ASCIIZ                        a32 /Z32
   char gname[32];     // ASCIIZ                        a32 /Z32
   char devmajor[8];   // 0 padded, octal, null         a8  /A8
   char devminor[8];   // 0 padded, octal, null         a8  /A8
   char prefix[155];   // ASCII (+ Z unless filled)     a155/Z155
};

The typeflag may be one of the following known values:

"0"

Regular file. NULL should be treated as a synonym, for compatibility purposes.

"1"

Hard link.

"2"

Symbolic link.

"3"

Character device node.

"4"

Block device node.

"5"

Directory.

"6"

FIFO node.

"7"

Reserved.

POSIX indicates that “A POSIX-compliant implementation must treat any unrecognized typeflag value as a regular file.”

Constants

FIELDS
HEADER_PACK_FORMAT
HEADER_UNPACK_FORMAT

Public Class Methods

new(vals) click to toggle source

Creates a new PosixHeader. A PosixHeader cannot be created unless the name, size, prefix, and mode are provided.

    # File lib/archive/tar/minitar.rb
103 def initialize(vals)
104   unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode]
105     raise ArgumentError
106   end
107 
108   vals[:mtime]    ||= 0
109   vals[:checksum] ||= ""
110   vals[:typeflag] ||= "0"
111   vals[:magic]    ||= "ustar"
112   vals[:version]  ||= "00"
113 
114   FIELDS.each do |field|
115     instance_variable_set("@#{field}", vals[field.intern])
116   end
117   @empty = vals[:empty]
118 end
new_from_stream(stream, long_name = nil) click to toggle source

Creates a new PosixHeader from a data stream.

   # File lib/archive/tar/minitar.rb
66 def self.new_from_stream(stream, long_name = nil)
67   data = stream.read(512)
68   fields    = data.unpack(HEADER_UNPACK_FORMAT)
69   name      = fields.shift
70   mode      = fields.shift.oct
71   uid       = fields.shift.oct
72   gid       = fields.shift.oct
73   size      = fields.shift.oct
74   mtime     = fields.shift.oct
75   checksum  = fields.shift.oct
76   typeflag  = fields.shift
77   linkname  = fields.shift
78   magic     = fields.shift
79   version   = fields.shift.oct
80   uname     = fields.shift
81   gname     = fields.shift
82   devmajor  = fields.shift.oct
83   devminor  = fields.shift.oct
84   prefix    = fields.shift
85 
86   empty = (data == "\0" * 512)
87 
88   if typeflag == 'L' && name == '././@LongLink'
89           long_name = stream.read(512).rstrip
90       return new_from_stream(stream, long_name)
91   end
92 
93   new(:name => long_name || name,
94       :mode => mode, :uid => uid, :gid => gid,
95       :size => size, :mtime => mtime, :checksum => checksum,
96       :typeflag => typeflag, :magic => magic, :version => version,
97       :uname => uname, :gname => gname, :devmajor => devmajor,
98       :devminor => devminor, :prefix => prefix, :empty => empty)
99 end

Public Instance Methods

empty?() click to toggle source
    # File lib/archive/tar/minitar.rb
120 def empty?
121   @empty
122 end
to_s() click to toggle source
    # File lib/archive/tar/minitar.rb
124 def to_s
125   update_checksum
126   header(@checksum)
127 end
update_checksum() click to toggle source

Update the checksum field.

    # File lib/archive/tar/minitar.rb
130 def update_checksum
131   hh = header(" " * 8)
132   @checksum = oct(calculate_checksum(hh), 6)
133 end

Private Instance Methods

calculate_checksum(hdr) click to toggle source
    # File lib/archive/tar/minitar.rb
144 def calculate_checksum(hdr)
145   hdr.unpack("C*").inject { |aa, bb| aa + bb }
146 end
header(chksum) click to toggle source
    # File lib/archive/tar/minitar.rb
148 def header(chksum)
149   arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),
150   oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version,
151   uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
152   str = arr.pack(HEADER_PACK_FORMAT)
153   str + "\0" * ((512 - str.size) % 512)
154 end
oct(num, len) click to toggle source
    # File lib/archive/tar/minitar.rb
136 def oct(num, len)
137   if num.nil?
138     "\0" * (len + 1)
139   else
140     "%0#{len}o" % num
141   end
142 end