diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c index 984dd99..4b73c86 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c @@ -1,629 +1,652 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include #include #include "../libxmount_morphing.h" #include "libxmount_morphing_unallocated.h" /******************************************************************************* * LibXmount_Morphing API implementation ******************************************************************************/ /* * LibXmount_Morphing_GetApiVersion */ uint8_t LibXmount_Morphing_GetApiVersion() { return LIBXMOUNT_MORPHING_API_VERSION; } /* * LibXmount_Morphing_GetSupportedFormats */ const char* LibXmount_Morphing_GetSupportedTypes() { return "unallocated\0\0"; } /* * LibXmount_Morphing_GetFunctions */ void LibXmount_Morphing_GetFunctions(ts_LibXmountMorphingFunctions *p_functions) { p_functions->CreateHandle=&UnallocatedCreateHandle; p_functions->DestroyHandle=&UnallocatedDestroyHandle; p_functions->Morph=&UnallocatedMorph; p_functions->Size=&UnallocatedSize; p_functions->Read=&UnallocatedRead; p_functions->OptionsHelp=&UnallocatedOptionsHelp; p_functions->OptionsParse=&UnallocatedOptionsParse; p_functions->GetInfofileContent=&UnallocatedGetInfofileContent; p_functions->GetErrorMessage=&UnallocatedGetErrorMessage; p_functions->FreeBuffer=&UnallocatedFreeBuffer; } /******************************************************************************* * Private ******************************************************************************/ /* * UnallocatedCreateHandle */ static int UnallocatedCreateHandle(void **pp_handle, const char *p_format, uint8_t debug) { pts_UnallocatedHandle p_unallocated_handle; - // Alloc new handle - p_unallocated_handle=malloc(sizeof(ts_UnallocatedHandle)); + // Alloc new handle. Using calloc in order to set everything to 0x00 + p_unallocated_handle=calloc(1,sizeof(ts_UnallocatedHandle)); if(p_unallocated_handle==NULL) return UNALLOCATED_MEMALLOC_FAILED; // Init handle values p_unallocated_handle->debug=debug; p_unallocated_handle->fs_type=UnallocatedFsType_Unknown; - // DEBUG - //p_unallocated_handle->fs_type=UnallocatedFsType_HfsPlus; - p_unallocated_handle->p_input_functions=NULL; - p_unallocated_handle->morphed_image_size=0; - p_unallocated_handle->hfsplus.p_vh=NULL; - p_unallocated_handle->hfsplus.p_alloc_file=NULL; - p_unallocated_handle->hfsplus.free_block_map_size=0; - p_unallocated_handle->hfsplus.p_free_block_map=NULL; LOG_DEBUG("Created new LibXmount_Morphing_Unallocated handle\n"); // Return new handle *pp_handle=p_unallocated_handle; return UNALLOCATED_OK; } /* * UnallocatedDestroyHandle */ static int UnallocatedDestroyHandle(void **pp_handle) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)*pp_handle; LOG_DEBUG("Destroying LibXmount_Morphing_Unallocated handle\n"); + // TODO: Return if p_unallocated_handle==NULL + // Free fs data switch(p_unallocated_handle->fs_type) { case UnallocatedFsType_HfsPlus: { - if(p_unallocated_handle->hfsplus.p_vh!=NULL) - free(p_unallocated_handle->hfsplus.p_vh); - if(p_unallocated_handle->hfsplus.p_alloc_file!=NULL) - free(p_unallocated_handle->hfsplus.p_alloc_file); - if(p_unallocated_handle->hfsplus.p_free_block_map!=NULL) - free(p_unallocated_handle->hfsplus.p_free_block_map); + if(p_unallocated_handle->p_hfsplus_vh!=NULL) + free(p_unallocated_handle->p_hfsplus_vh); break; } case UnallocatedFsType_Unknown: default: break; } - // Free handle + // Free handle values and handle + if(p_unallocated_handle->p_free_block_map!=NULL) + free(p_unallocated_handle->p_free_block_map); free(p_unallocated_handle); *pp_handle=NULL; return UNALLOCATED_OK; } /* * UnallocatedMorph */ static int UnallocatedMorph( void *p_handle, pts_LibXmountMorphingInputFunctions p_input_functions) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; uint64_t input_images_count; int ret; LOG_DEBUG("Initializing LibXmount_Morphing_Unallocated\n"); - // Make sure unallocated_fs was given - if(p_unallocated_handle->fs_type==UnallocatedFsType_Unknown) { - return UNALLOCATED_NO_FS_SPECIFIED; - } - // Set input functions and get image count p_unallocated_handle->p_input_functions=p_input_functions; if(p_unallocated_handle-> p_input_functions-> ImageCount(&input_images_count)!=0) { return UNALLOCATED_CANNOT_GET_IMAGECOUNT; } // Make sure there is exactly one input image if(input_images_count==0 || input_images_count>1) { return UNALLOCATED_WRONG_INPUT_IMAGE_COUNT; } - // Extract unallocated blocks from input image + // Read filesystem header switch(p_unallocated_handle->fs_type) { case UnallocatedFsType_HfsPlus: { // Read HFS+ VH - ret=UnallocatedReadHfsPlusHeader(p_unallocated_handle); + ret=ReadHfsPlusHeader(p_unallocated_handle); if(ret!=UNALLOCATED_OK) return ret; + break; + } + case UnallocatedFsType_Unknown: { + // Filesystem wasn't specified. Try to autodetect it. This will also read + // its header. + ret=DetectFs(p_unallocated_handle); + if(ret!=UNALLOCATED_OK) return ret; + break; + } + default: { + return UNALLOCATED_INTERNAL_ERROR; + } + } + + // Extract unallocated blocks from input image + switch(p_unallocated_handle->fs_type) { + case UnallocatedFsType_HfsPlus: { + uint8_t *p_alloc_file; + // Read HFS+ alloc file - ret=UnallocatedReadHfsPlusAllocFile(p_unallocated_handle); + ret=ReadHfsPlusAllocFile(p_unallocated_handle,&p_alloc_file); if(ret!=UNALLOCATED_OK) return ret; + // Build free block map - ret=UnallocatedBuildHfsPlusBlockMap(p_unallocated_handle); + ret=BuildHfsPlusBlockMap(p_unallocated_handle,p_alloc_file); + // Free alloc file before checking for errors as it needs to be freed + // either way + free(p_alloc_file); if(ret!=UNALLOCATED_OK) return ret; - // Calculate morphed image size - p_unallocated_handle->morphed_image_size= - p_unallocated_handle->hfsplus.p_vh->block_size* - p_unallocated_handle->hfsplus.free_block_map_size; + break; } case UnallocatedFsType_Unknown: default: - return UNALLOCATED_UNSUPPORTED_FS_SPECIFIED; + return UNALLOCATED_INTERNAL_ERROR; } + // Calculate morphed image size + p_unallocated_handle->morphed_image_size=p_unallocated_handle->block_size* + p_unallocated_handle->free_block_map_size; + LOG_DEBUG("Total size of unallocated blocks is %" PRIu64 " bytes\n", p_unallocated_handle->morphed_image_size); return UNALLOCATED_OK; } /* * UnallocatedSize */ static int UnallocatedSize(void *p_handle, uint64_t *p_size) { *p_size=((pts_UnallocatedHandle)(p_handle))->morphed_image_size; return UNALLOCATED_OK; } /* * UnallocatedRead */ static int UnallocatedRead(void *p_handle, char *p_buf, off_t offset, size_t count, size_t *p_read) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; + uint64_t cur_block; + off_t cur_block_offset; + off_t cur_image_offset; + size_t cur_count; int ret; + size_t bytes_read; LOG_DEBUG("Reading %zu bytes at offset %zu from morphed image\n", count, offset); // Make sure read parameters are within morphed image bounds if(offset>=p_unallocated_handle->morphed_image_size || offset+count>p_unallocated_handle->morphed_image_size) { return UNALLOCATED_READ_BEYOND_END_OF_IMAGE; } - // Read data - switch(p_unallocated_handle->fs_type) { - case UnallocatedFsType_HfsPlus: { - ret=UnallocatedReadHfsPlusBlock(p_unallocated_handle, - p_buf, - offset, - count, - p_read); - if(ret!=UNALLOCATED_OK) return ret; - break; + // Calculate starting block and block offset + cur_block=offset/p_unallocated_handle->block_size; + cur_block_offset=offset-(cur_block*p_unallocated_handle->block_size); + + // Init p_read + *p_read=0; + + while(count!=0) { + // Calculate input image offset to read from + cur_image_offset= + p_unallocated_handle->p_free_block_map[cur_block]+cur_block_offset; + + // Calculate how many bytes to read from current block + if(cur_block_offset+count>p_unallocated_handle->block_size) { + cur_count=p_unallocated_handle->block_size-cur_block_offset; + } else { + cur_count=count; } - case UnallocatedFsType_Unknown: - default: - return UNALLOCATED_UNSUPPORTED_FS_SPECIFIED; + + LOG_DEBUG("Reading %zu bytes at offset %zu (block %" PRIu64 ")\n", + cur_count, + cur_image_offset+cur_block_offset, + cur_block); + + // Read bytes + ret=p_unallocated_handle->p_input_functions-> + Read(0, + p_buf, + cur_image_offset+cur_block_offset, + cur_count, + &bytes_read); + if(ret!=0 || bytes_read!=cur_count) return UNALLOCATED_CANNOT_READ_DATA; + + p_buf+=cur_count; + cur_block_offset=0; + count-=cur_count; + cur_block++; + (*p_read)+=cur_count; } return UNALLOCATED_OK; } /* * UnallocatedOptionsHelp */ static int UnallocatedOptionsHelp(const char **pp_help) { int ok; char *p_buf; ok=asprintf(&p_buf, " unallocated_fs : Specify the filesystem to extract " - "unallocated blocks from. Supported filesystems are: 'hfs+'\n"); + "unallocated blocks from. Supported filesystems are: " + "'hfs+'. Default: autodetect.\n"); if(ok<0 || p_buf==NULL) { *pp_help=NULL; return UNALLOCATED_MEMALLOC_FAILED; } *pp_help=p_buf; return UNALLOCATED_OK; } /* * UnallocatedOptionsParse */ static int UnallocatedOptionsParse(void *p_handle, uint32_t options_count, const pts_LibXmountOptions *pp_options, const char **pp_error) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; int ok; char *p_buf; for(uint32_t i=0;ip_key,"unallocated_fs")==0) { if(strcmp(pp_options[i]->p_value,"hfs+")==0) { p_unallocated_handle->fs_type=UnallocatedFsType_HfsPlus; } else { ok=asprintf(&p_buf, "Unsupported filesystem '%s' specified", pp_options[i]->p_value); if(ok<0 || p_buf==NULL) { *pp_error=NULL; return UNALLOCATED_MEMALLOC_FAILED; } *pp_error=p_buf; return UNALLOCATED_UNSUPPORTED_FS_SPECIFIED; } LOG_DEBUG("Setting fs to %s\n",pp_options[i]->p_value); pp_options[i]->valid=1; } } return UNALLOCATED_OK; } /* * UnallocatedGetInfofileContent */ static int UnallocatedGetInfofileContent(void *p_handle, const char **pp_info_buf) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; - pts_UnallocatedHfsPlusData p_hfs_data=&(p_unallocated_handle->hfsplus); - int ret; - char *p_buf; + int ret=-1; + char *p_buf=NULL; + + switch(p_unallocated_handle->fs_type) { + case UnallocatedFsType_HfsPlus: { + pts_HfsPlusVH p_hfsplus_vh=p_unallocated_handle->p_hfsplus_vh; + ret=asprintf(&p_buf, + "HFS+ VH signature: 0x%04X\n" + "HFS+ VH version: %" PRIu16 "\n" + "HFS+ block size: %" PRIu32 " bytes\n" + "HFS+ total blocks: %" PRIu32 "\n" + "HFS+ free blocks: %" PRIu32 "\n" + "HFS+ allocation file size: %" PRIu64 " bytes\n" + "HFS+ allocation file blocks: %" PRIu32 "\n" + "Discovered free blocks: %" PRIu64 "\n" + "Total unallocated size: %" PRIu64 " bytes (%0.3f GiB)\n", + p_hfsplus_vh->signature, + p_hfsplus_vh->version, + p_hfsplus_vh->block_size, + p_hfsplus_vh->total_blocks, + p_hfsplus_vh->free_blocks, + p_hfsplus_vh->alloc_file_size, + p_hfsplus_vh->alloc_file_total_blocks, + p_unallocated_handle->free_block_map_size, + p_unallocated_handle->free_block_map_size* + p_unallocated_handle->block_size, + (p_unallocated_handle->free_block_map_size* + p_unallocated_handle->block_size)/(1024.0*1024.0*1024.0)); + break; + } + case UnallocatedFsType_Unknown: + default: + return UNALLOCATED_INTERNAL_ERROR; + } - ret=asprintf(&p_buf, - "HFS+ VH signature: 0x%04X\n" - "HFS+ VH version: %" PRIu16 "\n" - "HFS+ block size: %" PRIu32 " bytes\n" - "HFS+ total blocks: %" PRIu32 "\n" - "HFS+ free blocks: %" PRIu32 "\n" - "HFS+ allocation file size: %" PRIu64 " bytes\n" - "HFS+ allocation file blocks: %" PRIu32 "\n" - "Discovered free blocks: %" PRIu64 "\n" - "Total unallocated size: %" PRIu64 " bytes (%0.3f GiB)\n", - p_hfs_data->p_vh->signature, - p_hfs_data->p_vh->version, - p_hfs_data->p_vh->block_size, - p_hfs_data->p_vh->total_blocks, - p_hfs_data->p_vh->free_blocks, - p_hfs_data->p_vh->alloc_file_size, - p_hfs_data->p_vh->alloc_file_total_blocks, - p_hfs_data->free_block_map_size, - p_hfs_data->free_block_map_size*p_hfs_data->p_vh->block_size, - (p_hfs_data->free_block_map_size*p_hfs_data->p_vh->block_size)/ - (1024.0*1024.0*1024.0)); - if(ret<0 || *pp_info_buf==NULL) return UNALLOCATED_MEMALLOC_FAILED; + // Check if asprintf worked + if(ret<0 || p_buf==NULL) return UNALLOCATED_MEMALLOC_FAILED; *pp_info_buf=p_buf; return UNALLOCATED_OK; } /* * UnallocatedGetErrorMessage */ static const char* UnallocatedGetErrorMessage(int err_num) { switch(err_num) { case UNALLOCATED_MEMALLOC_FAILED: return "Unable to allocate memory"; break; - case UNALLOCATED_NO_FS_SPECIFIED: - return "No filesystem specified using option unallocated_fs"; + case UNALLOCATED_NO_SUPPORTED_FS_DETECTED: + return "Unable to detect a supported file system"; break; case UNALLOCATED_UNSUPPORTED_FS_SPECIFIED: return "Unsupported fs specified"; + break; + case UNALLOCATED_INTERNAL_ERROR: + return "Internal error"; + break; case UNALLOCATED_CANNOT_GET_IMAGECOUNT: return "Unable to get input image count"; break; case UNALLOCATED_WRONG_INPUT_IMAGE_COUNT: return "Only 1 input image is supported"; break; case UNALLOCATED_CANNOT_GET_IMAGESIZE: return "Unable to get input image size"; break; case UNALLOCATED_READ_BEYOND_END_OF_IMAGE: return "Unable to read data: Attempt to read past EOF"; break; case UNALLOCATED_CANNOT_READ_DATA: return "Unable to read data"; break; case UNALLOCATED_CANNOT_PARSE_OPTION: return "Unable to parse library option"; break; case UNALLOCATED_CANNOT_READ_HFSPLUS_HEADER: return "Unable to read HFS+ volume header"; break; case UNALLOCATED_INVALID_HFSPLUS_HEADER: return "Found invalid HFS+ volume header"; break; case UNALLOCATED_CANNOT_READ_HFSPLUS_ALLOC_FILE: return "Unable to read HFS+ allocation file"; break; case UNALLOCATED_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS: return "HFS+ allocation file has more then 8 extends. " "This is unsupported"; break; default: return "Unknown error"; } } /* * UnallocatedFreeBuffer */ static void UnallocatedFreeBuffer(void *p_buf) { free(p_buf); } /******************************************************************************* * Private helper functions ******************************************************************************/ /* - * UnallocatedReadHfsPlusHeader + * DetectFs */ -static int UnallocatedReadHfsPlusHeader( - pts_UnallocatedHandle p_unallocated_handle) -{ - pts_UnallocatedHfsPlusData p_hfs_data=&(p_unallocated_handle->hfsplus); +static int DetectFs(pts_UnallocatedHandle p_unallocated_handle) { + LOG_DEBUG("Trying to autodetect fs\n"); + + // Probe all supported filesystems by trying to read their headers + if(ReadHfsPlusHeader(p_unallocated_handle)==UNALLOCATED_OK) { + LOG_DEBUG("Detected HFS+ fs\n"); + p_unallocated_handle->fs_type=UnallocatedFsType_HfsPlus; + return UNALLOCATED_OK; + } + + LOG_DEBUG("Unable to autodetect fs\n"); + + return UNALLOCATED_NO_SUPPORTED_FS_DETECTED; +} + +/******************************************************************************* + * Private helper functions (HFS) + ******************************************************************************/ +/* + * ReadHfsPlusHeader + */ +static int ReadHfsPlusHeader(pts_UnallocatedHandle p_unallocated_handle) { + pts_HfsPlusVH p_hfsplus_vh; int ret; size_t bytes_read; - pts_UnallocatedHfsPlusExtend p_extend; + pts_HfsPlusExtend p_extend; - LOG_DEBUG("Reading HFS+ volume header\n"); + LOG_DEBUG("Trying to read HFS+ volume header\n"); // Alloc buffer for header - p_hfs_data->p_vh=calloc(1,sizeof(ts_UnallocatedHfsPlusVH)); - if(p_hfs_data->p_vh==NULL) return UNALLOCATED_MEMALLOC_FAILED; + p_hfsplus_vh=calloc(1,sizeof(ts_HfsPlusVH)); + if(p_hfsplus_vh==NULL) return UNALLOCATED_MEMALLOC_FAILED; // Read VH from input image ret=p_unallocated_handle-> p_input_functions-> Read(0, - (char*)(p_hfs_data->p_vh), - UNALLOCATED_HFSPLUS_VH_OFFSET, - sizeof(ts_UnallocatedHfsPlusVH), + (char*)(p_hfsplus_vh), + HFSPLUS_VH_OFFSET, + sizeof(ts_HfsPlusVH), &bytes_read); - if(ret!=0 || bytes_read!=sizeof(ts_UnallocatedHfsPlusVH)) { - free(p_hfs_data->p_vh); - p_hfs_data->p_vh=NULL; + if(ret!=0 || bytes_read!=sizeof(ts_HfsPlusVH)) { + free(p_hfsplus_vh); + p_hfsplus_vh=NULL; return UNALLOCATED_CANNOT_READ_HFSPLUS_HEADER; } // Convert VH to host endianness - p_hfs_data->p_vh->signature=be16toh(p_hfs_data->p_vh->signature); - p_hfs_data->p_vh->version=be16toh(p_hfs_data->p_vh->version); - p_hfs_data->p_vh->block_size=be32toh(p_hfs_data->p_vh->block_size); - p_hfs_data->p_vh->total_blocks=be32toh(p_hfs_data->p_vh->total_blocks); - p_hfs_data->p_vh->free_blocks=be32toh(p_hfs_data->p_vh->free_blocks); - p_hfs_data->p_vh->alloc_file_size=be64toh(p_hfs_data->p_vh->alloc_file_size); - p_hfs_data->p_vh->alloc_file_clump_size= - be32toh(p_hfs_data->p_vh->alloc_file_clump_size); - p_hfs_data->p_vh->alloc_file_total_blocks= - be32toh(p_hfs_data->p_vh->alloc_file_total_blocks); + p_hfsplus_vh->signature=be16toh(p_hfsplus_vh->signature); + p_hfsplus_vh->version=be16toh(p_hfsplus_vh->version); + p_hfsplus_vh->block_size=be32toh(p_hfsplus_vh->block_size); + p_hfsplus_vh->total_blocks=be32toh(p_hfsplus_vh->total_blocks); + p_hfsplus_vh->free_blocks=be32toh(p_hfsplus_vh->free_blocks); + p_hfsplus_vh->alloc_file_size=be64toh(p_hfsplus_vh->alloc_file_size); + p_hfsplus_vh->alloc_file_clump_size= + be32toh(p_hfsplus_vh->alloc_file_clump_size); + p_hfsplus_vh->alloc_file_total_blocks= + be32toh(p_hfsplus_vh->alloc_file_total_blocks); for(int i=0;i<8;i++) { - p_extend=&(p_hfs_data->p_vh->alloc_file_extends[i]); + p_extend=&(p_hfsplus_vh->alloc_file_extends[i]); p_extend->start_block=be32toh(p_extend->start_block); p_extend->block_count=be32toh(p_extend->block_count); } - LOG_DEBUG("HFS+ VH signature: 0x%04X\n",p_hfs_data->p_vh->signature); - LOG_DEBUG("HFS+ VH version: %" PRIu16 "\n",p_hfs_data->p_vh->version); - LOG_DEBUG("HFS+ block size: %" PRIu32 " bytes\n",p_hfs_data->p_vh->block_size); - LOG_DEBUG("HFS+ total blocks: %" PRIu32 "\n",p_hfs_data->p_vh->total_blocks); - LOG_DEBUG("HFS+ free blocks: %" PRIu32 "\n",p_hfs_data->p_vh->free_blocks); + LOG_DEBUG("HFS+ VH signature: 0x%04X\n",p_hfsplus_vh->signature); + LOG_DEBUG("HFS+ VH version: %" PRIu16 "\n",p_hfsplus_vh->version); + LOG_DEBUG("HFS+ block size: %" PRIu32 " bytes\n",p_hfsplus_vh->block_size); + LOG_DEBUG("HFS+ total blocks: %" PRIu32 "\n",p_hfsplus_vh->total_blocks); + LOG_DEBUG("HFS+ free blocks: %" PRIu32 "\n",p_hfsplus_vh->free_blocks); LOG_DEBUG("HFS+ allocation file size: %" PRIu64 " bytes\n", - p_hfs_data->p_vh->alloc_file_size); + p_hfsplus_vh->alloc_file_size); LOG_DEBUG("HFS+ allocation file blocks: %" PRIu32 "\n", - p_hfs_data->p_vh->alloc_file_total_blocks); + p_hfsplus_vh->alloc_file_total_blocks); // Check header signature and version - if(p_hfs_data->p_vh->signature!=UNALLOCATED_HFSPLUS_VH_SIGNATURE || - p_hfs_data->p_vh->version!=UNALLOCATED_HFSPLUS_VH_VERSION) + if(p_hfsplus_vh->signature!=HFSPLUS_VH_SIGNATURE || + p_hfsplus_vh->version!=HFSPLUS_VH_VERSION) { - free(p_hfs_data->p_vh); - p_hfs_data->p_vh=NULL; + free(p_hfsplus_vh); + p_hfsplus_vh=NULL; return UNALLOCATED_INVALID_HFSPLUS_HEADER; } + LOG_DEBUG("HFS+ volume header read successfully\n"); + + p_unallocated_handle->p_hfsplus_vh=p_hfsplus_vh; return UNALLOCATED_OK; } /* - * UnallocatedReadHfsPlusAllocFile + * ReadHfsPlusAllocFile */ -static int UnallocatedReadHfsPlusAllocFile( - pts_UnallocatedHandle p_unallocated_handle) +static int ReadHfsPlusAllocFile(pts_UnallocatedHandle p_unallocated_handle, + uint8_t **pp_alloc_file) { - pts_UnallocatedHfsPlusData p_hfs_data=&(p_unallocated_handle->hfsplus); - pts_UnallocatedHfsPlusExtend p_extend; + pts_HfsPlusVH p_hfsplus_vh=p_unallocated_handle->p_hfsplus_vh; + uint8_t *p_alloc_file; + pts_HfsPlusExtend p_extend; int ret; char *p_buf; size_t bytes_read; uint64_t total_bytes_read=0; - LOG_DEBUG("Reading HFS+ allocation file\n"); + LOG_DEBUG("Trying to read HFS+ allocation file\n"); // Alloc buffer for file - p_hfs_data->p_alloc_file=calloc(1,p_hfs_data->p_vh->alloc_file_size); - if(p_hfs_data->p_alloc_file==NULL) return UNALLOCATED_MEMALLOC_FAILED; + p_alloc_file=calloc(1,p_hfsplus_vh->alloc_file_size); + if(p_alloc_file==NULL) return UNALLOCATED_MEMALLOC_FAILED; // Loop over extends and read data - p_buf=(char*)(p_hfs_data->p_alloc_file); + p_buf=(char*)(p_alloc_file); for(int i=0;i<8;i++) { - p_extend=&(p_hfs_data->p_vh->alloc_file_extends[i]); + p_extend=&(p_hfsplus_vh->alloc_file_extends[i]); // If start_block and block_count are zero, we parsed last extend if(p_extend->start_block==0 && p_extend->block_count==0) break; LOG_DEBUG("Extend %d contains %" PRIu32 " block(s) starting with block %" PRIu32 "\n", i, p_extend->block_count, p_extend->start_block); // Read data for(uint32_t ii=0;iiblock_count;ii++) { LOG_DEBUG("Reading %" PRIu32 " bytes from block %" PRIu32 " at offset %" PRIu64 "\n", - p_hfs_data->p_vh->block_size, + p_hfsplus_vh->block_size, p_extend->start_block+ii, (uint64_t)((p_extend->start_block+ii)* - p_hfs_data->p_vh->block_size)); + p_hfsplus_vh->block_size)); ret=p_unallocated_handle-> p_input_functions-> Read(0, p_buf, - (p_extend->start_block+ii)*p_hfs_data->p_vh->block_size, - p_hfs_data->p_vh->block_size, + (p_extend->start_block+ii)*p_hfsplus_vh->block_size, + p_hfsplus_vh->block_size, &bytes_read); - if(ret!=0 || bytes_read!=p_hfs_data->p_vh->block_size) { - free(p_hfs_data->p_alloc_file); - p_hfs_data->p_alloc_file=NULL; + if(ret!=0 || bytes_read!=p_hfsplus_vh->block_size) { + free(p_alloc_file); return UNALLOCATED_CANNOT_READ_HFSPLUS_ALLOC_FILE; } - p_buf+=p_hfs_data->p_vh->block_size; - total_bytes_read+=p_hfs_data->p_vh->block_size; + p_buf+=p_hfsplus_vh->block_size; + total_bytes_read+=p_hfsplus_vh->block_size; } } - // Alloc files with more then 8 extends aren't supported yet - if(total_bytes_read!=p_hfs_data->p_vh->alloc_file_size) { - free(p_hfs_data->p_alloc_file); - p_hfs_data->p_alloc_file=NULL; + // Alloc files with more than 8 extends aren't supported yet + if(total_bytes_read!=p_hfsplus_vh->alloc_file_size) { + free(p_alloc_file); return UNALLOCATED_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS; } + LOG_DEBUG("HFS+ allocation file read successfully\n"); + + *pp_alloc_file=p_alloc_file; return UNALLOCATED_OK; } /* - * UnallocatedBuildHfsPlusBlockMap + * BuildHfsPlusBlockMap */ -static int UnallocatedBuildHfsPlusBlockMap( - pts_UnallocatedHandle p_unallocated_handle) +static int BuildHfsPlusBlockMap(pts_UnallocatedHandle p_unallocated_handle, + uint8_t *p_alloc_file) { - pts_UnallocatedHfsPlusData p_hfs_data=&(p_unallocated_handle->hfsplus); + pts_HfsPlusVH p_hfsplus_vh=p_unallocated_handle->p_hfsplus_vh; LOG_DEBUG("Searching unallocated HFS+ blocks\n"); // Save offset of every unallocated block in block map for(uint32_t cur_block=0; - cur_blockp_vh->total_blocks; + cur_blocktotal_blocks; cur_block++) { - if((p_hfs_data->p_alloc_file[cur_block/8] & (1<<(7-(cur_block%8))))==0) { - p_hfs_data->p_free_block_map=realloc(p_hfs_data->p_free_block_map, - (p_hfs_data->free_block_map_size+1)* - sizeof(uint64_t)); - if(p_hfs_data->p_free_block_map==NULL) { - p_hfs_data->free_block_map_size=0; + if((p_alloc_file[cur_block/8] & (1<<(7-(cur_block%8))))==0) { + p_unallocated_handle->p_free_block_map= + realloc(p_unallocated_handle->p_free_block_map, + (p_unallocated_handle->free_block_map_size+1)*sizeof(uint64_t)); + if(p_unallocated_handle->p_free_block_map==NULL) { + p_unallocated_handle->free_block_map_size=0; return UNALLOCATED_MEMALLOC_FAILED; } - p_hfs_data->p_free_block_map[p_hfs_data->free_block_map_size]= - cur_block*p_hfs_data->p_vh->block_size; - p_hfs_data->free_block_map_size++; + p_unallocated_handle-> + p_free_block_map[p_unallocated_handle->free_block_map_size]= + cur_block*p_hfsplus_vh->block_size; + p_unallocated_handle->free_block_map_size++; } } LOG_DEBUG("Found %" PRIu64 " unallocated HFS+ blocks\n", - p_hfs_data->free_block_map_size); + p_unallocated_handle->free_block_map_size); - if(p_hfs_data->p_vh->free_blocks!=p_hfs_data->free_block_map_size) { + if(p_hfsplus_vh->free_blocks!=p_unallocated_handle->free_block_map_size) { LOG_WARNING("According to VH, there should be %" PRIu64 " unallocated blocks but I found %" PRIu64 "\n", - p_hfs_data->p_vh->free_blocks, - p_hfs_data->free_block_map_size); - } - - return UNALLOCATED_OK; -} - -/* - * UnallocatedReadHfsPlusBlock - */ -static int UnallocatedReadHfsPlusBlock( - pts_UnallocatedHandle p_unallocated_handle, - char *p_buf, - off_t offset, - size_t count, - size_t *p_read) -{ - pts_UnallocatedHfsPlusData p_hfs_data=&(p_unallocated_handle->hfsplus); - uint64_t cur_block; - off_t cur_block_offset; - off_t cur_image_offset; - size_t cur_count; - int ret; - size_t bytes_read; - - // Calculate starting block and block offset - cur_block=offset/p_hfs_data->p_vh->block_size; - cur_block_offset=offset-(cur_block*p_hfs_data->p_vh->block_size); - - // Init p_read - *p_read=0; - - while(count!=0) { - // Calculate input image offset to read from - cur_image_offset=p_hfs_data->p_free_block_map[cur_block]+cur_block_offset; - - // Calculate how many bytes to read from current block - if(cur_block_offset+count>p_hfs_data->p_vh->block_size) { - cur_count=p_hfs_data->p_vh->block_size-cur_block_offset; - } else { - cur_count=count; - } - - LOG_DEBUG("Reading %zu bytes at offset %zu (block %" PRIu64 ")\n", - cur_count, - cur_image_offset+cur_block_offset, - cur_block); - - // Read bytes - ret=p_unallocated_handle->p_input_functions-> - Read(0, - p_buf, - cur_image_offset+cur_block_offset, - cur_count, - &bytes_read); - if(ret!=0 || bytes_read!=cur_count) return UNALLOCATED_CANNOT_READ_DATA; - - p_buf+=cur_count; - cur_block_offset=0; - count-=cur_count; - cur_block++; - (*p_read)+=cur_count; + p_hfsplus_vh->free_blocks, + p_unallocated_handle->free_block_map_size); } + // Save used block size in handle and return + p_unallocated_handle->block_size=p_hfsplus_vh->block_size; return UNALLOCATED_OK; } diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.h b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.h index 20d4611..17aa879 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.h +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.h @@ -1,151 +1,162 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef LIBXMOUNT_MORPHING_UNALLOCATED_H #define LIBXMOUNT_MORPHING_UNALLOCATED_H #define LOG_ERROR(...) { \ LibXmount_Morphing_LogMessage("ERROR", \ (char*)__FUNCTION__, \ __LINE__, \ __VA_ARGS__); \ } #define LOG_WARNING(...) { \ LibXmount_Morphing_LogMessage("WARNING", \ (char*)__FUNCTION__, \ __LINE__, \ __VA_ARGS__); \ } #define LOG_DEBUG(...) { \ if(p_unallocated_handle->debug==1) \ LibXmount_Morphing_LogMessage("DEBUG", \ (char*)__FUNCTION__, \ __LINE__, \ __VA_ARGS__); \ } /******************************************************************************* * Enums, type defs, etc... ******************************************************************************/ // Error codes enum { UNALLOCATED_OK=0, UNALLOCATED_MEMALLOC_FAILED, - UNALLOCATED_NO_FS_SPECIFIED, + UNALLOCATED_NO_SUPPORTED_FS_DETECTED, UNALLOCATED_UNSUPPORTED_FS_SPECIFIED, + UNALLOCATED_INTERNAL_ERROR, UNALLOCATED_CANNOT_GET_IMAGECOUNT, UNALLOCATED_WRONG_INPUT_IMAGE_COUNT, UNALLOCATED_CANNOT_GET_IMAGESIZE, UNALLOCATED_READ_BEYOND_END_OF_IMAGE, UNALLOCATED_CANNOT_READ_DATA, UNALLOCATED_CANNOT_PARSE_OPTION, UNALLOCATED_CANNOT_READ_HFSPLUS_HEADER, UNALLOCATED_INVALID_HFSPLUS_HEADER, UNALLOCATED_CANNOT_READ_HFSPLUS_ALLOC_FILE, UNALLOCATED_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS }; // Supported fs types typedef enum e_UnallocatedFsType { UnallocatedFsType_Unknown=0, - UnallocatedFsType_HfsPlus + UnallocatedFsType_HfsPlus, + UnallocatedFsType_Fat, + UnallocatedFsType_Fat12, + UnallocatedFsType_Fat16, + UnallocatedFsType_Fat32 } te_UnallocatedFsType; // HFS+ extend -typedef struct s_UnallocatedHfsPlusExtend { +typedef struct s_HfsPlusExtend { uint32_t start_block; uint32_t block_count; -} __attribute__ ((packed)) ts_UnallocatedHfsPlusExtend, *pts_UnallocatedHfsPlusExtend; +} __attribute__ ((packed)) ts_HfsPlusExtend, *pts_HfsPlusExtend; // Needed parts of the HFS+ volume header -#define UNALLOCATED_HFSPLUS_VH_OFFSET 1024 -#define UNALLOCATED_HFSPLUS_VH_SIGNATURE 0x482b //"H+" -#define UNALLOCATED_HFSPLUS_VH_VERSION 4 -typedef struct s_UnallocatedHfsPlusVH { +#define HFSPLUS_VH_OFFSET 1024 +#define HFSPLUS_VH_SIGNATURE 0x482b //"H+" +#define HFSPLUS_VH_VERSION 4 +typedef struct s_HfsPlusVH { uint16_t signature; // "H+" uint16_t version; // Currently 4 for HFS+ uint32_t unused01[9]; uint32_t block_size; uint32_t total_blocks; uint32_t free_blocks; uint32_t unused02[15]; uint64_t alloc_file_size; uint32_t alloc_file_clump_size; uint32_t alloc_file_total_blocks; - ts_UnallocatedHfsPlusExtend alloc_file_extends[8]; -} __attribute__ ((packed)) ts_UnallocatedHfsPlusVH, *pts_UnallocatedHfsPlusVH; + ts_HfsPlusExtend alloc_file_extends[8]; +} __attribute__ ((packed)) ts_HfsPlusVH, *pts_HfsPlusVH; // Needed data for HFS+ +/* typedef struct s_UnallocatedHfsPlusData { pts_UnallocatedHfsPlusVH p_vh; uint8_t *p_alloc_file; uint64_t free_block_map_size; uint64_t *p_free_block_map; } ts_UnallocatedHfsPlusData, *pts_UnallocatedHfsPlusData; +*/ // Handle typedef struct s_UnallocatedHandle { uint8_t debug; te_UnallocatedFsType fs_type; pts_LibXmountMorphingInputFunctions p_input_functions; + + uint64_t block_size; + uint64_t free_block_map_size; + uint64_t *p_free_block_map; uint64_t morphed_image_size; - ts_UnallocatedHfsPlusData hfsplus; + + union { + pts_HfsPlusVH p_hfsplus_vh; + + }; } ts_UnallocatedHandle, *pts_UnallocatedHandle; /******************************************************************************* * Forward declarations ******************************************************************************/ static int UnallocatedCreateHandle(void **pp_handle, const char *p_format, uint8_t debug); static int UnallocatedDestroyHandle(void **pp_handle); static int UnallocatedMorph( void *p_handle, pts_LibXmountMorphingInputFunctions p_input_functions); static int UnallocatedSize(void *p_handle, uint64_t *p_size); static int UnallocatedRead(void *p_handle, char *p_buf, off_t offset, size_t count, size_t *p_read); static int UnallocatedOptionsHelp(const char **pp_help); static int UnallocatedOptionsParse(void *p_handle, uint32_t options_count, const pts_LibXmountOptions *pp_options, const char **pp_error); static int UnallocatedGetInfofileContent(void *p_handle, const char **pp_info_buf); static const char* UnallocatedGetErrorMessage(int err_num); static void UnallocatedFreeBuffer(void *p_buf); // Helper functions -static int UnallocatedReadHfsPlusHeader( - pts_UnallocatedHandle p_unallocated_handle); -static int UnallocatedReadHfsPlusAllocFile( - pts_UnallocatedHandle p_unallocated_handle); -static int UnallocatedBuildHfsPlusBlockMap( - pts_UnallocatedHandle p_unallocated_handle); -static int UnallocatedReadHfsPlusBlock( - pts_UnallocatedHandle p_unallocated_handle, - char *p_buf, - off_t offset, - size_t count, - size_t *p_read); +static int DetectFs(pts_UnallocatedHandle p_unallocated_handle); + +// Helper functions for HFS +static int ReadHfsPlusHeader(pts_UnallocatedHandle p_unallocated_handle); +static int ReadHfsPlusAllocFile(pts_UnallocatedHandle p_unallocated_handle, + uint8_t **pp_alloc_file); +static int BuildHfsPlusBlockMap(pts_UnallocatedHandle p_unallocated_handle, + uint8_t *p_alloc_file); #endif // LIBXMOUNT_MORPHING_UNALLOCATED_H