def test_glom_fragmented_file_discontiguous(): """ Three out-of-order sectors of the file on disk, f0_f1_f2, are at discontiguous offsets i0, i0+1KiB, i0+1MiB. """ br0 = Objects.ByteRun() br1 = Objects.ByteRun() br2 = Objects.ByteRun() br0.len = 512 br1.len = 512 br2.len = 512 br0.img_offset = 0 br1.img_offset = br0.img_offset + 2**10 br2.img_offset = br0.img_offset + 2**20 br0.file_offset = 0 * 512 br1.file_offset = 1 * 512 br2.file_offset = 2 * 512 br0_br1 = br0 + br1 br1_br2 = br1 + br2 try: assert br0_br1 is None except: _logger.debug("br0_br1 = %r." % br0_br1) raise try: assert br1_br2 is None except: _logger.debug("br1_br2 = %r." % br1_br2) raise
def _gen_glom_samples(offset_property="img_offset"): """ Generate three contiguous byte runs. """ br0 = Objects.ByteRun() br1 = Objects.ByteRun() br2 = Objects.ByteRun() br0.len = 20 br1.len = 30 br2.len = 10 if offset_property == "img_offset": br0.img_offset = 0 br1.img_offset = 20 br2.img_offset = 50 elif offset_property == "fs_offset": br0.fs_offset = 0 br1.fs_offset = 20 br2.fs_offset = 50 elif offset_property == "file_offset": br0.file_offset = 0 br1.file_offset = 20 br2.file_offset = 50 return (br0, br1, br2)
def test_glom_fragmented_file_outoforder(): """ Three contiguous sectors on disk, i0_i1_i2, contain three out-of-order sectors of the file on disk, f0_f2_f1. """ br0 = Objects.ByteRun() br1 = Objects.ByteRun() br2 = Objects.ByteRun() br0.len = 512 br1.len = 512 br2.len = 512 br0.img_offset = 0 * 512 br1.img_offset = 1 * 512 br2.img_offset = 2 * 512 br0.file_offset = 0 * 512 br1.file_offset = 2 * 512 br2.file_offset = 1 * 512 br0_br1 = br0 + br1 br1_br2 = br1 + br2 try: assert br0_br1 is None except: _logger.debug("br0_br1 = %r." % br0_br1) raise try: assert br1_br2 is None except: _logger.debug("br1_br2 = %r." % br1_br2) raise
def test_fill(): _logger = logging.getLogger(os.path.basename(__file__)) logging.basicConfig(level=logging.DEBUG) br = Objects.ByteRun() _logger.debug("br = %r." % br) assert br.fill is None br.fill = b'\x00' _logger.debug("br.fill = %r." % br.fill) assert br.fill == b'\x00' #Catch current implementation decision. multibyte_failed = None try: br.fill = b'\x00\x01' except NotImplementedError as e: multibyte_failed = True assert multibyte_failed br.fill = 0 _logger.debug("br.fill = %r." % br.fill) assert br.fill == b'\x00' br.fill = "0" _logger.debug("br.fill = %r." % br.fill) assert br.fill == b'\x00' br.fill = 1 _logger.debug("br.fill = %r." % br.fill) assert br.fill == b'\x01'
def test_all(): br0 = Objects.ByteRun() br0.img_offset = 0 br0.len = 20 br1 = Objects.ByteRun() br1.img_offset = 20 br1.len = 30 br2 = Objects.ByteRun() br2.img_offset = 50 br2.len = 20 brs_contiguous = Objects.ByteRuns() brs_contiguous.append(br0) brs_contiguous.append(br1) brs_contiguous.append(br2) brs_glommed = Objects.ByteRuns() brs_glommed.glom(br0) brs_glommed.glom(br1) brs_glommed.glom(br2) brs_discontig = Objects.ByteRuns() brs_discontig.glom(br0) brs_discontig.glom(br2) brs_backward = Objects.ByteRuns() brs_backward.glom(br1) brs_backward.glom(br0) assert len(brs_contiguous) == 3 assert len(brs_glommed) == 1 assert len(brs_discontig) == 2 assert len(brs_backward) == 2 assert brs_glommed[0].len == 70 assert brs_backward[0].len == 30 assert brs_backward[1].len == 20 br_facet_data = Objects.ByteRuns(facet="data") br_facet_name = Objects.ByteRuns(facet="name") br_facet_default = Objects.ByteRuns() assert br_facet_data == br_facet_default assert br_facet_name != br_facet_data assert br_facet_name != br_facet_default
def get_brs(): logging.basicConfig(level=logging.DEBUG) _logger = logging.getLogger(os.path.basename(__file__)) br = Objects.ByteRun() br.file_offset = 4128 br.len = 133 brs = Objects.ByteRuns() brs.append(br) return brs
def test_all(): _logger = logging.getLogger(os.path.basename(__file__)) logging.basicConfig(level=logging.DEBUG) br1 = Objects.ByteRun(img_offset=1, len=1) br2 = Objects.ByteRun(img_offset=2, len=2) br3 = Objects.ByteRun(img_offset=4, len=3) dbr = Objects.ByteRuns() ibr = Objects.ByteRuns() nbr = Objects.ByteRuns() dbr.append(br1) ibr.append(br2) nbr.append(br3) dbr.facet = "data" ibr.facet = "inode" nbr.facet = "name" f1 = Objects.FileObject() f1.data_brs = dbr f1.inode_brs = ibr f1.name_brs = nbr assert f1.data_brs[0].img_offset == 1 assert f1.inode_brs[0].img_offset == 2 assert f1.name_brs[0].img_offset == 4 e1 = f1.to_Element() #_logger.debug(f1) #_logger.debug(ET.tostring(e1)) f2 = Objects.FileObject() f2.populate_from_Element(e1) #_logger.debug(f2) assert f2.data_brs[0].img_offset == 1 assert f2.inode_brs[0].img_offset == 2 assert f2.name_brs[0].img_offset == 4
def test_all(): br1 = Objects.ByteRun() br1.img_offset = 512 br1.len = 20 br2 = copy.deepcopy(br1) assert br1 + br2 is None br2.img_offset += br1.len assert (br1 + br2).len == 40
def test_hash_properties(): dobj = Objects.DFXMLObject(version="1.2.0") fobj = Objects.FileObject() dobj.append(fobj) fobj.byte_runs = Objects.ByteRuns() br = Objects.ByteRun() fobj.byte_runs.append(br) fobj.filesize = len(TEST_BYTE_STRING) br.len = len(TEST_BYTE_STRING) hash_functions = {"md5", "sha1", "sha224", "sha256", "sha384", "sha512"} # Key: Hash function. # Value: Hash of the byte string b"test". hash_values = dict() for hash_function in sorted(hash_functions): hash_object = getattr(hashlib, hash_function)() hash_object.update(TEST_BYTE_STRING) hash_values[hash_function] = hash_object.hexdigest() _logger.debug("hash_values[%r] = %r." % (hash_function, hash_values[hash_function])) setattr(fobj, hash_function, hash_values[hash_function]) setattr(br, hash_function, hash_values[hash_function]) assert getattr(fobj, hash_function) == hash_values[hash_function] assert getattr(br, hash_function) == hash_values[hash_function] # Do file I/O round trip. (tmp_filename, dobj_reconst) = libtest.file_round_trip_dfxmlobject(dobj) try: fobj_reconst = dobj_reconst.files[0] br_reconst = fobj_reconst.byte_runs[0] for hash_function in sorted(hash_functions): assert getattr(fobj_reconst, hash_function) == hash_values[hash_function] assert getattr(br_reconst, hash_function) == hash_values[hash_function] except: _logger.debug("tmp_filename = %r." % tmp_filename) raise os.remove(tmp_filename)
def parse(self, in_fh): """ Returns a DFXMLObject. """ dobj = Objects.DFXMLObject(version="1.2.0+") dobj.program = sys.argv[0] dobj.program_version = __version__ dobj.command_line = " ".join(sys.argv) dobj.dc["type"] = "Disk image sector map" dobj.add_creator_library("Python", ".".join(map(str, sys.version_info[0:3]))) #A bit of a bend, but gets the major version information out. dobj.add_creator_library("Objects.py", Objects.__version__) dobj.add_creator_library("dfxml.py", Objects.dfxml.__version__) diobj = Objects.DiskImageObject() dobj.append(diobj) brs = Objects.ByteRuns() diobj.byte_runs = brs dobj.add_namespace("gddr", Objects.dfxml.XMLNS_DFXML + "#gddrescue") self._state = ParseState.FILE_OPENED self._disk_image_len = 0 for (line_no, line) in enumerate(in_fh): self._line_no = line_no cleaned_line = line.strip() if cleaned_line.startswith("0x"): if self._state in (ParseState.TABLE_HEAD, ParseState.IN_TABLE): self.transition(ParseState.IN_TABLE) else: self.transition(ParseState.CURRENT_POS_RECORD) elif cleaned_line == "# pos size status": self.transition(ParseState.TABLE_HEAD) elif cleaned_line == "# current_pos current_status current_pass": self.transition(ParseState.CURRENT_POS_HEAD) else: self.transition(ParseState.PRE_TABLE) if self._state != ParseState.IN_TABLE: continue br = Objects.ByteRun() line_parts = cleaned_line.split(" ") br.img_offset = int(line_parts[0], base=16) br.len = int(line_parts[1], base=16) self._disk_image_len = br.img_offset + br.len # TODO # Independent design decision, while awaiting a consensus design: # Only report the byte runs ddrescue was able to collect. if line_parts[2] != "+": continue brs.append(br) diobj.filesize = self._disk_image_len _logger.info("diobj.filesize = %r." % diobj.filesize) self.transition(ParseState.STREAM_COMPLETE) return dobj
def main(): dobj = Objects.DFXMLObject(version="1.2.0") dobj.program = sys.argv[0] dobj.program_version = __version__ dobj.command_line = " ".join(sys.argv) dobj.dc["type"] = "Example" dobj.add_creator_library("Python", ".".join(map(str, sys.version_info[0:3]))) #A bit of a bend, but gets the major version information out. dobj.add_creator_library("Objects.py", Objects.__version__) dobj.add_creator_library("dfxml.py", Objects.dfxml.__version__) vobj = Objects.VolumeObject() dobj.append(vobj) vobj.ftype_str = "examplefs" # Define file system position. vobj.byte_runs = Objects.ByteRuns() vbr = Objects.ByteRun() vobj.byte_runs.append(vbr) vbr.img_offset = FILE_SYSTEM_START vbr.len = DISK_IMAGE_SIZE - FILE_SYSTEM_START fobj_specs = [ ( "first_sector.bin", [ (0, 512) ] ), ( "first_four_kilobytes.bin", [ (0, 4000) ] ), ( "contiguous_before_bad_region.dat", [ (FILE_SYSTEM_START + 4096*1, 4096) ] ), ( "contiguous_around_bad_region_left_edge.dat", [ (DAMAGE_REGION_START - 4096, 8192) ] ), ( "contiguous_in_bad_region.dat", [ (DAMAGE_REGION_START + 4096*1, 4096) ] ), ( "contiguous_around_bad_region_right_edge.dat", [ (GOOD_REGION_START - 4096*1, 8192) ] ), ( "contiguous_after_bad_region.dat", [ (GOOD_REGION_START + 4096*2, 4096) ] ), ( "fragmented_all_before_bad_region.dat", [ (FILE_SYSTEM_START + 4096*10, 4096), (FILE_SYSTEM_START + 4096*20, 4096), (FILE_SYSTEM_START + 4096*30, 4096) ] ), ( "fragmented_all_after_bad_region.dat", [ (GOOD_REGION_START + 4096*10, 4096), (GOOD_REGION_START + 4096*20, 4096), (GOOD_REGION_START + 4096*30, 4096) ] ), ( "fragmented_all_inside_bad_region.dat", [ (DAMAGE_REGION_START + 4096*10, 4096), (DAMAGE_REGION_START + 4096*20, 4096), (DAMAGE_REGION_START + 4096*30, 4096) ] ), ( "fragmented_beginning_inside_bad_region.dat", [ (DAMAGE_REGION_START + 4096*40, 4096), (GOOD_REGION_START + 4096*40, 4096) ] ), ( "fragmented_middle_inside_bad_region.dat", [ (FILE_SYSTEM_START + 4096*50, 4096), (DAMAGE_REGION_START + 4096*50, 4096), (GOOD_REGION_START + 4096*50, 4096) ] ), ( "fragmented_end_inside_bad_region.dat", [ (FILE_SYSTEM_START + 4096*60, 4096), (DAMAGE_REGION_START + 4096*60, 4096) ] ), ( "after_disk_image_end.dat", [ (DISK_IMAGE_SIZE + 4096*1000, 4096) ] ), ( "fragmented_partially_recoverable_directory", [ (FILE_SYSTEM_START + 4096*170, 4096), (DAMAGE_REGION_START + 4096*170, 4096), (GOOD_REGION_START + 4096*170, 4096), ] ), ( "fragmented_partially_recoverable_directory/child_file_1", [ (FILE_SYSTEM_START + 4096*180, 4096) ] ), ( "fragmented_partially_recoverable_directory/child_file_2", [ (FILE_SYSTEM_START + 4096*190, 4096) ] ), ( "fragmented_partially_recoverable_directory/child_file_3", [ (FILE_SYSTEM_START + 4096*200, 4096) ] ), ( "fragmented_partially_recoverable_directory/child_file_4", [ (FILE_SYSTEM_START + 4096*210, 4096) ] ), ( "fragmented_partially_recoverable_directory/child_file_9", [ (GOOD_REGION_START + 4096*180, 4096) ] ) ] for fobj_spec in fobj_specs: fobj = Objects.FileObject() vobj.append(fobj) fobj.filename = fobj_spec[0] fobj.alloc = True # Naming convention for this sample - the .bin files are virtual files that reference a region outside of the file system. if fobj.filename == "fragmented_partially_recoverable_directory": fobj.name_type = "d" elif fobj.filename.endswith(".bin"): fobj.name_type = "v" else: fobj.name_type = "r" fobj.data_brs = Objects.ByteRuns() for interval in fobj_spec[1]: br = Objects.ByteRun() fobj.data_brs.append(br) br.img_offset = interval[0] br.len = interval[1] fobj.filesize = sum([br.len for br in fobj.data_brs]) dobj.print_dfxml()