Class: NTFS::AttribHeader

Inherits:
Object
  • Object
show all
Defined in:
lib/fs/ntfs/attrib_header.rb

Overview

One Attribute Header.

Constant Summary collapse

AF_COMPRESSED =
0x0001
AF_ENCRPYTED =
0x4000
AF_SPARSE =
0x8000
RESIDENT_ATTR_IS_INDEXED =

Attribute is referenced in an index

0x01

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buf) ⇒ AttribHeader

NOTE: All the subordinate objects (attrib header & attributes) take

a buffer (a packed string) starting at the start of the sub object.


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/fs/ntfs/attrib_header.rb', line 83

def initialize(buf)
  raise "MIQ(NTFS::AttribHeader.initialize) Nil buffer" if buf.nil?

  # Decode standard attribute header.
  @header = STANDARD_ATTRIBUTE_HEADER.decode(buf)
  offset  = SIZEOF_STANDARD_ATTRIBUTE_HEADER

  # If type is AT_END we're done.
  return nil if @header['attrib_type'] == AT_END

  # Get accessor values.
  @length  = @header['length']
  @id      = @header['attrib_id']
  @flags   = @header['flags']
  @type    = @header['attrib_type']
  @namelen = @header['name_length']

  # Get the rest of the data (a resident or non-resident struct).
  which = isResident? ? SAH_RESIDENT : SAH_NONRESIDENT
  len   = isResident? ? SIZEOF_SAH_RESIDENT : SIZEOF_SAH_NONRESIDENT
  @specific = which.decode(buf[offset..-1])
  offset += len

  # If there's a name get it.
  @name = buf[offset, (@namelen * 2)].UnicodeToUtf8  if @namelen != 0
end

Instance Attribute Details

#flagsObject (readonly)

Returns the value of attribute flags.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def flags
  @flags
end

#idObject (readonly)

Returns the value of attribute id.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def id
  @id
end

#lengthObject (readonly)

Returns the value of attribute length.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def length
  @length
end

#nameObject (readonly)

Returns the value of attribute name.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def name
  @name
end

#namelenObject (readonly)

Returns the value of attribute namelen.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def namelen
  @namelen
end

#specificObject (readonly)

Returns the value of attribute specific.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def specific
  @specific
end

#typeObject (readonly)

Returns the value of attribute type.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def type
  @type
end

#typeNameObject (readonly)

Returns the value of attribute typeName.



72
73
74
# File 'lib/fs/ntfs/attrib_header.rb', line 72

def typeName
  @typeName
end

Instance Method Details

#containsFileNameIndexes?Boolean

The $I30 is the a “file” name given to NTFS MFT attributes containing file name indexes for directories. NTFS stores the file name contents of the directory in several places, depending on the number of files in the directory:

  • For directories with just a few files, all are stored resident in the MFT entry $INDEX_ROOT

  • For directories with many files, the indexes are stored non-resident in the MFT entry $INDEX_ALLOCATION

  • The allocation status of these entries are managed by the $BITMAP MFT entry

NTFS uses B-tree structures to store and quickly access the data. So, the $INDEX_ROOT attribute (with a name of $I30) was not large enough to store the B-tree index of file names. Instead, it points to index records stored in the non-resident $INDEX_ALLOCATION. Viewing the contents of that file, the B-tree index of file names in the directory.

Returns:

  • (Boolean)


164
165
166
# File 'lib/fs/ntfs/attrib_header.rb', line 164

def containsFileNameIndexes?
  name == "$I30"
end

#dumpObject



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/fs/ntfs/attrib_header.rb', line 168

def dump
  out = "\#<#{self.class}:0x#{'%08x' % object_id}>\n"
  out << "  Type             : 0x#{'%08x' % @header['attrib_type']} (#{typeName})\n"
  out << "  Length           : 0x#{'%08x' % @header['length']}\n"
  out << "  Non resident     : 0x#{'%02x' % @header['non_resident']}\n"
  out << "  Name length      : 0x#{'%02x' % @header['name_length']}\n"
  out << "  Offset to name   : 0x#{'%04x' % @header['name_offset']}\n"
  out << "  Flags            : 0x#{'%04x' % @header['flags']}\n"
  out << "  Attrib id        : 0x#{'%04x' % @header['attrib_id']}\n"

  # Further depends on type.
  if self.isResident?
    out << "  Value length     : 0x#{'%08x' % @specific['value_length']}\n"
    out << "  Value offset     : 0x#{'%04x' % @specific['value_offset']}\n"
    out << "  Resident Flags   : 0x#{'%02x' % @specific['resident_flags']}\n"
  else
    out << "  First VCN        : 0x#{'%016x' % @specific['first_vcn']}\n"
    out << "  Last VCN         : 0x#{'%016x' % @specific['last_vcn']}\n"
    out << "  Mapping Pairs Offset: 0x#{'%04x' % @specific['mapping_pairs_offset']}\n"
    out << "  Compression      : 0x#{'%04x' % @specific['compression_unit']}\n"
    out << "  Allocated size   : 0x#{'%016x' % @specific['allocated_size']}\n"
    out << "  Data size        : 0x#{'%016x' % @specific['data_size']}\n"
    out << "  Initialized size : 0x#{'%016x' % @specific['initialized_size']}\n"
  end
  out << "  Name             : #{@name}\n" if @header['name_length'] > 0
  out << "---\n"
end

#get_value(buf, boot_sector) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/fs/ntfs/attrib_header.rb', line 110

def get_value(buf, boot_sector)
  # Prep a buffer to pass to subobjects.
  if isResident?
    # Resident attributes are after header res struct & name.
    abuf = buf[@specific['value_offset'], @specific['value_length']]
  else
    # Nonresident attributes are defined by data runs.
    alen = @specific['data_size']
    alen = buf.size if alen == 0
    abuf = DataRun.new(boot_sector, buf[@specific['mapping_pairs_offset'], alen], self)
  end

  abuf
end

#isCompressed?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/fs/ntfs/attrib_header.rb', line 138

def isCompressed?
  NTFS::Utils.gotBit?(@flags, AF_COMPRESSED)
end

#isEncrypted?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/fs/ntfs/attrib_header.rb', line 142

def isEncrypted?
  NTFS::Utils.gotBit?(@flags, AF_ENCRYPTED)
end

#isResident?Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/fs/ntfs/attrib_header.rb', line 130

def isResident?
  @header['non_resident'] == 0
end

#isSparse?Boolean

Returns:

  • (Boolean)


146
147
148
# File 'lib/fs/ntfs/attrib_header.rb', line 146

def isSparse?
  NTFS::Utils.gotBit?(@flags, AF_SPARSE)
end

#to_sObject

Name will always be something, either name or N/A



126
127
128
# File 'lib/fs/ntfs/attrib_header.rb', line 126

def to_s
  @name.nil? ? 'N/A' : @name
end