/* Reads an free map * Returns 1 if successful or -1 on error */ int libpff_free_map_read( libcdata_range_list_t *unallocated_block_list, libbfio_handle_t *file_io_handle, off64_t free_map_offset, uint8_t file_type, libcerror_error_t **error ) { uint8_t *free_map_data = NULL; uint8_t *table_data = NULL; static char *function = "libpff_free_map_read"; off64_t back_pointer_offset = 0; off64_t unallocated_offset = 0; size_t read_size = 0; size_t unallocated_size = 0; size_t allocation_block_size = 0; ssize_t read_count = 0; uint32_t stored_checksum = 0; uint32_t calculated_checksum = 0; uint16_t table_iterator = 0; uint8_t bit_iterator = 0; uint8_t free_map_entry = 0; uint8_t free_map_type = 0; uint8_t free_map_type_copy = 0; int result = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint16_t value_16bit = 0; #endif if( unallocated_block_list == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid unallocated block list.", function ); return( -1 ); } if( file_io_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid file IO handle.", function ); return( -1 ); } if( ( file_type != LIBPFF_FILE_TYPE_32BIT ) && ( file_type != LIBPFF_FILE_TYPE_64BIT ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported file type.", function ); return( -1 ); } if( libbfio_handle_seek_offset( file_io_handle, free_map_offset, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek free map offset: %" PRIi64 ".", function, free_map_offset ); goto on_error; } if( file_type == LIBPFF_FILE_TYPE_32BIT ) { read_size = sizeof( pff_free_map_32bit_t ); } else if( file_type == LIBPFF_FILE_TYPE_64BIT ) { read_size = sizeof( pff_free_map_64bit_t ); } free_map_data = (uint8_t *) memory_allocate( sizeof( uint8_t ) * read_size ); if( free_map_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create alloction table data.", function ); goto on_error; } read_count = libbfio_handle_read_buffer( file_io_handle, free_map_data, read_size, error ); if( read_count != (ssize_t) read_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read free map.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: free map:\n", function ); libcnotify_print_data( free_map_data, read_size, 0 ); } #endif if( file_type == LIBPFF_FILE_TYPE_32BIT ) { table_data = ( (pff_free_map_32bit_t *) free_map_data )->data; free_map_type = ( (pff_free_map_32bit_t *) free_map_data )->type; free_map_type_copy = ( (pff_free_map_32bit_t *) free_map_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_free_map_32bit_t *) free_map_data )->back_pointer, back_pointer_offset ); byte_stream_copy_to_uint32_little_endian( ( (pff_free_map_32bit_t *) free_map_data )->checksum, stored_checksum ); } else if( file_type == LIBPFF_FILE_TYPE_64BIT ) { table_data = ( (pff_free_map_64bit_t *) free_map_data )->data; free_map_type = ( (pff_free_map_64bit_t *) free_map_data )->type; free_map_type_copy = ( (pff_free_map_64bit_t *) free_map_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_free_map_64bit_t *) free_map_data )->checksum, stored_checksum ); byte_stream_copy_to_uint64_little_endian( ( (pff_free_map_64bit_t *) free_map_data )->back_pointer, back_pointer_offset ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: type\t\t: 0x%02" PRIx8 "\n", function, free_map_type ); libcnotify_printf( "%s: type copy\t: 0x%02" PRIx8 "\n", function, free_map_type_copy ); if( file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_free_map_32bit_t *) free_map_data )->signature, value_16bit ); libcnotify_printf( "%s: signature\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: back pointer\t: %" PRIu64 "\n", function, back_pointer_offset ); libcnotify_printf( "%s: checksum\t: 0x%" PRIx32 "\n", function, stored_checksum ); } else if( file_type == LIBPFF_FILE_TYPE_64BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_free_map_64bit_t *) free_map_data )->signature, value_16bit ); libcnotify_printf( "%s: signature\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: checksum\t\t: 0x%" PRIx32 "\n", function, stored_checksum ); libcnotify_printf( "%s: back pointer\t: %" PRIu64 "\n", function, back_pointer_offset ); } libcnotify_printf( "\n" ); } #endif if( libfmapi_checksum_calculate_weak_crc32( &calculated_checksum, table_data, 496, 0, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to calculate weak CRC-32.", function ); goto on_error; } if( stored_checksum != calculated_checksum ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_INPUT, LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH, "%s: mismatch in checksum ( %" PRIu32 " != %" PRIu32 " ).", function, stored_checksum, calculated_checksum ); /* TODO implement error tollerance */ goto on_error; } if( free_map_type != free_map_type_copy ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_INPUT, LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH, "%s: mismatch in allocation table type ( 0x%02" PRIx8 " != 0x%02" PRIx8 " ).", function, free_map_type, free_map_type_copy ); /* TODO implement error tollerance */ goto on_error; } if( ( free_map_type != LIBPFF_FREE_MAP_TYPE_DATA ) && ( free_map_type != LIBPFF_FREE_MAP_TYPE_PAGE ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported allocation table type: 0x%08" PRIx32 "", function, free_map_type ); /* TODO implement error tollerance */ goto on_error; } /* TODO */ if( free_map_type == LIBPFF_FREE_MAP_TYPE_PAGE ) { allocation_block_size = 512; back_pointer_offset -= 0x200; } else if( free_map_type == LIBPFF_FREE_MAP_TYPE_DATA ) { allocation_block_size = 64; } for( table_iterator = 0; table_iterator < 496; table_iterator++ ) { free_map_entry = table_data[ table_iterator ]; for( bit_iterator = 0; bit_iterator < 8; bit_iterator++ ) { if( ( free_map_entry & 0x80 ) == 0 ) { if( unallocated_size == 0 ) { unallocated_offset = back_pointer_offset; } unallocated_size += allocation_block_size; } else if( unallocated_size > 0 ) { result = libcdata_range_list_insert_range( unallocated_block_list, unallocated_offset, unallocated_size, NULL, NULL, NULL, error ); if( result == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append unallocated block to list.", function ); goto on_error; } unallocated_size = 0; } free_map_entry <<= 1; back_pointer_offset += allocation_block_size; } } if( unallocated_size > 0 ) { result = libcdata_range_list_insert_range( unallocated_block_list, unallocated_offset, unallocated_size, NULL, NULL, NULL, error ); if( result == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append unallocated block to list.", function ); goto on_error; } unallocated_size = 0; } memory_free( free_map_data ); return( 1 ); on_error: if( free_map_data != NULL ) { memory_free( free_map_data ); } return( -1 ); }
/* Reads an index node * Returns 1 if successful or -1 on error */ int libpff_index_node_read( libpff_index_node_t *index_node, libpff_io_handle_t *io_handle, libbfio_handle_t *file_io_handle, off64_t node_offset, libcerror_error_t **error ) { uint8_t *index_node_footer_data = NULL; static char *function = "libpff_index_node_read"; ssize_t read_count = 0; uint32_t calculated_checksum = 0; uint32_t stored_checksum = 0; uint8_t calculated_entry_size = 0; uint8_t calculated_maximum_number_of_entries = 0; uint8_t index_node_type_copy = 0; int result = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint8_t *index_node_entry_data = NULL; uint64_t value_64bit = 0; uint32_t value_32bit = 0; uint16_t entry_index = 0; uint16_t index_node_entry_data_size = 0; uint16_t value_16bit = 0; #endif if( index_node == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid index node.", function ); return( -1 ); } if( index_node->data != NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, "%s: invalid index node - data already set.", function ); return( -1 ); } if( io_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid IO handle.", function ); return( -1 ); } if( ( io_handle->file_type != LIBPFF_FILE_TYPE_32BIT ) && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT ) && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported file type.", function ); return( -1 ); } if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { index_node->data_size = 512; index_node->maximum_entries_data_size = 512 - sizeof( pff_index_node_32bit_footer_t ); } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) { index_node->data_size = 512; index_node->maximum_entries_data_size = 512 - sizeof( pff_index_node_64bit_footer_t ); } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { index_node->data_size = 4096; index_node->maximum_entries_data_size = 4096 - sizeof( pff_index_node_64bit_4k_page_footer_t ); } index_node->data = (uint8_t *) memory_allocate( sizeof( uint8_t ) * index_node->data_size ); if( index_node->data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create index node data.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: reading index node data at offset: %" PRIi64 " (0x%08" PRIx64 ")\n", function, node_offset, node_offset ); } #endif if( libbfio_handle_seek_offset( file_io_handle, node_offset, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek node offset: %" PRIi64 ".", function, node_offset ); goto on_error; } read_count = libbfio_handle_read_buffer( file_io_handle, index_node->data, index_node->data_size, error ); if( read_count != (ssize_t) index_node->data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read index node data.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: index node data:\n", function ); libcnotify_print_data( index_node->data, index_node->data_size, LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); } #endif index_node_footer_data = &( index_node->data[ index_node->maximum_entries_data_size ] ); if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { index_node->type = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->type; index_node_type_copy = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->back_pointer, index_node->back_pointer ); byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->checksum, stored_checksum ); index_node->number_of_entries = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->number_of_entries; index_node->maximum_number_of_entries = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->maximum_number_of_entries; index_node->entry_size = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->entry_size; index_node->level = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->level; if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR ) && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) ) { calculated_entry_size = 16; calculated_maximum_number_of_entries = 496 / 16; } else { calculated_entry_size = 12; calculated_maximum_number_of_entries = 496 / 12; } } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) { index_node->type = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->type; index_node_type_copy = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->checksum, stored_checksum ); byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->back_pointer, index_node->back_pointer ); index_node->number_of_entries = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->number_of_entries; index_node->maximum_number_of_entries = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->maximum_number_of_entries; index_node->entry_size = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->entry_size; index_node->level = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->level; if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR ) && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) ) { calculated_entry_size = 32; calculated_maximum_number_of_entries = 488 / 32; } else { calculated_entry_size = 24; calculated_maximum_number_of_entries = 488 / 24; } } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { index_node->type = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->type; index_node_type_copy = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->checksum, stored_checksum ); byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->back_pointer, index_node->back_pointer ); byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->number_of_entries, index_node->number_of_entries ); byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->maximum_number_of_entries, index_node->maximum_number_of_entries ); index_node->entry_size = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->entry_size; index_node->level = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->level; if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR ) && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) ) { calculated_entry_size = 32; calculated_maximum_number_of_entries = 4056 / 32; } else { calculated_entry_size = 24; calculated_maximum_number_of_entries = 4056 / 24; } } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: number of entries\t\t\t\t: %" PRIu16 "\n", function, index_node->number_of_entries ); libcnotify_printf( "%s: maximum number of entries\t\t\t: %" PRIu16 "\n", function, index_node->maximum_number_of_entries ); libcnotify_printf( "%s: entry size\t\t\t\t\t: %" PRIu8 "\n", function, index_node->entry_size ); libcnotify_printf( "%s: node level\t\t\t\t\t: %" PRIu8 "\n", function, index_node->level ); if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) { libcnotify_printf( "%s: padding:\n", function ); libcnotify_print_data( ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->padding1, 4, 0 ); } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { libcnotify_printf( "%s: padding:\n", function ); libcnotify_print_data( ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->padding1, 10, 0 ); } libcnotify_printf( "%s: index node type\t\t\t\t\t: 0x%02" PRIx8 "\n", function, index_node->type ); libcnotify_printf( "%s: index node type copy\t\t\t\t: 0x%02" PRIx8 "\n", function, index_node_type_copy ); if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->signature, value_16bit ); libcnotify_printf( "%s: signature\t\t\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: back pointer\t\t\t\t\t: 0x%08" PRIx64 "\n", function, index_node->back_pointer ); libcnotify_printf( "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n", function, stored_checksum ); } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->signature, value_16bit ); libcnotify_printf( "%s: signature\t\t\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n", function, stored_checksum ); libcnotify_printf( "%s: back pointer\t\t\t\t\t: 0x%08" PRIx64 "\n", function, index_node->back_pointer ); } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->signature, value_16bit ); libcnotify_printf( "%s: signature\t\t\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n", function, stored_checksum ); libcnotify_printf( "%s: back pointer\t\t\t\t\t: 0x%08" PRIx64 "\n", function, index_node->back_pointer ); byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->unknown1, value_64bit ); libcnotify_printf( "%s: unknown1\t\t\t\t\t: 0x%08" PRIx64 "\n", function, value_64bit ); } libcnotify_printf( "\n" ); } #endif if( index_node->type != index_node_type_copy ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: mismatch in index node type (0x%02" PRIx8 " != 0x%02" PRIx8 ").\n", function, index_node->type, index_node_type_copy ); } #endif if( ( index_node->type != LIBPFF_INDEX_TYPE_DESCRIPTOR ) && ( index_node->type != LIBPFF_INDEX_TYPE_OFFSET ) && ( ( index_node_type_copy == LIBPFF_INDEX_TYPE_DESCRIPTOR ) || ( index_node_type_copy == LIBPFF_INDEX_TYPE_OFFSET ) ) ) { index_node->type = index_node_type_copy; } } if( ( index_node->type != LIBPFF_INDEX_TYPE_DESCRIPTOR ) && ( index_node->type != LIBPFF_INDEX_TYPE_OFFSET ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported index node type: 0x%02" PRIx8 ".", function, index_node->type ); goto on_error; } if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { result = libfmapi_checksum_calculate_weak_crc32( &calculated_checksum, index_node->data, 500, 0, error ); } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) { result = libfmapi_checksum_calculate_weak_crc32( &calculated_checksum, index_node->data, 496, 0, error ); } else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { result = libfmapi_checksum_calculate_weak_crc32( &calculated_checksum, index_node->data, 4072, 0, error ); } if( result != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to calculate weak CRC-32.", function ); goto on_error; } if( stored_checksum != calculated_checksum ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: mismatch in checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n", function, stored_checksum, calculated_checksum ); } #endif /* TODO smart error handling */ } if( ( index_node->entry_size != 0 ) && ( index_node->entry_size != calculated_entry_size ) ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: entry size mismatch (calculated: %" PRIu8 ", stored: %" PRIu8 ").\n", function, calculated_entry_size, index_node->entry_size ); } #endif index_node->entry_size = calculated_entry_size; } if( ( index_node->maximum_number_of_entries != 0 ) && ( index_node->maximum_number_of_entries != calculated_maximum_number_of_entries ) ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: maximum number of entries mismatch (calculated: %" PRIu8 ", stored: %" PRIu8 ").\n", function, calculated_maximum_number_of_entries, index_node->maximum_number_of_entries ); } #endif index_node->maximum_number_of_entries = calculated_maximum_number_of_entries; } if( index_node->number_of_entries > index_node->maximum_number_of_entries ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: number of entries: %" PRIu8 ", exceeds maximum: %" PRIu8 ".", function, index_node->number_of_entries, index_node->maximum_number_of_entries ); } #endif index_node->number_of_entries = index_node->maximum_number_of_entries; } if( ( (uint16_t) index_node->number_of_entries * (uint16_t) index_node->entry_size ) > index_node->maximum_entries_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: size of entries: %" PRIu16 ", exceeds maximum: %" PRIu16 ".", function, index_node->number_of_entries * index_node->entry_size, index_node->maximum_entries_data_size ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { index_node_entry_data = index_node->data; index_node_entry_data_size = index_node->maximum_entries_data_size; /* Print all the entries */ for( entry_index = 0; entry_index < index_node->maximum_number_of_entries; entry_index++ ) { if( entry_index == index_node->number_of_entries ) { result = libpff_index_node_check_for_empty_block( index_node_entry_data, index_node_entry_data_size, error ); if( result == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to determine if remaining index nodes are empty.", function ); return( -1 ); } else if( result != 0 ) { break; } libcnotify_printf( "\n" ); libcnotify_printf( "%s: remaining node entries\n", function ); } if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint32_little_endian( index_node_entry_data, value_64bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint64_little_endian( index_node_entry_data, value_64bit ); } libcnotify_printf( "%s: entry: %03" PRIu16 " index node identifier\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n", function, entry_index, value_64bit, value_64bit ); /* Process descriptor index node leaf nodes */ if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR ) && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) ) { if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_descriptor_entry_32bit_t *) index_node_entry_data )->data_identifier, value_64bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->data_identifier, value_64bit ); } libcnotify_printf( "%s: entry: %03" PRIu16 " data identifier\t\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n", function, entry_index, value_64bit, value_64bit ); if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_descriptor_entry_32bit_t *) index_node_entry_data )->local_descriptors_identifier, value_64bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->local_descriptors_identifier, value_64bit ); } libcnotify_printf( "%s: entry: %03" PRIu16 " local descriptors identifier\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n", function, entry_index, value_64bit, value_64bit ); if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_descriptor_entry_32bit_t *) index_node_entry_data )->parent_identifier, value_32bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->parent_identifier, value_32bit ); } libcnotify_printf( "%s: entry: %03" PRIu16 " parent identifier\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n", function, entry_index, value_32bit, value_32bit ); if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->unknown1, value_32bit ); libcnotify_printf( "%s: entry: %03" PRIu16 " unknown1\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n", function, entry_index, value_32bit, value_32bit ); } } /* Process offset and descriptor index node branch nodes and offset index node leaf nodes */ else { if( index_node->level != LIBPFF_INDEX_NODE_LEVEL_LEAF ) { if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_branch_entry_32bit_t *) index_node_entry_data )->back_pointer, value_64bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_branch_entry_64bit_t *) index_node_entry_data )->back_pointer, value_64bit ); } libcnotify_printf( "%s: entry: %03" PRIu16 " back pointer\t\t\t\t: 0x%08" PRIx64 "\n", function, entry_index, value_64bit ); } if( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) { if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_offset_entry_32bit_t *) index_node_entry_data )->file_offset, value_64bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->file_offset, value_64bit ); } } else { if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_branch_entry_32bit_t *) index_node_entry_data )->file_offset, value_64bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint64_little_endian( ( (pff_index_node_branch_entry_64bit_t *) index_node_entry_data )->file_offset, value_64bit ); } } libcnotify_printf( "%s: entry: %03" PRIu16 " file offset\t\t\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n", function, entry_index, value_64bit, value_64bit ); if( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) { if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_offset_entry_32bit_t *) index_node_entry_data )->data_size, value_16bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->data_size, value_16bit ); } libcnotify_printf( "%s: entry: %03" PRIu16 " data size\t\t\t\t: %" PRIu16 "\n", function, entry_index, value_16bit ); if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_offset_entry_32bit_t *) index_node_entry_data )->reference_count, value_16bit ); } else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint16_little_endian( ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->reference_count, value_16bit ); } libcnotify_printf( "%s: entry: %03" PRIu16 " reference count\t\t\t: %" PRIu16 "\n", function, entry_index, value_16bit ); if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { byte_stream_copy_to_uint32_little_endian( ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->data_allocation_table_file_offset, value_32bit ); libcnotify_printf( "%s: entry: %03" PRIu16 " data allocation table offset\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n", function, entry_index, value_32bit, value_32bit ); } } } index_node_entry_data += index_node->entry_size; index_node_entry_data_size -= index_node->entry_size; } libcnotify_printf( "\n" ); } #endif index_node->entries_data = index_node->data; return( 1 ); on_error: if( index_node->data != NULL ) { memory_free( index_node->data ); index_node->data = NULL; } return( -1 ); }
/* Reads an allocation table * Returns 1 if successful or -1 on error */ int libpff_allocation_table_read( libcdata_range_list_t *unallocated_block_list, libbfio_handle_t *file_io_handle, off64_t allocation_table_offset, uint8_t file_type, libcerror_error_t **error ) { uint8_t *allocation_table_data = NULL; uint8_t *table_data = NULL; static char *function = "libpff_allocation_table_read"; off64_t back_pointer_offset = 0; off64_t unallocated_offset = 0; size_t read_size = 0; size_t unallocated_size = 0; size_t allocation_block_size = 0; ssize_t read_count = 0; uint32_t stored_checksum = 0; uint32_t calculated_checksum = 0; uint16_t table_data_index = 0; uint16_t table_data_size = 0; uint8_t allocation_table_entry = 0; uint8_t allocation_table_type = 0; uint8_t allocation_table_type_copy = 0; uint8_t bit_index = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint64_t value_64bit = 0; uint16_t value_16bit = 0; #endif if( unallocated_block_list == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid unallocated block list.", function ); return( -1 ); } if( file_io_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid file IO handle.", function ); return( -1 ); } if( ( file_type != LIBPFF_FILE_TYPE_32BIT ) && ( file_type != LIBPFF_FILE_TYPE_64BIT ) && ( file_type != LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported file type.", function ); return( -1 ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: reading allocation table at offset: 0x%08" PRIx64 "\n", function, allocation_table_offset ); } #endif if( libbfio_handle_seek_offset( file_io_handle, allocation_table_offset, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek allocation table offset: 0x%08" PRIx64 ".", function, allocation_table_offset ); goto on_error; } if( file_type == LIBPFF_FILE_TYPE_32BIT ) { read_size = sizeof( pff_allocation_table_32bit_t ); table_data_size = 496; } else if( file_type == LIBPFF_FILE_TYPE_64BIT ) { read_size = sizeof( pff_allocation_table_64bit_t ); table_data_size = 496; } else if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { read_size = sizeof( pff_allocation_table_64bit_4k_page_t ); table_data_size = 4072; } allocation_table_data = (uint8_t *) memory_allocate( sizeof( uint8_t ) * read_size ); if( allocation_table_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create alloction table data.", function ); goto on_error; } read_count = libbfio_handle_read_buffer( file_io_handle, allocation_table_data, read_size, error ); if( read_count != (ssize_t) read_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read allocation table.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: allocation table:\n", function ); libcnotify_print_data( allocation_table_data, read_size, LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); } #endif if( file_type == LIBPFF_FILE_TYPE_32BIT ) { table_data = ( (pff_allocation_table_32bit_t *) allocation_table_data )->data; allocation_table_type = ( (pff_allocation_table_32bit_t *) allocation_table_data )->type; allocation_table_type_copy = ( (pff_allocation_table_32bit_t *) allocation_table_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_allocation_table_32bit_t *) allocation_table_data )->back_pointer, back_pointer_offset ); byte_stream_copy_to_uint32_little_endian( ( (pff_allocation_table_32bit_t *) allocation_table_data )->checksum, stored_checksum ); } else if( file_type == LIBPFF_FILE_TYPE_64BIT ) { table_data = ( (pff_allocation_table_64bit_t *) allocation_table_data )->data; allocation_table_type = ( (pff_allocation_table_64bit_t *) allocation_table_data )->type; allocation_table_type_copy = ( (pff_allocation_table_64bit_t *) allocation_table_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_allocation_table_64bit_t *) allocation_table_data )->checksum, stored_checksum ); byte_stream_copy_to_uint64_little_endian( ( (pff_allocation_table_64bit_t *) allocation_table_data )->back_pointer, back_pointer_offset ); } else if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { table_data = ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->data; allocation_table_type = ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->type; allocation_table_type_copy = ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->type_copy; byte_stream_copy_to_uint32_little_endian( ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->checksum, stored_checksum ); byte_stream_copy_to_uint64_little_endian( ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->back_pointer, back_pointer_offset ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: type\t\t: 0x%02" PRIx8 "\n", function, allocation_table_type ); libcnotify_printf( "%s: type copy\t\t: 0x%02" PRIx8 "\n", function, allocation_table_type_copy ); if( file_type == LIBPFF_FILE_TYPE_32BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_allocation_table_32bit_t *) allocation_table_data )->signature, value_16bit ); libcnotify_printf( "%s: signature\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: back pointer\t: %" PRIu64 "\n", function, back_pointer_offset ); libcnotify_printf( "%s: checksum\t\t: 0x%" PRIx32 "\n", function, stored_checksum ); } else if( ( file_type == LIBPFF_FILE_TYPE_64BIT ) || ( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) ) { if( file_type == LIBPFF_FILE_TYPE_64BIT ) { byte_stream_copy_to_uint16_little_endian( ( (pff_allocation_table_64bit_t *) allocation_table_data )->signature, value_16bit ); } else { byte_stream_copy_to_uint16_little_endian( ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->signature, value_16bit ); } libcnotify_printf( "%s: signature\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: checksum\t\t: 0x%" PRIx32 "\n", function, stored_checksum ); libcnotify_printf( "%s: back pointer\t: %" PRIu64 "\n", function, back_pointer_offset ); if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { byte_stream_copy_to_uint64_little_endian( ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->unknown1, value_64bit ); libcnotify_printf( "%s: unknown1\t\t: 0x%08" PRIx64 "\n", function, value_64bit ); } } libcnotify_printf( "\n" ); } #endif if( libfmapi_checksum_calculate_weak_crc32( &calculated_checksum, table_data, (size_t) table_data_size, 0, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to calculate weak CRC-32.", function ); goto on_error; } if( stored_checksum != calculated_checksum ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_INPUT, LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH, "%s: mismatch in checksum ( %" PRIu32 " != %" PRIu32 " ).", function, stored_checksum, calculated_checksum ); /* TODO implement error tollerance */ goto on_error; } if( allocation_table_type != allocation_table_type_copy ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_INPUT, LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH, "%s: mismatch in allocation table type ( 0x%02" PRIx8 " != 0x%02" PRIx8 " ).", function, allocation_table_type, allocation_table_type_copy ); /* TODO implement error tollerance */ goto on_error; } if( ( allocation_table_type != LIBPFF_ALLOCATION_TABLE_TYPE_DATA ) && ( allocation_table_type != LIBPFF_ALLOCATION_TABLE_TYPE_PAGE ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported allocation table type: 0x%08" PRIx32 "", function, allocation_table_type ); /* TODO implement error tollerance */ goto on_error; } if( allocation_table_type == LIBPFF_ALLOCATION_TABLE_TYPE_PAGE ) { /* The page type allocation has not yet been seen i.c.w. 4k pages */ if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported file type.", function ); goto on_error; } allocation_block_size = 512; back_pointer_offset -= 0x200; } else if( allocation_table_type == LIBPFF_ALLOCATION_TABLE_TYPE_DATA ) { allocation_block_size = 64; } for( table_data_index = 0; table_data_index < table_data_size; table_data_index++ ) { allocation_table_entry = table_data[ table_data_index ]; for( bit_index = 0; bit_index < 8; bit_index++ ) { if( ( allocation_table_entry & 0x80 ) == 0 ) { if( unallocated_size == 0 ) { unallocated_offset = back_pointer_offset; } unallocated_size += allocation_block_size; } else if( unallocated_size > 0 ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: unallocated block: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ")\n", function, unallocated_offset, unallocated_offset + unallocated_size, unallocated_size ); } #endif if( libcdata_range_list_insert_range( unallocated_block_list, unallocated_offset, unallocated_size, NULL, NULL, NULL, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append unallocated block to list.", function ); goto on_error; } unallocated_size = 0; } allocation_table_entry <<= 1; back_pointer_offset += allocation_block_size; } } if( unallocated_size > 0 ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: unallocated block: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ")\n", function, unallocated_offset, unallocated_offset + unallocated_size, unallocated_size ); } #endif if( libcdata_range_list_insert_range( unallocated_block_list, unallocated_offset, unallocated_size, NULL, NULL, NULL, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append unallocated block to list.", function ); goto on_error; } unallocated_size = 0; } memory_free( allocation_table_data ); return( 1 ); on_error: if( allocation_table_data != NULL ) { memory_free( allocation_table_data ); } return( -1 ); }