def main(): parser = argparse.ArgumentParser(description='Inspect ' 'a given MFT file record.') parser.add_argument('-a', action="store", metavar="cache_size", type=int, dest="cache_size", default=1024, help="Size of cache.") parser.add_argument('-p', action="store", metavar="prefix", nargs=1, dest="prefix", default="\\.", help="Prefix paths with `prefix` rather than \\.\\") parser.add_argument('-v', action="store_true", dest="verbose", help="Print debugging information") parser.add_argument('mft', action="store", help="Path to MFT") parser.add_argument('record_or_path', action="store", help="MFT record or file path to inspect") results = parser.parse_args() if results.verbose: logging.basicConfig(level=logging.DEBUG) with Mmap(results.mft) as buf: record_cache = Cache(results.cache_size) path_cache = Cache(results.cache_size) enum = MFTEnumerator(buf, record_cache=record_cache, path_cache=path_cache) should_use_inode = False try: record_num = int(results.record_or_path) should_use_inode = True except ValueError: should_use_inode = False if should_use_inode: record = enum.get_record(record_num) path = results.prefix + enum.get_path(record) print_indx_info(record, path) else: path = results.record_or_path record = enum.get_record_by_path(path) print_indx_info(record, results.prefix + path)
def main(): parser = argparse.ArgumentParser(description='Inspect ' 'a given MFT file record.') parser.add_argument('-a', action="store", metavar="cache_size", type=int, dest="cache_size", default=1024, help="Size of cache.") parser.add_argument('-p', action="store", metavar="prefix", nargs=1, dest="prefix", default="\\.", help="Prefix paths with `prefix` rather than \\.\\") parser.add_argument('-v', action="store_true", dest="verbose", help="Print debugging information") parser.add_argument('mft', action="store", help="Path to MFT") parser.add_argument('record_or_path', action="store", help="MFT record or file path to inspect") results = parser.parse_args() if results.verbose: logging.basicConfig(level=logging.DEBUG) with Mmap(results.mft) as buf: record_cache = Cache(results.cache_size) path_cache = Cache(results.cache_size) enum = MFTEnumerator(buf, record_cache=record_cache, path_cache=path_cache) should_use_inode = False try: record_num = int(results.record_or_path) should_use_inode = True except ValueError: should_use_inode = False if should_use_inode: record = enum.get_record(record_num) path = results.prefix + enum.get_path(record) print_indx_info(record, path) else: path = results.record_or_path record = enum.get_record_by_path(path) print_indx_info(record, results.prefix + path)
class MFTFuseOperations(Operations): """ MFTFuseOperations is a FUSE driver for NTFS MFT files. """ def __init__(self, root, mfttree, buf): self._root = root self._tree = mfttree self._buf = buf self._opened_files = {} # dict(int --> FH subclass) record_cache = Cache(1024) path_cache = Cache(1024) self._enumerator = MFTEnumerator(buf, record_cache=record_cache, path_cache=path_cache) # Helpers # ======= def _get_node(self, path): """ _get_node returns the MFTTreeNode associated with a path. @type path: str @rtype: MFT.MFTTreeNode @raises: FuseOSError(errno.ENOENT) """ if path.startswith("/"): path = path[1:] current_node = self._tree.get_root() for component in path.split("/"): if component == "": continue try: current_node = current_node.get_child_node(component) except KeyError: raise FuseOSError(errno.ENOENT) return current_node def _get_record(self, path): """ _get_record returns the MFTRecord associated with a path. @type path: str @rtype: MFT.MFTRecord """ return self._enumerator.get_record(self._get_node(path).get_record_number()) # Filesystem methods # ================== @log def getattr(self, path, fh=None): (uid, gid, pid) = fuse_get_context() working_path = path if is_special_file(path): (working_path, special) = explode_special_file(working_path) record = self._get_record(working_path) if record.is_directory(): mode = (stat.S_IFDIR | PERMISSION_ALL_READ) nlink = 2 else: mode = (stat.S_IFREG | PERMISSION_ALL_READ) nlink = 1 # TODO(wb): fix the duplication of this code with the FH classes if is_special_file(path): size = 0 (working_path, special) = explode_special_file(path) if special == "meta": node = self._get_node(working_path) record_buf = self._enumerator.get_record_buf(node.get_record_number()) size = len(get_meta_for_file(record, working_path)) else: data_attribute = record.data_attribute() if data_attribute is not None: if data_attribute.non_resident() == 0: size = len(data_attribute.value()) else: size = data_attribute.data_size() else: size = record.filename_information().logical_size() return { "st_atime": unixtimestamp(record.standard_information().accessed_time()), "st_ctime": unixtimestamp(record.standard_information().changed_time()), #"st_crtime": unixtimestamp(record.standard_information().created_time()), "st_mtime": unixtimestamp(record.standard_information().modified_time()), "st_size": size, "st_uid": uid, "st_gid": gid, "st_mode": mode, "st_nlink": nlink, } @log def readdir(self, path, fh): dirents = ['.', '..'] record = self._get_node(path) dirents.extend(map(lambda r: r.get_filename(), record.get_children_nodes())) for r in dirents: yield r @log def readlink(self, path): return path @log def statfs(self, path): return dict((key, 0) for key in ('f_bavail', 'f_bfree', 'f_blocks', 'f_bsize', 'f_favail', 'f_ffree', 'f_files', 'f_flag', 'f_frsize', 'f_namemax')) @log def chmod(self, path, mode): return errno.EROFS @log def chown(self, path, uid, gid): return errno.EROFS @log def mknod(self, path, mode, dev): return errno.EROFS @log def rmdir(self, path): return errno.EROFS @log def mkdir(self, path, mode): return errno.EROFS @log def unlink(self, path): return errno.EROFS @log def symlink(self, target, name): return errno.EROFS @log def rename(self, old, new): return errno.EROFS @log def link(self, target, name): return errno.EROFS @log def utimens(self, path, times=None): return errno.EROFS # File methods # ============ def _get_available_fh(self): """ _get_available_fh returns an unused fh The caller must be careful to handle race conditions. @rtype: int """ for i in xrange(65534): if i not in self._opened_files: return i @log def open(self, path, flags): if flags & os.O_WRONLY > 0: return errno.EROFS if flags & os.O_RDWR > 0: return errno.EROFS # TODO(wb): race here on fh used/unused fh = self._get_available_fh() if is_special_file(path): (path, special) = explode_special_file(path) if special == "meta": record = self._get_record(path) node = self._get_node(path) record_buf = self._enumerator.get_record_buf(node.get_record_number()) self._opened_files[fh] = MetaFH(fh, record, path, record_buf) else: raise FuseOSError(errno.ENOENT) else: self._opened_files[fh] = RegularFH(fh, self._get_record(path)) return fh @log def read(self, path, length, offset, fh): txt = self._opened_files[fh].get_data().encode("utf-8") return txt[offset:offset+length] @log def flush(self, path, fh): return "" @log def release(self, path, fh): del self._opened_files[fh] @log def create(self, path, mode, fi=None): return errno.EROFS @log def write(self, path, buf, offset, fh): return errno.EROFS @log def truncate(self, path, length, fh=None): return errno.EROFS @log def fsync(self, path, fdatasync, fh): return errno.EPERM