diff --git a/trunk/CMakeLists.txt b/trunk/CMakeLists.txt index ad0dd6a..a553e2c 100644 --- a/trunk/CMakeLists.txt +++ b/trunk/CMakeLists.txt @@ -1,5 +1,23 @@ +include(CheckCSourceCompiles) + cmake_minimum_required(VERSION 2.8) -project(xmount) -set(CMAKE_C_FLAGS "-std=c99 -Wall") + +add_definitions(-DXMOUNT_VERSION="0.7.0") + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/") +set(CMAKE_C_FLAGS "-ggdb -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -std=c99 -Wall") + +# Check that off_t can represent 2**63 - 1 correctly. +# If it can't, we need to set _FILE_OFFSET_BITS=64 +#check_c_source_compiles(" +# #include +# #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +# int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; +# int main() { return 0; } +#" _OFFT_IS_64BIT) +#if(NOT ${_OFFT_IS_64BIT}) +# set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-D_FILE_OFFSET_BITS=64") +#endif(NOT ${_OFFT_IS_64BIT}) + add_subdirectory(libxmount_input) -#add_subdirectory(src) +add_subdirectory(src) diff --git a/trunk/cmake_modules/FindLibFUSE.cmake b/trunk/cmake_modules/FindLibFUSE.cmake new file mode 100644 index 0000000..0ec355b --- /dev/null +++ b/trunk/cmake_modules/FindLibFUSE.cmake @@ -0,0 +1,20 @@ +find_package(PkgConfig) +pkg_check_modules(PC_LIBFUSE QUIET libfuse) +set(LIBFUSE_DEFINITIONS ${PC_LIBFUSE_CFLAGS_OTHER}) + +find_path(LIBFUSE_INCLUDE_DIR fuse.h + HINTS ${PC_LIBFUSE_INCLUDEDIR} ${PC_LIBFUSE_INCLUDE_DIRS} + PATH_SUFFIXES fuse) + +find_library(LIBFUSE_LIBRARY NAMES fuse libfuse + HINTS ${PC_LIBFUSE_LIBDIR} ${PC_LIBFUSE_LIBRARY_DIRS}) + +set(LIBFUSE_LIBRARIES ${LIBFUSE_LIBRARY}) +set(LIBFUSE_INCLUDE_DIRS ${LIBFUSE_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(LibFUSE DEFAULT_MSG LIBFUSE_LIBRARY LIBFUSE_INCLUDE_DIR) + +mark_as_advanced(LIBFUSE_INCLUDE_DIR LIBFUSE_LIBRARY) diff --git a/trunk/libxmount_input/CMakeLists.txt b/trunk/libxmount_input/CMakeLists.txt index 3310462..a84c410 100644 --- a/trunk/libxmount_input/CMakeLists.txt +++ b/trunk/libxmount_input/CMakeLists.txt @@ -1,12 +1,10 @@ -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/") - find_package(LibEWF) if(LIBEWF_FOUND) add_subdirectory(libxmount_input_ewf) endif(LIBEWF_FOUND) -find_package(LibAFF) -if(LIBAFF_FOUND) - add_subdirectory(libxmount_input_aff) -endif(LIBAFF_FOUND) +#find_package(LibAFF) +#if(LIBAFF_FOUND) +# add_subdirectory(libxmount_input_aff) +#endif(LIBAFF_FOUND) diff --git a/trunk/libxmount_input/libxmount_input.h b/trunk/libxmount_input/libxmount_input.h index a6f5040..dd77370 100644 --- a/trunk/libxmount_input/libxmount_input.h +++ b/trunk/libxmount_input/libxmount_input.h @@ -1,127 +1,132 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 LIBXMOUNT_INPUT_H #define LIBXMOUNT_INPUT_H #define LIBXMOUNT_INPUT_API_VERSION 1 #include //! Structure containing pointers to the lib's functions typedef struct s_LibXmountInputFunctions { /*! * Function to open input image * * \param pp_handle Pointer to store handle of opened image to * \param pp_filename_arr Array containing all specified input images * \param filename_arr_len Length of pp_filename_arr * \return 0 on success or error code */ int (*Open)(void **pp_handle, const char **pp_filename_arr, uint64_t filename_arr_len); /*! * Function to get the input image's size * * \param p_handle Handle to the opened image * \param p_size Pointer to store input image's size to * \return 0 on success or error code */ int (*Size)(void *p_handle, uint64_t *p_size); /*! * Function to read data from input image * * \param p_handle Handle to the opened image * \param offset Position at which to start reading * \param p_buf Buffer to store read data to * \param count Amount of bytes to read * \return 0 on success or error code */ int (*Read)(void *p_handle, uint64_t offset, - unsigned char *p_buf, + char *p_buf, uint32_t count); /*! * Function to close an opened input image * * \param pp_handle Pointer to the handle of the opened image * \return 0 on success or error code */ int (*Close)(void **pp_handle); /*! * Function to return a string containing help messages for any supported * lib-specific options * * \param pp_help Pointer to a string to store null-terminated help text * \return 0 on success or error code */ int (*OptionsHelp)(const char **pp_help); /*! * Function to parse any lib-specific options * * \param p_handle Handle to the opened image * \param p_options String with specified options * \param pp_error Pointer to a string with error message * \return 0 on success or error code and error message */ int (*OptionsParse)(void *p_handle, char *p_options, char **pp_error); /*! * Function to get content to add to the info file * * \param p_handle Handle to the opened image * \param pp_info_buf Pointer to store the null-terminated content * \return 0 on success or error code */ int (*GetInfofileContent)(void *p_handle, const char **pp_info_buf); /*! * Function to free buffers that were allocated by lib * * \param p_buf Buffer to free */ void (*FreeBuffer)(void *p_buf); } ts_LibXmountInputFunctions, *pts_LibXmountInputFunctions; //! Get library API version /*! * \param p_ver Supported version */ -void LibXmount_Input_GetApiVersion(uint8_t *p_ver); +uint8_t LibXmount_Input_GetApiVersion(); +typedef uint8_t (*t_LibXmount_Input_GetApiVersion)(); + //! Get a list of supported formats /*! * Gets a list of supported input image formats. These are the strings * specified with xmount's --in command line option. * * \param ppp_arr Array containing supported format strings - * \param p_arr_len Length of pp_arr + * \return Length of ppp_arr */ -void LibXmount_Input_GetSupportedFormats(char ***ppp_arr, uint8_t *p_arr_len); +const char* LibXmount_Input_GetSupportedFormats(); +typedef const char* (*t_LibXmount_Input_GetSupportedFormats)(); + //! Get the lib's s_LibXmountInputFunctions structure /*! * \param pp_functions Functions */ -void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions **pp_functions); +void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions); +typedef void (*t_LibXmount_Input_GetFunctions)(ts_LibXmountInputFunctions*); #endif // LIBXMOUNT_INPUT_H diff --git a/trunk/libaaff/aaff.c b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c similarity index 100% rename from trunk/libaaff/aaff.c rename to trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c diff --git a/trunk/libaaff/aaff.h b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h similarity index 100% rename from trunk/libaaff/aaff.h rename to trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h diff --git a/trunk/libaewf/aewf.c b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c similarity index 100% rename from trunk/libaewf/aewf.c rename to trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c diff --git a/trunk/libaewf/aewf.h b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h similarity index 100% rename from trunk/libaewf/aewf.h rename to trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h diff --git a/trunk/libdd/dd.c b/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.c similarity index 100% rename from trunk/libdd/dd.c rename to trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.c diff --git a/trunk/libdd/dd.h b/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.h similarity index 100% rename from trunk/libdd/dd.h rename to trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.h diff --git a/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c b/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c index ada05e6..ec095d4 100644 --- a/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c +++ b/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c @@ -1,302 +1,301 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 . * *******************************************************************************/ #undef HAVE_LIBEWF_STATIC #include #include #include "../libxmount_input.h" #ifndef HAVE_LIBEWF_STATIC #include #else #include "libewf/include/libewf.h" #endif #if !defined(LIBEWF_HANDLE) // libewf version 2 no longer defines LIBEWF_HANDLE #define HAVE_LIBEWF_V2_API #endif /******************************************************************************* * Forward declarations ******************************************************************************/ int EwfOpen(void **pp_handle, const char **pp_filename_arr, uint64_t filename_arr_len); int EwfSize(void *p_handle, uint64_t *p_size); int EwfRead(void *p_handle, uint64_t seek, - unsigned char *p_buf, + char *p_buf, uint32_t count); int EwfClose(void **pp_handle); int EwfOptionsHelp(const char **pp_help); int EwfOptionsParse(void *p_handle, char *p_options, char **pp_error); int EwfGetInfofileContent(void *p_handle, const char **pp_info_buf); void EwfFreeBuffer(void *p_buf); /******************************************************************************* * LibXmount_Input API implementation ******************************************************************************/ /* * LibXmount_Input_GetApiVersion */ -void LibXmount_Input_GetApiVersion(uint8_t *p_ver) { - *p_ver=LIBXMOUNT_INPUT_API_VERSION; +uint8_t LibXmount_Input_GetApiVersion() { + return LIBXMOUNT_INPUT_API_VERSION; } /* * LibXmount_Input_GetSupportedFormats */ -void LibXmount_Input_GetSupportedFormats(char ***ppp_arr, uint8_t *p_arr_len) { +const char* LibXmount_Input_GetSupportedFormats() { +/* // Alloc array containing 1 element with content "ewf" *ppp_arr=(char**)malloc(sizeof(char*)); if(*ppp_arr==NULL) { *p_arr_len=0; return; } **ppp_arr=(char*)malloc(sizeof(char)*4); if(**ppp_arr==NULL) { free(*ppp_arr); *ppp_arr=NULL; *p_arr_len=0; return; } strcpy(**ppp_arr,"ewf"); *p_arr_len=1; +*/ + return "ewf\0\0"; } /* * LibXmount_Input_GetFunctions */ -void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions **pp_functions) { - *pp_functions= - (pts_LibXmountInputFunctions)malloc(sizeof(ts_LibXmountInputFunctions)); - if(*pp_functions==NULL) return; - - (*pp_functions)->Open=&EwfOpen; - (*pp_functions)->Size=&EwfSize; - (*pp_functions)->Read=&EwfRead; - (*pp_functions)->Close=&EwfClose; - (*pp_functions)->OptionsHelp=&EwfOptionsHelp; - (*pp_functions)->OptionsParse=&EwfOptionsParse; - (*pp_functions)->GetInfofileContent=&EwfGetInfofileContent; - (*pp_functions)->FreeBuffer=&EwfFreeBuffer; +void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions) { + p_functions->Open=&EwfOpen; + p_functions->Size=&EwfSize; + p_functions->Read=&EwfRead; + p_functions->Close=&EwfClose; + p_functions->OptionsHelp=&EwfOptionsHelp; + p_functions->OptionsParse=&EwfOptionsParse; + p_functions->GetInfofileContent=&EwfGetInfofileContent; + p_functions->FreeBuffer=&EwfFreeBuffer; } /******************************************************************************* * Private ******************************************************************************/ /* * EwfOpen */ int EwfOpen(void **pp_handle, const char **pp_filename_arr, uint64_t filename_arr_len) { // We need at least one file if(filename_arr_len==0) return 1; // Make sure all files are EWF files for(uint64_t i=0;i * * * * 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 "config.h" //#ifndef HAVE_LIBZ // #undef WITH_LIBAEWF //#endif -#define XMOUNT_LIBRARY_PATH "/usr/lib/xmount" +//#define XMOUNT_LIBRARY_PATH "/usr/local/lib/xmount" #include #include #include #include #include //#include +#include // For dlopen, dlclose, dlsym +#include // For opendir, readdir, closedir #include #include #ifndef __APPLE__ #include #endif #include #include #include "xmount.h" #include "md5.h" -#include "../libxmount_input/libxmount_input.h" /******************************************************************************* * Global vars ******************************************************************************/ // Struct that contains various runtime configuration options -static TXMountConfData XMountConfData; +static ts_XmountConfData glob_xmount_cfg; // Struct containing pointers to the libxmount_input functions -static void *p_libxmount_in=NULL -static ts_LibXmountInputFunctions libxmount_in_functions; +static pts_InputLib *glob_pp_input_libs=NULL; +static uint32_t glob_input_libs_count=0; +static pts_LibXmountInputFunctions glob_p_input_functions=NULL; + +// Handle for input image +static void *glob_p_input_image=NULL; // Pointer to virtual info file -static char *pVirtualImageInfoFile=NULL; +static char *glob_p_info_file=NULL; // Vars needed for VDI emulation -static TVdiFileHeader *pVdiFileHeader=NULL; -static uint32_t VdiFileHeaderSize=0; -static char *pVdiBlockMap=NULL; -static uint32_t VdiBlockMapSize=0; +static pts_VdiFileHeader glob_p_vdi_header=NULL; +static uint32_t glob_vdi_header_size=0; +static char *glob_p_vdi_block_map=NULL; +static uint32_t glob_p_vdi_block_map_size=0; // Vars needed for VHD emulation -static TVhdFileHeader *pVhdFileHeader=NULL; +static ts_VhdFileHeader *glob_p_vhd_header=NULL; // Vars needed for VMDK emulation -static char *pVirtualVmdkFile=NULL; -static int VirtualVmdkFileSize=0; -static char *pVirtualVmdkLockDir=NULL; -static char *pVirtualVmdkLockDir2=NULL; -static char *pVirtualVmdkLockFileData=NULL; -static int VirtualVmdkLockFileDataSize=0; -static char *pVirtualVmdkLockFileName=NULL; +static char *glob_p_vmdk_file=NULL; +static int glob_vmdk_file_size=0; +static char *glob_p_vmdk_lockdir1=NULL; +static char *glob_p_vmdk_lockdir2=NULL; +static char *glob_p_vmdk_lockfile_data=NULL; +static int glob_vmdk_lockfile_size=0; +static char *glob_p_vmdk_lockfile_name=NULL; // Vars needed for virtual write access -static FILE *hCacheFile=NULL; -static pTCacheFileHeader pCacheFileHeader=NULL; -static pTCacheFileBlockIndex pCacheFileBlockIndex=NULL; +static FILE *glob_p_cache_file=NULL; +static pts_CacheFileHeader glob_p_cache_header=NULL; +static pts_CacheFileBlockIndex glob_p_cache_blkidx=NULL; // Mutexes to control concurrent read & write access -static pthread_mutex_t mutex_image_rw; -static pthread_mutex_t mutex_info_read; +static pthread_mutex_t glob_mutex_image_rw; +static pthread_mutex_t glob_mutex_info_read; /* * LogMessage: * Print error and debug messages to stdout * * Params: * pMessageType: "ERROR" or "DEBUG" * pCallingFunction: Name of calling function * line: Line number of call * pMessage: Message string * ...: Variable params with values to include in message string * * Returns: * n/a */ static void LogMessage(char *pMessageType, char *pCallingFunction, int line, char *pMessage, ...) { va_list VaList; // Print message "header" - printf("%s: %s.%s@%u : ",pMessageType,pCallingFunction,PACKAGE_VERSION,line); + printf("%s: %s.%s@%u : ",pMessageType,pCallingFunction,XMOUNT_VERSION,line); // Print message with variable parameters va_start(VaList,pMessage); vprintf(pMessage,VaList); va_end(VaList); } /* * LogWarnMessage: * Print warning messages to stdout * * Params: * pMessage: Message string * ...: Variable params with values to include in message string * * Returns: * n/a */ static void LogWarnMessage(char *pMessage,...) { va_list VaList; // Print message "header" printf("WARNING: "); // Print message with variable parameters va_start(VaList,pMessage); vprintf(pMessage,VaList); va_end(VaList); } /* * PrintUsage: * Print usage instructions (cmdline options etc..) * * Params: * pProgramName: Program name (argv[0]) * * Returns: * n/a */ static void PrintUsage(char *pProgramName) { - printf("\nxmount v%s copyright (c) 2008-2013 by Gillen Daniel " - "\n",PACKAGE_VERSION); + char *p_buf; + int first=1; + + printf("\nxmount v%s copyright (c) 2008-2014 by Gillen Daniel " + "\n",XMOUNT_VERSION); printf("\nUsage:\n"); printf(" %s [[fopts] [mopts]] [ [...]] \n\n",pProgramName); 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\n"); printf(" addition of FUSE's allow_other option!\n"); printf(" INFO: For VMDK emulation, you have to uncomment \"user_allow_other\" in\n"); printf(" /etc/fuse.conf or run xmount as root.\n"); printf(" mopts:\n"); printf(" --cache : Enable virtual write support and set cachefile to use.\n"); // printf(" --debug : Enable xmount's debug mode.\n"); - printf(" --in : Input image format. can be \"dd\""); -#ifdef WITH_LIBEWF - printf(", \"ewf\""); -#endif -#ifdef WITH_LIBAEWF - printf(", \"aewf\""); -#endif -#ifdef WITH_LIBAFF - printf(", \"aff\""); -#endif -#ifdef WITH_LIBAAFF - printf(", \"aaff\""); -#endif + printf(" --in : Input image format. can be "); + + for(uint32_t i=0;ip_supported_input_types; + while(*p_buf!='\0') { + if(first==1) { + printf("\"%s\"",p_buf); + first=0; + } else printf(", \"%s\"",p_buf); + p_buf+=(strlen(p_buf)+1); + } + } printf(".\n"); + printf(" --info : Print out some infos about used compiler and libraries.\n"); printf(" --offset : Move the output image data start bytes into the input image.\n"); printf(" --options : Specify special xmount options.\n"); printf(" --out : Output image format. can be \"dd\", \"dmg\", \"vdi\", \"vhd\", \"vmdk(s)\".\n"); printf(" --owcache : Same as --cache but overwrites existing cache.\n"); printf(" --rw : Same as --cache .\n"); printf(" --version : Same as --info.\n"); #ifndef __APPLE__ printf(" INFO: Input and output image type defaults to \"dd\" if not specified.\n"); #else printf(" INFO: Input image type defaults to \"dd\" and output image type defaults to \"dmg\" if not specified.\n"); #endif printf(" WARNING: Output image type \"vmdk(s)\" should be considered experimental!\n"); printf(" ifile:\n"); - printf(" Input image file."); -#if defined(WITH_LIBEWF) || defined(WITH_LIBAEWF) - printf(" If you use EWF files, you have to specify all image\n"); - printf(" segments! (If your shell supports it, you can use .E?? as file extension\n"); - printf(" to specify them all)\n"); -#else - printf("\n"); -#endif + printf(" Input image file. If your input image is split into multiple files, you have to specify them all!\n"); printf(" mntp:\n"); printf(" Mount point where virtual files should be located.\n"); } /* * CheckFuseAllowOther: * 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. * * Params: * n/a * * Returns: * TRUE on success, FALSE on error */ static int CheckFuseAllowOther() { if(geteuid()!=0) { // Not running xmount as root. Try to read FUSE's config file /etc/fuse.conf FILE *hFuseConf=(FILE*)FOPEN("/etc/fuse.conf","r"); if(hFuseConf==NULL) { LogWarnMessage("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"); return FALSE; } // Search conf file for set user_allow_others char line[256]; int PermSet=FALSE; while(fgets(line,sizeof(line),hFuseConf)!=NULL && PermSet!=TRUE) { // TODO: This works as long as there is no other parameter beginning with // "user_allow_other" :) if(strncmp(line,"user_allow_other",strlen("user_allow_other"))==0) { PermSet=TRUE; } } fclose(hFuseConf); if(PermSet==FALSE) { LogWarnMessage("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"); return FALSE; } } // Running xmount as root or user_allow_other is set in /etc/fuse.conf return TRUE; } /* * ParseCmdLine: * Parse command line options * * Params: * argc: Number of cmdline params * argv: Array containing cmdline params * pNargv: Number of FUSE options is written to this var * pppNargv: FUSE options are written to this array * pFilenameCount: Number of input image files is written to this var * pppFilenames: Input image filenames are written to this array * ppMountpoint: Mountpoint is written to this var * * Returns: * "TRUE" on success, "FALSE" on error */ static int ParseCmdLine(const int argc, char **argv, int *pNargc, char ***pppNargv, int *pFilenameCount, char ***pppFilenames, char **ppMountpoint) { - int i=1,files=0,opts=0,FuseMinusOControl=TRUE,FuseAllowOther=TRUE; + int i=1,files=0,opts=0,FuseMinusOControl=TRUE,FuseAllowOther=TRUE,first; + char *p_buf; // add argv[0] to pppNargv opts++; XMOUNT_MALLOC(*pppNargv,char**,opts*sizeof(char*)) XMOUNT_STRSET((*pppNargv)[opts-1],argv[0]) // Parse options while(i1 && *(argv[i]+1)!='-') { // Options beginning with - are mostly FUSE specific if(strcmp(argv[i],"-d")==0) { // Enable FUSE's and xmount's debug mode opts++; XMOUNT_REALLOC(*pppNargv,char**,opts*sizeof(char*)) XMOUNT_STRSET((*pppNargv)[opts-1],argv[i]) - XMountConfData.Debug=TRUE; + glob_xmount_cfg.Debug=TRUE; } else if(strcmp(argv[i],"-h")==0) { // Print help message PrintUsage(argv[0]); exit(1); } else if(strcmp(argv[i],"-o")==0) { // Next parameter specifies fuse / lib mount options if((argc+1)>i) { i++; // As the user specified the -o option, we assume he knows what he is // doing. We won't append allow_other automatically. And we allow him // to disable allow_other by passing a single "-o no_allow_other" // which won't be passed to FUSE as it is xmount specific. if(strcmp(argv[i],"no_allow_other")!=0) { opts+=2; XMOUNT_REALLOC(*pppNargv,char**,opts*sizeof(char*)) XMOUNT_STRSET((*pppNargv)[opts-2],argv[i-1]) XMOUNT_STRSET((*pppNargv)[opts-1],argv[i]) FuseMinusOControl=FALSE; } else FuseAllowOther=FALSE; } else { LOG_ERROR("Couldn't parse mount options!\n") PrintUsage(argv[0]); exit(1); } } else if(strcmp(argv[i],"-s")==0) { // Enable FUSE's single threaded mode opts++; XMOUNT_REALLOC(*pppNargv,char**,opts*sizeof(char*)) XMOUNT_STRSET((*pppNargv)[opts-1],argv[i]) } else if(strcmp(argv[i],"-V")==0) { // Display FUSE version info opts++; XMOUNT_REALLOC(*pppNargv,char**,opts*sizeof(char*)) XMOUNT_STRSET((*pppNargv)[opts-1],argv[i]) } else { LOG_ERROR("Unknown command line option \"%s\"\n",argv[i]); PrintUsage(argv[0]); exit(1); } } else { // Options beginning with -- are xmount specific if(strcmp(argv[i],"--cache")==0 || strcmp(argv[i],"--rw")==0) { // Emulate writable access to mounted image // Next parameter must be cache file to read/write changes from/to if((argc+1)>i) { i++; - XMOUNT_STRSET(XMountConfData.pCacheFile,argv[i]) - XMountConfData.Writable=TRUE; + XMOUNT_STRSET(glob_xmount_cfg.pCacheFile,argv[i]) + glob_xmount_cfg.Writable=TRUE; } else { LOG_ERROR("You must specify a cache file to read/write data from/to!\n") PrintUsage(argv[0]); exit(1); } LOG_DEBUG("Enabling virtual write support using cache file \"%s\"\n", - XMountConfData.pCacheFile) + glob_xmount_cfg.pCacheFile) } else if(strcmp(argv[i],"--in")==0) { // Specify input image type // Next parameter must be image type if((argc+1)>i) { i++; - if(strcmp(argv[i],"dd")==0) { - XMountConfData.OrigImageType=TOrigImageType_DD; - LOG_DEBUG("Setting input image type to DD\n") -#ifdef WITH_LIBEWF - } else if(strcmp(argv[i],"ewf")==0) { - XMountConfData.OrigImageType=TOrigImageType_EWF; - LOG_DEBUG("Setting input image type to EWF\n") -#endif -#ifdef WITH_LIBAEWF - } else if(strcmp(argv[i],"aewf")==0) { - XMountConfData.OrigImageType=TOrigImageType_AEWF; - LOG_DEBUG("Setting input image type to AEWF\n") -#endif -#ifdef WITH_LIBAFF - } else if(strcmp(argv[i],"aff")==0) { - XMountConfData.OrigImageType=TOrigImageType_AFF; - LOG_DEBUG("Setting input image type to AFF\n") -#endif -#ifdef WITH_LIBAAFF - } else if(strcmp(argv[i],"aaff")==0) { - XMountConfData.OrigImageType=TOrigImageType_AAFF; - LOG_DEBUG("Setting input image type to AAFF\n") -#endif + if(glob_xmount_cfg.p_orig_image_type==NULL) { + XMOUNT_STRSET(glob_xmount_cfg.p_orig_image_type,argv[i]); + LOG_DEBUG("Setting input image type to '%s'\n",argv[i]); } else { - LOG_ERROR("Unknown input image type \"%s\"!\n",argv[i]) + LOG_ERROR("You can only specify --in once!") PrintUsage(argv[0]); exit(1); } } else { LOG_ERROR("You must specify an input image type!\n"); PrintUsage(argv[0]); exit(1); } } else if(strcmp(argv[i],"--options")==0) { if((argc+1)>i) { i++; - XMOUNT_STRSET(XMountConfData.p_lib_params,argv[i]); + XMOUNT_STRSET(glob_xmount_cfg.p_lib_params,argv[i]); } else { LOG_ERROR("You must specify special options!\n"); PrintUsage(argv[0]); exit(1); } } else if(strcmp(argv[i],"--out")==0) { // Specify output image type // Next parameter must be image type if((argc+1)>i) { i++; if(strcmp(argv[i],"dd")==0) { - XMountConfData.VirtImageType=TVirtImageType_DD; + glob_xmount_cfg.VirtImageType=VirtImageType_DD; LOG_DEBUG("Setting virtual image type to DD\n") } else if(strcmp(argv[i],"dmg")==0) { - XMountConfData.VirtImageType=TVirtImageType_DMG; + glob_xmount_cfg.VirtImageType=VirtImageType_DMG; LOG_DEBUG("Setting virtual image type to DMG\n") } else if(strcmp(argv[i],"vdi")==0) { - XMountConfData.VirtImageType=TVirtImageType_VDI; + glob_xmount_cfg.VirtImageType=VirtImageType_VDI; LOG_DEBUG("Setting virtual image type to VDI\n") } else if(strcmp(argv[i],"vhd")==0) { - XMountConfData.VirtImageType=TVirtImageType_VHD; + glob_xmount_cfg.VirtImageType=VirtImageType_VHD; LOG_DEBUG("Setting virtual image type to VHD\n") } else if(strcmp(argv[i],"vmdk")==0) { - XMountConfData.VirtImageType=TVirtImageType_VMDK; + glob_xmount_cfg.VirtImageType=VirtImageType_VMDK; LOG_DEBUG("Setting virtual image type to VMDK\n") } else if(strcmp(argv[i],"vmdks")==0) { - XMountConfData.VirtImageType=TVirtImageType_VMDKS; + glob_xmount_cfg.VirtImageType=VirtImageType_VMDKS; LOG_DEBUG("Setting virtual image type to VMDKS\n") } else { LOG_ERROR("Unknown output image type \"%s\"!\n",argv[i]) PrintUsage(argv[0]); exit(1); } } else { LOG_ERROR("You must specify an output image type!\n"); PrintUsage(argv[0]); exit(1); } } else if(strcmp(argv[i],"--owcache")==0) { // Enable writable access to mounted image and overwrite existing cache // Next parameter must be cache file to read/write changes from/to if((argc+1)>i) { i++; - XMOUNT_STRSET(XMountConfData.pCacheFile,argv[i]) - XMountConfData.Writable=TRUE; - XMountConfData.OverwriteCache=TRUE; + XMOUNT_STRSET(glob_xmount_cfg.pCacheFile,argv[i]) + glob_xmount_cfg.Writable=TRUE; + glob_xmount_cfg.OverwriteCache=TRUE; } else { LOG_ERROR("You must specify a cache file to read/write data from/to!\n") PrintUsage(argv[0]); exit(1); } LOG_DEBUG("Enabling virtual write support overwriting cache file \"%s\"\n", - XMountConfData.pCacheFile) + glob_xmount_cfg.pCacheFile) } else if(strcmp(argv[i],"--version")==0 || strcmp(argv[i],"--info")==0) { - printf("xmount v%s copyright (c) 2008-2013 by Gillen Daniel " - "\n\n",PACKAGE_VERSION); + printf("xmount v%s copyright (c) 2008-2014 by Gillen Daniel " + "\n\n",XMOUNT_VERSION); #ifdef __GNUC__ printf(" compile timestamp: %s %s\n",__DATE__,__TIME__); printf(" gcc version: %s\n",__VERSION__); #endif -#if defined(WITH_LIBEWF) || defined(WITH_LIBAEWF) - printf(" EWF support: YES"); - #ifdef WITH_LIBEWF - printf(" (libewf v%s)",LIBEWF_VERSION_STRING); - #endif - #ifdef WITH_LIBAEWF - printf(" (internal)"); - #endif - printf("\n"); -#else - printf(" EWF support: NO\n"); -#endif -#if defined(WITH_LIBAFF) || defined(WITH_LIBAAFF) - printf(" AFF support: YES "); - #ifdef WITH_LIBAFF - printf("(libaff v%s)",af_version()); - #endif - #ifdef WITH_LIBAAFF - printf("(internal) "); - #endif - printf("\n"); -#else - printf(" AFF support: NO\n"); -#endif + printf(" loaded input libraries:\n"); + for(uint32_t ii=0;iip_name); + p_buf=glob_pp_input_libs[ii]->p_supported_input_types; + first=TRUE; + while(*p_buf!='\0') { + if(first) { + printf("\"%s\"",p_buf); + first=FALSE; + } else printf(", \"%s\"",p_buf); + p_buf+=(strlen(p_buf)+1); + } + printf("\n"); + } printf("\n"); exit(0); } else if(strcmp(argv[i],"--offset")==0) { if((argc+1)>i) { i++; - XMountConfData.orig_img_offset=strtoull(argv[i],NULL,10); + glob_xmount_cfg.orig_img_offset=strtoull(argv[i],NULL,10); } else { LOG_ERROR("You must specify an offset!\n") PrintUsage(argv[0]); exit(1); } LOG_DEBUG("Setting input image offset to \"%" PRIu64 "\"\n", - XMountConfData.orig_img_offset) + glob_xmount_cfg.orig_img_offset) } else { LOG_ERROR("Unknown command line option \"%s\"\n",argv[i]); PrintUsage(argv[0]); exit(1); } } i++; } // Parse input image filename(s) while(i<(argc-1)) { files++; XMOUNT_REALLOC(*pppFilenames,char**,files*sizeof(char*)) XMOUNT_STRSET((*pppFilenames)[files-1],argv[i]) i++; } if(files==0) { LOG_ERROR("No input files specified!\n") PrintUsage(argv[0]); exit(1); } *pFilenameCount=files; // Extract mountpoint if(i==(argc-1)) { XMOUNT_STRSET(*ppMountpoint,argv[argc-1]) opts++; XMOUNT_REALLOC(*pppNargv,char**,opts*sizeof(char*)) XMOUNT_STRSET((*pppNargv)[opts-1],*ppMountpoint) } else { LOG_ERROR("No mountpoint specified!\n") PrintUsage(argv[0]); exit(1); } if(FuseMinusOControl==TRUE) { // We control the -o flag, set subtype, fsname and allow_other options opts+=2; XMOUNT_REALLOC(*pppNargv,char**,opts*sizeof(char*)) XMOUNT_STRSET((*pppNargv)[opts-2],"-o") XMOUNT_STRSET((*pppNargv)[opts-1],"subtype=xmount,fsname=") XMOUNT_STRAPP((*pppNargv)[opts-1],(*pppFilenames)[0]) if(FuseAllowOther==TRUE) { // Try to add "allow_other" to FUSE's cmd-line params if(CheckFuseAllowOther()==TRUE) { XMOUNT_STRAPP((*pppNargv)[opts-1],",allow_other") } } } *pNargc=opts; return TRUE; } /* * ExtractVirtFileNames: * Extract virtual file name from input image name * * Params: * pOrigName: Name of input image (Can include a path) * * Returns: * "TRUE" on success, "FALSE" on error */ static int ExtractVirtFileNames(char *pOrigName) { char *tmp; // Truncate any leading path tmp=strrchr(pOrigName,'/'); if(tmp!=NULL) pOrigName=tmp+1; // Extract file extension tmp=strrchr(pOrigName,'.'); // Set leading '/' - XMOUNT_STRSET(XMountConfData.pVirtualImagePath,"/") - XMOUNT_STRSET(XMountConfData.pVirtualImageInfoPath,"/") - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + XMOUNT_STRSET(glob_xmount_cfg.pVirtualImagePath,"/") + XMOUNT_STRSET(glob_xmount_cfg.pVirtualImageInfoPath,"/") + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - XMOUNT_STRSET(XMountConfData.pVirtualVmdkPath,"/") + XMOUNT_STRSET(glob_xmount_cfg.pVirtualVmdkPath,"/") } // Copy filename if(tmp==NULL) { // Input image filename has no extension - XMOUNT_STRAPP(XMountConfData.pVirtualImagePath,pOrigName) - XMOUNT_STRAPP(XMountConfData.pVirtualImageInfoPath,pOrigName) - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImagePath,pOrigName) + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImageInfoPath,pOrigName) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - XMOUNT_STRAPP(XMountConfData.pVirtualVmdkPath,pOrigName) + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualVmdkPath,pOrigName) } - XMOUNT_STRAPP(XMountConfData.pVirtualImageInfoPath,".info") + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImageInfoPath,".info") } else { - XMOUNT_STRNAPP(XMountConfData.pVirtualImagePath,pOrigName, + XMOUNT_STRNAPP(glob_xmount_cfg.pVirtualImagePath,pOrigName, strlen(pOrigName)-strlen(tmp)) - XMOUNT_STRNAPP(XMountConfData.pVirtualImageInfoPath,pOrigName, + XMOUNT_STRNAPP(glob_xmount_cfg.pVirtualImageInfoPath,pOrigName, strlen(pOrigName)-strlen(tmp)) - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - XMOUNT_STRNAPP(XMountConfData.pVirtualVmdkPath,pOrigName, + XMOUNT_STRNAPP(glob_xmount_cfg.pVirtualVmdkPath,pOrigName, strlen(pOrigName)-strlen(tmp)) } - XMOUNT_STRAPP(XMountConfData.pVirtualImageInfoPath,".info") + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImageInfoPath,".info") } // Add virtual file extensions - switch(XMountConfData.VirtImageType) { - case TVirtImageType_DD: - XMOUNT_STRAPP(XMountConfData.pVirtualImagePath,".dd") + switch(glob_xmount_cfg.VirtImageType) { + case VirtImageType_DD: + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImagePath,".dd") break; - case TVirtImageType_DMG: - XMOUNT_STRAPP(XMountConfData.pVirtualImagePath,".dmg") + case VirtImageType_DMG: + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImagePath,".dmg") break; - case TVirtImageType_VDI: - XMOUNT_STRAPP(XMountConfData.pVirtualImagePath,".vdi") + case VirtImageType_VDI: + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImagePath,".vdi") break; - case TVirtImageType_VHD: - XMOUNT_STRAPP(XMountConfData.pVirtualImagePath,".vhd") + case VirtImageType_VHD: + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImagePath,".vhd") break; - case TVirtImageType_VMDK: - case TVirtImageType_VMDKS: - XMOUNT_STRAPP(XMountConfData.pVirtualImagePath,".dd") - XMOUNT_STRAPP(XMountConfData.pVirtualVmdkPath,".vmdk") + case VirtImageType_VMDK: + case VirtImageType_VMDKS: + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualImagePath,".dd") + XMOUNT_STRAPP(glob_xmount_cfg.pVirtualVmdkPath,".vmdk") break; default: LOG_ERROR("Unknown virtual image type!\n") return FALSE; } LOG_DEBUG("Set virtual image name to \"%s\"\n", - XMountConfData.pVirtualImagePath) + glob_xmount_cfg.pVirtualImagePath) LOG_DEBUG("Set virtual image info name to \"%s\"\n", - XMountConfData.pVirtualImageInfoPath) - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + glob_xmount_cfg.pVirtualImageInfoPath) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { LOG_DEBUG("Set virtual vmdk name to \"%s\"\n", - XMountConfData.pVirtualVmdkPath) + glob_xmount_cfg.pVirtualVmdkPath) } return TRUE; } /* * GetOrigImageSize: * Get size of original image * * Params: * p_size: Pointer to an uint64_t to which the size will be written to + * without_offset: If set to TRUE, returns the real size without substracting + * a given offset. * * Returns: * "TRUE" on success, "FALSE" on error */ -static int GetOrigImageSize(uint64_t *p_size) { +static int GetOrigImageSize(uint64_t *p_size, int without_offset) { // Make sure to return correct values when dealing with only 32bit file sizes *p_size=0; - int rc; // When size was already queryed, use old value rather than regetting value // from disk - if(XMountConfData.OrigImageSize!=0) { - *p_size=XMountConfData.OrigImageSize; + if(glob_xmount_cfg.OrigImageSize!=0 && !without_offset) { + *p_size=glob_xmount_cfg.OrigImageSize; return TRUE; } - // Now get size of original image - switch(XMountConfData.OrigImageType) { - case TOrigImageType_DD: - if((rc=ddSize(hDdFile,(long long unsigned int*)p_size))!=DD_OK) { - LOG_ERROR("Unable to determine DD size using ddSize. Error code %d!\n",rc); - return FALSE; - } -/* - // Original image is a DD file. Seek to end to get size. - if(fseeko(hDdFile,0,SEEK_END)!=0) { - LOG_ERROR("Couldn't seek to end of image file!\n") - return FALSE; - } - *p_size=ftello(hDdFile); -*/ - break; -#ifdef WITH_LIBEWF - case TOrigImageType_EWF: - // Original image is an EWF file. Just query media size. -#if defined( HAVE_LIBEWF_V2_API ) - if(libewf_handle_get_media_size(hEwfFile,p_size,NULL)!=1) -#else - if(libewf_get_media_size(hEwfFile,p_size)!=1) -#endif - { - LOG_ERROR("Couldn't get ewf media size!\n") - return FALSE; - } - break; -#endif -#ifdef WITH_LIBAEWF - case TOrigImageType_AEWF: - if((rc=AewfSize(hAewfFile,(long long unsigned int*)p_size))!=AEWF_OK) { - LOG_ERROR("Couldn't get ewf media size. Error code %d!\n",rc); - return FALSE; - } - break; -#endif -#ifdef WITH_LIBAFF - case TOrigImageType_AFF: - *p_size=af_seek(hAffFile,0,SEEK_END); - break; -#endif -#ifdef WITH_LIBAAFF - case TOrigImageType_AAFF: - if((rc=AaffSize(hAaffFile,(long long unsigned int*)p_size))!=AAFF_OK) { - LOG_ERROR("Unable to determine AFF size using AaffSize. Error code %d!\n",rc); - return FALSE; - } - break; -#endif - default: - LOG_ERROR("Unsupported image type!\n") - return FALSE; + // Get size of original image + if(glob_p_input_functions->Size(glob_p_input_image,p_size)!=0) { + LOG_ERROR("Unable to determine input image size\n"); + return FALSE; } - // Save size so we have not to reget it from disk next time - XMountConfData.OrigImageSize=*p_size; + + if(!without_offset) { + // Substract given offset + (*p_size)-=glob_xmount_cfg.orig_img_offset; + + // Save size so we have not to reget it from disk next time + glob_xmount_cfg.OrigImageSize=*p_size; + } + return TRUE; } /* * GetVirtImageSize: * Get size of the emulated image * * Params: * size: Pointer to an uint64_t to which the size will be written to * * Returns: * "TRUE" on success, "FALSE" on error */ static int GetVirtImageSize(uint64_t *size) { - if(XMountConfData.VirtImageSize!=0) { - *size=XMountConfData.VirtImageSize; + if(glob_xmount_cfg.VirtImageSize!=0) { + *size=glob_xmount_cfg.VirtImageSize; return TRUE; } - switch(XMountConfData.VirtImageType) { - case TVirtImageType_DD: - case TVirtImageType_DMG: - case TVirtImageType_VMDK: - case TVirtImageType_VMDKS: + switch(glob_xmount_cfg.VirtImageType) { + case VirtImageType_DD: + case VirtImageType_DMG: + case VirtImageType_VMDK: + case VirtImageType_VMDKS: // Virtual image is a DD, DMG or VMDK file. Just return the size of the // original image - if(!GetOrigImageSize(size)) { + if(!GetOrigImageSize(size,FALSE)) { LOG_ERROR("Couldn't get size of input image!\n") return FALSE; } break; - case TVirtImageType_VDI: + case VirtImageType_VDI: // Virtual image is a VDI file. Get size of original image and add size // of VDI header etc. - if(!GetOrigImageSize(size)) { + if(!GetOrigImageSize(size,FALSE)) { LOG_ERROR("Couldn't get size of input image!\n") return FALSE; } - (*size)+=(sizeof(TVdiFileHeader)+VdiBlockMapSize); + (*size)+=(sizeof(ts_VdiFileHeader)+glob_p_vdi_block_map_size); break; - case TVirtImageType_VHD: + case VirtImageType_VHD: // Virtual image is a VHD file. Get size of original image and add size // of VHD footer. - if(!GetOrigImageSize(size)) { + if(!GetOrigImageSize(size,FALSE)) { LOG_ERROR("Couldn't get size of input image!\n") return FALSE; } - (*size)+=sizeof(TVhdFileHeader); + (*size)+=sizeof(ts_VhdFileHeader); break; default: LOG_ERROR("Unsupported image type!\n") return FALSE; } - XMountConfData.VirtImageSize=*size; + glob_xmount_cfg.VirtImageSize=*size; return TRUE; } /* * GetOrigImageData: * Read data from original image * * Params: * buf: Pointer to buffer to write read data to (Must be preallocated!) * offset: Offset at which data should be read * size: Size of data which should be read (Size of buffer) * * Returns: * Number of read bytes on success or "-1" on error */ static int GetOrigImageData(char *buf, off_t offset, size_t size) { size_t ToRead=0; uint64_t ImageSize=0; - int rc; + + // Add offset if one was specified + offset+=glob_xmount_cfg.orig_img_offset; // Make sure we aren't reading past EOF of image file - if(!GetOrigImageSize(&ImageSize)) { + if(!GetOrigImageSize(&ImageSize,FALSE)) { LOG_ERROR("Couldn't get image size!\n") return -1; } if(offset>=ImageSize) { // Offset is beyond image size LOG_DEBUG("Offset is beyond image size.\n") return 0; } if(offset+size>ImageSize) { // Attempt to read data past EOF of image file ToRead=ImageSize-offset; LOG_DEBUG("Attempt to read data past EOF. Corrected size from %zd" " to %zd.\n",size,ToRead) } else ToRead=size; - // Now read data from image file - switch(XMountConfData.OrigImageType) { - case TOrigImageType_DD: - // Original image is a DD file. Read ToRead bytes. - if((rc=ddRead(hDdFile,offset,buf,ToRead))!=DD_OK) { - LOG_ERROR("Couldn't read %zd bytes from offset %" PRIu64 - " using ddRead. Error code %d!\n",ToRead,offset,rc); - return -1; - } -/* - // Original image is a DD file. Seek to offset and read ToRead bytes. - // TODO: Perhaps check whether it is cheaper to seek from current position - // to offset than seeking from beginning of the file - if(fseeko(hDdFile,offset,SEEK_SET)!=0) { - LOG_ERROR("Couldn't seek to offset %" PRIu64 "!\n",offset) - return -1; - } - if(fread(buf,ToRead,1,hDdFile)!=1) { - LOG_ERROR("Couldn't read %zd bytes from offset %" PRIu64 - "!\n",ToRead,offset) - return -1; - } -*/ - LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from DD file\n", - ToRead,offset); - break; -#ifdef WITH_LIBEWF - case TOrigImageType_EWF: - // Original image is an EWF file. Seek to offset and read ToRead bytes. -#if defined( HAVE_LIBEWF_V2_API ) - if(libewf_handle_seek_offset(hEwfFile,offset,SEEK_SET,NULL)!=-1) { - if(libewf_handle_read_buffer(hEwfFile,buf,ToRead,NULL)!=ToRead) { -#else - if(libewf_seek_offset(hEwfFile,offset)!=-1) { - if(libewf_read_buffer(hEwfFile,buf,ToRead)!=ToRead) { -#endif - LOG_ERROR("Couldn't read %zd bytes from offset %" PRIu64 - "!\n",ToRead,offset); - return -1; - } - } else { - LOG_ERROR("Couldn't seek to offset %" PRIu64 "!\n",offset); - return -1; - } - LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from EWF file\n", - ToRead,offset); - break; -#endif -#ifdef WITH_LIBAEWF - case TOrigImageType_AEWF: - if((rc=AewfRead(hAewfFile,offset,buf,ToRead))!=AEWF_OK) { - LOG_ERROR("Couldn't read %zd bytes from offset %" PRIu64 - " using AewfRead. Error code %d!\n",ToRead,offset,rc); - return -1; - } - LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from EWF file\n", - ToRead,offset); - break; -#endif -#ifdef WITH_LIBAFF - case TOrigImageType_AFF: - af_seek(hAffFile,offset,SEEK_SET); - if(af_read(hAffFile,buf,ToRead)!=ToRead) { - LOG_ERROR("Couldn't read %zd bytes from offset %" PRIu64 - "!\n",ToRead,offset); - return -1; - } - LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from AFF file\n", - ToRead,offset); - break; -#endif -#ifdef WITH_LIBAAFF - case TOrigImageType_AAFF: - if((rc=AaffRead(hAaffFile,offset,buf,ToRead))!=AAFF_OK) { - LOG_ERROR("Couldn't read %zd bytes from offset %" PRIu64 - " using AaffRead. Error code %d!\n",ToRead,offset,rc); - return -1; - } - LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from AFF file\n", - ToRead,offset); - break; -#endif - default: - LOG_ERROR("Unsupported image type!\n"); - return -1; + // Read data from image file + if(glob_p_input_functions->Read(glob_p_input_image,offset,buf,ToRead)!=0) { + LOG_ERROR("Couldn't read %zd bytes from offset %" PRIu64 "!\n", + ToRead, + offset); + return -1; } + return ToRead; } /* * GetVirtVmdkData: * Read data from virtual VMDK file * * Params: * buf: Pointer to buffer to write read data to (Must be preallocated!) * offset: Offset at which data should be read * size: Size of data which should be read (Size of buffer) * * Returns: * Number of read bytes on success or "-1" on error */ /* static int GetVirtualVmdkData(char *buf, off_t offset, size_t size) { uint32_t len; - len=strlen(pVirtualVmdkFile); + len=strlen(glob_p_vmdk_file); if(offsetlen) { size=len-offset; LOG_DEBUG("Attempt to read past EOF of virtual vmdk file\n") } - if(XMountConfData.Writable==TRUE && - pCacheFileHeader->VmdkFileCached==TRUE) + if(glob_xmount_cfg.Writable==TRUE && + glob_p_cache_header->VmdkFileCached==TRUE) { // VMDK file is cached. Read data from cache file // TODO: Read data from cache file } else { // No write support or VMDK file not cached. - memcpy(buf,pVirtualVmdkFile+offset,size); + memcpy(buf,glob_p_vmdk_file+offset,size); LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 " from virtual vmdk file\n",size,offset) } } else { LOG_DEBUG("Attempt to read past EOF of virtual vmdk file\n"); return -1; } return size; } */ /* * GetVirtImageData: * Read data from virtual image * * Params: * buf: Pointer to buffer to write read data to (Must be preallocated!) * offset: Offset at which data should be read * size: Size of data which should be read (Size of buffer) * * Returns: * Number of read bytes on success or "-1" on error */ static int GetVirtImageData(char *buf, off_t offset, size_t size) { uint32_t CurBlock=0; uint64_t VirtImageSize; uint64_t orig_image_size; size_t ToRead=0; size_t CurToRead=0; off_t FileOff=offset; off_t BlockOff=0; size_t to_read_later=0; // Get virtual image size if(!GetVirtImageSize(&VirtImageSize)) { LOG_ERROR("Couldn't get virtual image size!\n") return -1; } if(offset>=VirtImageSize) { LOG_ERROR("Attempt to read beyond virtual image EOF!\n") return -1; } if(offset+size>VirtImageSize) { LOG_DEBUG("Attempt to read pas EOF of virtual image file\n") size=VirtImageSize-offset; } ToRead=size; - if(!GetOrigImageSize(&orig_image_size)) { + if(!GetOrigImageSize(&orig_image_size,FALSE)) { LOG_ERROR("Couldn't get original image size!") return 0; } // Read virtual image type specific data preceeding original image data - switch(XMountConfData.VirtImageType) { - case TVirtImageType_DD: - case TVirtImageType_DMG: - case TVirtImageType_VMDK: - case TVirtImageType_VMDKS: + switch(glob_xmount_cfg.VirtImageType) { + case VirtImageType_DD: + case VirtImageType_DMG: + case VirtImageType_VMDK: + case VirtImageType_VMDKS: break; - case TVirtImageType_VDI: - if(FileOffVdiFileHeaderSize) CurToRead=VdiFileHeaderSize-FileOff; + case VirtImageType_VDI: + if(FileOffglob_vdi_header_size) CurToRead=glob_vdi_header_size-FileOff; else CurToRead=ToRead; - if(XMountConfData.Writable==TRUE && - pCacheFileHeader->VdiFileHeaderCached==TRUE) + if(glob_xmount_cfg.Writable==TRUE && + glob_p_cache_header->VdiFileHeaderCached==TRUE) { // VDI header was already cached - if(fseeko(hCacheFile, - pCacheFileHeader->pVdiFileHeader+FileOff, + if(fseeko(glob_p_cache_file, + glob_p_cache_header->pVdiFileHeader+FileOff, SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to cached VDI header at offset %" - PRIu64 "\n",pCacheFileHeader->pVdiFileHeader+FileOff) + PRIu64 "\n",glob_p_cache_header->pVdiFileHeader+FileOff) return 0; } - if(fread(buf,CurToRead,1,hCacheFile)!=1) { + if(fread(buf,CurToRead,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't read %zu bytes from cache file at offset %" PRIu64 "\n",CurToRead, - pCacheFileHeader->pVdiFileHeader+FileOff) + glob_p_cache_header->pVdiFileHeader+FileOff) return 0; } LOG_DEBUG("Read %zd bytes from cached VDI header at offset %" PRIu64 " at cache file offset %" PRIu64 "\n", CurToRead,FileOff, - pCacheFileHeader->pVdiFileHeader+FileOff) + glob_p_cache_header->pVdiFileHeader+FileOff) } else { // VDI header isn't cached - memcpy(buf,((char*)pVdiFileHeader)+FileOff,CurToRead); + memcpy(buf,((char*)glob_p_vdi_header)+FileOff,CurToRead); LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from virtual VDI header\n",CurToRead, FileOff) } if(ToRead==CurToRead) return ToRead; else { // Adjust values to read from original image ToRead-=CurToRead; buf+=CurToRead; FileOff=0; } - } else FileOff-=VdiFileHeaderSize; + } else FileOff-=glob_vdi_header_size; break; - case TVirtImageType_VHD: + case VirtImageType_VHD: // When emulating VHD, make sure the while loop below only reads data // available in the original image. Any VHD footer data must be read // afterwards. if(FileOff>=orig_image_size) { to_read_later=ToRead; ToRead=0; } else if((FileOff+ToRead)>orig_image_size) { to_read_later=(FileOff+ToRead)-orig_image_size; ToRead-=to_read_later; } break; } // Calculate block to read data from CurBlock=FileOff/CACHE_BLOCK_SIZE; BlockOff=FileOff%CACHE_BLOCK_SIZE; // Read image data while(ToRead!=0) { // Calculate how many bytes we have to read from this block if(BlockOff+ToRead>CACHE_BLOCK_SIZE) { CurToRead=CACHE_BLOCK_SIZE-BlockOff; } else CurToRead=ToRead; - if(XMountConfData.Writable==TRUE && - pCacheFileBlockIndex[CurBlock].Assigned==TRUE) + if(glob_xmount_cfg.Writable==TRUE && + glob_p_cache_blkidx[CurBlock].Assigned==TRUE) { // Write support enabled and need to read altered data from cachefile - if(fseeko(hCacheFile, - pCacheFileBlockIndex[CurBlock].off_data+BlockOff, + if(fseeko(glob_p_cache_file, + glob_p_cache_blkidx[CurBlock].off_data+BlockOff, SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to offset %" PRIu64 " in cache file\n") return -1; } - if(fread(buf,CurToRead,1,hCacheFile)!=1) { + if(fread(buf,CurToRead,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't read data from cache file!\n") return -1; } LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from cache file\n",CurToRead,FileOff) } else { // No write support or data not cached if(GetOrigImageData(buf, FileOff, CurToRead)!=CurToRead) { LOG_ERROR("Couldn't read data from input image!\n") return -1; } LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from original image file\n",CurToRead, FileOff) } CurBlock++; BlockOff=0; buf+=CurToRead; ToRead-=CurToRead; FileOff+=CurToRead; } if(to_read_later!=0) { // Read virtual image type specific data following original image data - switch(XMountConfData.VirtImageType) { - case TVirtImageType_DD: - case TVirtImageType_DMG: - case TVirtImageType_VMDK: - case TVirtImageType_VMDKS: - case TVirtImageType_VDI: + switch(glob_xmount_cfg.VirtImageType) { + case VirtImageType_DD: + case VirtImageType_DMG: + case VirtImageType_VMDK: + case VirtImageType_VMDKS: + case VirtImageType_VDI: break; - case TVirtImageType_VHD: + case VirtImageType_VHD: // Micro$oft has choosen to use a footer rather then a header. - if(XMountConfData.Writable==TRUE && - pCacheFileHeader->VhdFileHeaderCached==TRUE) + if(glob_xmount_cfg.Writable==TRUE && + glob_p_cache_header->VhdFileHeaderCached==TRUE) { // VHD footer was already cached - if(fseeko(hCacheFile, - pCacheFileHeader->pVhdFileHeader+(FileOff-orig_image_size), + if(fseeko(glob_p_cache_file, + glob_p_cache_header->pVhdFileHeader+(FileOff-orig_image_size), SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to cached VHD footer at offset %" PRIu64 "\n", - pCacheFileHeader->pVhdFileHeader+ + glob_p_cache_header->pVhdFileHeader+ (FileOff-orig_image_size)) return 0; } - if(fread(buf,to_read_later,1,hCacheFile)!=1) { + if(fread(buf,to_read_later,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't read %zu bytes from cache file at offset %" PRIu64 "\n",to_read_later, - pCacheFileHeader->pVhdFileHeader+ + glob_p_cache_header->pVhdFileHeader+ (FileOff-orig_image_size)) return 0; } LOG_DEBUG("Read %zd bytes from cached VHD footer at offset %" PRIu64 " at cache file offset %" PRIu64 "\n", to_read_later,(FileOff-orig_image_size), - pCacheFileHeader->pVhdFileHeader+(FileOff-orig_image_size)) + glob_p_cache_header->pVhdFileHeader+(FileOff-orig_image_size)) } else { // VHD header isn't cached memcpy(buf, - ((char*)pVhdFileHeader)+(FileOff-orig_image_size), + ((char*)glob_p_vhd_header)+(FileOff-orig_image_size), to_read_later); LOG_DEBUG("Read %zd bytes at offset %" PRIu64 " from virtual VHD header\n", to_read_later, (FileOff-orig_image_size)) } break; } } return size; } /* * SetVdiFileHeaderData: * Write data to virtual VDI file header * * Params: * buf: Buffer containing data to write * offset: Offset of changes * size: Amount of bytes to write * * Returns: * Number of written bytes on success or "-1" on error */ static int SetVdiFileHeaderData(char *buf,off_t offset,size_t size) { - if(offset+size>VdiFileHeaderSize) size=VdiFileHeaderSize-offset; + if(offset+size>glob_vdi_header_size) size=glob_vdi_header_size-offset; LOG_DEBUG("Need to cache %zu bytes at offset %" PRIu64 " from VDI header\n",size,offset) - if(pCacheFileHeader->VdiFileHeaderCached==1) { + if(glob_p_cache_header->VdiFileHeaderCached==1) { // Header was already cached - if(fseeko(hCacheFile, - pCacheFileHeader->pVdiFileHeader+offset, + if(fseeko(glob_p_cache_file, + glob_p_cache_header->pVdiFileHeader+offset, SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to cached VDI header at address %" - PRIu64 "\n",pCacheFileHeader->pVdiFileHeader+offset) + PRIu64 "\n",glob_p_cache_header->pVdiFileHeader+offset) return -1; } - if(fwrite(buf,size,1,hCacheFile)!=1) { + if(fwrite(buf,size,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write %zu bytes to cache file at offset %" PRIu64 "\n",size, - pCacheFileHeader->pVdiFileHeader+offset) + glob_p_cache_header->pVdiFileHeader+offset) return -1; } LOG_DEBUG("Wrote %zd bytes at offset %" PRIu64 " to cache file\n", - size,pCacheFileHeader->pVdiFileHeader+offset) + size,glob_p_cache_header->pVdiFileHeader+offset) } else { // Header wasn't already cached. - if(fseeko(hCacheFile, + if(fseeko(glob_p_cache_file, 0, SEEK_END)!=0) { LOG_ERROR("Couldn't seek to end of cache file!") return -1; } - pCacheFileHeader->pVdiFileHeader=ftello(hCacheFile); + glob_p_cache_header->pVdiFileHeader=ftello(glob_p_cache_file); LOG_DEBUG("Caching whole VDI header\n") if(offset>0) { // Changes do not begin at offset 0, need to prepend with data from // VDI header - if(fwrite((char*)pVdiFileHeader,offset,1,hCacheFile)!=1) { + if(fwrite((char*)glob_p_vdi_header,offset,1,glob_p_cache_file)!=1) { LOG_ERROR("Error while writing %" PRIu64 " bytes " "to cache file at offset %" PRIu64 "!\n", offset, - pCacheFileHeader->pVdiFileHeader); + glob_p_cache_header->pVdiFileHeader); return -1; } LOG_DEBUG("Prepended changed data with %" PRIu64 " bytes at cache file offset %" PRIu64 "\n", - offset,pCacheFileHeader->pVdiFileHeader) + offset,glob_p_cache_header->pVdiFileHeader) } // Cache changed data - if(fwrite(buf,size,1,hCacheFile)!=1) { + if(fwrite(buf,size,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write %zu bytes to cache file at offset %" PRIu64 "\n",size, - pCacheFileHeader->pVdiFileHeader+offset) + glob_p_cache_header->pVdiFileHeader+offset) return -1; } LOG_DEBUG("Wrote %zu bytes of changed data to cache file offset %" PRIu64 "\n",size, - pCacheFileHeader->pVdiFileHeader+offset) - if(offset+size!=VdiFileHeaderSize) { + glob_p_cache_header->pVdiFileHeader+offset) + if(offset+size!=glob_vdi_header_size) { // Need to append data from VDI header to cache whole data struct - if(fwrite(((char*)pVdiFileHeader)+offset+size, - VdiFileHeaderSize-(offset+size), + if(fwrite(((char*)glob_p_vdi_header)+offset+size, + glob_vdi_header_size-(offset+size), 1, - hCacheFile)!=1) + glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write %zu bytes to cache file at offset %" - PRIu64 "\n",VdiFileHeaderSize-(offset+size), - (uint64_t)(pCacheFileHeader->pVdiFileHeader+offset+size)) + PRIu64 "\n",glob_vdi_header_size-(offset+size), + (uint64_t)(glob_p_cache_header->pVdiFileHeader+offset+size)) return -1; } LOG_DEBUG("Appended %" PRIu32 " bytes to changed data at cache file offset %" - PRIu64 "\n",VdiFileHeaderSize-(offset+size), - pCacheFileHeader->pVdiFileHeader+offset+size) + PRIu64 "\n",glob_vdi_header_size-(offset+size), + glob_p_cache_header->pVdiFileHeader+offset+size) } // Mark header as cached and update header in cache file - pCacheFileHeader->VdiFileHeaderCached=1; - if(fseeko(hCacheFile,0,SEEK_SET)!=0) { + glob_p_cache_header->VdiFileHeaderCached=1; + if(fseeko(glob_p_cache_file,0,SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to offset 0 of cache file!\n") return -1; } - if(fwrite((char*)pCacheFileHeader,sizeof(TCacheFileHeader),1,hCacheFile)!=1) { + if(fwrite((char*)glob_p_cache_header,sizeof(ts_CacheFileHeader),1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write changed cache file header!\n") return -1; } } // All important data has been written, now flush all buffers to make // sure data is written to cache file - fflush(hCacheFile); + fflush(glob_p_cache_file); #ifndef __APPLE__ - ioctl(fileno(hCacheFile),BLKFLSBUF,0); + ioctl(fileno(glob_p_cache_file),BLKFLSBUF,0); #endif return size; } /* * SetVhdFileHeaderData: * Write data to virtual VHD file footer * * Params: * buf: Buffer containing data to write * offset: Offset of changes * size: Amount of bytes to write * * Returns: * Number of written bytes on success or "-1" on error */ static int SetVhdFileHeaderData(char *buf,off_t offset,size_t size) { LOG_DEBUG("Need to cache %zu bytes at offset %" PRIu64 " from VHD footer\n",size,offset) - if(pCacheFileHeader->VhdFileHeaderCached==1) { + if(glob_p_cache_header->VhdFileHeaderCached==1) { // Header has already been cached - if(fseeko(hCacheFile, - pCacheFileHeader->pVhdFileHeader+offset, + if(fseeko(glob_p_cache_file, + glob_p_cache_header->pVhdFileHeader+offset, SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to cached VHD header at address %" - PRIu64 "\n",pCacheFileHeader->pVhdFileHeader+offset) + PRIu64 "\n",glob_p_cache_header->pVhdFileHeader+offset) return -1; } - if(fwrite(buf,size,1,hCacheFile)!=1) { + if(fwrite(buf,size,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write %zu bytes to cache file at offset %" PRIu64 "\n",size, - pCacheFileHeader->pVhdFileHeader+offset) + glob_p_cache_header->pVhdFileHeader+offset) return -1; } LOG_DEBUG("Wrote %zd bytes at offset %" PRIu64 " to cache file\n", - size,pCacheFileHeader->pVhdFileHeader+offset) + size,glob_p_cache_header->pVhdFileHeader+offset) } else { // Header hasn't been cached yet. - if(fseeko(hCacheFile, + if(fseeko(glob_p_cache_file, 0, SEEK_END)!=0) { LOG_ERROR("Couldn't seek to end of cache file!") return -1; } - pCacheFileHeader->pVhdFileHeader=ftello(hCacheFile); + glob_p_cache_header->pVhdFileHeader=ftello(glob_p_cache_file); LOG_DEBUG("Caching whole VHD header\n") if(offset>0) { // Changes do not begin at offset 0, need to prepend with data from // VHD header - if(fwrite((char*)pVhdFileHeader,offset,1,hCacheFile)!=1) { + if(fwrite((char*)glob_p_vhd_header,offset,1,glob_p_cache_file)!=1) { LOG_ERROR("Error while writing %" PRIu64 " bytes " "to cache file at offset %" PRIu64 "!\n", offset, - pCacheFileHeader->pVhdFileHeader); + glob_p_cache_header->pVhdFileHeader); return -1; } LOG_DEBUG("Prepended changed data with %" PRIu64 " bytes at cache file offset %" PRIu64 "\n", - offset,pCacheFileHeader->pVhdFileHeader) + offset,glob_p_cache_header->pVhdFileHeader) } // Cache changed data - if(fwrite(buf,size,1,hCacheFile)!=1) { + if(fwrite(buf,size,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write %zu bytes to cache file at offset %" PRIu64 "\n",size, - pCacheFileHeader->pVhdFileHeader+offset) + glob_p_cache_header->pVhdFileHeader+offset) return -1; } LOG_DEBUG("Wrote %zu bytes of changed data to cache file offset %" PRIu64 "\n",size, - pCacheFileHeader->pVhdFileHeader+offset) - if(offset+size!=sizeof(TVhdFileHeader)) { + glob_p_cache_header->pVhdFileHeader+offset) + if(offset+size!=sizeof(ts_VhdFileHeader)) { // Need to append data from VHD header to cache whole data struct - if(fwrite(((char*)pVhdFileHeader)+offset+size, - sizeof(TVhdFileHeader)-(offset+size), + if(fwrite(((char*)glob_p_vhd_header)+offset+size, + sizeof(ts_VhdFileHeader)-(offset+size), 1, - hCacheFile)!=1) + glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write %zu bytes to cache file at offset %" - PRIu64 "\n",sizeof(TVhdFileHeader)-(offset+size), - (uint64_t)(pCacheFileHeader->pVhdFileHeader+offset+size)) + PRIu64 "\n",sizeof(ts_VhdFileHeader)-(offset+size), + (uint64_t)(glob_p_cache_header->pVhdFileHeader+offset+size)) return -1; } LOG_DEBUG("Appended %" PRIu32 " bytes to changed data at cache file offset %" - PRIu64 "\n",sizeof(TVhdFileHeader)-(offset+size), - pCacheFileHeader->pVhdFileHeader+offset+size) + PRIu64 "\n",sizeof(ts_VhdFileHeader)-(offset+size), + glob_p_cache_header->pVhdFileHeader+offset+size) } // Mark header as cached and update header in cache file - pCacheFileHeader->VhdFileHeaderCached=1; - if(fseeko(hCacheFile,0,SEEK_SET)!=0) { + glob_p_cache_header->VhdFileHeaderCached=1; + if(fseeko(glob_p_cache_file,0,SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to offset 0 of cache file!\n") return -1; } - if(fwrite((char*)pCacheFileHeader,sizeof(TCacheFileHeader),1,hCacheFile)!=1) { + if(fwrite((char*)glob_p_cache_header,sizeof(ts_CacheFileHeader),1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't write changed cache file header!\n") return -1; } } // All important data has been written, now flush all buffers to make // sure data is written to cache file - fflush(hCacheFile); + fflush(glob_p_cache_file); #ifndef __APPLE__ - ioctl(fileno(hCacheFile),BLKFLSBUF,0); + ioctl(fileno(glob_p_cache_file),BLKFLSBUF,0); #endif return size; } /* * SetVirtImageData: * Write data to virtual image * * Params: * buf: Buffer containing data to write * offset: Offset to start writing at * size: Size of data to be written * * Returns: * Number of written bytes on success or "-1" on error */ static int SetVirtImageData(const char *buf, off_t offset, size_t size) { uint64_t CurBlock=0; uint64_t VirtImageSize; uint64_t OrigImageSize; size_t ToWrite=0; size_t to_write_later=0; size_t CurToWrite=0; off_t FileOff=offset; off_t BlockOff=0; char *WriteBuf=(char*)buf; char *buf2; ssize_t ret; // Get virtual image size if(!GetVirtImageSize(&VirtImageSize)) { LOG_ERROR("Couldn't get virtual image size!\n") return -1; } if(offset>=VirtImageSize) { LOG_ERROR("Attempt to write beyond EOF of virtual image file!\n") return -1; } if(offset+size>VirtImageSize) { LOG_DEBUG("Attempt to write past EOF of virtual image file\n") size=VirtImageSize-offset; } ToWrite=size; // Get original image size - if(!GetOrigImageSize(&OrigImageSize)) { + if(!GetOrigImageSize(&OrigImageSize,FALSE)) { LOG_ERROR("Couldn't get original image size!\n") return -1; } // Cache virtual image type specific data preceeding original image data - switch(XMountConfData.VirtImageType) { - case TVirtImageType_DD: - case TVirtImageType_DMG: - case TVirtImageType_VMDK: - case TVirtImageType_VMDKS: + switch(glob_xmount_cfg.VirtImageType) { + case VirtImageType_DD: + case VirtImageType_DMG: + case VirtImageType_VMDK: + case VirtImageType_VMDKS: break; - case TVirtImageType_VDI: - if(FileOff=OrigImageSize) { to_write_later=ToWrite; ToWrite=0; } else if((FileOff+ToWrite)>OrigImageSize) { to_write_later=(FileOff+ToWrite)-OrigImageSize; ToWrite-=to_write_later; } break; } // Calculate block to write data to CurBlock=FileOff/CACHE_BLOCK_SIZE; BlockOff=FileOff%CACHE_BLOCK_SIZE; while(ToWrite!=0) { // Calculate how many bytes we have to write to this block if(BlockOff+ToWrite>CACHE_BLOCK_SIZE) { CurToWrite=CACHE_BLOCK_SIZE-BlockOff; } else CurToWrite=ToWrite; - if(pCacheFileBlockIndex[CurBlock].Assigned==1) { + if(glob_p_cache_blkidx[CurBlock].Assigned==1) { // Block was already cached // Seek to data offset in cache file - if(fseeko(hCacheFile, - pCacheFileBlockIndex[CurBlock].off_data+BlockOff, + if(fseeko(glob_p_cache_file, + glob_p_cache_blkidx[CurBlock].off_data+BlockOff, SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to cached block at address %" PRIu64 "\n", - pCacheFileBlockIndex[CurBlock].off_data+BlockOff) + glob_p_cache_blkidx[CurBlock].off_data+BlockOff) return -1; } - if(fwrite(WriteBuf,CurToWrite,1,hCacheFile)!=1) { + if(fwrite(WriteBuf,CurToWrite,1,glob_p_cache_file)!=1) { LOG_ERROR("Error while writing %zu bytes " "to cache file at offset %" PRIu64 "!\n", CurToWrite, - pCacheFileBlockIndex[CurBlock].off_data+BlockOff); + glob_p_cache_blkidx[CurBlock].off_data+BlockOff); return -1; } LOG_DEBUG("Wrote %zd bytes at offset %" PRIu64 " to cache file\n",CurToWrite, - pCacheFileBlockIndex[CurBlock].off_data+BlockOff) + glob_p_cache_blkidx[CurBlock].off_data+BlockOff) } else { // Uncached block. Need to cache entire new block // Seek to end of cache file to append new cache block - fseeko(hCacheFile,0,SEEK_END); - pCacheFileBlockIndex[CurBlock].off_data=ftello(hCacheFile); + fseeko(glob_p_cache_file,0,SEEK_END); + glob_p_cache_blkidx[CurBlock].off_data=ftello(glob_p_cache_file); if(BlockOff!=0) { // Changed data does not begin at block boundry. Need to prepend // with data from virtual image file XMOUNT_MALLOC(buf2,char*,BlockOff*sizeof(char)) if(GetOrigImageData(buf2,FileOff-BlockOff,BlockOff)!=BlockOff) { LOG_ERROR("Couldn't read data from original image file!\n") return -1; } - if(fwrite(buf2,BlockOff,1,hCacheFile)!=1) { + if(fwrite(buf2,BlockOff,1,glob_p_cache_file)!=1) { LOG_ERROR("Couldn't writing %" PRIu64 " bytes " "to cache file at offset %" PRIu64 "!\n", BlockOff, - pCacheFileBlockIndex[CurBlock].off_data); + glob_p_cache_blkidx[CurBlock].off_data); return -1; } LOG_DEBUG("Prepended changed data with %" PRIu64 " bytes from virtual image file at offset %" PRIu64 "\n",BlockOff,FileOff-BlockOff) free(buf2); } - if(fwrite(WriteBuf,CurToWrite,1,hCacheFile)!=1) { + if(fwrite(WriteBuf,CurToWrite,1,glob_p_cache_file)!=1) { LOG_ERROR("Error while writing %zd bytes " "to cache file at offset %" PRIu64 "!\n", CurToWrite, - pCacheFileBlockIndex[CurBlock].off_data+BlockOff); + glob_p_cache_blkidx[CurBlock].off_data+BlockOff); return -1; } if(BlockOff+CurToWrite!=CACHE_BLOCK_SIZE) { // Changed data does not end at block boundry. Need to append // with data from virtual image file XMOUNT_MALLOC(buf2,char*,(CACHE_BLOCK_SIZE- (BlockOff+CurToWrite))*sizeof(char)) memset(buf2,0,CACHE_BLOCK_SIZE-(BlockOff+CurToWrite)); if((FileOff-BlockOff)+CACHE_BLOCK_SIZE>OrigImageSize) { // Original image is smaller than full cache block if(GetOrigImageData(buf2, FileOff+CurToWrite, OrigImageSize-(FileOff+CurToWrite))!= OrigImageSize-(FileOff+CurToWrite)) { LOG_ERROR("Couldn't read data from virtual image file!\n") return -1; } } else { if(GetOrigImageData(buf2, FileOff+CurToWrite, CACHE_BLOCK_SIZE-(BlockOff+CurToWrite))!= CACHE_BLOCK_SIZE-(BlockOff+CurToWrite)) { LOG_ERROR("Couldn't read data from virtual image file!\n") return -1; } } if(fwrite(buf2, CACHE_BLOCK_SIZE-(BlockOff+CurToWrite), 1, - hCacheFile)!=1) + glob_p_cache_file)!=1) { LOG_ERROR("Error while writing %zd bytes " "to cache file at offset %" PRIu64 "!\n", CACHE_BLOCK_SIZE-(BlockOff+CurToWrite), - pCacheFileBlockIndex[CurBlock].off_data+ + glob_p_cache_blkidx[CurBlock].off_data+ BlockOff+CurToWrite); return -1; } free(buf2); } // All important data for this cache block has been written, // flush all buffers and mark cache block as assigned - fflush(hCacheFile); + fflush(glob_p_cache_file); #ifndef __APPLE__ - ioctl(fileno(hCacheFile),BLKFLSBUF,0); + ioctl(fileno(glob_p_cache_file),BLKFLSBUF,0); #endif - pCacheFileBlockIndex[CurBlock].Assigned=1; + glob_p_cache_blkidx[CurBlock].Assigned=1; // Update cache block index entry in cache file - fseeko(hCacheFile, - sizeof(TCacheFileHeader)+(CurBlock*sizeof(TCacheFileBlockIndex)), + fseeko(glob_p_cache_file, + sizeof(ts_CacheFileHeader)+(CurBlock*sizeof(ts_CacheFileBlockIndex)), SEEK_SET); - if(fwrite(&(pCacheFileBlockIndex[CurBlock]), - sizeof(TCacheFileBlockIndex), + if(fwrite(&(glob_p_cache_blkidx[CurBlock]), + sizeof(ts_CacheFileBlockIndex), 1, - hCacheFile)!=1) + glob_p_cache_file)!=1) { LOG_ERROR("Couldn't update cache file block index!\n"); return -1; } LOG_DEBUG("Updated cache file block index: Number=%" PRIu64 ", Data offset=%" PRIu64 "\n",CurBlock, - pCacheFileBlockIndex[CurBlock].off_data); + glob_p_cache_blkidx[CurBlock].off_data); } // Flush buffers - fflush(hCacheFile); + fflush(glob_p_cache_file); #ifndef __APPLE__ - ioctl(fileno(hCacheFile),BLKFLSBUF,0); + ioctl(fileno(glob_p_cache_file),BLKFLSBUF,0); #endif BlockOff=0; CurBlock++; WriteBuf+=CurToWrite; ToWrite-=CurToWrite; FileOff+=CurToWrite; } if(to_write_later!=0) { // Cache virtual image type specific data preceeding original image data - switch(XMountConfData.VirtImageType) { - case TVirtImageType_DD: - case TVirtImageType_DMG: - case TVirtImageType_VMDK: - case TVirtImageType_VMDKS: - case TVirtImageType_VDI: + switch(glob_xmount_cfg.VirtImageType) { + case VirtImageType_DD: + case VirtImageType_DMG: + case VirtImageType_VMDK: + case VirtImageType_VMDKS: + case VirtImageType_VDI: break; - case TVirtImageType_VHD: + case VirtImageType_VHD: // Micro$oft has choosen to use a footer rather then a header. ret=SetVhdFileHeaderData(WriteBuf,FileOff-OrigImageSize,to_write_later); if(ret==-1) { LOG_ERROR("Couldn't write data to virtual VHD file footer!\n") return -1; } break; } } return size; } /* * GetVirtFileAccess: * FUSE access implementation * * Params: * path: Path of file to get attributes from * perm: Requested permissisons * * Returns: * "0" on success, negated error code on error */ /* static int GetVirtFileAccess(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. return 0; } */ /* * GetVirtFileAttr: * FUSE getattr implementation * * Params: * path: Path of file to get attributes from * stbuf: Pointer to stat structure to save attributes to * * Returns: * "0" on success, negated error code on error */ static int GetVirtFileAttr(const char *path, struct stat *stbuf) { memset(stbuf,0,sizeof(struct stat)); if(strcmp(path,"/")==0) { // Attributes of mountpoint stbuf->st_mode=S_IFDIR | 0777; stbuf->st_nlink=2; - } else if(strcmp(path,XMountConfData.pVirtualImagePath)==0) { + } else if(strcmp(path,glob_xmount_cfg.pVirtualImagePath)==0) { // Attributes of virtual image - if(!XMountConfData.Writable) stbuf->st_mode=S_IFREG | 0444; + if(!glob_xmount_cfg.Writable) stbuf->st_mode=S_IFREG | 0444; else stbuf->st_mode=S_IFREG | 0666; stbuf->st_nlink=1; // Get virtual image file size - if(!GetVirtImageSize(&(stbuf->st_size))) { + if(!GetVirtImageSize((uint64_t*)&(stbuf->st_size))) { LOG_ERROR("Couldn't get image size!\n"); return -ENOENT; } - if(XMountConfData.VirtImageType==TVirtImageType_VHD) { + if(glob_xmount_cfg.VirtImageType==VirtImageType_VHD) { // Make sure virtual image seems to be fully allocated (not sparse file). // Without this, Windows won't attach the vhd file! stbuf->st_blocks=stbuf->st_size/512; if(stbuf->st_size%512!=0) stbuf->st_blocks++; } - } else if(strcmp(path,XMountConfData.pVirtualImageInfoPath)==0) { + } else if(strcmp(path,glob_xmount_cfg.pVirtualImageInfoPath)==0) { // Attributes of virtual image info file stbuf->st_mode=S_IFREG | 0444; stbuf->st_nlink=1; // Get virtual image info file size - if(pVirtualImageInfoFile!=NULL) { - stbuf->st_size=strlen(pVirtualImageInfoFile); + if(glob_p_info_file!=NULL) { + stbuf->st_size=strlen(glob_p_info_file); } else stbuf->st_size=0; - } else if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + } else if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { // Some special files only present when emulating VMDK files - if(strcmp(path,XMountConfData.pVirtualVmdkPath)==0) { + if(strcmp(path,glob_xmount_cfg.pVirtualVmdkPath)==0) { // Attributes of virtual vmdk file - if(!XMountConfData.Writable) stbuf->st_mode=S_IFREG | 0444; + if(!glob_xmount_cfg.Writable) stbuf->st_mode=S_IFREG | 0444; else stbuf->st_mode=S_IFREG | 0666; stbuf->st_nlink=1; // Get virtual image info file size - if(pVirtualVmdkFile!=NULL) { - stbuf->st_size=VirtualVmdkFileSize; + if(glob_p_vmdk_file!=NULL) { + stbuf->st_size=glob_vmdk_file_size; } else stbuf->st_size=0; - } else if(pVirtualVmdkLockDir!=NULL && - strcmp(path,pVirtualVmdkLockDir)==0) + } else if(glob_p_vmdk_lockdir1!=NULL && + strcmp(path,glob_p_vmdk_lockdir1)==0) { stbuf->st_mode=S_IFDIR | 0777; stbuf->st_nlink=2; - } else if(pVirtualVmdkLockDir2!=NULL && - strcmp(path,pVirtualVmdkLockDir2)==0) + } else if(glob_p_vmdk_lockdir2!=NULL && + strcmp(path,glob_p_vmdk_lockdir2)==0) { stbuf->st_mode=S_IFDIR | 0777; stbuf->st_nlink=2; - } else if(pVirtualVmdkLockFileName!=NULL && - strcmp(path,pVirtualVmdkLockFileName)==0) + } else if(glob_p_vmdk_lockfile_name!=NULL && + strcmp(path,glob_p_vmdk_lockfile_name)==0) { stbuf->st_mode=S_IFREG | 0666; - if(pVirtualVmdkLockFileName!=NULL) { - stbuf->st_size=strlen(pVirtualVmdkLockFileName); + if(glob_p_vmdk_lockfile_name!=NULL) { + stbuf->st_size=strlen(glob_p_vmdk_lockfile_name); } else stbuf->st_size=0; } else return -ENOENT; } else return -ENOENT; // Set uid and gid of all files to uid and gid of current process stbuf->st_uid=getuid(); stbuf->st_gid=getgid(); return 0; } /* * CreateVirtDir: * FUSE mkdir implementation * * Params: * path: Directory path * mode: Directory permissions * * Returns: * "0" on success, negated error code on error */ static int CreateVirtDir(const char *path, mode_t mode) { // Only allow creation of VMWare's lock directories - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - if(pVirtualVmdkLockDir==NULL) { - char aVmdkLockDir[strlen(XMountConfData.pVirtualVmdkPath)+5]; - sprintf(aVmdkLockDir,"%s.lck",XMountConfData.pVirtualVmdkPath); + if(glob_p_vmdk_lockdir1==NULL) { + char aVmdkLockDir[strlen(glob_xmount_cfg.pVirtualVmdkPath)+5]; + sprintf(aVmdkLockDir,"%s.lck",glob_xmount_cfg.pVirtualVmdkPath); if(strcmp(path,aVmdkLockDir)==0) { LOG_DEBUG("Creating virtual directory \"%s\"\n",aVmdkLockDir) - XMOUNT_STRSET(pVirtualVmdkLockDir,aVmdkLockDir) + XMOUNT_STRSET(glob_p_vmdk_lockdir1,aVmdkLockDir) return 0; } else { LOG_ERROR("Attempt to create illegal directory \"%s\"!\n",path) LOG_DEBUG("Supposed: %s\n",aVmdkLockDir) return -1; } - } else if(pVirtualVmdkLockDir2==NULL && - strncmp(path,pVirtualVmdkLockDir,strlen(pVirtualVmdkLockDir))==0) + } else if(glob_p_vmdk_lockdir2==NULL && + strncmp(path,glob_p_vmdk_lockdir1,strlen(glob_p_vmdk_lockdir1))==0) { LOG_DEBUG("Creating virtual directory \"%s\"\n",path) - XMOUNT_STRSET(pVirtualVmdkLockDir2,path) + XMOUNT_STRSET(glob_p_vmdk_lockdir2,path) return 0; } else { LOG_ERROR("Attempt to create illegal directory \"%s\"!\n",path) - LOG_DEBUG("Compared to first %u chars of \"%s\"\n",strlen(pVirtualVmdkLockDir),pVirtualVmdkLockDir) + LOG_DEBUG("Compared to first %u chars of \"%s\"\n",strlen(glob_p_vmdk_lockdir1),glob_p_vmdk_lockdir1) return -1; } } LOG_ERROR("Attempt to create directory \"%s\" " "on read-only filesystem!\n",path) return -1; } /* * CreateVirtFile: * FUSE create implementation. * Only allows to create VMWare's lock file! * * Params: * path: File to create * mode: File mode * dev: ??? but not used * * Returns: * "0" on success, negated error code on error */ static int CreateVirtFile(const char *path, mode_t mode, dev_t dev) { - if((XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) && - pVirtualVmdkLockDir!=NULL && pVirtualVmdkLockFileName==NULL) + if((glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) && + glob_p_vmdk_lockdir1!=NULL && glob_p_vmdk_lockfile_name==NULL) { LOG_DEBUG("Creating virtual file \"%s\"\n",path) - XMOUNT_STRSET(pVirtualVmdkLockFileName,path); + XMOUNT_STRSET(glob_p_vmdk_lockfile_name,path); return 0; } else { LOG_ERROR("Attempt to create illegal file \"%s\"\n",path) return -1; } } /* * GetVirtFiles: * FUSE readdir implementation * * Params: * path: Path from where files should be listed * buf: Buffer to write file entrys to * filler: Function to write file entrys to buffer * offset: ??? but not used * fi: ??? but not used * * Returns: * "0" on success, negated error code on error */ static int GetVirtFiles(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { (void)offset; (void)fi; if(strcmp(path,"/")==0) { // Add std . and .. entrys filler(buf,".",NULL,0); filler(buf,"..",NULL,0); // Add our virtual files (p+1 to ignore starting "/") - filler(buf,XMountConfData.pVirtualImagePath+1,NULL,0); - filler(buf,XMountConfData.pVirtualImageInfoPath+1,NULL,0); - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + filler(buf,glob_xmount_cfg.pVirtualImagePath+1,NULL,0); + filler(buf,glob_xmount_cfg.pVirtualImageInfoPath+1,NULL,0); + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { // For VMDK's, we use an additional descriptor file - filler(buf,XMountConfData.pVirtualVmdkPath+1,NULL,0); + filler(buf,glob_xmount_cfg.pVirtualVmdkPath+1,NULL,0); // And there could also be a lock directory - if(pVirtualVmdkLockDir!=NULL) { - filler(buf,pVirtualVmdkLockDir+1,NULL,0); + if(glob_p_vmdk_lockdir1!=NULL) { + filler(buf,glob_p_vmdk_lockdir1+1,NULL,0); } } - } else if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + } else if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { // For VMDK emulation, there could be a lock directory - if(pVirtualVmdkLockDir!=NULL && strcmp(path,pVirtualVmdkLockDir)==0) { + if(glob_p_vmdk_lockdir1!=NULL && strcmp(path,glob_p_vmdk_lockdir1)==0) { filler(buf,".",NULL,0); filler(buf,"..",NULL,0); - if(pVirtualVmdkLockFileName!=NULL) { - filler(buf,pVirtualVmdkLockFileName+strlen(pVirtualVmdkLockDir)+1,NULL,0); + if(glob_p_vmdk_lockfile_name!=NULL) { + filler(buf,glob_p_vmdk_lockfile_name+strlen(glob_p_vmdk_lockdir1)+1,NULL,0); } - } else if(pVirtualVmdkLockDir2!=NULL && - strcmp(path,pVirtualVmdkLockDir2)==0) + } else if(glob_p_vmdk_lockdir2!=NULL && + strcmp(path,glob_p_vmdk_lockdir2)==0) { filler(buf,".",NULL,0); filler(buf,"..",NULL,0); } else return -ENOENT; } else return -ENOENT; return 0; } /* * OpenVirtFile: * FUSE open implementation * * Params: * path: Path to file to open * fi: ??? but not used * * Returns: * "0" on success, negated error code on error */ static int OpenVirtFile(const char *path, struct fuse_file_info *fi) { - if(strcmp(path,XMountConfData.pVirtualImagePath)==0 || - strcmp(path,XMountConfData.pVirtualImageInfoPath)==0) + if(strcmp(path,glob_xmount_cfg.pVirtualImagePath)==0 || + strcmp(path,glob_xmount_cfg.pVirtualImageInfoPath)==0) { // Check open permissions - if(!XMountConfData.Writable && (fi->flags & 3)!=O_RDONLY) { + if(!glob_xmount_cfg.Writable && (fi->flags & 3)!=O_RDONLY) { // Attempt to open a read-only file for writing LOG_DEBUG("Attempt to open the read-only file \"%s\" for writing.\n",path) return -EACCES; } return 0; - } else if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + } else if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - if(strcmp(path,XMountConfData.pVirtualVmdkPath)==0) { + if(strcmp(path,glob_xmount_cfg.pVirtualVmdkPath)==0) { // Check open permissions - if(!XMountConfData.Writable && (fi->flags & 3)!=O_RDONLY) { + if(!glob_xmount_cfg.Writable && (fi->flags & 3)!=O_RDONLY) { // Attempt to open a read-only file for writing LOG_DEBUG("Attempt to open the read-only file \"%s\" for writing.\n",path) return -EACCES; } return 0; - } else if(pVirtualVmdkLockFileName!=NULL && - strcmp(path,pVirtualVmdkLockFileName)==0) + } else if(glob_p_vmdk_lockfile_name!=NULL && + strcmp(path,glob_p_vmdk_lockfile_name)==0) { // Check open permissions - if(!XMountConfData.Writable && (fi->flags & 3)!=O_RDONLY) { + if(!glob_xmount_cfg.Writable && (fi->flags & 3)!=O_RDONLY) { // Attempt to open a read-only file for writing LOG_DEBUG("Attempt to open the read-only file \"%s\" for writing.\n",path) return -EACCES; } return 0; } else { // Attempt to open a non existant file LOG_DEBUG("Attempt to open non existant file \"%s\".\n",path) return -ENOENT; } } else { // Attempt to open a non existant file LOG_DEBUG("Attempt to open non existant file \"%s\".\n",path) return -ENOENT; } } /* * ReadVirtFile: * FUSE read implementation * * Params: * buf: Buffer where read data is written to * size: Number of bytes to read * offset: Offset to start reading at * fi: ?? but not used * * Returns: * Read bytes on success, negated error code on error */ static int ReadVirtFile(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { uint64_t len; - if(strcmp(path,XMountConfData.pVirtualImagePath)==0) { + if(strcmp(path,glob_xmount_cfg.pVirtualImagePath)==0) { // Wait for other threads to end reading/writing data - pthread_mutex_lock(&mutex_image_rw); + pthread_mutex_lock(&glob_mutex_image_rw); // Get virtual image file size if(!GetVirtImageSize(&len)) { LOG_ERROR("Couldn't get virtual image size!\n") - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_unlock(&glob_mutex_image_rw); return 0; } if(offsetlen) size=len-offset; if(GetVirtImageData(buf,offset,size)!=size) { LOG_ERROR("Couldn't read data from virtual image file!\n") - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_unlock(&glob_mutex_image_rw); return 0; } } else { LOG_DEBUG("Attempt to read past EOF of virtual image file\n"); - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_unlock(&glob_mutex_image_rw); return 0; } // Allow other threads to read/write data again - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_unlock(&glob_mutex_image_rw); - } else if(strcmp(path,XMountConfData.pVirtualImageInfoPath)==0) { + } else if(strcmp(path,glob_xmount_cfg.pVirtualImageInfoPath)==0) { // Read data from virtual image info file - len=strlen(pVirtualImageInfoFile); + len=strlen(glob_p_info_file); if(offsetlen) { size=len-offset; LOG_DEBUG("Attempt to read past EOF of virtual image info file\n") } - pthread_mutex_lock(&mutex_info_read); - memcpy(buf,pVirtualImageInfoFile+offset,size); - pthread_mutex_unlock(&mutex_info_read); + pthread_mutex_lock(&glob_mutex_info_read); + memcpy(buf,glob_p_info_file+offset,size); + pthread_mutex_unlock(&glob_mutex_info_read); LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 " from virtual image info file\n",size,offset) } else { LOG_DEBUG("Attempt to read past EOF of virtual info file\n"); return 0; } - } else if(strcmp(path,XMountConfData.pVirtualVmdkPath)==0) { + } else if(strcmp(path,glob_xmount_cfg.pVirtualVmdkPath)==0) { // Read data from virtual vmdk file - len=VirtualVmdkFileSize; + len=glob_vmdk_file_size; if(offsetlen) { LOG_DEBUG("Attempt to read past EOF of virtual vmdk file\n") LOG_DEBUG("Adjusting read size from %u to %u\n",size,len-offset) size=len-offset; } - pthread_mutex_lock(&mutex_image_rw); - memcpy(buf,pVirtualVmdkFile+offset,size); - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_lock(&glob_mutex_image_rw); + memcpy(buf,glob_p_vmdk_file+offset,size); + pthread_mutex_unlock(&glob_mutex_image_rw); LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 " from virtual vmdk file\n",size,offset) } else { LOG_DEBUG("Attempt to read behind EOF of virtual vmdk file\n"); return 0; } - } else if(pVirtualVmdkLockFileName!=NULL && - strcmp(path,pVirtualVmdkLockFileName)==0) + } else if(glob_p_vmdk_lockfile_name!=NULL && + strcmp(path,glob_p_vmdk_lockfile_name)==0) { // Read data from virtual lock file - len=VirtualVmdkLockFileDataSize; + len=glob_vmdk_lockfile_size; if(offsetlen) { LOG_DEBUG("Attempt to read past EOF of virtual vmdk lock file\n") LOG_DEBUG("Adjusting read size from %u to %u\n",size,len-offset) size=len-offset; } - pthread_mutex_lock(&mutex_image_rw); - memcpy(buf,pVirtualVmdkLockFileData+offset,size); - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_lock(&glob_mutex_image_rw); + memcpy(buf,glob_p_vmdk_lockfile_data+offset,size); + pthread_mutex_unlock(&glob_mutex_image_rw); LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64 " from virtual vmdk lock file\n",size,offset) } else { LOG_DEBUG("Attempt to read past EOF of virtual vmdk lock file\n"); return 0; } } else { // Attempt to read non existant file LOG_DEBUG("Attempt to read from non existant file \"%s\"\n",path) return -ENOENT; } return size; } /* * RenameVirtFile: * FUSE rename implementation * * Params: * path: File to rename * npath: New filename * * Returns: * "0" on error, negated error code on error */ static int RenameVirtFile(const char *path, const char *npath) { - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - if(pVirtualVmdkLockFileName!=NULL && - strcmp(path,pVirtualVmdkLockFileName)==0) + if(glob_p_vmdk_lockfile_name!=NULL && + strcmp(path,glob_p_vmdk_lockfile_name)==0) { LOG_DEBUG("Renaming virtual lock file from \"%s\" to \"%s\"\n", - pVirtualVmdkLockFileName, + glob_p_vmdk_lockfile_name, npath) - XMOUNT_REALLOC(pVirtualVmdkLockFileName,char*, + XMOUNT_REALLOC(glob_p_vmdk_lockfile_name,char*, (strlen(npath)+1)*sizeof(char)); - strcpy(pVirtualVmdkLockFileName,npath); + strcpy(glob_p_vmdk_lockfile_name,npath); return 0; } } return -ENOENT; } /* * DeleteVirtDir: * FUSE rmdir implementation * * Params: * path: Directory to delete * * Returns: * "0" on success, negated error code on error */ static int DeleteVirtDir(const char *path) { // Only VMWare's lock directories can be deleted - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - if(pVirtualVmdkLockDir!=NULL && strcmp(path,pVirtualVmdkLockDir)==0) { - LOG_DEBUG("Deleting virtual lock dir \"%s\"\n",pVirtualVmdkLockDir) - free(pVirtualVmdkLockDir); - pVirtualVmdkLockDir=NULL; + if(glob_p_vmdk_lockdir1!=NULL && strcmp(path,glob_p_vmdk_lockdir1)==0) { + LOG_DEBUG("Deleting virtual lock dir \"%s\"\n",glob_p_vmdk_lockdir1) + free(glob_p_vmdk_lockdir1); + glob_p_vmdk_lockdir1=NULL; return 0; - } else if(pVirtualVmdkLockDir2!=NULL && - strcmp(path,pVirtualVmdkLockDir2)==0) + } else if(glob_p_vmdk_lockdir2!=NULL && + strcmp(path,glob_p_vmdk_lockdir2)==0) { - LOG_DEBUG("Deleting virtual lock dir \"%s\"\n",pVirtualVmdkLockDir) - free(pVirtualVmdkLockDir2); - pVirtualVmdkLockDir2=NULL; + LOG_DEBUG("Deleting virtual lock dir \"%s\"\n",glob_p_vmdk_lockdir1) + free(glob_p_vmdk_lockdir2); + glob_p_vmdk_lockdir2=NULL; return 0; } } return -1; } /* * DeleteVirtFile: * FUSE unlink implementation * * Params: * path: File to delete * * Returns: * "0" on success, negated error code on error */ static int DeleteVirtFile(const char *path) { // Only VMWare's lock file can be deleted - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { - if(pVirtualVmdkLockFileName!=NULL && - strcmp(path,pVirtualVmdkLockFileName)==0) + if(glob_p_vmdk_lockfile_name!=NULL && + strcmp(path,glob_p_vmdk_lockfile_name)==0) { - LOG_DEBUG("Deleting virtual file \"%s\"\n",pVirtualVmdkLockFileName) - free(pVirtualVmdkLockFileName); - free(pVirtualVmdkLockFileData); - pVirtualVmdkLockFileName=NULL; - pVirtualVmdkLockFileData=NULL; - VirtualVmdkLockFileDataSize=0; + LOG_DEBUG("Deleting virtual file \"%s\"\n",glob_p_vmdk_lockfile_name) + free(glob_p_vmdk_lockfile_name); + free(glob_p_vmdk_lockfile_data); + glob_p_vmdk_lockfile_name=NULL; + glob_p_vmdk_lockfile_data=NULL; + glob_vmdk_lockfile_size=0; return 0; } } return -1; } /* * GetVirtFsStats: * FUSE statfs implementation * * Params: * path: Get stats for fs that the specified file resides in * stats: Stats * * Returns: * "0" on success, negated error code on error */ /* static int GetVirtFsStats(const char *path, struct statvfs *stats) { struct statvfs CacheFileFsStats; int ret; - if(XMountConfData.Writable==TRUE) { + if(glob_xmount_cfg.Writable==TRUE) { // If write support is enabled, return stats of fs upon which cache file // resides in - if((ret=statvfs(XMountConfData.pCacheFile,&CacheFileFsStats))==0) { + if((ret=statvfs(glob_xmount_cfg.pCacheFile,&CacheFileFsStats))==0) { memcpy(stats,&CacheFileFsStats,sizeof(struct statvfs)); return 0; } else { LOG_ERROR("Couldn't get stats for fs upon which resides \"%s\"\n", - XMountConfData.pCacheFile) + glob_xmount_cfg.pCacheFile) return ret; } } else { // TODO: Return read only return 0; } } */ /* * WriteVirtFile: * FUSE write implementation * * Params: * buf: Buffer containing data to write * size: Number of bytes to write * offset: Offset to start writing at * fi: ?? but not used * * Returns: * Written bytes on success, negated error code on error */ static int WriteVirtFile(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { uint64_t len; - if(strcmp(path,XMountConfData.pVirtualImagePath)==0) { + if(strcmp(path,glob_xmount_cfg.pVirtualImagePath)==0) { // Wait for other threads to end reading/writing data - pthread_mutex_lock(&mutex_image_rw); + pthread_mutex_lock(&glob_mutex_image_rw); // Get virtual image file size if(!GetVirtImageSize(&len)) { LOG_ERROR("Couldn't get virtual image size!\n") - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_unlock(&glob_mutex_image_rw); return 0; } if(offsetlen) size=len-offset; if(SetVirtImageData(buf,offset,size)!=size) { LOG_ERROR("Couldn't write data to virtual image file!\n") - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_unlock(&glob_mutex_image_rw); return 0; } } else { LOG_DEBUG("Attempt to write past EOF of virtual image file\n") - pthread_mutex_unlock(&mutex_image_rw); + pthread_mutex_unlock(&glob_mutex_image_rw); return 0; } // Allow other threads to read/write data again - pthread_mutex_unlock(&mutex_image_rw); - } else if(strcmp(path,XMountConfData.pVirtualVmdkPath)==0) { - pthread_mutex_lock(&mutex_image_rw); - len=VirtualVmdkFileSize; + pthread_mutex_unlock(&glob_mutex_image_rw); + } else if(strcmp(path,glob_xmount_cfg.pVirtualVmdkPath)==0) { + pthread_mutex_lock(&glob_mutex_image_rw); + len=glob_vmdk_file_size; if((offset+size)>len) { // Enlarge or create buffer if needed if(len==0) { len=offset+size; - XMOUNT_MALLOC(pVirtualVmdkFile,char*,len*sizeof(char)) + XMOUNT_MALLOC(glob_p_vmdk_file,char*,len*sizeof(char)) } else { len=offset+size; - XMOUNT_REALLOC(pVirtualVmdkFile,char*,len*sizeof(char)) + XMOUNT_REALLOC(glob_p_vmdk_file,char*,len*sizeof(char)) } - VirtualVmdkFileSize=offset+size; + glob_vmdk_file_size=offset+size; } // Copy data to buffer - memcpy(pVirtualVmdkFile+offset,buf,size); - pthread_mutex_unlock(&mutex_image_rw); - } else if(pVirtualVmdkLockFileName!=NULL && - strcmp(path,pVirtualVmdkLockFileName)==0) + memcpy(glob_p_vmdk_file+offset,buf,size); + pthread_mutex_unlock(&glob_mutex_image_rw); + } else if(glob_p_vmdk_lockfile_name!=NULL && + strcmp(path,glob_p_vmdk_lockfile_name)==0) { - pthread_mutex_lock(&mutex_image_rw); - if((offset+size)>VirtualVmdkLockFileDataSize) { + pthread_mutex_lock(&glob_mutex_image_rw); + if((offset+size)>glob_vmdk_lockfile_size) { // Enlarge or create buffer if needed - if(VirtualVmdkLockFileDataSize==0) { - VirtualVmdkLockFileDataSize=offset+size; - XMOUNT_MALLOC(pVirtualVmdkLockFileData,char*, - VirtualVmdkLockFileDataSize*sizeof(char)) + if(glob_vmdk_lockfile_size==0) { + glob_vmdk_lockfile_size=offset+size; + XMOUNT_MALLOC(glob_p_vmdk_lockfile_data,char*, + glob_vmdk_lockfile_size*sizeof(char)) } else { - VirtualVmdkLockFileDataSize=offset+size; - XMOUNT_REALLOC(pVirtualVmdkLockFileData,char*, - VirtualVmdkLockFileDataSize*sizeof(char)) + glob_vmdk_lockfile_size=offset+size; + XMOUNT_REALLOC(glob_p_vmdk_lockfile_data,char*, + glob_vmdk_lockfile_size*sizeof(char)) } } // Copy data to buffer - memcpy(pVirtualVmdkLockFileData+offset,buf,size); - pthread_mutex_unlock(&mutex_image_rw); - } else if(strcmp(path,XMountConfData.pVirtualImageInfoPath)==0) { + memcpy(glob_p_vmdk_lockfile_data+offset,buf,size); + pthread_mutex_unlock(&glob_mutex_image_rw); + } else if(strcmp(path,glob_xmount_cfg.pVirtualImageInfoPath)==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",path) return -ENOENT; } return size; } /* * CalculateInputImageHash: * Calculates an MD5 hash of the first HASH_AMOUNT bytes of the input image. * * Params: * pHashLow : Pointer to the lower 64 bit of the hash * pHashHigh : Pointer to the higher 64 bit of the hash * * Returns: * TRUE on success, FALSE on error */ static int CalculateInputImageHash(uint64_t *pHashLow, uint64_t *pHashHigh) { char hash[16]; md5_state_t md5_state; char *buf; XMOUNT_MALLOC(buf,char*,HASH_AMOUNT*sizeof(char)) size_t read_data=GetOrigImageData(buf,0,HASH_AMOUNT); if(read_data>0) { // Calculate MD5 hash md5_init(&md5_state); - md5_append(&md5_state,buf,HASH_AMOUNT); - md5_finish(&md5_state,hash); + md5_append(&md5_state,(const md5_byte_t*)buf,HASH_AMOUNT); + md5_finish(&md5_state,(md5_byte_t*)hash); // Convert MD5 hash into two 64bit integers *pHashLow=*((uint64_t*)hash); *pHashHigh=*((uint64_t*)(hash+8)); free(buf); return TRUE; } else { LOG_ERROR("Couldn't read data from original image file!\n") free(buf); return FALSE; } } /* * InitVirtVdiHeader: * Build and init virtual VDI file header * * Params: * n/a * * Returns: * "TRUE" on success, "FALSE" on error */ static int InitVirtVdiHeader() { // See http://forums.virtualbox.org/viewtopic.php?t=8046 for a // "description" of the various header fields uint64_t ImageSize; off_t offset; uint32_t i,BlockEntries; // Get input image size - if(!GetOrigImageSize(&ImageSize)) { + if(!GetOrigImageSize(&ImageSize,FALSE)) { LOG_ERROR("Couldn't get input image size!\n") return FALSE; } // Calculate how many VDI blocks we need BlockEntries=ImageSize/VDI_IMAGE_BLOCK_SIZE; if((ImageSize%VDI_IMAGE_BLOCK_SIZE)!=0) BlockEntries++; - VdiBlockMapSize=BlockEntries*sizeof(uint32_t); + glob_p_vdi_block_map_size=BlockEntries*sizeof(uint32_t); LOG_DEBUG("BlockMap: %d (%08X) entries, %d (%08X) bytes!\n", BlockEntries, BlockEntries, - VdiBlockMapSize, - VdiBlockMapSize) + glob_p_vdi_block_map_size, + glob_p_vdi_block_map_size) // Allocate memory for vdi header and block map - VdiFileHeaderSize=sizeof(TVdiFileHeader)+VdiBlockMapSize; - XMOUNT_MALLOC(pVdiFileHeader,pTVdiFileHeader,VdiFileHeaderSize) - memset(pVdiFileHeader,0,VdiFileHeaderSize); - pVdiBlockMap=((void*)pVdiFileHeader)+sizeof(TVdiFileHeader); + glob_vdi_header_size=sizeof(ts_VdiFileHeader)+glob_p_vdi_block_map_size; + XMOUNT_MALLOC(glob_p_vdi_header,pts_VdiFileHeader,glob_vdi_header_size) + memset(glob_p_vdi_header,0,glob_vdi_header_size); + glob_p_vdi_block_map=((void*)glob_p_vdi_header)+sizeof(ts_VdiFileHeader); // Init header values - strncpy(pVdiFileHeader->szFileInfo,VDI_FILE_COMMENT, + strncpy(glob_p_vdi_header->szFileInfo,VDI_FILE_COMMENT, strlen(VDI_FILE_COMMENT)+1); - pVdiFileHeader->u32Signature=VDI_IMAGE_SIGNATURE; - pVdiFileHeader->u32Version=VDI_IMAGE_VERSION; - pVdiFileHeader->cbHeader=0x00000180; // No idea what this is for! Testimage had same value - pVdiFileHeader->u32Type=VDI_IMAGE_TYPE_FIXED; - pVdiFileHeader->fFlags=VDI_IMAGE_FLAGS; - strncpy(pVdiFileHeader->szComment,VDI_HEADER_COMMENT, + glob_p_vdi_header->u32Signature=VDI_IMAGE_SIGNATURE; + glob_p_vdi_header->u32Version=VDI_IMAGE_VERSION; + glob_p_vdi_header->cbHeader=0x00000180; // No idea what this is for! Testimage had same value + glob_p_vdi_header->u32Type=VDI_IMAGE_TYPE_FIXED; + glob_p_vdi_header->fFlags=VDI_IMAGE_FLAGS; + strncpy(glob_p_vdi_header->szComment,VDI_HEADER_COMMENT, strlen(VDI_HEADER_COMMENT)+1); - pVdiFileHeader->offData=VdiFileHeaderSize; - pVdiFileHeader->offBlocks=sizeof(TVdiFileHeader); - pVdiFileHeader->cCylinders=0; // Legacy info - pVdiFileHeader->cHeads=0; // Legacy info - pVdiFileHeader->cSectors=0; // Legacy info - pVdiFileHeader->cbSector=512; // Legacy info - pVdiFileHeader->u32Dummy=0; - pVdiFileHeader->cbDisk=ImageSize; + glob_p_vdi_header->offData=glob_vdi_header_size; + glob_p_vdi_header->offBlocks=sizeof(ts_VdiFileHeader); + glob_p_vdi_header->cCylinders=0; // Legacy info + glob_p_vdi_header->cHeads=0; // Legacy info + glob_p_vdi_header->cSectors=0; // Legacy info + glob_p_vdi_header->cbSector=512; // Legacy info + glob_p_vdi_header->u32Dummy=0; + glob_p_vdi_header->cbDisk=ImageSize; // Seems as VBox is always using a 1MB blocksize - pVdiFileHeader->cbBlock=VDI_IMAGE_BLOCK_SIZE; - pVdiFileHeader->cbBlockExtra=0; - pVdiFileHeader->cBlocks=BlockEntries; - pVdiFileHeader->cBlocksAllocated=BlockEntries; + glob_p_vdi_header->cbBlock=VDI_IMAGE_BLOCK_SIZE; + glob_p_vdi_header->cbBlockExtra=0; + glob_p_vdi_header->cBlocks=BlockEntries; + glob_p_vdi_header->cBlocksAllocated=BlockEntries; // Use partial MD5 input file hash as creation UUID and generate a random // modification UUID. VBox won't accept immages where create and modify UUIDS // aren't set. - pVdiFileHeader->uuidCreate_l=XMountConfData.InputHashLo; - pVdiFileHeader->uuidCreate_h=XMountConfData.InputHashHi; - //*((uint32_t*)(&(pVdiFileHeader->uuidCreate_l)))=rand(); - //*((uint32_t*)(&(pVdiFileHeader->uuidCreate_l))+4)=rand(); - //*((uint32_t*)(&(pVdiFileHeader->uuidCreate_h)))=rand(); - //*((uint32_t*)(&(pVdiFileHeader->uuidCreate_h))+4)=rand(); + glob_p_vdi_header->uuidCreate_l=glob_xmount_cfg.InputHashLo; + glob_p_vdi_header->uuidCreate_h=glob_xmount_cfg.InputHashHi; + //*((uint32_t*)(&(glob_p_vdi_header->uuidCreate_l)))=rand(); + //*((uint32_t*)(&(glob_p_vdi_header->uuidCreate_l))+4)=rand(); + //*((uint32_t*)(&(glob_p_vdi_header->uuidCreate_h)))=rand(); + //*((uint32_t*)(&(glob_p_vdi_header->uuidCreate_h))+4)=rand(); #define rand64(var) { \ *((uint32_t*)&(var))=rand(); \ *(((uint32_t*)&(var))+1)=rand(); \ } - rand64(pVdiFileHeader->uuidModify_l); - rand64(pVdiFileHeader->uuidModify_h); + rand64(glob_p_vdi_header->uuidModify_l); + rand64(glob_p_vdi_header->uuidModify_h); #undef rand64 // Generate block map i=0; - for(offset=0;offsetcookie=VHD_IMAGE_HVAL_COOKIE; - pVhdFileHeader->features=VHD_IMAGE_HVAL_FEATURES; - pVhdFileHeader->file_format_version=VHD_IMAGE_HVAL_FILE_FORMAT_VERSION; - pVhdFileHeader->data_offset=VHD_IMAGE_HVAL_DATA_OFFSET; - pVhdFileHeader->creation_time=htobe32(time(NULL)- + glob_p_vhd_header->cookie=VHD_IMAGE_HVAL_COOKIE; + glob_p_vhd_header->features=VHD_IMAGE_HVAL_FEATURES; + glob_p_vhd_header->file_format_version=VHD_IMAGE_HVAL_FILE_FORMAT_VERSION; + glob_p_vhd_header->data_offset=VHD_IMAGE_HVAL_DATA_OFFSET; + glob_p_vhd_header->creation_time=htobe32(time(NULL)- VHD_IMAGE_TIME_CONVERSION_OFFSET); - pVhdFileHeader->creator_app=VHD_IMAGE_HVAL_CREATOR_APPLICATION; - pVhdFileHeader->creator_ver=VHD_IMAGE_HVAL_CREATOR_VERSION; - pVhdFileHeader->creator_os=VHD_IMAGE_HVAL_CREATOR_HOST_OS; - pVhdFileHeader->size_original=htobe64(orig_image_size); - pVhdFileHeader->size_current=pVhdFileHeader->size_original; + glob_p_vhd_header->creator_app=VHD_IMAGE_HVAL_CREATOR_APPLICATION; + glob_p_vhd_header->creator_ver=VHD_IMAGE_HVAL_CREATOR_VERSION; + glob_p_vhd_header->creator_os=VHD_IMAGE_HVAL_CREATOR_HOST_OS; + glob_p_vhd_header->size_original=htobe64(orig_image_size); + glob_p_vhd_header->size_current=glob_p_vhd_header->size_original; // Convert size to sectors if(orig_image_size>136899993600) { // image is larger then CHS values can address. // Set sectors to max (C65535*H16*S255). geom_tot_s=267382800; } else { // Calculate actual sectors geom_tot_s=orig_image_size/512; if((orig_image_size%512)!=0) geom_tot_s++; } // Calculate CHS values. This is done according to the VHD specs if(geom_tot_s>=66059280) { // C65535 * H16 * S63 geom_s=255; geom_h=16; geom_c_x_h=geom_tot_s/geom_s; } else { geom_s=17; geom_c_x_h=geom_tot_s/geom_s; geom_h=(geom_c_x_h+1023)/1024; if(geom_h<4) geom_h=4; if(geom_c_x_h>=(geom_h*1024) || geom_h>16) { geom_s=31; geom_h=16; geom_c_x_h=geom_tot_s/geom_s; } if(geom_c_x_h>=(geom_h*1024)) { geom_s=63; geom_h=16; geom_c_x_h=geom_tot_s/geom_s; } } geom_c=geom_c_x_h/geom_h; - pVhdFileHeader->disk_geometry_c=htobe16(geom_c); - pVhdFileHeader->disk_geometry_h=geom_h; - pVhdFileHeader->disk_geometry_s=geom_s; + glob_p_vhd_header->disk_geometry_c=htobe16(geom_c); + glob_p_vhd_header->disk_geometry_h=geom_h; + glob_p_vhd_header->disk_geometry_s=geom_s; - pVhdFileHeader->disk_type=VHD_IMAGE_HVAL_DISK_TYPE; + glob_p_vhd_header->disk_type=VHD_IMAGE_HVAL_DISK_TYPE; - pVhdFileHeader->uuid_l=XMountConfData.InputHashLo; - pVhdFileHeader->uuid_h=XMountConfData.InputHashHi; - pVhdFileHeader->saved_state=0x00; + glob_p_vhd_header->uuid_l=glob_xmount_cfg.InputHashLo; + glob_p_vhd_header->uuid_h=glob_xmount_cfg.InputHashHi; + glob_p_vhd_header->saved_state=0x00; // Calculate footer checksum - for(i=0;ichecksum=htobe32(~checksum); + glob_p_vhd_header->checksum=htobe32(~checksum); - LOG_DEBUG("VHD header size = %u\n",sizeof(TVhdFileHeader)); + LOG_DEBUG("VHD header size = %u\n",sizeof(ts_VhdFileHeader)); return TRUE; } /* * InitVirtualVmdkFile: * Init the virtual VMDK file * * Params: * n/a * * Returns: * "TRUE" on success, "FALSE" on error */ static int InitVirtualVmdkFile() { uint64_t ImageSize=0; uint64_t ImageBlocks=0; char buf[500]; // Get original image size - if(!GetOrigImageSize(&ImageSize)) { + if(!GetOrigImageSize(&ImageSize,FALSE)) { LOG_ERROR("Couldn't get original image size!\n") return FALSE; } ImageBlocks=ImageSize/512; if(ImageSize%512!=0) ImageBlocks++; #define VMDK_DESC_FILE "# Disk DescriptorFile\n" \ "version=1\n" \ "CID=fffffffe\n" \ "parentCID=ffffffff\n" \ "createType=\"monolithicFlat\"\n\n" \ "# Extent description\n" \ "RW %" PRIu64 " FLAT \"%s\" 0\n\n" \ "# The Disk Data Base\n" \ "#DDB\n" \ "ddb.virtualHWVersion = \"3\"\n" \ "ddb.adapterType = \"%s\"\n" \ "ddb.geometry.cylinders = \"0\"\n" \ "ddb.geometry.heads = \"0\"\n" \ "ddb.geometry.sectors = \"0\"\n" - if(XMountConfData.VirtImageType==TVirtImageType_VMDK) { + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK) { // VMDK with IDE bus sprintf(buf, VMDK_DESC_FILE, ImageBlocks, - (XMountConfData.pVirtualImagePath)+1, + (glob_xmount_cfg.pVirtualImagePath)+1, "ide"); - } else if(XMountConfData.VirtImageType==TVirtImageType_VMDKS){ + } else if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS){ // VMDK with SCSI bus sprintf(buf, VMDK_DESC_FILE, ImageBlocks, - (XMountConfData.pVirtualImagePath)+1, + (glob_xmount_cfg.pVirtualImagePath)+1, "scsi"); } else { LOG_ERROR("Unknown virtual VMDK file format!\n") return FALSE; } #undef VMDK_DESC_FILE // Do not use XMOUNT_STRSET here to avoid adding '\0' to the buffer! - XMOUNT_MALLOC(pVirtualVmdkFile,char*,strlen(buf)) - strncpy(pVirtualVmdkFile,buf,strlen(buf)); - VirtualVmdkFileSize=strlen(buf); + XMOUNT_MALLOC(glob_p_vmdk_file,char*,strlen(buf)) + strncpy(glob_p_vmdk_file,buf,strlen(buf)); + glob_vmdk_file_size=strlen(buf); return TRUE; } /* * InitVirtImageInfoFile: * Create virtual image info file * * Params: * n/a * * Returns: * "TRUE" on success, "FALSE" on error */ static int InitVirtImageInfoFile() { - char buf[200]; - int ret; +// char buf[200]; +// int ret; // Add static header to file - XMOUNT_MALLOC(pVirtualImageInfoFile,char*,(strlen(IMAGE_INFO_HEADER)+1)) - strncpy(pVirtualImageInfoFile,IMAGE_INFO_HEADER,strlen(IMAGE_INFO_HEADER)+1); + XMOUNT_MALLOC(glob_p_info_file,char*,(strlen(IMAGE_INFO_HEADER)+1)) + strncpy(glob_p_info_file,IMAGE_INFO_HEADER,strlen(IMAGE_INFO_HEADER)+1); - switch(XMountConfData.OrigImageType) { + // TODO +/* + switch(glob_xmount_cfg.OrigImageType) { case TOrigImageType_DD: // Original image is a DD file. There isn't much info to extract. Perhaps // just add image size // TODO: Add infos to virtual image info file break; #ifdef WITH_LIBEWF #define M_SAVE_VALUE(DESC,SHORT_DESC) { \ if(ret==1) { \ - XMOUNT_REALLOC(pVirtualImageInfoFile,char*, \ - (strlen(pVirtualImageInfoFile)+strlen(buf)+strlen(DESC)+2)) \ - strncpy((pVirtualImageInfoFile+strlen(pVirtualImageInfoFile)),DESC,strlen(DESC)+1); \ - strncpy((pVirtualImageInfoFile+strlen(pVirtualImageInfoFile)),buf,strlen(buf)+1); \ - strncpy((pVirtualImageInfoFile+strlen(pVirtualImageInfoFile)),"\n",2); \ + XMOUNT_REALLOC(glob_p_info_file,char*, \ + (strlen(glob_p_info_file)+strlen(buf)+strlen(DESC)+2)) \ + strncpy((glob_p_info_file+strlen(glob_p_info_file)),DESC,strlen(DESC)+1); \ + strncpy((glob_p_info_file+strlen(glob_p_info_file)),buf,strlen(buf)+1); \ + strncpy((glob_p_info_file+strlen(glob_p_info_file)),"\n",2); \ } else if(ret==-1) { \ LOG_WARNING("Couldn't query EWF image header value '%s'\n",SHORT_DESC) \ } \ } case TOrigImageType_EWF: // Original image is an EWF file. Extract various infos from ewf file and // add them to the virtual image info file content. #if defined( HAVE_LIBEWF_V2_API ) ret=libewf_handle_get_utf8_header_value_case_number(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Case number: ","Case number") ret=libewf_handle_get_utf8_header_value_description(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Description: ","Description") ret=libewf_handle_get_utf8_header_value_examiner_name(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Examiner: ","Examiner") ret=libewf_handle_get_utf8_header_value_evidence_number(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Evidence number: ","Evidence number") ret=libewf_handle_get_utf8_header_value_notes(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Notes: ","Notes") ret=libewf_handle_get_utf8_header_value_acquiry_date(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Acquiry date: ","Acquiry date") ret=libewf_handle_get_utf8_header_value_system_date(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("System date: ","System date") ret=libewf_handle_get_utf8_header_value_acquiry_operating_system(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Acquiry os: ","Acquiry os") ret=libewf_handle_get_utf8_header_value_acquiry_software_version(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("Acquiry sw version: ","Acquiry sw version") ret=libewf_handle_get_utf8_hash_value_md5(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("MD5 hash: ","MD5 hash") ret=libewf_handle_get_utf8_hash_value_sha1(hEwfFile,buf,sizeof(buf),NULL); M_SAVE_VALUE("SHA1 hash: ","SHA1 hash") #else ret=libewf_get_header_value_case_number(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Case number: ","Case number") ret=libewf_get_header_value_description(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Description: ","Description") ret=libewf_get_header_value_examiner_name(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Examiner: ","Examiner") ret=libewf_get_header_value_evidence_number(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Evidence number: ","Evidence number") ret=libewf_get_header_value_notes(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Notes: ","Notes") ret=libewf_get_header_value_acquiry_date(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Acquiry date: ","Acquiry date") ret=libewf_get_header_value_system_date(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("System date: ","System date") ret=libewf_get_header_value_acquiry_operating_system(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Acquiry os: ","Acquiry os") ret=libewf_get_header_value_acquiry_software_version(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("Acquiry sw version: ","Acquiry sw version") ret=libewf_get_hash_value_md5(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("MD5 hash: ","MD5 hash") ret=libewf_get_hash_value_sha1(hEwfFile,buf,sizeof(buf)); M_SAVE_VALUE("SHA1 hash: ","SHA1 hash") #endif break; #undef M_SAVE_VALUE #endif #ifdef WITH_LIBAEWF case TOrigImageType_AEWF: - if((ret=AewfInfo(hAewfFile,(const char**)&pVirtualImageInfoFile))!=AEWF_OK) { + if((ret=AewfInfo(hAewfFile,(const char**)&glob_p_info_file))!=AEWF_OK) { LOG_ERROR("Unable to get EWF image infos using AewfInfo. Return code %d!\n",ret) return FALSE; } break; #endif #ifdef WITH_LIBAFF case TOrigImageType_AFF: // TODO: Extract some infos from AFF file to add to our info file break; #endif #ifdef WITH_LIBAAFF case TOrigImageType_AAFF: - if((ret=AaffInfo(hAaffFile,&pVirtualImageInfoFile))!=AAFF_OK) { + if((ret=AaffInfo(hAaffFile,&glob_p_info_file))!=AAFF_OK) { LOG_ERROR("Unable to get AAF image infos using AaffInfo. Return code %d!\n",ret) return FALSE; } break; #endif default: LOG_ERROR("Unsupported input image type!\n") return FALSE; } +*/ return TRUE; } /* * InitCacheFile: * Create / load cache file to enable virtual write support * * Params: * n/a * * Returns: * "TRUE" on success, "FALSE" on error */ static int InitCacheFile() { uint64_t ImageSize=0; uint64_t BlockIndexSize=0; uint64_t CacheFileHeaderSize=0; uint64_t CacheFileSize=0; uint32_t NeededBlocks=0; uint64_t buf; - if(!XMountConfData.OverwriteCache) { + if(!glob_xmount_cfg.OverwriteCache) { // Try to open an existing cache file or create a new one - hCacheFile=(FILE*)FOPEN(XMountConfData.pCacheFile,"rb+"); - if(hCacheFile==NULL) { + glob_p_cache_file=(FILE*)FOPEN(glob_xmount_cfg.pCacheFile,"rb+"); + if(glob_p_cache_file==NULL) { // As the c lib seems to have no possibility to open a file rw wether it // exists or not (w+ does not work because it truncates an existing file), // when r+ returns NULL the file could simply not exist LOG_DEBUG("Cache file does not exist. Creating new one\n") - hCacheFile=(FILE*)FOPEN(XMountConfData.pCacheFile,"wb+"); - if(hCacheFile==NULL) { + glob_p_cache_file=(FILE*)FOPEN(glob_xmount_cfg.pCacheFile,"wb+"); + if(glob_p_cache_file==NULL) { // There is really a problem opening the file LOG_ERROR("Couldn't open cache file \"%s\"!\n", - XMountConfData.pCacheFile) + glob_xmount_cfg.pCacheFile) return FALSE; } } } else { // Overwrite existing cache file or create a new one - hCacheFile=(FILE*)FOPEN(XMountConfData.pCacheFile,"wb+"); - if(hCacheFile==NULL) { + glob_p_cache_file=(FILE*)FOPEN(glob_xmount_cfg.pCacheFile,"wb+"); + if(glob_p_cache_file==NULL) { LOG_ERROR("Couldn't open cache file \"%s\"!\n", - XMountConfData.pCacheFile) + glob_xmount_cfg.pCacheFile) return FALSE; } } // Get input image size - if(!GetOrigImageSize(&ImageSize)) { + if(!GetOrigImageSize(&ImageSize,FALSE)) { LOG_ERROR("Couldn't get input image size!\n") return FALSE; } // Calculate how many blocks are needed and how big the buffers must be // for the actual cache file version NeededBlocks=ImageSize/CACHE_BLOCK_SIZE; if((ImageSize%CACHE_BLOCK_SIZE)!=0) NeededBlocks++; - BlockIndexSize=NeededBlocks*sizeof(TCacheFileBlockIndex); - CacheFileHeaderSize=sizeof(TCacheFileHeader)+BlockIndexSize; + BlockIndexSize=NeededBlocks*sizeof(ts_CacheFileBlockIndex); + CacheFileHeaderSize=sizeof(ts_CacheFileHeader)+BlockIndexSize; LOG_DEBUG("Cache blocks: %u (%04X) entries, %zd (%08zX) bytes\n", NeededBlocks, NeededBlocks, BlockIndexSize, BlockIndexSize) // Get cache file size // fseeko64 had massive problems! - if(fseeko(hCacheFile,0,SEEK_END)!=0) { + if(fseeko(glob_p_cache_file,0,SEEK_END)!=0) { LOG_ERROR("Couldn't seek to end of cache file!\n") return FALSE; } // Same here, ftello64 didn't work at all and returned 0 all the times - CacheFileSize=ftello(hCacheFile); + CacheFileSize=ftello(glob_p_cache_file); LOG_DEBUG("Cache file has %zd bytes\n",CacheFileSize) if(CacheFileSize>0) { // Cache file isn't empty, parse block header LOG_DEBUG("Cache file not empty. Parsing block header\n") - if(fseeko(hCacheFile,0,SEEK_SET)!=0) { + if(fseeko(glob_p_cache_file,0,SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to beginning of cache file!\n") return FALSE; } // Read and check file signature - if(fread(&buf,8,1,hCacheFile)!=1 || buf!=CACHE_FILE_SIGNATURE) { - free(pCacheFileHeader); + if(fread(&buf,8,1,glob_p_cache_file)!=1 || buf!=CACHE_FILE_SIGNATURE) { + free(glob_p_cache_header); LOG_ERROR("Not an xmount cache file or cache file corrupt!\n") return FALSE; } // Now get cache file version (Has only 32bit!) - if(fread(&buf,4,1,hCacheFile)!=1) { - free(pCacheFileHeader); + if(fread(&buf,4,1,glob_p_cache_file)!=1) { + free(glob_p_cache_header); LOG_ERROR("Not an xmount cache file or cache file corrupt!\n") return FALSE; } switch((uint32_t)buf) { case 0x00000001: // Old v1 cache file. LOG_ERROR("Unsupported cache file version!\n") LOG_ERROR("Please use xmount-tool to upgrade your cache file.\n") return FALSE; case CUR_CACHE_FILE_VERSION: // Current version - if(fseeko(hCacheFile,0,SEEK_SET)!=0) { + if(fseeko(glob_p_cache_file,0,SEEK_SET)!=0) { LOG_ERROR("Couldn't seek to beginning of cache file!\n") return FALSE; } // Alloc memory for header and block index - XMOUNT_MALLOC(pCacheFileHeader,pTCacheFileHeader,CacheFileHeaderSize) - memset(pCacheFileHeader,0,CacheFileHeaderSize); + XMOUNT_MALLOC(glob_p_cache_header,pts_CacheFileHeader,CacheFileHeaderSize) + memset(glob_p_cache_header,0,CacheFileHeaderSize); // Read header and block index from file - if(fread(pCacheFileHeader,CacheFileHeaderSize,1,hCacheFile)!=1) { + if(fread(glob_p_cache_header,CacheFileHeaderSize,1,glob_p_cache_file)!=1) { // Cache file isn't big enough - free(pCacheFileHeader); + free(glob_p_cache_header); LOG_ERROR("Cache file corrupt!\n") return FALSE; } break; default: LOG_ERROR("Unknown cache file version!\n") return FALSE; } // Check if cache file has same block size as we do - if(pCacheFileHeader->BlockSize!=CACHE_BLOCK_SIZE) { + if(glob_p_cache_header->BlockSize!=CACHE_BLOCK_SIZE) { LOG_ERROR("Cache file does not use default cache block size!\n") return FALSE; } // Set pointer to block index - pCacheFileBlockIndex=(pTCacheFileBlockIndex)((void*)pCacheFileHeader+ - pCacheFileHeader->pBlockIndex); + glob_p_cache_blkidx=(pts_CacheFileBlockIndex)((void*)glob_p_cache_header+ + glob_p_cache_header->pBlockIndex); } else { // New cache file, generate a new block header LOG_DEBUG("Cache file is empty. Generating new block header\n"); // Alloc memory for header and block index - XMOUNT_MALLOC(pCacheFileHeader,pTCacheFileHeader,CacheFileHeaderSize) - memset(pCacheFileHeader,0,CacheFileHeaderSize); - pCacheFileHeader->FileSignature=CACHE_FILE_SIGNATURE; - pCacheFileHeader->CacheFileVersion=CUR_CACHE_FILE_VERSION; - pCacheFileHeader->BlockSize=CACHE_BLOCK_SIZE; - pCacheFileHeader->BlockCount=NeededBlocks; - //pCacheFileHeader->UsedBlocks=0; + XMOUNT_MALLOC(glob_p_cache_header,pts_CacheFileHeader,CacheFileHeaderSize) + memset(glob_p_cache_header,0,CacheFileHeaderSize); + glob_p_cache_header->FileSignature=CACHE_FILE_SIGNATURE; + glob_p_cache_header->CacheFileVersion=CUR_CACHE_FILE_VERSION; + glob_p_cache_header->BlockSize=CACHE_BLOCK_SIZE; + glob_p_cache_header->BlockCount=NeededBlocks; + //glob_p_cache_header->UsedBlocks=0; // The following pointer is only usuable when reading data from cache file - pCacheFileHeader->pBlockIndex=sizeof(TCacheFileHeader); - pCacheFileBlockIndex=(pTCacheFileBlockIndex)((void*)pCacheFileHeader+ - sizeof(TCacheFileHeader)); - pCacheFileHeader->VdiFileHeaderCached=FALSE; - pCacheFileHeader->pVdiFileHeader=0; - pCacheFileHeader->VmdkFileCached=FALSE; - pCacheFileHeader->VmdkFileSize=0; - pCacheFileHeader->pVmdkFile=0; - pCacheFileHeader->VhdFileHeaderCached=FALSE; - pCacheFileHeader->pVhdFileHeader=0; + glob_p_cache_header->pBlockIndex=sizeof(ts_CacheFileHeader); + glob_p_cache_blkidx=(pts_CacheFileBlockIndex)((void*)glob_p_cache_header+ + sizeof(ts_CacheFileHeader)); + glob_p_cache_header->VdiFileHeaderCached=FALSE; + glob_p_cache_header->pVdiFileHeader=0; + glob_p_cache_header->VmdkFileCached=FALSE; + glob_p_cache_header->VmdkFileSize=0; + glob_p_cache_header->pVmdkFile=0; + glob_p_cache_header->VhdFileHeaderCached=FALSE; + glob_p_cache_header->pVhdFileHeader=0; // Write header to file - if(fwrite(pCacheFileHeader,CacheFileHeaderSize,1,hCacheFile)!=1) { - free(pCacheFileHeader); + if(fwrite(glob_p_cache_header,CacheFileHeaderSize,1,glob_p_cache_file)!=1) { + free(glob_p_cache_header); LOG_ERROR("Couldn't write cache file header to file!\n"); return FALSE; } } return TRUE; } /* - * SearchInputLib + * LoadInputLibs */ -int SearchInputLib() { +static int LoadInputLibs() { DIR *p_dir=NULL; struct dirent *p_dirent=NULL; + int base_library_path_len=0; + char *p_library_path=NULL; + void *p_libxmount_in=NULL; + t_LibXmount_Input_GetApiVersion pfun_GetApiVersion; + t_LibXmount_Input_GetSupportedFormats pfun_GetSupportedFormats; + t_LibXmount_Input_GetFunctions pfun_GetFunctions; + const char *p_supported_formats=NULL; + const char *p_buf; + uint32_t supported_formats_len=0; + pts_InputLib p_input_lib=NULL; + + LOG_DEBUG("Searching for input libraries in '%s'.\n", + XMOUNT_LIBRARY_PATH); // Open lib dir p_dir=opendir(XMOUNT_LIBRARY_PATH); if(p_dir==NULL) { - LOG_ERROR("Unable to access xmount library directory '%s'!", + LOG_ERROR("Unable to access xmount library directory '%s'!\n", XMOUNT_LIBRARY_PATH); - return 0; + return FALSE; + } + + // Construct base library path + base_library_path_len=strlen(XMOUNT_LIBRARY_PATH); + XMOUNT_STRSET(p_library_path,XMOUNT_LIBRARY_PATH); + if(XMOUNT_LIBRARY_PATH[base_library_path_len]!='/') { + base_library_path_len++; + XMOUNT_STRAPP(p_library_path,"/"); } + // Loop over lib dir while((p_dirent=readdir(p_dir))!=NULL) { - if(strncmp(p_dirent->d_name,"libxmount_input_",16)!=0) continue; -// p_libxmount_in=dlopen( + if(strncmp(p_dirent->d_name,"libxmount_input_",16)!=0) { + LOG_DEBUG("Ignoring '%s'.\n",p_dirent->d_name); + continue; + } + + LOG_DEBUG("Trying to load '%s'\n",p_dirent->d_name); + + // Found an input lib, construct full path to it and load it + p_library_path=realloc(p_library_path, + base_library_path_len+strlen(p_dirent->d_name)+1); + if(p_library_path==NULL) { + LOG_ERROR("Couldn't allocate memmory!\n"); + exit(1); + } + strcpy(p_library_path+base_library_path_len,p_dirent->d_name); + p_libxmount_in=dlopen(p_library_path,RTLD_NOW); + if(p_libxmount_in==NULL) { + LOG_ERROR("Unable to load input library '%s'!\n",p_library_path); + LOG_DEBUG("DLOPEN returned '%s'.\n",dlerror()); + continue; + } + + // Load library symbols +#define LIBXMOUNT_LOAD_SYMBOL(name,pfun) { \ + if((pfun=dlsym(p_libxmount_in,name))==NULL) { \ + LOG_ERROR("Unable to load symbol '%s' from library '%s'!\n", \ + name, \ + p_library_path); \ + dlclose(p_libxmount_in); \ + p_libxmount_in=NULL; \ + continue; \ + } \ +} + + LIBXMOUNT_LOAD_SYMBOL("LibXmount_Input_GetApiVersion",pfun_GetApiVersion); + LIBXMOUNT_LOAD_SYMBOL("LibXmount_Input_GetSupportedFormats", + pfun_GetSupportedFormats); + LIBXMOUNT_LOAD_SYMBOL("LibXmount_Input_GetFunctions",pfun_GetFunctions); + +#undef LIBXMOUNT_LOAD_SYMBOL + + // Check library's API version + if(pfun_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_in); + continue; + } + + // Construct new entry for our library list + XMOUNT_MALLOC(p_input_lib,pts_InputLib,sizeof(ts_InputLib)); + XMOUNT_STRSET(p_input_lib->p_name,p_dirent->d_name); + p_input_lib->p_lib=p_libxmount_in; + p_supported_formats=pfun_GetSupportedFormats(); + supported_formats_len=0; + p_buf=p_supported_formats; + while(*p_buf!='\0') { + supported_formats_len+=(strlen(p_buf)+1); + p_buf+=(strlen(p_buf)+1); + } + supported_formats_len++; + XMOUNT_MALLOC(p_input_lib->p_supported_input_types, + char*, + supported_formats_len); + memcpy(p_input_lib->p_supported_input_types, + p_supported_formats, + supported_formats_len); + // TODO: Maybe check if all functions are available + pfun_GetFunctions(&(p_input_lib->lib_functions)); + + // Add entry to our input library list + XMOUNT_REALLOC(glob_pp_input_libs, + pts_InputLib*, + sizeof(pts_InputLib)*(glob_input_libs_count+1)); + glob_pp_input_libs[glob_input_libs_count++]=p_input_lib; + + LOG_DEBUG("%s loaded successfully\n",p_dirent->d_name); + } + + LOG_DEBUG("A total of %u input libs were loaded.\n",glob_input_libs_count); + + free(p_library_path); + closedir(p_dir); + return (glob_input_libs_count>0 ? TRUE : FALSE); +} + +/* + * UnloadInputLibs + */ +static void UnloadInputLibs() { + LOG_DEBUG("Unloading all input libs.\n"); + for(uint32_t i=0;ip_name); + dlclose(glob_pp_input_libs[i]->p_lib); + free(glob_pp_input_libs[i]->p_supported_input_types); + free(glob_pp_input_libs[i]); + } + free(glob_pp_input_libs); + glob_pp_input_libs=NULL; + glob_input_libs_count=0; +} + +/* + * FindInputLib + */ +static int FindInputLib() { + char *p_buf; + + LOG_DEBUG("Trying to find suitable library for input type '%s'.\n", + glob_xmount_cfg.p_orig_image_type); + + // Loop over all loaded libs + for(uint32_t i=0;ip_name); + p_buf=glob_pp_input_libs[i]->p_supported_input_types; + while(*p_buf!='\0') { + if(strcmp(p_buf,glob_xmount_cfg.p_orig_image_type)==0) { + // Library supports input type, set lib functions + LOG_DEBUG("Input library '%s' pretends to handle that input type.\n", + glob_pp_input_libs[i]->p_name); + glob_p_input_functions=&(glob_pp_input_libs[i]->lib_functions); + return TRUE; + } + p_buf+=(strlen(p_buf)+1); + } } - //libxmount_in_functions + LOG_DEBUG("Couldn't find any suitable library.\n"); + + // No library supporting input type found + return FALSE; } /* * Struct containing implemented FUSE functions */ static struct fuse_operations xmount_operations = { // .access=GetVirtFileAccess, .getattr=GetVirtFileAttr, .mkdir=CreateVirtDir, .mknod=CreateVirtFile, .open=OpenVirtFile, .readdir=GetVirtFiles, .read=ReadVirtFile, .rename=RenameVirtFile, .rmdir=DeleteVirtDir, // .statfs=GetVirtFsStats, .unlink=DeleteVirtFile, .write=WriteVirtFile // .release=mountewf_release, }; /* * Main */ int main(int argc, char *argv[]) { char **ppInputFilenames=NULL; int InputFilenameCount=0; int nargc=0; char **ppNargv=NULL; char *pMountpoint=NULL; int ret=1; - int i=0; - int rc; - char *p_lib_err=NULL; setbuf(stdout,NULL); setbuf(stderr,NULL); - // Init XMountConfData - XMountConfData.OrigImageType=TOrigImageType_DD; + // Init glob_xmount_cfg + glob_xmount_cfg.p_orig_image_type=NULL; #ifndef __APPLE__ - XMountConfData.VirtImageType=TVirtImageType_DD; + glob_xmount_cfg.VirtImageType=VirtImageType_DD; #else - XMountConfData.VirtImageType=TVirtImageType_DMG; + glob_xmount_cfg.VirtImageType=VirtImageType_DMG; #endif - XMountConfData.Debug=FALSE; - XMountConfData.pVirtualImagePath=NULL; - XMountConfData.pVirtualVmdkPath=NULL; - XMountConfData.pVirtualImageInfoPath=NULL; - XMountConfData.Writable=FALSE; - XMountConfData.OverwriteCache=FALSE; - XMountConfData.pCacheFile=NULL; - XMountConfData.OrigImageSize=0; - XMountConfData.VirtImageSize=0; - XMountConfData.InputHashLo=0; - XMountConfData.InputHashHi=0; - XMountConfData.orig_img_offset=0; - XMountConfData.p_lib_params=NULL; + glob_xmount_cfg.Debug=FALSE; +// TODO: Remove + glob_xmount_cfg.Debug=TRUE; + glob_xmount_cfg.pVirtualImagePath=NULL; + glob_xmount_cfg.pVirtualVmdkPath=NULL; + glob_xmount_cfg.pVirtualImageInfoPath=NULL; + glob_xmount_cfg.Writable=FALSE; + glob_xmount_cfg.OverwriteCache=FALSE; + glob_xmount_cfg.pCacheFile=NULL; + glob_xmount_cfg.OrigImageSize=0; + glob_xmount_cfg.VirtImageSize=0; + glob_xmount_cfg.InputHashLo=0; + glob_xmount_cfg.InputHashHi=0; + glob_xmount_cfg.orig_img_offset=0; + glob_xmount_cfg.p_lib_params=NULL; + + // Load input libs + if(!LoadInputLibs()) { + LOG_ERROR("Unable to load any input libraries!\n") + return 1; + } // Parse command line options if(!ParseCmdLine(argc, argv, &nargc, &ppNargv, &InputFilenameCount, &ppInputFilenames, &pMountpoint)) { LOG_ERROR("Error parsing command line options!\n") //PrintUsage(argv[0]); + UnloadInputLibs(); return 1; } // Check command line options if(nargc<2 /*|| InputFilenameCount==0 || pMountpoint==NULL*/) { LOG_ERROR("Couldn't parse command line options!\n") PrintUsage(argv[0]); + UnloadInputLibs(); + return 1; + } + + // If no input type was specified, default to "dd" + if(glob_xmount_cfg.p_orig_image_type==NULL) { + XMOUNT_STRSET(glob_xmount_cfg.p_orig_image_type,"dd"); + } + + // Find an input lib for the specified input type + if(!FindInputLib()) { + LOG_ERROR("Unknown input image type \"%s\"!\n", + glob_xmount_cfg.p_orig_image_type) + PrintUsage(argv[0]); + UnloadInputLibs(); return 1; } - if(XMountConfData.Debug==TRUE) { + if(glob_xmount_cfg.Debug==TRUE) { LOG_DEBUG("Options passed to FUSE: ") - for(i=0;iOpen(&glob_p_input_image, + (const char**)ppInputFilenames, + InputFilenameCount)!=0) + { + LOG_ERROR("Unable to open input image file!"); + UnloadInputLibs(); + return 1; + } + LOG_DEBUG("Input image file opened successfully\n") + + // If an offset was specified, make sure it is within limits + if(glob_xmount_cfg.orig_img_offset!=0) { + uint64_t size; + if(!GetOrigImageSize(&size,TRUE)) { + LOG_ERROR("Couldn't get original image's size!\n"); + return 1; } -#endif -#ifdef WITH_LIBAFF - case TOrigImageType_AFF: - hAffFile=af_open(ppInputFilenames[0],O_RDONLY,0); - if(!hAffFile) { - LOG_ERROR("Couldn't open AFF file!\n") - return 1; - } - if(af_cannot_decrypt(hAffFile)) { - LOG_ERROR("Encrypted AFF input images aren't supported yet!\n") - return 1; - } - break; -#endif -#ifdef WITH_LIBAAFF - case TOrigImageType_AAFF: - if((rc=AaffOpen(&hAaffFile,ppInputFilenames[0],0))!=AAFF_OK) { - LOG_ERROR("Unable to open AFF file using AaffOpen. Error code %d!\n",rc) - return 1; - } - break; -#endif - default: - LOG_ERROR("Unsupported input image type specified!\n") + if(glob_xmount_cfg.orig_img_offset>size) { + LOG_ERROR("The specified offset is larger then the size of the input " + "image! (" PRIu64 " > " PRIu64 ")\n", + glob_xmount_cfg.orig_img_offset, + size); return 1; + } } - LOG_DEBUG("Input image file opened successfully\n") // Calculate partial MD5 hash of input image file - if(CalculateInputImageHash(&(XMountConfData.InputHashLo), - &(XMountConfData.InputHashHi))==FALSE) + if(CalculateInputImageHash(&(glob_xmount_cfg.InputHashLo), + &(glob_xmount_cfg.InputHashHi))==FALSE) { LOG_ERROR("Couldn't calculate partial hash of input image file!\n") return 1; } - if(XMountConfData.Debug==TRUE) { + if(glob_xmount_cfg.Debug==TRUE) { LOG_DEBUG("Partial MD5 hash of input image file: ") - for(i=0;i<8;i++) printf("%02hhx", - *(((char*)(&(XMountConfData.InputHashLo)))+i)); - for(i=0;i<8;i++) printf("%02hhx", - *(((char*)(&(XMountConfData.InputHashHi)))+i)); + for(int i=0;i<8;i++) printf("%02hhx", + *(((char*)(&(glob_xmount_cfg.InputHashLo)))+i)); + for(int i=0;i<8;i++) printf("%02hhx", + *(((char*)(&(glob_xmount_cfg.InputHashHi)))+i)); printf("\n"); } if(!ExtractVirtFileNames(ppInputFilenames[0])) { LOG_ERROR("Couldn't extract virtual file names!\n"); + UnloadInputLibs(); return 1; } LOG_DEBUG("Virtual file names extracted successfully\n") // Gather infos for info file if(!InitVirtImageInfoFile()) { LOG_ERROR("Couldn't gather infos for virtual image info file!\n") + UnloadInputLibs(); return 1; } LOG_DEBUG("Virtual image info file build successfully\n") // Do some virtual image type specific initialisations - switch(XMountConfData.VirtImageType) { - case TVirtImageType_DD: - case TVirtImageType_DMG: + switch(glob_xmount_cfg.VirtImageType) { + case VirtImageType_DD: + case VirtImageType_DMG: break; - case TVirtImageType_VDI: + case VirtImageType_VDI: // When mounting as VDI, we need to construct a vdi header if(!InitVirtVdiHeader()) { LOG_ERROR("Couldn't initialize virtual VDI file header!\n") + UnloadInputLibs(); return 1; } LOG_DEBUG("Virtual VDI file header build successfully\n") break; - case TVirtImageType_VHD: + case VirtImageType_VHD: // When mounting as VHD, we need to construct a vhd footer if(!InitVirtVhdHeader()) { LOG_ERROR("Couldn't initialize virtual VHD file footer!\n") + UnloadInputLibs(); return 1; } LOG_DEBUG("Virtual VHD file footer build successfully\n") break; - case TVirtImageType_VMDK: - case TVirtImageType_VMDKS: + case VirtImageType_VMDK: + case VirtImageType_VMDKS: // When mounting as VMDK, we need to construct the VMDK descriptor file if(!InitVirtualVmdkFile()) { LOG_ERROR("Couldn't initialize virtual VMDK file!\n") + UnloadInputLibs(); return 1; } break; } - if(XMountConfData.Writable) { + if(glob_xmount_cfg.Writable) { // Init cache file and cache file block index if(!InitCacheFile()) { LOG_ERROR("Couldn't initialize cache file!\n") + UnloadInputLibs(); return 1; } LOG_DEBUG("Cache file initialized successfully\n") } // Call fuse_main to do the fuse magic ret=fuse_main(nargc,ppNargv,&xmount_operations,NULL); // Destroy mutexes - pthread_mutex_destroy(&mutex_image_rw); - pthread_mutex_destroy(&mutex_info_read); + pthread_mutex_destroy(&glob_mutex_image_rw); + pthread_mutex_destroy(&glob_mutex_info_read); // Close input image - switch(XMountConfData.OrigImageType) { - case TOrigImageType_DD: - if((rc=ddClose(&hDdFile))!=DD_OK) { - LOG_ERROR("Couldn't close DD file using ddClose. Error code %d!"); - } -/* - fclose(hDdFile); -*/ - break; -#ifdef WITH_LIBEWF - case TOrigImageType_EWF: -#if defined( HAVE_LIBEWF_V2_API ) - libewf_handle_close(hEwfFile,NULL); - libewf_handle_free(&hEwfFile,NULL); -#else - libewf_close(hEwfFile); -#endif - break; -#endif -#ifdef WITH_LIBAEWF - case TOrigImageType_AEWF: - if((rc=AewfClose(&hAewfFile))!=AEWF_OK) { - LOG_ERROR("Couldn't close EWF file using AewfClose. Error code %d!"); - } - break; -#endif -#ifdef WITH_LIBAFF - case TOrigImageType_AFF: - af_close(hAffFile); - break; -#endif -#ifdef WITH_LIBAAFF - case TOrigImageType_AAFF: - if((rc=AaffClose(&hAaffFile))!=AAFF_OK) { - LOG_ERROR("Couldn't close AFF file using AaffClose. Error code %d!"); - } - break; -#endif - default: - LOG_ERROR("Couldn't close unsupported input image type!\n"); + if(glob_p_input_functions->Close(&glob_p_input_image)!=0) { + LOG_ERROR("Unable to close input image file!"); } - if(XMountConfData.Writable) { + if(glob_xmount_cfg.Writable) { // Write support was enabled, close cache file - fclose(hCacheFile); - free(pCacheFileHeader); + fclose(glob_p_cache_file); + free(glob_p_cache_header); } // Free allocated memory - if(XMountConfData.VirtImageType==TVirtImageType_VDI) { + if(glob_xmount_cfg.VirtImageType==VirtImageType_VDI) { // Free constructed VDI header - free(pVdiFileHeader); + free(glob_p_vdi_header); } - if(XMountConfData.VirtImageType==TVirtImageType_VHD) { + if(glob_xmount_cfg.VirtImageType==VirtImageType_VHD) { // Free constructed VHD header - free(pVhdFileHeader); + free(glob_p_vhd_header); } - if(XMountConfData.VirtImageType==TVirtImageType_VMDK || - XMountConfData.VirtImageType==TVirtImageType_VMDKS) + if(glob_xmount_cfg.VirtImageType==VirtImageType_VMDK || + glob_xmount_cfg.VirtImageType==VirtImageType_VMDKS) { // Free constructed VMDK file - free(pVirtualVmdkFile); - free(XMountConfData.pVirtualVmdkPath); - if(pVirtualVmdkLockFileName!=NULL) free(pVirtualVmdkLockFileName); - if(pVirtualVmdkLockFileData!=NULL) free(pVirtualVmdkLockFileData); - if(pVirtualVmdkLockDir!=NULL) free(pVirtualVmdkLockDir); - if(pVirtualVmdkLockDir2!=NULL) free(pVirtualVmdkLockDir2); - } - for(i=0;i32bit 20090308: * Added SetVdiFileHeaderData function to handle virtual image type specific data to be cached. This makes cache files independent from virtual image type 20090316: v0.2.0 released 20090327: v0.2.1 released * Fixed a bug in virtual write support. Checking whether data is cached didn't use semaphores. This could corrupt cache files when running multi-threaded. * Added IsVdiFileHeaderCached function to check whether VDI file header was already cached * Added IsBlockCached function to check whether a block was already cached 20090331: v0.2.2 released (Internal release) * Further changes to semaphores to fix write support bug. 20090410: v0.2.3 released * Reverted most of the fixes from v0.2.1 and v0.2.2 as those did not solve the write support bug. * Removed all semaphores * Added two pthread mutexes to protect virtual image and virtual info file. 20090508: * Configure script will now exit when needed libraries aren't found * Added support for newest libewf beta version 20090506 as it seems to reduce memory usage when working with EWF files by about 1/2. * Added LIBEWF_BETA define to adept source to new libewf API. * Added function InitVirtualVmdkFile to build a VmWare virtual disk descriptor file. 20090519: * Added function CreateVirtDir implementing FUSE's mkdir to allow VMWare to create his .vmdk.lck lock folder. Function does not allow to create other folders! * Changed cache file handling as VMDK caching will need new cache file structure incompatible to the old one. 20090522: v0.3.0 released * Added function DeleteVirtFile and DeleteVirtDir so VMWare can remove his lock directories and files. * Added function RenameVirtFile because VMWare needs to rename his lock files. * VMDK support should work now but descriptor file won't get cached as I didn't implement it yet. 20090604: * Added --cache commandline parameter doing the same as --rw. * Added --owcache commandline parameter doing the same as --rw but overwrites any existing cache data. This can be handy for debugging and testing purposes. * Added "vmdks" output type. Same as "vmdk" but generates a disk connected to the SCSI bus rather than the IDE bus. 20090710: v0.3.1 released 20090721: * Added function CheckFuseAllowOther to check wether FUSE supports the "-o allow_other" option. It is supported when "user_allow_other" is set in /etc/fuse.conf or when running xmount as root. * Automatic addition of FUSE's "-o allow_other" option if it is supported. * Added special "-o no_allow_other" command line parameter to disable automatic addition of the above option. * Reorganisation of FUSE's and xmount's command line options processing. * Added LogWarnMessage function to output a warning message. 20090722: * Added function CalculateInputImageHash to calculate an MD5 hash of the first input image's HASH_AMOUNT bytes of data. This hash is used as VDI creation UUID and will later be used to match cache files to input images. 20090724: v0.3.2 released 20090725: v0.4.0 released * Added AFF input image support. * Due to various problems with libewf and libaff packages (Mainly in Debian and Ubuntu), I decided to include them into xmount's source tree and link them in statically. This has the advantage that I can use whatever version I want. 20090727: v0.4.1 released * Added again the ability to compile xmount with shared libs as the Debian folks don't like the static ones :) 20090812: * Added TXMountConfData.OrigImageSize and TXMountConfData.VirtImageSize to save the size of the input and output image in order to avoid regetting it always from disk. 20090814: * Replaced all malloc and realloc occurences with the two macros XMOUNT_MALLOC and XMOUNT_REALLOC. 20090816: * Replaced where applicable all occurences of str(n)cpy or alike with their corresponding macros XMOUNT_STRSET, XMOUNT_STRCPY and XMOUNT_STRNCPY pendants. 20090907: v0.4.2 released - * Fixed a bug in VMDK lock file access. VirtualVmdkLockFileDataSize + * Fixed a bug in VMDK lock file access. glob_vmdk_lockfile_size wasn't reset to 0 when the file was deleted. * Fixed a bug in VMDK descriptor file access. Had to add - VirtualVmdkFileSize to track the size of this file as strlen was + glob_vmdk_file_size to track the size of this file as strlen was a bad idea :). 20100324: v0.4.3 released * Changed all header structs to prevent different sizes on i386 and amd64. See xmount.h for more details. 20100810: v0.4.4 released * Found a bug in InitVirtVdiHeader(). The 64bit values were addressed incorrectly while filled with rand(). This leads to an error message when trying to add a VDI file to VirtualBox 3.2.8. 20110210: * Adding subtype and fsname FUSE options in order to display mounted source in mount command output. 20110211: v0.4.5 released 20111011: * Changes to deal with libewf v2 API (Thx to Joachim Metz) 20111109: v0.4.6 released * Added support for DMG output type (actually a DD with .dmg file extension). This type is used as default output type when using xmount under Mac OS X. 20120130: v0.4.7 released * Made InitVirtImageInfoFile less picky about missing EWF infos. 20120507: * Added support for VHD output image as requested by various people. * Statically linked libs updated to 20120504 (libewf) and 3.7.0 (afflib). 20120510: v0.5.0 released * Added stbuf->st_blocks calculation for VHD images in function GetVirtFileAttr. This makes Windows not think the emulated file would be a sparse file. Sparse vhd files are not attachable in Windows. 20130726: v0.6.0 released * Added libaaff to replace libaff (thx to Guy Voncken). * Added libdd to replace raw dd input file handling and finally support split dd files (thx to Guy Voncken). 20140311: v0.7.0 released * Added libaewf (thx to Guy Voncken). */ diff --git a/trunk/src/xmount.h b/trunk/src/xmount.h index de378cd..bb4e3f1 100755 --- a/trunk/src/xmount.h +++ b/trunk/src/xmount.h @@ -1,513 +1,529 @@ /******************************************************************************* * xmount Copyright (c) 2008-2012 by Gillen Daniel * * * * 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 . * *******************************************************************************/ #define FUSE_USE_VERSION 26 #include #include #include #include +#include "../libxmount_input/libxmount_input.h" + #undef FALSE #undef TRUE #define FALSE 0 #define TRUE 1 #ifndef __APPLE__ #define FOPEN fopen64 #else // Apple does use fopen for fopen64 too #define FOPEN fopen #endif /* * Constants */ #define IMAGE_INFO_HEADER "The following values have been extracted from " \ "the mounted image file:\n\n" /* * Virtual image types */ -typedef enum TVirtImageType { +typedef enum e_VirtImageType { /** Virtual image is a DD file */ - TVirtImageType_DD, + VirtImageType_DD, /** Virtual image is a DMG file */ - TVirtImageType_DMG, + VirtImageType_DMG, /** Virtual image is a VDI file */ - TVirtImageType_VDI, + VirtImageType_VDI, /** Virtual image is a VMDK file (IDE bus)*/ - TVirtImageType_VMDK, + VirtImageType_VMDK, /** Virtual image is a VMDK file (SCSI bus)*/ - TVirtImageType_VMDKS, + VirtImageType_VMDKS, /** Virtual image is a VHD file*/ - TVirtImageType_VHD -} TVirtImageType; + VirtImageType_VHD +} te_VirtImageType; + +/* + * Infos about input libs + */ +typedef struct s_InputLib { + // Filename of lib + 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_InputLib, *pts_InputLib; /* * Various xmount runtime options */ -typedef struct TXMountConfData { +typedef struct s_XmountConfData { /** Input image type */ char *p_orig_image_type; /** Virtual image type */ - TVirtImageType VirtImageType; + te_VirtImageType VirtImageType; /** Enable debug output */ uint32_t Debug; /** Path of virtual image file */ char *pVirtualImagePath; /** Path of virtual VMDK file */ char *pVirtualVmdkPath; /** Path of virtual image info file */ char *pVirtualImageInfoPath; /** Enable virtual write support */ uint32_t Writable; /** Overwrite existing cache */ uint32_t OverwriteCache; /** Cache file to save changes to */ char *pCacheFile; /** Size of input image */ uint64_t OrigImageSize; /** Size of virtual image */ uint64_t VirtImageSize; /** MD5 hash of partial input image */ uint64_t InputHashLo; uint64_t InputHashHi; /** Offset */ uint64_t orig_img_offset; /** lib params */ char *p_lib_params; -} TXMountConfData; +} ts_XmountConfData; /* * VDI Binary File Header structure */ #define VDI_FILE_COMMENT "<<< This is a virtual VDI image >>>" #define VDI_HEADER_COMMENT "This VDI was emulated using xmount v" \ - PACKAGE_VERSION + XMOUNT_VERSION #define VDI_IMAGE_SIGNATURE 0xBEDA107F // 1:1 copy from hp #define VDI_IMAGE_VERSION 0x00010001 // Vers 1.1 #define VDI_IMAGE_TYPE_FIXED 0x00000002 // Type 2 (fixed size) #define VDI_IMAGE_FLAGS 0 #define VDI_IMAGE_BLOCK_SIZE (1024*1024) // 1 Megabyte -typedef struct TVdiFileHeader { +typedef struct s_VdiFileHeader { // ----- VDIPREHEADER ------ /** Just text info about image type, for eyes only. */ char szFileInfo[64]; /** The image signature (VDI_IMAGE_SIGNATURE). */ uint32_t u32Signature; /** The image version (VDI_IMAGE_VERSION). */ uint32_t u32Version; // ----- VDIHEADER1PLUS ----- /** Size of header structure in bytes. */ uint32_t cbHeader; /** The image type (VDI_IMAGE_TYPE_*). */ uint32_t u32Type; /** Image flags (VDI_IMAGE_FLAGS_*). */ uint32_t fFlags; /** Image comment. (UTF-8) */ char szComment[256]; /** Offset of Blocks array from the begining of image file. * Should be sector-aligned for HDD access optimization. */ uint32_t offBlocks; /** Offset of image data from the begining of image file. * Should be sector-aligned for HDD access optimization. */ uint32_t offData; /** Legacy image geometry (previous code stored PCHS there). */ /** Cylinders. */ uint32_t cCylinders; /** Heads. */ uint32_t cHeads; /** Sectors per track. */ uint32_t cSectors; /** Sector size. (bytes per sector) */ uint32_t cbSector; /** Was BIOS HDD translation mode, now unused. */ uint32_t u32Dummy; /** Size of disk (in bytes). */ uint64_t cbDisk; /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) Must be a power of 2! */ uint32_t cbBlock; /** Size of additional service information of every data block. * Prepended before block data. May be 0. * Should be a power of 2 and sector-aligned for optimization reasons. */ uint32_t cbBlockExtra; /** Number of blocks. */ uint32_t cBlocks; /** Number of allocated blocks. */ uint32_t cBlocksAllocated; /** UUID of image. */ uint64_t uuidCreate_l; uint64_t uuidCreate_h; /** UUID of image's last modification. */ uint64_t uuidModify_l; uint64_t uuidModify_h; /** Only for secondary images - UUID of previous image. */ uint64_t uuidLinkage_l; uint64_t uuidLinkage_h; /** Only for secondary images - UUID of previous image's last modification. */ uint64_t uuidParentModify_l; uint64_t uuidParentModify_h; /** Padding to get 512 byte alignment */ uint64_t padding0; uint64_t padding1; uint64_t padding2; uint64_t padding3; uint64_t padding4; uint64_t padding5; uint64_t padding6; -} __attribute__ ((packed)) TVdiFileHeader, *pTVdiFileHeader; +} __attribute__ ((packed)) ts_VdiFileHeader, *pts_VdiFileHeader; // /** The way the UUID is declared by the DCE specification. */ // struct // { // uint32_t u32TimeLow; // uint16_t u16TimeMid; // uint16_t u16TimeHiAndVersion; // uint8_t u8ClockSeqHiAndReserved; // uint8_t u8ClockSeqLow; // uint8_t au8Node[6]; // } Gen; /* * VHD Binary File footer structure * * At the time of writing, the specs could be found here: * http://www.microsoft.com/downloads/details.aspx? * FamilyID=C2D03242-2FFB-48EF-A211-F0C44741109E * * Warning: All values are big-endian! */ // #ifdef __LP64__ #define VHD_IMAGE_HVAL_COOKIE 0x78697463656E6F63 // "conectix" #else #define VHD_IMAGE_HVAL_COOKIE 0x78697463656E6F63LL #endif #define VHD_IMAGE_HVAL_FEATURES 0x02000000 #define VHD_IMAGE_HVAL_FILE_FORMAT_VERSION 0x00000100 #ifdef __LP64__ #define VHD_IMAGE_HVAL_DATA_OFFSET 0xFFFFFFFFFFFFFFFF #else #define VHD_IMAGE_HVAL_DATA_OFFSET 0xFFFFFFFFFFFFFFFFLL #endif #define VHD_IMAGE_HVAL_CREATOR_APPLICATION 0x746E6D78 // "xmnt" #define VHD_IMAGE_HVAL_CREATOR_VERSION 0x00000500 // This one is funny! According to VHD specs, I can only choose between Windows // and Macintosh. I'm going to choose the most common one. #define VHD_IMAGE_HVAL_CREATOR_HOST_OS 0x6B326957 // "Win2k" #define VHD_IMAGE_HVAL_DISK_TYPE 0x02000000 // Seconds from January 1st, 1970 to January 1st, 2000 #define VHD_IMAGE_TIME_CONVERSION_OFFSET 0x386D97E0 -typedef struct TVhdFileHeader { +typedef struct s_VhdFileHeader { uint64_t cookie; uint32_t features; uint32_t file_format_version; uint64_t data_offset; uint32_t creation_time; uint32_t creator_app; uint32_t creator_ver; uint32_t creator_os; uint64_t size_original; uint64_t size_current; uint16_t disk_geometry_c; uint8_t disk_geometry_h; uint8_t disk_geometry_s; uint32_t disk_type; uint32_t checksum; uint64_t uuid_l; uint64_t uuid_h; uint8_t saved_state; char Reserved[427]; -} __attribute__ ((packed)) TVhdFileHeader, *pTVhdFileHeader; +} __attribute__ ((packed)) ts_VhdFileHeader, *pts_VhdFileHeader; /* * Cache file block index array element */ #ifdef __LP64__ #define CACHE_BLOCK_FREE 0xFFFFFFFFFFFFFFFF #else #define CACHE_BLOCK_FREE 0xFFFFFFFFFFFFFFFFLL #endif -typedef struct TCacheFileBlockIndex { +typedef struct s_CacheFileBlockIndex { /** Set to 1 if block is assigned (This block has data in cache file) */ uint32_t Assigned; /** Offset to data in cache file */ uint64_t off_data; -} __attribute__ ((packed)) TCacheFileBlockIndex, *pTCacheFileBlockIndex; +} __attribute__ ((packed)) ts_CacheFileBlockIndex, *pts_CacheFileBlockIndex; /* * Cache file header structures */ #define CACHE_BLOCK_SIZE (1024*1024) // 1 megabyte #ifdef __LP64__ #define CACHE_FILE_SIGNATURE 0xFFFF746E756F6D78 // "xmount\xFF\xFF" #else #define CACHE_FILE_SIGNATURE 0xFFFF746E756F6D78LL #endif #define CUR_CACHE_FILE_VERSION 0x00000002 // Current cache file version #define HASH_AMOUNT (1024*1024)*10 // Amount of data used to construct a // "unique" hash for every input image // (10MByte) // Current header -typedef struct TCacheFileHeader { +typedef struct s_CacheFileHeader { /** Simple signature to identify cache files */ uint64_t FileSignature; /** Cache file version */ uint32_t CacheFileVersion; /** Cache block size */ uint64_t BlockSize; /** Total amount of cache blocks */ uint64_t BlockCount; /** Offset to the first block index array element */ uint64_t pBlockIndex; /** Set to 1 if VDI file header is cached */ uint32_t VdiFileHeaderCached; /** Offset to cached VDI file header */ uint64_t pVdiFileHeader; /** Set to 1 if VMDK file is cached */ uint32_t VmdkFileCached; /** Size of VMDK file */ uint64_t VmdkFileSize; /** Offset to cached VMDK file */ uint64_t pVmdkFile; /** Set to 1 if VHD header is cached */ uint32_t VhdFileHeaderCached; /** Offset to cached VHD header */ uint64_t pVhdFileHeader; /** Padding until offset 512 to ease further additions */ char HeaderPadding[432]; -} __attribute__ ((packed)) TCacheFileHeader, *pTCacheFileHeader; +} __attribute__ ((packed)) ts_CacheFileHeader, *pts_CacheFileHeader; // Old v1 header -typedef struct TCacheFileHeader_v1 { +typedef struct s_CacheFileHeader_v1 { /** Simple signature to identify cache files */ uint64_t FileSignature; /** Cache file version */ uint32_t CacheFileVersion; /** Total amount of cache blocks */ uint64_t BlockCount; /** Offset to the first block index array element */ uint64_t pBlockIndex; /** Set to 1 if VDI file header is cached */ uint32_t VdiFileHeaderCached; /** Offset to cached VDI file header */ uint64_t pVdiFileHeader; /** Set to 1 if VMDK file is cached */ -} TCacheFileHeader_v1, *pTCacheFileHeader_v1; +} ts_CacheFileHeader_v1, *pts_CacheFileHeader_v1; /* * Macros to ease debugging and error reporting */ #define LOG_ERROR(...) \ LogMessage("ERROR",(char*)__FUNCTION__,__LINE__,__VA_ARGS__); #define LOG_WARNING(...) \ LogMessage("WARNING",(char*)__FUNCTION__,__LINE__,__VA_ARGS__); #define LOG_DEBUG(...) { \ - if(XMountConfData.Debug) \ + if(glob_xmount_cfg.Debug) \ LogMessage("DEBUG",(char*)__FUNCTION__,__LINE__,__VA_ARGS__); \ } /* * Macros to alloc or realloc memory and check whether it worked */ #define XMOUNT_MALLOC(var,var_type,size) { \ (var)=(var_type)malloc(size); \ if((var)==NULL) { \ LOG_ERROR("Couldn't allocate memmory!\n"); \ exit(1); \ } \ } #define XMOUNT_REALLOC(var,var_type,size) { \ (var)=(var_type)realloc((var),size); \ if((var)==NULL) { \ LOG_ERROR("Couldn't allocate memmory!\n"); \ exit(1); \ } \ } /* * Macros for some often used string functions */ #define XMOUNT_STRSET(var1,var2) { \ XMOUNT_MALLOC(var1,char*,strlen(var2)+1) \ strcpy(var1,var2); \ } #define XMOUNT_STRNSET(var1,var2,size) { \ XMOUNT_MALLOC(var1,char*,(size)+1) \ strncpy(var1,var2,size); \ (var1)[size]='\0'; \ } #define XMOUNT_STRAPP(var1,var2) { \ XMOUNT_REALLOC(var1,char*,strlen(var1)+strlen(var2)+1) \ strcpy((var1)+strlen(var1),var2); \ } #define XMOUNT_STRNAPP(var1,var2,size) { \ XMOUNT_REALLOC(var1,char*,strlen(var1)+(size)+1) \ (var1)[strlen(var1)+(size)]='\0'; \ strncpy((var1)+strlen(var1),var2,size); \ } /* * Macros for endian conversions */ // First we need to have the bswap functions #if HAVE_BYTESWAP_H #include #elif defined(HAVE_ENDIAN_H) #include #elif defined(__APPLE__) #include #define bswap_16 OSSwapInt16 #define bswap_32 OSSwapInt32 #define bswap_64 OSSwapInt64 #else #define bswap_16(value) { \ ((((value) & 0xff) << 8) | ((value) >> 8)) \ } #define bswap_32(value) { \ (((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \ (uint32_t)bswap_16((uint16_t)((value) >> 16))) \ } #define bswap_64(value) { \ (((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) << 32) | \ (uint64_t)bswap_32((uint32_t)((value) >> 32))) \ } #endif // Next we need to know what endianess is used #if defined(__LITTLE_ENDIAN__) #define XMOUNT_BYTEORDER_LE #elif defined(__BIG_ENDIAN__) #define XMOUNT_BYTEORDER_BE #elif defined(__BYTE_ORDER__) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define XMOUNT_BYTEORDER_LE #else #define XMOUNT_BYTEORDER_BE #endif #endif // And finally we can define the macros #ifdef XMOUNT_BYTEORDER_LE #ifndef be16toh #define be16toh(x) bswap_16(x) #endif #ifndef htobe16 #define htobe16(x) bswap_16(x) #endif #ifndef be32toh #define be32toh(x) bswap_32(x) #endif #ifndef htobe32 #define htobe32(x) bswap_32(x) #endif #ifndef be64toh #define be64toh(x) bswap_64(x) #endif #ifndef htobe64 #define htobe64(x) bswap_64(x) #endif #ifndef le16toh #define le16toh(x) (x) #endif #ifndef htole16 #define htole16(x) (x) #endif #ifndef le32toh #define le32toh(x) (x) #endif #ifndef htole32 #define htole32(x) (x) #endif #ifndef le64toh #define le64toh(x) (x) #endif #ifndef htole64 #define htole64(x) (x) #endif #else #ifndef be16toh #define be16toh(x) (x) #endif #ifndef htobe16 #define htobe16(x) (x) #endif #ifndef be32toh #define be32toh(x) (x) #endif #ifndef htobe32 #define htobe32(x) (x) #endif #ifndef be64toh #define be64toh(x) (x) #endif #ifndef htobe64 #define htobe64(x) (x) #endif #ifndef le16toh #define le16toh(x) bswap_16(x) #endif #ifndef htole16 #define htole16(x) bswap_16(x) #endif #ifndef le32toh #define le32toh(x) bswap_32(x) #endif #ifndef htole32 #define htole32(x) bswap_32(x) #endif #ifndef le64toh #define le64toh(x) bswap_64(x) #endif #ifndef htole64 #define htole64(x) bswap_64(x) #endif #endif /* ----- Change history ----- 20090226: * Added change history information to this file. * Added TVirtImageType enum to identify virtual image type. * Added TOrigImageType enum to identify input image type. * Added TMountimgConfData struct to hold various mountimg runtime options. - * Renamed VDIFILEHEADER to TVdiFileHeader. + * Renamed VDIFILEHEADER to ts_VdiFileHeader. 20090228: * Added LOG_ERROR and LOG_DEBUG macros * Added defines for various static VDI header values * Added defines for TRUE and FALSE 20090307: * Added defines for various static cache file header values * Added VdiFileHeaderCached and pVdiFileHeader values to be able to cache the VDI file header separatly. 20090519: * Added new cache file header structure and moved old one to - TCacheFileHeader_v1. + ts_CacheFileHeader_v1. * New cache file structure includes VmdkFileCached and pVmdkFile to cache virtual VMDK file and makes room for further additions so current cache file version 2 cache files can be easily converted to newer ones. 20090814: * Added XMOUNT_MALLOC and XMOUNT_REALLOC macros. 20090816: * Added XMOUNT_STRSET, XMOUNT_STRNSET, XMOUNT_STRAPP and XMOUNT_STRNAPP macros. 20100324: * Added "__attribute__ ((packed))" to all header structs to prevent different sizes on i386 and amd64. 20111109: * Added TVirtImageType_DMG type. 20120130: * Added LOG_WARNING macro. - 20120507: * Added TVhdFileHeader structure. + 20120507: * Added ts_VhdFileHeader structure. 20120511: * Added endianess conversation macros */