/* Opens an EWF file for reading */ LIBEWF_HANDLE *libewf_open_read( LIBEWF_HANDLE *handle, const char *filename ) { int file_descriptor; EWF_FILE_HEADER *file_header; uint16_t fields_segment; if( handle == NULL ) { LIBEWF_FATAL_PRINT( "libewf_open_read: incorrect handle.\n" ); } file_descriptor = open( filename, O_RDONLY ); if( file_descriptor == -1 ) { LIBEWF_FATAL_PRINT( "libewf_open: unable to open file: %s\n", filename ); } file_header = ewf_file_header_read( file_descriptor ); if( file_header == NULL ) { LIBEWF_FATAL_PRINT( "libewf_open_read: incorrect file header in: %s.\n", filename ); } fields_segment = convert_16bit( file_header->fields_segment ); LIBEWF_VERBOSE_PRINT( "libewf_open_read: added segment file: %s with file descriptor: %d with segment number: %" PRIu16 ".\n", filename, file_descriptor, fields_segment ); handle->segment_table = libewf_segment_table_set_values( handle->segment_table, fields_segment, filename, file_descriptor ); ewf_file_header_free( file_header ); LIBEWF_VERBOSE_PRINT( "libewf_open_read: open successful.\n" ); return( handle ); }
/* Builds the index from the files */ LIBEWF_HANDLE *libewf_build_index( LIBEWF_HANDLE *handle ) { EWF_SECTION *last_section = NULL; uint32_t segment = 0; if( handle == NULL ) { LIBEWF_FATAL_PRINT( "libewf_build_index: incorrect handle\n" ); } if( handle->index_build != 0 ) { LIBEWF_FATAL_PRINT( "libewf_build_index: index has already been build\n" ); } for( segment = 1; segment < handle->segment_table->amount; segment++ ) { LIBEWF_VERBOSE_PRINT( "libewf_build_index: building index for segment: %" PRIu32 "\n", segment ); last_section = libewf_sections_read_segment( handle, segment ); } /* Check to see if we are done */ if( ( last_section == NULL ) || ( !ewf_section_is_type_done( last_section ) ) ) { LIBEWF_FATAL_PRINT( "libewf_build_index: no ending section, cannot find the last segment file\n" ); } ewf_section_free( last_section ); handle->index_build = 1; LIBEWF_VERBOSE_PRINT( "libewf_build_index: index successful build.\n" ); return( handle ); }
/* Opens an EWF file * For reading files should contain all filenames that make up an EWF image * For writing files should contain the base of the filename, extentions like .e01 will be automatically added */ LIBEWF_HANDLE *libewf_open( const char **filenames, uint32_t file_amount, uint8_t flags ) { uint32_t iterator; LIBEWF_HANDLE *handle = NULL; if( flags == LIBEWF_OPEN_READ ) { /* 1 additional entry required because * entry [ 0 ] is not used for reading */ handle = libewf_handle_alloc( file_amount + 1 ); for( iterator = 0; iterator < file_amount; iterator++ ) { libewf_open_read( handle, filenames[ iterator ] ); } handle = libewf_build_index( handle ); } else if( flags == LIBEWF_OPEN_WRITE ) { /* Allocate 2 entries * entry [ 0 ] is used for the base filename */ handle = libewf_handle_alloc( 2 ); libewf_open_write( handle, filenames[ 0 ] ); } else { LIBEWF_FATAL_PRINT( "libewf_open: unsupported flags.\n" ); } LIBEWF_VERBOSE_PRINT( "libewf_open: open successful.\n" ); return( handle ); }
/* Creates a printable string of the stored md5 hash * Returns 1 if successful, 0 if no md5 hash is stored, -1 on error */ int8_t libewf_get_stored_md5_hash( LIBEWF_HANDLE *handle, LIBEWF_CHAR *string, size_t length ) { LIBEWF_INTERNAL_HANDLE *internal_handle = NULL; int8_t result = 0; if( handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_get_stored_md5_hash: invalid handle.\n" ); return( -1 ); } internal_handle = (LIBEWF_INTERNAL_HANDLE *) handle; if( internal_handle->stored_md5_hash == NULL ) { LIBEWF_VERBOSE_PRINT( "libewf_get_stored_md5_hash: MD5 hash was not set.\n" ); return( 0 ); } result = libewf_string_copy_from_digest_hash( string, length, internal_handle->stored_md5_hash, EWF_DIGEST_HASH_SIZE_MD5 ); if( result == -1 ) { LIBEWF_WARNING_PRINT( "libewf_get_stored_md5_hash: unable to create MD5 hash string.\n" ); } return( result ); }
/* Converts the EWF digest hash to a printable string * Returns 1 if successful, 0 if hash was not set, or -1 on error */ int8_t libewf_string_copy_from_digest_hash( LIBEWF_CHAR *string, size_t size_string, EWF_DIGEST_HASH *digest_hash, size_t size_digest_hash ) { size_t string_iterator = 0; size_t digest_hash_iterator = 0; uint8_t digest_digit = 0; if( string == NULL ) { LIBEWF_WARNING_PRINT( "libewf_string_copy_from_digest_hash: invalid string.\n" ); return( -1 ); } if( ( size_string > (size_t) SSIZE_MAX ) || ( size_digest_hash > (size_t) SSIZE_MAX ) ) { LIBEWF_WARNING_PRINT( "libewf_string_copy_from_digest_hash: invalid size value exceeds maximum.\n" ); return( -1 ); } /* The string requires space for 2 characters per digest hash digit and a end of string */ if( size_string < ( ( 2 * size_digest_hash ) + 1 ) ) { LIBEWF_WARNING_PRINT( "libewf_string_copy_from_digest_hash: string too small.\n" ); return( -1 ); } if( digest_hash == NULL ) { LIBEWF_VERBOSE_PRINT( "libewf_string_copy_from_digest_hash: invalid digest hash.\n" ); return( 0 ); } for( digest_hash_iterator = 0; digest_hash_iterator < size_digest_hash; digest_hash_iterator++ ) { digest_digit = digest_hash[ digest_hash_iterator ] / 16; if( digest_digit <= 9 ) { string[ string_iterator++ ] = (LIBEWF_CHAR) ( (uint8_t) '0' + digest_digit ); } else { string[ string_iterator++ ] = (LIBEWF_CHAR) ( (uint8_t) 'a' + ( digest_digit - 10 ) ); } digest_digit = digest_hash[ digest_hash_iterator ] % 16; if( digest_digit <= 9 ) { string[ string_iterator++ ] = (LIBEWF_CHAR) ( (uint8_t) '0' + digest_digit ); } else { string[ string_iterator++ ] = (LIBEWF_CHAR) ( (uint8_t) 'a' + ( digest_digit - 10 ) ); } } string[ string_iterator ] = (LIBEWF_CHAR) '\0'; return( 1 ); }
/* Writes the ltree to a file descriptor * Returns the amount of bytes written, or -1 on error */ ssize_t ewf_ltree_write( EWF_LTREE *ltree, int file_descriptor ) { ssize_t count = 0; size_t size = EWF_LTREE_SIZE; if( ltree == NULL ) { LIBEWF_VERBOSE_PRINT( "ewf_ltree_write: invalid ltree.\n" ); return( -1 ); } count = libewf_common_write( file_descriptor, ltree, size ); if( count < (ssize_t) size ) { return( -1 ); } return( count ); }
/* Writes the sectors to a file descriptor * Returns a -1 on error, the amount of bytes written on success */ ssize_t ewf_error2_sectors_write( EWF_ERROR2_SECTOR *sectors, int file_descriptor, uint32_t amount ) { ssize_t count; size_t size = EWF_ERROR2_SECTOR_SIZE * amount; if( sectors == NULL ) { LIBEWF_VERBOSE_PRINT( "ewf_error2_sectors_write: invalid sectors.\n" ); return( -1 ); } count = write( file_descriptor, sectors, size ); if( count < size ) { return( -1 ); } return( count ); }
/* Sets the values for a specific segment */ LIBEWF_SEGMENT_TABLE *libewf_segment_table_set_values( LIBEWF_SEGMENT_TABLE *segment_table, uint32_t segment, const char *filename, int file_descriptor ) { size_t filename_size; if( segment_table == NULL ) { LIBEWF_FATAL_PRINT( "libewf_segment_table_set_values: invalid segment_table\n" ); } /* Check if additional entries should be allocated */ if( segment > segment_table->amount ) { LIBEWF_VERBOSE_PRINT( "libewf_segment_table_set_values: allocating additional segment_table entries\n" ); /* Segment has an offset of 1 so an additional values entry is needed */ segment_table = libewf_segment_table_values_realloc( segment_table, ( segment + 1 ) ); } if( segment_table->filename[ segment ] != NULL ) { LIBEWF_FATAL_PRINT( "libewf_segment_table_set_values: duplicate segments not supported: segment %d in %s was already specified in %s.\n", segment, filename, segment_table->filename[ segment ] ); } filename_size = strlen( filename ); /* One additional byte for the end of string character is needed */ segment_table->filename[ segment ] = (char *) malloc( sizeof( char ) * ( filename_size + 1 ) ); if( segment_table->filename[ segment ] == NULL ) { LIBEWF_FATAL_PRINT( "libewf_segment_table_set_values: unable to allocate filename\n" ); } memcpy( segment_table->filename[ segment ], filename, filename_size ); /* Make sure the string is terminated */ segment_table->filename[ segment ][ filename_size ] = '\0'; segment_table->file_descriptor[ segment ] = file_descriptor; return( segment_table ); }
/* Writes the table to a file descriptor * Returns a -1 on error, the amount of bytes written on success */ ssize_t ewf_table_write( EWF_TABLE *table, int file_descriptor ) { EWF_CRC crc; ssize_t count; size_t size = EWF_TABLE_SIZE; if( table == NULL ) { LIBEWF_VERBOSE_PRINT( "ewf_table_write: invalid table.\n" ); return( -1 ); } crc = ewf_crc( (void *) table, ( size - EWF_CRC_SIZE ), 1 ); revert_32bit( crc, table->crc ); count = write( file_descriptor, table, size ); if( count < size ) { return( -1 ); } return( count ); }
/* Writes the volume to a file descriptor * Returns a -1 on error, the amount of bytes written on success */ ssize_t ewf_volume_write( EWF_VOLUME *volume, int file_descriptor ) { EWF_CRC crc; ssize_t count; size_t size = EWF_VOLUME_SIZE; if( volume == NULL ) { LIBEWF_VERBOSE_PRINT( "ewf_volume_write: invalid volume.\n" ); return( -1 ); } crc = ewf_crc( (void *) volume, ( size - EWF_CRC_SIZE ), 1 ); revert_32bit( crc, volume->crc ); count = write( file_descriptor, volume, size ); if( count < size ) { return( -1 ); } return( count ); }
/* Writes the error2 to a file descriptor, without the first sector * this should be written by the sectors write function * Returns a -1 on error, the amount of bytes written on success */ ssize_t ewf_error2_write( EWF_ERROR2 *error2, int file_descriptor ) { EWF_CRC crc; ssize_t count; size_t size = EWF_ERROR2_SIZE; if( error2 == NULL ) { LIBEWF_VERBOSE_PRINT( "ewf_error2_write: invalid error2.\n" ); return( -1 ); } crc = ewf_crc( (void *) error2, ( size - EWF_CRC_SIZE ), 1 ); revert_32bit( crc, error2->crc ); count = write( file_descriptor, error2, size ); if( count < size ) { return( -1 ); } return( count ); }
/* Writes the hash to a file descriptor * Returns a -1 on error, the amount of bytes written on success */ ssize_t ewf_hash_write( EWF_HASH *hash, int file_descriptor ) { EWF_CRC crc; ssize_t count; size_t size = EWF_HASH_SIZE; if( hash == NULL ) { LIBEWF_VERBOSE_PRINT( "ewf_hash_write: invalid hash.\n" ); return( -1 ); } crc = ewf_crc( (void *) hash, ( size - EWF_CRC_SIZE ), 1 ); revert_32bit( crc, hash->crc ); count = write( file_descriptor, hash, size ); if( count < size ) { return( -1 ); } return( count ); }
/* Writes the offsets to a file descriptor * Returns a -1 on error, the amount of bytes written on success */ ssize_t ewf_table_offsets_write( EWF_TABLE_OFFSET *offsets, int file_descriptor, uint32_t amount ) { EWF_CRC crc; ssize_t count; ssize_t crc_count; size_t size = EWF_TABLE_OFFSET_SIZE * amount; if( offsets == NULL ) { LIBEWF_VERBOSE_PRINT( "ewf_table_offsets_write: invalid offsets.\n" ); return( -1 ); } count = write( file_descriptor, offsets, size ); if( count < size ) { return( -1 ); } crc = ewf_crc( offsets, size, 1 ); crc_count = ewf_crc_write( crc, file_descriptor ); return( count + crc_count ); }
/* Calculates the MD5 hash and creates a printable string of the calculated md5 hash * Returns 1 if successful, -1 on error */ int8_t libewf_calculate_md5_hash( LIBEWF_HANDLE *handle, LIBEWF_CHAR *string, size_t length ) { LIBEWF_INTERNAL_HANDLE *internal_handle = NULL; uint8_t *data = NULL; off_t offset = 0; ssize_t count = 0; uint32_t iterator = 0; if( handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_calculate_md5_hash: invalid handle.\n" ); return( -1 ); } internal_handle = (LIBEWF_INTERNAL_HANDLE *) internal_handle; if( internal_handle->media == NULL ) { LIBEWF_WARNING_PRINT( "libewf_calculate_md5_hash: invalid handle - missing subhandle media.\n" ); return( -1 ); } if( string == NULL ) { LIBEWF_VERBOSE_PRINT( "libewf_calculate_md5_hash: invalid string.\n" ); return( -1 ); } if( length < LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 ) { LIBEWF_VERBOSE_PRINT( "libewf_calculate_md5_hash: string too small.\n" ); return( -1 ); } if( internal_handle->index_build == 0 ) { LIBEWF_WARNING_PRINT( "libewf_calculate_md5_hash: index was not build.\n" ); return( -1 ); } if( internal_handle->calculated_md5_hash == NULL ) { data = (uint8_t *) libewf_common_alloc( internal_handle->media->chunk_size * sizeof( uint8_t ) ); if( data == NULL ) { LIBEWF_WARNING_PRINT( "libewf_calculate_md5_hash: unable to allocate data.\n" ); return( -1 ); } for( iterator = 0; iterator <= internal_handle->offset_table->last; iterator++ ) { offset = iterator * internal_handle->media->chunk_size; count = libewf_read_random( handle, data, internal_handle->media->chunk_size, offset ); if( count == -1 ) { LIBEWF_WARNING_PRINT( "libewf_calculate_md5_hash: unable to read chunk.\n" ); libewf_common_free( data ); return( -1 ); } if( count > (ssize_t) INT32_MAX ) { LIBEWF_WARNING_PRINT( "libewf_calculate_md5_hash: invalid count - only values below 2^32 supported.\n" ); libewf_common_free( data ); return( -1 ); } } libewf_common_free( data ) ; } else { LIBEWF_VERBOSE_PRINT( "libewf_calculate_md5_hash: MD5 hash already calculated.\n" ); } if( libewf_string_copy_from_digest_hash( string, length, internal_handle->calculated_md5_hash, EWF_DIGEST_HASH_SIZE_MD5 ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_calculate_md5_hash: unable to set MD5 hash string.\n" ); return( -1 ); } return( 1 ); }
/* Seeks a certain chunk offset within the EWF file(s) * Returns the segment file offset if seek is successful, or -1 on error */ off_t libewf_seek_chunk( LIBEWF_INTERNAL_HANDLE *internal_handle, uint32_t chunk ) { off_t offset = 0; uint16_t segment_number = 0; int file_descriptor = 0; if( internal_handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: invalid handle.\n" ); return( -1 ); } if( internal_handle->segment_table == NULL ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: invalid handle - missing segment table.\n" ); return( -1 ); } if( internal_handle->offset_table == NULL ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: invalid handle - missing offset table.\n" ); return( -1 ); } if( internal_handle->chunk_cache == NULL ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: invalid handle - missing chunk cache.\n" ); return( -1 ); } if( internal_handle->index_build == 0 ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: index was not build.\n" ); return( -1 ); } if( chunk >= internal_handle->offset_table->amount ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: chunk: %" PRIu32 " not in offset table.\n", chunk ); return( -1 ); } file_descriptor = internal_handle->offset_table->file_descriptor[ chunk ]; offset = internal_handle->offset_table->offset[ chunk ]; segment_number = internal_handle->offset_table->segment_number[ chunk ]; LIBEWF_VERBOSE_PRINT( "libewf_seek_chunk: seek file descriptor: %d, for segment: %" PRIu16 " for offset: %jd.\n", file_descriptor, segment_number, offset ); if( offset > (off_t) INT32_MAX ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: invalid chunk offset only values below 2^32 are supported.\n" ); return( -1 ); } if( internal_handle->segment_table->file_offset[ segment_number ] != offset ) { if( libewf_common_lseek( file_descriptor, offset, SEEK_SET ) == -1 ) { LIBEWF_WARNING_PRINT( "libewf_seek_chunk: cannot find offset: %jd.\n", offset ); return( -1 ); } internal_handle->segment_table->file_offset[ segment_number ] = offset; } internal_handle->current_chunk = chunk; return( offset ); }
/* Copies a multi byte UTF16 string to a single byte ASCII string * Returns 1 if successful, on -1 on error */ int8_t libewf_string_copy_utf16_to_ascii( LIBEWF_CHAR *utf16_string, size_t size_utf16, LIBEWF_CHAR* ascii_string, size_t size_ascii ) { size_t utf16_iterator = 2; size_t ascii_iterator = 0; uint8_t byte_order = 0; if( utf16_string == NULL ) { LIBEWF_WARNING_PRINT( "libewf_string_copy_utf16_to_ascii: invalid UTF16 string.\n" ); return( -1 ); } if( ascii_string == NULL ) { LIBEWF_WARNING_PRINT( "libewf_string_copy_utf16_to_ascii: invalid ASCII string.\n" ); return( -1 ); } if( ( size_utf16 > (size_t) SSIZE_MAX ) || ( size_ascii > (size_t) SSIZE_MAX ) ) { LIBEWF_WARNING_PRINT( "libewf_string_copy_utf16_to_ascii: invalid size value exceeds maximum.\n" ); return( -1 ); } /* The UTF16 string contains twice as much bytes needed for the ASCII string * with two additional bytes representing byte order */ if( size_ascii < ( ( size_utf16 - 2 ) / 2 ) ) { LIBEWF_WARNING_PRINT( "libewf_string_copy_utf16_to_ascii: ASCII string too small.\n" ); return( -1 ); } /* Check if UTF16 string is in big or little endian */ if( ( (uint8_t) utf16_string[ 0 ] == 0xff ) && ( (uint8_t) utf16_string[ 1 ] == 0xfe ) ) { byte_order = LIBEWF_STRING_LITTLE_ENDIAN; } else if( ( (uint8_t) utf16_string[ 0 ] == 0xfe ) && ( (uint8_t) utf16_string[ 1 ] == 0xff ) ) { byte_order = LIBEWF_STRING_BIG_ENDIAN; } else { LIBEWF_VERBOSE_PRINT( "libewf_string_copy_utf16_to_ascii: no byte order in UTF16 string.\n" ); if( ( utf16_string[ 0 ] == (LIBEWF_CHAR) '\0' ) && ( utf16_string[ 1 ] != (LIBEWF_CHAR) '\0' ) ) { byte_order = LIBEWF_STRING_LITTLE_ENDIAN; } else if( ( utf16_string[ 0 ] != (LIBEWF_CHAR) '\0' ) && ( utf16_string[ 1 ] == (LIBEWF_CHAR) '\0' ) ) { byte_order = LIBEWF_STRING_LITTLE_ENDIAN; } else { LIBEWF_WARNING_PRINT( "libewf_string_copy_utf16_to_ascii: unable to determine byte order in UTF16 string.\n" ); return( -1 ); } utf16_iterator = 0; } /* Convert string */ while( utf16_iterator < size_utf16 ) { if( byte_order == LIBEWF_STRING_BIG_ENDIAN ) { if( utf16_string[ utf16_iterator ] == (LIBEWF_CHAR) '\0' ) { ascii_string[ ascii_iterator ] = utf16_string[ utf16_iterator + 1 ]; } else { /* Add a place holder character */ ascii_string[ ascii_iterator ] = '_'; } } else if( byte_order == LIBEWF_STRING_LITTLE_ENDIAN ) { if( utf16_string[ utf16_iterator + 1 ] == (LIBEWF_CHAR) '\0' ) { ascii_string[ ascii_iterator ] = utf16_string[ utf16_iterator ]; } else { /* Add a place holder character */ ascii_string[ ascii_iterator ] = '_'; } } utf16_iterator += 2; ascii_iterator += 1; } ascii_string[ size_ascii - 1 ] = (LIBEWF_CHAR) '\0'; return( 1 ); }
/* Opens EWF file(s) * For reading files should contain all filenames that make up an EWF image * For writing files should contain the base of the filename, extentions like .e01 will be automatically added * Returns a pointer to the new instance of handle, NULL on error */ LIBEWF_HANDLE *libewf_open( char * const filenames[], uint16_t file_amount, uint8_t flags ) { EWF_FILE_HEADER file_header; LIBEWF_INTERNAL_HANDLE *internal_handle = NULL; char *error_string = NULL; uint32_t iterator = 0; uint16_t fields_segment = 0; int file_descriptor = 0; if( ( flags == LIBEWF_OPEN_READ ) || ( flags == LIBEWF_OPEN_READ_WRITE ) ) { /* 1 additional entry required because * entry [ 0 ] is not used for reading */ internal_handle = libewf_internal_handle_alloc( ( file_amount + 1 ), flags ); if( internal_handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to create handle.\n" ); return( NULL ); } if( internal_handle->segment_table == NULL ) { LIBEWF_WARNING_PRINT( "libewf_open: invalid handle - missing segment table.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } for( iterator = 0; iterator < file_amount; iterator++ ) { file_descriptor = libewf_common_open( filenames[ iterator ], flags ); if( file_descriptor == -1 ) { error_string = libewf_common_strerror( errno ); if( error_string == NULL ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to open file: %s.\n", filenames[ iterator ] ); } else { LIBEWF_WARNING_PRINT( "libewf_open: unable to open file: %s with error: %s.\n", filenames[ iterator ], error_string ); libewf_common_free( error_string ); } libewf_internal_handle_free( internal_handle ); return( NULL ); } if( ewf_file_header_read( &file_header, file_descriptor ) <= -1 ) { LIBEWF_WARNING_PRINT( "libewf_open: invalid file header in: %s.\n", filenames[ iterator ] ); libewf_internal_handle_free( internal_handle ); return( NULL ); } if( ewf_file_header_check_signature( file_header.signature ) == 0 ) { LIBEWF_WARNING_PRINT( "libewf_open: file signature does not match.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } if( libewf_endian_convert_16bit( &fields_segment, file_header.fields_segment ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to convert fields segment value.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } LIBEWF_VERBOSE_PRINT( "libewf_open: added segment file: %s with file descriptor: %d with segment number: %" PRIu16 ".\n", filenames[ iterator ], file_descriptor, fields_segment ); if( libewf_segment_table_set_filename( internal_handle->segment_table, fields_segment, filenames[ iterator ], libewf_common_string_length( filenames[ iterator ] ) ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to set filename in segment table.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } if( libewf_segment_table_set_file_descriptor( internal_handle->segment_table, fields_segment, file_descriptor ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to set file descriptor in segment table.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } } if( libewf_read_build_index( internal_handle ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to create index.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } } else if( flags == LIBEWF_OPEN_WRITE ) { /* Allocate 2 entries * entry [ 0 ] is used for the base filename */ internal_handle = libewf_internal_handle_alloc( 1, flags ); if( internal_handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to create handle.\n" ); return( NULL ); } if( internal_handle->segment_table == NULL ) { LIBEWF_WARNING_PRINT( "libewf_open: invalid handle - missing segment table.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } if( libewf_segment_table_set_filename( internal_handle->segment_table, 0, filenames[ iterator ], libewf_common_string_length( filenames[ iterator ] ) ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to set filename in segment table.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } if( libewf_segment_table_set_file_descriptor( internal_handle->segment_table, 0, -1 ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_open: unable to set file descriptor in segment table.\n" ); libewf_internal_handle_free( internal_handle ); return( NULL ); } } else { LIBEWF_WARNING_PRINT( "libewf_open: unsupported flags.\n" ); return( NULL ); } LIBEWF_VERBOSE_PRINT( "libewf_open: open successful.\n" ); return( (LIBEWF_HANDLE *) internal_handle ); }
/* Reads media data from the last current into a buffer * This function swaps byte pairs if specified * Returns the amount of bytes read, or -1 on error */ ssize_t libewf_read_buffer( LIBEWF_HANDLE *handle, void *buffer, size_t size ) { LIBEWF_INTERNAL_HANDLE *internal_handle = NULL; ssize_t chunk_read_count = 0; ssize_t total_read_count = 0; size_t chunk_data_size = 0; int8_t chunk_cache_used = 0; if( handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: invalid handle.\n" ); return( -1 ); } internal_handle = (LIBEWF_INTERNAL_HANDLE *) handle; if( internal_handle->chunk_cache == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: invalid chunk cache.\n" ); return( -1 ); } if( internal_handle->index_build == 0 ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: index was not build.\n" ); return( -1 ); } if( buffer == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: invalid buffer.\n" ); return( -1 ); } if( buffer == internal_handle->chunk_cache->compressed ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: invalid buffer - chunk cache compressed cannot be used as buffer.\n"); return( -1 ); } if( size > (size_t) SSIZE_MAX ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: invalid size value exceeds maximum.\n" ); return( -1 ); } LIBEWF_VERBOSE_PRINT( "libewf_read_buffer: reading size: %zu.\n", size ); /* Check if chunk cache passthrough is used * if the chunk cache is used as the chunk data buffer */ chunk_cache_used = (int8_t) ( buffer == internal_handle->chunk_cache->data ); /* Reallocate the chunk cache if the chunk size is not the default chunk size * this prevents multiple reallocations of the chunk cache */ chunk_data_size = internal_handle->media->chunk_size + EWF_CRC_SIZE; if( chunk_data_size > internal_handle->chunk_cache->allocated_size ) { LIBEWF_VERBOSE_PRINT( "libewf_read_buffer: reallocating chunk data size: %zu.\n", chunk_data_size ); if( libewf_internal_handle_chunk_cache_realloc( internal_handle, chunk_data_size ) == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: unable to reallocate chunk cache.\n"); return( -1 ); } /* Adjust chunk data buffer if necessary */ if( ( chunk_cache_used == 1 ) && ( buffer != internal_handle->chunk_cache->data ) ) { buffer = (void *) internal_handle->chunk_cache->data; } } while( size > 0 ) { chunk_read_count = libewf_read_chunk( internal_handle, internal_handle->current_chunk, internal_handle->current_chunk_offset, (void *) &( (uint8_t *) buffer )[ total_read_count ], size ); /* libewf_read_chunk could relocate the chunk cache * correct buffer is chunk cache passthrough is used */ if( ( chunk_cache_used == 1 ) && ( buffer != internal_handle->chunk_cache->data ) ) { buffer = (void *) internal_handle->chunk_cache->data; } if( chunk_read_count <= -1 ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: unable to read data from chunk.\n" ); return( -1 ); } else if( chunk_read_count == 0 ) { break; } size -= chunk_read_count; total_read_count += chunk_read_count; internal_handle->current_chunk_offset += (uint32_t) chunk_read_count; if( internal_handle->current_chunk_offset == internal_handle->media->chunk_size ) { internal_handle->current_chunk_offset = 0; internal_handle->current_chunk += 1; } else if( internal_handle->current_chunk_offset > internal_handle->media->chunk_size ) { LIBEWF_WARNING_PRINT( "libewf_read_buffer: invalid current chunk offset.\n" ); return( -1 ); } } return( total_read_count ); }
/* Builds the index (section list and offset table) from the input files * Returns 1 if successful, or -1 on error */ int8_t libewf_read_build_index( LIBEWF_INTERNAL_HANDLE *internal_handle ) { EWF_SECTION *last_section = NULL; uint16_t segment_number = 0; if( internal_handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_build_index: invalid handle.\n" ); return( -1 ); } if( internal_handle->index_build != 0 ) { LIBEWF_WARNING_PRINT( "libewf_read_build_index: index has already been build.\n" ); return( -1 ); } if( libewf_internal_handle_read_initialize( internal_handle ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_build_index: unable to initialize read values in handle.\n" ); return( -1 ); } for( segment_number = 1; segment_number < internal_handle->segment_table->amount; segment_number++ ) { if( last_section != NULL ) { libewf_common_free( last_section ); } LIBEWF_VERBOSE_PRINT( "libewf_read_build_index: building index for segment number: %" PRIu32 ".\n", segment_number ); last_section = libewf_read_sections_from_segment( internal_handle, segment_number ); } /* Check to see if the done section has been found */ if( last_section == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_build_index: invalid last section.\n" ); return( -1 ); } else if( ewf_section_is_type_done( last_section ) == 0 ) { LIBEWF_WARNING_PRINT( "libewf_read_build_index: unable to find the last segment file (done section).\n" ); libewf_common_free( last_section ); return( -1 ); } libewf_common_free( last_section ); /* Determine the EWF file format */ if( libewf_internal_handle_determine_format( internal_handle ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_build_index: unable to determine file format.\n" ); } LIBEWF_VERBOSE_PRINT( "libewf_read_build_index: index successful build.\n" ); /* Calculate the media size */ internal_handle->media->media_size = (uint64_t) internal_handle->media->amount_of_sectors * (uint64_t) internal_handle->media->bytes_per_sector; /* Flag that the index was build */ internal_handle->index_build = 1; return( 1 ); }
/* Reads a certain chunk of data from the segment file(s) * Will read until the requested size is filled or the entire chunk is read * This function swaps byte pairs if specified * Returns the amount of bytes read, 0 if no bytes can be read, or -1 on error */ ssize_t libewf_read_chunk( LIBEWF_INTERNAL_HANDLE *internal_handle, uint32_t chunk, uint32_t chunk_offset, void *buffer, size_t size ) { EWF_CHUNK *chunk_data = NULL; EWF_CHUNK *chunk_read = NULL; EWF_CRC calculated_crc = 0; EWF_CRC stored_crc = 0; #if defined( HAVE_WIDE_CHARACTER_TYPE ) && defined( HAVE_WIDE_CHARACTER_SUPPORT_FUNCTIONS ) wchar_t *filename = NULL; #else char *filename = NULL; #endif ssize_t chunk_read_count = 0; ssize_t crc_read_count = 0; size_t chunk_data_size = 0; size_t bytes_available = 0; size_t md5_hash_size = 0; uint16_t segment_number = 0; int8_t chunk_cache_used = 0; int8_t result = 0; uint8_t percentage = 0; int file_descriptor = 0; if( internal_handle == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid handle.\n" ); return( -1 ); } if( internal_handle->media == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid handle - missing subhandle media.\n" ); return( -1 ); } if( internal_handle->read == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid handle - missing subhandle read.\n" ); return( -1 ); } if( internal_handle->offset_table == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid handle - missing offset table.\n" ); return( -1 ); } if( internal_handle->segment_table == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid handle - missing segment table.\n" ); return( -1 ); } if( internal_handle->chunk_cache == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid chunk cache.\n" ); return( -1 ); } if( internal_handle->index_build == 0 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: index was not build.\n" ); return( -1 ); } if( buffer == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid buffer.\n" ); return( -1 ); } if( buffer == internal_handle->chunk_cache->compressed ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid buffer - same as chunk cache compressed.\n" ); return( -1 ); } /* Check if the chunk is available */ if( chunk >= internal_handle->offset_table->amount ) { return( 0 ); } /* Check if the chunk is cached */ if( ( internal_handle->chunk_cache->chunk != chunk ) || ( internal_handle->chunk_cache->cached == 0 ) ) { file_descriptor = internal_handle->offset_table->file_descriptor[ chunk ]; segment_number = internal_handle->offset_table->segment_number[ chunk ]; /* Check if chunk cache passthrough is used * if the chunk cache is used as the chunk data buffer */ chunk_cache_used = (int8_t) ( buffer == internal_handle->chunk_cache->data ); /* Determine the size of the chunk including the CRC */ chunk_data_size = internal_handle->offset_table->size[ chunk ]; /* Make sure the chunk cache is large enough */ if( chunk_data_size > internal_handle->chunk_cache->allocated_size ) { LIBEWF_VERBOSE_PRINT( "libewf_read_chunk: reallocating chunk data size: %zu.\n", chunk_data_size ); if( libewf_internal_handle_chunk_cache_realloc( internal_handle, chunk_data_size ) == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to reallocate chunk cache.\n"); return( -1 ); } /* Adjust chunk data buffer if necessary */ if( ( chunk_cache_used == 1 ) && ( buffer != internal_handle->chunk_cache->data ) ) { buffer = internal_handle->chunk_cache->data; } } chunk_data = internal_handle->chunk_cache->data; #ifdef HAVE_BUFFER_PASSTHROUGH /* Determine if the chunk data should be put directly in the buffer */ if( ( buffer != internal_handle->chunk_cache->data ) && ( chunk_offset == 0 ) && ( size >= (uint64_t) internal_handle->media->chunk_size ) ) { chunk_data = (EWF_CHUNK *) buffer; } #endif /* Determine if the chunk data should be directly read into chunk data buffer * or to use the intermediate storage for a compressed chunk */ if( internal_handle->offset_table->compressed[ chunk ] == 1 ) { chunk_read = internal_handle->chunk_cache->compressed; } else { chunk_read = chunk_data; } /* If buffer passthrough is used the CRC is read seperately */ if( ( chunk_read != internal_handle->chunk_cache->compressed ) && ( chunk_read != internal_handle->chunk_cache->data ) ) { chunk_data_size -= EWF_CRC_SIZE; } /* Make sure the file offset is in the right place */ if( libewf_seek_chunk( internal_handle, chunk ) <= -1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to seek chunk.\n"); return( -1 ); } /* Read the chunk data */ chunk_read_count = ewf_chunk_read( chunk_read, file_descriptor, chunk_data_size ); if( chunk_read_count <= -1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to read chunk.\n"); return( -1 ); } internal_handle->segment_table->file_offset[ segment_number ] += (off_t) chunk_read_count; if( ( internal_handle->offset_table->last > 0 ) && ( chunk > 0 ) ) { percentage = (uint8_t) ( (uint32_t) ( chunk * 100 ) / internal_handle->offset_table->last ); } /* Determine if the chunk is not compressed */ if( internal_handle->offset_table->compressed[ chunk ] == 0 ) { LIBEWF_VERBOSE_PRINT( "libewf_read_chunk: chunk %" PRIu32 " of %" PRIu32 " (%" PRIu8 "%%) is UNCOMPRESSED.\n", ( chunk + 1 ), internal_handle->offset_table->amount, percentage ); /* If buffer passthrough is used the CRC needs to be read seperately */ if( ( chunk_read != internal_handle->chunk_cache->compressed ) && ( chunk_read != internal_handle->chunk_cache->data ) ) { crc_read_count = ewf_crc_read( &stored_crc, file_descriptor ); if( crc_read_count != (ssize_t) EWF_CRC_SIZE ) { #if defined( HAVE_WIDE_CHARACTER_TYPE ) && defined( HAVE_WIDE_CHARACTER_SUPPORT_FUNCTIONS ) filename = libewf_segment_table_get_wide_filename( internal_handle->segment_table, segment_number ); #else filename = libewf_segment_table_get_filename( internal_handle->segment_table, segment_number ); #endif if( filename == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: error reading CRC of chunk: %" PRIu32 " from segment file: %" PRIu16 ".\n", chunk, segment_number ); } else { #if defined( HAVE_WIDE_CHARACTER_TYPE ) && defined( HAVE_WIDE_CHARACTER_SUPPORT_FUNCTIONS ) LIBEWF_WARNING_PRINT( "libewf_read_chunk: error reading CRC of chunk: %" PRIu32 " from segment file: %" PRIu16 " (%ls).\n", chunk, segment_number, filename ); #else LIBEWF_WARNING_PRINT( "libewf_read_chunk: error reading CRC of chunk: %" PRIu32 " from segment file: %" PRIu16 " (%s).\n", chunk, segment_number, filename ); #endif } return( -1 ); } internal_handle->segment_table->file_offset[ segment_number ] += (off_t) crc_read_count; } /* Otherwise convert the last 4 bytes of the chunk cache */ else { if( libewf_endian_convert_32bit( &stored_crc, &chunk_data[ chunk_data_size - EWF_CRC_SIZE ] ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to convert stored CRC value.\n" ); return( -1 ); } chunk_data_size -= (uint32_t) EWF_CRC_SIZE; } /* Calculate the CRC */ if( ewf_crc_calculate( &calculated_crc, (uint8_t *) chunk_data, chunk_data_size, 1 ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to calculate CRC.\n" ); return( -1 ); } LIBEWF_VERBOSE_PRINT( "libewf_read_chunk: CRC for chunk: %" PRIu32 " (in file: %" PRIu32 ", calculated: %" PRIu32 ").\n", ( chunk + 1 ), stored_crc, calculated_crc ); if( stored_crc != calculated_crc ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: CRC does not match for chunk: %" PRIu32 " (in file: %" PRIu32 ", calculated: %" PRIu32 ").\n", chunk, stored_crc, calculated_crc ); #ifdef WIPEONERROR /* The chunk data is wiped */ if( libewf_common_memset( chunk_read, 0, internal_handle->media->chunk_size ) == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to wipe chunk data.\n" ); return( -1 ); } #endif if( libewf_internal_handle_add_crc_error_chunk( internal_handle, chunk ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to set CRC error chunk.\n" ); return( -1 ); } if( internal_handle->error_tollerance < LIBEWF_ERROR_TOLLERANCE_COMPENSATE ) { return( -1 ); } } } /* Determine if the chunk is compressed */ else if( internal_handle->offset_table->compressed[ chunk ] == 1 ) { chunk_data_size = internal_handle->media->chunk_size + EWF_CRC_SIZE; result = ewf_chunk_uncompress( chunk_data, &chunk_data_size, chunk_read, chunk_read_count ); LIBEWF_VERBOSE_PRINT( "libewf_read_chunk: chunk %" PRIu32 " of %" PRIu32 " (%" PRIu8 "%%) is COMPRESSED.\n", ( chunk + 1 ), internal_handle->offset_table->amount, percentage ); if( result != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to uncompress chunk.\n" ); #ifdef WIPEONERROR /* The chunk data is wiped */ if( libewf_common_memset( chunk_data, 0, internal_handle->media->chunk_size ) == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to wipe chunk data.\n" ); return( -1 ); } #endif if( libewf_internal_handle_add_crc_error_chunk( internal_handle, chunk ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to set CRC error chunk.\n" ); return( -1 ); } if( internal_handle->error_tollerance < LIBEWF_ERROR_TOLLERANCE_COMPENSATE ) { return( -1 ); } } } else { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unsupported compressed chunk value.\n" ); return( -1 ); } /* Check if the chunk was processed in the MD5 hash calculation */ if( internal_handle->offset_table->hashed[ chunk ] != 1 ) { if( libewf_md5_update( &internal_handle->md5_context, chunk_data, chunk_data_size ) != 1 ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to update MD5 context.\n" ); if( internal_handle->error_tollerance < LIBEWF_ERROR_TOLLERANCE_COMPENSATE ) { return( -1 ); } } internal_handle->offset_table->hashed[ chunk ] = 1; } /* Check if the last chunk was processed and finalize MD5 hash */ if( chunk == ( internal_handle->offset_table->amount - 1 ) ) { md5_hash_size = EWF_DIGEST_HASH_SIZE_MD5; if( internal_handle->calculated_md5_hash == NULL ) { internal_handle->calculated_md5_hash = (EWF_DIGEST_HASH *) libewf_common_alloc( md5_hash_size ); if( internal_handle->calculated_md5_hash == NULL ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to created calculated MD5 hash.\n" ); return( -1 ); } } if( ( libewf_md5_finalize( &internal_handle->md5_context, internal_handle->calculated_md5_hash, &md5_hash_size ) != 1 ) || ( md5_hash_size != EWF_DIGEST_HASH_SIZE_MD5 ) ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to finalize MD5 context.\n" ); if( internal_handle->error_tollerance < LIBEWF_ERROR_TOLLERANCE_COMPENSATE ) { return( -1 ); } } } /* Swap bytes after MD5 calculation */ if( ( internal_handle->swap_byte_pairs == 1 ) && ( libewf_endian_swap_byte_pairs( chunk_data, chunk_data_size ) != 1 ) ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to swap byte pairs.\n" ); return( -1 ); } /* Flag that the chunk was cached */ if( chunk_data == internal_handle->chunk_cache->data ) { internal_handle->chunk_cache->chunk = chunk; internal_handle->chunk_cache->amount = chunk_data_size; internal_handle->chunk_cache->offset = 0; internal_handle->chunk_cache->cached = 1; } } else { chunk_data = internal_handle->chunk_cache->data; chunk_data_size = internal_handle->chunk_cache->amount; } /* Determine the available amount of data within the cached chunk */ if( chunk_data_size < chunk_offset ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: chunk offset exceeds amount of bytes available in chunk.\n" ); return( -1 ); } bytes_available = chunk_data_size - chunk_offset; /* Correct the available amount of bytes is larger than the requested amount of bytes */ if( (uint64_t) bytes_available > size ) { bytes_available = (uint32_t) size; } if( bytes_available > (uint64_t) INT32_MAX ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: invalid available amount of bytes only values below 2^32 are supported.\n" ); return( -1 ); } /* If the data was read into the chunk cache copy it to the buffer */ if( chunk_data == internal_handle->chunk_cache->data ) { /* Copy the relevant data to buffer */ if( ( bytes_available > 0 ) && ( libewf_common_memcpy( buffer, &chunk_data[ chunk_offset ], bytes_available ) == NULL ) ) { LIBEWF_WARNING_PRINT( "libewf_read_chunk: unable to set chunk data in buffer.\n" ); return( -1 ); } } return( (int32_t) bytes_available ); }