diff --git a/src/xmount.c b/src/xmount.c index 94a2b27..b84d26a 100755 --- a/src/xmount.c +++ b/src/xmount.c @@ -1,1752 +1,1909 @@ /******************************************************************************* * xmount Copyright (c) 2008-2016 by Gillen Daniel * * * * xmount is a small tool to "fuse mount" various harddisk image formats as dd, * * vdi, vhd or vmdk files and enable virtual write access to them. * * * * 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 #include #include // For PRI* #include #include // For dlopen, dlclose, dlsym #include // For opendir, readdir, closedir #include #include #include // For fstat #include #ifdef HAVE_LINUX_FS_H #include // For SEEK_* ?? #endif #if !defined(__APPLE__) && defined(HAVE_GRP_H) && defined(HAVE_PWD_H) #include // For getgrnam, struct group #include // For getpwuid, struct passwd #endif #include #include // For time #include "xmount.h" #include "xmount_fuse.h" #include "md5.h" #include "macros.h" #include "../libxmount/libxmount.h" #define XMOUNT_COPYRIGHT_NOTICE \ "xmount v%s Copyright (c) 2008-2016 by Gillen Daniel " #define LOG_WARNING(...) { \ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \ } #define LOG_ERROR(...) { \ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \ } #define LOG_DEBUG(...) { \ LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \ } #define HASH_AMOUNT (1024*1024)*10 // Amount of data used to construct a // "unique" hash for every input image // (10MByte) /******************************************************************************* * Forward declarations ******************************************************************************/ /* * Misc */ static int InitResources(); static void FreeResources(); static void PrintUsage(char*); static void CheckFuseSettings(); static int ParseCmdLine(const int, char**); static int ExtractOutputFileNames(char*); static int CalculateInputImageHash(uint64_t*, uint64_t*); /* * Info file */ static int InitInfoFile(); /* * Lib related */ static int LoadLibs(); -static int FindMorphingLib(); static int FindOutputLib(); /* * Functions exported to LibXmount_Morphing */ static int LibXmount_Morphing_ImageCount(uint64_t*); static int LibXmount_Morphing_Size(uint64_t, uint64_t*); static int LibXmount_Morphing_Read(uint64_t, char*, off_t, size_t, size_t*); +static int LibXmount_Morphing_Write(uint64_t, char*, off_t, size_t, size_t*); /* * Functions exported to LibXmount_Output */ static int LibXmount_Output_Size(uint64_t*); static int LibXmount_Output_Read(char*, off_t, size_t, size_t*); static int LibXmount_Output_Write(char*, off_t, size_t, size_t*); /******************************************************************************* * Helper functions ******************************************************************************/ //! Print usage instructions (cmdline options etc..) /*! * \param p_prog_name Program name (argv[0]) */ static void PrintUsage(char *p_prog_name) { char *p_buf; int first; int ret; printf("\n" XMOUNT_COPYRIGHT_NOTICE "\n",XMOUNT_VERSION); printf("\nUsage:\n"); printf(" %s [fopts] \n\n",p_prog_name); printf("Options:\n"); printf(" fopts:\n"); printf(" -d : Enable FUSE's and xmount's debug mode.\n"); printf(" -h : Display this help message.\n"); printf(" -s : Run single threaded.\n"); printf(" -o no_allow_other : Disable automatic addition of FUSE's " "allow_other option.\n"); printf(" -o : Specify fuse mount options. Will also disable " "automatic addition of FUSE's allow_other option!\n"); printf("\n"); printf(" xopts:\n"); printf(" --cache : Enable virtual write support.\n"); printf(" specifies the cache file to use.\n"); printf(" --in : Input image format and source file(s). " "May be specified multiple times.\n"); printf(" can be "); #define PRINTUSAGE__LIST_SUPP_LIB_TYPES(fun,handle,ret_ok) do { \ first=1; \ if(fun(handle,&p_buf)==ret_ok) { \ while(*p_buf!='\0') { \ if(first==1) { \ printf("\"%s\"",p_buf); \ first=0; \ } else printf(", \"%s\"",p_buf); \ p_buf+=(strlen(p_buf)+1); \ } \ free(p_buf); \ } \ printf(".\n"); \ } while(0) // List supported input formats PRINTUSAGE__LIST_SUPP_LIB_TYPES(XmountInput_GetSupportedFormats, glob_xmount.h_input, e_XmountInput_Error_None); printf(" specifies the source file. If your image is split into " "multiple files, you have to specify them all!\n"); printf(" --inopts : Specify input library specific options.\n"); printf(" specifies a comma separated list of key=value options. " "See below for details.\n"); printf(" --info : Print out infos about used compiler and libraries.\n"); printf(" --morph : Morphing function to apply to input image(s). " "If not specified, defaults to \"combine\".\n"); printf(" can be "); // List supported morphing functions PRINTUSAGE__LIST_SUPP_LIB_TYPES(XmountMorphing_GetSupportedTypes, glob_xmount.h_morphing, e_XmountMorphError_None); printf(" --morphopts : Specify morphing library specific " "options.\n"); printf(" specifies a comma separated list of key=value options. " "See below for details.\n"); printf(" --offset : Move the output image data start bytes " "into the input image(s).\n"); printf(" --out : Output image format. If not specified, " "defaults to "); #ifdef __APPLE__ printf("\"dmg\".\n"); #else printf("\"raw\".\n"); #endif printf(" can be "); // List supported output formats first=1; for(uint32_t i=0;ip_supported_output_formats; while(*p_buf!='\0') { if(first==1) { printf("\"%s\"",p_buf); first=0; } else printf(", \"%s\"",p_buf); p_buf+=(strlen(p_buf)+1); } } printf(".\n"); printf(" --outopts : Specify output library specific " "options.\n"); printf(" --owcache : Same as --cache but overwrites " "existing cache file.\n"); printf(" --sizelimit : The data end of input image(s) is set to no " "more than bytes after the data start.\n"); printf(" --version : Same as --info.\n"); printf("\n"); printf(" mntp:\n"); printf(" Mount point where output image should be located.\n"); printf("\n"); printf("Infos:\n"); printf(" * One --in option and a mount point are mandatory!\n"); printf(" * If you specify --in multiple times, data from all images is " "morphed into one output image using the specified morphing " "function.\n"); printf(" * For VMDK emulation, you have to uncomment \"user_allow_other\" " "in /etc/fuse.conf or run xmount as root.\n"); printf("\n"); printf("Input / Morphing / Output library specific options:\n"); printf(" Input / Morphing libraries might support an own set of " "options to configure / tune their behaviour.\n"); printf(" Libraries supporting this feature (if any) and their " "options are listed below.\n"); printf("\n"); #define PRINTUSAGE__LIST_LIB_OPT_HELP(fun,handle,ret_ok) do { \ if(fun(handle,&p_buf)==ret_ok) { \ printf("%s",p_buf); \ free(p_buf); \ } \ } while(0) // List input, morphing and output lib options PRINTUSAGE__LIST_LIB_OPT_HELP(XmountInput_GetOptionsHelpText, glob_xmount.h_input, e_XmountInput_Error_None); PRINTUSAGE__LIST_LIB_OPT_HELP(XmountMorphing_GetOptionsHelpText, glob_xmount.h_morphing, e_XmountMorphError_None); for(uint32_t i=0;i lib_functions.OptionsHelp((const char**)&p_buf); if(ret!=0) { LOG_ERROR("Unable to get options help for library '%s': %s!\n", glob_xmount.output.pp_libs[i]->p_name, glob_xmount.output.pp_libs[i]-> lib_functions.GetErrorMessage(ret)); } if(p_buf==NULL) continue; printf(" - %s\n",glob_xmount.output.pp_libs[i]->p_name); printf("%s",p_buf); printf("\n"); } #undef PRINTUSAGE__LIST_LIB_OPT_HELP #undef PRINTUSAGE__LIST_SUPPORTED_LIB_OPTS } //! Check fuse settings /*! * Check if FUSE allows us to pass the -o allow_other parameter. This only works * if we are root or user_allow_other is set in /etc/fuse.conf. * * In addition, this function also checks if the user is member of the fuse * group which is generally needed to use fuse at all. */ static void CheckFuseSettings() { #if !defined(__APPLE__) && defined(HAVE_GRP_H) && defined(HAVE_PWD_H) struct group *p_group; struct passwd *p_passwd; #endif int found; FILE *h_fuse_conf; char line[256]; glob_xmount.may_set_fuse_allow_other=FALSE; if(geteuid()==0) { // Running as root, there should be no problems glob_xmount.may_set_fuse_allow_other=TRUE; return; } #if !defined(__APPLE__) && defined(HAVE_GRP_H) && defined(HAVE_PWD_H) // Check if a fuse group exists and if so, make sure user is a member of it. // Makes only sense on Linux because as far as I know osxfuse has no own group p_group=getgrnam("fuse"); if(p_group!=NULL) { // Get effective user name p_passwd=getpwuid(geteuid()); if(p_passwd==NULL) { printf("\nWARNING: Unable to determine your effective user name. If " "mounting works, you can ignore this message.\n\n"); return; } // Check if user is member of fuse group found=FALSE; while(*(p_group->gr_mem)!=NULL) { if(strcmp(*(p_group->gr_mem),p_passwd->pw_name)==0) { found=TRUE; break; } p_group->gr_mem++; } if(found==FALSE) { printf("\nWARNING: You are not a member of the \"fuse\" group. This will " "prevent you from mounting images using xmount. Please add " "yourself to the \"fuse\" group using the command " "\"sudo usermod -a -G fuse %s\" and reboot your system or " "execute xmount as root.\n\n", p_passwd->pw_name); return; } } else { printf("\nWARNING: Your system does not seem to have a \"fuse\" group. If " "mounting works, you can ignore this message.\n\n"); } #endif // Read FUSE's config file /etc/fuse.conf and check for set user_allow_other h_fuse_conf=(FILE*)FOPEN("/etc/fuse.conf","r"); if(h_fuse_conf!=NULL) { // Search conf file for set user_allow_others found=FALSE; while(fgets(line,sizeof(line),h_fuse_conf)!=NULL) { // TODO: This works as long as there is no other parameter beginning with // "user_allow_other" :) if(strncmp(line,"user_allow_other",16)==0) { found=TRUE; break; } } fclose(h_fuse_conf); if(found==TRUE) { glob_xmount.may_set_fuse_allow_other=TRUE; } else { printf("\nWARNING: FUSE will not allow other users nor root to access " "your virtual harddisk image. To change this behavior, please " "add \"user_allow_other\" to /etc/fuse.conf or execute xmount " "as root.\n\n"); } } else { printf("\nWARNING: Unable to open /etc/fuse.conf. If mounting works, you " "can ignore this message. If you encounter issues, please create " "the file and add a single line containing the string " "\"user_allow_other\" or execute xmount as root.\n\n"); return; } } //! Parse command line options /*! * \param argc Number of cmdline params * \param pp_argv Array containing cmdline params * \return TRUE on success, FALSE on error */ static int ParseCmdLine(const int argc, char **pp_argv) { int i=1; int FuseMinusOControl=TRUE; int FuseAllowOther=TRUE; int first; uint64_t buf; char *p_buf; char **pp_buf; int ret; te_XmountInput_Error input_ret=e_XmountInput_Error_None; te_XmountMorphError morph_ret=e_XmountMorphError_None; // add pp_argv[0] to FUSE's argv XMOUNT_MALLOC(glob_xmount.pp_fuse_argv,char**,sizeof(char*)); XMOUNT_STRSET(glob_xmount.pp_fuse_argv[0],pp_argv[0]); glob_xmount.fuse_argc=1; // Parse options while(i1 && *(pp_argv[i]+1)!='-') { // Options beginning with one - are mostly FUSE specific if(strcmp(pp_argv[i],"-d")==0) { // Enable FUSE's and xmount's debug mode XMOUNT_REALLOC(glob_xmount.pp_fuse_argv, char**, (glob_xmount.fuse_argc+1)*sizeof(char*)); XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc], pp_argv[i]) glob_xmount.fuse_argc++; glob_xmount.debug=TRUE; input_ret=XmountInput_EnableDebugging(glob_xmount.h_input); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to enable input debugging: Error code %u!\n", input_ret); return FALSE; } + morph_ret=XmountMorphing_EnableDebugging(glob_xmount.h_morphing); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Unable to enable morphing debugging: Error code %u!\n", + morph_ret); + return FALSE; + } } else if(strcmp(pp_argv[i],"-h")==0) { // Print help message PrintUsage(pp_argv[0]); exit(0); } else if(strcmp(pp_argv[i],"-o")==0) { // Next parameter specifies fuse mount options if((i+1)p_name); p_buf=glob_xmount.output.pp_libs[ii]->p_supported_output_formats; first=TRUE; while(*p_buf!='\0') { if(first) { printf("\"%s\"",p_buf); first=FALSE; } else printf(", \"%s\"",p_buf); p_buf+=(strlen(p_buf)+1); } printf("\n"); } printf("\n"); exit(0); } else { LOG_ERROR("Unknown command line option \"%s\"\n",pp_argv[i]); return FALSE; } } i++; } // Extract mountpoint if(i==(argc-1)) { XMOUNT_STRSET(glob_xmount.p_mountpoint,pp_argv[argc-1]) XMOUNT_REALLOC(glob_xmount.pp_fuse_argv, char**, (glob_xmount.fuse_argc+1)*sizeof(char*)); XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc], glob_xmount.p_mountpoint); glob_xmount.fuse_argc++; } else { LOG_ERROR("No mountpoint specified!\n") return FALSE; } if(FuseMinusOControl==TRUE) { // We control the -o flag, set subtype, fsname and allow_other options glob_xmount.fuse_argc+=2; XMOUNT_REALLOC(glob_xmount.pp_fuse_argv, char**, glob_xmount.fuse_argc*sizeof(char*)); XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-2],"-o"); XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1], "subtype=xmount"); if(glob_xmount.p_first_input_image_name!=NULL) { // Set name of first source file as fsname XMOUNT_STRAPP(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1], ",fsname='"); // If possible, use full path p_buf=realpath(glob_xmount.p_first_input_image_name,NULL); if(p_buf==NULL) { XMOUNT_STRSET(p_buf,glob_xmount.p_first_input_image_name); } // Make sure fsname does not include some forbidden chars for(uint32_t i=0;id_name); // Construct full path to found object p_library_path=realloc(p_library_path, base_library_path_len+strlen(p_dirent->d_name)+1); if(p_library_path==NULL) { LOG_ERROR("Couldn't allocate memory!\n"); exit(1); } strcpy(p_library_path+base_library_path_len,p_dirent->d_name); if(strncmp(p_dirent->d_name, XMOUNT_INPUT_LIBRARY_NAMING_SCHEME, strlen(XMOUNT_INPUT_LIBRARY_NAMING_SCHEME))==0) { // Found possible input lib. Try to load it input_ret=XmountInput_AddLibrary(glob_xmount.h_input,p_dirent->d_name); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to add input library '%s': Error code %u!\n", p_dirent->d_name, input_ret); continue; } } if(strncmp(p_dirent->d_name, XMOUNT_MORPHING_LIBRARY_NAMING_SCHEME, strlen(XMOUNT_MORPHING_LIBRARY_NAMING_SCHEME))==0) { // Found possible morphing lib. Try to load it morph_ret=XmountMorphing_AddLibrary(glob_xmount.h_morphing, p_dirent->d_name); if(morph_ret!=e_XmountMorphError_None) { LOG_ERROR("Unable to add morphing library '%s': Error code %u!\n", p_dirent->d_name, morph_ret); continue; } } if(strncmp(p_dirent->d_name,"libxmount_output_",17)==0) { // Found possible output lib. Try to load it LIBXMOUNT_LOAD(p_library_path); // Load library symbols LIBXMOUNT_LOAD_SYMBOL("LibXmount_Output_GetApiVersion", pfun_output_GetApiVersion); // Check library's API version if(pfun_output_GetApiVersion()!=LIBXMOUNT_OUTPUT_API_VERSION) { LOG_DEBUG("Failed! Wrong API version.\n"); LOG_ERROR("Unable to load output library '%s'. Wrong API version\n", p_library_path); dlclose(p_libxmount); continue; } LIBXMOUNT_LOAD_SYMBOL("LibXmount_Output_GetSupportedFormats", pfun_output_GetSupportedFormats); LIBXMOUNT_LOAD_SYMBOL("LibXmount_Output_GetFunctions", pfun_output_GetFunctions); // Construct new entry for our library list XMOUNT_MALLOC(p_output_lib,pts_OutputLib,sizeof(ts_OutputLib)); // Initialize lib_functions structure to NULL memset(&(p_output_lib->lib_functions), 0, sizeof(ts_LibXmountOutput_Functions)); // Set name and handle XMOUNT_STRSET(p_output_lib->p_name,p_dirent->d_name); p_output_lib->p_lib=p_libxmount; // Get and set supported types p_supported_formats=pfun_output_GetSupportedFormats(); supported_formats_len=0; p_buf=p_supported_formats; while(*p_buf!='\0') { supported_formats_len+=(strlen(p_buf)+1); p_buf+=(strlen(p_buf)+1); } supported_formats_len++; XMOUNT_MALLOC(p_output_lib->p_supported_output_formats, char*, supported_formats_len); memcpy(p_output_lib->p_supported_output_formats, p_supported_formats, supported_formats_len); // Get, set and check lib_functions pfun_output_GetFunctions(&(p_output_lib->lib_functions)); if(p_output_lib->lib_functions.CreateHandle==NULL || p_output_lib->lib_functions.DestroyHandle==NULL || p_output_lib->lib_functions.Transform==NULL || p_output_lib->lib_functions.Size==NULL || p_output_lib->lib_functions.Read==NULL || p_output_lib->lib_functions.Write==NULL || p_output_lib->lib_functions.OptionsHelp==NULL || p_output_lib->lib_functions.OptionsParse==NULL || p_output_lib->lib_functions.GetInfofileContent==NULL || p_output_lib->lib_functions.GetErrorMessage==NULL || p_output_lib->lib_functions.FreeBuffer==NULL) { LOG_DEBUG("Missing implemention of one or more functions in lib %s!\n", p_dirent->d_name); free(p_output_lib->p_supported_output_formats); free(p_output_lib->p_name); free(p_output_lib); dlclose(p_libxmount); continue; } // Add entry to the input library list XMOUNT_REALLOC(glob_xmount.output.pp_libs, pts_OutputLib*, sizeof(pts_OutputLib)* (glob_xmount.output.libs_count+1)); glob_xmount.output.pp_libs[glob_xmount.output.libs_count++]= p_output_lib; LOG_DEBUG("Output library '%s' loaded successfully\n",p_dirent->d_name); } else { LOG_DEBUG("Ignoring '%s'.\n",p_dirent->d_name); continue; } } #undef LIBXMOUNT_LOAD_SYMBOL #undef LIBXMOUNT_LOAD // Get loaded library counts input_ret=XmountInput_GetLibraryCount(glob_xmount.h_input,&input_lib_count); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to get input library count: Error code %u!\n",input_ret); return FALSE; } morph_ret=XmountMorphing_GetLibraryCount(glob_xmount.h_morphing, &morphing_lib_count); if(morph_ret!=e_XmountMorphError_None) { LOG_ERROR("Unable to get morphing library count: Error code %u!\n", input_ret); return FALSE; } LOG_DEBUG("A total of %u input libs, %u morphing libs and %u output libs " "were loaded.\n", input_lib_count, morphing_lib_count, glob_xmount.output.libs_count); free(p_library_path); closedir(p_dir); return ((input_lib_count>0 && morphing_lib_count>0 && glob_xmount.output.libs_count>0) ? TRUE : FALSE); } //! Search an appropriate output lib for the specified output format /*! * \return TRUE on success, FALSE on error */ static int FindOutputLib() { char *p_buf; LOG_DEBUG("Trying to find suitable library for output format '%s'.\n", glob_xmount.output.p_output_format); // Loop over all loaded output libs for(uint32_t i=0;ip_name); p_buf=glob_xmount.output.pp_libs[i]->p_supported_output_formats; while(*p_buf!='\0') { if(strcmp(p_buf,glob_xmount.output.p_output_format)==0) { // Library supports output type, set lib functions LOG_DEBUG("Output library '%s' pretends to handle that output format.\n", glob_xmount.output.pp_libs[i]->p_name); glob_xmount.output.p_functions= &(glob_xmount.output.pp_libs[i]->lib_functions); return TRUE; } p_buf+=(strlen(p_buf)+1); } } LOG_DEBUG("Couldn't find any suitable library.\n"); // No library supporting output format found return FALSE; } static int InitResources() { te_XmountInput_Error input_ret=e_XmountInput_Error_None; te_XmountMorphError morph_ret=e_XmountMorphError_None; // Args glob_xmount.args.overwrite_cache=FALSE; glob_xmount.args.p_cache_file=NULL; // Input input_ret=XmountInput_CreateHandle(&(glob_xmount.h_input)); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to create input handle: Error code %u!\n",input_ret); return FALSE; } // Morphing morph_ret=XmountMorphing_CreateHandle(&(glob_xmount.h_morphing), &LibXmount_Morphing_ImageCount, &LibXmount_Morphing_Size, &LibXmount_Morphing_Read, &LibXmount_Morphing_Write); - if(input_ret!=e_XmountMorphError_None) { + if(morph_ret!=e_XmountMorphError_None) { LOG_ERROR("Unable to create morphing handle: Error code %u!\n",morph_ret); return FALSE; } // Cache glob_xmount.h_cache=NULL; // Output glob_xmount.output.libs_count=0; glob_xmount.output.pp_libs=NULL; glob_xmount.output.p_output_format=NULL; glob_xmount.output.lib_params_count=0; glob_xmount.output.pp_lib_params=NULL; glob_xmount.output.p_handle=NULL; glob_xmount.output.p_functions=NULL; glob_xmount.output.input_functions.Size=&LibXmount_Output_Size; glob_xmount.output.input_functions.Read=&LibXmount_Output_Read; glob_xmount.output.input_functions.Write=&LibXmount_Output_Write; glob_xmount.output.image_size=0; glob_xmount.output.writable=FALSE; glob_xmount.output.p_virtual_image_path=NULL; glob_xmount.output.p_info_path=NULL; glob_xmount.output.p_info_file=NULL; // Misc data glob_xmount.debug=FALSE; glob_xmount.may_set_fuse_allow_other=FALSE; glob_xmount.fuse_argc=0; glob_xmount.pp_fuse_argv=NULL; glob_xmount.p_mountpoint=NULL; glob_xmount.p_first_input_image_name=NULL; glob_xmount.image_hash_lo=0; glob_xmount.image_hash_hi=0; return TRUE; } /* * FreeResources */ static void FreeResources() { int ret; - te_XmountCache_Error cache_ret=e_XmountCache_Error_None; te_XmountInput_Error input_ret=e_XmountInput_Error_None; + te_XmountMorphError morph_ret=e_XmountMorphError_None; + te_XmountCache_Error cache_ret=e_XmountCache_Error_None; LOG_DEBUG("Freeing all resources\n"); // Misc if(glob_xmount.p_first_input_image_name!=NULL) { XMOUNT_FREE(glob_xmount.p_first_input_image_name); } if(glob_xmount.pp_fuse_argv!=NULL) { for(int i=0;i DestroyHandle(&(glob_xmount.output.p_handle)); if(ret!=0) { LOG_ERROR("Unable to destroy output handle: %s!\n", glob_xmount.output.p_functions->GetErrorMessage(ret)); } } } if(glob_xmount.output.pp_lib_params!=NULL) { for(uint32_t i=0;ip_supported_output_formats!=NULL) free(glob_xmount.output.pp_libs[i]->p_supported_output_formats); if(glob_xmount.output.pp_libs[i]->p_lib!=NULL) dlclose(glob_xmount.output.pp_libs[i]->p_lib); if(glob_xmount.output.pp_libs[i]->p_name!=NULL) free(glob_xmount.output.pp_libs[i]->p_name); free(glob_xmount.output.pp_libs[i]); } free(glob_xmount.output.pp_libs); } if(glob_xmount.output.p_info_path!=NULL) free(glob_xmount.output.p_info_path); if(glob_xmount.output.p_info_file!=NULL) free(glob_xmount.output.p_info_file); if(glob_xmount.output.p_virtual_image_path!=NULL) free(glob_xmount.output.p_virtual_image_path); // Cache if(glob_xmount.h_cache!=NULL) { cache_ret=XmountCache_Close(&(glob_xmount.h_cache)); if(cache_ret!=e_XmountCache_Error_None) { LOG_ERROR("Unable to close cache file: Error code %u: Ignoring!\n", cache_ret); } } // Morphing - if(glob_xmount.morphing.p_functions!=NULL) { - if(glob_xmount.morphing.p_handle!=NULL) { - // Destroy morphing handle - ret=glob_xmount.morphing.p_functions-> - DestroyHandle(&(glob_xmount.morphing.p_handle)); - if(ret!=0) { - LOG_ERROR("Unable to destroy morphing handle: %s!\n", - glob_xmount.morphing.p_functions->GetErrorMessage(ret)); - } - } - } - if(glob_xmount.morphing.pp_lib_params!=NULL) { - for(uint32_t i=0;ip_supported_morphing_types!=NULL) - free(glob_xmount.morphing.pp_libs[i]->p_supported_morphing_types); - if(glob_xmount.morphing.pp_libs[i]->p_lib!=NULL) - dlclose(glob_xmount.morphing.pp_libs[i]->p_lib); - if(glob_xmount.morphing.pp_libs[i]->p_name!=NULL) - free(glob_xmount.morphing.pp_libs[i]->p_name); - free(glob_xmount.morphing.pp_libs[i]); - } - free(glob_xmount.morphing.pp_libs); + morph_ret=XmountMorphing_DestroyHandle(&(glob_xmount.h_morphing)); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Unable to destroy morphing handle: Error code %u: Ignoring!\n", + morph_ret); } // Input // Just in case close was not already called, call it now input_ret=XmountInput_Close(glob_xmount.h_input); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to close input image(s): Error code %u: Ignoring!\n", input_ret); } input_ret=XmountInput_DestroyHandle(&(glob_xmount.h_input)); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to destroy input handle: Error code %u: Ignoring!\n", input_ret); } // Args if(glob_xmount.args.p_cache_file!=NULL) { XMOUNT_FREE(glob_xmount.args.p_cache_file); } // Before we return, initialize everything in case ReleaseResources would be // called again. InitResources(); } /******************************************************************************* * LibXmount_Morphing function implementation ******************************************************************************/ //! Function to get the amount of input images /*! * \param p_count Count of input images * \return 0 on success */ static int LibXmount_Morphing_ImageCount(uint64_t *p_count) { te_XmountInput_Error input_ret=e_XmountInput_Error_None; input_ret=XmountInput_GetImageCount(glob_xmount.h_input,p_count); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to get input image count: Error code %u!\n",input_ret); return -EIO; } return 0; } //! Function to get the size of the morphed data /*! * \param image Image number * \param p_size Pointer to store input image's size to * \return 0 on success */ static int LibXmount_Morphing_Size(uint64_t image, uint64_t *p_size) { te_XmountInput_Error input_ret=e_XmountInput_Error_None; input_ret=XmountInput_GetSize(glob_xmount.h_input,image,p_size); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to get size of input image %" PRIu64 ": Error code %u!\n", image, input_ret); return -EIO; } return 0; } //! Function to read data from input image /*! * \param image Image number * \param p_buf Buffer to store read data to * \param offset Position at which to start reading * \param count Amount of bytes to read * \param p_read Number of read bytes on success * \return 0 on success or negated error code on error */ static int LibXmount_Morphing_Read(uint64_t image, char *p_buf, off_t offset, size_t count, size_t *p_read) { te_XmountInput_Error input_ret=e_XmountInput_Error_None; input_ret=XmountInput_ReadData(glob_xmount.h_input, image, p_buf, offset, count, p_read); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to read data of input image %" PRIu64 ": Error code %u!\n", image, input_ret); return -EIO; } return 0; } static int LibXmount_Morphing_Write(uint64_t image, char *p_buf, off_t offset, size_t count, size_t *p_written) { te_XmountInput_Error input_ret=e_XmountInput_Error_None; /* input_ret=XmountInput_ReadData(glob_xmount.h_input, image, p_buf, offset, count, p_read); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to read data of input image %" PRIu64 ": Error code %u!\n", image, input_ret); return -EIO; } */ return 0; } /******************************************************************************* * LibXmount_Output function implementation ******************************************************************************/ //! Function to get the size of the morphed image /*! * \param p_size Pointer to store morphed image's size to * \return 0 on success */ static int LibXmount_Output_Size(uint64_t *p_size) { - int ret=0; + te_XmountMorphError morph_ret=e_XmountMorphError_None; - ret=GetMorphedImageSize(p_size); + morph_ret=XmountMorphing_GetSize(glob_xmount.h_morphing,p_size); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Unable to get morphed image size: Error code %u!\n",morph_ret); + return FALSE; + } - return ret==TRUE ? 0 : ret; + return TRUE; } //! Function to read data from the morphed image /*! * \param p_buf Buffer to store read data to * \param offset Position at which to start reading * \param count Amount of bytes to read * \param p_read Number of read bytes on success * \return 0 on success or negated error code on error */ static int LibXmount_Output_Read(char *p_buf, off_t offset, size_t count, size_t *p_read) { - return ReadMorphedImageData(p_buf,offset,count,p_read); + uint64_t block_off=0; + uint64_t cur_block=0; + uint64_t cur_to_read=0; + uint64_t image_size=0; + size_t read=0; + size_t to_read=0; + uint8_t is_block_cached=FALSE; + te_XmountMorphError morph_ret=e_XmountMorphError_None; + te_XmountCache_Error cache_ret=e_XmountCache_Error_None; + + // Make sure we aren't reading past EOF of image file + morph_ret=XmountMorphing_GetSize(glob_xmount.h_morphing,&image_size); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Couldn't get size of morphed image: Error code %u!\n",morph_ret); + return -EIO; + } + if(offset>=image_size) { + // Offset is beyond image size + LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset); + *p_read=0; + return FALSE; + } + if(offset+count>image_size) { + // Attempt to read data past EOF of morphed image file + to_read=image_size-offset; + LOG_DEBUG("Attempt to read data past EOF of morphed image. Corrected size " + "from %zu to %" PRIu64 ".\n", + count, + to_read); + } else to_read=count; + + // Calculate block to start reading data from + cur_block=offset/XMOUNT_CACHE_BLOCK_SIZE; + block_off=offset%XMOUNT_CACHE_BLOCK_SIZE; + + // Read image data + while(to_read!=0) { + // Calculate how many bytes we have to read from this block + if(block_off+to_read>XMOUNT_CACHE_BLOCK_SIZE) { + cur_to_read=XMOUNT_CACHE_BLOCK_SIZE-block_off; + } else cur_to_read=to_read; + + // Determine if we have to read cached data + is_block_cached=FALSE; + if(glob_xmount.output.writable==TRUE) { + cache_ret=XmountCache_IsBlockCached(glob_xmount.h_cache,cur_block); + if(cache_ret==e_XmountCache_Error_None) is_block_cached=TRUE; + else if(cache_ret!=e_XmountCache_Error_UncachedBlock) { + LOG_ERROR("Unable to determine if block %" PRIu64 " is cached: " + "Error code %u!\n", + cur_block, + cache_ret); + return -EIO; + } + } + + // Check if block is cached + if(is_block_cached==TRUE) { + // Write support enabled and need to read altered data from cachefile + LOG_DEBUG("Reading %zu bytes from block cache file\n",cur_to_read); + + cache_ret=XmountCache_BlockCacheRead(glob_xmount.h_cache, + p_buf, + cur_block, + block_off, + cur_to_read); + if(cache_ret!=e_XmountCache_Error_None) { + LOG_ERROR("Unable to read %" PRIu64 + " bytes of cached data from cache block %" PRIu64 + " at cache block offset %" PRIu64 ": Error code %u!\n", + cur_to_read, + cur_block, + block_off, + cache_ret); + return -EIO; + } + } else { + // No write support or data not cached + morph_ret=XmountMorphing_ReadData(glob_xmount.h_morphing, + p_buf, + (cur_block*XMOUNT_CACHE_BLOCK_SIZE)+ + block_off, + cur_to_read, + &read); + if(morph_ret!=e_XmountMorphError_None || read!=cur_to_read) { + LOG_ERROR("Couldn't read %zu bytes at offset %zu from morphed image: " + "Error code %u!\n", + cur_to_read, + offset, + morph_ret); + return -EIO; + } + LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 + " from morphed image file\n", + cur_to_read, + (cur_block*XMOUNT_CACHE_BLOCK_SIZE)+block_off); + } + + cur_block++; + block_off=0; + p_buf+=cur_to_read; + to_read-=cur_to_read; + } + + *p_read=to_read; + return TRUE; } //! Function to write data to the morphed image /*! * \param p_buf Buffer with data to write * \param offset Position at which to start writing * \param count Amount of bytes to write * \param p_written Number of written bytes on success * \return 0 on success or negated error code on error */ static int LibXmount_Output_Write(char *p_buf, off_t offset, size_t count, size_t *p_written) { - return WriteMorphedImageData(p_buf,offset,count,p_written); + uint64_t block_off=0; + uint64_t cur_block=0; + uint64_t cur_to_read=0; + uint64_t cur_to_write=0; + uint64_t image_size=0; + uint64_t read=0; + size_t to_write=0; + char *p_buf2=NULL; + uint8_t is_block_cached=FALSE; + te_XmountMorphError morph_ret=e_XmountMorphError_None; + te_XmountCache_Error cache_ret=e_XmountCache_Error_None; + + // Make sure we aren't writing past EOF of image file + morph_ret=XmountMorphing_GetSize(glob_xmount.h_morphing,&image_size); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Couldn't get size of morphed image: Error code %u!\n",morph_ret); + return -EIO; + } + if(offset>=image_size) { + // Offset is beyond image size + LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset); + *p_written=0; + return 0; + } + if(offset+count>image_size) { + // Attempt to write data past EOF of morphed image file + to_write=image_size-offset; + LOG_DEBUG("Attempt to write data past EOF of morphed image. Corrected size " + "from %zu to %" PRIu64 ".\n", + count, + to_write); + } else to_write=count; + + // Calculate block to start writing data to + cur_block=offset/XMOUNT_CACHE_BLOCK_SIZE; + block_off=offset%XMOUNT_CACHE_BLOCK_SIZE; + + while(to_write!=0) { + // Calculate how many bytes we have to write to this block + if(block_off+to_write>XMOUNT_CACHE_BLOCK_SIZE) { + cur_to_write=XMOUNT_CACHE_BLOCK_SIZE-block_off; + } else cur_to_write=to_write; + + // Determine if block is already in cache + is_block_cached=FALSE; + cache_ret=XmountCache_IsBlockCached(glob_xmount.h_cache,cur_block); + if(cache_ret==e_XmountCache_Error_None) is_block_cached=TRUE; + else if(cache_ret!=e_XmountCache_Error_UncachedBlock) { + LOG_ERROR("Unable to determine if block %" PRIu64 " is cached: " + "Error code %u!\n", + cur_block, + cache_ret); + return -EIO; + } + + // Check if block is cached + if(is_block_cached==TRUE) { + // Block is cached + cache_ret=XmountCache_BlockCacheWrite(glob_xmount.h_cache, + p_buf, + cur_block, + block_off, + cur_to_write); + if(cache_ret!=e_XmountCache_Error_None) { + LOG_ERROR("Unable to write %" PRIu64 + " bytes of data to cache block %" PRIu64 + " at cache block offset %" PRIu64 ": Error code %u!\n", + cur_to_write, + cur_block, + block_off, + cache_ret); + return -EIO; + } + + LOG_DEBUG("Wrote %" PRIu64 " bytes to block cache\n",cur_to_write); + } else { + // Uncached block. Need to cache entire new block + // Prepare new write buffer + XMOUNT_MALLOC(p_buf2,char*,XMOUNT_CACHE_BLOCK_SIZE); + memset(p_buf2,0x00,XMOUNT_CACHE_BLOCK_SIZE); + + // Read full block from morphed image + cur_to_read=XMOUNT_CACHE_BLOCK_SIZE; + if((cur_block*XMOUNT_CACHE_BLOCK_SIZE)+XMOUNT_CACHE_BLOCK_SIZE>image_size) { + cur_to_read=XMOUNT_CACHE_BLOCK_SIZE-(((cur_block*XMOUNT_CACHE_BLOCK_SIZE)+ + XMOUNT_CACHE_BLOCK_SIZE)-image_size); + } + morph_ret=XmountMorphing_ReadData(glob_xmount.h_morphing, + p_buf, + cur_block*XMOUNT_CACHE_BLOCK_SIZE, + cur_to_read, + &read); + if(morph_ret!=e_XmountMorphError_None || read!=cur_to_read) { + LOG_ERROR("Couldn't read %" PRIu64 " bytes at offset %zu " + "from morphed image: Error code %u!\n", + cur_to_read, + offset, + morph_ret); + XMOUNT_FREE(p_buf2); + return -EIO; + } + + // Set changed data + memcpy(p_buf2+block_off,p_buf,cur_to_write); + + cache_ret=XmountCache_BlockCacheAppend(glob_xmount.h_cache, + p_buf, + cur_block); + if(cache_ret!=e_XmountCache_Error_None) { + LOG_ERROR("Unable to append new block cache block %" PRIu64 + ": Error code %u!\n", + cur_block, + cache_ret); + XMOUNT_FREE(p_buf2); + return -EIO; + } + XMOUNT_FREE(p_buf2); + + LOG_DEBUG("Appended new block cache block %" PRIu64 "\n",cur_block); + } + + block_off=0; + cur_block++; + p_buf+=cur_to_write; + to_write-=cur_to_write; + } + + *p_written=to_write; + return TRUE; } /******************************************************************************* * Main ******************************************************************************/ int main(int argc, char *argv[]) { uint64_t input_image_count=0; struct stat file_stat; int ret; int fuse_ret; char *p_err_msg; te_XmountInput_Error input_ret=e_XmountInput_Error_None; + te_XmountMorphError morph_ret=e_XmountMorphError_None; te_XmountCache_Error cache_ret=e_XmountCache_Error_None; // Set implemented FUSE functions struct fuse_operations xmount_operations = { //.access=FuseAccess, .getattr=Xmount_FuseGetAttr, .mkdir=Xmount_FuseMkDir, .mknod=Xmount_FuseMkNod, .open=Xmount_FuseOpen, .readdir=Xmount_FuseReadDir, .read=Xmount_FuseRead, .rename=Xmount_FuseRename, .rmdir=Xmount_FuseRmDir, //.statfs=FuseStatFs, .unlink=Xmount_FuseUnlink, .write=Xmount_FuseWrite }; // Disable std output / input buffering setbuf(stdout,NULL); setbuf(stderr,NULL); // Init glob_xmount if(InitResources()==FALSE) { LOG_ERROR("Unable to initialize internal resources!\n"); return 1; } // Load input, morphing and output libs if(!LoadLibs()) { LOG_ERROR("Unable to load any libraries!\n") return 1; } // Check FUSE settings CheckFuseSettings(); // Parse command line options if(ParseCmdLine(argc,argv)!=TRUE) { PrintUsage(argv[0]); FreeResources(); return 1; } // Check command line options input_ret=XmountInput_GetImageCount(glob_xmount.h_input,&input_image_count); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to get input image count: Error code %u!\n",input_ret); return 1; } if(input_image_count==0) { LOG_ERROR("No --in command line option specified!\n") PrintUsage(argv[0]); FreeResources(); return 1; } if(glob_xmount.fuse_argc<2) { LOG_ERROR("Couldn't parse command line options!\n") PrintUsage(argv[0]); FreeResources(); return 1; } - if(glob_xmount.morphing.p_morph_type==NULL) { - XMOUNT_STRSET(glob_xmount.morphing.p_morph_type,"combine"); - } // TODO: Add default output image format here // Check if mountpoint is a valid dir if(stat(glob_xmount.p_mountpoint,&file_stat)!=0) { LOG_ERROR("Unable to stat mount point '%s'!\n",glob_xmount.p_mountpoint); PrintUsage(argv[0]); FreeResources(); return 1; } if(!S_ISDIR(file_stat.st_mode)) { LOG_ERROR("Mount point '%s' is not a directory!\n", glob_xmount.p_mountpoint); PrintUsage(argv[0]); FreeResources(); return 1; } if(glob_xmount.debug==TRUE) { LOG_DEBUG("Options passed to FUSE: ") for(int i=0;i - CreateHandle(&glob_xmount.morphing.p_handle, - glob_xmount.morphing.p_morph_type, - glob_xmount.debug); - if(ret!=0) { - LOG_ERROR("Unable to create morphing handle: %s!\n", - glob_xmount.morphing.p_functions->GetErrorMessage(ret)); - FreeResources(); - return 1; - } - - // Parse morphing lib specific options - if(glob_xmount.morphing.pp_lib_params!=NULL) { - p_err_msg=NULL; - ret=glob_xmount.morphing.p_functions-> - OptionsParse(glob_xmount.morphing.p_handle, - glob_xmount.morphing.lib_params_count, - glob_xmount.morphing.pp_lib_params, - (const char**)&p_err_msg); - if(ret!=0) { - if(p_err_msg!=NULL) { - LOG_ERROR("Unable to parse morphing library specific options: %s: %s!\n", - glob_xmount.morphing.p_functions->GetErrorMessage(ret), - p_err_msg); - glob_xmount.morphing.p_functions->FreeBuffer(p_err_msg); - FreeResources(); - return 1; - } else { - LOG_ERROR("Unable to parse morphing library specific options: %s!\n", - glob_xmount.morphing.p_functions->GetErrorMessage(ret)); - FreeResources(); - return 1; - } - } - } - - // Morph image - ret=glob_xmount.morphing.p_functions-> - Morph(glob_xmount.morphing.p_handle, - &(glob_xmount.morphing.input_image_functions)); - if(ret!=0) { - LOG_ERROR("Unable to start morphing: %s!\n", - glob_xmount.morphing.p_functions->GetErrorMessage(ret)); - FreeResources(); - return 1; - } - // Init random generator srand(time(NULL)); // Calculate partial MD5 hash of input image file if(CalculateInputImageHash(&(glob_xmount.image_hash_lo), &(glob_xmount.image_hash_hi))==FALSE) { LOG_ERROR("Couldn't calculate partial hash of morphed image!\n") return 1; } if(glob_xmount.debug==TRUE) { LOG_DEBUG("Partial MD5 hash of morphed image: ") for(int i=0;i<8;i++) printf("%02hhx",*(((char*)(&(glob_xmount.image_hash_lo)))+i)); for(int i=0;i<8;i++) printf("%02hhx",*(((char*)(&(glob_xmount.image_hash_hi)))+i)); printf("\n"); } if(!ExtractOutputFileNames(glob_xmount.p_first_input_image_name)) { LOG_ERROR("Couldn't extract virtual file names!\n"); FreeResources(); return 1; } LOG_DEBUG("Virtual file names extracted successfully\n") // Find output lib if(FindOutputLib()!=TRUE) { LOG_ERROR("Unable to find a library supporting the output format '%s'!\n", glob_xmount.output.p_output_format); FreeResources(); return 1; } // Init output ret=glob_xmount.output.p_functions-> CreateHandle(&glob_xmount.output.p_handle, glob_xmount.output.p_output_format, glob_xmount.debug); if(ret!=0) { LOG_ERROR("Unable to create output handle: %s!\n", glob_xmount.output.p_functions->GetErrorMessage(ret)); FreeResources(); return 1; } // Parse output lib specific options if(glob_xmount.output.pp_lib_params!=NULL) { p_err_msg=NULL; ret=glob_xmount.output.p_functions-> OptionsParse(glob_xmount.output.p_handle, glob_xmount.output.lib_params_count, glob_xmount.output.pp_lib_params, (const char**)&p_err_msg); if(ret!=0) { if(p_err_msg!=NULL) { LOG_ERROR("Unable to parse output library specific options: %s: %s!\n", glob_xmount.output.p_functions->GetErrorMessage(ret), p_err_msg); glob_xmount.output.p_functions->FreeBuffer(p_err_msg); FreeResources(); return 1; } else { LOG_ERROR("Unable to parse output library specific options: %s!\n", glob_xmount.output.p_functions->GetErrorMessage(ret)); FreeResources(); return 1; } } } // Morph image - ret=glob_xmount.morphing.p_functions-> - Morph(glob_xmount.morphing.p_handle, - &(glob_xmount.morphing.input_image_functions)); - if(ret!=0) { - LOG_ERROR("Unable to start morphing: %s!\n", - glob_xmount.morphing.p_functions->GetErrorMessage(ret)); + morph_ret=XmountMorphing_StartMorphing(glob_xmount.h_morphing); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Unable to start morphing: Error code %u!\n",morph_ret); FreeResources(); return 1; } // Gather infos for info file if(!InitInfoFile()) { LOG_ERROR("Couldn't gather infos for virtual image info file!\n") FreeResources(); return 1; } LOG_DEBUG("Virtual image info file build successfully\n") if(glob_xmount.output.writable) { // Init cache file and cache file block index // TODO: Add cache file creration / opening /* if(glob_xmount.args.overwrite_cache==TRUE) { cache_ret=XmountCache_Create(&(glob_xmount.h_cache), glob_xmount.args.p_cache_file, } else { cache_ret=XmountCache_Open } te_XmountCache_Error cache_ret=e_XmountCache_Error_None; if(!InitCacheFile()) { LOG_ERROR("Couldn't initialize cache file!\n") FreeResources(); return 1; } */ LOG_DEBUG("Cache file initialized successfully\n") } // Call fuse_main to do the fuse magic fuse_ret=fuse_main(glob_xmount.fuse_argc, glob_xmount.pp_fuse_argv, &xmount_operations, NULL); // Destroy mutexes pthread_mutex_destroy(&(glob_xmount.mutex_image_rw)); pthread_mutex_destroy(&(glob_xmount.mutex_info_read)); // Free allocated memory FreeResources(); return fuse_ret; } diff --git a/src/xmount_morphing.c b/src/xmount_morphing.c index f7207c1..3c164a8 100644 --- a/src/xmount_morphing.c +++ b/src/xmount_morphing.c @@ -1,862 +1,737 @@ /******************************************************************************* * xmount Copyright (c) 2008-2016 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 // For calloc #include // For memcpy #include // For dlopen, dlclose, dlsym #include "../libxmount_morphing/libxmount_morphing.h" #include "xmount_morphing.h" #include "xmount.h" #include "macros.h" /******************************************************************************* * Private definitions / macros ******************************************************************************/ +#define XMOUNT_MORPHING_DEFAULT_MORPH_TYPE "combine" + #define LOG_WARNING(...) { \ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \ } #define LOG_ERROR(...) { \ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \ } #define LOG_DEBUG(...) { \ LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \ } /******************************************************************************* * Private types / structures / enums ******************************************************************************/ //! Structure containing infos about morphing libs typedef struct s_XmountMorphingLib { //! Filename of lib (without path) char *p_name; //! Handle to the loaded lib void *p_lib; //! Array of supported morphing types char *p_supported_morphing_types; //! Struct containing lib functions ts_LibXmountMorphingFunctions lib_functions; } ts_XmountMorphingLib, *pts_XmountMorphingLib; //! Structures and vars needed for morph support typedef struct s_XmountMorphHandle { //! Loaded morphing lib count uint32_t libs_count; //! Array containing infos about loaded morphing libs pts_XmountMorphingLib *pp_libs; //! Specified morphing type (--morph) char *p_morph_type; //! Amount of specified morphing lib params (--morphopts) uint32_t lib_params_count; //! Specified morphing lib params (--morphopts) pts_LibXmountOptions *pp_lib_params; //! Handle to initialized morphing lib void *p_handle; + //! Debug + uint8_t debug; //! Morphing functions of initialized lib pts_LibXmountMorphingFunctions p_functions; //! Input image functions passed to morphing lib ts_LibXmountMorphingInputFunctions input_image_functions; } ts_XmountMorphHandle; /******************************************************************************* * Private functions declarations ******************************************************************************/ /*! * \brief Find a morphing lib for a given morph type * * Searches trough the list of loaded morphing libraries to find one that * supports the given morph type. On success, that library is associated with * the given handle. * * \param p_h Morphing handle * \return e_XmountInput_Error_None on success */ te_XmountMorphError XmountMorphing_FindMorphLib(pts_XmountMorphHandle p_h); /******************************************************************************* * Public functions implementations ******************************************************************************/ /* * XmountMorphing_CreateHandle */ -te_XmountMorphError XmountMorphing_CreateHandle(pts_XmountMorphHandle *pp_h) { +te_XmountMorphError + XmountMorphing_CreateHandle(pts_XmountMorphHandle *pp_h, + tfun_XmountMorphing_InputImageCount p_img_count, + tfun_XmountMorphing_InputImageSize p_img_size, + tfun_XmountMorphing_InputImageRead p_img_read, + tfun_XmountMorphing_InputImageWrite p_img_write) +{ pts_XmountMorphHandle p_h=NULL; // Params check if(pp_h==NULL) return e_XmountMorphError_InvalidHandlePointer; // Alloc new handle p_h=(pts_XmountMorphHandle)calloc(1,sizeof(ts_XmountMorphHandle)); if(p_h==NULL) return e_XmountMorphError_Alloc; // Init values p_h->pp_libs=NULL; p_h->p_morph_type=NULL; p_h->pp_lib_params=NULL; p_h->p_handle=NULL; p_h->p_functions=NULL; - p_h->input_image_functions.ImageCount=&LibXmount_Morphing_ImageCount; - p_h->input_image_functions.Size=&LibXmount_Morphing_Size; - p_h->input_image_functions.Read=&LibXmount_Morphing_Read; + p_h->input_image_functions.ImageCount=p_img_count; + p_h->input_image_functions.Size=p_img_size; + p_h->input_image_functions.Read=p_img_read; + //p_h->input_image_functions.Write=p_img_write; *pp_h=p_h; return e_XmountMorphError_None; } /* * XmountMorphing_DestroyHandle */ te_XmountMorphError XmountMorphing_DestroyHandle(pts_XmountMorphHandle *pp_h) { + int ret=0; + pts_XmountMorphHandle p_h=NULL; + // Params check if(pp_h==NULL) return e_XmountMorphError_InvalidHandlePointer; + if(*pp_h==NULL) return e_XmountMorphError_InvalidHandle; + p_h=*pp_h; + + if(p_h->p_functions!=NULL) { + if(p_h->p_handle!=NULL) { + // Destroy morphing handle + ret=p_h->p_functions->DestroyHandle(&(p_h->p_handle)); + if(ret!=0) { + LOG_ERROR("Unable to destroy morphing handle: %s!\n", + p_h->p_functions->GetErrorMessage(ret)); + } + } + } + if(p_h->pp_lib_params!=NULL) { + for(uint32_t i=0;ilib_params_count;i++) { + XMOUNT_FREE(p_h->pp_lib_params[i]); + } + XMOUNT_FREE(p_h->pp_lib_params); + } + if(p_h->p_morph_type!=NULL) XMOUNT_FREE(p_h->p_morph_type); + if(p_h->pp_libs!=NULL) { + // Unload morphing libs + for(uint32_t i=0;ilibs_count;i++) { + if(p_h->pp_libs[i]==NULL) continue; + if(p_h->pp_libs[i]->p_supported_morphing_types!=NULL) + XMOUNT_FREE(p_h->pp_libs[i]->p_supported_morphing_types); + if(p_h->pp_libs[i]->p_lib!=NULL) + dlclose(p_h->pp_libs[i]->p_lib); + if(p_h->pp_libs[i]->p_name!=NULL) + XMOUNT_FREE(p_h->pp_libs[i]->p_name); + XMOUNT_FREE(p_h->pp_libs[i]); + } + XMOUNT_FREE(p_h->pp_libs); + } - // TODO: Impement - + *pp_h=NULL; return e_XmountMorphError_None; } /* * XmountMorphing_EnableDebugging */ te_XmountMorphError XmountMorphing_EnableDebugging(pts_XmountMorphHandle p_h) { // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; - // TODO: Impement - + p_h->debug=1; return e_XmountMorphError_None; } /* * XmountMorphing_AddLibrary */ te_XmountMorphError XmountMorphing_AddLibrary(pts_XmountMorphHandle p_h, const char *p_lib_name) { uint32_t supported_types_len=0; t_LibXmount_Morphing_GetApiVersion pfun_morphing_GetApiVersion; t_LibXmount_Morphing_GetSupportedTypes pfun_morphing_GetSupportedTypes; t_LibXmount_Morphing_GetFunctions pfun_morphing_GetFunctions; void *p_libxmount=NULL; pts_XmountMorphingLib p_morphing_lib=NULL; char *p_buf=NULL; char *p_library_path=NULL; char *p_supported_types=NULL; // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(p_lib_name==NULL) return e_XmountMorphError_InvalidString; // Construct full library path XMOUNT_STRSET(p_library_path,XMOUNT_LIBRARY_PATH); if(p_library_path[strlen(p_library_path)]!='/') { XMOUNT_STRAPP(p_library_path,"/"); } XMOUNT_STRAPP(p_library_path,p_lib_name); #define XMOUNTMORPHING_LOADLIBS__LOAD_SYMBOL(name,pfun) { \ if((pfun=dlsym(p_libxmount,name))==NULL) { \ LOG_ERROR("Unable to load symbol '%s' from library '%s'!\n", \ name, \ p_library_path); \ dlclose(p_libxmount); \ return e_XmountMorphError_FailedLoadingSymbol; \ } \ } // Try to load given library p_libxmount=dlopen(p_library_path,RTLD_NOW); if(p_libxmount==NULL) { LOG_ERROR("Unable to load morphing library '%s': %s!\n", p_library_path, dlerror()); return e_XmountMorphError_FailedLoadingLibrary; } // Load library symbols XMOUNTMORPHING_LOADLIBS__LOAD_SYMBOL("LibXmount_Morphing_GetApiVersion", pfun_morphing_GetApiVersion); // Check library's API version if(pfun_morphing_GetApiVersion()!=LIBXMOUNT_MORPHING_API_VERSION) { LOG_DEBUG("Failed! Wrong API version.\n"); LOG_ERROR("Unable to load morphing library '%s'. Wrong API version\n", p_library_path); dlclose(p_libxmount); return e_XmountMorphError_WrongLibraryApiVersion; } - LIBXMOUNT_LOAD_SYMBOL("LibXmount_Morphing_GetSupportedTypes", - pfun_morphing_GetSupportedTypes); - LIBXMOUNT_LOAD_SYMBOL("LibXmount_Morphing_GetFunctions", - pfun_morphing_GetFunctions); + XMOUNTMORPHING_LOADLIBS__LOAD_SYMBOL("LibXmount_Morphing_GetSupportedTypes", + pfun_morphing_GetSupportedTypes); + XMOUNTMORPHING_LOADLIBS__LOAD_SYMBOL("LibXmount_Morphing_GetFunctions", + pfun_morphing_GetFunctions); // Construct new entry for our library list XMOUNT_MALLOC(p_morphing_lib, pts_XmountMorphingLib, sizeof(ts_XmountMorphingLib)); // Initialize lib_functions structure to NULL memset(&(p_morphing_lib->lib_functions), 0, sizeof(ts_LibXmountMorphingFunctions)); // Set name and handle XMOUNT_STRSET(p_morphing_lib->p_name,p_lib_name); p_morphing_lib->p_lib=p_libxmount; // Get and set supported types p_supported_types=pfun_morphing_GetSupportedTypes(); supported_types_len=0; p_buf=p_supported_types; while(*p_buf!='\0') { supported_types_len+=(strlen(p_buf)+1); p_buf+=(strlen(p_buf)+1); } supported_types_len++; XMOUNT_MALLOC(p_morphing_lib->p_supported_morphing_types, char*, supported_types_len); memcpy(p_morphing_lib->p_supported_morphing_types, p_supported_types, supported_types_len); // Get, set and check lib_functions pfun_morphing_GetFunctions(&(p_morphing_lib->lib_functions)); if(p_morphing_lib->lib_functions.CreateHandle==NULL || p_morphing_lib->lib_functions.DestroyHandle==NULL || p_morphing_lib->lib_functions.Morph==NULL || p_morphing_lib->lib_functions.Size==NULL || p_morphing_lib->lib_functions.Read==NULL || p_morphing_lib->lib_functions.OptionsHelp==NULL || p_morphing_lib->lib_functions.OptionsParse==NULL || p_morphing_lib->lib_functions.GetInfofileContent==NULL || p_morphing_lib->lib_functions.GetErrorMessage==NULL || p_morphing_lib->lib_functions.FreeBuffer==NULL) { LOG_DEBUG("Missing implemention of one or more functions in lib %s!\n", p_lib_name); XMOUNT_FREE(p_morphing_lib->p_supported_morphing_types); XMOUNT_FREE(p_morphing_lib->p_name); XMOUNT_FREE(p_morphing_lib); dlclose(p_libxmount); return e_XmountMorphError_MissingLibraryFunction; } // Add entry to the input library list XMOUNT_REALLOC(p_h->pp_libs, pts_XmountMorphingLib*, sizeof(pts_XmountMorphingLib)*(p_h->libs_count+1)); p_h->pp_libs[p_h->libs_count++]=p_morphing_lib; LOG_DEBUG("Morphing library '%s' loaded successfully\n",p_lib_name); return e_XmountMorphError_None; } /* * XmountMorphing_GetLibraryCount */ te_XmountMorphError XmountMorphing_GetLibraryCount(pts_XmountMorphHandle p_h, uint32_t *p_count) { // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; // TODO: Impement return e_XmountMorphError_None; } /* * XmountMorphing_GetSupportedTypes */ te_XmountMorphError XmountMorphing_GetSupportedTypes(pts_XmountMorphHandle p_h, char **pp_types) { char *p_buf=NULL; char *p_types=NULL; uint32_t cur_len=0; uint32_t vector_len=0; // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(pp_types==NULL) return e_XmountMorphError_InvalidBuffer; // Loop over all loaded libs, extract supported types and add to our vector // TODO: IMPROVEMENT: Final vector could be sorted for(uint32_t i=0;ilibs_count;i++) { p_buf=p_h->pp_libs[i]->p_supported_morphing_types; while(p_buf!=NULL && *p_buf!='\0') p_buf+=(strlen(p_buf)+1); cur_len=(uint32_t)(p_buf-p_h->pp_libs[i]->p_supported_morphing_types); if(cur_len==0) continue; p_types=(char*)realloc(p_types,vector_len+cur_len); if(p_types==NULL) return e_XmountInput_Error_Alloc; memcpy(p_types+vector_len, p_h->pp_libs[i]->p_supported_morphing_types, cur_len); vector_len+=cur_len; } // Null-terminate vector p_types=(char*)realloc(p_types,vector_len+1); if(p_types==NULL) return e_XmountInput_Error_Alloc; p_types[vector_len]='\0'; *pp_types=p_types; return e_XmountMorphError_None; } /* * XmountMorphing_SetOptions */ te_XmountMorphError XmountMorphing_SetOptions(pts_XmountMorphHandle p_h, char *p_options) { // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(p_options==NULL) return e_XmountMorphError_InvalidString; // Make sure library parameters haven't been set previously if(p_h->pp_lib_params!=NULL) { LOG_ERROR("Morphing library options already set!\n"); return e_XmountMorphError_LibOptionsAlreadySet; } // Save options if(XmountLib_SplitLibParams(p_options, &(p_h->lib_params_count), &(p_h->pp_lib_params))!=0) { LOG_ERROR("Unable to parse morphing library options '%s'!\n",p_options); return e_XmountMorphError_FailedParsingOptions; } return e_XmountMorphError_None; } /* * XmountMorphing_GetOptionsHelpText */ te_XmountMorphError XmountMorphing_GetOptionsHelpText(pts_XmountMorphHandle p_h, char **pp_help_text) { - const char *p_buf=NULL; + char *p_buf=NULL; char *p_help=NULL; int ret=0; // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(pp_help_text==NULL) return e_XmountMorphError_InvalidBuffer; // Loop over all loaded libs, extract help and add to our text buffer // TODO: IMPROVEMENT: Final text should be sorted by lib's name for(uint32_t i=0;ilibs_count;i++) { ret=p_h->pp_libs[i]->lib_functions.OptionsHelp(&p_buf); if(ret!=0) { LOG_ERROR("Unable to get options help for library '%s': %s!\n", p_h->pp_libs[i]->p_name, p_h->pp_libs[i]->lib_functions.GetErrorMessage(ret)); continue; } if(p_buf==NULL) continue; XMOUNT_STRAPP(p_help," - "); XMOUNT_STRAPP(p_help,p_h->pp_libs[i]->p_name); XMOUNT_STRAPP(p_help,"\n"); XMOUNT_STRAPP(p_help,p_buf); XMOUNT_STRAPP(p_help,"\n"); p_h->pp_libs[i]->lib_functions.FreeBuffer(p_buf); } *pp_help_text=p_help; return e_XmountMorphError_None; } /* * XmountMorphingt_GetLibsInfoText */ te_XmountMorphError XmountMorphing_GetLibsInfoText(pts_XmountMorphHandle p_h, char **pp_info_text) { char *p_buf=NULL; char *p_info_text=NULL; uint8_t first=0; // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(pp_info_text==NULL) return e_XmountMorphError_InvalidBuffer; // Loop over all loaded libs, extract name and supported types and add to // our text buffer // TODO: IMPROVEMENT: Final text should be sorted by lib's name for(uint32_t i=0;ilibs_count;i++) { XMOUNT_STRAPP(p_info_text," - "); XMOUNT_STRAPP(p_info_text,p_h->pp_libs[i]->p_name); XMOUNT_STRAPP(p_info_text," supporting "); XMOUNT_STRAPP(p_info_text," - "); XMOUNT_STRAPP(p_info_text," - "); p_buf=p_h->pp_libs[i]->p_supported_morphing_types; first=1; while(*p_buf!='\0') { if(first==1) { XMOUNT_STRAPP(p_info_text,"\""); XMOUNT_STRAPP(p_info_text,p_buf); XMOUNT_STRAPP(p_info_text,"\""); first=0; } else { XMOUNT_STRAPP(p_info_text,", \""); XMOUNT_STRAPP(p_info_text,p_buf); XMOUNT_STRAPP(p_info_text,"\""); } p_buf+=(strlen(p_buf)+1); } XMOUNT_STRAPP(p_info_text,"\n"); } *pp_info_text=p_info_text; return e_XmountMorphError_None; } /* * XmountMorphing_SetType */ te_XmountMorphError XmountMorphing_SetType(pts_XmountMorphHandle p_h, char *p_type) { // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(p_type==NULL) return e_XmountMorphError_InvalidString; XMOUNT_STRSET(p_h->p_morph_type,p_type); return e_XmountMorphError_None; } /* - * XmountMorphing_StartMorph + * XmountMorphing_StartMorphing */ -te_XmountMorphError XmountMorphing_StartMorph(pts_XmountMorphHandle p_h) { +te_XmountMorphError XmountMorphing_StartMorphing(pts_XmountMorphHandle p_h) { + const char *p_err_msg=NULL; + int ret=0; + te_XmountMorphError morph_ret=e_XmountMorphError_None; + // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; - // TODO: Impement + // Set default morph type if none was set previously + if(p_h->p_morph_type==NULL) { + XMOUNT_STRSET(p_h->p_morph_type,XMOUNT_MORPHING_DEFAULT_MORPH_TYPE); + } + + // Find morphing lib + morph_ret=XmountMorphing_FindMorphLib(p_h); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Unable to find a library supporting the morphing type '%s'!\n", + p_h->p_morph_type); + return morph_ret; + } + + // Init morphing + ret=p_h->p_functions->CreateHandle(&(p_h->p_handle), + p_h->p_morph_type, + p_h->debug); + if(ret!=0) { + LOG_ERROR("Unable to create morphing handle: %s!\n", + p_h->p_functions->GetErrorMessage(ret)); + return e_XmountMorphError_FailedCreatingMorphHandle; + } + + // Parse morphing lib specific options + if(p_h->pp_lib_params!=NULL) { + p_err_msg=NULL; + ret=p_h->p_functions->OptionsParse(p_h->p_handle, + p_h->lib_params_count, + p_h->pp_lib_params, + &p_err_msg); + if(ret!=0) { + if(p_err_msg!=NULL) { + LOG_ERROR("Unable to parse morphing library specific options: %s: %s!\n", + p_h->p_functions->GetErrorMessage(ret), + p_err_msg); + p_h->p_functions->FreeBuffer(p_err_msg); + } else { + LOG_ERROR("Unable to parse morphing library specific options: %s!\n", + p_h->p_functions->GetErrorMessage(ret)); + } + return e_XmountInput_Error_FailedParsingLibParams; + } + } + + // Morph image + ret=p_h->p_functions->Morph(p_h->p_handle,&(p_h->input_image_functions)); + if(ret!=0) { + LOG_ERROR("Unable to start morphing: %s!\n", + p_h->p_functions->GetErrorMessage(ret)); + return e_XmountMorphError_FailedCreatingMorphHandle; + } return e_XmountMorphError_None; } /* - * XmountInput_StopMorph + * XmountInput_StopMorphing */ -te_XmountMorphError XmountInput_StopMorph(pts_XmountMorphHandle p_h) { +te_XmountMorphError XmountInput_StopMorphing(pts_XmountMorphHandle p_h) { // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; // TODO: Impement return e_XmountMorphError_None; } /* * XmountMorphing_GetSize */ te_XmountMorphError XmountMorphing_GetSize(pts_XmountMorphHandle p_h, uint64_t *p_size) { int ret=0; // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(p_size==NULL) return e_XmountMorphError_InvalidBuffer; // Get morphed image size ret=p_h->p_functions->Size(p_h->p_handle,p_size); if(ret!=0) { LOG_ERROR("Unable to get morphed image size: %s!\n", p_h->p_functions->GetErrorMessage(ret)); return e_XmountMorphError_FailedGettingImageSize; } return e_XmountMorphError_None; } /* * XmountMorphing_ReadData */ te_XmountMorphError XmountMorphing_ReadData(pts_XmountMorphHandle p_h, char *p_buf, uint64_t offset, uint64_t count, uint64_t *p_read) { + uint64_t image_size=0; + size_t read=0; + size_t to_read=0; + int ret; + te_XmountMorphError morph_ret=e_XmountMorphError_None; + // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; - // TODO: Impement + // Make sure we aren't reading past EOF of image file + morph_ret=XmountMorphing_GetSize(p_h,&image_size); + if(morph_ret!=e_XmountMorphError_None) { + LOG_ERROR("Couldn't get size of morphed image: Error code %u!\n",morph_ret); + return morph_ret; + } + if(offset>=image_size) { + // Offset is beyond image size + LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset); + *p_read=0; + return e_XmountMorphError_OffsetExceedsImageSize; + } + if(offset+count>image_size) { + // Attempt to read data past EOF of morphed image file + to_read=image_size-offset; + LOG_DEBUG("Attempt to read data past EOF of morphed image. Corrected size " + "from %zu to %" PRIu64 ".\n", + count, + to_read); + } else to_read=count; + + ret=p_h->p_functions->Read(p_h->p_handle, + p_buf, + offset, + to_read, + p_read); + if(ret!=0) { + LOG_ERROR("Couldn't read %zu bytes at offset %zu from morphed image: %s!\n", + to_read, + offset, + p_h->p_functions->GetErrorMessage(ret)); + return e_XmountMorphError_FailedReadingData; + } + + LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 + " from morphed image file\n", + to_read, + offset); return e_XmountMorphError_None; } /* * XmountMorphing_WriteData */ te_XmountMorphError XmountMorphing_WriteData(pts_XmountMorphHandle p_h, const char *p_buf, uint64_t offset, - uint64_t count) + uint64_t count, + uint64_t *p_written) { // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; // TODO: Impement return e_XmountMorphError_None; } /* * XmountMorphing_GetInfoFileContent */ te_XmountMorphError XmountMorphing_GetInfoFileContent(pts_XmountMorphHandle p_h, char **pp_content) { int ret=0; char *p_buf=NULL; char *p_content=NULL; // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; if(pp_content==NULL) return e_XmountMorphError_InvalidBuffer; ret=p_h->p_functions->GetInfofileContent(p_h->p_handle,(const char**)&p_buf); if(ret!=0) { LOG_ERROR("Unable to get info file content from morphing lib: %s!\n", p_h->p_functions->GetErrorMessage(ret)); return e_XmountMorphError_FailedGettingInfoFileContent; } // Add infos to main buffer and free p_buf if(p_buf!=NULL) { XMOUNT_STRAPP(p_content,p_buf); p_h->p_functions->FreeBuffer(p_buf); } else { XMOUNT_STRAPP(p_content,"None\n"); } *pp_content=p_content; return e_XmountMorphError_None; } /******************************************************************************* * Private functions implementations ******************************************************************************/ /* * XmountMorphing_FindMorphLib */ te_XmountMorphError XmountMorphing_FindMorphLib(pts_XmountMorphHandle p_h) { char *p_buf; LOG_DEBUG("Trying to find suitable library for morph type '%s'.\n", p_h->p_morph_type); // Loop over all loaded libs for(uint32_t i=0;ilibs_count;i++) { LOG_DEBUG("Checking morphing library %s\n",p_h->pp_libs[i]->p_name); p_buf=p_h->pp_libs[i]->p_supported_morphing_types; while(*p_buf!='\0') { if(strcmp(p_buf,p_h->p_morph_type)==0) { // Library supports morph type, set lib functions LOG_DEBUG("Morphing library '%s' pretends to handle that morph type.\n", p_h->pp_libs[i]->p_name); p_h->p_functions=&(p_h->pp_libs[i]->lib_functions); return e_XmountMorphError_None; } p_buf+=(strlen(p_buf)+1); } } LOG_DEBUG("Couldn't find any suitable library.\n"); // No library supporting morph type found - return e_XmountInput_Error_UnsupportedType; -} - - -//! Read data from morphed image -/*! - * \param p_buf Pointer to buffer to write read data to (must be preallocated!) - * \param offset Offset at which data should be read - * \param size Size of data which should be read (size of buffer) - * \param p_read Number of read bytes on success - * \return TRUE on success, negated error code on error - */ -/* -int ReadMorphedImageData(char *p_buf, - off_t offset, - size_t size, - size_t *p_read) -{ - uint64_t block_off=0; - uint64_t cur_block=0; - uint64_t cur_to_read=0; - uint64_t image_size=0; - size_t read=0; - size_t to_read=0; - int ret; - uint8_t is_block_cached=FALSE; - te_XmountCache_Error cache_ret=e_XmountCache_Error_None; - - // Make sure we aren't reading past EOF of image file - if(GetMorphedImageSize(&image_size)!=TRUE) { - LOG_ERROR("Couldn't get size of morphed image!\n"); - return -EIO; - } - if(offset>=image_size) { - // Offset is beyond image size - LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset); - *p_read=0; - return FALSE; - } - if(offset+size>image_size) { - // Attempt to read data past EOF of morphed image file - to_read=image_size-offset; - LOG_DEBUG("Attempt to read data past EOF of morphed image. Corrected size " - "from %zu to %" PRIu64 ".\n", - size, - to_read); - } else to_read=size; - - // Calculate block to start reading data from - cur_block=offset/XMOUNT_CACHE_BLOCK_SIZE; - block_off=offset%XMOUNT_CACHE_BLOCK_SIZE; - - // Read image data - while(to_read!=0) { - // Calculate how many bytes we have to read from this block - if(block_off+to_read>XMOUNT_CACHE_BLOCK_SIZE) { - cur_to_read=XMOUNT_CACHE_BLOCK_SIZE-block_off; - } else cur_to_read=to_read; - - // Determine if we have to read cached data - is_block_cached=FALSE; - if(glob_xmount.output.writable==TRUE) { - cache_ret=XmountCache_IsBlockCached(glob_xmount.h_cache,cur_block); - if(cache_ret==e_XmountCache_Error_None) is_block_cached=TRUE; - else if(cache_ret!=e_XmountCache_Error_UncachedBlock) { - LOG_ERROR("Unable to determine if block %" PRIu64 " is cached: " - "Error code %u!\n", - cur_block, - cache_ret); - return -EIO; - } - } - - // Check if block is cached - if(is_block_cached==TRUE) { - // Write support enabled and need to read altered data from cachefile - LOG_DEBUG("Reading %zu bytes from block cache file\n",cur_to_read); - - cache_ret=XmountCache_BlockCacheRead(glob_xmount.h_cache, - p_buf, - cur_block, - block_off, - cur_to_read); - if(cache_ret!=e_XmountCache_Error_None) { - LOG_ERROR("Unable to read %" PRIu64 - " bytes of cached data from cache block %" PRIu64 - " at cache block offset %" PRIu64 ": Error code %u!\n", - cur_to_read, - cur_block, - block_off, - cache_ret); - return -EIO; - } - } else { - // No write support or data not cached - ret=glob_xmount.morphing.p_functions->Read(glob_xmount.morphing.p_handle, - p_buf, - (cur_block*XMOUNT_CACHE_BLOCK_SIZE)+ - block_off, - cur_to_read, - &read); - if(ret!=0 || read!=cur_to_read) { - LOG_ERROR("Couldn't read %zu bytes at offset %zu from morphed image: " - "%s!\n", - cur_to_read, - offset, - glob_xmount.morphing.p_functions->GetErrorMessage(ret)); - return -EIO; - } - LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 - " from morphed image file\n", - cur_to_read, - (cur_block*XMOUNT_CACHE_BLOCK_SIZE)+block_off); - } - - cur_block++; - block_off=0; - p_buf+=cur_to_read; - to_read-=cur_to_read; - } - - *p_read=to_read; - return TRUE; -} -*/ - -//! Write data to morphed image -/*! - * \param p_buf Buffer with data to write - * \param offset Offset to start writing at - * \param count Amount of bytes to write - * \param p_written Amount of successfully written bytes - * \return TRUE on success, negated error code on error - */ -/* -int WriteMorphedImageData(const char *p_buf, - off_t offset, - size_t count, - size_t *p_written) -{ - uint64_t block_off=0; - uint64_t cur_block=0; - uint64_t cur_to_read=0; - uint64_t cur_to_write=0; - uint64_t image_size=0; - uint64_t read=0; - size_t written=0; - size_t to_write=0; - int ret; - char *p_buf2=NULL; - uint8_t is_block_cached=FALSE; - te_XmountCache_Error cache_ret=e_XmountCache_Error_None; - - // Make sure we aren't writing past EOF of image file - if(GetMorphedImageSize(&image_size)!=TRUE) { - LOG_ERROR("Couldn't get size of morphed image!\n"); - return -EIO; - } - if(offset>=image_size) { - // Offset is beyond image size - LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset); - *p_written=0; - return 0; - } - if(offset+count>image_size) { - // Attempt to write data past EOF of morphed image file - to_write=image_size-offset; - LOG_DEBUG("Attempt to write data past EOF of morphed image. Corrected size " - "from %zu to %" PRIu64 ".\n", - count, - to_write); - } else to_write=count; - - // Calculate block to start writing data to - cur_block=offset/XMOUNT_CACHE_BLOCK_SIZE; - block_off=offset%XMOUNT_CACHE_BLOCK_SIZE; - - while(to_write!=0) { - // Calculate how many bytes we have to write to this block - if(block_off+to_write>XMOUNT_CACHE_BLOCK_SIZE) { - cur_to_write=XMOUNT_CACHE_BLOCK_SIZE-block_off; - } else cur_to_write=to_write; - - // Determine if block is already in cache - is_block_cached=FALSE; - cache_ret=XmountCache_IsBlockCached(glob_xmount.h_cache,cur_block); - if(cache_ret==e_XmountCache_Error_None) is_block_cached=TRUE; - else if(cache_ret!=e_XmountCache_Error_UncachedBlock) { - LOG_ERROR("Unable to determine if block %" PRIu64 " is cached: " - "Error code %u!\n", - cur_block, - cache_ret); - return -EIO; - } - - // Check if block is cached - if(is_block_cached==TRUE) { - // Block is cached - cache_ret=XmountCache_BlockCacheWrite(glob_xmount.h_cache, - p_buf, - cur_block, - block_off, - cur_to_write); - if(cache_ret!=e_XmountCache_Error_None) { - LOG_ERROR("Unable to write %" PRIu64 - " bytes of data to cache block %" PRIu64 - " at cache block offset %" PRIu64 ": Error code %u!\n", - cur_to_write, - cur_block, - block_off, - cache_ret); - return -EIO; - } - - LOG_DEBUG("Wrote %" PRIu64 " bytes to block cache\n",cur_to_write); - } else { - // Uncached block. Need to cache entire new block - // Prepare new write buffer - XMOUNT_MALLOC(p_buf2,char*,XMOUNT_CACHE_BLOCK_SIZE); - memset(p_buf2,0x00,XMOUNT_CACHE_BLOCK_SIZE); - - // Read full block from morphed image - cur_to_read=XMOUNT_CACHE_BLOCK_SIZE; - if((cur_block*XMOUNT_CACHE_BLOCK_SIZE)+XMOUNT_CACHE_BLOCK_SIZE>image_size) { - cur_to_read=XMOUNT_CACHE_BLOCK_SIZE-(((cur_block*XMOUNT_CACHE_BLOCK_SIZE)+ - XMOUNT_CACHE_BLOCK_SIZE)-image_size); - } - ret=glob_xmount.morphing.p_functions->Read(glob_xmount.morphing.p_handle, - p_buf2, - cur_block*XMOUNT_CACHE_BLOCK_SIZE, - cur_to_read, - &read); - if(ret!=0 || read!=cur_to_read) { - LOG_ERROR("Couldn't read %" PRIu64 " bytes at offset %zu " - "from morphed image: %s!\n", - cur_to_read, - offset, - glob_xmount.morphing.p_functions->GetErrorMessage(ret)); - XMOUNT_FREE(p_buf2); - return -EIO; - } - - // Set changed data - memcpy(p_buf2+block_off,p_buf,cur_to_write); - - cache_ret=XmountCache_BlockCacheAppend(glob_xmount.h_cache, - p_buf, - cur_block); - if(cache_ret!=e_XmountCache_Error_None) { - LOG_ERROR("Unable to append new block cache block %" PRIu64 - ": Error code %u!\n", - cur_block, - cache_ret); - XMOUNT_FREE(p_buf2); - return -EIO; - } - XMOUNT_FREE(p_buf2); - - LOG_DEBUG("Appended new block cache block %" PRIu64 "\n",cur_block); - } - - block_off=0; - cur_block++; - p_buf+=cur_to_write; - to_write-=cur_to_write; - } - - *p_written=to_write; - return TRUE; + return e_XmountMorphError_UnsupportedType; } -*/ diff --git a/src/xmount_morphing.h b/src/xmount_morphing.h index bd98b7a..1d6c82c 100644 --- a/src/xmount_morphing.h +++ b/src/xmount_morphing.h @@ -1,342 +1,343 @@ /******************************************************************************* * xmount Copyright (c) 2008-2016 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 XMOUNT_MORPHING_H #define XMOUNT_MORPHING_H /******************************************************************************* * Public definitions / macros ******************************************************************************/ -//! Naming scheme of input libraries +//! Naming scheme of morphing libraries #define XMOUNT_MORPHING_LIBRARY_NAMING_SCHEME "libxmount_morph_" /******************************************************************************* * Public types / structures / enums ******************************************************************************/ //! Morphing handle typedef struct s_XmountMorphHandle *pts_XmountMorphHandle; /*! * \brief Function to get the amount of input images * * Function to get the amount of input images * * \param p_count Count of input images * \return 0 on success */ typedef int (*tfun_XmountMorphing_InputImageCount)(uint64_t *p_count); /*! * \brief Function to get the size of the morphed data * * Function to get the size of the morphed data * * \param image Image number * \param p_size Pointer to store input image's size to * \return 0 on success */ typedef int (*tfun_XmountMorphing_InputImageSize)(uint64_t image, uint64_t *p_size); //! Function to read data from input image /*! * \param image Image number * \param p_buf Buffer to store read data to * \param offset Position at which to start reading * \param count Amount of bytes to read * \param p_read Number of read bytes on success * \return 0 on success or negated error code on error */ typedef int (*tfun_XmountMorphing_InputImageRead)(uint64_t image, char *p_buf, off_t offset, size_t count, size_t *p_read); //! Function to write data to input image /*! * \param image Image number * \param p_buf Buffer to store read data to * \param offset Position at which to start reading * \param count Amount of bytes to read * \param p_read Number of read bytes on success * \return 0 on success or negated error code on error */ typedef int (*tfun_XmountMorphing_InputImageWrite)(uint64_t image, char *p_buf, off_t offset, size_t count, size_t *p_written); typedef enum e_XmountMorphError { //! No error e_XmountMorphError_None=0, //! Error to allocate memory e_XmountMorphError_Alloc, - //! Invalid input handle + //! Invalid morphing handle e_XmountMorphError_InvalidHandle, - //! Invalid pointer to an input handle + //! Invalid pointer to a morphing handle e_XmountMorphError_InvalidHandlePointer, //! A given buffer is invalid e_XmountMorphError_InvalidBuffer, //! A given string is invalid e_XmountMorphError_InvalidString, - //! A given array is invalid - //e_XmountMorphError_InvalidArray, //! Library options have already been set e_XmountMorphError_LibOptionsAlreadySet, //! Library options couldn't be parsed e_XmountMorphError_FailedParsingOptions, //! Unable to get info file content from library e_XmountMorphError_FailedGettingInfoFileContent, //! Unable to load library file e_XmountMorphError_FailedLoadingLibrary, //! Unable to load a library symbol e_XmountMorphError_FailedLoadingSymbol, //! Library has wrong API version e_XmountMorphError_WrongLibraryApiVersion, //! Library is missing a function e_XmountMorphError_MissingLibraryFunction, //! Unsupported morphing type - e_XmountInput_Error_UnsupportedType, -/* - //! Specified image number is incorrect - e_XmountInput_Error_NoSuchImage, - //! Unable to create input image handle - e_XmountInput_Error_FailedCreatingImageHandle, - //! Unable to parse input library options - e_XmountInput_Error_FailedParsingLibParams, - //! Unable to open input image - e_XmountInput_Error_FailedOpeningImage, -*/ + e_XmountMorphError_UnsupportedType, + //! Unable to create morphing image handle + e_XmountMorphError_FailedCreatingMorphHandle, + //! Unable to parse morphing library options + e_XmountMorphError_FailedParsingLibParams, //! Unable to get image size e_XmountMorphError_FailedGettingImageSize, -/* - //! A specified offset is larger than a specified image - e_XmountInput_Error_OffsetExceedsImageSize, - //! A specified size limit is larger than a specified image - e_XmountInput_Error_SizelimitExceedsImageSize, - //! Unable to read data from input image - e_XmountInput_Error_FailedReadingData -*/ + //! A specified offset is larger than the image + e_XmountMorphError_OffsetExceedsImageSize, + //! Unable to read data from morphed image + e_XmountMorphError_FailedReadingData } te_XmountMorphError; /******************************************************************************* * Public functions declarations ******************************************************************************/ /*! - * \brief Create new input handle + * \brief Create new morphing handle * - * Creates a new input handle. + * Creates a new morphing handle. * - * \param pp_h Pointer to input handle - * \return e_XmountInput_Error_None on success + * \param pp_h Pointer to morphing handle + * \return e_XmountMorphError_None on success */ -te_XmountMorphError XmountMorphing_CreateHandle(pts_XmountMorphHandle *pp_h, - tfun_XmountMorphing_InputImageCount fun_image_count, - tfun_XmountMorphing_InputImageSize fun_image_size, - tfun_XmountMorphing_InputImageRead fun_image_read, - tfun_XmountMorphing_InputImageWrite fun_image_write); +te_XmountMorphError + XmountMorphing_CreateHandle(pts_XmountMorphHandle *pp_h, + tfun_XmountMorphing_InputImageCount p_img_count, + tfun_XmountMorphing_InputImageSize p_img_size, + tfun_XmountMorphing_InputImageRead p_img_read, + tfun_XmountMorphing_InputImageWrite p_img_write); /*! - * \brief Destroy input handle + * \brief Destroy morphing handle * * Invalidates the given handle and frees all used resources. * - * \param pp_h Pointer to input handle - * \return e_XmountInput_Error_None on success + * \param pp_h Pointer to morphing handle + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_DestroyHandle(pts_XmountMorphHandle *pp_h); /*! * \brief Enable internal debugging * * Enables the generation of intrernal debugging messages. * - * \param p_h Input handle - * \return e_XmountInput_Error_None on success + * \param p_h Morphing handle + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_EnableDebugging(pts_XmountMorphHandle p_h); /*! - * \brief Load an input library + * \brief Load a morphing library * - * Loads a given input library. + * Loads a given morphing library. * - * \param p_h Input handle + * \param p_h Morphing handle * \param p_lib Library name (without path) - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_AddLibrary(pts_XmountMorphHandle p_h, const char *p_lib_name); /*! - * \brief Get loaded input library count + * \brief Get loaded morphing library count * - * Returns the number of successfully loaded input libraries. + * Returns the number of successfully loaded morphing libraries. * - * \param p_h Input handle + * \param p_h Morphing handle * \param p_count Library count is returned in this variable - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetLibraryCount(pts_XmountMorphHandle p_h, uint32_t *p_count); /*! * \brief Return all supported morphing types * * Returns a null-terminated vector of all supported morphing types. * * The returned vector must be freed by the caller. * * \param p_h Morphing handle * \param pp_types Supported types vector is returned in this var * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetSupportedTypes(pts_XmountMorphHandle p_h, char **pp_types); /*! * \brief Set library options * * Parses the given library option string (as given after --inopts). * - * \param p_h Input handle + * \param p_h Morphing handle * \param p_options Library option string - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_SetOptions(pts_XmountMorphHandle p_h, char *p_options); /*! * \brief Return all library specific option help texts * - * Returns a string containing help messages for all loaded input lib options. - * The string is pre-formated to be used in xmount's help output. + * Returns a string containing help messages for all loaded morphing lib + * options. The string is pre-formated to be used in xmount's help output. * * The caller must free the returned string. * - * \param p_h Input handle + * \param p_h Morphing handle * \param pp_help_text Help text is returned in this parameter - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetOptionsHelpText(pts_XmountMorphHandle p_h, char **pp_help_text); /*! * \brief Returns a string containing infos about loaded libs * - * Returns a string containing infos about loaded input libraries. The string is - * pre-formated to be used in xmount's info output. + * Returns a string containing infos about loaded morphing libraries. The + * string is pre-formated to be used in xmount's info output. * * The caller must free the returned string. * - * \param p_h Input handle + * \param p_h Morphing handle * \param pp_info_text Info text is returned in this parameter - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetLibsInfoText(pts_XmountMorphHandle p_h, char **pp_info_text); /*! * \brief Set morphing type * * Set the morphing type that should be applied to the input image. * - * \param p_h Input handle + * \param p_h Morphing handle * \param p_type Morphing type string as specified with xmount's --morph option. * \return e_XmountMorphError_None on success */ -te_XmountMorphError XmountMorphing_SaetType(pts_XmountMorphHandle p_h, - char *p_type); +te_XmountMorphError XmountMorphing_SetType(pts_XmountMorphHandle p_h, + char *p_type); /*! - * \brief Opens all added input images + * \brief Start the morphing process * - * Opens all added input images. + * Begins the morphing process. * - * \param p_h Input handle - * \return e_XmountInput_Error_None on success + * \param p_h Morphing handle + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_StartMorphing(pts_XmountMorphHandle p_h); /*! - * \brief Closes all previously opened input images + * \brief Stop the morphing process * - * Closes all previously opened input images. + * Ends the morphing process. * - * \param p_h Input handle - * \return e_XmountInput_Error_None on success + * \param p_h Morphing handle + * \return e_XmountMorphError_None on success */ -te_XmountMorphError XmountInput_StopMorphing(pts_XmountMorphHandle p_h); +te_XmountMorphError XmountMorphing_StopMorphing(pts_XmountMorphHandle p_h); /*! - * \brief Get the size of an input image + * \brief Get the size of the morphed image * - * Returns the size (in bytes) of the specified input image. + * Returns the size (in bytes) of the morphed image. * - * \param p_h Input handle + * \param p_h Morphing handle * \param image_nr Image number for which to return the size * \param p_size On success, size is returned in this variable - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetSize(pts_XmountMorphHandle p_h, uint64_t *p_size); /*! - * \brief Read data from an input image + * \brief Read data from the morphed image * - * Reads count bytes from input image image_nr starting at given offset and + * Reads count bytes from the morphed image starting at given offset and * copies the data into p_buf. * * The given buffer must be pre-allocated to hold as many bytes as should be * read! * - * \param p_h Input handle - * \param image_nr Image number for which to return the size + * \param p_h Morphing handle * \param p_buf Buffer into which to copy read data * \param offset Offset at which to start reading * \param count Amount of bytes to read * \param p_read On success, amount of bytes read is returned in this variable - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_ReadData(pts_XmountMorphHandle p_h, char *p_buf, uint64_t offset, uint64_t count, uint64_t *p_read); +/*! + * \brief Writes data to the morphed image + * + * Writes count bytes from p_buf to the morphed image starting at the given + * offset. + * + * \param p_h Morphing handle + * \param p_buf Buffer with data to write + * \param offset Offset at which to start writing + * \param count Amount of bytes to write + * \param p_written On success, amount of bytes written is returned here + * \return e_XmountMorphError_None on success + */ te_XmountMorphError XmountMorphing_WriteData(pts_XmountMorphHandle p_h, const char *p_buf, uint64_t offset, - uint64_t count); + uint64_t count, + uint64_t *p_written); /*! * \brief Get info text to be added to xmount's info file * - * Generates a string containing informations about currently opened input - * images. + * Generates a string containing informations about the currently morphed image. * * The caller must free the returned string. * - * \param p_h Input handle + * \param p_h Morphing handle * \param pp_content Buffer in which text is returned - * \return e_XmountInput_Error_None on success + * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetInfoFileContent(pts_XmountMorphHandle p_h, char **pp_content); #endif // XMOUNT_MORPHING_H