Class: Archive::Tar::PosixHeader

Inherits:
Object
  • Object
show all
Defined in:
lib/archive/tar/minitar.rb

Overview

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.”

Constant Summary collapse

FIELDS =
%w(name mode uid gid size mtime checksum typeflag linkname) +
%w(magic version uname gname devmajor devminor prefix)
HEADER_PACK_FORMAT =
"a100a8a8a8a12a12a7aaa100a6a2a32a32a8a8a155"
HEADER_UNPACK_FORMAT =
"Z100A8A8A8A12A12A8aZ100A6A2Z32Z32A8A8Z155"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(vals) ⇒ PosixHeader

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



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/archive/tar/minitar.rb', line 103

def initialize(vals)
  unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode]
    raise ArgumentError
  end

  vals[:mtime]    ||= 0
  vals[:checksum] ||= ""
  vals[:typeflag] ||= "0"
  vals[:magic]    ||= "ustar"
  vals[:version]  ||= "00"

  FIELDS.each do |field|
    instance_variable_set("@#{field}", vals[field.intern])
  end
  @empty = vals[:empty]
end

Class Method Details

.new_from_stream(stream, long_name = nil) ⇒ Object

Creates a new PosixHeader from a data stream.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/archive/tar/minitar.rb', line 66

def self.new_from_stream(stream, long_name = nil)
  data = stream.read(512)
  fields    = data.unpack(HEADER_UNPACK_FORMAT)
  name      = fields.shift
  mode      = fields.shift.oct
  uid       = fields.shift.oct
  gid       = fields.shift.oct
  size      = fields.shift.oct
  mtime     = fields.shift.oct
  checksum  = fields.shift.oct
  typeflag  = fields.shift
  linkname  = fields.shift
  magic     = fields.shift
  version   = fields.shift.oct
  uname     = fields.shift
  gname     = fields.shift
  devmajor  = fields.shift.oct
  devminor  = fields.shift.oct
  prefix    = fields.shift

  empty = (data == "\0" * 512)

  if typeflag == 'L' && name == '././@LongLink'
   long_name = stream.read(512).rstrip
  	return new_from_stream(stream, long_name)
  end

  new(:name => long_name || name,
	:mode => mode, :uid => uid, :gid => gid,
      :size => size, :mtime => mtime, :checksum => checksum,
      :typeflag => typeflag, :magic => magic, :version => version,
      :uname => uname, :gname => gname, :devmajor => devmajor,
      :devminor => devminor, :prefix => prefix, :empty => empty)
end

Instance Method Details

#empty?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/archive/tar/minitar.rb', line 120

def empty?
  @empty
end

#to_sObject



124
125
126
127
# File 'lib/archive/tar/minitar.rb', line 124

def to_s
  update_checksum
  header(@checksum)
end

#update_checksumObject

Update the checksum field.



130
131
132
133
# File 'lib/archive/tar/minitar.rb', line 130

def update_checksum
  hh = header(" " * 8)
  @checksum = oct(calculate_checksum(hh), 6)
end