/* Reads the space tree page * Returns 1 if successful or -1 on error */ int libesedb_page_tree_read_space_tree_page( libesedb_page_tree_t *page_tree, libbfio_handle_t *file_io_handle, uint32_t page_number, libcerror_error_t **error ) { libesedb_page_t *page = NULL; libesedb_page_value_t *page_value = NULL; libesedb_space_tree_value_t *space_tree_value = NULL; static char *function = "libesedb_page_tree_read_space_tree_page"; uint32_t required_flags = 0; uint32_t supported_flags = 0; uint32_t total_number_of_pages = 0; uint16_t number_of_page_values = 0; uint16_t page_value_index = 0; if( page_tree == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid page tree.", function ); return( -1 ); } if( libfdata_vector_get_element_value_by_index( page_tree->pages_vector, (intptr_t *) file_io_handle, (libfdata_cache_t *) page_tree->pages_cache, (int) page_number - 1, (intptr_t **) &page, 0, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve page: %" PRIu32 ".", function, page_number ); goto on_error; } if( page == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing page.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { if( page_tree->object_identifier != page->header->father_data_page_object_identifier ) { libcnotify_printf( "%s: mismatch in father data page object identifier (tree: %" PRIu32 " != page: %" PRIu32 ").\n", function, page_tree->object_identifier, page->header->father_data_page_object_identifier ); } } #endif required_flags = LIBESEDB_PAGE_FLAG_IS_ROOT | LIBESEDB_PAGE_FLAG_IS_SPACE_TREE; if( ( page->header->flags & required_flags ) != required_flags ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing required page flags: 0x%08" PRIx32 ".", function, page->header->flags ); goto on_error; } if( ( page->header->flags & LIBESEDB_PAGE_FLAG_IS_EMPTY ) != 0 ) { return( 1 ); } supported_flags = required_flags | LIBESEDB_PAGE_FLAG_IS_LEAF | LIBESEDB_PAGE_FLAG_IS_PARENT | LIBESEDB_PAGE_FLAG_IS_INDEX | LIBESEDB_PAGE_FLAG_IS_LONG_VALUE | LIBESEDB_PAGE_FLAG_0x0400 | LIBESEDB_PAGE_FLAG_0x0800 | LIBESEDB_PAGE_FLAG_IS_NEW_RECORD_FORMAT | LIBESEDB_PAGE_FLAG_IS_SCRUBBED | LIBESEDB_PAGE_FLAG_0x8000 | LIBESEDB_PAGE_FLAG_0x10000; if( ( page->header->flags & ~supported_flags ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported page flags: 0x%08" PRIx32 ".", function, page->header->flags ); goto on_error; } if( page->header->previous_page_number != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported previous page number: %" PRIu32 ".", function, page->header->previous_page_number ); goto on_error; } if( page->header->next_page_number != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported next page number: %" PRIu32 ".", function, page->header->next_page_number ); goto on_error; } if( libesedb_page_get_number_of_values( page, &number_of_page_values, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve number of page values.", function ); goto on_error; } if( number_of_page_values == 0 ) { return( 1 ); } if( libesedb_page_get_value( page, page_value_index, &page_value, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve page value: %" PRIu16 ".", function, page_value_index ); goto on_error; } if( page_value == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid page value.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: page value: %03" PRIu16 " data:\n", function, page_value_index ); libcnotify_print_data( page_value->data, (size_t) page_value->size, LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); libcnotify_printf( "%s: page value: %03" PRIu16 " page tag flags\t\t: 0x%02" PRIx8 "", function, page_value_index, page_value->flags ); libesedb_debug_print_page_tag_flags( page_value->flags ); libcnotify_printf( "\n" ); } #endif if( ( page->header->flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) != 0 ) { if( page_value->size != 16 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported header size.", function ); goto on_error; } /* TODO handle the space tree page header */ } for( page_value_index = 1; page_value_index < number_of_page_values; page_value_index++ ) { if( libesedb_page_get_value( page, page_value_index, &page_value, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve page value: %" PRIu16 ".", function, page_value_index ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: page value: %03" PRIu16 " data:\n", function, page_value_index ); libcnotify_print_data( page_value->data, (size_t) page_value->size, LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); libcnotify_printf( "%s: page value: %03" PRIu16 " page tag flags\t\t: 0x%02" PRIx8 "", function, page_value_index, page_value->flags ); libesedb_debug_print_page_tag_flags( page_value->flags ); libcnotify_printf( "\n" ); } #endif if( ( page->header->flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) != 0 ) { if( ( page_value->flags & 0x05 ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported page value flags: 0x%02" PRIx8 ".", function, page_value->flags ); goto on_error; } if( libesedb_space_tree_value_initialize( &space_tree_value, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create space tree value.", function ); goto on_error; } if( libesedb_space_tree_value_read_data( space_tree_value, page_value->data, (size_t) page_value->size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read space tree value: %" PRIu16 ".", function, page_value_index ); goto on_error; } if( ( page_value->flags & LIBESEDB_PAGE_TAG_FLAG_IS_DEFUNCT ) == 0 ) { total_number_of_pages += space_tree_value->number_of_pages; } if( libesedb_space_tree_value_free( &space_tree_value, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to free space tree value.", function ); goto on_error; } } else if( ( page->header->flags & LIBESEDB_PAGE_FLAG_IS_PARENT ) != 0 ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: data:\n", function ); libcnotify_print_data( page_value->data, (size_t) page_value->size, 0 ); } #endif #ifdef TODO /* TODO handle parent space tree pages */ if( libesedb_page_tree_read_space_tree_page( page_tree, file_io_handle, space_tree_page_number, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read space tree page: %" PRIu32 ".", function, space_tree_page_number ); goto on_error; } #endif } } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: total number of pages\t\t\t: %" PRIu32 "\n", function, total_number_of_pages ); libcnotify_printf( "\n" ); } #endif return( 1 ); on_error: if( space_tree_value != NULL ) { libesedb_space_tree_value_free( &space_tree_value, NULL ); } return( -1 ); }
/* Reads a chunk * Callback function for the chunk vector * Returns 1 if successful or -1 on error */ int libevtx_chunks_table_read_record( intptr_t *io_handle, libbfio_handle_t *file_io_handle, libfdata_list_element_t *list_element, libfdata_cache_t *cache, int data_range_file_index LIBEVTX_ATTRIBUTE_UNUSED, off64_t data_range_offset, size64_t data_range_size, uint32_t data_range_flags LIBEVTX_ATTRIBUTE_UNUSED, uint8_t read_flags LIBEVTX_ATTRIBUTE_UNUSED, libcerror_error_t **error ) { libevtx_chunk_t *chunk = NULL; libevtx_chunks_table_t *chunks_table = NULL; libevtx_record_values_t *chunk_record_values = NULL; libevtx_record_values_t *record_values = NULL; static char *function = "libevtx_io_handle_read_chunk"; size_t calculated_chunk_data_offset = 0; size_t chunk_data_offset = 0; uint16_t number_of_records = 0; uint16_t record_index = 0; LIBEVTX_UNREFERENCED_PARAMETER( data_range_file_index ); LIBEVTX_UNREFERENCED_PARAMETER( data_range_flags ); LIBEVTX_UNREFERENCED_PARAMETER( read_flags ); if( io_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid IO handle.", function ); return( -1 ); } chunks_table = (libevtx_chunks_table_t *) io_handle; /* The chunk index is stored in the data range size */ if( data_range_size > (uint64_t) UINT16_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid data range size value out of bounds.", function ); goto on_error; } if( libfdata_vector_get_element_value_by_index( chunks_table->chunks_vector, (intptr_t *) file_io_handle, (libfdata_cache_t *) chunks_table->chunks_cache, (uint16_t) data_range_size, (intptr_t **) &chunk, 0, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve chunk: %" PRIu64 ".", function, data_range_size ); goto on_error; } if( chunk == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing chunk: %" PRIu64 ".", function, data_range_size ); goto on_error; } if( ( data_range_offset < chunk->file_offset ) || ( data_range_offset >= (off64_t) ( chunk->file_offset + chunk->data_size ) ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid chunk file offset value out of bounds.", function ); goto on_error; } calculated_chunk_data_offset = (size_t) ( data_range_offset - chunk->file_offset ); if( libevtx_chunk_get_number_of_records( chunk, &number_of_records, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve number of records from chunk.", function ); goto on_error; } /* TODO optimize determining the corresponding record */ for( record_index = 0; record_index < number_of_records; record_index++ ) { if( libevtx_chunk_get_record( chunk, record_index, &chunk_record_values, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve record: %" PRIu16 " from chunk.", function, record_index ); goto on_error; } if( chunk_record_values == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing record: %" PRIu16 ".", function, record_index ); goto on_error; } chunk_data_offset = chunk_record_values->chunk_data_offset; if( calculated_chunk_data_offset == chunk_data_offset ) { break; } } /* TODO allow to control look up in normal vs recovered */ if( calculated_chunk_data_offset != chunk_data_offset ) { if( libevtx_chunk_get_number_of_recovered_records( chunk, &number_of_records, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve number of recovered records from chunk.", function ); goto on_error; } for( record_index = 0; record_index < number_of_records; record_index++ ) { if( libevtx_chunk_get_recovered_record( chunk, record_index, &chunk_record_values, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve recovered record: %" PRIu16 " from chunk.", function, record_index ); goto on_error; } if( chunk_record_values == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing recovered record: %" PRIu16 ".", function, record_index ); goto on_error; } chunk_data_offset = chunk_record_values->chunk_data_offset; if( calculated_chunk_data_offset == chunk_data_offset ) { break; } } } if( calculated_chunk_data_offset != chunk_data_offset ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: no record found at offset: %" PRIi64 ".", function, data_range_offset ); goto on_error; } /* The record values are managed by the chunk and freed after usage * A copy is created to make sure that the records values that are passed * to the records list can be managed by the list */ if( libevtx_record_values_clone( &record_values, chunk_record_values, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create record values.", function ); goto on_error; } if( libevtx_record_values_read_xml_document( record_values, chunks_table->io_handle, chunk->data, chunk->data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read record values XML document.", function ); goto on_error; } if( libfdata_list_element_set_element_value( list_element, (intptr_t *) file_io_handle, cache, (intptr_t *) record_values, (int (*)(intptr_t **, libcerror_error_t **)) &libevtx_record_values_free, LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to set record values as element value.", function ); goto on_error; } return( 1 ); on_error: if( record_values != NULL ) { libevtx_record_values_free( &record_values, NULL ); } return( -1 ); }
/* Reads the B-tree file * Returns 1 if successful or -1 on error */ int libfshfs_btree_file_read( libfshfs_btree_file_t *btree_file, libfshfs_io_handle_t *io_handle, libbfio_handle_t *file_io_handle, libfshfs_fork_descriptor_t *fork_descriptor, libcerror_error_t **error ) { libfcache_cache_t *btree_nodes_cache = NULL; libfdata_vector_t *btree_nodes_vector = NULL; libfshfs_allocation_block_t *allocation_block = NULL; fshfs_btree_node_descriptor_t *btree_node_descriptor = NULL; static char *function = "libfshfs_btree_file_read"; size_t btree_node_data_offset = 0; uint32_t next_node_number = 0; uint32_t previous_node_number = 0; uint16_t number_of_records = 0; uint16_t record_index = 0; uint16_t record_offset = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint16_t value_16bit = 0; size_t btree_node_record_offsets_data_size = 0; #endif if( btree_file == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid B-tree file.", function ); return( -1 ); } if( libfshfs_allocation_block_vector_initialize( &btree_nodes_vector, io_handle, 512, fork_descriptor, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create B-tree nodes vector.", function ); goto on_error; } /* TODO add max number of cache definition */ if( libfcache_cache_initialize( &btree_nodes_cache, 4, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create B-tree nodes cache.", function ); goto on_error; } if( libfdata_vector_get_element_value_by_index( btree_nodes_vector, (intptr_t *) file_io_handle, btree_nodes_cache, 0, (intptr_t **) &allocation_block, 0, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve B-tree node: 0.", function ); goto on_error; } if( allocation_block == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid allocation block: 0.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: B-tree node data:\n", function ); libcnotify_print_data( (uint8_t *) allocation_block->data, 512, LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); } #endif if( libfshfs_btree_file_read_node_descriptor( allocation_block->data, allocation_block->data_size, &number_of_records, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read B-tree node descriptor.", function ); goto on_error; } /* TODO add bounds checks */ #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { btree_node_record_offsets_data_size = ( number_of_records + 1 ) * 2; libcnotify_printf( "%s: B-tree node record offsets data:\n", function ); libcnotify_print_data( (uint8_t *) &( allocation_block->data[ 512 - btree_node_record_offsets_data_size ] ), btree_node_record_offsets_data_size, LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); } #endif btree_node_data_offset = 510; for( record_index = 0; record_index < number_of_records; record_index++ ) { byte_stream_copy_to_uint16_big_endian( &( ( allocation_block->data )[ btree_node_data_offset ] ), record_offset ); btree_node_data_offset -= 2; #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: record offset: %" PRIu16 "\t\t\t\t: 0x%04" PRIx16 "\n", function, record_index, record_offset ); } #endif } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { byte_stream_copy_to_uint16_big_endian( &( ( allocation_block->data )[ btree_node_data_offset ] ), value_16bit ); libcnotify_printf( "%s: free space offset\t\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); } #endif if( libfdata_vector_free( &btree_nodes_vector, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to free B-tree nodes vector.", function ); goto on_error; } if( libfcache_cache_free( &btree_nodes_cache, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to free B-tree nodes cache.", function ); goto on_error; } return( 1 ); on_error: if( btree_nodes_cache != NULL ) { libfcache_cache_free( &btree_nodes_cache, NULL ); } if( btree_nodes_vector != NULL ) { libfdata_vector_free( &btree_nodes_vector, NULL ); } return( -1 ); }