diff --git a/src/xmount.c b/src/xmount.c index d967f7e..5cfa25f 100755 --- a/src/xmount.c +++ b/src/xmount.c @@ -1,1660 +1,1695 @@ /******************************************************************************* * 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" #define XMOUNT_COPYRIGHT_NOTICE \ "xmount v%s Copyright (c) 2008-2016 by Gillen Daniel " -#define LOG_WARNING(...) { \ +#define IMAGE_INFO_INPUT_HEADER \ + "------> The following values are supplied by the used input library(ies) " \ + "<------\n" + +#define IMAGE_INFO_MORPHING_HEADER \ + "\n------> The following values are supplied by the used morphing library " \ + "<------\n\n" + +#define LOG_WARNING(...) do { \ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \ -} -#define LOG_ERROR(...) { \ +} while(0) + +#define LOG_ERROR(...) do { \ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \ -} -#define LOG_DEBUG(...) { \ +} while(0) + +#define LOG_DEBUG(...) do { \ LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \ -} +} while(0) #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(); /* * 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 morphing functions PRINTUSAGE__LIST_SUPP_LIB_TYPES(XmountOutput_GetSupportedFormats, glob_xmount.h_output, e_XmountOutputError_None); 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); PRINTUSAGE__LIST_LIB_OPT_HELP(XmountOutput_GetOptionsHelpText, glob_xmount.h_output, e_XmountOutputError_None); #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; 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; te_XmountOutputError output_ret=e_XmountOutputError_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)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 output_ret=XmountOutput_AddLibrary(glob_xmount.h_output, p_dirent->d_name); if(output_ret!=e_XmountOutputError_None) { LOG_ERROR("Unable to add output library '%s': Error code %u!\n", p_dirent->d_name, output_ret); continue; } } 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", morph_ret); return FALSE; } output_ret=XmountOutput_GetLibraryCount(glob_xmount.h_output, &output_lib_count); if(output_ret!=e_XmountOutputError_None) { LOG_ERROR("Unable to get output library count: Error code %u!\n", output_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, output_lib_count); closedir(p_dir); return ((input_lib_count>0 && morphing_lib_count>0 && output_lib_count>0) ? TRUE : FALSE); } static int InitResources() { te_XmountInput_Error input_ret=e_XmountInput_Error_None; te_XmountMorphError morph_ret=e_XmountMorphError_None; te_XmountOutputError output_ret=e_XmountOutputError_None; // Args glob_xmount.args.overwrite_cache=FALSE; glob_xmount.args.p_cache_file=NULL; glob_xmount.args.writable=FALSE; // 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(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 output_ret=XmountOutput_CreateHandle(&(glob_xmount.h_output), &LibXmount_Output_Size, &LibXmount_Output_Read, &LibXmount_Output_Write); if(output_ret!=e_XmountOutputError_None) { LOG_ERROR("Unable to create output handle: Error code %u!\n",output_ret); return FALSE; } // 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.p_info_path=NULL; glob_xmount.p_info_file=NULL; glob_xmount.image_hash_lo=0; glob_xmount.image_hash_hi=0; return TRUE; } /* * FreeResources */ static void FreeResources() { int ret; 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; te_XmountOutputError output_ret=e_XmountOutputError_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=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.args.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) { 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; te_XmountOutputError output_ret=e_XmountOutputError_None; // Set implemented FUSE functions struct fuse_operations xmount_operations = { + // File functions + .create=XmountFuse_create, + .ftruncate=XmountFuse_ftruncate, + .open=XmountFuse_open, + .read=XmountFuse_read, + .release=XmountFuse_release, + .write=XmountFuse_write, + // Dir functions + .mkdir=XmountFuse_mkdir, + .readdir=XmountFuse_readdir, + // Misc functions + .chmod=XmountFuse_chmod, + .chown=XmountFuse_chown, + .getattr=XmountFuse_getattr, + .link=XmountFuse_link, + .readlink=XmountFuse_readlink, + .rename=XmountFuse_rename, + .rmdir=XmountFuse_rmdir, + //.statfs=XmountFuse_statfs, + .symlink=XmountFuse_symlink, + .truncate=XmountFuse_truncate, + .utimens=XmountFuse_utimens, + .unlink=XmountFuse_unlink +/* //.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") + 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") + 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") + LOG_ERROR("Couldn't parse command line options!\n"); PrintUsage(argv[0]); FreeResources(); return 1; } // 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: ") + LOG_DEBUG("Options passed to FUSE: "); for(int i=0;i * * * * xmount is a small tool to "fuse mount" various image formats and enable * * virtual write access. * * * * 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_H #define XMOUNT_H #include "../libxmount/libxmount.h" #include "xmount_input.h" #include "xmount_morphing.h" #include "xmount_cache.h" #include "xmount_output.h" #undef FALSE #undef TRUE #define FALSE 0 #define TRUE 1 /* * Constants */ -#define IMAGE_INFO_INPUT_HEADER \ - "------> The following values are supplied by the used input library(ies) " \ - "<------\n" -#define IMAGE_INFO_MORPHING_HEADER \ - "\n------> The following values are supplied by the used morphing library " \ - "<------\n\n" +#define XMOUNT_ /******************************************************************************* * Xmount specific structures ******************************************************************************/ //! Return codes typedef enum e_XmountError { //! No error e_XmountError_None=0, } te_XmountError; //! Structure containing xmount arguments typedef struct s_XmountArgs { //! Cache file char *p_cache_file; //! If set to 1, overwrite any existing cache file uint8_t overwrite_cache; //! Writable? (Set to 1 if --cache was specified) uint8_t writable; } ts_XmountArgs; //! Structure containing global xmount runtime infos typedef struct s_XmountData { //! Parsed xmount arguments ts_XmountArgs args; //! Input image related data pts_XmountInputHandle h_input; //! Morphing related data pts_XmountMorphHandle h_morphing; //! Cache file handle pts_XmountCacheHandle h_cache; //! Output image related data pts_XmountOutputHandle h_output; //! Enable debug output uint8_t debug; //! Set if we are allowed to set fuse's allow_other option uint8_t may_set_fuse_allow_other; //! Argv for FUSE int fuse_argc; //! Argv for FUSE char **pp_fuse_argv; //! Mount point char *p_mountpoint; //! First input image's path/name char *p_first_input_image_name; //! Path of virtual image info file char *p_info_path; //! Pointer to virtual info file char *p_info_file; //! MD5 hash of partial input image (lower 64 bit) (after morph) uint64_t image_hash_lo; //! MD5 hash of partial input image (higher 64 bit) (after morph) uint64_t image_hash_hi; //! Mutex to control concurrent read & write access on output image pthread_mutex_t mutex_image_rw; //! Mutex to control concurrent read access on info file pthread_mutex_t mutex_info_read; } ts_XmountData; /******************************************************************************* * Global vars ******************************************************************************/ //! Struct that contains various runtime configuration options ts_XmountData glob_xmount; /******************************************************************************* * Xmount functions ******************************************************************************/ +te_XmountError Xmount_GetFileAttr(const char *p_path, struct stat *p_stat); +te_XmountError Xmount_GetDirListing(const char *p_path, + uint64_t *p_dir_entries, + char ***ppp_dir_entries); #endif // XMOUNT_H diff --git a/src/xmount_cache.c b/src/xmount_cache.c index c6f6e79..3b0e9a5 100644 --- a/src/xmount_cache.c +++ b/src/xmount_cache.c @@ -1,798 +1,853 @@ /******************************************************************************* * 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 #include #include +#include #include "xmount_cache.h" -#include "xmount.h" +#include "../libxmount/libxmount.h" #include "macros.h" /******************************************************************************* * Private definitions / macros ******************************************************************************/ -#define LOG_WARNING(...) { \ +#define LOG_WARNING(...) do { \ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \ -} -#define LOG_ERROR(...) { \ +} while(0) + +#define LOG_ERROR(...) do { \ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \ -} -#define LOG_DEBUG(...) { \ - LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \ -} +} while(0) + +#define LOG_DEBUG(...) do { \ + LIBXMOUNT_LOG_DEBUG(p_h->debug,__VA_ARGS__); \ +} while(0) #ifndef __LP64__ //! Value used to indicate an uncached block entry #define XMOUNT_CACHE_INVALID_INDEX 0xFFFFFFFFFFFFFFFFLL #else #define XMOUNT_CACHE_INVALID_INDEX 0xFFFFFFFFFFFFFFFF #endif //! Structures and vars needed for write access #define XMOUNT_CACHE_FOLDER "/.xmount" #define XMOUNT_CACHE_BLOCK_FILE XMOUNT_CACHE_FOLDER "/blocks.data" #define XMOUNT_CACHE_BLOCK_INDEX_FILE XMOUNT_CACHE_FOLDER "/blocks.index" /******************************************************************************* * Private types / structures / enums ******************************************************************************/ typedef struct s_XmountCacheHandle { //! Cache file to save changes to char *p_cache_file; //! Handle to cache file hGidaFs h_cache_file; //! Handle to block cache hGidaFsFile h_block_cache; //! Handle to block cache index hGidaFsFile h_block_cache_index; //! In-memory copy of cache index uint64_t *p_block_cache_index; //! Length (in elements) of in-memory block cache index uint64_t block_cache_index_len; // TODO: Move to s_XmountData //! Overwrite existing cache uint8_t overwrite_cache; + //! Debug + uint8_t debug; } ts_XmountCacheHandle, *pts_XmountCacheHandle; /******************************************************************************* * Private functions declarations ******************************************************************************/ /*! * \brief Create a new xmount cache handle * * \param pp_h Pointer to an xmount cache handle * \param p_file Cache file path / name * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_CreateHandle(pts_XmountCacheHandle *pp_h, const char *p_file); /*! * \brief Destroy an xmount cache handle * * \param pp_h Pointer to an xmount cache handle * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_DestroyHandle(pts_XmountCacheHandle *pp_h); /*! * \brief Check if a file exists * * Checks if the given file p_file exists. * * \param p_file File to check for * \return e_XmountCache_Error_None if file exists */ te_XmountCache_Error XmountCache_FileExists(const char *p_file); /*! * \brief Updates a block cache entry * * Updates the given block cache index entry on disk. If the special value * XMOUNT_CACHE_INVALID_INDEX is given as entry value, the whole block cache * index is updated. * * \param p_h Cache handle * \param entry Block cache entry number to update * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_UpdateIndex(pts_XmountCacheHandle p_h, uint64_t entry); /******************************************************************************* * Public functions implementations ******************************************************************************/ /* * XmountCache_Create */ te_XmountCache_Error XmountCache_Create(pts_XmountCacheHandle *pp_h, const char *p_file, uint64_t image_size, uint8_t overwrite) { pts_XmountCacheHandle p_h=NULL; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer; if(p_file==NULL) return e_XmountCache_Error_InvalidString; if(strlen(p_file)==0) return e_XmountCache_Error_InvalidFile; // Make sure file does not exist when overwrite was not specified if(overwrite==0 && XmountCache_FileExists(p_file)==e_XmountCache_Error_None) { // Given file exists and overwrite was not specified. This is fatal! return e_XmountCache_Error_ExistingFile; } // Create new handle ret=XmountCache_CreateHandle(&p_h,p_file); if(ret!=e_XmountCache_Error_None) return ret; #define XMOUNTCACHE_CREATE__DESTROY_HANDLE do { \ ret=XmountCache_DestroyHandle(&p_h); \ if(ret!=e_XmountCache_Error_None) { \ LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", \ ret); \ } \ *pp_h=NULL; \ } while(0) // Create new cache file gidafs_ret=GidaFsLib_NewFs(&(p_h->h_cache_file), p_h->p_cache_file, 0); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create new xmount cache file '%s': Error code %u!\n", p_h->p_cache_file, gidafs_ret); XMOUNTCACHE_CREATE__DESTROY_HANDLE; - return FALSE; + return e_XmountCache_Error_FailedCacheInit; } #define XMOUNTCACHE_CREATE__CLOSE_CACHE do { \ gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close xmount cache file '%s': " \ "Error code %u: Ignoring!\n", \ p_h->p_cache_file, \ gidafs_ret); \ } \ } while(0) // TODO: Check if cache file uses same block size as we do // Create needed xmount subdirectory gidafs_ret=GidaFsLib_CreateDir(p_h->h_cache_file, XMOUNT_CACHE_FOLDER, eGidaFsNodeFlag_RWXu); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create cache file directory '%s': Error code %u!\n", XMOUNT_CACHE_FOLDER, gidafs_ret); XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; return e_XmountCache_Error_FailedCacheInit; } // Create block cache file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_FILE, &(p_h->h_block_cache), eGidaFsOpenFileFlag_ReadWrite | eGidaFsOpenFileFlag_CreateAlways, eGidaFsNodeFlag_Rall | eGidaFsNodeFlag_Wusr); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create block cache file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedCacheInit; } #define XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Create block cache index file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_INDEX_FILE, &(p_h->h_block_cache_index), eGidaFsOpenFileFlag_ReadWrite | eGidaFsOpenFileFlag_CreateAlways, eGidaFsNodeFlag_Rall | eGidaFsNodeFlag_Wusr); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create block cache index file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE; XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedCacheInit; } #define XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache_index)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache index file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Calculate how many cache blocks are needed and how big the cache block // index must be p_h->block_cache_index_len=image_size/XMOUNT_CACHE_BLOCK_SIZE; if((image_size%XMOUNT_CACHE_BLOCK_SIZE)!=0) p_h->block_cache_index_len++; LOG_DEBUG("Cache blocks: %" PRIu64 " entries using %" PRIu64 " bytes\n", p_h->block_cache_index_len, p_h->block_cache_index_len*sizeof(uint8_t)); // Prepare in-memory buffer for block cache index p_h->p_block_cache_index= (uint64_t*)calloc(1,p_h->block_cache_index_len*sizeof(uint64_t)); if(p_h->p_block_cache_index==NULL) { XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE; XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; return e_XmountCache_Error_Alloc; } // Generate initial block cache index for(uint64_t i=0;iblock_cache_index_len;i++) { p_h->p_block_cache_index[i]=XMOUNT_CACHE_INVALID_INDEX; } // Write initial block cache index to cache file ret=XmountCache_UpdateIndex(p_h,XMOUNT_CACHE_INVALID_INDEX); if(ret!=e_XmountCache_Error_None) { LOG_ERROR("Unable to update initial block cache index file: " "Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, ret); XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE; XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; return ret; } #undef XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX #undef XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE #undef XMOUNTCACHE_CREATE__CLOSE_CACHE #undef XMOUNTCACHE_CREATE__DESTROY_HANDLE *pp_h=p_h; return e_XmountCache_Error_None; } /* * XmountCache_Open */ te_XmountCache_Error XmountCache_Open(pts_XmountCacheHandle *pp_h, const char *p_file, uint64_t image_size) { uint64_t blockindex_size=0; uint64_t read=0; pts_XmountCacheHandle p_h=NULL; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer; if(p_file==NULL) return e_XmountCache_Error_InvalidString; if(strlen(p_file)==0) return e_XmountCache_Error_InvalidFile; // If file does not exist, create it if(XmountCache_FileExists(p_file)!=e_XmountCache_Error_None) { // Given file does not exist. Call XmountCache_Create instead! return XmountCache_Create(pp_h,p_file,image_size,0); } // Create new handle ret=XmountCache_CreateHandle(&p_h,p_file); if(ret!=e_XmountCache_Error_None) return ret; #define XMOUNTCACHE_OPEN__DESTROY_HANDLE do { \ ret=XmountCache_DestroyHandle(&p_h); \ if(ret!=e_XmountCache_Error_None) { \ LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", \ ret); \ } \ *pp_h=NULL; \ } while(0) // Open cache file gidafs_ret=GidaFsLib_OpenFs(&(p_h->h_cache_file),p_h->p_cache_file); if(gidafs_ret!=eGidaFsError_None) { // TODO: Check for old cache file type and inform user it isn't supported // anymore! LOG_ERROR("Couldn't open xmount cache file '%s': Error code %u!\n", p_h->p_cache_file, - gidafs_ret) + gidafs_ret); return e_XmountCache_Error_FailedOpeningCache; } #define XMOUNTCACHE_OPEN__CLOSE_CACHE do { \ gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close xmount cache file '%s': " \ "Error code %u: Ignoring!\n", \ p_h->p_cache_file, \ gidafs_ret); \ } \ } while(0) // Open block cache file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_FILE, &(p_h->h_block_cache), eGidaFsOpenFileFlag_ReadWrite, 0); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to open block cache file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedOpeningCache; } #define XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Open block cache index file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_INDEX_FILE, &(p_h->h_block_cache_index), eGidaFsOpenFileFlag_ReadWrite, 0); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to open block cache index file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedOpeningCache; } #define XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache_index)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache index file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Calculate how many cache blocks are needed and how big the cache block // index must be p_h->block_cache_index_len=image_size/XMOUNT_CACHE_BLOCK_SIZE; if((image_size%XMOUNT_CACHE_BLOCK_SIZE)!=0) p_h->block_cache_index_len++; LOG_DEBUG("Cache blocks: %" PRIu64 " entries using %" PRIu64 " bytes\n", p_h->block_cache_index_len, p_h->block_cache_index_len*sizeof(uint8_t)); // Make sure block cache index has correct size gidafs_ret=GidaFsLib_GetFileSize(p_h->h_cache_file, p_h->h_block_cache_index, &blockindex_size); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to get block cache index file size: Error code %u!\n", - gidafs_ret) + gidafs_ret); XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_FailedGettingIndexSize; } if(blockindex_size%sizeof(uint64_t)!=0 || (blockindex_size/sizeof(uint64_t))!=p_h->block_cache_index_len) { // TODO: Be more helpfull in error message - LOG_ERROR("Block cache index size is incorrect for given input image!\n") + LOG_ERROR("Block cache index size is incorrect for given input image!\n"); XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_InvalidIndexSize; } // Prepare in-memory buffer for block cache index p_h->p_block_cache_index= (uint64_t*)calloc(1,p_h->block_cache_index_len*sizeof(uint64_t)); if(p_h->p_block_cache_index==NULL) { XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_Alloc; } // Read block cache index into memory gidafs_ret=GidaFsLib_ReadFile(p_h->h_cache_file, p_h->h_block_cache_index, 0, blockindex_size, p_h->p_block_cache_index, &read); if(gidafs_ret!=eGidaFsError_None || read!=blockindex_size) { LOG_ERROR("Unable to read block cache index: Error code %u!\n", gidafs_ret); XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_FailedReadingIndex; } #undef XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX #undef XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE #undef XMOUNTCACHE_OPEN__CLOSE_CACHE #undef XMOUNTCACHE_OPEN__DESTROY_HANDLE *pp_h=p_h; return e_XmountCache_Error_None; } /* * XmountCache_Close */ te_XmountCache_Error XmountCache_Close(pts_XmountCacheHandle *pp_h) { pts_XmountCacheHandle p_h=NULL; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error final_ret=e_XmountCache_Error_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer; if(*pp_h==NULL) return e_XmountCache_Error_InvalidHandle; p_h=*pp_h; // Close block cache index gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file,&(p_h->h_block_cache_index)); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to close block cache index file: Error code %u: " "Ignoring!\n", gidafs_ret); if(final_ret==e_XmountCache_Error_None) { final_ret=e_XmountCache_Error_FailedClosingIndex; } } // Close block cache gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file,&(p_h->h_block_cache)); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to close block cache file: Error code %u: " "Ignoring!\n", gidafs_ret); if(final_ret==e_XmountCache_Error_None) { final_ret=e_XmountCache_Error_FailedClosingBlockCache; } } // Close cache file gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to close xmount cache file '%s': Error code %u: " "Ignoring!\n", p_h->p_cache_file, gidafs_ret); if(final_ret==e_XmountCache_Error_None) { final_ret=e_XmountCache_Error_FailedClosingCache; } } // Destroy handle ret=XmountCache_DestroyHandle(&p_h); if(ret!=e_XmountCache_Error_None) { LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", ret); if(final_ret==e_XmountCache_Error_None) { final_ret=ret; } } *pp_h=NULL; return final_ret; } +/* + * XmountCache_GetGidaFsHandle + */ +hGidaFs XmountCache_GetGidaFsHandle(pts_XmountCacheHandle p_h) { + // Params check + if(p_h==NULL) return NULL; + + // Return handle + return p_h->h_cache_file; +} + /* * XmountCache_BlockCacheRead */ te_XmountCache_Error XmountCache_BlockCacheRead(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block, uint64_t block_offset, uint64_t count) { uint64_t read=0; teGidaFsError gidafs_ret=eGidaFsError_None; // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(p_buf==NULL) return e_XmountCache_Error_InvalidBuffer; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; if(block_offset>XMOUNT_CACHE_BLOCK_SIZE || block_offset+count>XMOUNT_CACHE_BLOCK_SIZE) { return e_XmountCache_Error_ReadBeyondBlockBounds; } if(p_h->p_block_cache_index[block]==XMOUNT_CACHE_INVALID_INDEX) { return e_XmountCache_Error_UncachedBlock; } // Read requested data from block cache file gidafs_ret=GidaFsLib_ReadFile(p_h->h_cache_file, p_h->h_block_cache, p_h->p_block_cache_index[block]+block_offset, count, p_buf, &read); if(gidafs_ret!=eGidaFsError_None || read!=count) { LOG_ERROR("Unable to read cached data from block %" PRIu64 ": Error code %u!\n", block, gidafs_ret); return e_XmountCache_Error_FailedReadingBlockCache; } return e_XmountCache_Error_None; } /* * XmountCache_BlockCacheWrite */ te_XmountCache_Error XmountCache_BlockCacheWrite(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block, uint64_t block_offset, uint64_t count) { uint64_t written=0; teGidaFsError gidafs_ret=eGidaFsError_None; // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(p_buf==NULL) return e_XmountCache_Error_InvalidBuffer; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; if(block_offset>XMOUNT_CACHE_BLOCK_SIZE || block_offset+count>XMOUNT_CACHE_BLOCK_SIZE) { return e_XmountCache_Error_ReadBeyondBlockBounds; } if(p_h->p_block_cache_index[block]==XMOUNT_CACHE_INVALID_INDEX) { return e_XmountCache_Error_UncachedBlock; } gidafs_ret=GidaFsLib_WriteFile(p_h->h_cache_file, p_h->h_block_cache, p_h->p_block_cache_index[block]+block_offset, count, p_buf, &written); if(gidafs_ret!=eGidaFsError_None || written!=count) { LOG_ERROR("Unable to write data to cached block %" PRIu64 ": Error code %u!\n", block, gidafs_ret); return e_XmountCache_Error_FailedWritingBlockCache; } return e_XmountCache_Error_None; } /* * XmountCache_BlockCacheAppend */ te_XmountCache_Error XmountCache_BlockCacheAppend(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block) { uint64_t written=0; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(p_buf==NULL) return e_XmountCache_Error_InvalidBuffer; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; // Get current block cache size gidafs_ret=GidaFsLib_GetFileSize(p_h->h_cache_file, p_h->h_block_cache, &(p_h->p_block_cache_index[block])); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to get current block cache size: Error code %u!\n", gidafs_ret); return e_XmountCache_Error_FailedGettingIndexSize; } // Append new block gidafs_ret=GidaFsLib_WriteFile(p_h->h_cache_file, p_h->h_block_cache, p_h->p_block_cache_index[block], XMOUNT_CACHE_BLOCK_SIZE, p_buf, &written); if(gidafs_ret!=eGidaFsError_None || written!=XMOUNT_CACHE_BLOCK_SIZE) { LOG_ERROR("Unable to write data to cached block %" PRIu64 ": Error code %u!\n", block, gidafs_ret); return e_XmountCache_Error_FailedWritingBlockCache; } // Update on-disk block cache index ret=XmountCache_UpdateIndex(p_h,block); if(ret!=e_XmountCache_Error_None) { LOG_ERROR("Unable to update block cache index %" PRIu64 ": Error code %u!\n", block, ret); return ret; } return e_XmountCache_Error_None; } /* * XmountCache_IsBlockCached */ te_XmountCache_Error XmountCache_IsBlockCached(pts_XmountCacheHandle p_h, uint64_t block) { // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; // Check if given block has been cached previously if(p_h->p_block_cache_index[block]==XMOUNT_CACHE_INVALID_INDEX) { // Block is not in cache return e_XmountCache_Error_UncachedBlock; } return e_XmountCache_Error_None; } /******************************************************************************* * Private functions implementations ******************************************************************************/ /* * XmountCache_CreateHandle */ te_XmountCache_Error XmountCache_CreateHandle(pts_XmountCacheHandle *pp_h, const char *p_file) { pts_XmountCacheHandle p_h=NULL; // Alloc memory for handle p_h=(pts_XmountCacheHandle)calloc(1,sizeof(ts_XmountCacheHandle)); if(p_h==NULL) { *pp_h=NULL; return e_XmountCache_Error_Alloc; } // Init values. The p_cache_file alloc and memcpy works corrently as strlen() // counts the amount of bytes, not chars. No UTF8-issue here. p_h->p_cache_file=(char*)calloc(1,strlen(p_file)+1); if(p_h->p_cache_file==NULL) { free(p_h); *pp_h=NULL; return e_XmountCache_Error_Alloc; } memcpy(p_h->p_cache_file,p_file,strlen(p_file)); p_h->h_cache_file=NULL; p_h->h_block_cache=NULL; p_h->h_block_cache_index=NULL; p_h->p_block_cache_index=NULL; // Return new handle *pp_h=p_h; return e_XmountCache_Error_None; } /* * XmountCache_DestroyHandle */ te_XmountCache_Error XmountCache_DestroyHandle(pts_XmountCacheHandle *pp_h) { pts_XmountCacheHandle p_h=*pp_h; // Free handle if(p_h->p_cache_file!=NULL) free(p_h->p_cache_file); if(p_h->p_block_cache_index!=NULL) free(p_h->p_block_cache_index); free(p_h); // Return destroyed handle *pp_h=NULL; return e_XmountCache_Error_None; } /* * XmountCache_FileExists */ te_XmountCache_Error XmountCache_FileExists(const char *p_file) { struct stat statbuf; if(lstat(p_file,&statbuf)==0) return e_XmountCache_Error_None; else return e_XmountCache_Error_InexistingFile; } /* * XmountCache_UpdateIndex */ te_XmountCache_Error XmountCache_UpdateIndex(pts_XmountCacheHandle p_h, uint64_t entry) { uint64_t update_size=0; uint64_t written=0; uint64_t *p_buf; teGidaFsError gidafs_ret=eGidaFsError_None; if(entry!=XMOUNT_CACHE_INVALID_INDEX) { // Update specific index entry in cache file p_buf=p_h->p_block_cache_index+entry; update_size=sizeof(uint64_t); } else { // Dump whole block cache index to cache file p_buf=p_h->p_block_cache_index; update_size=p_h->block_cache_index_len*sizeof(uint64_t); } // Update cache file gidafs_ret=GidaFsLib_WriteFile(p_h->h_cache_file, p_h->h_block_cache_index, 0, update_size, p_buf, &written); if(gidafs_ret!=eGidaFsError_None || written!=update_size) { LOG_ERROR("Unable to update block cache index: Error code %u!\n", - gidafs_ret) + gidafs_ret); return e_XmountCache_Error_FailedUpdatingIndex; } return e_XmountCache_Error_None; } + +/* + * XmountCache_GidaFsError2Errno + */ +int XmountCache_GidaFsError2Errno(teGidaFsError error_code) { + switch(error_code) { + case eGidaFsError_ExistingEntry: + return -EEXIST; + case eGidaFsError_UnableToOpenDirectoryAsFile: + return -EISDIR; + case eGidaFsError_InexistingFile: + case eGidaFsError_InexistingPathElement: + case eGidaFsError_InexistingDirEntry: + return -ENOENT; + case eGidaFsError_NonDirInPath: + return -ENOTDIR; + case eGidaFsError_EndOfNodeData: + case eGidaFsError_NoMoreEntries: + return 0; + case eGidaFsError_InvalidDirEntryHandle: + case eGidaFsError_InvalidDirEntryHandlePointer: + case eGidaFsError_InvalidDirHandle: + case eGidaFsError_InvalidDirHandlePointer: + case eGidaFsError_InvalidFileHandle: + case eGidaFsError_InvalidFileHandlePointer: + return -EBADF; + case eGidaFsError_UnableToOpenNonDirectoryAsDirectory: + return -ENOTDIR; + case eGidaFsError_InvalidObjectName: + case eGidaFsError_InvalidObjectPath: + return -ENAMETOOLONG; + case eGidaFsError_FailedWritingRawData: + return -ENOSPC; + case eGidaFsError_UnableToReadNonSymlinkAsSymlink: + return -EINVAL; + default: + return -EIO; + } +} diff --git a/src/xmount_cache.h b/src/xmount_cache.h index 5431e3f..2c68c1c 100644 --- a/src/xmount_cache.h +++ b/src/xmount_cache.h @@ -1,203 +1,224 @@ /******************************************************************************* * 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_CACHE_H #define XMOUNT_CACHE_H #include /******************************************************************************* * Public definitions / macros ******************************************************************************/ //! Default block cache block size to use (1 megabyte) #define XMOUNT_CACHE_BLOCK_SIZE (1024*1024) /******************************************************************************* * Public types / structures / enums ******************************************************************************/ typedef struct s_XmountCacheHandle *pts_XmountCacheHandle; typedef enum e_XmountCache_Error { //! No error e_XmountCache_Error_None=0, //! Error to allocate memory e_XmountCache_Error_Alloc, //! Invalid cache handle e_XmountCache_Error_InvalidHandle, //! Invalid pointer to a cache handle e_XmountCache_Error_InvalidHandlePointer, //! A given string is invalid e_XmountCache_Error_InvalidString, //! A given file path / name is invalid e_XmountCache_Error_InvalidFile, //! A given file does not exist e_XmountCache_Error_InexistingFile, //! A given file exists e_XmountCache_Error_ExistingFile, //! Unable to create needed xmount structures inside cache file e_XmountCache_Error_FailedCacheInit, //! Unable to open xmount cache file e_XmountCache_Error_FailedOpeningCache, //! Failed to get block cache index size e_XmountCache_Error_FailedGettingIndexSize, //! Invalid block cache index size e_XmountCache_Error_InvalidIndexSize, //! Unable to read block cache index e_XmountCache_Error_FailedReadingIndex, //! Failed closing cache block index e_XmountCache_Error_FailedClosingIndex, //! Failed closing cache block index e_XmountCache_Error_FailedClosingBlockCache, //! Failed closing cache block index e_XmountCache_Error_FailedClosingCache, //! Failed to update block cache index e_XmountCache_Error_FailedUpdatingIndex, //! Invalid block cache index specified e_XmountCache_Error_InvalidIndex, //! Block has not yet been cached e_XmountCache_Error_UncachedBlock, //! Invalid buffer specified e_XmountCache_Error_InvalidBuffer, //! Request would read beyond a single cache block e_XmountCache_Error_ReadBeyondBlockBounds, //! Failed reading cached data e_XmountCache_Error_FailedReadingBlockCache, //! Failed writing cached data e_XmountCache_Error_FailedWritingBlockCache, } te_XmountCache_Error; /******************************************************************************* * Public functions declarations ******************************************************************************/ /*! * \brief Create new xmount cache file * * Creates a new xmount cache file in the given file. If the given file already * exists, this function will fail except if overwrite is set to 1. * * \param pp_handle Pointer to an xmount cache handle * \param p_file File to use as cache file * \param image_size Size of image in bytes for which this cache will be used * \param overwrite If set to 1, overwrites existig cache file * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_Create(pts_XmountCacheHandle *pp_h, const char *p_file, uint64_t image_size, uint8_t overwrite); /*! * \brief Open an existing xmount cache file * * Opens the given xmount cache file. * - * \param pp_handle Pointer to an xmount cache handle + * \param pp_h Pointer to an xmount cache handle * \param p_file File to use as cache file * \param image_size Size of image in bytes for which this cache will be used * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_Open(pts_XmountCacheHandle *pp_h, const char *p_file, uint64_t image_size); /*! * \brief Closes a previously openend xmount cache file * * Closes the given xmount cache file and frees any used resources. * - * \param pp_handle Pointer to an xmount cache handle + * \param pp_h Pointer to an xmount cache handle * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_Close(pts_XmountCacheHandle *pp_h); +/*! + * \brief Get GidaFS handle + * + * Returns the raw GidaFS handle used by XmountCache. This handle can be + * used to manipulate the underlying cache file directly. + * + * \param p_h Xmount cache handle + * \return GidaFS handle on success or NULL on error + */ +hGidaFs XmountCache_GetGidaFsHandle(pts_XmountCacheHandle p_h); + /*! * \brief Read data from block cache * * Reads count bytes at offset block_offset from block number block and writes * the read data into the pre-allocated buffer p_buf. The given block has to * have been previously cached by a call to XmountCache_BlockCacheAppend(). * * WARNING: This function does only work on single blocks. It is not possible to * read beyond a block end. * - * \param p_handle Xmount cache handle + * \param p_h Xmount cache handle * \param p_buf Buffer to store read data into * \param block Number of block to read data from * \param block_offset Offset inside block to start reading from * \param count Amount of bytes to read * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_BlockCacheRead(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block, uint64_t block_offset, uint64_t count); /*! * \brief Write data to block cache * * Writes count bytes from buffer p_buf to block number block at offset * block_offset. The given block has to have been previously cached by a call to * XmountCache_BlockCacheAppend(). * * WARNING: This function does only work on single blocks. It is not possible to * write beyond a block end. * - * \param p_handle Xmount cache handle + * \param p_h Xmount cache handle * \param p_buf Buffer with data to write * \param block Number of block to write data to * \param block_offset Offset inside block to start writing from * \param count Amount of bytes to write * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_BlockCacheWrite(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block, uint64_t block_offset, uint64_t count); /*! * \brief Add a new block to the cache * * Adds the data inside p_buf to the cache file and saves it under the block * number block. Every block must contain exactly XMOUNT_CACHE_BLOCK_SIZE bytes. * Every block can only be cached once. Appending the same block twice will * fail. * - * \param p_handle Xmount cache handle + * \param p_h Xmount cache handle * \param p_buf Buffer with block data * \param block Number of block under which to save given data * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_BlockCacheAppend(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block); /*! * \brief Chech if a block has previously been chached * * Checks if the given block has previously been cached. If it hasn't, * e_XmountCache_Error_UncachedBlock is returned. * - * \param p_handle Xmount cache handle + * \param p_h Xmount cache handle * \param block Number of block to check * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_IsBlockCached(pts_XmountCacheHandle p_h, uint64_t block); +/*! + * \brief Translate GidaFS error into errno + * + * Translates the given GidaFS error code into its corresponding errno + * + * \param error_code GidaFS error + * \return errno + */ +int XmountCache_GidaFsError2Errno(teGidaFsError error_code); + #endif // XMOUNT_CACHE_H diff --git a/src/xmount_fuse.c b/src/xmount_fuse.c index 50ca6af..eaf173b 100644 --- a/src/xmount_fuse.c +++ b/src/xmount_fuse.c @@ -1,393 +1,1073 @@ /******************************************************************************* * 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 #include #include #include #include #include "xmount_fuse.h" +#include "xmount_cache.h" +#include "../libxmount/libxmount.h" #include "xmount.h" #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__); \ } /******************************************************************************* - * FUSE function implementation + * FUSE operations implementation + * File functions ******************************************************************************/ -//! FUSE access implementation -/*! - * \param p_path Path of file to get attributes from - * \param perm Requested permissisons - * \return 0 on success, negated error code on error +/* + * XmountFuse_create + */ +int XmountFuse_create(const char *p_path, + mode_t mode, + struct fuse_file_info *p_fi) +{ + teGidaFsError ret=eGidaFsError_None; + teGidaFsOpenFileFlag flags=eGidaFsOpenFileFlag_None; + teGidaFsNodePermissions perms=eGidaFsNodeFlag_None; + hGidaFsFile h_file=NULL; + + if((p_fi->flags&O_TMPFILE)==O_TMPFILE) { + // GidaFS does not support the O_TMPFILE flag + return -EOPNOTSUPP; + } + + // Parse open flags and always add eGidaFsOpenFileFlag_Create + if((p_fi->flags&O_RDONLY)==O_RDONLY) flags|=eGidaFsOpenFileFlag_ReadOnly; + if((p_fi->flags&O_WRONLY)==O_WRONLY) flags|=eGidaFsOpenFileFlag_WriteOnly; + if((p_fi->flags&O_RDWR)==O_RDWR) flags|=eGidaFsOpenFileFlag_ReadWrite; + flags|=eGidaFsOpenFileFlag_Create; + + // Parse mode + if((mode&S_IXOTH)==S_IXOTH) perms|=eGidaFsNodeFlag_Xoth; + if((mode&S_IWOTH)==S_IWOTH) perms|=eGidaFsNodeFlag_Woth; + if((mode&S_IROTH)==S_IROTH) perms|=eGidaFsNodeFlag_Roth; + if((mode&S_IRWXO)==S_IRWXO) perms|=eGidaFsNodeFlag_RWXo; + if((mode&S_IXGRP)==S_IXGRP) perms|=eGidaFsNodeFlag_Xgrp; + if((mode&S_IWGRP)==S_IWGRP) perms|=eGidaFsNodeFlag_Wgrp; + if((mode&S_IRGRP)==S_IRGRP) perms|=eGidaFsNodeFlag_Rgrp; + if((mode&S_IRWXG)==S_IRWXG) perms|=eGidaFsNodeFlag_RWXg; + if((mode&S_IXUSR)==S_IXUSR) perms|=eGidaFsNodeFlag_Xusr; + if((mode&S_IWUSR)==S_IWUSR) perms|=eGidaFsNodeFlag_Wusr; + if((mode&S_IRUSR)==S_IRUSR) perms|=eGidaFsNodeFlag_Rusr; + if((mode&S_IRWXU)==S_IRWXU) perms|=eGidaFsNodeFlag_RWXu; + + // Try to open requested file + if((ret=GidaFsLib_OpenFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + &h_file, + flags, + perms))!=eGidaFsError_None) + { + LOG_ERROR("Unable to open file '%s': Error %u!",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Save file handle and return + p_fi->fh=(uint64_t)h_file; + return 0; +} + +/* + * XmountFuse_ftruncate + */ +int XmountFuse_ftruncate(const char *p_path, + off_t offset, + struct fuse_file_info *p_fi) +{ + teGidaFsError ret=eGidaFsError_None; + hGidaFsFile h_file=(hGidaFsFile)p_fi->fh; + + // Try to truncate file + if((ret=GidaFsLib_TruncateFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + h_file, + offset))!=eGidaFsError_None) + { + LOG_ERROR("Unable to truncate file handle for file '%s': Error %u!", + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_open + */ +int XmountFuse_open(const char *p_path, struct fuse_file_info *p_fi) { + teGidaFsError ret=eGidaFsError_None; + teGidaFsOpenFileFlag flags=eGidaFsOpenFileFlag_None; + hGidaFsFile h_file=NULL; + + if((p_fi->flags&O_TMPFILE)==O_TMPFILE) { + // GidaFS does not support the O_TMPFILE flag + return -EOPNOTSUPP; + } + + // Parse open flags + // TODO: Need further refinements, see man open(2) + if((p_fi->flags&O_RDONLY)==O_RDONLY) flags|=eGidaFsOpenFileFlag_ReadOnly; + if((p_fi->flags&O_WRONLY)==O_WRONLY) flags|=eGidaFsOpenFileFlag_WriteOnly; + if((p_fi->flags&O_RDWR)==O_RDWR) flags|=eGidaFsOpenFileFlag_ReadWrite; + if((p_fi->flags&O_CREAT)==O_CREAT) flags|=eGidaFsOpenFileFlag_Create; + if((p_fi->flags&O_EXCL)==O_EXCL) flags|=eGidaFsOpenFileFlag_CreateAlways; + if((p_fi->flags&O_TRUNC)==O_TRUNC) flags|=eGidaFsOpenFileFlag_CreateAlways; + + // Try to open requested file + if((ret=GidaFsLib_OpenFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + &h_file, + flags, + eGidaFsNodeFlag_None))!=eGidaFsError_None) + { + LOG_ERROR("Unable to open file '%s': Error %u!",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Save file handle and return + p_fi->fh=(uint64_t)h_file; + return 0; +} + +/* + * XmountFuse_read + */ +int XmountFuse_read(const char *p_path, + char *p_buf, + size_t count, + off_t offset, + struct fuse_file_info *p_fi) +{ + teGidaFsError ret=eGidaFsError_None; + hGidaFsFile h_file=(hGidaFsFile)p_fi->fh; + uint64_t read=0; + + // Try to read requested data + if((ret=GidaFsLib_ReadFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + h_file, + offset, + count, + p_buf, + &read))!=eGidaFsError_None) + { + LOG_ERROR("Unable to read %" PRIu64 " bytes at offset %" PRIu64 + " from file '%s': Error %u!", + count, + offset, + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return read; +} + +/* + * XmountFuse_release + */ +int XmountFuse_release(const char *p_path, struct fuse_file_info *p_fi) { + teGidaFsError ret=eGidaFsError_None; + hGidaFsFile h_file=(hGidaFsFile)p_fi->fh; + + // Try to close file + if((ret=GidaFsLib_CloseFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + &h_file))!=eGidaFsError_None) + { + LOG_ERROR("Unable to close file handle for file '%s': Error %u!", + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Clear file handle and return + p_fi->fh=0; + return 0; +} + +/* + * XmountFuse_write + */ +int XmountFuse_write(const char *p_path, + const char *p_buf, + size_t count, + off_t offset, + struct fuse_file_info *p_fi) +{ + teGidaFsError ret=eGidaFsError_None; + hGidaFsFile h_file=(hGidaFsFile)p_fi->fh; + uint64_t written=0; + + // Try to write requested data + if((ret=GidaFsLib_WriteFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + h_file, + offset, + count, + p_buf, + &written))!=eGidaFsError_None) + { + LOG_ERROR("Unable to write %" PRIu64 " bytes to offset %" PRIu64 + " in file '%s': Error %u!", + count, + offset, + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return written; +} + +/******************************************************************************* + * FUSE operations implementation + * Directory functions + ******************************************************************************/ +/* + * XmountFuse_mkdir + */ +int XmountFuse_mkdir(const char *p_path, mode_t mode) { + teGidaFsError ret=eGidaFsError_None; + teGidaFsNodePermissions perms=eGidaFsNodeFlag_None; + + // Parse mode + if((mode&S_IXOTH)==S_IXOTH) perms|=eGidaFsNodeFlag_Xoth; + if((mode&S_IWOTH)==S_IWOTH) perms|=eGidaFsNodeFlag_Woth; + if((mode&S_IROTH)==S_IROTH) perms|=eGidaFsNodeFlag_Roth; + if((mode&S_IRWXO)==S_IRWXO) perms|=eGidaFsNodeFlag_RWXo; + if((mode&S_IXGRP)==S_IXGRP) perms|=eGidaFsNodeFlag_Xgrp; + if((mode&S_IWGRP)==S_IWGRP) perms|=eGidaFsNodeFlag_Wgrp; + if((mode&S_IRGRP)==S_IRGRP) perms|=eGidaFsNodeFlag_Rgrp; + if((mode&S_IRWXG)==S_IRWXG) perms|=eGidaFsNodeFlag_RWXg; + if((mode&S_IXUSR)==S_IXUSR) perms|=eGidaFsNodeFlag_Xusr; + if((mode&S_IWUSR)==S_IWUSR) perms|=eGidaFsNodeFlag_Wusr; + if((mode&S_IRUSR)==S_IRUSR) perms|=eGidaFsNodeFlag_Rusr; + if((mode&S_IRWXU)==S_IRWXU) perms|=eGidaFsNodeFlag_RWXu; + + if((ret=GidaFsLib_CreateDir(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + perms))!=eGidaFsError_None) + { + LOG_ERROR("Unable to create directory '%s': Error %u!",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_readdir + */ +int XmountFuse_readdir(const char *p_path, + void *p_buf, + fuse_fill_dir_t filler, + off_t offset, + struct fuse_file_info *p_fi) +{ + (void)offset; + (void)p_fi; + teGidaFsError ret=eGidaFsError_None; + hGidaFsDir h_dir=NULL; + GidaFsDirEntry entry; + + // Try to open directory + if((ret=GidaFsLib_OpenDir(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + &h_dir))!=eGidaFsError_None) + { + LOG_ERROR("Unable to open directory '%s': Error %u!", + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Fill in "." and ".." entries + filler(p_buf,".",NULL,0); + filler(p_buf,"..",NULL,0); + + // Fill in directory content + while((ret=GidaFsLib_ReadDir(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + h_dir, + &entry))==eGidaFsError_None) + { + filler(p_buf,entry.name,NULL,0); + } + if(ret!=eGidaFsError_NoMoreEntries) { + LOG_ERROR("Unable to read all directory entries of '%s': Error %u!", + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Close directory + if((ret=GidaFsLib_CloseDir(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + &h_dir))!=eGidaFsError_None) + { + LOG_ERROR("Unable to close directory '%s': Error %u!", + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/******************************************************************************* + * FUSE operations implementation + * Misc functions + ******************************************************************************/ +/* + * XmountFuse_chmod + */ +int XmountFuse_chmod(const char *p_path, mode_t mode) { + teGidaFsError ret=eGidaFsError_None; + teGidaFsNodePermissions perms=eGidaFsNodeFlag_None; + +#define XMOUNTFUSE_CHMOD__SET_FLAG(f,ff) if((mode&f)==f) perms|=ff + + XMOUNTFUSE_CHMOD__SET_FLAG(S_IXOTH,eGidaFsNodeFlag_Xoth); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IWOTH,eGidaFsNodeFlag_Woth); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IROTH,eGidaFsNodeFlag_Roth); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IXGRP,eGidaFsNodeFlag_Xgrp); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IWGRP,eGidaFsNodeFlag_Wgrp); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IRGRP,eGidaFsNodeFlag_Rgrp); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IXUSR,eGidaFsNodeFlag_Xusr); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IWUSR,eGidaFsNodeFlag_Wusr); + XMOUNTFUSE_CHMOD__SET_FLAG(S_IRUSR,eGidaFsNodeFlag_Rusr); + XMOUNTFUSE_CHMOD__SET_FLAG(S_ISVTX,eGidaFsNodeFlag_Svtx); + XMOUNTFUSE_CHMOD__SET_FLAG(S_ISGID,eGidaFsNodeFlag_Sgid); + XMOUNTFUSE_CHMOD__SET_FLAG(S_ISUID,eGidaFsNodeFlag_Suid); + +#undef XMOUNTFUSE_CHMOD__SET_FLAG + + if((ret=GidaFsLib_SetAttr(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + perms, + 0, + 0, + 0))!=eGidaFsError_None) + { + LOG_ERROR("Unable to set permissions 0x%08x on node '%s': Error %u!", + mode, + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_chown + */ +int XmountFuse_chown(const char *p_path, uid_t uid, gid_t gid) { + // GidaFS does not implement user and group ids. Simply return no error + // when someone calls this + return 0; +} + +/* + * XmountFuse_getattr + */ +int XmountFuse_getattr(const char *p_path, struct stat *p_stbuf) { + teGidaFsError ret=eGidaFsError_None; + GidaFsNodeInfo node_info; + + // Get requested node infos + if((ret=GidaFsLib_GetAttr(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + &node_info))!=eGidaFsError_None) + { + LOG_ERROR("Unable to stat node '%s': Error %u!",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Clear stat buffer + memset(p_stbuf,0x00,sizeof(struct stat)); + + // Set uid and gid + p_stbuf->st_uid=getuid(); + p_stbuf->st_gid=getgid(); + + // Populate st_mode + switch(node_info.type) { + case eGidaFsNodeType_File: { + p_stbuf->st_mode=S_IFREG; + p_stbuf->st_nlink=node_info.link_count; + break; + } + case eGidaFsNodeType_Dir: { + p_stbuf->st_mode=S_IFDIR; + // As GidaFS does not have '.' entries, need to increment link count here + p_stbuf->st_nlink=node_info.link_count+1; + break; + } + case eGidaFsNodeType_SymLink: { + p_stbuf->st_mode=S_IFLNK; + p_stbuf->st_nlink=node_info.link_count; + break; + } + default: { + LOG_ERROR("GidaFsLib_GetNodeAttr() returned unknown node type for '%s'", + p_path); + return -EFAULT; + } + } + +#define XMOUNTFUSE_GETATTR__SET_FLAG(f,ff) \ + if((node_info.mode&f)==f) p_stbuf->st_mode|=ff + + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Xoth,S_IXOTH); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Woth,S_IWOTH); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Roth,S_IROTH); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Xgrp,S_IXGRP); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Wgrp,S_IWGRP); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Rgrp,S_IRGRP); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Xusr,S_IXUSR); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Wusr,S_IWUSR); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Rusr,S_IRUSR); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Svtx,S_ISVTX); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Sgid,S_ISGID); + XMOUNTFUSE_GETATTR__SET_FLAG(eGidaFsNodeFlag_Suid,S_ISUID); + +#undef XMOUNTFUSE_GETATTR__SET_FLAG + + // Populate rest of stat struct values + p_stbuf->st_size=node_info.logical_size; + p_stbuf->st_blksize=node_info.blocksize; + // st_blocks uses 512B blocks + p_stbuf->st_blocks=node_info.physical_size/512; + // TODO: Our indoes are always 64bit. Might pose probs for ino_t !! + p_stbuf->st_ino=node_info.inode; + // TODO: Our times are always 64bit. Might pose probs on some platforms !! + p_stbuf->st_mtime=node_info.mtime; + p_stbuf->st_atime=node_info.atime; + p_stbuf->st_ctime=node_info.ctime; + + LOG_DEBUG("'%s': Type: 0x%08x, Perm: 0x%08x -> Mode: 0x%08x", + p_path, + node_info.type, + node_info.mode, + p_stbuf->st_mode, + p_stbuf->st_size); + + return 0; +} + +int XmountFuse_link(const char *p_target_path, const char *p_link_path) { + teGidaFsError ret=eGidaFsError_None; + + if((ret=GidaFsLib_Link(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_target_path, + p_link_path))!=eGidaFsError_None) + { + LOG_ERROR("Unable to link '%s' to '%s': Error %u!", + p_target_path, + p_link_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_readlink */ +int XmountFuse_readlink(const char *p_link_path, + char *p_buf, + size_t buf_size) +{ + teGidaFsError ret=eGidaFsError_None; + + if((ret=GidaFsLib_ReadSymLink(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_link_path, + p_buf, + buf_size))!=eGidaFsError_None) + { + LOG_ERROR("Unable to read contents of symlink '%s': Error %u!", + p_link_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + /* -int Xmount_FuseAccess(const char *path, int perm) { - // TODO: Implement propper file permission handling - // http://www.cs.cf.ac.uk/Dave/C/node20.html - // Values for the second argument to access. - // These may be OR'd together. - //#define R_OK 4 // Test for read permission. - //#define W_OK 2 // Test for write permission. - //#define X_OK 1 // Test for execute permission. - //#define F_OK 0 // Test for existence. + * XmountFuse_rename + */ +int XmountFuse_rename(const char *p_old_path, const char *p_new_path) { + teGidaFsError ret=eGidaFsError_None; + + // Rename / move node + if((ret=GidaFsLib_Move(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_old_path, + p_new_path))!=eGidaFsError_None) + { + LOG_ERROR("Unable to move / rename '%s' to '%s': Error %u!", + p_old_path, + p_new_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_rmdir + */ +int XmountFuse_rmdir(const char *p_path) { + return XmountFuse_unlink(p_path); + // TODO: Check error and return correct errno code +} + +/* + * XmountFuse_statfs + */ +/* +int XmountFuse_statfs(const char *p_path, struct statvfs *p_stat) { + uint64_t ufree=0; + struct statvfs ustat; + GidaFsInfo info_struct; + teGidaFsError ret=eGidaFsError_None; + + // Get values from underlying fs + if(statvfs(globs.p_gidafs_file,&ustat)!=0) { + LOG_ERROR("Unable to get stats from underlying fs!"); + return -errno; + } + + // Get GidaFS infos + if((ret=GidaFsLib_GetFsInfo(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + &info_struct))!=eGidaFsError_None) + { + LOG_ERROR("Unable to get GidaFS infos: Error %u",ret) + return XmountCache_GidaFsError2Errno(ret); + } + + // Calculate how many GidaFS blocks are free in underlying fs + ufree=((uint64_t)(((uint64_t)(ustat.f_bfree))*((uint64_t)(ustat.f_frsize)))); + ufree/=info_struct.blocksize; + LOG_ERROR("According to statvfs, %" PRIu64 " blocks of %" PRIu64 + " bytes are free in underlying fs", + ufree, + info_struct.blocksize); + + // Fill statvfs structure + p_stat->f_bsize=info_struct.blocksize; + p_stat->f_frsize=p_stat->f_bsize; + p_stat->f_fsid=0x47494441; + p_stat->f_flag=0; + p_stat->f_namemax=GIDAFS_MAX_NODENAME_LEN; + + // It is not possible to set the following values correctly as they are + // missing used vars! + p_stat->f_blocks=ufree; + p_stat->f_bfree=ufree; + p_stat->f_bavail=p_stat->f_bfree; + p_stat->f_files=ufree; + p_stat->f_ffree=ufree; + p_stat->f_favail=p_stat->f_ffree; + return 0; } */ +/* + * XmountFuse_symlink + */ +int XmountFuse_symlink(const char *p_target_path, const char *p_link_path) { + teGidaFsError ret=eGidaFsError_None; + + if((ret=GidaFsLib_SymLink(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_target_path, + p_link_path))!=eGidaFsError_None) + { + LOG_ERROR("Unable to symlink '%s' to '%s': Error %u!", + p_target_path, + p_link_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_truncate + */ +int XmountFuse_truncate(const char *p_path, off_t new_size) { + teGidaFsError ret=eGidaFsError_None; + hGidaFsFile h_file=NULL; + + // Try to open requested file + if((ret=GidaFsLib_OpenFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + &h_file, + eGidaFsOpenFileFlag_ReadWrite, + eGidaFsNodeFlag_None))!=eGidaFsError_None) + { + LOG_ERROR("Unable to open file '%s': Error %u!",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Try to truncate file to requested size + if((ret=GidaFsLib_TruncateFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + h_file, + new_size))!=eGidaFsError_None) + { + LOG_ERROR("Unable to truncate file '%s': Error %u!",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + // Try to close file again + if((ret=GidaFsLib_CloseFile(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + &h_file))!=eGidaFsError_None) + { + LOG_ERROR("Unable to close file '%s': Error %u!",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_utimens + */ +int XmountFuse_utimens(const char *p_path, const struct timespec tv[2]) { + teGidaFsError ret=eGidaFsError_None; + uint64_t mtime=0; + uint64_t atime=0; + + // Decide what and how to update + if(tv!=NULL) { + if(tv[0].tv_nsec==UTIME_NOW) atime=(uint64_t)time(NULL); + else if(tv[0].tv_nsec!=UTIME_OMIT) atime=(uint64_t)tv[0].tv_sec; + + if(tv[1].tv_nsec==UTIME_NOW) mtime=(uint64_t)time(NULL); + else if(tv[1].tv_nsec!=UTIME_OMIT) mtime=(uint64_t)tv[1].tv_sec; + } else { + mtime=(uint64_t)time(NULL); + atime=mtime; + } + + // Update times + if((ret=GidaFsLib_SetAttr(XmountCache_GetGidaFsHandle(glob_xmount.h_cache), + p_path, + eGidaFsNodeFlag_Invalid, + mtime, + atime, + 0))!=eGidaFsError_None) + { + LOG_ERROR("Unable to set modification / last accessed times on node '%s': " + "Error %u!", + p_path, + ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + +/* + * XmountFuse_unlink + */ +int XmountFuse_unlink(const char *p_path) { + teGidaFsError ret=eGidaFsError_None; + + if((ret=GidaFsLib_Unlink(XmountCache_GetGidaFsHandle(glob_xmount.h_cache),p_path))!=eGidaFsError_None) { + LOG_ERROR("Unable to delete node '%s': Error %u",p_path,ret); + return XmountCache_GidaFsError2Errno(ret); + } + + return 0; +} + + + + + + + //! FUSE getattr implementation /*! * \param p_path Path of file to get attributes from * \param p_stat Pointer to stat structure to save attributes to * \return 0 on success, negated error code on error */ +/* int Xmount_FuseGetAttr(const char *p_path, struct stat *p_stat) { te_XmountError xmount_ret=e_XmountError_None; memset(p_stat,0,sizeof(struct stat)); if((xmount_ret=Xmount_GetFileAttr(p_path,p_stat))!=e_XmountError_None) { LOG_ERROR("Couldn't get file attributes: Error code %u!\n",xmount_ret); return -ENOENT; } +*/ /* if(strcmp(p_path,"/")==0) { // Attributes of mountpoint p_stat->st_mode=S_IFDIR | 0777; p_stat->st_nlink=2; } else if(strcmp(p_path,glob_xmount.output.p_virtual_image_path)==0) { // Attributes of virtual image if(!glob_xmount.output.writable) p_stat->st_mode=S_IFREG | 0444; else p_stat->st_mode=S_IFREG | 0666; p_stat->st_nlink=1; // Get output image file size if(!GetOutputImageSize((uint64_t*)&(p_stat->st_size))) { LOG_ERROR("Couldn't get image size!\n"); return -ENOENT; } // Make sure virtual image seems to be fully allocated (not sparse file). p_stat->st_blocks=p_stat->st_size/512; if(p_stat->st_size%512!=0) p_stat->st_blocks++; } else if(strcmp(p_path,glob_xmount.output.p_info_path)==0) { // Attributes of virtual image info file p_stat->st_mode=S_IFREG | 0444; p_stat->st_nlink=1; // Get virtual image info file size if(glob_xmount.output.p_info_file!=NULL) { p_stat->st_size=strlen(glob_xmount.output.p_info_file); } else p_stat->st_size=0; } else return -ENOENT; // Set uid and gid of all files to uid and gid of current process p_stat->st_uid=getuid(); p_stat->st_gid=getgid(); */ +/* return 0; } +*/ //! FUSE mkdir implementation /*! * \param p_path Directory path * \param mode Directory permissions * \return 0 on success, negated error code on error */ +/* int Xmount_FuseMkDir(const char *p_path, mode_t mode) { // TODO: Implement LOG_ERROR("Attempt to create directory \"%s\" " "on read-only filesystem!\n",p_path) return -1; } +*/ //! FUSE create implementation. /*! * \param p_path File to create * \param mode File mode * \param dev ??? but not used * \return 0 on success, negated error code on error */ +/* int Xmount_FuseMkNod(const char *p_path, mode_t mode, dev_t dev) { // TODO: Implement LOG_ERROR("Attempt to create illegal file \"%s\"\n",p_path) return -1; } +*/ //! FUSE readdir implementation /*! * \param p_path Path from where files should be listed * \param p_buf Buffer to write file entrys to * \param filler Function to write dir entrys to buffer * \param offset ??? but not used * \param p_fi File info struct * \return 0 on success, negated error code on error */ +/* int Xmount_FuseReadDir(const char *p_path, void *p_buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *p_fi) { uint64_t dir_entries=0; char **pp_dir_entries=NULL; te_XmountError xmount_ret=e_XmountError_None; // Ignore some params (void)offset; (void)p_fi; // Get directory listing xmount_ret=Xmount_GetDirListing(p_path, &dir_entries, &pp_dir_entries); if(xmount_ret!=e_XmountError_None) { LOG_ERROR("Couldn't get directory listing: Error code %u!\n",xmount_ret); return -ENOENT; } // Add std . and .. entrys filler(p_buf,".",NULL,0); filler(p_buf,"..",NULL,0); // Add retrieved entries for(uint64_t i=0;iflags & 3)!=O_RDONLY) { \ LOG_DEBUG("Attempt to open the read-only file \"%s\" for writing.\n", \ p_path) \ return -EACCES; \ } \ return 0; \ } if(strcmp(p_path,glob_xmount.output.p_virtual_image_path)==0 || strcmp(p_path,glob_xmount.output.p_info_path)==0) { CHECK_OPEN_PERMS(); } #undef CHECK_OPEN_PERMS LOG_DEBUG("Attempt to open inexistant file \"%s\".\n",p_path); return -ENOENT; } +*/ //! FUSE read implementation /*! * \param p_path Path (relative to mount folder) of file to read data from * \param p_buf Pre-allocated buffer where read data should be written to * \param size Number of bytes to read * \param offset Offset to start reading at * \param p_fi: File info struct * \return Read bytes on success, negated error code on error */ +/* int Xmount_FuseRead(const char *p_path, char *p_buf, size_t size, off_t offset, struct fuse_file_info *p_fi) { (void)p_fi; int ret; uint64_t len; #define READ_MEM_FILE(filebuf,filesize,filetypestr,mutex) { \ len=filesize; \ if(offsetlen) { \ LOG_DEBUG("Attempt to read past EOF of virtual " filetypestr " file\n"); \ LOG_DEBUG("Adjusting read size from %u to %u\n",size,len-offset); \ size=len-offset; \ } \ pthread_mutex_lock(&mutex); \ memcpy(p_buf,filebuf+offset,size); \ pthread_mutex_unlock(&mutex); \ LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 \ " from virtual " filetypestr " file\n",size,offset); \ ret=size; \ } else { \ LOG_DEBUG("Attempt to read behind EOF of virtual " filetypestr " file\n"); \ ret=0; \ } \ } if(strcmp(p_path,glob_xmount.output.p_virtual_image_path)==0) { // Read data from virtual output file // Wait for other threads to end reading/writing data pthread_mutex_lock(&(glob_xmount.mutex_image_rw)); // Get requested data if((ret=ReadOutputImageData(p_buf,offset,size))<0) { LOG_ERROR("Couldn't read data from virtual image file!\n") } // Allow other threads to read/write data again pthread_mutex_unlock(&(glob_xmount.mutex_image_rw)); } else if(strcmp(p_path,glob_xmount.output.p_info_path)==0) { // Read data from virtual info file READ_MEM_FILE(glob_xmount.output.p_info_file, strlen(glob_xmount.output.p_info_file), "info", glob_xmount.mutex_info_read); } else { // Attempt to read non existant file LOG_DEBUG("Attempt to read from non existant file \"%s\"\n",p_path) ret=-ENOENT; } #undef READ_MEM_FILE // TODO: Return size of read data!!!!! return ret; } +*/ //! FUSE rename implementation /*! * \param p_path File to rename * \param p_npath New filename * \return 0 on error, negated error code on error */ +/* int Xmount_FuseRename(const char *p_path, const char *p_npath) { // TODO: Implement return -ENOENT; } +*/ //! FUSE rmdir implementation /*! * \param p_path Directory to delete * \return 0 on success, negated error code on error */ +/* int Xmount_FuseRmDir(const char *p_path) { // TODO: Implement return -1; } +*/ //! FUSE unlink implementation /*! * \param p_path File to delete * \return 0 on success, negated error code on error */ +/* int Xmount_FuseUnlink(const char *p_path) { // TODO: Implement return -1; } +*/ //! FUSE statfs implementation /*! * \param p_path Get stats for fs that the specified file resides in * \param stats Stats * \return 0 on success, negated error code on error */ /* int Xmount_FuseStatFs(const char *p_path, struct statvfs *stats) { struct statvfs CacheFileFsStats; int ret; if(glob_xmount.writable==TRUE) { // If write support is enabled, return stats of fs upon which cache file // resides in if((ret=statvfs(glob_xmount.p_cache_file,&CacheFileFsStats))==0) { memcpy(stats,&CacheFileFsStats,sizeof(struct statvfs)); return 0; } else { LOG_ERROR("Couldn't get stats for fs upon which resides \"%s\"\n", glob_xmount.p_cache_file) return ret; } } else { // TODO: Return read only return 0; } } */ // FUSE write implementation /*! * \param p_buf Buffer containing data to write * \param size Number of bytes to write * \param offset Offset to start writing at * \param p_fi: File info struct * * Returns: * Written bytes on success, negated error code on error */ +/* int Xmount_FuseWrite(const char *p_path, const char *p_buf, size_t size, off_t offset, struct fuse_file_info *p_fi) { (void)p_fi; uint64_t len; if(strcmp(p_path,glob_xmount.output.p_virtual_image_path)==0) { // Wait for other threads to end reading/writing data pthread_mutex_lock(&(glob_xmount.mutex_image_rw)); // Get output image file size if(!GetOutputImageSize(&len)) { LOG_ERROR("Couldn't get virtual image size!\n") pthread_mutex_unlock(&(glob_xmount.mutex_image_rw)); return 0; } if(offsetlen) size=len-offset; if(WriteOutputImageData(p_buf,offset,size)!=size) { LOG_ERROR("Couldn't write data to virtual image file!\n") pthread_mutex_unlock(&(glob_xmount.mutex_image_rw)); return 0; } } else { LOG_DEBUG("Attempt to write past EOF of virtual image file\n") pthread_mutex_unlock(&(glob_xmount.mutex_image_rw)); return 0; } // Allow other threads to read/write data again pthread_mutex_unlock(&(glob_xmount.mutex_image_rw)); } else if(strcmp(p_path,glob_xmount.output.p_info_path)==0) { // Attempt to write data to read only image info file LOG_DEBUG("Attempt to write data to virtual info file\n"); return -ENOENT; } else { // Attempt to write to non existant file LOG_DEBUG("Attempt to write to the non existant file \"%s\"\n",p_path) return -ENOENT; } return size; } +*/ diff --git a/src/xmount_fuse.h b/src/xmount_fuse.h index 45a22c4..d3c937e 100644 --- a/src/xmount_fuse.h +++ b/src/xmount_fuse.h @@ -1,59 +1,122 @@ /******************************************************************************* * 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_FUSE_H #define XMOUNT_FUSE_H #define FUSE_USE_VERSION 26 #include + +int XmountFuse_create(const char *p_path, + mode_t mode, + struct fuse_file_info *p_fi); + +int XmountFuse_ftruncate(const char *p_path, + off_t offset, + struct fuse_file_info *p_fi); + +int XmountFuse_open(const char *p_path, struct fuse_file_info *p_fi); + +int XmountFuse_read(const char *p_path, + char *p_buf, + size_t count, + off_t offset, + struct fuse_file_info *p_fi); + +int XmountFuse_release(const char *p_path, struct fuse_file_info *p_fi); + +int XmountFuse_write(const char *p_path, + const char *p_buf, + size_t count, + off_t offset, + struct fuse_file_info *p_fi); + +int XmountFuse_mkdir(const char *p_path, mode_t mode); + +int XmountFuse_readdir(const char *p_path, + void *p_buf, + fuse_fill_dir_t filler, + off_t offset, + struct fuse_file_info *p_fi); + +int XmountFuse_chmod(const char *p_path, mode_t mode); + +int XmountFuse_chown(const char *p_path, uid_t uid, gid_t gid); + +int XmountFuse_getattr(const char *p_path, struct stat *p_stbuf); + +int XmountFuse_link(const char *p_target_path, const char *p_link_path); + +int XmountFuse_readlink(const char *p_link_path, + char *p_buf, + size_t buf_size); + +int XmountFuse_rename(const char *p_old_path, const char *p_new_path); + +int XmountFuse_rmdir(const char *p_path); + +//int XmountFuse_statfs(const char *p_path, struct statvfs *p_stat); + +int XmountFuse_symlink(const char *p_target_path, const char *p_link_path); + +int XmountFuse_truncate(const char *p_path, off_t new_size); + +int XmountFuse_utimens(const char *p_path, const struct timespec tv[2]); + +int XmountFuse_unlink(const char *p_path); + /* int Xmount_FuseAccess(const char*, int); */ +/* int Xmount_FuseGetAttr(const char*, struct stat*); int Xmount_FuseMkDir(const char*, mode_t); int Xmount_FuseMkNod(const char*, mode_t, dev_t); int Xmount_FuseReadDir(const char*, void*, fuse_fill_dir_t, off_t, struct fuse_file_info*); int Xmount_FuseOpen(const char*, struct fuse_file_info*); int Xmount_FuseRead(const char*, char*, size_t, off_t, struct fuse_file_info*); int Xmount_FuseRename(const char*, const char*); int Xmount_FuseRmDir(const char*); int Xmount_FuseUnlink(const char*); +*/ /* int XmountFuse_StatFs(const char*, struct statvfs*); */ +/* int Xmount_FuseWrite(const char *p_path, const char*, size_t, off_t, struct fuse_file_info*); +*/ #endif // XMOUNT_FUSE_H diff --git a/src/xmount_input.c b/src/xmount_input.c index 994157f..a99a64d 100644 --- a/src/xmount_input.c +++ b/src/xmount_input.c @@ -1,922 +1,924 @@ /******************************************************************************* * 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 "xmount_input.h" +#include "../libxmount/libxmount.h" +#include "../libxmount_input/libxmount_input.h" +#include "macros.h" + #include // For calloc #include // For memcpy #include // For dlopen, dlclose, dlsym -#include "xmount_input.h" -#include "xmount.h" -#include "macros.h" -#include "../libxmount_input/libxmount_input.h" - /******************************************************************************* * Private definitions / macros ******************************************************************************/ -#define LOG_WARNING(...) { \ +#define LOG_WARNING(...) do { \ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \ -} -#define LOG_ERROR(...) { \ +} while(0) + +#define LOG_ERROR(...) do { \ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \ -} -#define LOG_DEBUG(...) { \ - LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \ -} +} while(0) + +#define LOG_DEBUG(...) do { \ + LIBXMOUNT_LOG_DEBUG(p_h->debug,__VA_ARGS__); \ +} while(0) /******************************************************************************* * Private types / structures / enums ******************************************************************************/ //! Structure containing infos about input libs typedef struct s_XmountInputLib { //! Filename of lib (without path) char *p_name; //! Handle to the loaded lib void *p_lib; //! Array of supported input types char *p_supported_input_types; //! Struct containing lib functions ts_LibXmountInputFunctions lib_functions; } ts_XmountInputLib, *pts_XmountInputLib; //! Structure containing infos about input images typedef struct s_XmountInputImage { //! Image type char *p_type; //! Image source file count uint64_t files_count; //! Image source files char **pp_files; //! Input lib functions for this image pts_LibXmountInputFunctions p_functions; //! Image handle void *p_handle; //! Image size uint64_t size; } ts_XmountInputImage, *pts_XmountInputImage; typedef struct s_XmountInputHandle { //! Loaded input lib count uint32_t libs_count; //! Array containing infos about loaded input libs pts_XmountInputLib *pp_libs; //! Amount of input lib params (--inopts) uint32_t lib_params_count; //! Input lib params (--inopts) pts_LibXmountOptions *pp_lib_params; //! Input image count uint64_t images_count; //! Input images pts_XmountInputImage *pp_images; //! Input image offset (--offset) uint64_t image_offset; //! Input image size limit (--sizelimit) uint64_t image_size_limit; //! Enable debugging uint8_t debug; } ts_XmountInputHandle; /******************************************************************************* * Private functions declarations ******************************************************************************/ /*! * \brief Find an input lib for a given input image * * Searches trough the list of loaded input libraries to find one that supports * the given input image's format. On success, that library is associated with * the given image. * * \param p_h Input handle * \param p_input_image Input image to search input lib for * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_FindLib(pts_XmountInputHandle p_h, pts_XmountInputImage p_input_image); /******************************************************************************* * Public functions implementations ******************************************************************************/ /* * XmountInput_CreateHandle */ te_XmountInput_Error XmountInput_CreateHandle(pts_XmountInputHandle *pp_h) { pts_XmountInputHandle p_h=NULL; // Params check if(pp_h==NULL) return e_XmountInput_Error_InvalidHandlePointer; // Alloc new handle p_h=(pts_XmountInputHandle)calloc(1,sizeof(ts_XmountInputHandle)); if(p_h==NULL) { return e_XmountInput_Error_Alloc; } // Init values p_h->pp_libs=NULL; p_h->pp_lib_params=NULL; p_h->pp_images=NULL; *pp_h=p_h; return e_XmountInput_Error_None; } /* * XmountInput_DestroyHandle */ te_XmountInput_Error XmountInput_DestroyHandle(pts_XmountInputHandle *pp_h) { pts_XmountInputHandle p_h=NULL; // Params check if(pp_h==NULL) return e_XmountInput_Error_InvalidHandlePointer; if(*pp_h==NULL) return e_XmountInput_Error_InvalidHandle; p_h=*pp_h; // Free resources if(p_h->images_count!=0 && p_h->pp_images!=NULL) { // TODO: Close images } if(p_h->libs_count>0 && p_h->pp_libs!=NULL) { // Unload all input libs for(uint32_t i=0;ilibs_count;i++) { if(p_h->pp_libs[i]->p_supported_input_types!=NULL) { XMOUNT_FREE(p_h->pp_libs[i]->p_supported_input_types); } if(p_h->pp_libs[i]->p_lib!=NULL) { dlclose(p_h->pp_libs[i]->p_lib); p_h->pp_libs[i]->p_lib=NULL; } 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); p_h->libs_count=0; } if(p_h->lib_params_count!=0 && p_h->pp_lib_params!=NULL) { // Free library parameter array for(uint32_t i=0;ilib_params_count;i++) { XMOUNT_FREE(p_h->pp_lib_params[i]); } XMOUNT_FREE(p_h->pp_lib_params); p_h->lib_params_count=0; } *pp_h=NULL; return e_XmountInput_Error_None; } /* * XmountInput_EnableDebugging */ te_XmountInput_Error XmountInput_EnableDebugging(pts_XmountInputHandle p_h) { // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; p_h->debug=1; return e_XmountInput_Error_None; } /* * XmountInput_AddLibrary */ te_XmountInput_Error XmountInput_AddLibrary(pts_XmountInputHandle p_h, const char *p_lib_name) { uint32_t supported_formats_len=0; t_LibXmount_Input_GetApiVersion pfun_input_GetApiVersion; t_LibXmount_Input_GetSupportedFormats pfun_input_GetSupportedFormats; t_LibXmount_Input_GetFunctions pfun_input_GetFunctions; void *p_libxmount=NULL; pts_XmountInputLib p_input_lib=NULL; char *p_buf=NULL; char *p_library_path=NULL; char *p_supported_formats=NULL; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(p_lib_name==NULL) return e_XmountInput_Error_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 XMOUNTINPUT_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_XmountInput_Error_FailedLoadingSymbol; \ } \ } // Try to load given library p_libxmount=dlopen(p_library_path,RTLD_NOW); if(p_libxmount==NULL) { LOG_ERROR("Unable to load input library '%s': %s!\n", p_library_path, dlerror()); return e_XmountInput_Error_FailedLoadingLibrary; } // Load library symbols XMOUNTINPUT_LOADLIBS__LOAD_SYMBOL("LibXmount_Input_GetApiVersion", pfun_input_GetApiVersion); // Check library's API version if(pfun_input_GetApiVersion()!=LIBXMOUNT_INPUT_API_VERSION) { LOG_DEBUG("Failed! Wrong API version.\n"); LOG_ERROR("Unable to load input library '%s'. Wrong API version\n", p_library_path); dlclose(p_libxmount); return e_XmountInput_Error_WrongLibraryApiVersion; } XMOUNTINPUT_LOADLIBS__LOAD_SYMBOL("LibXmount_Input_GetSupportedFormats", pfun_input_GetSupportedFormats); XMOUNTINPUT_LOADLIBS__LOAD_SYMBOL("LibXmount_Input_GetFunctions", pfun_input_GetFunctions); // Construct new entry for our library list XMOUNT_MALLOC(p_input_lib,pts_XmountInputLib,sizeof(ts_XmountInputLib)); // Initialize lib_functions structure to NULL memset(&(p_input_lib->lib_functions), 0, sizeof(ts_LibXmountInputFunctions)); // Set name and handle XMOUNT_STRSET(p_input_lib->p_name,p_lib_name); p_input_lib->p_lib=p_libxmount; // Get and set supported formats p_supported_formats=pfun_input_GetSupportedFormats(); 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_input_lib->p_supported_input_types, char*, supported_formats_len); memcpy(p_input_lib->p_supported_input_types, p_supported_formats, supported_formats_len); // Get, set and check lib_functions pfun_input_GetFunctions(&(p_input_lib->lib_functions)); if(p_input_lib->lib_functions.CreateHandle==NULL || p_input_lib->lib_functions.DestroyHandle==NULL || p_input_lib->lib_functions.Open==NULL || p_input_lib->lib_functions.Close==NULL || p_input_lib->lib_functions.Size==NULL || p_input_lib->lib_functions.Read==NULL || p_input_lib->lib_functions.OptionsHelp==NULL || p_input_lib->lib_functions.OptionsParse==NULL || p_input_lib->lib_functions.GetInfofileContent==NULL || p_input_lib->lib_functions.GetErrorMessage==NULL || p_input_lib->lib_functions.FreeBuffer==NULL) { LOG_DEBUG("Missing implemention of one or more functions in lib %s!\n", p_lib_name); XMOUNT_FREE(p_input_lib->p_supported_input_types); XMOUNT_FREE(p_input_lib->p_name); XMOUNT_FREE(p_input_lib); dlclose(p_libxmount); return e_XmountInput_Error_MissingLibraryFunction; } // Add entry to the input library list XMOUNT_REALLOC(p_h->pp_libs, pts_XmountInputLib*, sizeof(pts_XmountInputLib)*(p_h->libs_count+1)); p_h->pp_libs[p_h->libs_count++]=p_input_lib; LOG_DEBUG("Input library '%s' loaded successfully\n",p_lib_name); #undef XMOUNTINPUT_LOADLIBS__LOAD_SYMBOL return e_XmountInput_Error_None; } te_XmountInput_Error XmountInput_GetLibraryCount(pts_XmountInputHandle p_h, uint32_t *p_count) { // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(p_count==NULL) return e_XmountInput_Error_InvalidBuffer; *p_count=p_h->libs_count; return e_XmountInput_Error_None; } /* * XmountInput_GetSupportedFormats */ te_XmountInput_Error XmountInput_GetSupportedFormats(pts_XmountInputHandle p_h, char **pp_formats) { char *p_buf=NULL; char *p_formats=NULL; uint32_t cur_len=0; uint32_t vector_len=0; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(pp_formats==NULL) return e_XmountInput_Error_InvalidBuffer; // Loop over all loaded libs, extract supported formats 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_input_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_input_types); if(cur_len==0) continue; p_formats=(char*)realloc(p_formats,vector_len+cur_len); if(p_formats==NULL) return e_XmountInput_Error_Alloc; memcpy(p_formats+vector_len, p_h->pp_libs[i]->p_supported_input_types, cur_len); vector_len+=cur_len; } // Null-terminate vector p_formats=(char*)realloc(p_formats,vector_len+1); if(p_formats==NULL) return e_XmountInput_Error_Alloc; p_formats[vector_len]='\0'; *pp_formats=p_formats; return e_XmountInput_Error_None; } /* * XmountInput_SetOptions */ te_XmountInput_Error XmountInput_SetOptions(pts_XmountInputHandle p_h, char *p_options) { // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(p_options==NULL) return e_XmountInput_Error_InvalidString; // Make sure library parameters haven't been set previously if(p_h->pp_lib_params!=NULL) { LOG_ERROR("Input library options already set!\n"); return e_XmountInput_Error_LibOptionsAlreadySet; } // Save options if(XmountLib_SplitLibParams(p_options, &(p_h->lib_params_count), &(p_h->pp_lib_params))!=0) { LOG_ERROR("Unable to parse input library options '%s'!\n",p_options); return e_XmountInput_Error_FailedParsingOptions; } return e_XmountInput_Error_None; } /* * XmountInput_GetOptionsHelpText */ te_XmountInput_Error XmountInput_GetOptionsHelpText(pts_XmountInputHandle p_h, char **pp_help_text) { const char *p_buf=NULL; char *p_help=NULL; int ret=0; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(pp_help_text==NULL) return e_XmountInput_Error_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"); ret=p_h->pp_libs[i]->lib_functions.FreeBuffer(p_buf); if(ret!=0) { LOG_ERROR("Unable to free options help text from library '%s': %s!\n", p_h->pp_libs[i]->p_name, p_h->pp_libs[i]->lib_functions.GetErrorMessage(ret)); } } *pp_help_text=p_help; return e_XmountInput_Error_None; } /* * XmountInput_GetLibsInfoText */ te_XmountInput_Error XmountInput_GetLibsInfoText(pts_XmountInputHandle 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_XmountInput_Error_InvalidHandle; if(pp_info_text==NULL) return e_XmountInput_Error_InvalidBuffer; // Loop over all loaded libs, extract name and supported formats 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_input_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_XmountInput_Error_None; } /* * XmountInput_AddImage */ te_XmountInput_Error XmountInput_AddImage(pts_XmountInputHandle p_h, const char *p_format, uint64_t files_count, const char **pp_files) { pts_XmountInputImage p_image=NULL; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(p_format==NULL) return e_XmountInput_Error_InvalidString; if(pp_files==NULL) return e_XmountInput_Error_InvalidArray; // Alloc and fill new image structure XMOUNT_CALLOC(p_image,pts_XmountInputImage,sizeof(ts_XmountInputImage)); XMOUNT_STRSET(p_image->p_type,p_format); p_image->files_count=files_count; XMOUNT_CALLOC(p_image->pp_files,char**,p_image->files_count*sizeof(char*)); for(uint64_t i=0;ifiles_count;i++) { XMOUNT_STRSET(p_image->pp_files[i],pp_files[i]); } p_image->p_functions=NULL; p_image->p_handle=NULL; // TODO: Find lib and open input file // Add image to our image array XMOUNT_REALLOC(p_h->pp_images,pts_XmountInputImage*,p_h->images_count+1); p_h->pp_images[p_h->images_count++]=p_image; return e_XmountInput_Error_None; } /*! * \brief Get input image count * * Get input image count. * * \param p_h Input handle * \param p_count Input image count is returned in this variable * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_GetImageCount(pts_XmountInputHandle p_h, uint64_t *p_count) { // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(p_count==NULL) return e_XmountInput_Error_InvalidBuffer; *p_count=p_h->images_count; return e_XmountInput_Error_None; } /* * XmountInput_SetInputOffset */ te_XmountInput_Error XmountInput_SetInputOffset(pts_XmountInputHandle p_h, uint64_t offset) { // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; LOG_DEBUG("Setting input image offset to \"%" PRIu64 "\"\n",offset); p_h->image_offset=offset; return e_XmountInput_Error_None; } /* * XmountInput_SetInputSizeLimit */ te_XmountInput_Error XmountInput_SetInputSizeLimit(pts_XmountInputHandle p_h, uint64_t size_limit) { // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; LOG_DEBUG("Setting input image size limit to \"%" PRIu64 "\"\n",size_limit); p_h->image_size_limit=size_limit; return e_XmountInput_Error_None; } /* * XmountInput_Open */ te_XmountInput_Error XmountInput_Open(pts_XmountInputHandle p_h) { int ret=0; const char *p_err_msg; te_XmountInput_Error input_ret=e_XmountInput_Error_None; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; for(uint64_t i=0;iimages_count;i++) { - if(p_h->debug==TRUE) { + if(p_h->debug==1) { if(p_h->pp_images[i]->files_count==1) { LOG_DEBUG("Loading image file \"%s\"...\n", p_h->pp_images[i]->pp_files[0]); } else { LOG_DEBUG("Loading image files \"%s .. %s\"...\n", p_h->pp_images[i]->pp_files[0], p_h->pp_images[i]-> pp_files[p_h->pp_images[i]->files_count-1]); } } // Find input lib input_ret=XmountInput_FindLib(p_h,p_h->pp_images[i]); if(input_ret!=e_XmountInput_Error_None) { LOG_ERROR("Unable to find input library for input image format '%s' " "of input image '%s': Error code %u!\n", p_h->pp_images[i]->p_type, p_h->pp_images[i]->pp_files[0], input_ret); return input_ret; } // Init input image handle ret=p_h->pp_images[i]->p_functions-> CreateHandle(&(p_h->pp_images[i]->p_handle), p_h->pp_images[i]->p_type, p_h->debug); if(ret!=0) { LOG_ERROR("Unable to init input handle for input image '%s': %s!\n", p_h->pp_images[i]->pp_files[0], p_h->pp_images[i]->p_functions-> GetErrorMessage(ret)); return e_XmountInput_Error_FailedCreatingImageHandle; } // Parse input lib specific options if(p_h->pp_lib_params!=NULL) { ret=p_h->pp_images[i]->p_functions-> OptionsParse(p_h->pp_images[i]->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 input library specific options for image " "'%s': %s: %s!\n", p_h->pp_images[i]->pp_files[0], p_h->pp_images[i]->p_functions-> GetErrorMessage(ret), p_err_msg); p_h->pp_images[i]->p_functions->FreeBuffer(p_err_msg); } else { LOG_ERROR("Unable to parse input library specific options for image " "'%s': %s!\n", p_h->pp_images[i]->pp_files[0], p_h->pp_images[i]->p_functions-> GetErrorMessage(ret)); } return e_XmountInput_Error_FailedParsingLibParams; } } // Open input image ret=p_h->pp_images[i]->p_functions->Open(p_h->pp_images[i]->p_handle, (const char**)(p_h->pp_images[i]-> pp_files), p_h->pp_images[i]->files_count); if(ret!=0) { LOG_ERROR("Unable to open input image file '%s': %s!\n", p_h->pp_images[i]->pp_files[0], p_h->pp_images[i]->p_functions-> GetErrorMessage(ret)); return e_XmountInput_Error_FailedOpeningImage; } // Determine input image size ret=p_h->pp_images[i]->p_functions->Size(p_h->pp_images[i]->p_handle, &(p_h->pp_images[i]->size)); if(ret!=0) { LOG_ERROR("Unable to determine size of input image '%s': %s!\n", p_h->pp_images[i]->pp_files[0], p_h->pp_images[i]-> p_functions->GetErrorMessage(ret)); return e_XmountInput_Error_FailedGettingImageSize; } // If an offset was specified, check it against offset and change size if(p_h->image_offset!=0) { if(p_h->image_offset>p_h->pp_images[i]->size) { LOG_ERROR("The specified offset is larger than the size of the input " "image '%s'! (%" PRIu64 " > %" PRIu64 ")\n", p_h->pp_images[i]->pp_files[0], p_h->image_offset, p_h->pp_images[i]->size); return e_XmountInput_Error_OffsetExceedsImageSize; } p_h->pp_images[i]->size-=p_h->image_offset; } // If a size limit was specified, check it and change size if(p_h->image_size_limit!=0) { if(p_h->pp_images[i]->sizeimage_size_limit) { LOG_ERROR("The specified size limit is larger than the size of the " "input image '%s'! (%" PRIu64 " > %" PRIu64 ")\n", p_h->pp_images[i]->pp_files[0], p_h->image_size_limit, p_h->pp_images[i]->size); return e_XmountInput_Error_SizelimitExceedsImageSize; } p_h->pp_images[i]->size=p_h->image_size_limit; } - LOG_DEBUG("Input image loaded successfully\n") + LOG_DEBUG("Input image loaded successfully\n"); } return e_XmountInput_Error_None; } /* * XmountInput_Close */ te_XmountInput_Error XmountInput_Close(pts_XmountInputHandle p_h) { int ret=0; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(p_h->pp_images!=NULL) { // Close all input images for(uint64_t i=0;iimages_count;i++) { if(p_h->pp_images[i]==NULL) continue; if(p_h->pp_images[i]->p_functions!=NULL) { if(p_h->pp_images[i]->p_handle!=NULL) { ret=p_h->pp_images[i]->p_functions-> Close(p_h->pp_images[i]->p_handle); if(ret!=0) { LOG_ERROR("Unable to close input image '%s': %s\n", p_h->pp_images[i]->pp_files[0]!=NULL ? p_h->pp_images[i]->pp_files[0] : "n/a", p_h->pp_images[i]->p_functions->GetErrorMessage(ret)); } ret=p_h->pp_images[i]->p_functions-> DestroyHandle(&(p_h->pp_images[i]->p_handle)); if(ret!=0) { LOG_ERROR("Unable to destroy handle of input image '%s': %s\n", p_h->pp_images[i]->pp_files[0]!=NULL ? p_h->pp_images[i]->pp_files[0] : "n/a", p_h->pp_images[i]->p_functions->GetErrorMessage(ret)); } p_h->pp_images[i]->p_handle=NULL; } } if(p_h->pp_images[i]->pp_files!=NULL) { for(uint64_t ii=0;iipp_images[i]->files_count;ii++) { if(p_h->pp_images[i]->pp_files[ii]!=NULL) XMOUNT_FREE(p_h->pp_images[i]->pp_files[ii]); } XMOUNT_FREE(p_h->pp_images[i]->pp_files); } if(p_h->pp_images[i]->p_type!=NULL) { XMOUNT_FREE(p_h->pp_images[i]->p_type); } XMOUNT_FREE(p_h->pp_images[i]); } XMOUNT_FREE(p_h->pp_images); } return e_XmountInput_Error_None; } /* * XmountInput_GetSize */ te_XmountInput_Error XmountInput_GetSize(pts_XmountInputHandle p_h, uint64_t image_nr, uint64_t *p_size) { // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(image_nr>=p_h->images_count) return e_XmountInput_Error_NoSuchImage; if(p_size==NULL) return e_XmountInput_Error_InvalidBuffer; *p_size=p_h->pp_images[image_nr]->size; return e_XmountInput_Error_None; } /* * XmountInput_ReadData */ te_XmountInput_Error XmountInput_ReadData(pts_XmountInputHandle p_h, uint64_t image_nr, char *p_buf, uint64_t offset, uint64_t count, uint64_t *p_read) { uint64_t to_read=0; int ret=0; int read_errno=0; pts_XmountInputImage p_image=NULL; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(image_nr>=p_h->images_count) return e_XmountInput_Error_NoSuchImage; if(p_buf==NULL) return e_XmountInput_Error_InvalidBuffer; p_image=p_h->pp_images[image_nr]; LOG_DEBUG("Reading %zu bytes at offset %zu from input image '%s'\n", count, offset, p_image->pp_files[0]); // Make sure we aren't reading past EOF of image file if(offset>=p_image->size) { // Offset is beyond image size LOG_DEBUG("Offset %zu is at / beyond size of input image '%s'\n", offset, p_image->pp_files[0]); *p_read=0; return 0; } if(offset+count>p_image->size) { // Attempt to read data past EOF of image file to_read=p_image->size-offset; LOG_DEBUG("Attempt to read data past EOF of input image '%s'. " "Correcting size from %zu to %zu\n", p_image->pp_files[0], count, to_read); } else to_read=count; // Read data from image file (adding input image offset if one was specified) ret=p_image->p_functions->Read(p_image->p_handle, p_buf, offset+p_h->image_offset, to_read, p_read, &read_errno); if(ret!=0) { LOG_ERROR("Couldn't read %zu bytes at offset %zu from input image " "'%s': %s: Error code %u!\n", to_read, offset, p_image->pp_files[0], p_image->p_functions->GetErrorMessage(ret), read_errno); return e_XmountInput_Error_FailedReadingData; } return e_XmountInput_Error_None; } /* * XmountInput_WriteData */ te_XmountInput_Error XmountInput_WriteData(pts_XmountInputHandle p_h, uint64_t image_nr, const char *p_buf, uint64_t offset, uint64_t count) { // TODO: Implement return e_XmountInput_Error_None; } /* * XmountInput_GetInfoFileContent */ te_XmountInput_Error XmountInput_GetInfoFileContent(pts_XmountInputHandle p_h, char **pp_content) { int ret=0; char *p_buf=NULL; char *p_content=NULL; // Params check if(p_h==NULL) return e_XmountInput_Error_InvalidHandle; if(pp_content==NULL) return e_XmountInput_Error_InvalidBuffer; for(uint64_t i=0;iimages_count;i++) { ret=p_h->pp_images[i]->p_functions-> GetInfofileContent(p_h->pp_images[i]->p_handle,(const char**)&p_buf); if(ret!=0) { LOG_ERROR("Unable to get info file content for image '%s': %s!\n", p_h->pp_images[i]->pp_files[0], p_h->pp_images[i]->p_functions->GetErrorMessage(ret)); return e_XmountInput_Error_FailedGettingInfoFileContent; } // Add infos to main buffer and free p_buf XMOUNT_STRAPP(p_content,"\n--> "); XMOUNT_STRAPP(p_content,p_h->pp_images[i]->pp_files[0]); XMOUNT_STRAPP(p_content," <--\n"); if(p_buf!=NULL) { XMOUNT_STRAPP(p_content,p_buf); p_h->pp_images[i]->p_functions->FreeBuffer(p_buf); } else { XMOUNT_STRAPP(p_content,"None\n"); } } *pp_content=p_content; return e_XmountInput_Error_None; } /******************************************************************************* * Private functions implementations ******************************************************************************/ /* * FindInputLib */ te_XmountInput_Error XmountInput_FindLib(pts_XmountInputHandle p_h, pts_XmountInputImage p_input_image) { char *p_buf; LOG_DEBUG("Trying to find suitable library for input type '%s'.\n", p_input_image->p_type); // Loop over all loaded libs for(uint32_t i=0;ilibs_count;i++) { LOG_DEBUG("Checking input library %s\n",p_h->pp_libs[i]->p_name); p_buf=p_h->pp_libs[i]->p_supported_input_types; while(*p_buf!='\0') { if(strcmp(p_buf,p_input_image->p_type)==0) { // Library supports input type, set lib functions LOG_DEBUG("Input library '%s' pretends to handle that input type.\n", p_h->pp_libs[i]->p_name); p_input_image->p_functions=&(p_h->pp_libs[i]->lib_functions); return e_XmountInput_Error_None; } p_buf+=(strlen(p_buf)+1); } } LOG_DEBUG("Couldn't find any suitable library.\n"); // No library supporting input type found return e_XmountInput_Error_UnsupportedFormat; } diff --git a/src/xmount_input.h b/src/xmount_input.h index 6fed491..03cbc49 100644 --- a/src/xmount_input.h +++ b/src/xmount_input.h @@ -1,329 +1,329 @@ /******************************************************************************* * 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_INPUT_H #define XMOUNT_INPUT_H -#include +#include // For uint* types /******************************************************************************* * Public definitions / macros ******************************************************************************/ //! Naming scheme of input libraries #define XMOUNT_INPUT_LIBRARY_NAMING_SCHEME "libxmount_input_" /******************************************************************************* * Public types / structures / enums ******************************************************************************/ typedef struct s_XmountInputHandle *pts_XmountInputHandle; typedef enum e_XmountInput_Error { //! No error e_XmountInput_Error_None=0, //! Error to allocate memory e_XmountInput_Error_Alloc, //! Invalid input handle e_XmountInput_Error_InvalidHandle, //! Invalid pointer to an input handle e_XmountInput_Error_InvalidHandlePointer, //! A given buffer is invalid e_XmountInput_Error_InvalidBuffer, //! A given string is invalid e_XmountInput_Error_InvalidString, //! A given array is invalid e_XmountInput_Error_InvalidArray, //! Library options have already been set e_XmountInput_Error_LibOptionsAlreadySet, //! Library options couldn't be parsed e_XmountInput_Error_FailedParsingOptions, //! Unable to get info file content from library e_XmountInput_Error_FailedGettingInfoFileContent, //! Unable to load library file e_XmountInput_Error_FailedLoadingLibrary, //! Unable to load a library symbol e_XmountInput_Error_FailedLoadingSymbol, //! Library has wrong API version e_XmountInput_Error_WrongLibraryApiVersion, //! Library is missing a function e_XmountInput_Error_MissingLibraryFunction, //! Unsupported input image format e_XmountInput_Error_UnsupportedFormat, //! 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, //! Unable to get image size e_XmountInput_Error_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 } te_XmountInput_Error; /******************************************************************************* * Public functions declarations ******************************************************************************/ /*! * \brief Create new input handle * * Creates a new input handle. * * \param pp_h Pointer to input handle * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_CreateHandle(pts_XmountInputHandle *pp_h); /*! * \brief Destroy input handle * * Invalidates the given handle and frees all used resources. * * \param pp_h Pointer to input handle * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_DestroyHandle(pts_XmountInputHandle *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 */ te_XmountInput_Error XmountInput_EnableDebugging(pts_XmountInputHandle p_h); /*! * \brief Load an input library * * Loads a given input library. * * \param p_h Input handle * \param p_lib Library name (without path) * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_AddLibrary(pts_XmountInputHandle p_h, const char *p_lib_name); /*! * \brief Get loaded input library count * * Returns the number of successfully loaded input libraries. * * \param p_h Input handle * \param p_count Library count is returned in this variable * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_GetLibraryCount(pts_XmountInputHandle p_h, uint32_t *p_count); /*! * \brief Return all supported formats * * Returns a null-terminated vector of all supported input formats. * * The returned vector must be freed by the caller. * * \param p_h Input handle * \param pp_formats Supported formats vector is returned in this var * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_GetSupportedFormats(pts_XmountInputHandle p_h, char **pp_formats); /*! * \brief Set library options * * Parses the given library option string (as given after --inopts). * * \param p_h Input handle * \param p_options Library option string * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_SetOptions(pts_XmountInputHandle 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. * * The caller must free the returned string. * * \param p_h Input handle * \param pp_help_text Help text is returned in this parameter * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_GetOptionsHelpText(pts_XmountInputHandle 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. * * The caller must free the returned string. * * \param p_h Input handle * \param pp_info_text Info text is returned in this parameter * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_GetLibsInfoText(pts_XmountInputHandle p_h, char **pp_info_text); /*! * \brief Add an input image * * Adds the given input image to the list of available input images. * * \param p_h Input handle * \param p_format Input image format string as given by the user * \param files_count Amount of files specified by the user * \param pp_files Array containing all specified files * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_AddImage(pts_XmountInputHandle p_h, const char *p_format, uint64_t files_count, const char **pp_files); /*! * \brief Get input image count * * Get input image count. * * \param p_h Input handle * \param p_count Input image count is returned in this variable * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_GetImageCount(pts_XmountInputHandle p_h, uint64_t *p_count); /*! * \brief Set an input image offset * * Sets the amount of bytes that should be ignored at the beginning of every * input image. * * \param p_h Input handle * \param offset Amount of bytes to ignore * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_SetInputOffset(pts_XmountInputHandle p_h, uint64_t offset); /*! * \brief Set an input image size limit * * Sets the amount of bytes that should be ignored at the end of every * input image. * * \param p_h Input handle * \param size_limit Amount of bytes to ignore * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_SetInputSizeLimit(pts_XmountInputHandle p_h, uint64_t size_limit); /*! * \brief Opens all added input images * * Opens all added input images. * * \param p_h Input handle * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_Open(pts_XmountInputHandle p_h); /*! * \brief Closes all previously opened input images * * Closes all previously opened input images. * * \param p_h Input handle * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_Close(pts_XmountInputHandle p_h); /*! * \brief Get the size of an input image * * Returns the size (in bytes) of the specified input image. * * \param p_h Input 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 */ te_XmountInput_Error XmountInput_GetSize(pts_XmountInputHandle p_h, uint64_t image_nr, uint64_t *p_size); /*! * \brief Read data from an input image * * Reads count bytes from input image image_nr 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_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 */ te_XmountInput_Error XmountInput_ReadData(pts_XmountInputHandle p_h, uint64_t image_nr, char *p_buf, uint64_t offset, uint64_t count, uint64_t *p_read); te_XmountInput_Error XmountInput_WriteData(pts_XmountInputHandle p_h, uint64_t image_nr, const char *p_buf, uint64_t offset, uint64_t count); /*! * \brief Get info text to be added to xmount's info file * * Generates a string containing informations about currently opened input * images. * * The caller must free the returned string. * * \param p_h Input handle * \param pp_content Buffer in which text is returned * \return e_XmountInput_Error_None on success */ te_XmountInput_Error XmountInput_GetInfoFileContent(pts_XmountInputHandle p_h, char **pp_content); #endif // XMOUNT_INPUT_H diff --git a/src/xmount_morphing.c b/src/xmount_morphing.c index 6c91be2..89624a5 100644 --- a/src/xmount_morphing.c +++ b/src/xmount_morphing.c @@ -1,738 +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 "../libxmount/libxmount.h" +#include "../libxmount_morphing/libxmount_morphing.h" #include "macros.h" +#include // For memcpy +#include // For dlopen, dlclose, dlsym + /******************************************************************************* * Private definitions / macros ******************************************************************************/ -#define XMOUNT_MORPHING_DEFAULT_MORPH_TYPE "combine" - -#define LOG_WARNING(...) { \ +#define LOG_WARNING(...) do { \ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \ -} -#define LOG_ERROR(...) { \ +} while(0) + +#define LOG_ERROR(...) do { \ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \ -} -#define LOG_DEBUG(...) { \ - LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \ -} +} while(0) + +#define LOG_DEBUG(...) do { \ + LIBXMOUNT_LOG_DEBUG(p_h->debug,__VA_ARGS__); \ +} while(0) /******************************************************************************* * 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, 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=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); } *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; 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; } 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; + if(p_types==NULL) return e_XmountMorphError_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; + if(p_types==NULL) return e_XmountMorphError_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) { 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; // Set morphing type XMOUNT_STRSET(p_h->p_morph_type,p_type); return e_XmountMorphError_None; } /* * XmountMorphing_StartMorphing */ 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; // 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_XmountMorphError_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_StopMorphing */ 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 to_read=0; int ret; te_XmountMorphError morph_ret=e_XmountMorphError_None; // Params check if(p_h==NULL) return e_XmountMorphError_InvalidHandle; // 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 *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_XmountMorphError_UnsupportedType; } diff --git a/src/xmount_morphing.h b/src/xmount_morphing.h index 386d0a1..c49ca78 100644 --- a/src/xmount_morphing.h +++ b/src/xmount_morphing.h @@ -1,344 +1,349 @@ /******************************************************************************* * 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 +#include // For calloc and size_t, off_t types +#include // For uint* types + /******************************************************************************* * Public definitions / macros ******************************************************************************/ //! Naming scheme of morphing libraries #define XMOUNT_MORPHING_LIBRARY_NAMING_SCHEME "libxmount_morph_" +//! Default morph type +#define XMOUNT_MORPHING_DEFAULT_MORPH_TYPE "combine" /******************************************************************************* * 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 morphing handle e_XmountMorphError_InvalidHandle, //! 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, //! 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_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 the image e_XmountMorphError_OffsetExceedsImageSize, //! Unable to read data from morphed image e_XmountMorphError_FailedReadingData } te_XmountMorphError; /******************************************************************************* * Public functions declarations ******************************************************************************/ /*! * \brief Create new morphing handle * * Creates a new morphing handle. * * \param pp_h Pointer to morphing handle * \return e_XmountMorphError_None on success */ 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 morphing handle * * Invalidates the given handle and frees all used resources. * * \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 Morphing handle * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_EnableDebugging(pts_XmountMorphHandle p_h); /*! * \brief Load a morphing library * * Loads a given morphing library. * * \param p_h Morphing handle * \param p_lib Library name (without path) * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_AddLibrary(pts_XmountMorphHandle p_h, const char *p_lib_name); /*! * \brief Get loaded morphing library count * * Returns the number of successfully loaded morphing libraries. * * \param p_h Morphing handle * \param p_count Library count is returned in this variable * \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 --morphopts). * * \param p_h Morphing handle * \param p_options Library option string * \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 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 Morphing handle * \param pp_help_text Help text is returned in this parameter * \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 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 Morphing handle * \param pp_info_text Info text is returned in this parameter * \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 Morphing handle * \param p_type Morphing type string as specified with xmount's --morph option. * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_SetType(pts_XmountMorphHandle p_h, char *p_type); /*! * \brief Start the morphing process * * Begins the morphing process. * * \param p_h Morphing handle * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_StartMorphing(pts_XmountMorphHandle p_h); /*! * \brief Stop the morphing process * * Ends the morphing process. * * \param p_h Morphing handle * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_StopMorphing(pts_XmountMorphHandle p_h); /*! * \brief Get the size of the morphed image * * Returns the size (in bytes) of the morphed image. * * \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_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetSize(pts_XmountMorphHandle p_h, uint64_t *p_size); /*! * \brief Read data from the morphed image * * 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 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_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 *p_written); /*! * \brief Get info text to be added to xmount's info file * * Generates a string containing informations about the currently morphed image. * * The caller must free the returned string. * * \param p_h Morphing handle * \param pp_content Buffer in which text is returned * \return e_XmountMorphError_None on success */ te_XmountMorphError XmountMorphing_GetInfoFileContent(pts_XmountMorphHandle p_h, char **pp_content); #endif // XMOUNT_MORPHING_H diff --git a/src/xmount_output.c b/src/xmount_output.c index 3a1575d..5229217 100644 --- a/src/xmount_output.c +++ b/src/xmount_output.c @@ -1,859 +1,865 @@ /******************************************************************************* * 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_output/libxmount_output.h" #include "xmount_output.h" -#include "xmount.h" +#include "../libxmount/libxmount.h" +#include "../libxmount_output/libxmount_output.h" #include "macros.h" +#include // For memcpy +#include // For dlopen, dlclose, dlsym + /******************************************************************************* * Private definitions / macros ******************************************************************************/ -#define LOG_WARNING(...) { \ +#define LOG_WARNING(...) do { \ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \ -} -#define LOG_ERROR(...) { \ +} while(0) + +#define LOG_ERROR(...) do { \ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \ -} -#define LOG_DEBUG(...) { \ - LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \ -} +} while(0) + +#define LOG_DEBUG(...) do { \ + LIBXMOUNT_LOG_DEBUG(p_h->debug,__VA_ARGS__); \ +} while(0) /******************************************************************************* * Private types / structures / enums ******************************************************************************/ //! Structure containing infos about output libs typedef struct s_XmountOutputLib { //! Filename of lib (without path) char *p_name; //! Handle to the loaded lib void *p_lib; //! Array of supported output formats char *p_supported_output_formats; //! Struct containing lib functions ts_LibXmountOutput_Functions lib_functions; } ts_XmountOutputLib, *pts_XmountOutputLib; //! Structure containing infos about output image typedef struct s_XmountOutputHandle { //! Loaded output lib count uint32_t libs_count; //! Array containing infos about loaded output libs pts_XmountOutputLib *pp_libs; //! Specified output format (--out) char *p_output_format; //! Amount of specified output lib params uint32_t lib_params_count; //! Specified output lib params (--outopts) pts_LibXmountOptions *pp_lib_params; //! Handle to initialized output lib void *p_handle; //! Transformation functions of initialized lib pts_LibXmountOutput_Functions p_functions; //! Output image functions passed to output lib ts_LibXmountOutput_Functions output_functions; //! Size uint64_t image_size; //! Path of virtual image file char *p_virtual_image_path; //! Debug uint8_t debug; } ts_XmountOutputHandle; /******************************************************************************* * Private functions declarations ******************************************************************************/ /*! * \brief Find an input lib for a given input image * * Searches trough the list of loaded input libraries to find one that supports * the given input image's format. On success, that library is associated with * the given image. * * \param p_h Output handle * \param p_input_image Output image to search input lib for * \return e_XmountOutputError_None on success */ te_XmountOutputError XmountOutput_FindLib(pts_XmountOutputHandle p_h); /******************************************************************************* * Public functions implementations ******************************************************************************/ /* * XmountOutput_CreateHandle */ te_XmountOutputError XmountOutput_CreateHandle(pts_XmountOutputHandle *pp_h, tfun_XmountOutput_InputImageSize p_img_size, tfun_XmountOutput_InputImageRead p_img_read, tfun_XmountOutput_InputImageWrite p_img_write) { pts_XmountOutputHandle p_h=NULL; // Params check if(pp_h==NULL) return e_XmountOutputError_InvalidHandlePointer; // Alloc new handle p_h=(pts_XmountOutputHandle)calloc(1,sizeof(ts_XmountOutputHandle)); if(p_h==NULL) { return e_XmountOutputError_Alloc; } // Init values p_h->pp_libs=NULL; p_h->p_output_format=NULL; p_h->pp_lib_params=NULL; p_h->p_handle=NULL; p_h->p_functions=NULL; p_h->output_functions.Size=p_img_size; p_h->output_functions.Read=p_img_read; p_h->output_functions.Write=p_img_write; p_h->p_virtual_image_path=NULL; *pp_h=p_h; return e_XmountOutputError_None; } /* * XmountOutput_DestroyHandle */ te_XmountOutputError XmountOutput_DestroyHandle(pts_XmountOutputHandle *pp_h) { int ret=0; pts_XmountOutputHandle p_h=NULL; // Params check if(pp_h==NULL) return e_XmountOutputError_InvalidHandlePointer; if(*pp_h==NULL) return e_XmountOutputError_InvalidHandle; p_h=*pp_h; // Free resources if(p_h->p_functions!=NULL) { if(p_h->p_handle!=NULL) { // Destroy output handle ret=p_h->p_functions->DestroyHandle(&(p_h->p_handle)); if(ret!=0) { LOG_ERROR("Unable to destroy output 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_output_format!=NULL) XMOUNT_FREE(p_h->p_output_format); if(p_h->pp_libs!=NULL) { // Unload output 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_output_formats!=NULL) { XMOUNT_FREE(p_h->pp_libs[i]->p_supported_output_formats); } 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); } if(p_h->p_virtual_image_path!=NULL) XMOUNT_FREE(p_h->p_virtual_image_path); *pp_h=NULL; return e_XmountOutputError_None; } /* * XmountOutput_EnableDebugging */ te_XmountOutputError XmountOutput_EnableDebugging(pts_XmountOutputHandle p_h) { // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; // Enable debugging p_h->debug=1; return e_XmountOutputError_None; } /* * XmountOutput_AddLibrary */ te_XmountOutputError XmountOutput_AddLibrary(pts_XmountOutputHandle p_h, const char *p_lib_name) { uint32_t supported_formats_len=0; t_LibXmount_Output_GetApiVersion pfun_output_GetApiVersion; t_LibXmount_Output_GetSupportedFormats pfun_output_GetSupportedFormats; t_LibXmount_Output_GetFunctions pfun_output_GetFunctions; void *p_libxmount=NULL; pts_XmountOutputLib p_output_lib=NULL; char *p_buf=NULL; char *p_library_path=NULL; char *p_supported_formats=NULL; // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; if(p_lib_name==NULL) return e_XmountOutputError_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 XMOUNTOUTPUT_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_XmountOutputError_FailedLoadingSymbol; \ } \ } // Try to load given library p_libxmount=dlopen(p_library_path,RTLD_NOW); if(p_libxmount==NULL) { LOG_ERROR("Unable to load output library '%s': %s!\n", p_library_path, dlerror()); return e_XmountOutputError_FailedLoadingLibrary; } // Load library symbols XMOUNTOUTPUT_LOADLIBS__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); return e_XmountOutputError_WrongLibraryApiVersion; } XMOUNTOUTPUT_LOADLIBS__LOAD_SYMBOL("LibXmount_Output_GetSupportedFormats", pfun_output_GetSupportedFormats); XMOUNTOUTPUT_LOADLIBS__LOAD_SYMBOL("LibXmount_Output_GetFunctions", pfun_output_GetFunctions); // Construct new entry for our library list XMOUNT_MALLOC(p_output_lib,pts_XmountOutputLib,sizeof(ts_XmountOutputLib)); // 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_lib_name); p_output_lib->p_lib=p_libxmount; // Get and set supported formats p_supported_formats=pfun_output_GetSupportedFormats(); 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.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_lib_name); XMOUNT_FREE(p_output_lib->p_supported_output_formats); XMOUNT_FREE(p_output_lib->p_name); XMOUNT_FREE(p_output_lib); dlclose(p_libxmount); return e_XmountOutputError_MissingLibraryFunction; } // Add entry to the input library list XMOUNT_REALLOC(p_h->pp_libs, pts_XmountOutputLib*, sizeof(pts_XmountOutputLib)*(p_h->libs_count+1)); p_h->pp_libs[p_h->libs_count++]=p_output_lib; LOG_DEBUG("Output library '%s' loaded successfully\n",p_lib_name); #undef XMOUNTOUTPUT_LOADLIBS__LOAD_SYMBOL return e_XmountOutputError_None; } te_XmountOutputError XmountOutput_GetLibraryCount(pts_XmountOutputHandle p_h, uint32_t *p_count) { // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; if(p_count==NULL) return e_XmountOutputError_InvalidBuffer; // Return library count *p_count=p_h->libs_count; return e_XmountOutputError_None; } /* * XmountOutput_GetSupportedFormats */ te_XmountOutputError XmountOutput_GetSupportedFormats(pts_XmountOutputHandle p_h, char **pp_formats) { char *p_buf=NULL; char *p_formats=NULL; uint32_t cur_len=0; uint32_t vector_len=0; // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; if(pp_formats==NULL) return e_XmountOutputError_InvalidBuffer; // Loop over all loaded libs, extract supported formats 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_output_formats; 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_output_formats); if(cur_len==0) continue; p_formats=(char*)realloc(p_formats,vector_len+cur_len); if(p_formats==NULL) return e_XmountOutputError_Alloc; memcpy(p_formats+vector_len, p_h->pp_libs[i]->p_supported_output_formats, cur_len); vector_len+=cur_len; } // Null-terminate vector p_formats=(char*)realloc(p_formats,vector_len+1); if(p_formats==NULL) return e_XmountOutputError_Alloc; p_formats[vector_len]='\0'; *pp_formats=p_formats; return e_XmountOutputError_None; } /* * XmountOutput_SetOptions */ te_XmountOutputError XmountOutput_SetOptions(pts_XmountOutputHandle p_h, char *p_options) { // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; if(p_options==NULL) return e_XmountOutputError_InvalidString; // Make sure library parameters haven't been set previously if(p_h->pp_lib_params!=NULL) { LOG_ERROR("Output library options already set!\n"); return e_XmountOutputError_LibOptionsAlreadySet; } // Save options if(XmountLib_SplitLibParams(p_options, &(p_h->lib_params_count), &(p_h->pp_lib_params))!=0) { LOG_ERROR("Unable to parse input library options '%s'!\n",p_options); return e_XmountOutputError_FailedParsingOptions; } return e_XmountOutputError_None; } /* * XmountOutput_GetOptionsHelpText */ te_XmountOutputError XmountOutput_GetOptionsHelpText(pts_XmountOutputHandle p_h, char **pp_help_text) { const char *p_buf=NULL; char *p_help=NULL; int ret=0; // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; if(pp_help_text==NULL) return e_XmountOutputError_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((const char**)&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)); } 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_XmountOutputError_None; } /* * XmountOutput_GetLibsInfoText */ te_XmountOutputError XmountOutput_GetLibsInfoText(pts_XmountOutputHandle 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_XmountOutputError_InvalidHandle; if(pp_info_text==NULL) return e_XmountOutputError_InvalidBuffer; // Loop over all loaded libs, extract name and supported formats 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_output_formats; 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_XmountOutputError_None; } /* * XmountOutput_SetFormat */ te_XmountOutputError XmountOutput_SetFormat(pts_XmountOutputHandle p_h, char *p_format) { // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; - if(p_format==NULL) return e_XmountMorphError_InvalidString; + if(p_format==NULL) return e_XmountOutputError_InvalidString; // Set output format XMOUNT_STRSET(p_h->p_output_format,p_format); return e_XmountOutputError_None; } /* * XmountOutput_Transform */ te_XmountOutputError XmountOutput_Transform(pts_XmountOutputHandle p_h) { const char *p_err_msg=NULL; int ret=0; te_XmountOutputError output_ret=e_XmountOutputError_None; // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; // Set default output format if none was set previously if(p_h->p_output_format==NULL) { XMOUNT_STRSET(p_h->p_output_format,XMOUNT_OUTPUT_DEFAULT_OUTPUT_FORMAT); } // Find output lib - output_ret=XmountOutput_FindOutputLib(p_h); + output_ret=XmountOutput_FindLib(p_h); if(output_ret!=e_XmountOutputError_None) { LOG_ERROR("Unable to find a library supporting the output format '%s'!\n", p_h->p_output_format); return output_ret; } // Init output ret=p_h->p_functions->CreateHandle(&p_h->p_handle, p_h->p_output_format, p_h->debug); if(ret!=0) { LOG_ERROR("Unable to create output handle: %s!\n", p_h->p_functions->GetErrorMessage(ret)); return e_XmountOutputError_FailedCreatingOutputHandle; } // Parse output 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 output 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 output library specific options: %s!\n", p_h->p_functions->GetErrorMessage(ret)); } return e_XmountOutputError_FailedParsingLibParams; } } // TODO: This has to be done somewhere! /* 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") */ return e_XmountOutputError_None; } /* * XmountOutput_GetOutputFilenames */ te_XmountOutputError XmountOutput_GetOutputFilenames(pts_XmountOutputHandle p_h, - char ***ppp_output_files); + char ***ppp_output_files) +{ + // TODO: Implement + + return e_XmountOutputError_None; +} /* * XmountOutput_GetSize */ te_XmountOutputError XmountOutput_GetSize(pts_XmountOutputHandle p_h, const char *p_output_filename, uint64_t *p_size) { /* // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; if(image_nr>=p_h->images_count) return e_XmountOutputError_NoSuchImage; if(p_size==NULL) return e_XmountOutputError_InvalidBuffer; *p_size=p_h->pp_images[image_nr]->size; */ // TODO: Implement return e_XmountOutputError_None; } /* * XmountOutput_ReadData */ te_XmountOutputError XmountOutput_ReadData(pts_XmountOutputHandle p_h, const char *p_output_filename, char *p_buf, uint64_t offset, uint64_t count, uint64_t *p_read) { // TODO: Implement /* uint64_t to_read=0; int ret=0; int read_errno=0; pts_XmountOutputImage p_image=NULL; // Params check if(p_h==NULL) return e_XmountOutputError_InvalidHandle; if(image_nr>=p_h->images_count) return e_XmountOutputError_NoSuchImage; if(p_buf==NULL) return e_XmountOutputError_InvalidBuffer; p_image=p_h->pp_images[image_nr]; LOG_DEBUG("Reading %zu bytes at offset %zu from input image '%s'\n", count, offset, p_image->pp_files[0]); // Make sure we aren't reading past EOF of image file if(offset>=p_image->size) { // Offset is beyond image size LOG_DEBUG("Offset %zu is at / beyond size of input image '%s'\n", offset, p_image->pp_files[0]); *p_read=0; return 0; } if(offset+count>p_image->size) { // Attempt to read data past EOF of image file to_read=p_image->size-offset; LOG_DEBUG("Attempt to read data past EOF of input image '%s'. " "Correcting size from %zu to %zu\n", p_image->pp_files[0], count, to_read); } else to_read=count; // Read data from image file (adding input image offset if one was specified) ret=p_image->p_functions->Read(p_image->p_handle, p_buf, offset+p_h->image_offset, to_read, p_read, &read_errno); if(ret!=0) { LOG_ERROR("Couldn't read %zu bytes at offset %zu from input image " "'%s': %s: Error code %u!\n", to_read, offset, p_image->pp_files[0], p_image->p_functions->GetErrorMessage(ret), read_errno); return e_XmountOutputError_FailedReadingData; } */ return e_XmountOutputError_None; } /* * XmountOutput_WriteData */ te_XmountOutputError XmountOutput_WriteData(pts_XmountOutputHandle p_h, const char *p_output_filename, const char *p_buf, uint64_t offset, uint64_t count, uint64_t *p_written) { // TODO: Implement return e_XmountOutputError_None; } /* * XmountOutput_GetInfoFileContent */ te_XmountOutputError XmountOutput_GetInfoFileContent(pts_XmountOutputHandle p_h, char **pp_content) { char *p_content=NULL; // TODO: Implement *pp_content=p_content; return e_XmountOutputError_None; } /******************************************************************************* * Private functions implementations ******************************************************************************/ /* * FindOutputLib */ te_XmountOutputError XmountOutput_FindLib(pts_XmountOutputHandle p_h) { char *p_buf; LOG_DEBUG("Trying to find suitable library for output format '%s'.\n", p_h->p_output_format); // Loop over all loaded output libs for(uint32_t i=0;ilibs_count;i++) { LOG_DEBUG("Checking output library %s\n",p_h->pp_libs[i]->p_name); p_buf=p_h->pp_libs[i]->p_supported_output_formats; while(*p_buf!='\0') { if(strcmp(p_buf,p_h->p_output_format)==0) { // Library supports output type, set lib functions LOG_DEBUG("Output library '%s' pretends to handle that output format.\n", p_h->pp_libs[i]->p_name); p_h->p_functions=&(p_h->pp_libs[i]->lib_functions); return e_XmountOutputError_None; } p_buf+=(strlen(p_buf)+1); } } LOG_DEBUG("Couldn't find any suitable library.\n"); // No library supporting input type found return e_XmountOutputError_UnsupportedFormat; } //! Get size of output image /*! * \param p_size Pointer to an uint64_t to which the size will be written to * \return TRUE on success, FALSE on error */ /* int GetOutputImageSize(uint64_t *p_size) { int ret; uint64_t output_image_size=0; if(glob_xmount.output.image_size!=0) { *p_size=glob_xmount.output.image_size; return TRUE; } ret=glob_xmount.output.p_functions->Size(glob_xmount.output.p_handle, &output_image_size); if(ret!=0) { LOG_ERROR("Couldn't get output image size!\n") return FALSE; } glob_xmount.output.image_size=output_image_size; *p_size=output_image_size; return TRUE; } */ //! Read data from output image /*! * \param p_buf Pointer to buffer to write read data to * \param offset Offset at which data should be read * \param size Size of data which should be read * \return Number of read bytes on success or negated error code on error */ /* int ReadOutputImageData(char *p_buf, off_t offset, size_t size) { uint64_t output_image_size; size_t read=0; int ret; // Get output image size if(GetOutputImageSize(&output_image_size)!=TRUE) { LOG_ERROR("Couldn't get size of output image!\n") return -EIO; } // Make sure request is within output image if(offset>=output_image_size) { LOG_DEBUG("Offset %zu is at / beyond size of output image.\n",offset); return 0; } if(offset+size>output_image_size) { LOG_DEBUG("Attempt to read data past EOF of output image. Correcting size " "from %zu to %zu.\n", size, output_image_size-offset); size=output_image_size-offset; } // Read data ret=glob_xmount.output.p_functions->Read(glob_xmount.output.p_handle, p_buf, offset, size, &read); if(ret!=0) { LOG_ERROR("Unable to read %zu bytes at offset %zu from output image!\n", size, offset) return ret; } else if(read!=size) { LOG_WARNING("Unable to read all requested data from output image!\n") return read; } return size; } */ //! Write data to output image /*! * \param p_buf Buffer with data to write * \param offset Offset to write to * \param size Amount of bytes to write * \return Number of written bytes on success or "-1" on error */ /* int WriteOutputImageData(const char *p_buf, off_t offset, size_t size) { uint64_t output_image_size; int ret; size_t written; // Get output image size if(!GetOutputImageSize(&output_image_size)) { LOG_ERROR("Couldn't get output image size!\n") return -1; } // Make sure write is within output image if(offset>=output_image_size) { LOG_ERROR("Attempt to write beyond EOF of output image file!\n") return -1; } if(offset+size>output_image_size) { LOG_DEBUG("Attempt to write past EOF of output image file. Correcting size " "from %zu to %zu.\n", size, output_image_size-offset); size=output_image_size-offset; } ret=glob_xmount.output.p_functions->Write(glob_xmount.output.p_handle, p_buf, offset, size, &written); if(ret!=0) { LOG_ERROR("Unable to write %zu bytes at offset %zu to output image!\n", offset, size) return ret; } else if(written!=size) { LOG_WARNING("Unable to write all requested data to output image!\n") } return size; } */ diff --git a/src/xmount_output.h b/src/xmount_output.h index 73705e4..42a8032 100644 --- a/src/xmount_output.h +++ b/src/xmount_output.h @@ -1,347 +1,350 @@ /******************************************************************************* * 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_OUTPUT_H #define XMOUNT_OUTPUT_H +#include // For uint* types +#include // For calloc and off_t, size_t types + /******************************************************************************* * Public definitions / macros ******************************************************************************/ //! Naming scheme of morphing libraries #define XMOUNT_OUTPUT_LIBRARY_NAMING_SCHEME "libxmount_output_" //! Default output format #define XMOUNT_OUTPUT_DEFAULT_OUTPUT_FORMAT "raw" /******************************************************************************* * Public types / structures / enums ******************************************************************************/ //! Output handle typedef struct s_XmountOutputHandle *pts_XmountOutputHandle; /*! * \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_XmountOutput_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_XmountOutput_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_XmountOutput_InputImageWrite)(uint64_t image, char *p_buf, off_t offset, size_t count, size_t *p_written); typedef enum e_XmountOutputError { //! No error e_XmountOutputError_None=0, //! Error to allocate memory e_XmountOutputError_Alloc, //! Invalid morphing handle e_XmountOutputError_InvalidHandle, //! Invalid pointer to a morphing handle e_XmountOutputError_InvalidHandlePointer, //! A given buffer is invalid e_XmountOutputError_InvalidBuffer, //! A given string is invalid e_XmountOutputError_InvalidString, //! Library options have already been set e_XmountOutputError_LibOptionsAlreadySet, //! Library options couldn't be parsed e_XmountOutputError_FailedParsingOptions, /* //! Unable to get info file content from library e_XmountMorphError_FailedGettingInfoFileContent, */ //! Unable to load library file e_XmountOutputError_FailedLoadingLibrary, //! Unable to load a library symbol e_XmountOutputError_FailedLoadingSymbol, //! Library has wrong API version e_XmountOutputError_WrongLibraryApiVersion, //! Library is missing a function e_XmountOutputError_MissingLibraryFunction, //! Unsupported output format e_XmountOutputError_UnsupportedFormat, //! Unable to create output library handle e_XmountOutputError_FailedCreatingOutputHandle, //! Unable to parse output library options e_XmountOutputError_FailedParsingLibParams, /* //! Unable to get image size e_XmountMorphError_FailedGettingImageSize, //! A specified offset is larger than the image e_XmountMorphError_OffsetExceedsImageSize, //! Unable to read data from morphed image e_XmountMorphError_FailedReadingData */ } te_XmountOutputError; /******************************************************************************* * Public functions declarations ******************************************************************************/ /*! * \brief Create new output handle * * Creates a new output handle. * * \param pp_h Pointer to output handle * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_CreateHandle(pts_XmountOutputHandle *pp_h, tfun_XmountOutput_InputImageSize p_img_size, tfun_XmountOutput_InputImageRead p_img_read, tfun_XmountOutput_InputImageWrite p_img_write); /*! * \brief Destroy output handle * * Invalidates the given handle and frees all used resources. * * \param pp_h Pointer to output handle * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_DestroyHandle(pts_XmountOutputHandle *pp_h); /*! * \brief Enable internal debugging * * Enables the generation of intrernal debugging messages. * * \param p_h Output handle * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_EnableDebugging(pts_XmountOutputHandle p_h); /*! * \brief Load an output library * * Loads a given output library. * * \param p_h Output handle * \param p_lib Library name (without path) * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_AddLibrary(pts_XmountOutputHandle p_h, const char *p_lib_name); /*! * \brief Get loaded output library count * * Returns the number of successfully loaded output libraries. * * \param p_h Output handle * \param p_count Library count is returned in this variable * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_GetLibraryCount(pts_XmountOutputHandle p_h, uint32_t *p_count); /*! * \brief Return all supported output formats * * Returns a null-terminated vector of all supported output formats. * * The returned vector must be freed by the caller. * * \param p_h Output handle * \param pp_types Supported formats vector is returned in this var * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_GetSupportedFormats(pts_XmountOutputHandle p_h, char **pp_formats); /*! * \brief Set library options * * Parses the given library option string (as given after --outopts). * * \param p_h Output handle * \param p_options Library option string * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_SetOptions(pts_XmountOutputHandle p_h, char *p_options); /*! * \brief Return all library specific option help texts * * Returns a string containing help messages for all loaded output 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 Output handle * \param pp_help_text Help text is returned in this parameter * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_GetOptionsHelpText(pts_XmountOutputHandle p_h, char **pp_help_text); /*! * \brief Returns a string containing infos about loaded libs * * Returns a string containing infos about loaded output libraries. The * string is pre-formated to be used in xmount's info output. * * The caller must free the returned string. * * \param p_h Output handle * \param pp_info_text Info text is returned in this parameter * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_GetLibsInfoText(pts_XmountOutputHandle p_h, char **pp_info_text); /*! * \brief Set output format * * Set the output format. * * \param p_h Output handle * \param p_type Output format string as specified with xmount's --out option. * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_SetFormat(pts_XmountOutputHandle p_h, char *p_format); /*! * \brief Generate output image * * Gets the output image ready for usage. * * \param p_h Output handle * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_Transform(pts_XmountOutputHandle p_h); /*! * \brief Returns an array containing all output files names * * TODO: Describe * * \param p_h Output handle * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_GetOutputFilenames(pts_XmountOutputHandle p_h, char ***ppp_output_files); /*! * \brief Get the size of the output image * * Returns the size (in bytes) of the specified output image. * * \param p_h Output handle * \param p_output_filename Output file for which to return the size * \param p_size On success, size is returned in this variable * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_GetSize(pts_XmountOutputHandle p_h, const char *p_output_filename, uint64_t *p_size); /*! * \brief Read data from an output image * * Reads count bytes from the specified output 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 Output handle * \param p_output_filename Output file for which to return the size * \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_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_ReadData(pts_XmountOutputHandle p_h, const char *p_output_filename, char *p_buf, uint64_t offset, uint64_t count, uint64_t *p_read); /*! * \brief Writes data to an output image * * Writes count bytes from p_buf to the specified output image starting at the * given offset. * * \param p_h Output handle * \param p_output_filename Output file for which to return the size * \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_XmountOutputError XmountOutput_WriteData(pts_XmountOutputHandle p_h, const char *p_output_filename, const char *p_buf, uint64_t offset, 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 the output image. * * The caller must free the returned string. * * \param p_h Output handle * \param pp_content Buffer in which text is returned * \return e_XmountMorphError_None on success */ te_XmountOutputError XmountOutput_GetInfoFileContent(pts_XmountOutputHandle p_h, char **pp_content); #endif // XMOUNT_OUTPUT_H