/* Retrieves the chunk data of a chunk at a specific offset * Adds a checksum error if the data is corrupted * Returns 1 if successful or -1 on error */ int libewf_chunk_table_get_chunk_data_by_offset( libewf_chunk_table_t *chunk_table, uint64_t chunk_index, libewf_io_handle_t *io_handle, libbfio_pool_t *file_io_pool, libewf_media_values_t *media_values, libewf_segment_table_t *segment_table, libfdata_range_list_t *delta_chunks_range_list, libfcache_cache_t *chunk_groups_cache, libfcache_cache_t *chunks_cache, off64_t offset, libewf_chunk_data_t **chunk_data, off64_t *chunk_data_offset, libcerror_error_t **error ) { libewf_segment_file_t *segment_file = NULL; libfdata_list_t *chunks_list = NULL; static char *function = "libewf_chunk_table_get_chunk_data_by_offset"; off64_t chunk_offset = 0; off64_t chunk_group_data_offset = 0; off64_t segment_file_data_offset = 0; size_t chunk_data_size = 0; uint64_t start_sector = 0; uint64_t number_of_sectors = 0; uint32_t segment_number = 0; int chunk_groups_list_index = 0; int chunks_list_index = 0; int result = 0; if( chunk_table == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid chunk table.", 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( media_values == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid media values.", function ); return( -1 ); } if( chunk_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid chunk data.", function ); return( -1 ); } if( chunk_data_offset == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid chunk data offset.", function ); return( -1 ); } if( delta_chunks_range_list != NULL ) { result = libfdata_range_list_get_element_value_at_offset( delta_chunks_range_list, (intptr_t *) file_io_pool, chunks_cache, offset, chunk_data_offset, (intptr_t **) chunk_data, 0, error ); if( result == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve chunk: %" PRIu64 " from delta chunks range list.", function, chunk_index ); return( -1 ); } } if( result == 0 ) { result = libewf_chunk_table_get_segment_file_chunk_group_by_offset( chunk_table, file_io_pool, segment_table, chunk_groups_cache, offset, &segment_number, &segment_file_data_offset, &segment_file, &chunk_groups_list_index, &chunk_group_data_offset, &chunks_list, error ); if( result == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve segment file chunk group at offset: %" PRIi64 ".", function, offset ); return( -1 ); } if( result != 0 ) { if( chunks_list == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing chunks list: %d.", function, chunk_groups_list_index ); return( -1 ); } result = libfdata_list_get_element_value_at_offset( chunks_list, (intptr_t *) file_io_pool, chunks_cache, chunk_group_data_offset, &chunks_list_index, chunk_data_offset, (intptr_t **) chunk_data, 0, error ); if( result == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve chunk: %" PRIu64 " data from chunk group: %d in segment file: %" PRIu32 " at offset: %" PRIi64 ".", function, chunk_index, chunk_groups_list_index, segment_number, segment_file_data_offset ); return( -1 ); } } } if( result != 0 ) { if( *chunk_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing chunk: %" PRIu64 " data.", function, chunk_index ); return( -1 ); } if( libewf_chunk_data_unpack( *chunk_data, media_values->chunk_size, io_handle->compression_method, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GENERIC, "%s: unable to unpack chunk: %" PRIu64 " data.", function, chunk_index ); return( -1 ); } if( ( ( *chunk_data )->range_flags & LIBEWF_RANGE_FLAG_IS_CORRUPTED ) != 0 ) { if( io_handle->zero_on_error != 0 ) { if( memory_set( ( *chunk_data )->data, 0, ( *chunk_data )->data_size ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to zero chunk: %" PRIu64 " data.", function, chunk_index ); return( -1 ); } } chunk_offset = offset - *chunk_data_offset; } } else { chunk_offset = (off64_t) chunk_index * media_values->chunk_size; chunk_data_size = media_values->chunk_size; if( (size64_t) ( chunk_offset + chunk_data_size ) > media_values->media_size ) { chunk_data_size = (size_t) ( media_values->media_size - chunk_offset ); } if( libewf_chunk_data_initialize_clear_data( chunk_data, chunk_data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create chunk: %" PRIu64 " data.", function, chunk_index ); return( -1 ); } if( *chunk_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: missing chunk data: %" PRIu64 ".", function, chunk_index ); return( -1 ); } ( *chunk_data )->data_size = chunk_data_size; ( *chunk_data )->range_flags |= LIBEWF_RANGE_FLAG_IS_CORRUPTED; } if( ( ( *chunk_data )->range_flags & LIBEWF_RANGE_FLAG_IS_CORRUPTED ) != 0 ) { /* Add checksum error */ start_sector = chunk_offset / media_values->bytes_per_sector; number_of_sectors = media_values->sectors_per_chunk; if( ( start_sector + number_of_sectors ) > (uint64_t) media_values->number_of_sectors ) { number_of_sectors = (uint64_t) media_values->number_of_sectors - start_sector; } if( libcdata_range_list_insert_range( chunk_table->checksum_errors, start_sector, number_of_sectors, NULL, NULL, NULL, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to insert checksum error in range list.", function ); return( -1 ); } } return( 1 ); }
/* Reads a buffer from the data chunk * It applies decompression if necessary and validates the chunk checksum * This function should be used after libewf_handle_read_data_chunk * Returns the number of bytes read, 0 when no longer data can be read or -1 on error */ ssize_t libewf_data_chunk_read_buffer( libewf_data_chunk_t *data_chunk, void *buffer, size_t buffer_size, libcerror_error_t **error ) { libewf_internal_data_chunk_t *internal_data_chunk = NULL; static char *function = "libewf_data_chunk_read_buffer"; ssize_t read_count = 0; if( data_chunk == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid data chunk.", function ); return( -1 ); } internal_data_chunk = (libewf_internal_data_chunk_t *) data_chunk; if( internal_data_chunk->chunk_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid data chunk - missing chunk data.", function ); return( -1 ); } #if defined( HAVE_LIBEWF_MULTI_THREAD_SUPPORT ) if( libcthreads_read_write_lock_grab_for_write( internal_data_chunk->read_write_lock, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to grab read/write lock for writing.", function ); return( -1 ); } #endif if( ( internal_data_chunk->chunk_data->range_flags & LIBEWF_RANGE_FLAG_IS_PACKED ) != 0 ) { /* TODO optimize to unpack directly to buffer */ if( libewf_chunk_data_unpack( internal_data_chunk->chunk_data, internal_data_chunk->io_handle, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GENERIC, "%s: unable to unpack chunk: %" PRIu64 " data.", function, internal_data_chunk->chunk_index ); goto on_error; } } read_count = libewf_chunk_data_read_buffer( internal_data_chunk->chunk_data, buffer, buffer_size, error ); if( read_count < 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read chunk: %" PRIu64 " data.", function, internal_data_chunk->chunk_index ); goto on_error; } #if defined( HAVE_LIBEWF_MULTI_THREAD_SUPPORT ) if( libcthreads_read_write_lock_release_for_write( internal_data_chunk->read_write_lock, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to release read/write lock for writing.", function ); return( -1 ); } #endif return( read_count ); on_error: #if defined( HAVE_LIBEWF_MULTI_THREAD_SUPPORT ) libcthreads_read_write_lock_release_for_write( internal_data_chunk->read_write_lock, NULL ); #endif return( -1 ); }