/* Determines the uncompressed data size from the LZFu header in the compressed data * Return 1 on success or -1 on error */ int lzfu_get_uncompressed_data_size( uint8_t *compressed_data, size_t compressed_data_size, size_t *uncompressed_data_size, libcerror_error_t **error ) { lzfu_header_t lzfu_header; uint8_t *lzfu_data = 0; static char *function = "lzfu_get_uncompressed_data_size"; uint8_t lz_buffer[ 4096 ]; uint8_t *lzfu_reference_data = 0; size_t compressed_data_iterator = 0; size_t uncompressed_data_iterator = 0; uint16_t lz_buffer_iterator = 0; uint16_t reference_offset = 0; uint16_t reference_size = 0; uint16_t reference_iterator = 0; uint8_t flag_byte_bit_mask = 0; uint8_t flag_byte = 0; if( compressed_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid compressed data.", function ); return( -1 ); } if( compressed_data_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid compressed data size value exceeds maximum.", function ); return( -1 ); } if( uncompressed_data_size == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid uncompressed data size.", function ); return( -1 ); } lzfu_data = compressed_data; byte_stream_copy_to_uint32_little_endian( lzfu_data, lzfu_header.compressed_data_size ); lzfu_data += 4; byte_stream_copy_to_uint32_little_endian( lzfu_data, lzfu_header.uncompressed_data_size ); lzfu_data += 4; byte_stream_copy_to_uint32_little_endian( lzfu_data, lzfu_header.signature ); lzfu_data += 8; if( ( lzfu_header.signature != LZFU_SIGNATURE_COMPRESSED ) && ( lzfu_header.signature != LZFU_SIGNATURE_UNCOMPRESSED ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported compression signature: 0x%08" PRIx32 ".", function, lzfu_header.signature ); return( -1 ); } compressed_data_size -= sizeof( lzfu_header_t ); /* The compressed data size includes 12 bytes of the header */ lzfu_header.compressed_data_size -= 12; #ifdef X if( (size_t) lzfu_header.compressed_data_size != compressed_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_RANGE, "%s: mismatch in compressed data size (%" PRIu32 " != %" PRIzd ").", function, lzfu_header.compressed_data_size, compressed_data_size ); return( -1 ); } #endif if( memory_copy( lz_buffer, lzfu_rtf_dictionary, 207 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to initialize lz buffer.", function ); return( -1 ); } lz_buffer_iterator = 207; if( memory_set( &( lz_buffer[ lz_buffer_iterator ] ), 0, ( 4096 - lz_buffer_iterator ) ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear lz buffer.", function ); return( -1 ); } while( compressed_data_iterator < (size_t) lzfu_header.compressed_data_size ) { flag_byte = lzfu_data[ compressed_data_iterator++ ]; /* Check every bit in the chunk flag byte from LSB to MSB */ for( flag_byte_bit_mask = 0x01; flag_byte_bit_mask != 0x00; flag_byte_bit_mask <<= 1 ) { if( compressed_data_iterator == (size_t) lzfu_header.compressed_data_size ) { break; } /* Check if the byte value is a literal or a reference */ if( ( flag_byte & flag_byte_bit_mask ) == 0 ) { lz_buffer[ lz_buffer_iterator++ ] = lzfu_data[ compressed_data_iterator ]; uncompressed_data_iterator++; compressed_data_iterator++; /* Make sure the lz buffer iterator wraps around */ lz_buffer_iterator %= 4096; lz_buffer[ lz_buffer_iterator ] = 0; } else { lzfu_reference_data = &( lzfu_data[ compressed_data_iterator ] ); compressed_data_iterator += 2; byte_stream_copy_to_uint16_big_endian( lzfu_reference_data, reference_offset ); reference_size = ( reference_offset & 0x000f ) + 2; reference_offset >>= 4; for( reference_iterator = 0; reference_iterator < reference_size; reference_iterator++ ) { lz_buffer[ lz_buffer_iterator++ ] = lz_buffer[ reference_offset ]; uncompressed_data_iterator++; reference_offset++; /* Make sure the lz buffer iterator and reference offset wrap around */ lz_buffer_iterator %= 4096; reference_offset %= 4096; lz_buffer[ lz_buffer_iterator ] = 0; } } } } if( (size_t) ( lzfu_header.uncompressed_data_size + 2 ) != uncompressed_data_iterator ) { if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: mismatch in uncompressed data size (in header: %" PRIu32 " != required: %" PRIzd ").\n", function, lzfu_header.uncompressed_data_size + 2, uncompressed_data_iterator ); } } /* Compensate for the 2 trailing zero bytes */ *uncompressed_data_size = lzfu_header.uncompressed_data_size + 2; return( 1 ); }
/* Reads the property set from the property set stream * Returns 1 if successful or -1 on error */ int libolecf_property_set_read( libolecf_property_set_t *property_set, libolecf_io_handle_t *io_handle, libolecf_item_t *property_set_stream, libcerror_error_t **error ) { olecf_property_set_header_t property_set_header; libolecf_internal_property_set_t *internal_property_set = NULL; libolecf_property_section_t *property_section = NULL; static char *function = "libolecf_property_set_read"; off64_t section_list_entry_offset = 0; ssize_t read_count = 0; uint32_t section_header_offset = 0; uint16_t number_of_sections = 0; uint16_t section_index = 0; int sections_entry = 0; #if defined( HAVE_DEBUG_OUTPUT ) libcstring_system_character_t guid_string[ 48 ]; libfguid_identifier_t *guid = NULL; int result = 0; #endif if( property_set == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid property set.", function ); return( -1 ); } internal_property_set = (libolecf_internal_property_set_t *) property_set; if( libolecf_stream_seek_offset( property_set_stream, 0, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek property set header offset: 0.", function ); goto on_error; } read_count = libolecf_stream_read_buffer( property_set_stream, (uint8_t *) &property_set_header, sizeof( olecf_property_set_header_t ), error ); if( read_count != (ssize_t) sizeof( olecf_property_set_header_t ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read property set header.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: property set header:\n", function ); libcnotify_print_data( (uint8_t *) &property_set_header, sizeof( olecf_property_set_header_t ), 0 ); } #endif if( ( property_set_header.byte_order[ 0 ] == 0xfe ) && ( property_set_header.byte_order[ 1 ] == 0xff ) ) { internal_property_set->byte_order = LIBOLECF_ENDIAN_LITTLE; } else if( ( property_set_header.byte_order[ 0 ] == 0xff ) && ( property_set_header.byte_order[ 1 ] == 0xfe ) ) { internal_property_set->byte_order = LIBOLECF_ENDIAN_BIG; } else { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported byte order: 0x%02" PRIx8 " 0x%02" PRIx8 ".", function, property_set_header.byte_order[ 0 ], property_set_header.byte_order[ 1 ] ); goto on_error; } if( internal_property_set->byte_order == LIBOLECF_ENDIAN_LITTLE ) { byte_stream_copy_to_uint16_little_endian( property_set_header.format, internal_property_set->format ); byte_stream_copy_to_uint32_little_endian( property_set_header.system_version, internal_property_set->system_version ); byte_stream_copy_to_uint16_little_endian( property_set_header.number_of_sections, number_of_sections ); } else if( internal_property_set->byte_order == LIBOLECF_ENDIAN_BIG ) { byte_stream_copy_to_uint16_big_endian( property_set_header.format, internal_property_set->format ); byte_stream_copy_to_uint32_big_endian( property_set_header.system_version, internal_property_set->system_version ); byte_stream_copy_to_uint16_big_endian( property_set_header.number_of_sections, number_of_sections ); } if( memory_copy( internal_property_set->class_identifier, property_set_header.class_identifier, 16 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy class identifier.", function ); goto on_error; } /* TODO make sure the class identifier is set in little endian */ #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: property set header byte order\t\t: 0x%02" PRIx8 " 0x%02" PRIx8 "\n", function, property_set_header.byte_order[ 0 ], property_set_header.byte_order[ 1 ] ); libcnotify_printf( "%s: property set header format\t\t\t: %" PRIu16 "\n", function, internal_property_set->format ); libcnotify_printf( "%s: property set header system version\t\t: 0x%08" PRIx32 "\n", function, internal_property_set->system_version ); if( libfguid_identifier_initialize( &guid, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create GUID.", function ); goto on_error; } if( libfguid_identifier_copy_from_byte_stream( guid, internal_property_set->class_identifier, 16, internal_property_set->byte_order, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_COPY_FAILED, "%s: unable to copy byte stream to GUID.", function ); goto on_error; } #if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER ) result = libfguid_identifier_copy_to_utf16_string( guid, (uint16_t *) guid_string, 48, LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE, error ); #else result = libfguid_identifier_copy_to_utf8_string( guid, (uint8_t *) guid_string, 48, LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE, error ); #endif if( result != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_COPY_FAILED, "%s: unable to copy GUID to string.", function ); goto on_error; } libcnotify_printf( "%s: property set header class identifier\t: %" PRIs_LIBCSTRING_SYSTEM " (%s : %s)\n", function, guid_string, libfwps_format_class_identifier_get_identifier( internal_property_set->class_identifier ), libfwps_format_class_identifier_get_description( internal_property_set->class_identifier ) ); if( libfguid_identifier_free( &guid, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to free GUID.", function ); goto on_error; } libcnotify_printf( "%s: property set header number of sections\t: %" PRIu16 "\n", function, number_of_sections ); libcnotify_printf( "\n" ); } #endif section_list_entry_offset = sizeof( olecf_property_set_header_t ); for( section_index = 0; section_index < (int) number_of_sections; section_index++ ) { if( libolecf_property_section_initialize( &property_section, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create property section: %d.", function, section_index ); goto on_error; } if( libolecf_stream_seek_offset( property_set_stream, section_list_entry_offset, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek property section list entry: %d offset: %" PRIi64 ".", function, section_index, section_list_entry_offset ); goto on_error; } if( libolecf_property_section_read_list_entry( (libolecf_internal_property_section_t *) property_section, property_set_stream, internal_property_set->byte_order, §ion_header_offset, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read property section list entry: %d.", function, section_index ); goto on_error; } if( libolecf_stream_get_offset( property_set_stream, §ion_list_entry_offset, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to retrieve property section list entry offset.", function ); goto on_error; } if( libolecf_property_section_read( (libolecf_internal_property_section_t *) property_section, io_handle, property_set_stream, section_header_offset, internal_property_set->byte_order, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read property section: %d at offset: %" PRIu32 ".", function, section_index, section_header_offset ); goto on_error; } if( libcdata_array_append_entry( internal_property_set->sections, §ions_entry, (intptr_t *) property_section, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append property section: %d to sections array.", function, section_index ); goto on_error; } property_section = NULL; } return( 1 ); on_error: #if defined( HAVE_DEBUG_OUTPUT ) if( guid != NULL ) { libfguid_identifier_free( &guid, NULL ); } #endif if( property_section != NULL ) { libolecf_property_section_free( &property_section, NULL ); } return( -1 ); }
/* Sends a SCSI read track information to the file descriptor * Returns the number of bytes read if successful or -1 on error */ ssize_t libsmdev_scsi_read_track_information( int file_descriptor, uint32_t offset, uint8_t *response, size_t response_size, liberror_error_t **error ) { libsmdev_scsi_read_track_information_cdb_t command; uint8_t sense[ LIBSMDEV_SCSI_SENSE_SIZE ]; static char *function = "libsmdev_scsi_read_track_information"; ssize_t response_count = 0; if( file_descriptor == -1 ) { liberror_error_set( error, LIBERROR_ERROR_DOMAIN_ARGUMENTS, LIBERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid file descriptor.", function ); return( -1 ); } if( response == NULL ) { liberror_error_set( error, LIBERROR_ERROR_DOMAIN_ARGUMENTS, LIBERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid response.", function ); return( -1 ); } if( response_size > (size_t) SSIZE_MAX ) { liberror_error_set( error, LIBERROR_ERROR_DOMAIN_ARGUMENTS, LIBERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid response size value exceeds maximum.", function ); return( -1 ); } if( memory_set( &command, 0, sizeof( libsmdev_scsi_read_track_information_cdb_t ) ) == NULL ) { liberror_error_set( error, LIBERROR_ERROR_DOMAIN_MEMORY, LIBERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear command.", function ); return( -1 ); } command.operation_code = LIBSMDEV_SCSI_OPERATION_CODE_READ_TRACK_INFORMATION; command.address_type = LIBSMDEV_SCSI_TRACK_INFORMATION_ADDRESS_TYPE_LBA; byte_stream_copy_from_uint32_big_endian( command.offset, offset ); byte_stream_copy_from_uint16_big_endian( command.receive_size, response_size ); if( libsmdev_scsi_command( file_descriptor, (uint8_t *) &command, sizeof( libsmdev_scsi_read_track_information_cdb_t ), response, response_size, sense, LIBSMDEV_SCSI_SENSE_SIZE, error ) != 1 ) { liberror_error_set( error, LIBERROR_ERROR_DOMAIN_IO, LIBERROR_IO_ERROR_GENERIC, "%s: SCSI READ TRACK INFORMATION command failed.", function ); return( -1 ); } byte_stream_copy_to_uint16_big_endian( response, response_count ); if( response_count > (ssize_t) response_size ) { liberror_error_set( error, LIBERROR_ERROR_DOMAIN_ARGUMENTS, LIBERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: response too small.", function ); return( -1 ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libnotify_verbose != 0 ) { libnotify_printf( "%s: response:\n", function ); libnotify_print_data( response, response_count, 0 ); } #endif return( response_count ); }
/* Decompresses data using LZFu compression * Returns 1 on success or -1 on error */ int lzfu_decompress( uint8_t *compressed_data, size_t compressed_data_size, uint8_t *uncompressed_data, size_t *uncompressed_data_size, libcerror_error_t **error ) { lzfu_header_t lzfu_header; uint8_t lz_buffer[ 4096 ]; uint8_t *lzfu_data = 0; uint8_t *lzfu_reference_data = 0; static char *function = "lzfu_decompress"; size_t compressed_data_iterator = 0; size_t uncompressed_data_iterator = 0; uint32_t calculated_crc = 0; uint16_t lz_buffer_iterator = 0; uint16_t reference_offset = 0; uint16_t reference_size = 0; uint16_t reference_iterator = 0; uint8_t flag_byte_bit_mask = 0; uint8_t flag_byte = 0; if( uncompressed_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid uncompressed data.", function ); return( -1 ); } if( uncompressed_data_size == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid uncompressed data size.", function ); return( -1 ); } if( compressed_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid compressed data.", function ); return( -1 ); } if( compressed_data_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid compressed data size value exceeds maximum.", function ); return( -1 ); } if( memory_copy( lz_buffer, lzfu_rtf_dictionary, 207 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to initialize lz buffer.", function ); return( -1 ); } lz_buffer_iterator = 207; if( memory_set( &( lz_buffer[ lz_buffer_iterator ] ), 0, ( 4096 - lz_buffer_iterator ) ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear lz buffer.", function ); return( -1 ); } lzfu_data = compressed_data; byte_stream_copy_to_uint32_little_endian( lzfu_data, lzfu_header.compressed_data_size ); lzfu_data += 4; byte_stream_copy_to_uint32_little_endian( lzfu_data, lzfu_header.uncompressed_data_size ); lzfu_data += 4; byte_stream_copy_to_uint32_little_endian( lzfu_data, lzfu_header.signature ); lzfu_data += 4; byte_stream_copy_to_uint32_little_endian( lzfu_data, lzfu_header.crc ); lzfu_data += 4; if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: lzfu header compressed data size\t: %" PRIu32 "\n", function, lzfu_header.compressed_data_size ); libcnotify_printf( "%s: lzfu header uncompressed data size\t: %" PRIu32 "\n", function, lzfu_header.uncompressed_data_size ); libcnotify_printf( "%s: lzfu header signature\t\t\t: 0x08%" PRIx32 "\n", function, lzfu_header.signature ); libcnotify_printf( "%s: lzfu header crc\t\t\t: %" PRIu32 "\n", function, lzfu_header.crc ); } if( ( lzfu_header.signature != LZFU_SIGNATURE_COMPRESSED ) && ( lzfu_header.signature != LZFU_SIGNATURE_UNCOMPRESSED ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported compression signature: 0x%08" PRIx32 ".", function, lzfu_header.signature ); return( -1 ); } compressed_data_size -= sizeof( lzfu_header_t ); /* The compressed data size includes 12 bytes of the header */ lzfu_header.compressed_data_size -= 12; #ifdef X if( lzfu_header.compressed_data_size != compressed_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_RANGE, "%s: mismatch in compressed data size (%" PRIu32 " != %" PRIzd ").", function, lzfu_header.compressed_data_size, compressed_data_size ); return( -1 ); } #endif /* Make sure the uncompressed buffer is large enough */ if( *uncompressed_data_size < lzfu_header.uncompressed_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: uncompressed data too small.", function ); *uncompressed_data_size = lzfu_header.uncompressed_data_size; return( -1 ); } if( crc32_calculate( &calculated_crc, lzfu_data, (size_t) lzfu_header.compressed_data_size, 0, 1, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to calculate weak CRC.", function ); return( -1 ); } if( lzfu_header.crc != calculated_crc ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_INPUT, LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH, "%s: mismatch in crc ( %" PRIu32 " != %" PRIu32 " ).", function, lzfu_header.crc, calculated_crc ); return( -1 ); } while( compressed_data_iterator < (size_t) lzfu_header.compressed_data_size ) { flag_byte = lzfu_data[ compressed_data_iterator++ ]; /* Check every bit in the chunk flag byte from LSB to MSB */ for( flag_byte_bit_mask = 0x01; flag_byte_bit_mask != 0x00; flag_byte_bit_mask <<= 1 ) { if( compressed_data_iterator == (size_t) lzfu_header.compressed_data_size ) { break; } /* Check if the byte value is a literal or a reference */ if( ( flag_byte & flag_byte_bit_mask ) == 0 ) { if( compressed_data_iterator >= (size_t) lzfu_header.compressed_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: missing compressed data.", function ); *uncompressed_data_size = 0; return( -1 ); } if( uncompressed_data_iterator >= *uncompressed_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: uncompressed data too small.", function ); *uncompressed_data_size = uncompressed_data_iterator; return( -1 ); } lz_buffer[ lz_buffer_iterator++ ] = lzfu_data[ compressed_data_iterator ]; uncompressed_data[ uncompressed_data_iterator++ ] = lzfu_data[ compressed_data_iterator ]; compressed_data_iterator++; /* Make sure the lz buffer iterator wraps around */ lz_buffer_iterator %= 4096; lz_buffer[ lz_buffer_iterator ] = 0; } else { if( ( compressed_data_iterator + 1 ) >= (size_t) lzfu_header.compressed_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: missing compressed data.", function ); *uncompressed_data_size = 0; return( -1 ); } lzfu_reference_data = &( lzfu_data[ compressed_data_iterator ] ); compressed_data_iterator += 2; byte_stream_copy_to_uint16_big_endian( lzfu_reference_data, reference_offset ); reference_size = ( reference_offset & 0x000f ) + 2; reference_offset >>= 4; if( ( uncompressed_data_iterator + reference_size - 1 ) >= *uncompressed_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: uncompressed data too small.", function ); *uncompressed_data_size = uncompressed_data_iterator + reference_size; return( -1 ); } for( reference_iterator = 0; reference_iterator < reference_size; reference_iterator++ ) { lz_buffer[ lz_buffer_iterator++ ] = lz_buffer[ reference_offset ]; uncompressed_data[ uncompressed_data_iterator++ ] = lz_buffer[ reference_offset ]; reference_offset++; /* Make sure the lz buffer iterator and reference offset wrap around */ lz_buffer_iterator %= 4096; reference_offset %= 4096; lz_buffer[ lz_buffer_iterator ] = 0; } } } } *uncompressed_data_size = uncompressed_data_iterator; return( 1 ); }
/* Copies a byte stream from a base16 stream * * LIBUNA_BASE16_FLAG_STRIP_WHITESPACE removes leading space and tab characters, * and trailing space, tab and end of line characters * * Returns 1 if successful or -1 on error */ int libuna_base16_stream_copy_to_byte_stream( const uint8_t *base16_stream, size_t base16_stream_size, uint8_t *byte_stream, size_t byte_stream_size, uint32_t base16_variant, uint8_t flags, libcerror_error_t **error ) { static char *function = "libuna_base16_stream_copy_to_byte_stream"; size_t base16_character_size = 0; size_t base16_stream_index = 0; size_t byte_stream_index = 0; size_t number_of_characters = 0; size_t whitespace_size = 0; uint32_t base16_character1 = 0; uint32_t base16_character2 = 0; uint8_t byte_value = 0; uint8_t character_case = 0; uint8_t character_limit = 0; uint8_t strip_mode = LIBUNA_STRIP_MODE_LEADING_WHITESPACE; if( base16_stream == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid base16 stream.", function ); return( -1 ); } if( base16_stream_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid base16 stream size value exceeds maximum.", function ); return( -1 ); } if( byte_stream == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid byte stream.", function ); return( -1 ); } if( byte_stream_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid byte stream size value exceeds maximum.", function ); return( -1 ); } switch( base16_variant & 0x000000ffUL ) { case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_NONE: character_limit = 0; break; case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_64: character_limit = 64; break; case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_76: character_limit = 76; break; default: libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported base16 variant.", function ); return( -1 ); } switch( base16_variant & 0x000f0000UL ) { case LIBUNA_BASE16_VARIANT_CASE_LOWER: character_case = LIBUNA_CASE_LOWER; break; case LIBUNA_BASE16_VARIANT_CASE_MIXED: character_case = LIBUNA_CASE_MIXED; break; case LIBUNA_BASE16_VARIANT_CASE_UPPER: character_case = LIBUNA_CASE_UPPER; break; default: libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported base16 variant.", function ); return( -1 ); } switch( base16_variant & 0xf0000000UL ) { case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM: base16_character_size = 1; break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN: case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN: base16_character_size = 2; break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN: case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN: base16_character_size = 4; break; default: libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported base16 variant.", function ); return( -1 ); } if( base16_stream_size < base16_character_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: invalid base16 stream value too small.", function ); return( -1 ); } if( ( flags & ~( LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported flags.", function ); return( -1 ); } if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) == 0 ) { strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE; } base16_stream_index = base16_stream_size - base16_character_size; whitespace_size = 0; while( base16_stream_index > base16_character_size ) { switch( base16_variant & 0xf0000000UL ) { case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM: base16_character1 = base16_stream[ base16_stream_index ]; break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN: byte_stream_copy_to_uint16_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN: byte_stream_copy_to_uint16_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN: byte_stream_copy_to_uint32_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN: byte_stream_copy_to_uint32_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; } if( ( base16_character1 & 0xffffff00UL ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: invalid base16 character at index: %" PRIzd ".", function, base16_stream_index ); return( -1 ); } base16_stream_index -= base16_character_size; if( ( base16_character1 == (uint32_t) '\n' ) || ( base16_character1 == (uint32_t) '\r' ) ) { whitespace_size += base16_character_size; } else if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) == 0 ) { break; } else if( ( base16_character1 == (uint32_t) ' ' ) || ( base16_character1 == (uint32_t) '\t' ) || ( base16_character1 == (uint32_t) '\v' ) ) { whitespace_size += base16_character_size; } else { break; } } base16_stream_size -= whitespace_size; if( base16_stream_size < base16_character_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: invalid base16 stream value too small.", function ); return( -1 ); } base16_stream_index = 0; while( base16_stream_index < base16_stream_size ) { switch( base16_variant & 0xf0000000UL ) { case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM: base16_character1 = base16_stream[ base16_stream_index ]; break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN: byte_stream_copy_to_uint16_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN: byte_stream_copy_to_uint16_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN: byte_stream_copy_to_uint32_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN: byte_stream_copy_to_uint32_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; } if( ( base16_character1 & 0xffffff00UL ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: invalid base16 character at index: %" PRIzd ".", base16_stream_index, function ); return( -1 ); } base16_stream_index += base16_character_size; if( ( base16_character1 == (uint32_t) '\n' ) || ( base16_character1 == (uint32_t) '\r' ) ) { if( ( strip_mode != LIBUNA_STRIP_MODE_NON_WHITESPACE ) && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) ) { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } else { if( ( base16_stream_index + base16_character_size ) < base16_stream_size ) { switch( base16_variant & 0xf0000000UL ) { case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM: base16_character2 = base16_stream[ base16_stream_index ]; break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN: byte_stream_copy_to_uint16_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character2 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN: byte_stream_copy_to_uint16_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character2 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN: byte_stream_copy_to_uint32_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character2 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN: byte_stream_copy_to_uint32_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character2 ); break; } if( ( base16_character2 & 0xffffff00UL ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: invalid base16 character at index: %" PRIzd ".", function, base16_stream_index ); return( -1 ); } if( ( base16_character2 == (uint32_t) '\n' ) || ( base16_character2 == (uint32_t) '\r' ) ) { base16_stream_index += base16_character_size; } } strip_mode = LIBUNA_STRIP_MODE_LEADING_WHITESPACE; } if( character_limit != 0 ) { if( number_of_characters != (size_t) character_limit ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_CONVERSION, LIBCERROR_CONVERSION_ERROR_INPUT_FAILED, "%s: number of characters in line does not match character limit.", function ); return( -1 ); } number_of_characters = 0; } } else if( ( base16_character1 == (uint32_t) ' ' ) || ( base16_character1 == (uint32_t) '\t' ) || ( base16_character1 == (uint32_t) '\v' ) ) { if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) != 0 ) { if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE ) { strip_mode = LIBUNA_STRIP_MODE_TRAILING_WHITESPACE; } if( ( strip_mode != LIBUNA_STRIP_MODE_LEADING_WHITESPACE ) && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) ) { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } } else { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } } else if( strip_mode == LIBUNA_STRIP_MODE_LEADING_WHITESPACE ) { strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE; } else if( strip_mode == LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_CONVERSION, LIBCERROR_CONVERSION_ERROR_INPUT_FAILED, "%s: invalid character in base16 stream at index: %" PRIzd ".", function, base16_stream_index - base16_character_size ); return( -1 ); } if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE ) { byte_value = 0; if( ( base16_character1 >= (uint32_t) 'A' ) && ( base16_character1 <= (uint32_t) 'F' ) ) { if( ( character_case != LIBUNA_CASE_MIXED ) && ( character_case != LIBUNA_CASE_UPPER ) ) { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } byte_value = (uint8_t) ( base16_character1 - (uint32_t) 'A' + 10 ); } else if( ( base16_character1 >= (uint32_t) 'a' ) && ( base16_character1 <= (uint32_t) 'f' ) ) { if( ( character_case != LIBUNA_CASE_MIXED ) && ( character_case != LIBUNA_CASE_LOWER ) ) { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } byte_value = (uint8_t) ( base16_character1 - (uint32_t) 'a' + 10 ); } else if( ( base16_character1 >= (uint32_t) '0' ) && ( base16_character1 <= (uint32_t) '9' ) ) { byte_value = (uint8_t) ( base16_character1 - (uint32_t) '0' ); } else { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: invalid base16 character stream at index: %" PRIzd ".", function, base16_stream_index - base16_character_size ); return( -1 ); } byte_value <<= 4; switch( base16_variant & 0xf0000000UL ) { case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM: base16_character1 = base16_stream[ base16_stream_index ]; break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN: byte_stream_copy_to_uint16_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN: byte_stream_copy_to_uint16_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN: byte_stream_copy_to_uint32_big_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN: byte_stream_copy_to_uint32_little_endian( &( base16_stream[ base16_stream_index ] ), base16_character1 ); break; } if( ( base16_character1 & 0xffffff00UL ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: invalid base16 character at index: %" PRIzd ".", base16_stream_index, function ); return( -1 ); } base16_stream_index += base16_character_size; if( ( base16_character1 >= (uint32_t) 'A' ) && ( base16_character1 <= (uint32_t) 'F' ) ) { if( ( character_case != LIBUNA_CASE_MIXED ) && ( character_case != LIBUNA_CASE_UPPER ) ) { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } byte_value |= (uint8_t) ( base16_character1 - (uint32_t) 'A' + 10 ); } else if( ( base16_character1 >= (uint32_t) 'a' ) && ( base16_character1 <= (uint32_t) 'f' ) ) { if( ( character_case != LIBUNA_CASE_MIXED ) && ( character_case != LIBUNA_CASE_LOWER ) ) { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } byte_value |= (uint8_t) ( base16_character1 - (uint32_t) 'a' + 10 ); } else if( ( base16_character1 >= (uint32_t) '0' ) && ( base16_character1 <= (uint32_t) '9' ) ) { byte_value |= (uint8_t) ( base16_character1 - (uint32_t) '0' ); } else { strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER; } if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: invalid base16 character stream at index: %" PRIzd ".", function, base16_stream_index - base16_character_size ); return( -1 ); } if( byte_stream_index >= byte_stream_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: byte stream is too small.", function ); return( -1 ); } byte_stream[ byte_stream_index++ ] = byte_value; number_of_characters += 2; } } if( character_limit != 0 ) { if( number_of_characters > (size_t) character_limit ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_CONVERSION, LIBCERROR_CONVERSION_ERROR_INPUT_FAILED, "%s: number of characters in last line exceed maximum.", function ); return( -1 ); } } return( 1 ); }
/* Reads a B-tree file node descriptor * Returns 1 if successful or -1 on error */ int libfshfs_btree_file_read_node_descriptor( const uint8_t *data, size_t data_size, uint16_t *number_of_records, libcerror_error_t **error ) { static char *function = "libfshfs_btree_file_read_node_descriptor"; uint32_t next_node_number = 0; uint32_t previous_node_number = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint16_t value_16bit = 0; #endif if( data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid data.", function ); return( -1 ); } if( ( data_size < sizeof( fshfs_btree_node_descriptor_t ) ) || ( data_size > (size_t) SSIZE_MAX ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid data size value out of bounds.", function ); return( -1 ); } if( number_of_records == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid number of records.", function ); return( -1 ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: B-tree node descriptor data:\n", function ); libcnotify_print_data( (uint8_t *) data, sizeof( fshfs_btree_node_descriptor_t ), LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); } #endif byte_stream_copy_to_uint32_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->next_node_number, next_node_number ); byte_stream_copy_to_uint32_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->previous_node_number, previous_node_number ); byte_stream_copy_to_uint16_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->number_of_records, *number_of_records ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: next node number\t\t: %" PRIu32 "\n", function, next_node_number ); libcnotify_printf( "%s: previous node number\t\t: %" PRIu32 "\n", function, previous_node_number ); libcnotify_printf( "%s: node type\t\t\t: %" PRIi8 " (%s)\n", function, ( (fshfs_btree_node_descriptor_t *) data )->node_type, libfshfs_debug_print_btree_node_type( ( (fshfs_btree_node_descriptor_t *) data )->node_type ) ); libcnotify_printf( "%s: node level\t\t\t: %" PRIi8 "\n", function, ( (fshfs_btree_node_descriptor_t *) data )->node_level ); libcnotify_printf( "%s: number of records\t\t: %" PRIu16 "\n", function, *number_of_records ); byte_stream_copy_to_uint16_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->unknown1, value_16bit ); libcnotify_printf( "%s: unknown1\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "\n", function ); } #endif 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 ); }
/* Reads the file header * Returns 1 if successful or -1 on error */ int libqcow_io_handle_read_file_header( libqcow_io_handle_t *io_handle, libbfio_handle_t *file_io_handle, uint32_t *encryption_method, libcerror_error_t **error ) { uint8_t *file_header_data = NULL; static char *function = "libqcow_io_handle_read_file_header"; size_t read_size = 512; ssize_t read_count = 0; uint64_t backing_filename_offset = 0; uint32_t number_of_level1_table_references = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint64_t value_64bit = 0; uint32_t value_32bit = 0; uint16_t value_16bit = 0; #endif 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->backing_filename != NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, "%s: invalid IO handle - backing filename value already set.", function ); return( -1 ); } if( encryption_method == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid encryption method.", function ); return( -1 ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: reading file header at offset: 0 (0x00000000)\n", function ); } #endif if( libbfio_handle_seek_offset( file_io_handle, 0, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek file header offset: 0.", function ); goto on_error; } file_header_data = (uint8_t *) memory_allocate( sizeof( uint8_t ) * read_size ); if( file_header_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create file header data.", function ); goto on_error; } read_count = libbfio_handle_read_buffer( file_io_handle, file_header_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 file header.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: file header data:\n", function ); libcnotify_print_data( file_header_data, sizeof( qcow_file_header_v1_t ), 0 ); } #endif if( memory_compare( ( (qcow_file_header_v1_t *) file_header_data )->signature, qcow_file_signature, 4 ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported file signature.", function ); goto on_error; } byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->format_version, io_handle->format_version ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->backing_filename_offset, backing_filename_offset ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->backing_filename_size, io_handle->backing_filename_size ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->signature, value_32bit ); libcnotify_printf( "%s: signature\t\t\t\t: 0x%08" PRIx32 "\n", function, value_32bit ); libcnotify_printf( "%s: format version\t\t\t: %" PRIu32 "\n", function, io_handle->format_version ); libcnotify_printf( "%s: backing filename offset\t\t: %" PRIu32 "\n", function, backing_filename_offset ); libcnotify_printf( "%s: backing filename size\t\t: %" PRIu32 "\n", function, io_handle->backing_filename_size ); } #endif if( ( io_handle->format_version != 1 ) && ( io_handle->format_version != 2 ) && ( io_handle->format_version != 3 ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported format version: %" PRIu32 ".", function, io_handle->format_version ); goto on_error; } if( io_handle->format_version == 1 ) { byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->media_size, io_handle->media_size ); io_handle->number_of_cluster_block_bits = (uint32_t) ( (qcow_file_header_v1_t *) file_header_data )->number_of_cluster_block_bits; io_handle->number_of_level2_table_bits = (uint32_t) ( (qcow_file_header_v1_t *) file_header_data )->number_of_level2_table_bits; byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->encryption_method, *encryption_method ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->level1_table_offset, io_handle->level1_table_offset ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->modification_time, value_32bit ); libcnotify_printf( "%s: modification time\t\t\t: %" PRIu32 "\n", function, value_32bit ); libcnotify_printf( "%s: media size\t\t\t\t: %" PRIu64 "\n", function, io_handle->media_size ); libcnotify_printf( "%s: number of cluster block bits\t: %" PRIu32 "\n", function, io_handle->number_of_cluster_block_bits ); libcnotify_printf( "%s: number of level 2 table bits\t: %" PRIu32 "\n", function, io_handle->number_of_level2_table_bits ); byte_stream_copy_to_uint16_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->unknown1, value_16bit ); libcnotify_printf( "%s: unknown1\t\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: encryption method\t\t\t: %" PRIu32 "\n", function, *encryption_method ); libcnotify_printf( "%s: level 1 table offset\t\t: 0x%08" PRIx64 "\n", function, io_handle->level1_table_offset ); } #endif } else if( ( io_handle->format_version == 2 ) || ( io_handle->format_version == 3 ) ) { byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->number_of_cluster_block_bits, io_handle->number_of_cluster_block_bits ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->number_of_level1_table_references, number_of_level1_table_references ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->level1_table_offset, io_handle->level1_table_offset ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->media_size, io_handle->media_size ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->encryption_method, *encryption_method ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: number of cluster block bits\t: %" PRIu32 "\n", function, io_handle->number_of_cluster_block_bits ); libcnotify_printf( "%s: media size\t\t\t\t: %" PRIu64 "\n", function, io_handle->media_size ); libcnotify_printf( "%s: encryption method\t\t\t: %" PRIu32 "\n", function, *encryption_method ); libcnotify_printf( "%s: number of level 1 table references\t: %" PRIu32 "\n", function, number_of_level1_table_references ); libcnotify_printf( "%s: level 1 table offset\t\t: 0x%08" PRIx64 "\n", function, io_handle->level1_table_offset ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->reference_count_table_offset, value_64bit ); libcnotify_printf( "%s: reference count table offset\t: 0x%08" PRIx64 "\n", function, value_64bit ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->reference_count_table_clusters, value_32bit ); libcnotify_printf( "%s: reference count table clusters\t: %" PRIu32 "\n", function, value_32bit ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->number_of_snapshots, value_32bit ); libcnotify_printf( "%s: number of snapshots\t\t\t: %" PRIu32 "\n", function, value_32bit ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->snapshots_offset, value_64bit ); libcnotify_printf( "%s: snapshots offset\t\t\t: 0x%08" PRIx64 "\n", function, value_64bit ); } #endif } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "\n" ); } #endif memory_free( file_header_data ); file_header_data = NULL; if( io_handle->format_version == 1 ) { io_handle->offset_bit_mask = 0x7fffffffffffffffULL; io_handle->compression_flag_bit_mask = (uint64_t) 1 << 63; io_handle->compression_bit_shift = 63 - io_handle->number_of_cluster_block_bits; } else if( ( io_handle->format_version == 2 ) || ( io_handle->format_version == 3 ) ) { if( io_handle->number_of_cluster_block_bits <= 8 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid number of cluster block bits value out of bounds.", function ); goto on_error; } io_handle->number_of_level2_table_bits = io_handle->number_of_cluster_block_bits - 3; io_handle->offset_bit_mask = 0x3fffffffffffffffULL; io_handle->compression_flag_bit_mask = (uint64_t) 1 << 62; io_handle->compression_bit_shift = 62 - ( io_handle->number_of_cluster_block_bits - 8 ); } io_handle->level1_index_bit_shift = io_handle->number_of_cluster_block_bits + io_handle->number_of_level2_table_bits; io_handle->level2_index_bit_mask = ~( (uint64_t) -1 << io_handle->number_of_level2_table_bits ); io_handle->cluster_block_bit_mask = ~( (uint64_t) -1 << io_handle->number_of_cluster_block_bits ); io_handle->compression_bit_mask = ~( (uint64_t) -1 << io_handle->compression_bit_shift ); io_handle->level2_table_size = (size_t) 1 << io_handle->number_of_level2_table_bits; io_handle->cluster_block_size = (size_t) 1 << io_handle->number_of_cluster_block_bits; if( io_handle->format_version == 1 ) { io_handle->level1_table_size = (uint32_t) ( io_handle->cluster_block_size * io_handle->level2_table_size ); if( ( io_handle->media_size % io_handle->level1_table_size ) != 0 ) { io_handle->level1_table_size = (uint32_t) ( ( io_handle->media_size / io_handle->level1_table_size ) + 1 ); } else { io_handle->level1_table_size = (uint32_t) ( io_handle->media_size / io_handle->level1_table_size ); } } else if( ( io_handle->format_version == 2 ) || ( io_handle->format_version == 3 ) ) { io_handle->level1_table_size = number_of_level1_table_references; } io_handle->level1_table_size *= 8; io_handle->level2_table_size *= 8; #if UINT32_MAX > SSIZE_MAX if( io_handle->level1_table_size > (uint32_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid level 1 table size value exceeds maximum.", function ); goto on_error; } #endif #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: level 1 table size\t\t\t: %" PRIzd "\n", function, io_handle->level1_table_size ); libcnotify_printf( "%s: level 2 table size\t\t\t: %" PRIzd "\n", function, io_handle->level2_table_size ); libcnotify_printf( "%s: cluster block size\t\t\t: %" PRIzd "\n", function, io_handle->cluster_block_size ); } #endif if( ( backing_filename_offset > 0 ) && ( io_handle->backing_filename_size > 0 ) ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: reading backing filename at offset: %" PRIu64 " (0x%08" PRIx64 ")\n", function, backing_filename_offset, backing_filename_offset ); } #endif if( libbfio_handle_seek_offset( file_io_handle, backing_filename_offset, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek file header offset: %" PRIu64 ".", function, backing_filename_offset ); goto on_error; } io_handle->backing_filename = (uint8_t *) memory_allocate( sizeof( uint8_t ) * io_handle->backing_filename_size ); if( io_handle->backing_filename == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create backing filename.", function ); goto on_error; } read_count = libbfio_handle_read_buffer( file_io_handle, io_handle->backing_filename, io_handle->backing_filename_size, error ); if( read_count != (ssize_t) io_handle->backing_filename_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read file header.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: backing filename data:\n", function ); libcnotify_print_data( io_handle->backing_filename, (size_t) io_handle->backing_filename_size, 0 ); } #endif } return( 1 ); on_error: if( io_handle->backing_filename != NULL ) { memory_free( io_handle->backing_filename ); io_handle->backing_filename = NULL; io_handle->backing_filename_size = 0; } if( file_header_data != NULL ) { memory_free( file_header_data ); } return( -1 ); }
/* Retrieves the table of contents from the optical disk using the SCSI READ TOC command * Returns 1 if successful, 0 if not or -1 on error */ int libsmdev_optical_disc_get_table_of_contents_scsi( libcfile_file_t *device_file, libsmdev_internal_handle_t *internal_handle, libcerror_error_t **error ) { uint8_t track_info_data[ 64 ]; uint8_t *toc_data = NULL; uint8_t *toc_entries = NULL; static char *function = "libsmdev_optical_disc_get_table_of_contents_scsi"; void *reallocation = NULL; size_t toc_data_offset = 0; size_t toc_data_size = 0; ssize_t read_count = 0; uint32_t lead_out_size = 0; uint32_t lead_out_offset = 0; uint32_t last_track_offset = 0; uint32_t track_offset = 0; uint32_t session_size = 0; uint32_t session_offset = 0; uint32_t next_session_offset = 0; uint16_t entry_index = 0; uint8_t first_track_number = 0; uint8_t last_track_number = 0; uint8_t lead_out_index = 0; uint8_t number_of_sessions = 0; uint8_t session_index = 0; uint8_t track_index = 0; uint8_t track_number = 0; uint8_t track_type = 0; int result = 0; toc_data_size = 1024; toc_data = (uint8_t *) memory_allocate( sizeof( uint8_t ) * toc_data_size ); if( toc_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create TOC data.", function ); goto on_error; } if( memory_set( toc_data, 0, sizeof( uint8_t ) * toc_data_size ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear TOC data.", function ); goto on_error; } read_count = libsmdev_scsi_read_toc( device_file, LIBSMDEV_SCSI_TOC_CDB_FORMAT_RAW_TOC, toc_data, toc_data_size, error ); if( read_count == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve TOC.", function ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { if( ( error != NULL ) && ( *error != NULL ) ) { libcnotify_print_error_backtrace( *error ); } } #endif libcerror_error_free( error ); byte_stream_copy_to_uint16_big_endian( toc_data, toc_data_size ); if( toc_data_size > 1024 ) { reallocation = memory_reallocate( toc_data, sizeof( uint8_t ) * toc_data_size ); if( reallocation == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to resize TOC data.", function ); goto on_error; } toc_data = (uint8_t *) reallocation; read_count = libsmdev_scsi_read_toc( device_file, LIBSMDEV_SCSI_TOC_CDB_FORMAT_RAW_TOC, toc_data, toc_data_size, error ); if( read_count == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve TOC.", function ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { if( ( error != NULL ) && ( *error != NULL ) ) { libcnotify_print_error_backtrace( *error ); } } #endif libcerror_error_free( error ); } } } toc_data_size = (size_t) read_count; if( toc_data_size > 4 ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: header:\n", function ); libcnotify_print_data( toc_data, 4, 0 ); } #endif number_of_sessions = (uint16_t) toc_data[ 3 ]; #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: number of sessions\t\t\t: %" PRIu8 "\n", function, number_of_sessions ); libcnotify_printf( "\n" ); } #endif toc_entries = &( toc_data[ 4 ] ); toc_data_offset = 4; while( toc_data_offset < (size_t) toc_data_size ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: entry: %02" PRIu16 ":\n", function, entry_index ); libcnotify_print_data( toc_entries, 11, 0 ); } #endif if( toc_entries[ 3 ] <= 0x63 ) { libsmdev_optical_disc_copy_msf_to_lba( toc_entries[ 8 ], toc_entries[ 9 ], toc_entries[ 10 ], track_offset ); } else if( toc_entries[ 3 ] == 0xa0 ) { first_track_number = toc_entries[ 8 ]; } else if( toc_entries[ 3 ] == 0xa1 ) { last_track_number = toc_entries[ 8 ]; } else if( toc_entries[ 3 ] == 0xa2 ) { libsmdev_optical_disc_copy_msf_to_lba( toc_entries[ 8 ], toc_entries[ 9 ], toc_entries[ 10 ], lead_out_offset ); } else if( toc_entries[ 3 ] == 0xb0 ) { libsmdev_optical_disc_copy_absolute_msf_to_lba( toc_entries[ 4 ], toc_entries[ 5 ], toc_entries[ 6 ], next_session_offset ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { if( toc_entries[ 3 ] <= 0x63 ) { libcnotify_printf( "%s: session: %02" PRIu16 " track: %02" PRIu8 "\t\t\t: %02" PRIu8 ":%02" PRIu8 ".%02" PRIu8 " (offset: %" PRIu32 ")\n", function, toc_entries[ 0 ], toc_entries[ 3 ], toc_entries[ 4 ], toc_entries[ 5 ], toc_entries[ 6 ], track_offset ); } else if( toc_entries[ 3 ] == 0xa0 ) { libcnotify_printf( "%s: session: %02" PRIu8 " first track number\t: %" PRIu8 "\n", function, toc_entries[ 0 ], first_track_number ); } else if( toc_entries[ 3 ] == 0xa1 ) { libcnotify_printf( "%s: session: %02" PRIu8 " last track number\t\t: %" PRIu8 "\n", function, toc_entries[ 0 ], last_track_number ); } else if( toc_entries[ 3 ] == 0xa2 ) { libcnotify_printf( "%s: session: %02" PRIu8 " lead out\t\t\t: %02" PRIu8 ":%02" PRIu8 ".%02" PRIu8 " (offset: %" PRIu32 ")\n", function, toc_entries[ 0 ], toc_entries[ 8 ], toc_entries[ 9 ], toc_entries[ 10 ], lead_out_offset ); } else if( toc_entries[ 3 ] == 0xb0 ) { libcnotify_printf( "%s: session: %02" PRIu16 " end\t\t\t: %02" PRIu8 ":%02" PRIu8 ".%02" PRIu8 " (offset: %" PRIu32 ")\n", function, toc_entries[ 0 ], toc_entries[ 4 ], toc_entries[ 5 ], toc_entries[ 6 ], next_session_offset ); } libcnotify_printf( "\n" ); } #endif if( ( toc_entries[ 3 ] <= 0x63 ) || ( toc_entries[ 3 ] == 0xb0 ) ) { if( track_number >= first_track_number ) { if( toc_entries[ 3 ] == 0xb0 ) { track_offset = lead_out_offset; } if( track_offset < last_track_offset ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track offset value out of bounds.", function ); goto on_error; } if( ( track_index + 1 ) != track_number ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track number value out of bounds.", function ); goto on_error; } if( toc_entries[ 3 ] == 0xa2 ) { if( track_number != last_track_number ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track number value out of bounds.", function ); goto on_error; } } if( memory_set( track_info_data, 0, 64 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear track info data.", function ); goto on_error; } read_count = libsmdev_scsi_read_track_information( device_file, last_track_offset, track_info_data, 64, error ); if( read_count == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve track info data: %d.", function, track_index ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { if( ( error != NULL ) && ( *error != NULL ) ) { libcnotify_print_error_backtrace( *error ); } } #endif libcerror_error_free( error ); break; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: track information data: %d:\n", function, track_index ); libcnotify_print_data( track_info_data, (size_t) read_count, 0 ); } #endif if( track_info_data[ 2 ] != toc_entries[ 0 ] ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track information data - session number value out of bounds.", function ); goto on_error; } if( track_info_data[ 3 ] != track_number ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track information data - track number value out of bounds.", function ); goto on_error; } track_type = LIBSMDEV_TRACK_TYPE_UNKNOWN; if( ( track_info_data[ 5 ] & 0x04 ) != 0 ) { if( ( track_info_data[ 5 ] & 0x08 ) == 0 ) { if( ( track_info_data[ 6 ] & 0x0f ) == 1 ) { track_type = LIBSMDEV_TRACK_TYPE_MODE1_2048; } else if( ( track_info_data[ 6 ] & 0x0f ) == 2 ) { track_type = LIBSMDEV_TRACK_TYPE_MODE2_2048; } } } else { track_type = LIBSMDEV_TRACK_TYPE_AUDIO; } if( libsmdev_handle_append_track( internal_handle, last_track_offset, track_offset - last_track_offset, track_type, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append track: %d.", function, track_index ); goto on_error; } track_index++; } last_track_offset = track_offset; if( toc_entries[ 3 ] != 0xb0 ) { track_number = toc_entries[ 3 ]; } } if( toc_entries[ 3 ] == 0xb0 ) { if( session_offset >= next_session_offset ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid session offset value out of bounds.", function ); goto on_error; } if( ( session_index + 1 ) != toc_entries[ 0 ] ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid session number value out of bounds.", function ); goto on_error; } lead_out_size = 0; if( ( lead_out_offset >= session_offset ) && ( lead_out_offset < next_session_offset ) ) { lead_out_size = next_session_offset - lead_out_offset; if( libsmdev_handle_append_lead_out( internal_handle, lead_out_offset, lead_out_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append lead_out: %d.", function, lead_out_index ); goto on_error; } lead_out_index++; } session_size = next_session_offset - session_offset; if( ( session_index + 1 ) == number_of_sessions ) { session_size -= lead_out_size; } if( libsmdev_handle_append_session( internal_handle, session_offset, session_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append session: %d.", function, session_index ); goto on_error; } session_offset = next_session_offset; session_index++; } toc_entries += 11; toc_data_offset += 11; entry_index++; } if( ( track_index + 1 ) == track_number ) { if( track_offset < last_track_offset ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track offset value out of bounds.", function ); goto on_error; } if( memory_set( track_info_data, 0, 64 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear track info data.", function ); goto on_error; } read_count = libsmdev_scsi_read_track_information( device_file, last_track_offset, track_info_data, 64, error ); if( read_count == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve track info data: %d.", function, track_index ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { if( ( error != NULL ) && ( *error != NULL ) ) { libcnotify_print_error_backtrace( *error ); } } #endif libcerror_error_free( error ); } else { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: track information data: %d:\n", function, track_index ); libcnotify_print_data( track_info_data, (size_t) read_count, 0 ); } #endif if( track_info_data[ 2 ] != toc_entries[ 0 ] ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track information data - session number value out of bounds.", function ); goto on_error; } if( track_info_data[ 3 ] != toc_entries[ 3 ] ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid track information data - track number value out of bounds.", function ); goto on_error; } track_type = LIBSMDEV_TRACK_TYPE_UNKNOWN; if( ( track_info_data[ 5 ] & 0x04 ) != 0 ) { if( ( track_info_data[ 5 ] & 0x08 ) == 0 ) { if( ( track_info_data[ 6 ] & 0x0f ) == 1 ) { track_type = LIBSMDEV_TRACK_TYPE_MODE1_2048; } else if( ( track_info_data[ 6 ] & 0x0f ) == 2 ) { track_type = LIBSMDEV_TRACK_TYPE_MODE2_2048; } } } else { track_type = LIBSMDEV_TRACK_TYPE_AUDIO; } if( libsmdev_handle_append_track( internal_handle, last_track_offset, track_offset - last_track_offset, track_type, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append last track: %d.", function, track_index ); goto on_error; } } if( session_index != number_of_sessions ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid session index value out of bounds.", function ); goto on_error; } result = 1; } } if( result == 0 ) { if( libcdata_array_empty( internal_handle->tracks_array, (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_track_value_free, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to empty tracks array.", function ); goto on_error; } if( libcdata_array_empty( internal_handle->lead_outs_array, (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to empty lead outs array.", function ); goto on_error; } if( libcdata_array_empty( internal_handle->sessions_array, (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to empty sessions array.", function ); goto on_error; } } memory_free( toc_data ); toc_data = NULL; return( result ); on_error: if( toc_data != NULL ) { memory_free( toc_data ); } libcdata_array_empty( internal_handle->tracks_array, (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_track_value_free, NULL ); libcdata_array_empty( internal_handle->lead_outs_array, (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free, NULL ); libcdata_array_empty( internal_handle->sessions_array, (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free, NULL ); return( -1 ); }