def testReadFileEntriesOnBinary(self): """Tests the _ReadFileEntries function on binary format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(output_writer=output_writer) test_file.file_format = 'bin-little-endian' test_file_path = self._GetTestFilePath(['cpio', 'syslog.bin.cpio']) with open(test_file_path, 'rb') as file_object: test_file._ReadFileEntries(file_object) self.assertEqual(len(test_file._file_entries), 1)
def testReadFileEntryOnNewASCII(self): """Tests the _ReadFileEntry function on new ASCII format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(output_writer=output_writer) test_file.file_format = 'newc' test_file_path = self._GetTestFilePath(['cpio', 'syslog.newc.cpio']) with open(test_file_path, 'rb') as file_object: file_entry = test_file._ReadFileEntry(file_object, 0) self.assertEqual(file_entry.data_size, 1247)
def testReadFileObjectOnPortableASCII(self): """Tests the ReadFileObject function on portable ASCII format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(debug=True, output_writer=output_writer) test_file_path = self._GetTestFilePath(['cpio', 'syslog.odc.cpio']) test_file.Open(test_file_path) self.assertEqual(test_file.file_format, 'odc') test_file.Close()
def testReadFileObjectOnNewASCIIWithCRC(self): """Tests the ReadFileObject function on new ASCII with CRC format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(debug=True, output_writer=output_writer) test_file_path = self._GetTestFilePath(['cpio', 'syslog.crc.cpio']) test_file.Open(test_file_path) self.assertEqual(test_file.file_format, 'crc') test_file.Close()
def testReadFileObjectOnBinary(self): """Tests the ReadFileObject function on binary format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(debug=True, output_writer=output_writer) test_file_path = self._GetTestFilePath(['cpio', 'syslog.bin.cpio']) test_file.Open(test_file_path) self.assertEqual(test_file.file_format, 'bin-little-endian') test_file.Close()
def testGetFileEntryByPathOnBinary(self): """Tests the GetFileEntryByPath function on binary format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(output_writer=output_writer) test_file_path = self._GetTestFilePath(['cpio', 'syslog.bin.cpio']) test_file.Open(test_file_path) file_entry = test_file.GetFileEntryByPath('syslog') self.assertIsNotNone(file_entry) file_entry = test_file.GetFileEntryByPath('bogus') self.assertIsNone(file_entry) test_file.Close()
def testGetFileEntriesOnBinary(self): """Tests the GetFileEntries function on binary format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(output_writer=output_writer) test_file_path = self._GetTestFilePath(['cpio', 'syslog.bin.cpio']) test_file.Open(test_file_path) file_entries = list(test_file.GetFileEntries()) self.assertEqual(len(file_entries), 1) test_file.Close() file_entries = list(test_file.GetFileEntries()) self.assertEqual(len(file_entries), 0)
def testFileEntryExistsByPathOnBinary(self): """Tests the FileEntryExistsByPath function on binary format.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(output_writer=output_writer) test_file_path = self._GetTestFilePath(['cpio', 'syslog.bin.cpio']) test_file.Open(test_file_path) result = test_file.FileEntryExistsByPath('syslog') self.assertTrue(result) result = test_file.FileEntryExistsByPath('bogus') self.assertFalse(result) test_file.Close()
def testDebugPrintFileEntry(self): """Tests the _DebugPrintFileEntry function.""" output_writer = test_lib.TestOutputWriter() test_file = cpio.CPIOArchiveFile(output_writer=output_writer) test_file.file_format = 'bin-little-endian' data_type_map = test_file._GetDataTypeMap( 'cpio_binary_little_endian_file_entry') file_entry = data_type_map.CreateStructureValues( device_number=1, file_size=0, group_identifier=1001, inode_number=2, mode=0o777, modification_time=0, number_of_links=1, path_size=0, signature=0x71c7, special_device_number=0, user_identifier=1000) test_file._DebugPrintFileEntry(file_entry) test_file.file_format = 'newc' data_type_map = test_file._GetDataTypeMap('cpio_new_ascii_file_entry') file_entry = data_type_map.CreateStructureValues( checksum=0x12345678, device_major_number=3, device_minor_number=4, file_size=0, group_identifier=1001, inode_number=2, mode=0o777, modification_time=0, number_of_links=1, path_size=0, signature=b'070702', special_device_major_number=5, special_device_minor_number=5, user_identifier=1000) test_file._DebugPrintFileEntry(file_entry)
def HashFileEntries(self): """Hashes the file entries stored in the CPIO archive file.""" stat_object = os.stat(self._path) file_object = open(self._path, 'rb') file_offset = 0 file_size = stat_object.st_size # initrd files can consist of an uncompressed and compressed cpio archive. # Keeping the functionality in this script for now, but this likely # needs to be in a separate initrd hashing script. while file_offset < stat_object.st_size: file_object.seek(file_offset, os.SEEK_SET) signature_data = file_object.read(6) file_type = None if len(signature_data) > 2: if (signature_data[:2] in (self._CPIO_SIGNATURE_BINARY_BIG_ENDIAN, self._CPIO_SIGNATURE_BINARY_LITTLE_ENDIAN) or signature_data in (self._CPIO_SIGNATURE_PORTABLE_ASCII, self._CPIO_SIGNATURE_NEW_ASCII, self._CPIO_SIGNATURE_NEW_ASCII_WITH_CHECKSUM)): file_type = 'cpio' elif signature_data[:2] == self._GZIP_SIGNATURE: file_type = 'gzip' elif signature_data[:2] == self._BZIP_SIGNATURE: file_type = 'bzip' elif signature_data == self._XZ_SIGNATURE: file_type = 'xz' if not file_type: self._output_writer.WriteText( 'Unsupported file type at offset: 0x{0:08x}.\n'.format( file_offset)) return if file_type == 'cpio': file_object.seek(file_offset, os.SEEK_SET) cpio_file_object = file_object elif file_type in ('bzip', 'gzip', 'xz'): compressed_data_size = file_size - file_offset compressed_data_file_object = data_range.DataRange( file_object, data_offset=file_offset, data_size=compressed_data_size) if file_type == 'bzip': cpio_file_object = bz2.BZ2File(compressed_data_file_object) elif file_type == 'gzip': cpio_file_object = gzip.GzipFile( fileobj=compressed_data_file_object) # pylint: disable=no-member elif file_type == 'xz' and lzma: cpio_file_object = lzma.LZMAFile( compressed_data_file_object) cpio_archive_file = cpio.CPIOArchiveFile(debug=self._debug) cpio_archive_file.ReadFileObject(cpio_file_object) for file_entry in sorted(cpio_archive_file.GetFileEntries()): if file_entry.data_size == 0: continue sha256_context = hashlib.sha256() file_data = file_entry.read(4096) while file_data: sha256_context.update(file_data) file_data = file_entry.read(4096) self._output_writer.WriteText('{0:s}\t{1:s}\n'.format( sha256_context.hexdigest(), file_entry.path)) file_offset += cpio_archive_file.size padding_size = file_offset % 16 if padding_size > 0: file_offset += 16 - padding_size cpio_archive_file.Close()
def Main(): """The main program function. Returns: bool: True if successful or False if not. """ argument_parser = argparse.ArgumentParser( description=('Extracts information from CPIO archive files.')) argument_parser.add_argument('-d', '--debug', dest='debug', action='store_true', default=False, help='enable debug output.') argument_parser.add_argument( '--hash', dest='hash', action='store_true', default=False, help='calculate the SHA-256 sum of the file entries.') argument_parser.add_argument('source', nargs='?', action='store', metavar='PATH', default=None, help='path of the CPIO archive file.') options = argument_parser.parse_args() if not options.source: print('Source file missing.') print('') argument_parser.print_help() print('') return False logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(message)s') output_writer = output_writers.StdoutWriter() try: output_writer.Open() except IOError as exception: print( 'Unable to open output writer with error: {0!s}'.format(exception)) print('') return False if options.hash: cpio_archive_file_hasher = CPIOArchiveFileHasher( options.source, debug=options.debug, output_writer=output_writer) cpio_archive_file_hasher.HashFileEntries() else: # TODO: move functionality to CPIOArchiveFileInfo. cpio_archive_file = cpio.CPIOArchiveFile(debug=options.debug, output_writer=output_writer) cpio_archive_file.Open(options.source) output_writer.WriteText('CPIO archive information:\n') output_writer.WriteText('\tFormat\t\t: {0:s}\n'.format( cpio_archive_file.file_format)) output_writer.WriteText('\tSize\t\t: {0:d} bytes\n'.format( cpio_archive_file.size)) cpio_archive_file.Close() output_writer.WriteText('\n') output_writer.Close() return True