diff --git a/dfvfs/helpers/command_line.py b/dfvfs/helpers/command_line.py index 8ce7cc3f..ce6e9897 100644 --- a/dfvfs/helpers/command_line.py +++ b/dfvfs/helpers/command_line.py @@ -298,6 +298,14 @@ class CLIVolumeScannerMediator(volume_scanner.VolumeScannerMediator): 'volume is 1. All volumes can be defined as "all". If no volumes are ' 'specified none will be processed. You can abort with Ctrl^C.') + _USER_PROMPT_LVM = ( + 'Please specify the identifier(s) of the LVM volume that should be ' + 'processed: Note that a range of volumes can be defined as: 3..5. ' + 'Multiple volumes can be defined as: 1,3,5 (a list of comma separated ' + 'values). Ranges and lists can also be combined as: 1,3..5. The first ' + 'volume is 1. All volumes can be defined as "all". If no volumes are ' + 'specified none will be processed. You can abort with Ctrl^C.') + _USER_PROMPT_TSK = ( 'Please specify the identifier of the partition that should be ' 'processed. All partitions can be defined as: "all". Note that you can ' @@ -500,6 +508,37 @@ def _PrintAPFSVolumeIdentifiersOverview( self._output_writer.Write('\n') table_view.Write(self._output_writer) + def _PrintLVMVolumeIdentifiersOverview( + self, volume_system, volume_identifiers): + """Prints an overview of LVM volume identifiers. + + Args: + volume_system (LVMVolumeSystem): volume system. + volume_identifiers (list[str]): allowed volume identifiers. + + Raises: + ScannerError: if a volume cannot be resolved from the volume identifier. + """ + header = 'The following Logical Volume Manager (LVM) volumes were found:\n' + self._output_writer.Write(header) + + column_names = ['Identifier'] + table_view = CLITabularTableView(column_names=column_names) + + # Sort the volume identifiers in alphanumeric order. + for volume_identifier in sorted(volume_identifiers, key=lambda string: int( + ''.join([character for character in string if character.isdigit()]))): + volume = volume_system.GetVolumeByIdentifier(volume_identifier) + if not volume: + raise errors.ScannerError( + 'Volume missing for identifier: {0:s}.'.format( + volume_identifier)) + + table_view.AddRow([volume.identifier]) + + self._output_writer.Write('\n') + table_view.Write(self._output_writer) + def _PrintPartitionIdentifiersOverview( self, volume_system, volume_identifiers): """Prints an overview of TSK partition identifiers. @@ -578,7 +617,7 @@ def _ReadSelectedVolumes(self, volume_system, prefix='v'): """Reads the selected volumes provided by the user. Args: - volume_system (APFSVolumeSystem): volume system. + volume_system (VolumeSystem): volume system. prefix (Optional[str]): volume identifier prefix. Returns: @@ -650,6 +689,52 @@ def GetAPFSVolumeIdentifiers(self, volume_system, volume_identifiers): return selected_volumes + def GetLVMVolumeIdentifiers(self, volume_system, volume_identifiers): + """Retrieves LVM volume identifiers. + + This method can be used to prompt the user to provide LVM volume + identifiers. + + Args: + volume_system (LVMVolumeSystem): volume system. + volume_identifiers (list[str]): volume identifiers including prefix. + + Returns: + list[str]: selected volume identifiers including prefix or None. + """ + print_header = True + while True: + if print_header: + self._PrintLVMVolumeIdentifiersOverview( + volume_system, volume_identifiers) + + print_header = False + + self._output_writer.Write('\n') + + lines = self._textwrapper.wrap(self._USER_PROMPT_LVM) + self._output_writer.Write('\n'.join(lines)) + self._output_writer.Write('\n\nVolume identifier(s): ') + + try: + selected_volumes = self._ReadSelectedVolumes( + volume_system, prefix='lvm') + if (not selected_volumes or + not set(selected_volumes).difference(volume_identifiers)): + break + except ValueError: + pass + + self._output_writer.Write('\n') + + lines = self._textwrapper.wrap( + 'Unsupported volume identifier(s), please try again or abort with ' + 'Ctrl^C.') + self._output_writer.Write('\n'.join(lines)) + self._output_writer.Write('\n\n') + + return selected_volumes + def GetPartitionIdentifiers(self, volume_system, volume_identifiers): """Retrieves partition identifiers. @@ -791,6 +876,8 @@ def UnlockEncryptedVolume( header = 'Found a BitLocker encrypted volume.' elif locked_scan_node.type_indicator == definitions.TYPE_INDICATOR_FVDE: header = 'Found a CoreStorage (FVDE) encrypted volume.' + elif locked_scan_node.type_indicator == definitions.TYPE_INDICATOR_LUKSDE: + header = 'Found a LUKS encrypted volume.' else: header = 'Found an encrypted volume.' diff --git a/dfvfs/helpers/volume_scanner.py b/dfvfs/helpers/volume_scanner.py index bf369e84..91be7aa2 100644 --- a/dfvfs/helpers/volume_scanner.py +++ b/dfvfs/helpers/volume_scanner.py @@ -14,6 +14,7 @@ from dfvfs.path import factory as path_spec_factory from dfvfs.resolver import resolver from dfvfs.volume import apfs_volume_system +from dfvfs.volume import lvm_volume_system from dfvfs.volume import tsk_volume_system from dfvfs.volume import vshadow_volume_system @@ -54,8 +55,8 @@ class VolumeScannerMediator(object): # pylint: disable=redundant-returns-doc - # TODO: merge GetAPFSVolumeIdentifiers, GetVSSStoreIdentifiers, - # GetVSSStoreIdentifiers into GetVolumeIdentifiers? + # TODO: merge GetAPFSVolumeIdentifiers, GetLVMVolumeIdentifiers, + # GetVSSStoreIdentifiers, GetVSSStoreIdentifiers into GetVolumeIdentifiers? @abc.abstractmethod def GetAPFSVolumeIdentifiers(self, volume_system, volume_identifiers): @@ -72,6 +73,21 @@ def GetAPFSVolumeIdentifiers(self, volume_system, volume_identifiers): list[str]: selected volume identifiers including prefix or None. """ + @abc.abstractmethod + def GetLVMVolumeIdentifiers(self, volume_system, volume_identifiers): + """Retrieves LVM volume identifiers. + + This method can be used to prompt the user to provide LVM volume + identifiers. + + Args: + volume_system (LVMVolumeSystem): volume system. + volume_identifiers (list[str]): volume identifiers including prefix. + + Returns: + list[str]: selected volume identifiers including prefix or None. + """ + @abc.abstractmethod def GetPartitionIdentifiers(self, volume_system, volume_identifiers): """Retrieves partition identifiers. @@ -191,6 +207,63 @@ def _GetAPFSVolumeIdentifiers(self, scan_node, options): return self._NormalizedVolumeIdentifiers( volume_system, volume_identifiers, prefix='apfs') + def _GetLVMVolumeIdentifiers(self, scan_node, options): + """Determines the LVM volume identifiers. + + Args: + scan_node (SourceScanNode): scan node. + options (VolumeScannerOptions): volume scanner options. + + Returns: + list[str]: LVM volume identifiers. + + Raises: + ScannerError: if the format of or within the source is not supported + or the the scan node is invalid. + UserAbort: if the user requested to abort. + """ + if not scan_node or not scan_node.path_spec: + raise errors.ScannerError('Invalid scan node.') + + volume_system = lvm_volume_system.LVMVolumeSystem() + volume_system.Open(scan_node.path_spec) + + volume_identifiers = self._source_scanner.GetVolumeIdentifiers( + volume_system) + if not volume_identifiers: + return [] + + if options.volumes: + if options.volumes == ['all']: + volumes = range(1, volume_system.number_of_volumes + 1) + else: + volumes = options.volumes + + try: + selected_volumes = self._NormalizedVolumeIdentifiers( + volume_system, volumes, prefix='lvm') + + if not set(selected_volumes).difference(volume_identifiers): + return selected_volumes + except errors.ScannerError as exception: + if self._mediator: + self._mediator.PrintWarning('{0!s}'.format(exception)) + + if len(volume_identifiers) > 1: + if not self._mediator: + raise errors.ScannerError( + 'Unable to proceed. LVM volumes found but no mediator to ' + 'determine how they should be used.') + + try: + volume_identifiers = self._mediator.GetLVMVolumeIdentifiers( + volume_system, volume_identifiers) + except KeyboardInterrupt: + raise errors.UserAbort('File system scan aborted.') + + return self._NormalizedVolumeIdentifiers( + volume_system, volume_identifiers, prefix='lvm') + def _GetPartitionIdentifiers(self, scan_node, options): """Determines the partition identifiers. @@ -467,6 +540,9 @@ def _ScanVolumeSystemRoot( if scan_node.type_indicator == definitions.TYPE_INDICATOR_APFS_CONTAINER: volume_identifiers = self._GetAPFSVolumeIdentifiers(scan_node, options) + elif scan_node.type_indicator == definitions.TYPE_INDICATOR_LVM: + volume_identifiers = self._GetLVMVolumeIdentifiers(scan_node, options) + elif scan_node.type_indicator == definitions.TYPE_INDICATOR_VSHADOW: volume_identifiers = self._GetVSSStoreIdentifiers(scan_node, options) # Process VSS stores (snapshots) starting with the most recent one. diff --git a/test_data/lvm.raw b/test_data/lvm.raw index d7af1312..6c867389 100644 Binary files a/test_data/lvm.raw and b/test_data/lvm.raw differ diff --git a/tests/helpers/command_line.py b/tests/helpers/command_line.py index 02fb8939..02039c8d 100644 --- a/tests/helpers/command_line.py +++ b/tests/helpers/command_line.py @@ -17,6 +17,7 @@ from dfvfs.helpers import command_line from dfvfs.path import factory as path_spec_factory from dfvfs.volume import apfs_volume_system +from dfvfs.volume import lvm_volume_system from dfvfs.volume import tsk_volume_system from dfvfs.volume import vshadow_volume_system @@ -286,6 +287,47 @@ def testPrintAPFSVolumeIdentifiersOverview(self): self.assertEqual(output_data.split(b'\n'), expected_output_data) + def testPrintLVMVolumeIdentifiersOverview(self): + """Tests the _PrintLVMVolumeIdentifiersOverview function.""" + test_path = self._GetTestFilePath(['lvm.raw']) + self._SkipIfPathNotExists(test_path) + + test_os_path_spec = path_spec_factory.Factory.NewPathSpec( + definitions.TYPE_INDICATOR_OS, location=test_path) + test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( + definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) + test_lvm_container_path_spec = path_spec_factory.Factory.NewPathSpec( + definitions.TYPE_INDICATOR_LVM, location='/', parent=test_raw_path_spec) + + volume_system = lvm_volume_system.LVMVolumeSystem() + volume_system.Open(test_lvm_container_path_spec) + + file_object = io.BytesIO() + test_output_writer = command_line.FileObjectOutputWriter(file_object) + + test_mediator = command_line.CLIVolumeScannerMediator( + output_writer=test_output_writer) + + test_mediator._PrintLVMVolumeIdentifiersOverview( + volume_system, ['lvm1']) + + file_object.seek(0, os.SEEK_SET) + output_data = file_object.read() + + expected_output_data = [ + b'The following Logical Volume Manager (LVM) volumes were found:', + b'', + b'Identifier', + b'lvm1', + b''] + + if not win32console: + # Using join here since Python 3 does not support format of bytes. + expected_output_data[2] = b''.join([ + b'\x1b[1m', expected_output_data[2], b'\x1b[0m']) + + self.assertEqual(output_data.split(b'\n'), expected_output_data) + def testPrintTSKPartitionIdentifiersOverview(self): """Tests the _PrintTSKPartitionIdentifiersOverview function.""" test_path = self._GetTestFilePath(['mbr.raw']) @@ -463,6 +505,96 @@ def testGetAPFSVolumeIdentifiers(self): self.assertEqual(volume_identifiers, []) + def testGetLVMVolumeIdentifiers(self): + """Tests the GetLVMVolumeIdentifiers function.""" + test_path = self._GetTestFilePath(['lvm.raw']) + self._SkipIfPathNotExists(test_path) + + test_os_path_spec = path_spec_factory.Factory.NewPathSpec( + definitions.TYPE_INDICATOR_OS, location=test_path) + test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( + definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) + test_lvm_container_path_spec = path_spec_factory.Factory.NewPathSpec( + definitions.TYPE_INDICATOR_LVM, location='/', parent=test_raw_path_spec) + + volume_system = lvm_volume_system.LVMVolumeSystem() + volume_system.Open(test_lvm_container_path_spec) + + # Test selection of single volume. + input_file_object = io.BytesIO(b'1\n') + test_input_reader = command_line.FileObjectInputReader(input_file_object) + + output_file_object = io.BytesIO() + test_output_writer = command_line.FileObjectOutputWriter(output_file_object) + + test_mediator = command_line.CLIVolumeScannerMediator( + input_reader=test_input_reader, output_writer=test_output_writer) + + volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( + volume_system, ['lvm1']) + + self.assertEqual(volume_identifiers, ['lvm1']) + + # Test selection of single volume. + input_file_object = io.BytesIO(b'lvm1\n') + test_input_reader = command_line.FileObjectInputReader(input_file_object) + + output_file_object = io.BytesIO() + test_output_writer = command_line.FileObjectOutputWriter(output_file_object) + + test_mediator = command_line.CLIVolumeScannerMediator( + input_reader=test_input_reader, output_writer=test_output_writer) + + volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( + volume_system, ['lvm1']) + + self.assertEqual(volume_identifiers, ['lvm1']) + + # Test selection of single volume with invalid input on first attempt. + input_file_object = io.BytesIO(b'bogus\nlvm1\n') + test_input_reader = command_line.FileObjectInputReader(input_file_object) + + output_file_object = io.BytesIO() + test_output_writer = command_line.FileObjectOutputWriter(output_file_object) + + test_mediator = command_line.CLIVolumeScannerMediator( + input_reader=test_input_reader, output_writer=test_output_writer) + + volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( + volume_system, ['lvm1']) + + self.assertEqual(volume_identifiers, ['lvm1']) + + # Test selection of all volumes. + input_file_object = io.BytesIO(b'all\n') + test_input_reader = command_line.FileObjectInputReader(input_file_object) + + output_file_object = io.BytesIO() + test_output_writer = command_line.FileObjectOutputWriter(output_file_object) + + test_mediator = command_line.CLIVolumeScannerMediator( + input_reader=test_input_reader, output_writer=test_output_writer) + + volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( + volume_system, ['lvm1', 'lvm2']) + + self.assertEqual(volume_identifiers, ['lvm1', 'lvm2']) + + # Test selection of no volumes. + input_file_object = io.BytesIO(b'\n') + test_input_reader = command_line.FileObjectInputReader(input_file_object) + + output_file_object = io.BytesIO() + test_output_writer = command_line.FileObjectOutputWriter(output_file_object) + + test_mediator = command_line.CLIVolumeScannerMediator( + input_reader=test_input_reader, output_writer=test_output_writer) + + volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( + volume_system, ['lvm1']) + + self.assertEqual(volume_identifiers, []) + def testGetPartitionIdentifiers(self): """Tests the GetPartitionIdentifiers function.""" test_path = self._GetTestFilePath(['mbr.raw']) diff --git a/tests/helpers/source_scanner.py b/tests/helpers/source_scanner.py index 6f4093b1..370e3842 100644 --- a/tests/helpers/source_scanner.py +++ b/tests/helpers/source_scanner.py @@ -397,6 +397,28 @@ def testScanOnEncryptedAPFS(self): self.assertIsNotNone(scan_node) self.assertEqual(scan_node.type_indicator, definitions.TYPE_INDICATOR_APFS) + def testScanOnLVM(self): + """Test the Scan function on LVM.""" + test_path = self._GetTestFilePath(['lvm.raw']) + self._SkipIfPathNotExists(test_path) + + scan_context = source_scanner.SourceScannerContext() + scan_context.OpenSourcePath(test_path) + + self._source_scanner.Scan(scan_context) + self.assertEqual( + scan_context.source_type, definitions.SOURCE_TYPE_STORAGE_MEDIA_IMAGE) + + scan_node = self._GetTestScanNode(scan_context) + self.assertIsNotNone(scan_node) + self.assertEqual(scan_node.type_indicator, definitions.TYPE_INDICATOR_LVM) + + self.assertEqual(len(scan_node.sub_nodes), 2) + + scan_node = scan_node.sub_nodes[0].GetSubNodeByLocation('/') + self.assertIsNotNone(scan_node) + self.assertEqual(scan_node.type_indicator, definitions.TYPE_INDICATOR_TSK) + def testScanOnMBRPartitionedImage(self): """Test the Scan function on a MBR partitioned image.""" test_path = self._GetTestFilePath(['mbr.raw']) diff --git a/tests/helpers/volume_scanner.py b/tests/helpers/volume_scanner.py index be15ec33..a8a17fcb 100644 --- a/tests/helpers/volume_scanner.py +++ b/tests/helpers/volume_scanner.py @@ -40,6 +40,21 @@ def GetAPFSVolumeIdentifiers(self, volume_system, volume_identifiers): """ return volume_identifiers + def GetLVMVolumeIdentifiers(self, volume_system, volume_identifiers): + """Retrieves LVM volume identifiers. + + This method can be used to prompt the user to provide LVM volume + identifiers. + + Args: + volume_system (LVMVolumeSystem): volume system. + volume_identifiers (list[str]): volume identifiers including prefix. + + Returns: + list[str]: selected volume identifiers including prefix or None. + """ + return volume_identifiers + def GetPartitionIdentifiers(self, volume_system, volume_identifiers): """Retrieves partition identifiers. diff --git a/tests/vfs/lvm_file_entry.py b/tests/vfs/lvm_file_entry.py index abbb556b..017e1bda 100644 --- a/tests/vfs/lvm_file_entry.py +++ b/tests/vfs/lvm_file_entry.py @@ -53,7 +53,7 @@ def testEntriesGenerator(self): self.assertIsNotNone(directory) entries = list(directory.entries) - self.assertEqual(len(entries), 1) + self.assertEqual(len(entries), 2) class LVMFileEntryTest(shared_test_lib.BaseTestCase): @@ -214,9 +214,9 @@ def testSubFileEntries(self): file_entry = self._file_system.GetFileEntryByPathSpec(path_spec) self.assertIsNotNone(file_entry) - self.assertEqual(file_entry.number_of_sub_file_entries, 1) + self.assertEqual(file_entry.number_of_sub_file_entries, 2) - expected_sub_file_entry_names = ['lvm1'] + expected_sub_file_entry_names = ['lvm1', 'lvm2'] sub_file_entry_names = [] for sub_file_entry in file_entry.sub_file_entries: diff --git a/tests/volume/lvm_volume_system.py b/tests/volume/lvm_volume_system.py index 3d7a97d0..a22058a4 100644 --- a/tests/volume/lvm_volume_system.py +++ b/tests/volume/lvm_volume_system.py @@ -27,26 +27,26 @@ def setUp(self): self._lvm_path_spec = lvm_path_spec.LVMPathSpec( location='/', parent=path_spec) - # vslvminfo fuse/lvm.raw + # vslvminfo lvm.raw # # Linux Logical Volume Manager (LVM) information: # Volume Group (VG): # Name: test_volume_group - # Identifier: SN0dH9-7Eic-NCvi-WHj8-76G8-za0g-iJobeq - # Sequence number: 2 + # Identifier: OdFqZi-WJfC-35Ok-2Jxv-mcC3-e2OS-QROmeJ + # Sequence number: 3 # Extent size: 4.0 MiB (4194304 bytes) # Number of physical volumes: 1 - # Number of logical volumes: 1 + # Number of logical volumes: 2 # # Physical Volume (PV): 1 # Name: pv0 - # Identifier: K994MB-Sn1r-7rpS-hQEW-DgUP-87Dr-9d0MFa - # Device path: /dev/loop0 - # Volume size: 8.0 MiB (8388608 bytes) + # Identifier: l051NA-ZitO-CRvE-QizU-JsB2-CqmX-LNDICw + # Device path: /dev/loop99 + # Volume size: 10 MiB (10485760 bytes) # # Logical Volume (LV): 1 - # Name: test_logical_volume - # Identifier: 0MUZZr-7jgO-iFwW-sSG3-Rb8W-w5td-qAOF8e + # Name: test_logical_volume1 + # Identifier: RI0pgm-rdy4-XxcL-5eoK-Easc-fgPq-CWaEJb # Number of segments: 1 # Segment: 1 # Offset: 0x00000000 (0) @@ -55,6 +55,18 @@ def setUp(self): # Stripe: 1 # Physical volume: pv0 # Data area offset: 0x00000000 (0) + # + # Logical Volume (LV): 2 + # Name: test_logical_volume2 + # Identifier: 2ySlpP-g1fn-qwMH-h7y9-3u4n-GInp-Pfvvxo + # Number of segments: 1 + # Segment: 1 + # Offset: 0x00000000 (0) + # Size: 4.0 MiB (4194304 bytes) + # Number of stripes: 1 + # Stripe: 1 + # Physical volume: pv0 + # Data area offset: 0x00400000 (4194304) def testIterateVolumes(self): """Test the iterate volumes functionality.""" @@ -62,7 +74,7 @@ def testIterateVolumes(self): volume_system.Open(self._lvm_path_spec) - self.assertEqual(volume_system.number_of_volumes, 1) + self.assertEqual(volume_system.number_of_volumes, 2) volume = volume_system.GetVolumeByIndex(0) self.assertIsNotNone(volume) @@ -71,7 +83,7 @@ def testIterateVolumes(self): self.assertEqual(volume.number_of_attributes, 1) self.assertEqual(volume.identifier, 'lvm1') - expected_value = '0MUZZr-7jgO-iFwW-sSG3-Rb8W-w5td-qAOF8e' + expected_value = 'RI0pgm-rdy4-XxcL-5eoK-Easc-fgPq-CWaEJb' volume_attribute = volume.GetAttribute('identifier') self.assertIsNotNone(volume_attribute) self.assertEqual(volume_attribute.value, expected_value) diff --git a/utils/generate_test_data_linux.sh b/utils/generate_test_data_linux.sh index 19a123ea..daaa482f 100755 --- a/utils/generate_test_data_linux.sh +++ b/utils/generate_test_data_linux.sh @@ -214,7 +214,9 @@ sudo umount ${MOUNT_POINT}; sudo losetup -d /dev/loop99; -# Create test image with a GPT partition table with 2 partitions one with an ext2 file system and the other with ext4 +# Create test image with a GPT partition table with 2 partitions with an ext2 +# file system in the first partition and an ext4 file system in the second +# partition. IMAGE_FILE="test_data/gpt.raw"; dd if=/dev/zero of=${IMAGE_FILE} bs=${SECTOR_SIZE} count=$(( ${IMAGE_SIZE} / ${SECTOR_SIZE} )) 2> /dev/null; @@ -262,8 +264,9 @@ sudo umount ${MOUNT_POINT}; sudo losetup -d /dev/loop99; -# Create test image with a LVM and an EXT2 file system -IMAGE_SIZE=$(( 8192 * 1024 )); +# Create test image with a LVM with 2 volumes with an EXT2 file system in the +# first volume. +IMAGE_SIZE=$(( 10 * 1024 * 1024 )); IMAGE_FILE="test_data/lvm.raw"; @@ -275,11 +278,11 @@ sudo pvcreate -q /dev/loop99 2>&1 | sed '/is using an old PV header, modify the sudo vgcreate -q test_volume_group /dev/loop99 2>&1 | sed '/is using an old PV header, modify the VG to update/ d;/open failed: No medium found/ d'; -sudo lvcreate -q --name test_logical_volume --size 4m --type linear test_volume_group 2>&1 | sed '/is using an old PV header, modify the VG to update/ d;/open failed: No medium found/ d'; +sudo lvcreate -q --name test_logical_volume1 --size 4m --type linear test_volume_group 2>&1 | sed '/is using an old PV header, modify the VG to update/ d;/open failed: No medium found/ d'; -sudo mke2fs -q -t ext2 -L "ext2_test" /dev/test_volume_group/test_logical_volume; +sudo mke2fs -q -t ext2 -L "ext2_test" /dev/test_volume_group/test_logical_volume1; -sudo mount -o loop,rw /dev/test_volume_group/test_logical_volume ${MOUNT_POINT}; +sudo mount -o loop,rw /dev/test_volume_group/test_logical_volume1 ${MOUNT_POINT}; sudo chown ${USERNAME} ${MOUNT_POINT}; @@ -287,14 +290,12 @@ create_test_file_entries ${MOUNT_POINT}; sudo umount ${MOUNT_POINT}; +sudo lvcreate -q --name test_logical_volume2 --size 4m --type linear test_volume_group 2>&1 | sed '/is using an old PV header, modify the VG to update/ d;/open failed: No medium found/ d'; + sudo vgchange -q --activate n test_volume_group 2>&1 | sed '/is using an old PV header, modify the VG to update/ d;/open failed: No medium found/ d'; sudo losetup -d /dev/loop99; -qemu-img convert -f raw -O qcow2 test_data/lvm.raw test_data/lvm.qcow2; - -rm -f test_data/lvm.raw; - # Create test image with a LUKS 1 and an EXT2 file system IMAGE_FILE="test_data/luks1.raw";