def test_key_material_read(self): volume = Volume(disk=Disk(ImageParser(keys={'3': 'hello'}), "..."), index='3') self.assertEqual(volume.key, "hello") volume = Volume(disk=Disk(ImageParser(keys={'3': 'hello', '*': 'ola'}), "..."), index='2') self.assertEqual(volume.key, "ola") volume = Volume(disk=Disk(ImageParser(keys={'3': 'hello'}), "..."), index='1') self.assertEqual(volume.key, "")
def test_ext4(self): # Removed some items from this output as we don't use it in its entirety anyway result = b"""FILE SYSTEM INFORMATION -------------------------------------------- File System Type: Ext4 Volume Name: Example Volume ID: 2697f5b0479b15b1b4c81994387cdba Last Written at: 2017-07-02 12:23:22 (CEST) Last Checked at: 2016-07-09 20:27:28 (CEST) Last Mounted at: 2017-07-02 12:23:23 (CEST) Unmounted properly Last mounted on: / Source OS: Linux BLOCK GROUP INFORMATION --------------------------------------------""" with mock.patch('subprocess.Popen') as mock_popen: type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result)) volume = Volume(disk=Disk(ImageParser(), "...")) volume.get_raw_path = mock.Mock(return_value="...") volume._load_fsstat_data() self.assertEqual(volume.info['statfstype'], 'Ext4') self.assertEqual(volume.info['lastmountpoint'], '/') self.assertEqual(volume.info['label'], '/ (Example)') self.assertEqual(volume.info['version'], 'Linux') # must be called after reading BLOCK GROUP INFORMATION mock_popen().terminate.assert_called()
def test_magic(self): # Add values here that are shown in the wild for file magic output # !! Always try to add it also to test_combination descriptions = { "Linux Compressed ROM File System data": "cramfs", "Linux rev 1.0 ext2 filesystem data": "ext", 'DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, ' 'root entries 512, sectors 100 (volumes <=32 MB) , Media descriptor 0xf8, ' 'sectors/FAT 1, sectors/track 32, heads 64, serial number 0x3cb7474b, ' 'label: "TEST ", FAT (12 bit)': "fat", "ISO 9660 CD-ROM filesystem data 'test'": "iso", "Minix filesystem, V1, 30 char names, 12800 zones": "minix", 'DOS/MBR boot sector, code offset 0x52+2, OEM-ID "NTFS ", sectors/cluster 8, ' 'Media descriptor 0xf8, sectors/track 0, dos < 4.0 BootSector (0x80), FAT (1Y bit ' 'by descriptor); NTFS, sectors 2048, $MFT start cluster 4, $MFTMirror start ' 'cluster 128, bytes/RecordSegment 2^(-1*246), clusters/index block 1, serial ' 'number 04e8742c12a96cecd; contains Microsoft Windows XP/VISTA bootloader BOOTMGR': "ntfs", "Squashfs filesystem, little endian, version 4.0": "squashfs", } for description, fstype in descriptions.items(): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=description) volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
def test_luks_key_communication(self, _, check_call): def modified_check_call(cmd, *args, **kwargs): if cmd[0:2] == ['cryptsetup', 'isLuks']: return True return mock.DEFAULT check_call.side_effect = modified_check_call original_popen = subprocess.Popen def modified_popen(cmd, *args, **kwargs): if cmd[0:3] == ['cryptsetup', '-r', 'luksOpen']: # A command that requests user input x = original_popen(["python2", "-c", "print(raw_input(''))"], *args, **kwargs) return x return mock.DEFAULT with mock.patch("subprocess.Popen", side_effect=modified_popen) as popen: disk = Disk(ImageParser(keys={'1': 'p:passphrase'}), "...") disk.is_mounted = True volume = Volume(disk=disk, fstype='luks', index='1', parent=disk) volume.mount() self.assertTrue(volume.is_mounted) self.assertEqual(len(volume.volumes), 1) self.assertEqual(volume.volumes[0].info['fsdescription'], "LUKS Volume")
def _mount_pytsk3_volumes(self): """Generator that mounts every partition of this image and yields the mountpoint.""" # Loop over all volumes in image. for p in self._find_pytsk3_volumes(): import pytsk3 volume = Volume(disk=self, **self.args) self.volumes.append(volume) # Fill volume with more information volume.offset = p.start * BLOCK_SIZE volume.fsdescription = p.desc if self.index is not None: volume.index = '{0}.{1}'.format(self.index, p.addr) else: volume.index = p.addr volume.size = p.len * BLOCK_SIZE if p.flags == pytsk3.TSK_VS_PART_FLAG_ALLOC: volume.flag = 'alloc' elif p.flags == pytsk3.TSK_VS_PART_FLAG_UNALLOC: volume.flag = 'unalloc' self._debug(" Unallocated space: block offset: {0}, length: {1} ".format(p.start, p.len)) elif p.flags == pytsk3.TSK_VS_PART_FLAG_META: volume.flag = 'meta' # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def mount_single_volume(self): """Mounts a volume assuming that the mounted image does not contain a full disk image, but only a single volume. A new :class:`Volume` object is created based on the disk file and :func:`init` is called on this object. This function will typically yield one volume, although if the volume contains other volumes, multiple volumes may be returned. """ volume = Volume(disk=self, **self.args) volume.offset = 0 if self.index is None: volume.index = 0 else: volume.index = '{0}.0'.format(self.index) description = util.check_output_(['file', '-sL', self.get_fs_path()]).strip() if description: # description is the part after the :, until the first comma volume.fsdescription = description.split(': ', 1)[1].split(',', 1)[0].strip() if 'size' in description: volume.size = re.findall(r'size: (\d+)', description)[0] else: volume.size = os.path.getsize(self.get_fs_path()) volume.flag = 'alloc' self.volumes = [volume] self.volume_source = 'single' for v in volume.init(no_stats=True): # stats can't be retrieved from single volumes yield v
def test_killed_after_timeout(self): def mock_side_effect(*args, **kwargs): time.sleep(0.2) return io.BytesIO(b"") with mock.patch('subprocess.Popen') as mock_popen: type(mock_popen()).stdout = mock.PropertyMock(side_effect=mock_side_effect) volume = Volume(disk=Disk(ImageParser(), "...")) volume.get_raw_path = mock.Mock(return_value="...") volume._load_fsstat_data(timeout=0.1) mock_popen().terminate.assert_called()
def mount_directory(self): """Method that 'mounts' a directory. It actually just symlinks it. It is useful for AVFS mounts, that are not otherwise detected. This is a last resort method. """ if not self.mount_directories: return volume = Volume(disk=self, **self.args) volume.offset = 0 if self.index is None: volume.index = 0 else: volume.index = '{0}.0'.format(self.index) filesize = _util.check_output_(['du', '-scDb', self.get_fs_path()]).strip() if filesize: volume.size = int(filesize.splitlines()[-1].split()[0]) volume.flag = 'alloc' volume.fsdescription = 'Directory' self.volumes = [volume] self.volume_source = 'directory' for v in volume.init(no_stats=True): # stats can't be retrieved from directory yield v
def _mount_mmls_volumes(self): """Finds and mounts all volumes based on mmls.""" try: cmd = ['mmls'] if self.vstype != 'detect': cmd.extend(['-t', self.vstype]) cmd.append(self.get_raw_path()) output = util.check_output_(cmd, self.parser) self.volume_source = 'multi' except Exception as e: self._debug("[-] Failed executing mmls command") self._debug(e) return output = output.split("Description", 1)[-1] for line in output.splitlines(): if not line: continue try: index, slot, start, end, length, description = line.split(None, 5) volume = Volume(disk=self, **self.args) self.volumes.append(volume) volume.offset = int(start) * BLOCK_SIZE volume.fsdescription = description if self.index is not None: volume.index = '{0}.{1}'.format(self.index, int(index[:-1])) else: volume.index = int(index[:-1]) volume.size = int(length) * BLOCK_SIZE except Exception as e: self._debug("[-] Error while parsing mmls output") self._debug(e) continue if slot.lower() == 'meta': volume.flag = 'meta' elif slot.lower() == '-----': volume.flag = 'unalloc' else: volume.flag = 'alloc' # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def test_fstype_fallback(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume._get_fstype_from_parser('?ufs') volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES["ufs"], volume.fstype)
def test_utf8_label(self): # Removed some items from this output as we don't use it in its entirety anyway result = b"""FILE SYSTEM INFORMATION -------------------------------------------- File System Type: Ext4 Volume Name: \xd0\xa0\xd0\xbe\xd1\x81\xd1\x81\xd0\xb8\xd0\xb8 Volume ID: 2697f5b0479b15b1b4c81994387cdba""" with mock.patch('subprocess.Popen') as mock_popen: type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result)) volume = Volume(disk=Disk(ImageParser(), "...")) volume.get_raw_path = mock.Mock(return_value="...") volume._load_fsstat_data() self.assertEqual(volume.info['statfstype'], 'Ext4') self.assertEqual(volume.info['label'], u'\u0420\u043e\u0441\u0441\u0438\u0438')
def test_combination(self): # Add values here to test full combinations of specific filesystem types # The _ as key is the expected result _ = "use as key for the expected result" definitions = [ {_: "cramfs", "blkid": "cramfs", "magic": "Linux Compressed ROM File System data", "fsdescription": "???"}, {_: "exfat", "blkid": "exfat", "fsdescription": "NTFS / exFAT", "statfstype": "exFAT"}, {_: "ext", "blkid": "ext4", "fsdescription": "Linux (0x83)", "guid": "", "statfstype": "Ext2"}, {_: "fat", "blkid": "vfat", "magic": "FAT (12 bit)", "fsdescription": "DOS FAT12 (0x04)", "statfstype": "FAT12"}, {_: "iso", "blkid": "iso9660", "magic": ".. ISO 9660 ..", "statfstype": "ISO9660"}, {_: "minix", "blkid": "min ix", "magic": "Minix filesystem", "fsdescription": "???"}, {_: "ntfs", "blkid": "ntfs", "magic": ".. NTFS ..", "fsdescription": "NTFS / exFAT", "statfstype": "NTFS"}, {_: "squashfs", "blkid": "squashfs", "magic": "Squashfs filesystem", "fsdescription": "???"}, {_: "lvm", "guid": "79D3D6E6-07F5-C244-A23C-238F2A3DF928"}, {_: "raid", "fsdescription": "Linux (0x83)", "blkid": "linux_raid_member"}, {_: "volumesystem", "blkid": "dos", "fsdescription": "Logical Volume"}, {_: "volumesystem", "blkid": "dos", "fsdescription": "RAID Volume"}, {_: "volumesystem", "blkid": "dos", "magic": "DOS/MBR boot sector"}, {_: "volumesystem", "fsdescription": "BSD/386, 386BSD, NetBSD, FreeBSD (0xa5)", "blkid": "ufs"}, {_: "ufs", "fsdescription": "4.2BSD (0x07)", "blkid": "ufs"}, ] for definition in definitions: volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=definition.get("blkid")) volume._get_magic_type = mock.Mock(return_value=definition.get("magic")) volume.info = definition volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES[definition[_]], volume.fstype)
def test_fstype_fallback(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume.fstype = "?bsd" volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.determine_fs_type() self.assertEqual("bsd", volume.fstype)
def test_fsdescription(self): # Add names in here that are shown in the wild for output of mmls / gparted # !! Always try to add it also to test_combination descriptions = { # Names assigned by imagemounter "Logical Volume": "unknown", "LUKS Volume": "unknown", "BDE Volume": "unknown", "RAID Volume": "unknown", "VSS Store": "unknown", "NTFS / exFAT": "ntfs", # mmls, should use fallback "Linux (0x83)": "unknown", # should use unknown "4.2BSD": "ufs", "BSD/386, 386BSD, NetBSD, FreeBSD (0xa5)": "volumesystem", "DOS FAT16": "fat", } for description, fstype in descriptions.items(): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) self.fstype = "" # prevent fallback to unknown by default volume.info['fsdescription'] = description volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
def test_guid(self): for description, fstype in FILE_SYSTEM_GUIDS.items(): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.info['guid'] = description volume.determine_fs_type() self.assertEqual(fstype, volume.fstype)
def test_no_root(self): parser = ImageParser() disk = parser.add_disk("...") v1 = Volume(disk) v1.mountpoint = '...' v1.info['lastmountpoint'] = '/etc/x' v2 = Volume(disk) v2.mountpoint = '....' v2.info['lastmountpoint'] = '/etc' disk.volumes.volumes = [v1, v2] with self.assertRaises(NoRootFoundError): parser.reconstruct()
def test_ntfs(self): # Removed some items from this output as we don't use it in its entirety anyway result = b"""FILE SYSTEM INFORMATION -------------------------------------------- File System Type: NTFS Volume Serial Number: 4E8742C12A96CECD OEM Name: NTFS Version: Windows XP""" with mock.patch('subprocess.Popen') as mock_popen: type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result)) volume = Volume(disk=Disk(ImageParser(), "...")) volume.get_raw_path = mock.Mock(return_value="...") volume._load_fsstat_data() self.assertEqual(volume.info['statfstype'], 'NTFS') self.assertNotIn("lastmountpoint", volume.info) self.assertNotIn("label", volume.info) self.assertEqual(volume.info['version'], 'Windows XP')
def test_simple(self): parser = ImageParser() disk = parser.add_disk("...") v1 = Volume(disk) v1.mountpoint = '...' v1.info['lastmountpoint'] = '/' v2 = Volume(disk) v2.mountpoint = '....' v2.info['lastmountpoint'] = '/etc' disk.volumes.volumes = [v1, v2] with mock.patch.object(v2, "bindmount") as v2_bm: parser.reconstruct() v2_bm.assert_called_once_with(".../etc")
def _make_subvolume(self, **args): """Creates a subvolume, adds it to this class and returns it.""" from imagemounter.volume import Volume v = Volume( disk=self.disk, parent=self.parent, volume_detector=self.volume_detector, **args) # vstype is not passed down, let it decide for itself. self.volumes.append(v) return v
def test_blkid(self): # Add values here that are shown in the wild for blkid # !! Always try to add it also to test_combination descriptions = { "cramfs": "cramfs", "ext4": "ext", "ext2": "ext", "vfat": "fat", "iso9660": "iso", "minix": "minix", "ntfs": "ntfs", "squashfs": "squashfs", "ufs": "ufs", "dos": "volumesystem", } for description, fstype in descriptions.items(): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=description) volume._get_magic_type = mock.Mock(return_value=None) volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
def test_guid(self): FILE_SYSTEM_GUIDS = { '2AE031AA-0F40-DB11-9590-000C2911D1B8': 'vmfs', # '8053279D-AD40-DB11-BF97-000C2911D1B8': 'vmkcore-diagnostics', # '6A898CC3-1DD2-11B2-99A6-080020736631': 'zfs-member', # 'C38C896A-D21D-B211-99A6-080020736631': 'zfs-member', # '0FC63DAF-8483-4772-8E79-3D69D8477DE4': 'linux', 'E6D6D379-F507-44C2-A23C-238F2A3DF928': 'lvm', '79D3D6E6-07F5-C244-A23C-238F2A3DF928': 'lvm', 'CA7D7CCB-63ED-4C53-861C-1742536059CC': 'luks' } for description, fstype in FILE_SYSTEM_GUIDS.items(): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.info['guid'] = description volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
def test_guid(self): FILE_SYSTEM_GUIDS = { '2AE031AA-0F40-DB11-9590-000C2911D1B8': 'vmfs', #'8053279D-AD40-DB11-BF97-000C2911D1B8': 'vmkcore-diagnostics', #'6A898CC3-1DD2-11B2-99A6-080020736631': 'zfs-member', #'C38C896A-D21D-B211-99A6-080020736631': 'zfs-member', #'0FC63DAF-8483-4772-8E79-3D69D8477DE4': 'linux', 'E6D6D379-F507-44C2-A23C-238F2A3DF928': 'lvm', '79D3D6E6-07F5-C244-A23C-238F2A3DF928': 'lvm', 'CA7D7CCB-63ED-4C53-861C-1742536059CC': 'luks' } for description, fstype in FILE_SYSTEM_GUIDS.items(): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.info['guid'] = description volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
def test_blkid(self): # Add values here that are shown in the wild for blkid # !! Always try to add it also to test_combination descriptions = { "cramfs": "cramfs", "ext4": "ext", "ext2": "ext", "vfat": "fat", "iso9660": "iso", "minix": "minix", "ntfs": "ntfs", "squashfs": "squashfs", "ufs": "ufs", "dos": "volumesystem", } for description, fstype in descriptions.items(): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=description) volume._get_magic_type = mock.Mock(return_value=None) volume.determine_fs_type() self.assertEqual(fstype, volume.fstype)
def test_fstype_fallback_unknown(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.info['fsdescription'] = "Linux (0x83)" # If something more specific is set, we use that volume._get_fstype_from_parser('?ufs') volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES["ufs"], volume.fstype) # Otherwise we fallback to unknown if Linux (0x83) is set volume._get_fstype_from_parser('') volume.determine_fs_type() self.assertEqual(UnknownFileSystemType(), volume.fstype)
def test_valid_fstype(self): volume = Volume(disk=Disk(ImageParser(), "..."), fstype='ext') volume.determine_fs_type() self.assertEqual(FILE_SYSTEM_TYPES['ext'], volume.fstype)
def test_read_bytes_crash(self, mock_open): mock_open().__enter__().read.side_effect = IOError volume = Volume(disk=Disk(ImageParser(), "...")) volume.get_raw_path = mock.Mock(return_value="...") self.assertIsNone(volume._get_magic_type())
def test_valid_vstype(self): volume = Volume(disk=Disk(ImageParser(), "..."), fstype="dos") volume.determine_fs_type() self.assertEqual("dos", volume.volumes.vstype) self.assertEqual(FILE_SYSTEM_TYPES["volumesystem"], volume.fstype)
def _mount_pytsk3_volumes(self): """Generator that mounts every partition of this image and yields the mountpoint.""" # Loop over all volumes in image. for p in self._find_pytsk3_volumes(): import pytsk3 volume = Volume(disk=self, **self.args) self.volumes.append(volume) # Fill volume with more information volume.offset = p.start * self.block_size volume.fsdescription = p.desc.strip() if self.index is not None: volume.index = '{0}.{1}'.format(self.index, p.addr) else: volume.index = p.addr volume.size = p.len * self.block_size if p.flags == pytsk3.TSK_VS_PART_FLAG_ALLOC: volume.flag = 'alloc' volume.slot = _util.determine_slot(p.table_num, p.slot_num) self._assign_disktype_data(volume) logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(p.start, p.len, volume.fsdescription)) elif p.flags == pytsk3.TSK_VS_PART_FLAG_UNALLOC: volume.flag = 'unalloc' logger.info("Found unallocated space: block offset: {0}, length: {1} ".format(p.start, p.len)) elif p.flags == pytsk3.TSK_VS_PART_FLAG_META: volume.flag = 'meta' logger.info("Found meta volume: block offset: {0}, length: {1} ".format(p.start, p.len)) # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def _mount_mmls_volumes(self): """Finds and mounts all volumes based on mmls.""" try: cmd = ['mmls'] if self.vstype != 'detect': cmd.extend(['-t', self.vstype]) cmd.append(self.get_raw_path()) output = _util.check_output_(cmd, stderr=subprocess.STDOUT) self.volume_source = 'multi' except Exception as e: # some bug in sleuthkit makes detection sometimes difficult, so we hack around it: if hasattr(e, 'output') and "(GPT or DOS at 0)" in e.output.decode() and self.vstype != 'gpt': self.vstype = 'gpt' try: logger.warning("Error in retrieving volume info: mmls couldn't decide between GPT and DOS, " "choosing GPT for you. Use --vstype=dos to force DOS.", exc_info=True) cmd = ['mmls', '-t', self.vstype, self.get_raw_path()] output = _util.check_output_(cmd, stderr=subprocess.STDOUT) self.volume_source = 'multi' except Exception as e: logger.exception("Failed executing mmls command") return else: logger.exception("Failed executing mmls command") return output = output.split("Description", 1)[-1] for line in output.splitlines(): if not line: continue try: values = line.split(None, 5) # sometimes there are only 5 elements available description = '' index, slot, start, end, length = values[0:5] if len(values) > 5: description = values[5] volume = Volume(disk=self, **self.args) self.volumes.append(volume) volume.offset = int(start) * self.block_size volume.fsdescription = description if self.index is not None: volume.index = '{0}.{1}'.format(self.index, int(index[:-1])) else: volume.index = int(index[:-1]) volume.size = int(length) * self.block_size except Exception as e: logger.exception("Error while parsing mmls output") continue if slot.lower() == 'meta': volume.flag = 'meta' logger.info("Found meta volume: block offset: {0}, length: {1}".format(start, length)) elif slot.lower() == '-----': volume.flag = 'unalloc' logger.info("Found unallocated space: block offset: {0}, length: {1}".format(start, length)) else: volume.flag = 'alloc' if ":" in slot: volume.slot = _util.determine_slot(*slot.split(':')) else: volume.slot = _util.determine_slot(-1, slot) self._assign_disktype_data(volume) logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(start, length, volume.fsdescription)) # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def test_fstype_fallback_unknown(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.info['fsdescription'] = "Linux (0x83)" # If something more specific is set, we use that volume.fstype = "?bsd" volume.determine_fs_type() self.assertEqual("bsd", volume.fstype) # Otherwise we fallback to unknown if Linux (0x83) is set volume.fstype = "" volume.determine_fs_type() self.assertEqual("unknown", volume.fstype)
def test_valid_fstype(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume.fstype = 'ext' volume.determine_fs_type() self.assertEqual("ext", volume.fstype)
def test_little_clue_fstype(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value="-") volume._get_magic_type = mock.Mock(return_value="-") volume.determine_fs_type() self.assertEqual(UnknownFileSystemType(), volume.fstype)
def test_multiple_roots(self): parser = ImageParser() disk = parser.add_disk("...") v1 = Volume(disk) v1.index = '1' v1.mountpoint = '...' v1.info['lastmountpoint'] = '/' v2 = Volume(disk) v2.index = '2' v2.mountpoint = '....' v2.info['lastmountpoint'] = '/' v3 = Volume(disk) v3.index = '3' v3.mountpoint = '.....' v3.info['lastmountpoint'] = '/etc' disk.volumes.volumes = [v1, v2, v3] with mock.patch.object(v1, "bindmount") as v1_bm, mock.patch.object(v2, "bindmount") as v2_bm, \ mock.patch.object(v3, "bindmount") as v3_bm: parser.reconstruct() v1_bm.assert_not_called() v2_bm.assert_not_called() v3_bm.assert_called_with('.../etc')
def _mount_parted_volumes(self): """Finds and mounts all volumes based on parted.""" # for some reason, parted does not properly return extended volume types in its machine # output, so we need to execute it twice. meta_volumes = [] try: output = _util.check_output_(['parted', self.get_raw_path(), 'print']) for line in output.splitlines(): if 'extended' in line: meta_volumes.append(int(line.split()[0])) except Exception: logger.exception("Failed executing parted command.") # skip detection of meta volumes try: # parted does not support passing in the vstype. It either works, or it doesn't. cmd = ['parted', self.get_raw_path(), '-sm', 'unit s', 'print free'] output = _util.check_output_(cmd) self.volume_source = 'multi' except Exception as e: logger.exception("Failed executing parted command") return num = 0 for line in output.splitlines(): if line.startswith("Warning") or not line or ':' not in line or line.startswith(self.get_raw_path()): continue line = line[:-1] # remove last ; try: slot, start, end, length, description = line.split(':', 4) if ':' in description: description, label, flags = description.split(':', 2) else: description, label, flags = description, '', '' volume = Volume(disk=self, **self.args) self.volumes.append(volume) volume.offset = int(start[:-1]) * self.block_size # remove last s volume.size = int(length[:-1]) * self.block_size volume.fsdescription = description if self.index is not None: volume.index = '{0}.{1}'.format(self.index, num) else: volume.index = num # TODO: detection of meta volumes if description == 'free': volume.flag = 'unalloc' logger.info("Found unallocated space: block offset: {0}, length: {1}".format(start[:-1], length[:-1])) elif int(slot) in meta_volumes: volume.flag = 'meta' volume.slot = int(slot) logger.info("Found meta volume: block offset: {0}, length: {1}".format(start[:-1], length[:-1])) else: volume.flag = 'alloc' volume.slot = int(slot) self._assign_disktype_data(volume) logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(start[:-1], length[:-1], volume.fsdescription)) except AttributeError as e: logger.exception("Error while parsing parted output") continue num += 1 # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def test_valid_vstype(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume.fstype = 'dos' volume.determine_fs_type() self.assertEqual("dos", volume.volumes.vstype) self.assertEqual("volumesystem", volume.fstype)
def test_no_clue_fstype(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.determine_fs_type() self.assertEqual("unknown", volume.fstype)
def test_no_clue_fstype(self): volume = Volume(disk=Disk(ImageParser(), "...")) volume._get_blkid_type = mock.Mock(return_value=None) volume._get_magic_type = mock.Mock(return_value=None) volume.determine_fs_type() self.assertEqual(UnknownFileSystem, volume.filesystem.__class__)