def __init__(self, vdev, os_bptr, dvas=(0,1)): self._vdev = vdev # Load the object set dnode self._dnode = self._load_os_dnode(os_bptr, dvas) if self._dnode is None: print("[-] Object set dnode is unreachable") self._broken = True return # Compute intermediate properties self._indblksize = 1 << self._dnode.indblkshift self._datablksize = self._dnode.datablksize self._dnodes_per_block = self._datablksize // 512 self._maxdnodeid = (self._dnode.maxblkid+1)*self._dnodes_per_block - 1 print("[+] Object set information:") print("[+] dnode", self._dnode) print("[+] block size: indirect {} / data {}".format(self._indblksize, self._datablksize)) print("[+] {} blocks / {} dnodes per block".format(self._dnode.maxblkid+1, self._dnodes_per_block)) self._blocktree = BlockTree(self._dnode.levels, self._vdev, self._dnode.blkptrs[0]) if self._blocktree is None: print("[-] Object set block tree is broken") self._broken = True return # print("[+] Block pointer 0 is", self._blocktree[0]) # print("[+] Block pointer {} is {}".format(self._dnode.maxblkid, self._blocktree[self._dnode.maxblkid])) self._block_cache = {} self._broken = False
def __init__(self, vdev, dnode, bad_as_zeros=False): self._vdev = vdev self._bt = BlockTree(dnode.levels, self._vdev, dnode.blkptrs[0]) self._next_blkid = 0 self._max_blkid = dnode.maxblkid self._datablksize = dnode.datablksize self._size = dnode.bonus.zp_size self._filepos = 0 self._blkpos = 0 self._buf = bytearray() self._corrupted = False self._bad_as_zeros = bad_as_zeros
def extract_file(self, file_node_id, target_path, _abspath='undef'): print("[+] Extracting object {} to {}".format(file_node_id, target_path)) file_dnode = self[file_node_id] f = open(target_path, "wb") f.close() if file_dnode.blkptrs[0].empty and file_dnode.bonus.size() > 0: f = open("problemfiles.txt", "a") f.write("%s\n" % (_abspath)) f.close() print("[+] Cannot extract %s : %s : sz:%d" % (_abspath, str(file_dnode), file_dnode.bonus.size())) return False bt = BlockTree(file_dnode.levels, self._vdev, file_dnode.blkptrs[0]) num_blocks = file_dnode.maxblkid + 1 f = open(target_path, "wb") total_len = 0 corrupted = False tt = -time.time() if file_dnode.bonus.size() > 0: for n in range(num_blocks): bp = bt[n] bad_block = False if bp is None: print("[-] Broken block tree") bad_block = True else: block_data, c = self._vdev.read_block(bp, dva=0) if block_data is None: print("[-] Unreadable block") bad_block = True if bad_block: block_data = b'\x00' * file_dnode.datablksize corrupted = True f.write(block_data) total_len += len(block_data) if n % 16 == 0: print("[+] Block {:>3}/{} total {:>7} bytes".format( n, num_blocks, total_len)) tt += time.time() if tt == 0.0: tt = 1.0 # Prevent division by zero for 0-length files data_size = min(total_len, file_dnode.bonus.size()) f.truncate(data_size) f.close() print("[+] {} bytes in {:.3f} s ({:.1f} KiB/s)".format( total_len, tt, total_len / (1024 * tt))) return not corrupted