Source code for dfvfs.vfs.tsk_directory

# -*- coding: utf-8 -*-
"""The SleuthKit (TSK) directory implementation."""

import pytsk3

from dfvfs.lib import errors
from dfvfs.path import tsk_path_spec
from dfvfs.vfs import directory


[docs] class TSKDirectory(directory.Directory): """File system directory that uses pytsk3.""" def _EntriesGenerator(self): """Retrieves directory entries. Since a directory can contain a vast number of entries using a generator is more memory efficient. Yields: TSKPathSpec: a path specification. Raises: BackEndError: if pytsk3 cannot open the directory. """ # Opening a file by inode number is faster than opening a file # by location. inode = getattr(self.path_spec, 'inode', None) location = getattr(self.path_spec, 'location', None) fs_info = self._file_system.GetFsInfo() tsk_directory = None try: if inode is not None: tsk_directory = fs_info.open_dir(inode=inode) elif location is not None: tsk_directory = fs_info.open_dir(path=location) except IOError as exception: raise errors.BackEndError( f'Unable to open directory with error: {exception!s}') if tsk_directory: for tsk_directory_entry in tsk_directory: # Note that because pytsk3.Directory does not explicitly define info # we need to check if the attribute exists and has a value other # than None. if getattr(tsk_directory_entry, 'info', None) is None: continue # Note that because pytsk3.TSK_FS_FILE does not explicitly define # fs_info we need to check if the attribute exists and has a value # other than None. if getattr(tsk_directory_entry.info, 'fs_info', None) is None: continue # Note that because pytsk3.TSK_FS_FILE does not explicitly define meta # we need to check if the attribute exists and has a value other # than None. if getattr(tsk_directory_entry.info, 'meta', None) is None: # Most directory entries will have an "inode" but not all, e.g. # previously deleted files. Currently directory entries without # a pytsk3.TSK_FS_META object are ignored. continue # Note that because pytsk3.TSK_FS_META does not explicitly define addr # we need to check if the attribute exists. if not hasattr(tsk_directory_entry.info.meta, 'addr'): continue directory_entry_inode = tsk_directory_entry.info.meta.addr directory_entry = None # Ignore references to self. if directory_entry_inode == inode: continue # On non-NTFS file systems ignore inode 0. if directory_entry_inode == 0 and not self._file_system.IsNTFS(): continue # Note that because pytsk3.TSK_FS_FILE does not explicitly define name # we need to check if the attribute exists and has a value other # than None. if getattr(tsk_directory_entry.info, 'name', None) is not None: # Ignore file entries marked as "unallocated". flags = getattr(tsk_directory_entry.info.name, 'flags', 0) if int(flags) & pytsk3.TSK_FS_NAME_FLAG_UNALLOC: continue directory_entry = getattr(tsk_directory_entry.info.name, 'name', '') try: # pytsk3 returns an UTF-8 encoded byte string. directory_entry = directory_entry.decode('utf8') except UnicodeError: # Continue here since we cannot represent the directory entry. continue if directory_entry: # Ignore references to self or parent. if directory_entry in ['.', '..']: continue if not location or location == self._file_system.PATH_SEPARATOR: directory_entry = self._file_system.JoinPath([directory_entry]) else: directory_entry = self._file_system.JoinPath([ location, directory_entry]) yield tsk_path_spec.TSKPathSpec( inode=directory_entry_inode, location=directory_entry, parent=self.path_spec.parent)