diff --git a/trunk/libxmount_morphing/libxmount_morphing_raid/libxmount_morphing_raid.c b/trunk/libxmount_morphing/libxmount_morphing_raid/libxmount_morphing_raid.c index 37f7884..718af0c 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_raid/libxmount_morphing_raid.c +++ b/trunk/libxmount_morphing/libxmount_morphing_raid/libxmount_morphing_raid.c @@ -1,374 +1,374 @@ /******************************************************************************* * xmount Copyright (c) 2008-2017 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_raid.h" #define LOG_DEBUG(...) { \ LIBXMOUNT_LOG_DEBUG(p_raid_handle->debug,__VA_ARGS__); \ } /******************************************************************************* * 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 "raid0\0\0"; } /* * LibXmount_Morphing_GetFunctions */ void LibXmount_Morphing_GetFunctions(ts_LibXmountMorphingFunctions *p_functions) { p_functions->CreateHandle=&RaidCreateHandle; p_functions->DestroyHandle=&RaidDestroyHandle; p_functions->Morph=&RaidMorph; p_functions->Size=&RaidSize; p_functions->Read=&RaidRead; p_functions->OptionsHelp=&RaidOptionsHelp; p_functions->OptionsParse=&RaidOptionsParse; p_functions->GetInfofileContent=&RaidGetInfofileContent; p_functions->GetErrorMessage=&RaidGetErrorMessage; p_functions->FreeBuffer=&RaidFreeBuffer; } /******************************************************************************* * Private ******************************************************************************/ /* * RaidCreateHandle */ static int RaidCreateHandle(void **pp_handle, const char *p_format, uint8_t debug) { pts_RaidHandle p_raid_handle; // Alloc new handle p_raid_handle=malloc(sizeof(ts_RaidHandle)); if(p_raid_handle==NULL) return RAID_MEMALLOC_FAILED; // Init handle values p_raid_handle->debug=debug; p_raid_handle->input_images_count=0; p_raid_handle->chunk_size=RAID_DEFAULT_CHUNKSIZE; p_raid_handle->chunks_per_image=0; p_raid_handle->p_input_functions=NULL; p_raid_handle->morphed_image_size=0; LOG_DEBUG("Created new LibXmount_Morphing_Raid handle\n"); // Return new handle *pp_handle=p_raid_handle; return RAID_OK; } /* * RaidDestroyHandle */ static int RaidDestroyHandle(void **pp_handle) { pts_RaidHandle p_raid_handle=(pts_RaidHandle)*pp_handle; LOG_DEBUG("Destroying LibXmount_Morphing_Raid handle\n"); // Free handle free(p_raid_handle); *pp_handle=NULL; return RAID_OK; } /* * RaidMorph */ static int RaidMorph(void *p_handle, pts_LibXmountMorphingInputFunctions p_input_functions) { pts_RaidHandle p_raid_handle=(pts_RaidHandle)p_handle; int ret; uint64_t input_image_size; uint64_t chunks_per_image; LOG_DEBUG("Initializing LibXmount_Morphing_Raid\n"); // Set input functions and get image count p_raid_handle->p_input_functions=p_input_functions; if(p_raid_handle-> p_input_functions-> ImageCount(&p_raid_handle->input_images_count)!=0) { return RAID_CANNOT_GET_IMAGECOUNT; } // Calculate chunks per image for(uint64_t i=0;iinput_images_count;i++) { ret=p_raid_handle-> p_input_functions-> Size(i,&input_image_size); if(ret!=0) return RAID_CANNOT_GET_IMAGESIZE; chunks_per_image=input_image_size/p_raid_handle->chunk_size; LOG_DEBUG("Image %" PRIu64 " can hold a maximum of %" PRIu64 " chunks of %" PRIu32 " bytes\n", i, chunks_per_image, p_raid_handle->chunk_size); // The smallest image determines how many chunks are availbale on all images if(p_raid_handle->chunks_per_image==0) { p_raid_handle->chunks_per_image=chunks_per_image; } else if(chunks_per_imagechunks_per_image) { p_raid_handle->chunks_per_image=chunks_per_image; } } LOG_DEBUG("Smallest image holds %" PRIu64 " chunks of %" PRIu32 " bytes\n", p_raid_handle->chunks_per_image, p_raid_handle->chunk_size); // Calculate total raid capacity based on smallest disk p_raid_handle->morphed_image_size= p_raid_handle->chunks_per_image* p_raid_handle->chunk_size*p_raid_handle->input_images_count; LOG_DEBUG("Total raid capacity is %" PRIu64 " bytes\n", p_raid_handle->morphed_image_size); return RAID_OK; } /* * RaidSize */ static int RaidSize(void *p_handle, uint64_t *p_size) { *p_size=((pts_RaidHandle)(p_handle))->morphed_image_size; return RAID_OK; } /* * RaidRead */ static int RaidRead(void *p_handle, char *p_buf, off_t offset, size_t count, size_t *p_read) { pts_RaidHandle p_raid_handle=(pts_RaidHandle)p_handle; uint64_t cur_chunk; uint64_t cur_image; off_t cur_chunk_offset; off_t cur_image_offset; size_t cur_count; int ret; size_t 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_raid_handle->morphed_image_size || offset+count>p_raid_handle->morphed_image_size) { return RAID_READ_BEYOND_END_OF_IMAGE; } // Calculate starting chunk, and chunk offset cur_chunk=offset/p_raid_handle->chunk_size; cur_chunk_offset=offset-(cur_chunk*p_raid_handle->chunk_size); // Init p_read *p_read=0; while(count!=0) { // Calculate image and image offset to read from cur_image=cur_chunk%p_raid_handle->input_images_count; cur_image_offset= (cur_chunk/p_raid_handle->input_images_count)*p_raid_handle->chunk_size; // Calculate how many bytes to read from current chunk if(cur_chunk_offset+count>p_raid_handle->chunk_size) { cur_count=p_raid_handle->chunk_size-cur_chunk_offset; } else { cur_count=count; } LOG_DEBUG("Reading %zu bytes at offset %zu from image %" PRIu64 " (chunk %" PRIu64 ")\n", cur_count, cur_image_offset+cur_chunk_offset, cur_image, cur_chunk); // Read bytes ret=p_raid_handle->p_input_functions-> Read(cur_image, p_buf, cur_image_offset+cur_chunk_offset, cur_count, &read); if(ret!=0 || read!=cur_count) return RAID_CANNOT_READ_DATA; p_buf+=cur_count; cur_chunk_offset=0; count-=cur_count; cur_chunk++; (*p_read)+=cur_count; } return RAID_OK; } /* * RaidOptionsHelp */ static int RaidOptionsHelp(const char **pp_help) { int ok; char *p_buf; ok=asprintf(&p_buf, " raid_chunksize : Specify the chunk size to use in bytes. " "Defaults to 524288 (512k).\n"); if(ok<0 || p_buf==NULL) { *pp_help=NULL; return RAID_MEMALLOC_FAILED; } *pp_help=p_buf; return RAID_OK; } /* * RaidOptionsParse */ static int RaidOptionsParse(void *p_handle, uint32_t options_count, const pts_LibXmountOptions *pp_options, const char **pp_error) { pts_RaidHandle p_raid_handle=(pts_RaidHandle)p_handle; int ok; uint32_t uint32value; char *p_buf; for(uint32_t i=0;ip_key,"raid_chunksize")) { + if(strcmp(pp_options[i]->p_key,"raid_chunksize")==0) { // Convert value to uint32 uint32value=StrToUint32(pp_options[i]->p_value,&ok); if(ok==0 || uint32value==0) { // Conversion failed, generate error message and return ok=asprintf(&p_buf, "Unable to parse value '%s' of '%s' as valid 32bit number", pp_options[i]->p_value, pp_options[i]->p_key); if(ok<0 || *pp_error==NULL) { *pp_error=NULL; return RAID_MEMALLOC_FAILED; } *pp_error=p_buf; return RAID_CANNOT_PARSE_OPTION; } LOG_DEBUG("Setting chunk size to %" PRIu32 " bytes\n",uint32value); // Conversion ok, save value and mark option as valid p_raid_handle->chunk_size=uint32value; pp_options[i]->valid=1; continue; } } return RAID_OK; } /* * RaidGetInfofileContent */ static int RaidGetInfofileContent(void *p_handle, const char **pp_info_buf) { pts_RaidHandle p_raid_handle=(pts_RaidHandle)p_handle; int ret; char *p_buf; ret=asprintf(&p_buf, "Simulating RAID level 0 over %" PRIu64 " disks.\n" "Chunk size: %" PRIu32 " bytes\n" "Chunks per disk: %" PRIu64 "\n" "Total capacity: %" PRIu64 " bytes (%0.3f GiB)\n", p_raid_handle->input_images_count, p_raid_handle->chunk_size, p_raid_handle->chunks_per_image, p_raid_handle->morphed_image_size, p_raid_handle->morphed_image_size/(1024.0*1024.0*1024.0)); if(ret<0 || *pp_info_buf==NULL) return RAID_MEMALLOC_FAILED; *pp_info_buf=p_buf; return RAID_OK; } /* * RaidGetErrorMessage */ static const char* RaidGetErrorMessage(int err_num) { switch(err_num) { case RAID_MEMALLOC_FAILED: return "Unable to allocate memory"; break; case RAID_CANNOT_GET_IMAGECOUNT: return "Unable to get input image count"; break; case RAID_CANNOT_GET_IMAGESIZE: return "Unable to get input image size"; break; case RAID_READ_BEYOND_END_OF_IMAGE: return "Unable to read data: Attempt to read past EOF"; break; case RAID_CANNOT_READ_DATA: return "Unable to read data"; break; case RAID_CANNOT_PARSE_OPTION: return "Unable to parse library option"; break; default: return "Unknown error"; } } /* * RaidFreeBuffer */ static void RaidFreeBuffer(void *p_buf) { free(p_buf); }