Source code for rawdisk.plugins.filesystems.ntfs.mft_entry

# -*- coding: utf-8 -*-


from .mft_attribute import MFT_ATTR_FILENAME, MftAttr
from rawdisk.util.rawstruct import RawStruct
from .headers import MFT_RECORD_HEADER

MFT_ENTRY_HEADER_SIZE = 48


[docs]class MftEntry(RawStruct): """Represents MFT table entry. Attributes: offset (uint): MFT entry offset starting from the beginning of \ disk in bytes. attributes (list): List of initialized mft attribute objects \ (eg. :class:`~.mft_attribute.MftAttrStandardInformation`). header (MftEntryHeader): Initialized \ :class:`~.mft_entry_header.MftEntryHeader`. """ def __init__( self, data=None, offset=None, length=None, filename=None, index=None ): RawStruct.__init__( self, data=data, filename=filename, offset=offset, length=length ) self.index = index self.attributes = [] self.fname_str = "" self.header = MFT_RECORD_HEADER( self.get_string(0, 4), # signature self.get_ushort_le(4), # upd_seq_array_offset self.get_ushort_le(6), # upd_seq_array_size self.get_ulonglong_le(8), # logfile_seq_number self.get_ushort_le(16), # seq_number self.get_ushort_le(18), # hard_link_count self.get_ushort_le(20), # first_attr_offset self.get_ushort_le(22), # flags self.get_uint_le(24), # used_size self.get_ushort_le(28), # allocated_size self.get_ulonglong_le(30), # base_file_record self.get_ushort_le(38), # next_attr_id self.get_uint_le(42) # mft_record_number ) self.name_str = self._get_entry_name(self.index) self._load_attributes() @property def is_directory(self): return self.header.flags & 0x0002 @property def is_file(self): return not self.is_directory @property def is_in_use(self): return self.header.flags & 0x0001 @property def used_size(self): return self.header.used_size def _load_attributes(self): free_space = self.size - MFT_ENTRY_HEADER_SIZE offset = self.header.first_attr_offset while free_space > 0: attr = self._get_attribute(offset) if (attr is not None): if attr.header.type == MFT_ATTR_FILENAME: self.fname_str = attr.fname self.attributes.append(attr) free_space = free_space - attr.header.length offset = offset + attr.header.length else: break
[docs] def lookup_attribute(self, attr_type_id): for attr in self.attributes: if attr.header.type == attr_type_id: return attr return None
def _get_attribute(self, offset): """Determines attribute type at the offset and returns \ initialized attribute object. Returns: MftAttr: One of the attribute objects \ (eg. :class:`~.mft_attribute.MftAttrFilename`). None: If atttribute type does not mach any one of the supported \ attribute types. """ attr_type = self.get_uint_le(offset) # Attribute length is in header @ offset 0x4 length = self.get_uint_le(offset + 0x04) data = self.get_chunk(offset, length) return MftAttr.factory(attr_type, data) def _get_entry_name(self, index): names = { 0: "Master File Table", 1: "Master File Table Mirror", 2: "Log File", 3: "Volume File", 4: "Attribute Definition Table", 5: "Root Directory", 6: "Volume Bitmap", 7: "Boot Sector", 8: "Bad Cluster List", 9: "Security", 10: "Upcase Table", 11: "Extend Table", } return names.get(index, "(unknown/unnamed)") def __str__(self): result = ( "File: %d\n%s (%s)" % ( self.index, self.name_str, self.fname_str )) for attr in self.attributes: result = result + "\n\t" + str(attr) return result