Page MenuHomePhabricator

No OneTemporary

Size
210 KB
Referenced Files
None
Subscribers
None
diff --git a/codelite/xmount.project b/codelite/xmount.project
index 584d48e..2628180 100644
--- a/codelite/xmount.project
+++ b/codelite/xmount.project
@@ -1,251 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Project Name="xmount" InternalType="Console">
<Description/>
<Dependencies/>
<VirtualDirectory Name="src">
<File Name="../src/CMakeLists.txt"/>
<File Name="../src/macros.h"/>
<File Name="../src/md5.c"/>
<File Name="../src/md5.h"/>
<File Name="../src/xmount.c"/>
<File Name="../src/xmount.h"/>
<File Name="../src/xmount_fuse.c"/>
<File Name="../src/xmount_fuse.h"/>
+ <File Name="../src/xmount_input.c"/>
+ <File Name="../src/xmount_input.h"/>
+ <File Name="../src/xmount_morphing.c"/>
+ <File Name="../src/xmount_morphing.h"/>
+ <File Name="../src/xmount_output.c"/>
+ <File Name="../src/xmount_output.h"/>
+ <File Name="../src/xmount_cache.c"/>
+ <File Name="../src/xmount_cache.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount">
<File Name="../libxmount/endianness.h"/>
<File Name="../libxmount/libxmount.c"/>
<File Name="../libxmount/libxmount.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_input">
<File Name="../libxmount_input/CMakeLists.txt"/>
<File Name="../libxmount_input/libxmount_input.h"/>
<VirtualDirectory Name="libxmount_input_aaff">
<File Name="../libxmount_input/libxmount_input_aaff/CMakeLists.txt"/>
<File Name="../libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c"/>
<File Name="../libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_input_aewf">
<File Name="../libxmount_input/libxmount_input_aewf/CMakeLists.txt"/>
<File Name="../libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c"/>
<File Name="../libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_input_aff">
<File Name="../libxmount_input/libxmount_input_aff/CMakeLists.txt"/>
<File Name="../libxmount_input/libxmount_input_aff/libxmount_input_aff.c"/>
<File Name="../libxmount_input/libxmount_input_aff/libxmount_input_aff.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_input_ewf">
<File Name="../libxmount_input/libxmount_input_ewf/CMakeLists.txt"/>
<File Name="../libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c"/>
<File Name="../libxmount_input/libxmount_input_ewf/libxmount_input_ewf.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_input_raw">
<File Name="../libxmount_input/libxmount_input_raw/CMakeLists.txt"/>
<File Name="../libxmount_input/libxmount_input_raw/libxmount_input_raw.c"/>
<File Name="../libxmount_input/libxmount_input_raw/libxmount_input_raw.h"/>
</VirtualDirectory>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_morphing">
<VirtualDirectory Name="libxmount_morphing_combine">
<File Name="../libxmount_morphing/libxmount_morphing_combine/CMakeLists.txt"/>
<File Name="../libxmount_morphing/libxmount_morphing_combine/libxmount_morphing_combine.c"/>
<File Name="../libxmount_morphing/libxmount_morphing_combine/libxmount_morphing_combine.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_morphing_raid">
<File Name="../libxmount_morphing/libxmount_morphing_raid/CMakeLists.txt"/>
<File Name="../libxmount_morphing/libxmount_morphing_raid/libxmount_morphing_raid.c"/>
<File Name="../libxmount_morphing/libxmount_morphing_raid/libxmount_morphing_raid.h"/>
</VirtualDirectory>
<VirtualDirectory Name="libxmount_morphing_unallocated">
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/CMakeLists.txt"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/fat_functions.c"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/fat_functions.h"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.c"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.h"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.h"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated_retvalues.h"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/ntfs_functions.c"/>
<File Name="../libxmount_morphing/libxmount_morphing_unallocated/ntfs_functions.h"/>
</VirtualDirectory>
<File Name="../libxmount_morphing/CMakeLists.txt"/>
<File Name="../libxmount_morphing/libxmount_morphing.h"/>
</VirtualDirectory>
<Settings Type="Executable">
<GlobalSettings>
<Compiler Options="" C_Options="" Assembler="">
<IncludePath Value="."/>
</Compiler>
<Linker Options="">
<LibraryPath Value="."/>
</Linker>
<ResourceCompiler Options=""/>
</GlobalSettings>
<Configuration Name="Debug_Linux" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-g;-O0;-Wall" C_Options="-g;-O0;-Wall" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
</Compiler>
<Linker Options="" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./build-debug/HelloWorld" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="yes">
<Target Name="cmake">cmake ../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=1</Target>
<RebuildCommand>make clean &amp;&amp; make -j4</RebuildCommand>
<CleanCommand>make clean</CleanCommand>
<BuildCommand>make -j4</BuildCommand>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName>None</ThirdPartyToolName>
<WorkingDirectory>$(WorkspacePath)/build-debug</WorkingDirectory>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
<Configuration Name="Debug_Windows" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-g;-O0;-Wall" C_Options="-g;-O0;-Wall" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
</Compiler>
<Linker Options="" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./build-debug/HelloWorld" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="yes">
<Target Name="cmake">cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=1</Target>
<RebuildCommand>mingw32-make clean &amp;&amp; mingw32-make -j4</RebuildCommand>
<CleanCommand>mingw32-make clean</CleanCommand>
<BuildCommand>mingw32-make -j4</BuildCommand>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName>None</ThirdPartyToolName>
<WorkingDirectory>$(WorkspacePath)/build-debug</WorkingDirectory>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
<Configuration Name="Release_Linux" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-g;-O0;-Wall" C_Options="-g;-O0;-Wall" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
</Compiler>
<Linker Options="" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Release" Command="./build-release/HelloWorld" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="yes">
<Target Name="cmake">cmake ../.. -DCMAKE_EXPORT_COMPILE_COMMANDS=1</Target>
<RebuildCommand>make clean &amp;&amp; make -j4</RebuildCommand>
<CleanCommand>make clean</CleanCommand>
<BuildCommand>make -j4</BuildCommand>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName>None</ThirdPartyToolName>
<WorkingDirectory>$(WorkspacePath)/build-release</WorkingDirectory>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
<Configuration Name="Release_Windows" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-g;-O0;-Wall" C_Options="-g;-O0;-Wall" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
</Compiler>
<Linker Options="" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Release" Command="./build-release/HelloWorld" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="yes">
<Target Name="cmake">cmake .. -G "MinGW Makefiles" -DCMAKE_EXPORT_COMPILE_COMMANDS=1</Target>
<RebuildCommand>mingw32-make clean &amp;&amp; mingw32-make -j4</RebuildCommand>
<CleanCommand>mingw32-make clean</CleanCommand>
<BuildCommand>mingw32-make -j4</BuildCommand>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName>None</ThirdPartyToolName>
<WorkingDirectory>$(WorkspacePath)/build-release</WorkingDirectory>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
</Settings>
<VirtualDirectory Name="libxmount_output">
<File Name="../libxmount_output/CMakeLists.txt"/>
<File Name="../libxmount_output/libxmount_output.h"/>
<VirtualDirectory Name="libxmount_output_raw">
<File Name="../libxmount_output/libxmount_output_raw/CMakeLists.txt"/>
<File Name="../libxmount_output/libxmount_output_raw/libxmount_output_raw.c"/>
<File Name="../libxmount_output/libxmount_output_raw/libxmount_output_raw.h"/>
</VirtualDirectory>
</VirtualDirectory>
</CodeLite_Project>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a1445d1..e649374 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,22 +1,22 @@
if(NOT APPLE)
include_directories(${LIBFUSE_INCLUDE_DIRS})
set(LIBS ${LIBS} ${LIBFUSE_LIBRARIES})
else(NOT APPLE)
include_directories(${LIBOSXFUSE_INCLUDE_DIRS})
set(LIBS ${LIBS} ${LIBOSXFUSE_LIBRARIES})
link_directories(${LIBOSXFUSE_LIBRARY_DIRS})
endif(NOT APPLE)
set(LIBS ${LIBS} ${libgidafs_LIBRARIES})
include_directories(${libgidafs_INCLUDE_DIRS})
set(LIBS ${LIBS} "dl")
add_definitions(-DXMOUNT_LIBRARY_PATH="${CMAKE_INSTALL_PREFIX}/lib/xmount")
-add_executable(xmount xmount.c xmount_fuse.c md5.c ../libxmount/libxmount.c)
+add_executable(xmount xmount.c xmount_input.c xmount_morphing.c xmount_cache.c xmount_output.c xmount_fuse.c md5.c ../libxmount/libxmount.c)
target_link_libraries(xmount ${LIBS})
install(TARGETS xmount DESTINATION bin)
diff --git a/src/xmount.c b/src/xmount.c
index a60b4e1..cae2851 100755
--- a/src/xmount.c
+++ b/src/xmount.c
@@ -1,2930 +1,2170 @@
/*******************************************************************************
* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h> // For PRI*
#include <errno.h>
#include <dlfcn.h> // For dlopen, dlclose, dlsym
#include <dirent.h> // For opendir, readdir, closedir
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h> // For fstat
#include <sys/types.h>
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h> // For SEEK_* ??
#endif
#if !defined(__APPLE__) && defined(HAVE_GRP_H) && defined(HAVE_PWD_H)
#include <grp.h> // For getgrnam, struct group
#include <pwd.h> // For getpwuid, struct passwd
#endif
#include <pthread.h>
#include <time.h> // For time
#include "xmount.h"
#include "xmount_fuse.h"
#include "md5.h"
#include "macros.h"
#include "../libxmount/libxmount.h"
#define XMOUNT_COPYRIGHT_NOTICE \
"xmount v%s Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu>"
#define LOG_WARNING(...) { \
LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \
}
#define LOG_ERROR(...) { \
LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \
}
#define LOG_DEBUG(...) { \
LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \
}
+#define HASH_AMOUNT (1024*1024)*10 // Amount of data used to construct a
+ // "unique" hash for every input image
+ // (10MByte)
/*******************************************************************************
* Forward declarations
******************************************************************************/
/*
* Misc
*/
static void InitResources();
static void FreeResources();
static void PrintUsage(char*);
static void CheckFuseSettings();
static int ParseCmdLine(const int, char**);
static int ExtractOutputFileNames(char*);
static int CalculateInputImageHash(uint64_t*, uint64_t*);
-/*
- * Input
- */
-static int ReadInputImageData(pts_InputImage, char*, off_t, size_t, size_t*);
-/*
- * Morphing
- */
-static int GetMorphedImageSize(uint64_t*);
-static int ReadMorphedImageData(char*, off_t, size_t, size_t*);
-static int WriteMorphedImageData(const char*, off_t, size_t, size_t*);
-/*
- * Cache
- */
-static int InitCacheFile();
-static int UpdateBlockCacheIndex(uint64_t, t_CacheFileBlockIndex);
-
/*
* Info file
*/
static int InitInfoFile();
/*
* Lib related
*/
static int LoadLibs();
static int FindInputLib(pts_InputImage);
static int FindMorphingLib();
static int FindOutputLib();
static int SplitLibraryParameters(char*, uint32_t*, pts_LibXmountOptions**);
/*
* Functions exported to LibXmount_Morphing
*/
static int LibXmount_Morphing_ImageCount(uint64_t*);
static int LibXmount_Morphing_Size(uint64_t, uint64_t*);
static int LibXmount_Morphing_Read(uint64_t, char*, off_t, size_t, size_t*);
/*
* Functions exported to LibXmount_Output
*/
static int LibXmount_Output_Size(uint64_t*);
static int LibXmount_Output_Read(char*, off_t, size_t, size_t*);
static int LibXmount_Output_Write(char*, off_t, size_t, size_t*);
/*******************************************************************************
* Helper functions
******************************************************************************/
//! Print usage instructions (cmdline options etc..)
/*!
* \param p_prog_name Program name (argv[0])
*/
static void PrintUsage(char *p_prog_name) {
char *p_buf;
int first;
int ret;
printf("\n" XMOUNT_COPYRIGHT_NOTICE "\n",XMOUNT_VERSION);
printf("\nUsage:\n");
printf(" %s [fopts] <xopts> <mntp>\n\n",p_prog_name);
printf("Options:\n");
printf(" fopts:\n");
printf(" -d : Enable FUSE's and xmount's debug mode.\n");
printf(" -h : Display this help message.\n");
printf(" -s : Run single threaded.\n");
printf(" -o no_allow_other : Disable automatic addition of FUSE's "
"allow_other option.\n");
printf(" -o <fopts> : Specify fuse mount options. Will also disable "
"automatic addition of FUSE's allow_other option!\n");
printf("\n");
printf(" xopts:\n");
printf(" --cache <cfile> : Enable virtual write support.\n");
printf(" <cfile> specifies the cache file to use.\n");
printf(" --in <itype> <ifile> : Input image format and source file(s). "
"May be specified multiple times.\n");
printf(" <itype> can be ");
// List supported input formats
first=1;
for(uint32_t i=0;i<glob_xmount.input.libs_count;i++) {
p_buf=glob_xmount.input.pp_libs[i]->p_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(" <ifile> specifies the source file. If your image is split into "
"multiple files, you have to specify them all!\n");
printf(" --inopts <iopts> : Specify input library specific options.\n");
printf(" <iopts> specifies a comma separated list of key=value options. "
"See below for details.\n");
printf(" --info : Print out infos about used compiler and libraries.\n");
printf(" --morph <mtype> : Morphing function to apply to input image(s). "
"If not specified, defaults to \"combine\".\n");
printf(" <mtype> can be ");
// List supported morphing functions
first=1;
for(uint32_t i=0;i<glob_xmount.morphing.libs_count;i++) {
p_buf=glob_xmount.morphing.pp_libs[i]->p_supported_morphing_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(" --morphopts <mopts> : Specify morphing library specific "
"options.\n");
printf(" <mopts> specifies a comma separated list of key=value options. "
"See below for details.\n");
printf(" --offset <off> : Move the output image data start <off> bytes "
"into the input image(s).\n");
printf(" --out <otype> : Output image format. If not specified, "
"defaults to ");
#ifdef __APPLE__
printf("\"dmg\".\n");
#else
printf("\"raw\".\n");
#endif
printf(" <otype> can be ");
// List supported output formats
first=1;
for(uint32_t i=0;i<glob_xmount.output.libs_count;i++) {
p_buf=glob_xmount.output.pp_libs[i]->p_supported_output_formats;
while(*p_buf!='\0') {
if(first==1) {
printf("\"%s\"",p_buf);
first=0;
} else printf(", \"%s\"",p_buf);
p_buf+=(strlen(p_buf)+1);
}
}
printf(".\n");
printf(" --outopts <oopts> : Specify output library specific "
"options.\n");
printf(" --owcache <file> : Same as --cache <file> but overwrites "
"existing cache file.\n");
printf(" --sizelimit <size> : The data end of input image(s) is set to no "
"more than <size> bytes after the data start.\n");
printf(" --version : Same as --info.\n");
printf("\n");
printf(" mntp:\n");
printf(" Mount point where output image should be located.\n");
printf("\n");
printf("Infos:\n");
printf(" * One --in option and a mount point are mandatory!\n");
printf(" * If you specify --in multiple times, data from all images is "
"morphed into one output image using the specified morphing "
"function.\n");
printf(" * For VMDK emulation, you have to uncomment \"user_allow_other\" "
"in /etc/fuse.conf or run xmount as root.\n");
printf("\n");
printf("Input / Morphing library specific options:\n");
printf(" Input / Morphing libraries might support an own set of "
"options to configure / tune their behaviour.\n");
printf(" Libraries supporting this feature (if any) and their "
"options are listed below.\n");
printf("\n");
// List input, morphing and output lib options
for(uint32_t i=0;i<glob_xmount.input.libs_count;i++) {
ret=glob_xmount.input.pp_libs[i]->
lib_functions.OptionsHelp((const char**)&p_buf);
if(ret!=0) {
LOG_ERROR("Unable to get options help for library '%s': %s!\n",
glob_xmount.input.pp_libs[i]->p_name,
glob_xmount.input.pp_libs[i]->
lib_functions.GetErrorMessage(ret));
}
if(p_buf==NULL) continue;
printf(" - %s\n",glob_xmount.input.pp_libs[i]->p_name);
printf("%s",p_buf);
printf("\n");
ret=glob_xmount.input.pp_libs[i]->lib_functions.FreeBuffer(p_buf);
if(ret!=0) {
LOG_ERROR("Unable to free options help text from library '%s': %s!\n",
glob_xmount.input.pp_libs[i]->p_name,
glob_xmount.input.pp_libs[i]->
lib_functions.GetErrorMessage(ret));
}
}
for(uint32_t i=0;i<glob_xmount.morphing.libs_count;i++) {
ret=glob_xmount.morphing.pp_libs[i]->
lib_functions.OptionsHelp((const char**)&p_buf);
if(ret!=0) {
LOG_ERROR("Unable to get options help for library '%s': %s!\n",
glob_xmount.morphing.pp_libs[i]->p_name,
glob_xmount.morphing.pp_libs[i]->
lib_functions.GetErrorMessage(ret));
}
if(p_buf==NULL) continue;
printf(" - %s\n",glob_xmount.morphing.pp_libs[i]->p_name);
printf("%s",p_buf);
printf("\n");
}
for(uint32_t i=0;i<glob_xmount.output.libs_count;i++) {
ret=glob_xmount.output.pp_libs[i]->
lib_functions.OptionsHelp((const char**)&p_buf);
if(ret!=0) {
LOG_ERROR("Unable to get options help for library '%s': %s!\n",
glob_xmount.output.pp_libs[i]->p_name,
glob_xmount.output.pp_libs[i]->
lib_functions.GetErrorMessage(ret));
}
if(p_buf==NULL) continue;
printf(" - %s\n",glob_xmount.output.pp_libs[i]->p_name);
printf("%s",p_buf);
printf("\n");
}
}
//! Check fuse settings
/*!
* Check if FUSE allows us to pass the -o allow_other parameter. This only works
* if we are root or user_allow_other is set in /etc/fuse.conf.
*
* In addition, this function also checks if the user is member of the fuse
* group which is generally needed to use fuse at all.
*/
static void CheckFuseSettings() {
#if !defined(__APPLE__) && defined(HAVE_GRP_H) && defined(HAVE_PWD_H)
struct group *p_group;
struct passwd *p_passwd;
#endif
int found;
FILE *h_fuse_conf;
char line[256];
glob_xmount.may_set_fuse_allow_other=FALSE;
if(geteuid()==0) {
// Running as root, there should be no problems
glob_xmount.may_set_fuse_allow_other=TRUE;
return;
}
#if !defined(__APPLE__) && defined(HAVE_GRP_H) && defined(HAVE_PWD_H)
// Check if a fuse group exists and if so, make sure user is a member of it.
// Makes only sense on Linux because as far as I know osxfuse has no own group
p_group=getgrnam("fuse");
if(p_group!=NULL) {
// Get effective user name
p_passwd=getpwuid(geteuid());
if(p_passwd==NULL) {
printf("\nWARNING: Unable to determine your effective user name. If "
"mounting works, you can ignore this message.\n\n");
return;
}
// Check if user is member of fuse group
found=FALSE;
while(*(p_group->gr_mem)!=NULL) {
if(strcmp(*(p_group->gr_mem),p_passwd->pw_name)==0) {
found=TRUE;
break;
}
p_group->gr_mem++;
}
if(found==FALSE) {
printf("\nWARNING: You are not a member of the \"fuse\" group. This will "
"prevent you from mounting images using xmount. Please add "
"yourself to the \"fuse\" group using the command "
"\"sudo usermod -a -G fuse %s\" and reboot your system or "
"execute xmount as root.\n\n",
p_passwd->pw_name);
return;
}
} else {
printf("\nWARNING: Your system does not seem to have a \"fuse\" group. If "
"mounting works, you can ignore this message.\n\n");
}
#endif
// Read FUSE's config file /etc/fuse.conf and check for set user_allow_other
h_fuse_conf=(FILE*)FOPEN("/etc/fuse.conf","r");
if(h_fuse_conf!=NULL) {
// Search conf file for set user_allow_others
found=FALSE;
while(fgets(line,sizeof(line),h_fuse_conf)!=NULL) {
// TODO: This works as long as there is no other parameter beginning with
// "user_allow_other" :)
if(strncmp(line,"user_allow_other",16)==0) {
found=TRUE;
break;
}
}
fclose(h_fuse_conf);
if(found==TRUE) {
glob_xmount.may_set_fuse_allow_other=TRUE;
} else {
printf("\nWARNING: FUSE will not allow other users nor root to access "
"your virtual harddisk image. To change this behavior, please "
"add \"user_allow_other\" to /etc/fuse.conf or execute xmount "
"as root.\n\n");
}
} else {
printf("\nWARNING: Unable to open /etc/fuse.conf. If mounting works, you "
"can ignore this message. If you encounter issues, please create "
"the file and add a single line containing the string "
"\"user_allow_other\" or execute xmount as root.\n\n");
return;
}
}
//! Parse command line options
/*!
* \param argc Number of cmdline params
* \param pp_argv Array containing cmdline params
* \return TRUE on success, FALSE on error
*/
static int ParseCmdLine(const int argc, char **pp_argv) {
int i=1;
int FuseMinusOControl=TRUE;
int FuseAllowOther=TRUE;
int first;
char *p_buf;
pts_InputImage p_input_image=NULL;
int ret;
// add pp_argv[0] to FUSE's argv
XMOUNT_MALLOC(glob_xmount.pp_fuse_argv,char**,sizeof(char*));
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[0],pp_argv[0]);
glob_xmount.fuse_argc=1;
// Parse options
while(i<argc && *pp_argv[i]=='-') {
if(strlen(pp_argv[i])>1 && *(pp_argv[i]+1)!='-') {
// Options beginning with one - are mostly FUSE specific
if(strcmp(pp_argv[i],"-d")==0) {
// Enable FUSE's and xmount's debug mode
XMOUNT_REALLOC(glob_xmount.pp_fuse_argv,
char**,
(glob_xmount.fuse_argc+1)*sizeof(char*));
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc],
pp_argv[i])
glob_xmount.fuse_argc++;
glob_xmount.debug=TRUE;
} else if(strcmp(pp_argv[i],"-h")==0) {
// Print help message
PrintUsage(pp_argv[0]);
exit(0);
} else if(strcmp(pp_argv[i],"-o")==0) {
// Next parameter specifies fuse mount options
if((i+1)<argc) {
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(pp_argv[i],"no_allow_other")!=0) {
glob_xmount.fuse_argc+=2;
XMOUNT_REALLOC(glob_xmount.pp_fuse_argv,
char**,
glob_xmount.fuse_argc*sizeof(char*));
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-2],
pp_argv[i-1]);
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1],
pp_argv[i]);
FuseMinusOControl=FALSE;
} else FuseAllowOther=FALSE;
} else {
LOG_ERROR("Couldn't parse fuse mount options!\n")
return FALSE;
}
} else if(strcmp(pp_argv[i],"-s")==0) {
// Enable FUSE's single threaded mode
XMOUNT_REALLOC(glob_xmount.pp_fuse_argv,
char**,
(glob_xmount.fuse_argc+1)*sizeof(char*));
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc],
pp_argv[i]);
glob_xmount.fuse_argc++;
} else if(strcmp(pp_argv[i],"-V")==0) {
// Display FUSE version info
XMOUNT_REALLOC(glob_xmount.pp_fuse_argv,
char**,
(glob_xmount.fuse_argc+1)*sizeof(char*));
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc],
pp_argv[i]);
glob_xmount.fuse_argc++;
} else {
LOG_ERROR("Unknown command line option \"%s\"\n",pp_argv[i]);
return FALSE;
}
} else {
// Options beginning with -- are xmount specific
if(strcmp(pp_argv[i],"--cache")==0 /*|| strcmp(pp_argv[i],"--rw")==0*/) {
// Emulate writable access to mounted image
// Next parameter must be cache file to read/write changes from/to
if((i+1)<argc) {
i++;
XMOUNT_STRSET(glob_xmount.cache.p_cache_file,pp_argv[i])
glob_xmount.output.writable=TRUE;
} else {
LOG_ERROR("You must specify a cache file!\n")
return FALSE;
}
LOG_DEBUG("Enabling virtual write support using cache file \"%s\"\n",
glob_xmount.cache.p_cache_file)
} else if(strcmp(pp_argv[i],"--in")==0) {
// Specify input image type and source files
if((i+2)<argc) {
i++;
// Alloc and init new ts_InputImage struct
XMOUNT_MALLOC(p_input_image,pts_InputImage,sizeof(ts_InputImage));
XMOUNT_STRSET(p_input_image->p_type,pp_argv[i]);
p_input_image->pp_files=NULL;
p_input_image->p_functions=NULL;
p_input_image->p_handle=NULL;
// Parse input image filename(s) and add to p_input_image->pp_files
i++;
p_input_image->files_count=0;
while(i<(argc-1) && strncmp(pp_argv[i],"--",2)!=0) {
p_input_image->files_count++;
XMOUNT_REALLOC(p_input_image->pp_files,
char**,
p_input_image->files_count*sizeof(char*));
XMOUNT_STRSET(p_input_image->pp_files[p_input_image->files_count-1],
pp_argv[i]);
i++;
}
i--;
if(p_input_image->files_count==0) {
LOG_ERROR("No input files specified for \"--in %s\"!\n",
p_input_image->p_type)
free(p_input_image->p_type);
free(p_input_image);
return FALSE;
}
// Add input image struct to input image array
glob_xmount.input.images_count++;
XMOUNT_REALLOC(glob_xmount.input.pp_images,
pts_InputImage*,
glob_xmount.input.images_count*
sizeof(pts_InputImage));
glob_xmount.input.pp_images[glob_xmount.input.images_count-1]=
p_input_image;
} else {
LOG_ERROR("You must specify an input image type and source file!\n");
return FALSE;
}
} else if(strcmp(pp_argv[i],"--inopts")==0) {
// Set input lib options
if((i+1)<argc) {
i++;
if(glob_xmount.input.pp_lib_params==NULL) {
if(SplitLibraryParameters(pp_argv[i],
&(glob_xmount.input.lib_params_count),
&(glob_xmount.input.pp_lib_params)
)==FALSE)
{
LOG_ERROR("Unable to parse input library options '%s'!\n",
pp_argv[i]);
return FALSE;
}
} else {
LOG_ERROR("You can only specify --inopts once!")
return FALSE;
}
} else {
LOG_ERROR("You must specify special options!\n");
return FALSE;
}
} else if(strcmp(pp_argv[i],"--morph")==0) {
// Set morphing lib to use
if((i+1)<argc) {
i++;
if(glob_xmount.morphing.p_morph_type==NULL) {
XMOUNT_STRSET(glob_xmount.morphing.p_morph_type,pp_argv[i]);
} else {
LOG_ERROR("You can only specify --morph once!")
return FALSE;
}
} else {
LOG_ERROR("You must specify morphing type!\n");
return FALSE;
}
} else if(strcmp(pp_argv[i],"--morphopts")==0) {
// Set morphing lib options
if((i+1)<argc) {
i++;
if(glob_xmount.morphing.pp_lib_params==NULL) {
if(SplitLibraryParameters(pp_argv[i],
&(glob_xmount.morphing.lib_params_count),
&(glob_xmount.morphing.pp_lib_params)
)==FALSE)
{
LOG_ERROR("Unable to parse morphing library options '%s'!\n",
pp_argv[i]);
return FALSE;
}
} else {
LOG_ERROR("You can only specify --morphopts once!")
return FALSE;
}
} else {
LOG_ERROR("You must specify special morphing lib params!\n");
return FALSE;
}
} else if(strcmp(pp_argv[i],"--offset")==0) {
// Set input image offset
if((i+1)<argc) {
i++;
glob_xmount.input.image_offset=StrToUint64(pp_argv[i],&ret);
if(ret==0) {
LOG_ERROR("Unable to convert '%s' to a number!\n",pp_argv[i])
return FALSE;
}
} else {
LOG_ERROR("You must specify an offset!\n")
return FALSE;
}
LOG_DEBUG("Setting input image offset to \"%" PRIu64 "\"\n",
glob_xmount.input.image_offset)
} else if(strcmp(pp_argv[i],"--out")==0) {
// Set output lib to use
if((i+1)<argc) {
i++;
if(glob_xmount.output.p_output_format==NULL) {
XMOUNT_STRSET(glob_xmount.output.p_output_format,pp_argv[i]);
} else {
LOG_ERROR("You can only specify --out once!")
return FALSE;
}
} else {
LOG_ERROR("You must specify an output format!\n");
return FALSE;
}
} else if(strcmp(pp_argv[i],"--outopts")==0) {
// Set output lib options
if((i+1)<argc) {
i++;
if(glob_xmount.output.pp_lib_params==NULL) {
if(SplitLibraryParameters(pp_argv[i],
&(glob_xmount.output.lib_params_count),
&(glob_xmount.output.pp_lib_params)
)==FALSE)
{
LOG_ERROR("Unable to parse output library options '%s'!\n",
pp_argv[i]);
return FALSE;
}
} else {
LOG_ERROR("You can only specify --outopts once!")
return FALSE;
}
} else {
LOG_ERROR("You must specify special output lib params!\n");
return FALSE;
}
} else if(strcmp(pp_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((i+1)<argc) {
i++;
XMOUNT_STRSET(glob_xmount.cache.p_cache_file,pp_argv[i])
glob_xmount.output.writable=TRUE;
glob_xmount.cache.overwrite_cache=TRUE;
} else {
LOG_ERROR("You must specify a cache file!\n")
return FALSE;
}
LOG_DEBUG("Enabling virtual write support overwriting cache file %s\n",
glob_xmount.cache.p_cache_file)
} else if(strcmp(pp_argv[i],"--sizelimit")==0) {
// Set input image size limit
if((i+1)<argc) {
i++;
glob_xmount.input.image_size_limit=StrToUint64(pp_argv[i],&ret);
if(ret==0) {
LOG_ERROR("Unable to convert '%s' to a number!\n",pp_argv[i])
return FALSE;
}
} else {
LOG_ERROR("You must specify a size limit!\n")
return FALSE;
}
LOG_DEBUG("Setting input image size limit to \"%" PRIu64 "\"\n",
glob_xmount.input.image_size_limit)
} else if(strcmp(pp_argv[i],"--version")==0 ||
strcmp(pp_argv[i],"--info")==0)
{
// Print xmount info
printf(XMOUNT_COPYRIGHT_NOTICE "\n\n",XMOUNT_VERSION);
#ifdef __GNUC__
printf(" compile timestamp: %s %s\n",__DATE__,__TIME__);
printf(" gcc version: %s\n",__VERSION__);
#endif
printf(" loaded input libraries:\n");
for(uint32_t ii=0;ii<glob_xmount.input.libs_count;ii++) {
printf(" - %s supporting ",glob_xmount.input.pp_libs[ii]->p_name);
p_buf=glob_xmount.input.pp_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(" loaded morphing libraries:\n");
for(uint32_t ii=0;ii<glob_xmount.morphing.libs_count;ii++) {
printf(" - %s supporting ",
glob_xmount.morphing.pp_libs[ii]->p_name);
p_buf=glob_xmount.morphing.pp_libs[ii]->p_supported_morphing_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(" loaded output libraries:\n");
for(uint32_t ii=0;ii<glob_xmount.output.libs_count;ii++) {
printf(" - %s supporting ",
glob_xmount.output.pp_libs[ii]->p_name);
p_buf=glob_xmount.output.pp_libs[ii]->p_supported_output_formats;
first=TRUE;
while(*p_buf!='\0') {
if(first) {
printf("\"%s\"",p_buf);
first=FALSE;
} else printf(", \"%s\"",p_buf);
p_buf+=(strlen(p_buf)+1);
}
printf("\n");
}
printf("\n");
exit(0);
} else {
LOG_ERROR("Unknown command line option \"%s\"\n",pp_argv[i]);
return FALSE;
}
}
i++;
}
// Extract mountpoint
if(i==(argc-1)) {
XMOUNT_STRSET(glob_xmount.p_mountpoint,pp_argv[argc-1])
XMOUNT_REALLOC(glob_xmount.pp_fuse_argv,
char**,
(glob_xmount.fuse_argc+1)*sizeof(char*));
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc],
glob_xmount.p_mountpoint);
glob_xmount.fuse_argc++;
} else {
LOG_ERROR("No mountpoint specified!\n")
return FALSE;
}
if(FuseMinusOControl==TRUE) {
// We control the -o flag, set subtype, fsname and allow_other options
glob_xmount.fuse_argc+=2;
XMOUNT_REALLOC(glob_xmount.pp_fuse_argv,
char**,
glob_xmount.fuse_argc*sizeof(char*));
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-2],"-o");
XMOUNT_STRSET(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1],
"subtype=xmount");
if(glob_xmount.input.images_count!=0) {
// Set name of first source file as fsname
XMOUNT_STRAPP(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1],
",fsname='");
// If possible, use full path
p_buf=realpath(glob_xmount.input.pp_images[0]->pp_files[0],NULL);
if(p_buf==NULL) {
XMOUNT_STRSET(p_buf,glob_xmount.input.pp_images[0]->pp_files[0]);
}
// Make sure fsname does not include some forbidden chars
for(uint32_t i=0;i<strlen(p_buf);i++) {
if(p_buf[i]=='\'') p_buf[i]='_';
}
// Set fsname
XMOUNT_STRAPP(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1],
p_buf);
XMOUNT_STRAPP(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1],
"'");
free(p_buf);
}
if(FuseAllowOther==TRUE) {
// Add "allow_other" option if allowed
if(glob_xmount.may_set_fuse_allow_other) {
XMOUNT_STRAPP(glob_xmount.pp_fuse_argv[glob_xmount.fuse_argc-1],
",allow_other");
}
}
}
return TRUE;
}
//! Extract output file name from input image name
/*!
* \param p_orig_name Name of input image (may include a path)
* \return TRUE on success, FALSE on error
*/
static int ExtractOutputFileNames(char *p_orig_name) {
char *tmp;
// Truncate any leading path
tmp=strrchr(p_orig_name,'/');
if(tmp!=NULL) p_orig_name=tmp+1;
// Extract file extension
tmp=strrchr(p_orig_name,'.');
// Set leading '/'
XMOUNT_STRSET(glob_xmount.output.p_virtual_image_path,"/");
XMOUNT_STRSET(glob_xmount.output.p_info_path,"/");
// Copy filename
if(tmp==NULL) {
// Input image filename has no extension
XMOUNT_STRAPP(glob_xmount.output.p_virtual_image_path,p_orig_name);
XMOUNT_STRAPP(glob_xmount.output.p_info_path,p_orig_name);
XMOUNT_STRAPP(glob_xmount.output.p_info_path,".info");
} else {
XMOUNT_STRNAPP(glob_xmount.output.p_virtual_image_path,p_orig_name,
strlen(p_orig_name)-strlen(tmp));
XMOUNT_STRNAPP(glob_xmount.output.p_info_path,p_orig_name,
strlen(p_orig_name)-strlen(tmp));
XMOUNT_STRAPP(glob_xmount.output.p_info_path,".info");
}
// Add virtual file extensions
// TODO: Get from output lib and add
//XMOUNT_STRAPP(glob_xmount.output.p_virtual_image_path,".dd");
LOG_DEBUG("Set virtual image name to \"%s\"\n",
glob_xmount.output.p_virtual_image_path);
LOG_DEBUG("Set virtual image info name to \"%s\"\n",
glob_xmount.output.p_info_path);
return TRUE;
}
-//! Get size of morphed image
-/*!
- * \param p_size Buf to save size to
- * \return TRUE on success, FALSE on error
- */
-static int GetMorphedImageSize(uint64_t *p_size) {
- int ret;
-
- ret=glob_xmount.morphing.p_functions->Size(glob_xmount.morphing.p_handle,
- p_size);
- if(ret!=0) {
- LOG_ERROR("Unable to get morphed image size: %s!\n",
- glob_xmount.morphing.p_functions->GetErrorMessage(ret));
- return FALSE;
- }
-
- return TRUE;
-}
-
-//! Get size of output image
-/*!
- * \param p_size Pointer to an uint64_t to which the size will be written to
- * \return TRUE on success, FALSE on error
- */
-int GetOutputImageSize(uint64_t *p_size) {
- int ret;
- uint64_t output_image_size=0;
-
- if(glob_xmount.output.image_size!=0) {
- *p_size=glob_xmount.output.image_size;
- return TRUE;
- }
-
- ret=glob_xmount.output.p_functions->Size(glob_xmount.output.p_handle,
- &output_image_size);
- if(ret!=0) {
- LOG_ERROR("Couldn't get output image size!\n")
- return FALSE;
- }
-
- glob_xmount.output.image_size=output_image_size;
- *p_size=output_image_size;
- return TRUE;
-}
-
-//! Read data from input image
-/*!
- * \param p_image Image from which to read data
- * \param p_buf Pointer to buffer to write read data to (must be preallocated!)
- * \param offset Offset at which data should be read
- * \param size Size of data which should be read (size of buffer)
- * \param p_read Number of read bytes on success
- * \return 0 on success, negated error code on error
- */
-static int ReadInputImageData(pts_InputImage p_image,
- char *p_buf,
- off_t offset,
- size_t size,
- size_t *p_read)
-{
- int ret;
- size_t to_read=0;
- int read_errno=0;
-
- LOG_DEBUG("Reading %zu bytes at offset %zu from input image '%s'\n",
- size,
- offset,
- p_image->pp_files[0]);
-
- // Make sure we aren't reading past EOF of image file
- if(offset>=p_image->size) {
- // Offset is beyond image size
- LOG_DEBUG("Offset %zu is at / beyond size of input image '%s'\n",
- offset,
- p_image->pp_files[0]);
- *p_read=0;
- return 0;
- }
- if(offset+size>p_image->size) {
- // Attempt to read data past EOF of image file
- to_read=p_image->size-offset;
- LOG_DEBUG("Attempt to read data past EOF of input image '%s'. "
- "Correcting size from %zu to %zu\n",
- p_image->pp_files[0],
- size,
- to_read);
- } else to_read=size;
-
- // Read data from image file (adding input image offset if one was specified)
- ret=p_image->p_functions->Read(p_image->p_handle,
- p_buf,
- offset+glob_xmount.input.image_offset,
- to_read,
- p_read,
- &read_errno);
- if(ret!=0) {
- LOG_ERROR("Couldn't read %zu bytes at offset %zu from input image "
- "'%s': %s!\n",
- to_read,
- offset,
- p_image->pp_files[0],
- p_image->p_functions->GetErrorMessage(ret));
- if(read_errno==0) return -EIO;
- else return (read_errno*(-1));
- }
-
- return 0;
-}
-
-//! Read data from morphed image
-/*!
- * \param p_buf Pointer to buffer to write read data to (must be preallocated!)
- * \param offset Offset at which data should be read
- * \param size Size of data which should be read (size of buffer)
- * \param p_read Number of read bytes on success
- * \return TRUE on success, negated error code on error
- */
-static int ReadMorphedImageData(char *p_buf,
- off_t offset,
- size_t size,
- size_t *p_read)
-{
- uint64_t block_off=0;
- uint64_t cur_block=0;
- uint64_t cur_to_read=0;
- uint64_t image_size=0;
- size_t read=0;
- size_t to_read=0;
- int ret;
- teGidaFsError gidafs_ret=eGidaFsError_None;
-
- // Make sure we aren't reading past EOF of image file
- if(GetMorphedImageSize(&image_size)!=TRUE) {
- LOG_ERROR("Couldn't get size of morphed image!\n");
- return -EIO;
- }
- if(offset>=image_size) {
- // Offset is beyond image size
- LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset);
- *p_read=0;
- return FALSE;
- }
- if(offset+size>image_size) {
- // Attempt to read data past EOF of morphed image file
- to_read=image_size-offset;
- LOG_DEBUG("Attempt to read data past EOF of morphed image. Corrected size "
- "from %zu to %" PRIu64 ".\n",
- size,
- to_read);
- } else to_read=size;
-
- // Calculate block to start reading data from
- cur_block=offset/CACHE_BLOCK_SIZE;
- block_off=offset%CACHE_BLOCK_SIZE;
-
- // Read image data
- while(to_read!=0) {
- // Calculate how many bytes we have to read from this block
- if(block_off+to_read>CACHE_BLOCK_SIZE) {
- cur_to_read=CACHE_BLOCK_SIZE-block_off;
- } else cur_to_read=to_read;
-
- // Check if block is cached
- if(glob_xmount.output.writable==TRUE &&
- glob_xmount.cache.p_block_cache_index[cur_block]!=CACHE_BLOCK_FREE)
- {
- // Write support enabled and need to read altered data from cachefile
- LOG_DEBUG("Reading %zu bytes at offset %" PRIu64
- " from block cache file\n",
- cur_to_read,
- glob_xmount.cache.p_block_cache_index[cur_block]+block_off)
-
- gidafs_ret=GidaFsLib_ReadFile(glob_xmount.cache.h_cache_file,
- glob_xmount.cache.h_block_cache,
- glob_xmount.cache.
- p_block_cache_index[cur_block]+block_off,
- cur_to_read,
- p_buf,
- &read);
- if(gidafs_ret!=eGidaFsError_None || read!=cur_to_read) {
- LOG_ERROR("Unable to read cached data from block %" PRIu64
- ": Error code %u!\n",
- cur_block,
- gidafs_ret);
- return -EIO;
- }
- } else {
- // No write support or data not cached
- ret=glob_xmount.morphing.p_functions->Read(glob_xmount.morphing.p_handle,
- p_buf,
- (cur_block*CACHE_BLOCK_SIZE)+
- block_off,
- cur_to_read,
- &read);
- if(ret!=0 || read!=cur_to_read) {
- LOG_ERROR("Couldn't read %zu bytes at offset %zu from morphed image: "
- "%s!\n",
- cur_to_read,
- offset,
- glob_xmount.morphing.p_functions->GetErrorMessage(ret));
- return -EIO;
- }
- LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64
- " from morphed image file\n",
- cur_to_read,
- (cur_block*CACHE_BLOCK_SIZE)+block_off);
- }
-
- cur_block++;
- block_off=0;
- p_buf+=cur_to_read;
- to_read-=cur_to_read;
- }
-
- *p_read=to_read;
- return TRUE;
-}
-
-//! Write data to morphed image
-/*!
- * \param p_buf Buffer with data to write
- * \param offset Offset to start writing at
- * \param count Amount of bytes to write
- * \param p_written Amount of successfully written bytes
- * \return TRUE on success, negated error code on error
- */
-static int WriteMorphedImageData(const char *p_buf,
- off_t offset,
- size_t count,
- size_t *p_written)
-{
- uint64_t block_off=0;
- uint64_t cur_block=0;
- uint64_t cur_to_read=0;
- uint64_t cur_to_write=0;
- uint64_t image_size=0;
- size_t written=0;
- size_t to_write=0;
- int ret;
- teGidaFsError gidafs_ret=eGidaFsError_None;
- char *p_buf2=NULL;
-
- // Make sure we aren't writing past EOF of image file
- if(GetMorphedImageSize(&image_size)!=TRUE) {
- LOG_ERROR("Couldn't get size of morphed image!\n");
- return -EIO;
- }
- if(offset>=image_size) {
- // Offset is beyond image size
- LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset);
- *p_written=0;
- return 0;
- }
- if(offset+count>image_size) {
- // Attempt to write data past EOF of morphed image file
- to_write=image_size-offset;
- LOG_DEBUG("Attempt to write data past EOF of morphed image. Corrected size "
- "from %zu to %" PRIu64 ".\n",
- count,
- to_write);
- } else to_write=count;
-
- // Calculate block to start writing data to
- cur_block=offset/CACHE_BLOCK_SIZE;
- block_off=offset%CACHE_BLOCK_SIZE;
-
- while(to_write!=0) {
- // Calculate how many bytes we have to write to this block
- if(block_off+to_write>CACHE_BLOCK_SIZE) {
- cur_to_write=CACHE_BLOCK_SIZE-block_off;
- } else cur_to_write=to_write;
-
- // Check if block is cached
- if(glob_xmount.cache.p_block_cache_index[cur_block]!=CACHE_BLOCK_FREE) {
- // Block is cached
- gidafs_ret=GidaFsLib_WriteFile(glob_xmount.cache.h_cache_file,
- glob_xmount.cache.h_block_cache,
- glob_xmount.cache.
- p_block_cache_index[cur_block]+block_off,
- cur_to_write,
- p_buf,
- &written);
- if(gidafs_ret!=eGidaFsError_None || written!=cur_to_write) {
- LOG_ERROR("Unable to write data to cached block %" PRIu64
- ": Error code %u!\n",
- cur_block,
- gidafs_ret);
- return -EIO;
- }
-
- LOG_DEBUG("Wrote %" PRIu64 " bytes at offset %" PRIu64
- " to block cache file\n",
- cur_to_write,
- glob_xmount.cache.p_block_cache_index[cur_block]+block_off);
- } else {
- // Uncached block. Need to cache entire new block
- // Prepare new write buffer
- XMOUNT_MALLOC(p_buf2,char*,CACHE_BLOCK_SIZE);
- memset(p_buf2,0x00,CACHE_BLOCK_SIZE);
-
- // Read full block from morphed image
- cur_to_read=CACHE_BLOCK_SIZE;
- if((cur_block*CACHE_BLOCK_SIZE)+CACHE_BLOCK_SIZE>image_size) {
- cur_to_read=CACHE_BLOCK_SIZE-(((cur_block*CACHE_BLOCK_SIZE)+
- CACHE_BLOCK_SIZE)-image_size);
- }
- ret=glob_xmount.morphing.p_functions->Read(glob_xmount.morphing.p_handle,
- p_buf2,
- cur_block*CACHE_BLOCK_SIZE,
- cur_to_read,
- &read);
- if(ret!=0 || read!=cur_to_read) {
- LOG_ERROR("Couldn't read %" PRIu64 " bytes at offset %zu "
- "from morphed image: %s!\n",
- cur_to_read,
- offset,
- glob_xmount.morphing.p_functions->GetErrorMessage(ret));
- XMOUNT_FREE(p_buf2);
- return -EIO;
- }
-
- // Set changed data
- memcpy(p_buf2+block_off,p_buf,cur_to_write);
-
- // Write new block to block cache
- // Get current block cache size
- gidafs_ret=GidaFsLib_GetFileSize(glob_xmount.cache.h_cache_file,
- glob_xmount.cache.h_block_cache,
- &(glob_xmount.cache.
- p_block_cache_index[cur_block]));
- if(gidafs_ret!=eGidaFsError_None) {
- LOG_ERROR("Unable to get current block cache size: Error code %u!\n",
- gidafs_ret);
- XMOUNT_FREE(p_buf2);
- return -EIO;
- }
- // Append new block
- gidafs_ret=GidaFsLib_WriteFile(glob_xmount.cache.h_cache_file,
- glob_xmount.cache.h_block_cache,
- glob_xmount.cache.
- p_block_cache_index[cur_block],
- CACHE_BLOCK_SIZE,
- p_buf2,
- &written);
- if(gidafs_ret!=eGidaFsError_None || written!=cur_to_write) {
- LOG_ERROR("Unable to write data to cached block %" PRIu64
- ": Error code %u!\n",
- cur_block,
- gidafs_ret);
- XMOUNT_FREE(p_buf2);
- return -EIO;
- }
- XMOUNT_FREE(p_buf2);
- // Update on-disk block cache index
- ret=UpdateBlockCacheIndex(cur_block,
- glob_xmount.cache.p_block_cache_index[
- cur_block]);
- if(ret!=TRUE) {
- LOG_ERROR("Unable to update block cache index %" PRIu64
- ": Error code %u!\n",
- cur_block,
- gidafs_ret);
- return -EIO;
- }
-
- LOG_DEBUG("Updated cache file block index: Number=%" PRIu64
- ", Data offset=%" PRIu64 "\n",
- cur_block,
- glob_xmount.cache.p_block_cache_index[cur_block]);
- }
-
- block_off=0;
- cur_block++;
- p_buf+=cur_to_write;
- to_write-=cur_to_write;
- }
-
- *p_written=to_write;
- return TRUE;
-}
-
-//! Read data from output image
-/*!
- * \param p_buf Pointer to buffer to write read data to
- * \param offset Offset at which data should be read
- * \param size Size of data which should be read
- * \return Number of read bytes on success or negated error code on error
- */
-int ReadOutputImageData(char *p_buf, off_t offset, size_t size) {
- uint64_t output_image_size;
- size_t read=0;
- int ret;
-
- // Get output image size
- if(GetOutputImageSize(&output_image_size)!=TRUE) {
- LOG_ERROR("Couldn't get size of output image!\n")
- return -EIO;
- }
-
- // Make sure request is within output image
- if(offset>=output_image_size) {
- LOG_DEBUG("Offset %zu is at / beyond size of output image.\n",offset);
- return 0;
- }
- if(offset+size>output_image_size) {
- LOG_DEBUG("Attempt to read data past EOF of output image. Correcting size "
- "from %zu to %zu.\n",
- size,
- output_image_size-offset);
- size=output_image_size-offset;
- }
-
- // Read data
- ret=glob_xmount.output.p_functions->Read(glob_xmount.output.p_handle,
- p_buf,
- offset,
- size,
- &read);
- if(ret!=0) {
- LOG_ERROR("Unable to read %zu bytes at offset %zu from output image!\n",
- size,
- offset)
- return ret;
- } else if(read!=size) {
- LOG_WARNING("Unable to read all requested data from output image!\n")
- return read;
- }
-
- return size;
-}
-
-//! Write data to output image
-/*!
- * \param p_buf Buffer with data to write
- * \param offset Offset to write to
- * \param size Amount of bytes to write
- * \return Number of written bytes on success or "-1" on error
- */
-int WriteOutputImageData(const char *p_buf, off_t offset, size_t size) {
- uint64_t output_image_size;
- int ret;
- size_t written;
-
- // Get output image size
- if(!GetOutputImageSize(&output_image_size)) {
- LOG_ERROR("Couldn't get output image size!\n")
- return -1;
- }
-
- // Make sure write is within output image
- if(offset>=output_image_size) {
- LOG_ERROR("Attempt to write beyond EOF of output image file!\n")
- return -1;
- }
- if(offset+size>output_image_size) {
- LOG_DEBUG("Attempt to write past EOF of output image file. Correcting size "
- "from %zu to %zu.\n",
- size,
- output_image_size-offset);
- size=output_image_size-offset;
- }
-
- ret=glob_xmount.output.p_functions->Write(glob_xmount.output.p_handle,
- p_buf,
- offset,
- size,
- &written);
- if(ret!=0) {
- LOG_ERROR("Unable to write %zu bytes at offset %zu to output image!\n",
- offset,
- size)
- return ret;
- } else if(written!=size) {
- LOG_WARNING("Unable to write all requested data to output image!\n")
- }
-
- return size;
-}
-
//! Calculates an MD5 hash of the first HASH_AMOUNT bytes of the input image
/*!
* \param p_hash_low Pointer to the lower 64 bit of the hash
* \param p_hash_high Pointer to the higher 64 bit of the hash
* \return TRUE on success, FALSE on error
*/
static int CalculateInputImageHash(uint64_t *p_hash_low,
uint64_t *p_hash_high)
{
char hash[16];
md5_state_t md5_state;
char *p_buf;
int ret;
size_t read_data;
XMOUNT_MALLOC(p_buf,char*,HASH_AMOUNT*sizeof(char));
ret=ReadMorphedImageData(p_buf,0,HASH_AMOUNT,&read_data);
if(ret!=TRUE || read_data==0) {
LOG_ERROR("Couldn't read data from morphed image file!\n")
free(p_buf);
return FALSE;
}
// Calculate MD5 hash
md5_init(&md5_state);
md5_append(&md5_state,(const md5_byte_t*)p_buf,read_data);
md5_finish(&md5_state,(md5_byte_t*)hash);
// Convert MD5 hash into two 64bit integers
*p_hash_low=*((uint64_t*)hash);
*p_hash_high=*((uint64_t*)(hash+8));
free(p_buf);
return TRUE;
}
//! Create info file
/*!
* \return TRUE on success, FALSE on error
*/
static int InitInfoFile() {
int ret;
char *p_buf;
// Start with static input header
XMOUNT_MALLOC(glob_xmount.output.p_info_file,
char*,
strlen(IMAGE_INFO_INPUT_HEADER)+1);
strncpy(glob_xmount.output.p_info_file,
IMAGE_INFO_INPUT_HEADER,
strlen(IMAGE_INFO_INPUT_HEADER)+1);
// Get and add infos from input lib(s)
for(uint64_t i=0;i<glob_xmount.input.images_count;i++) {
ret=glob_xmount.input.pp_images[i]->p_functions->
GetInfofileContent(glob_xmount.input.pp_images[i]->p_handle,(const char**)&p_buf);
if(ret!=0) {
LOG_ERROR("Unable to get info file content for image '%s': %s!\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.pp_images[i]->p_functions->
GetErrorMessage(ret));
return FALSE;
}
// Add infos to main buffer and free p_buf
XMOUNT_STRAPP(glob_xmount.output.p_info_file,"\n--> ");
XMOUNT_STRAPP(glob_xmount.output.p_info_file,
glob_xmount.input.pp_images[i]->pp_files[0]);
XMOUNT_STRAPP(glob_xmount.output.p_info_file," <--\n");
if(p_buf!=NULL) {
XMOUNT_STRAPP(glob_xmount.output.p_info_file,p_buf);
glob_xmount.input.pp_images[i]->p_functions->FreeBuffer(p_buf);
} else {
XMOUNT_STRAPP(glob_xmount.output.p_info_file,"None\n");
}
}
// Add static morphing header
XMOUNT_STRAPP(glob_xmount.output.p_info_file,IMAGE_INFO_MORPHING_HEADER);
// Get and add infos from morphing lib
ret=glob_xmount.morphing.p_functions->
GetInfofileContent(glob_xmount.morphing.p_handle,(const char**)&p_buf);
if(ret!=0) {
LOG_ERROR("Unable to get info file content from morphing lib: %s!\n",
glob_xmount.morphing.p_functions->GetErrorMessage(ret));
return FALSE;
}
if(p_buf!=NULL) {
XMOUNT_STRAPP(glob_xmount.output.p_info_file,p_buf);
glob_xmount.morphing.p_functions->FreeBuffer(p_buf);
} else {
XMOUNT_STRAPP(glob_xmount.output.p_info_file,"None\n");
}
return TRUE;
}
-//! Create / load cache file to enable virtual write support
-/*!
- * \return TRUE on success, FALSE on error
- */
-static int InitCacheFile() {
- uint64_t blockindex_size=0;
- uint64_t image_size=0;
- uint64_t read=0;
- uint8_t is_new_cache_file=0;
- teGidaFsError gidafs_ret=eGidaFsError_None;
-
- // Get input image size for later use
- if(!GetMorphedImageSize(&image_size)) {
- LOG_ERROR("Couldn't get morphed image size!\n")
- return FALSE;
- }
-
- if(!glob_xmount.cache.overwrite_cache) {
- // Try to open an existing cache file or create a new one
- gidafs_ret=GidaFsLib_OpenFs(&(glob_xmount.cache.h_cache_file),
- glob_xmount.cache.p_cache_file);
- if(gidafs_ret!=eGidaFsError_None &&
- gidafs_ret!=eGidaFsError_FailedOpeningFsFile)
- {
- // TODO: Check for old cache file type and inform user it isn't supported
- // anymore!
- LOG_ERROR("Couldn't open cache file '%s': Error code %u!\n",
- glob_xmount.cache.p_cache_file,
- gidafs_ret)
- return FALSE;
- } else if(gidafs_ret==eGidaFsError_FailedOpeningFsFile) {
- // Unable to open cache file. It might simply not exist.
- LOG_DEBUG("Cache file '%s' does not exist. Creating new one\n",
- glob_xmount.cache.p_cache_file)
- gidafs_ret=GidaFsLib_NewFs(&(glob_xmount.cache.h_cache_file),
- glob_xmount.cache.p_cache_file,
- 0);
- if(gidafs_ret!=eGidaFsError_None) {
- // There is really a problem opening/creating the file
- LOG_ERROR("Couldn't open cache file '%s': Error code %u!\n",
- glob_xmount.cache.p_cache_file,
- gidafs_ret)
- return FALSE;
- }
- is_new_cache_file=1;
- }
- } else {
- // Overwrite existing cache file or create a new one
- gidafs_ret=GidaFsLib_NewFs(&(glob_xmount.cache.h_cache_file),
- glob_xmount.cache.p_cache_file,
- 0);
- if(gidafs_ret!=eGidaFsError_None) {
- // There is really a problem opening/creating the file
- LOG_ERROR("Couldn't open cache file '%s': Error code %u!\n",
- glob_xmount.cache.p_cache_file,
- gidafs_ret)
- return FALSE;
- }
- is_new_cache_file=1;
- }
-
-#define INITCACHEFILE__CLOSE_CACHE do { \
- gidafs_ret=GidaFsLib_CloseFs(&(glob_xmount.cache.h_cache_file)); \
- if(gidafs_ret!=eGidaFsError_None) { \
- LOG_ERROR("Unable to close cache file: Error code %u: Ignoring!\n", \
- gidafs_ret) \
- } \
-} while(0)
-
-#define INITCACHEFILE__CLOSE_BLOCK_CACHE do { \
- gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file, \
- &(glob_xmount.cache.h_block_cache)); \
- if(gidafs_ret!=eGidaFsError_None) { \
- LOG_ERROR("Unable to close block cache file: Error code %u: Ignoring!\n", \
- gidafs_ret) \
- } \
-} while(0)
-
-#define INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX do { \
- gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file, \
- &(glob_xmount.cache.h_block_cache_index)); \
- if(gidafs_ret!=eGidaFsError_None) { \
- LOG_ERROR("Unable to close block cache index file: Error code %u: " \
- "Ignoring!\n", \
- gidafs_ret) \
- } \
-} while(0)
-
- // TODO: Check if cache file uses same block size as we do
-
- if(is_new_cache_file==1) {
- // New cache file, create needed xmount subdirectory
- gidafs_ret=GidaFsLib_CreateDir(glob_xmount.cache.h_cache_file,
- XMOUNT_CACHE_FOLDER,
- eGidaFsNodeFlag_RWXu);
- if(gidafs_ret!=eGidaFsError_None) {
- LOG_ERROR("Unable to create cache file directory '%s': Error code %u!\n",
- XMOUNT_CACHE_FOLDER,
- gidafs_ret)
- INITCACHEFILE__CLOSE_CACHE;
- return FALSE;
- }
- }
-
- // Open / Create block cache file
- gidafs_ret=GidaFsLib_OpenFile(glob_xmount.cache.h_cache_file,
- XMOUNT_CACHE_BLOCK_FILE,
- &(glob_xmount.cache.h_block_cache),
- eGidaFsOpenFileFlag_ReadWrite |
- (is_new_cache_file==1 ?
- eGidaFsOpenFileFlag_CreateAlways : 0),
- eGidaFsNodeFlag_Rall |
- eGidaFsNodeFlag_Wusr);
- if(gidafs_ret!=eGidaFsError_None) {
- LOG_ERROR("Unable to open / create block cache file '%s': Error code %u!\n",
- XMOUNT_CACHE_BLOCK_FILE,
- gidafs_ret)
- INITCACHEFILE__CLOSE_CACHE;
- return FALSE;
- }
-
- // Open / Create block cache index file
- gidafs_ret=GidaFsLib_OpenFile(glob_xmount.cache.h_cache_file,
- XMOUNT_CACHE_BLOCK_INDEX_FILE,
- &(glob_xmount.cache.h_block_cache_index),
- eGidaFsOpenFileFlag_ReadWrite |
- (is_new_cache_file==1 ?
- eGidaFsOpenFileFlag_CreateAlways : 0),
- eGidaFsNodeFlag_Rall |
- eGidaFsNodeFlag_Wusr);
- if(gidafs_ret!=eGidaFsError_None) {
- LOG_ERROR("Unable to open / create block cache index file '%s': "
- "Error code %u!\n",
- XMOUNT_CACHE_BLOCK_FILE,
- gidafs_ret)
- INITCACHEFILE__CLOSE_BLOCK_CACHE;
- INITCACHEFILE__CLOSE_CACHE;
- return FALSE;
- }
-
- // Calculate how many cache blocks are needed and how big the cache block
- // index must be
- glob_xmount.cache.block_cache_index_len=image_size/CACHE_BLOCK_SIZE;
- if((image_size%CACHE_BLOCK_SIZE)!=0) {
- glob_xmount.cache.block_cache_index_len++;
- }
-
- LOG_DEBUG("Cache blocks: %u (0x%04X) entries using %zd (0x%08zX) bytes\n",
- glob_xmount.cache.block_cache_index_len,
- glob_xmount.cache.block_cache_index_len,
- glob_xmount.cache.block_cache_index_len*
- sizeof(t_CacheFileBlockIndex),
- glob_xmount.cache.block_cache_index_len*
- sizeof(t_CacheFileBlockIndex))
-
- // Prepare in-memory buffer for block cache index
- XMOUNT_MALLOC(glob_xmount.cache.p_block_cache_index,
- t_CacheFileBlockIndex*,
- glob_xmount.cache.block_cache_index_len*
- sizeof(t_CacheFileBlockIndex))
-
- if(is_new_cache_file==1) {
- // Generate initial block cache index
- for(uint64_t i=0;i<glob_xmount.cache.block_cache_index_len;i++) {
- glob_xmount.cache.p_block_cache_index[i]=CACHE_BLOCK_FREE;
- }
- // Write initial block cache index to cache file
- if(UpdateBlockCacheIndex(XMOUNT_BLOCK_CACHE_INVALID_INDEX,0)!=TRUE) {
- LOG_ERROR("Unable to generate initial block cache index file '%s': "
- "Error code %u!\n",
- XMOUNT_CACHE_BLOCK_FILE,
- gidafs_ret)
- INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
- INITCACHEFILE__CLOSE_BLOCK_CACHE;
- INITCACHEFILE__CLOSE_CACHE;
- XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
- return FALSE;
- }
- } else {
- // Existing cache file, make sure block cache index has correct size
- gidafs_ret=GidaFsLib_GetFileSize(glob_xmount.cache.h_cache_file,
- glob_xmount.cache.h_block_cache_index,
- &blockindex_size);
- if(gidafs_ret!=eGidaFsError_None) {
- LOG_ERROR("Unable to get block cache index file size: Error code %u!\n",
- gidafs_ret)
- INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
- INITCACHEFILE__CLOSE_BLOCK_CACHE;
- INITCACHEFILE__CLOSE_CACHE;
- XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
- return FALSE;
- }
- if(blockindex_size%sizeof(t_CacheFileBlockIndex)!=0 ||
- (blockindex_size/sizeof(t_CacheFileBlockIndex))!=
- glob_xmount.cache.block_cache_index_len)
- {
- // TODO: Be more helpfull in error message
- LOG_ERROR("Block cache index size is incorrect for given input image!\n")
- INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
- INITCACHEFILE__CLOSE_BLOCK_CACHE;
- INITCACHEFILE__CLOSE_CACHE;
- XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
- return FALSE;
- }
- // Read block cache index into memory
- gidafs_ret=GidaFsLib_ReadFile(glob_xmount.cache.h_cache_file,
- glob_xmount.cache.h_block_cache_index,
- 0,
- blockindex_size,
- glob_xmount.cache.p_block_cache_index,
- &read);
- if(gidafs_ret!=eGidaFsError_None || read!=blockindex_size) {
- LOG_ERROR("Unable to read block cache index: Error code %u!\n",
- gidafs_ret);
- INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
- INITCACHEFILE__CLOSE_BLOCK_CACHE;
- INITCACHEFILE__CLOSE_CACHE;
- XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
- return FALSE;
- }
- }
-
-#undef INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX
-#undef INITCACHEFILE__CLOSE_BLOCK_CACHE
-#undef INITCACHEFILE__CLOSE_CACHE
-
- return TRUE;
-}
-
-//! Update block cache index
-/*!
- * \return TRUE on success, FALSE on error
- */
-static int UpdateBlockCacheIndex(uint64_t index, t_CacheFileBlockIndex value) {
- uint64_t update_size=0;
- uint64_t written=0;
- teGidaFsError gidafs_ret=eGidaFsError_None;
- t_CacheFileBlockIndex *p_buf;
-
- if(index!=XMOUNT_BLOCK_CACHE_INVALID_INDEX) {
- // Update specific index element in cache file
- p_buf=glob_xmount.cache.p_block_cache_index+index;
- update_size=sizeof(t_CacheFileBlockIndex);
- } else {
- // Dump whole block cache index to cache file
- p_buf=glob_xmount.cache.p_block_cache_index;
- update_size=glob_xmount.cache.block_cache_index_len*
- sizeof(t_CacheFileBlockIndex);
- }
-
- // Update cache file
- gidafs_ret=GidaFsLib_WriteFile(glob_xmount.cache.h_cache_file,
- glob_xmount.cache.h_block_cache_index,
- 0,
- update_size,
- p_buf,
- &written);
- if(gidafs_ret!=eGidaFsError_None || written!=update_size) {
- LOG_ERROR("Unable to update block cache index file '%s': "
- "Error code %u!\n",
- XMOUNT_CACHE_BLOCK_INDEX_FILE,
- gidafs_ret)
- return FALSE;
- }
-
- return TRUE;
-}
-
//! Load input / morphing libs
/*!
* \return TRUE on success, FALSE on error
*/
static int LoadLibs() {
DIR *p_dir=NULL;
struct dirent *p_dirent=NULL;
int base_library_path_len=0;
char *p_library_path=NULL;
void *p_libxmount=NULL;
t_LibXmount_Input_GetApiVersion pfun_input_GetApiVersion;
t_LibXmount_Input_GetSupportedFormats pfun_input_GetSupportedFormats;
t_LibXmount_Input_GetFunctions pfun_input_GetFunctions;
t_LibXmount_Morphing_GetApiVersion pfun_morphing_GetApiVersion;
t_LibXmount_Morphing_GetSupportedTypes pfun_morphing_GetSupportedTypes;
t_LibXmount_Morphing_GetFunctions pfun_morphing_GetFunctions;
t_LibXmount_Output_GetApiVersion pfun_output_GetApiVersion;
t_LibXmount_Output_GetSupportedFormats pfun_output_GetSupportedFormats;
t_LibXmount_Output_GetFunctions pfun_output_GetFunctions;
const char *p_supported_formats=NULL;
const char *p_buf;
uint32_t supported_formats_len=0;
pts_InputLib p_input_lib=NULL;
pts_MorphingLib p_morphing_lib=NULL;
pts_OutputLib p_output_lib=NULL;
LOG_DEBUG("Searching for xmount 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'!\n",
XMOUNT_LIBRARY_PATH);
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,"/");
}
#define LIBXMOUNT_LOAD(path) { \
p_libxmount=dlopen(path,RTLD_NOW); \
if(p_libxmount==NULL) { \
LOG_ERROR("Unable to load input library '%s': %s!\n", \
path, \
dlerror()); \
continue; \
} \
}
#define LIBXMOUNT_LOAD_SYMBOL(name,pfun) { \
if((pfun=dlsym(p_libxmount,name))==NULL) { \
LOG_ERROR("Unable to load symbol '%s' from library '%s'!\n", \
name, \
p_library_path); \
dlclose(p_libxmount); \
p_libxmount=NULL; \
continue; \
} \
}
// Loop over lib dir
while((p_dirent=readdir(p_dir))!=NULL) {
LOG_DEBUG("Trying to load '%s'\n",p_dirent->d_name);
// Construct full path to found object
p_library_path=realloc(p_library_path,
base_library_path_len+strlen(p_dirent->d_name)+1);
if(p_library_path==NULL) {
LOG_ERROR("Couldn't allocate memory!\n");
exit(1);
}
strcpy(p_library_path+base_library_path_len,p_dirent->d_name);
if(strncmp(p_dirent->d_name,"libxmount_input_",16)==0) {
// Found possible input lib. Try to load it
LIBXMOUNT_LOAD(p_library_path);
// Load library symbols
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Input_GetApiVersion",
pfun_input_GetApiVersion);
// Check library's API version
if(pfun_input_GetApiVersion()!=LIBXMOUNT_INPUT_API_VERSION) {
LOG_DEBUG("Failed! Wrong API version.\n");
LOG_ERROR("Unable to load input library '%s'. Wrong API version\n",
p_library_path);
dlclose(p_libxmount);
continue;
}
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Input_GetSupportedFormats",
pfun_input_GetSupportedFormats);
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Input_GetFunctions",
pfun_input_GetFunctions);
// Construct new entry for our library list
XMOUNT_MALLOC(p_input_lib,pts_InputLib,sizeof(ts_InputLib));
// Initialize lib_functions structure to NULL
memset(&(p_input_lib->lib_functions),
0,
sizeof(ts_LibXmountInputFunctions));
// Set name and handle
XMOUNT_STRSET(p_input_lib->p_name,p_dirent->d_name);
p_input_lib->p_lib=p_libxmount;
// Get and set supported formats
p_supported_formats=pfun_input_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);
// Get, set and check lib_functions
pfun_input_GetFunctions(&(p_input_lib->lib_functions));
if(p_input_lib->lib_functions.CreateHandle==NULL ||
p_input_lib->lib_functions.DestroyHandle==NULL ||
p_input_lib->lib_functions.Open==NULL ||
p_input_lib->lib_functions.Close==NULL ||
p_input_lib->lib_functions.Size==NULL ||
p_input_lib->lib_functions.Read==NULL ||
p_input_lib->lib_functions.OptionsHelp==NULL ||
p_input_lib->lib_functions.OptionsParse==NULL ||
p_input_lib->lib_functions.GetInfofileContent==NULL ||
p_input_lib->lib_functions.GetErrorMessage==NULL ||
p_input_lib->lib_functions.FreeBuffer==NULL)
{
LOG_DEBUG("Missing implemention of one or more functions in lib %s!\n",
p_dirent->d_name);
free(p_input_lib->p_supported_input_types);
free(p_input_lib->p_name);
free(p_input_lib);
dlclose(p_libxmount);
continue;
}
// Add entry to the input library list
XMOUNT_REALLOC(glob_xmount.input.pp_libs,
pts_InputLib*,
sizeof(pts_InputLib)*(glob_xmount.input.libs_count+1));
glob_xmount.input.pp_libs[glob_xmount.input.libs_count++]=p_input_lib;
LOG_DEBUG("Input library '%s' loaded successfully\n",p_dirent->d_name);
} if(strncmp(p_dirent->d_name,"libxmount_morphing_",19)==0) {
// Found possible morphing lib. Try to load it
LIBXMOUNT_LOAD(p_library_path);
// Load library symbols
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Morphing_GetApiVersion",
pfun_morphing_GetApiVersion);
// Check library's API version
if(pfun_morphing_GetApiVersion()!=LIBXMOUNT_MORPHING_API_VERSION) {
LOG_DEBUG("Failed! Wrong API version.\n");
LOG_ERROR("Unable to load morphing library '%s'. Wrong API version\n",
p_library_path);
dlclose(p_libxmount);
continue;
}
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Morphing_GetSupportedTypes",
pfun_morphing_GetSupportedTypes);
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Morphing_GetFunctions",
pfun_morphing_GetFunctions);
// Construct new entry for our library list
XMOUNT_MALLOC(p_morphing_lib,pts_MorphingLib,sizeof(ts_MorphingLib));
// Initialize lib_functions structure to NULL
memset(&(p_morphing_lib->lib_functions),
0,
sizeof(ts_LibXmountMorphingFunctions));
// Set name and handle
XMOUNT_STRSET(p_morphing_lib->p_name,p_dirent->d_name);
p_morphing_lib->p_lib=p_libxmount;
// Get and set supported types
p_supported_formats=pfun_morphing_GetSupportedTypes();
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_morphing_lib->p_supported_morphing_types,
char*,
supported_formats_len);
memcpy(p_morphing_lib->p_supported_morphing_types,
p_supported_formats,
supported_formats_len);
// Get, set and check lib_functions
pfun_morphing_GetFunctions(&(p_morphing_lib->lib_functions));
if(p_morphing_lib->lib_functions.CreateHandle==NULL ||
p_morphing_lib->lib_functions.DestroyHandle==NULL ||
p_morphing_lib->lib_functions.Morph==NULL ||
p_morphing_lib->lib_functions.Size==NULL ||
p_morphing_lib->lib_functions.Read==NULL ||
p_morphing_lib->lib_functions.OptionsHelp==NULL ||
p_morphing_lib->lib_functions.OptionsParse==NULL ||
p_morphing_lib->lib_functions.GetInfofileContent==NULL ||
p_morphing_lib->lib_functions.GetErrorMessage==NULL ||
p_morphing_lib->lib_functions.FreeBuffer==NULL)
{
LOG_DEBUG("Missing implemention of one or more functions in lib %s!\n",
p_dirent->d_name);
free(p_morphing_lib->p_supported_morphing_types);
free(p_morphing_lib->p_name);
free(p_morphing_lib);
dlclose(p_libxmount);
continue;
}
// Add entry to the input library list
XMOUNT_REALLOC(glob_xmount.morphing.pp_libs,
pts_MorphingLib*,
sizeof(pts_MorphingLib)*
(glob_xmount.morphing.libs_count+1));
glob_xmount.morphing.pp_libs[glob_xmount.morphing.libs_count++]=
p_morphing_lib;
LOG_DEBUG("Morphing library '%s' loaded successfully\n",p_dirent->d_name);
} if(strncmp(p_dirent->d_name,"libxmount_output_",17)==0) {
// Found possible output lib. Try to load it
LIBXMOUNT_LOAD(p_library_path);
// Load library symbols
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Output_GetApiVersion",
pfun_output_GetApiVersion);
// Check library's API version
if(pfun_output_GetApiVersion()!=LIBXMOUNT_OUTPUT_API_VERSION) {
LOG_DEBUG("Failed! Wrong API version.\n");
LOG_ERROR("Unable to load output library '%s'. Wrong API version\n",
p_library_path);
dlclose(p_libxmount);
continue;
}
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Output_GetSupportedFormats",
pfun_output_GetSupportedFormats);
LIBXMOUNT_LOAD_SYMBOL("LibXmount_Output_GetFunctions",
pfun_output_GetFunctions);
// Construct new entry for our library list
XMOUNT_MALLOC(p_output_lib,pts_OutputLib,sizeof(ts_OutputLib));
// Initialize lib_functions structure to NULL
memset(&(p_output_lib->lib_functions),
0,
sizeof(ts_LibXmountOutput_Functions));
// Set name and handle
XMOUNT_STRSET(p_output_lib->p_name,p_dirent->d_name);
p_output_lib->p_lib=p_libxmount;
// Get and set supported types
p_supported_formats=pfun_output_GetSupportedFormats();
supported_formats_len=0;
p_buf=p_supported_formats;
while(*p_buf!='\0') {
supported_formats_len+=(strlen(p_buf)+1);
p_buf+=(strlen(p_buf)+1);
}
supported_formats_len++;
XMOUNT_MALLOC(p_output_lib->p_supported_output_formats,
char*,
supported_formats_len);
memcpy(p_output_lib->p_supported_output_formats,
p_supported_formats,
supported_formats_len);
// Get, set and check lib_functions
pfun_output_GetFunctions(&(p_output_lib->lib_functions));
if(p_output_lib->lib_functions.CreateHandle==NULL ||
p_output_lib->lib_functions.DestroyHandle==NULL ||
p_output_lib->lib_functions.Transform==NULL ||
p_output_lib->lib_functions.Size==NULL ||
p_output_lib->lib_functions.Read==NULL ||
p_output_lib->lib_functions.Write==NULL ||
p_output_lib->lib_functions.OptionsHelp==NULL ||
p_output_lib->lib_functions.OptionsParse==NULL ||
p_output_lib->lib_functions.GetInfofileContent==NULL ||
p_output_lib->lib_functions.GetErrorMessage==NULL ||
p_output_lib->lib_functions.FreeBuffer==NULL)
{
LOG_DEBUG("Missing implemention of one or more functions in lib %s!\n",
p_dirent->d_name);
free(p_output_lib->p_supported_output_formats);
free(p_output_lib->p_name);
free(p_output_lib);
dlclose(p_libxmount);
continue;
}
// Add entry to the input library list
XMOUNT_REALLOC(glob_xmount.output.pp_libs,
pts_OutputLib*,
sizeof(pts_OutputLib)*
(glob_xmount.output.libs_count+1));
glob_xmount.output.pp_libs[glob_xmount.output.libs_count++]=
p_output_lib;
LOG_DEBUG("Output library '%s' loaded successfully\n",p_dirent->d_name);
} else {
LOG_DEBUG("Ignoring '%s'.\n",p_dirent->d_name);
continue;
}
}
#undef LIBXMOUNT_LOAD_SYMBOL
#undef LIBXMOUNT_LOAD
LOG_DEBUG("A total of %u input libs, %u morphing libs and %u output libs "
"were loaded.\n",
glob_xmount.input.libs_count,
glob_xmount.morphing.libs_count,
glob_xmount.output.libs_count);
free(p_library_path);
closedir(p_dir);
return ((glob_xmount.input.libs_count>0 &&
glob_xmount.morphing.libs_count>0 &&
glob_xmount.output.libs_count>0) ? TRUE : FALSE);
}
//! Search an appropriate input lib for specified input type
/*!
* \param p_input_image Input image to search input lib for
* \return TRUE on success, FALSE on error
*/
static int FindInputLib(pts_InputImage p_input_image) {
char *p_buf;
LOG_DEBUG("Trying to find suitable library for input type '%s'.\n",
p_input_image->p_type);
// Loop over all loaded libs
for(uint32_t i=0;i<glob_xmount.input.libs_count;i++) {
LOG_DEBUG("Checking input library %s\n",
glob_xmount.input.pp_libs[i]->p_name);
p_buf=glob_xmount.input.pp_libs[i]->p_supported_input_types;
while(*p_buf!='\0') {
if(strcmp(p_buf,p_input_image->p_type)==0) {
// Library supports input type, set lib functions
LOG_DEBUG("Input library '%s' pretends to handle that input type.\n",
glob_xmount.input.pp_libs[i]->p_name);
p_input_image->p_functions=
&(glob_xmount.input.pp_libs[i]->lib_functions);
return TRUE;
}
p_buf+=(strlen(p_buf)+1);
}
}
LOG_DEBUG("Couldn't find any suitable library.\n");
// No library supporting input type found
return FALSE;
}
//! Search an appropriate morphing lib for the specified morph type
/*!
* \return TRUE on success, FALSE on error
*/
static int FindMorphingLib() {
char *p_buf;
LOG_DEBUG("Trying to find suitable library for morph type '%s'.\n",
glob_xmount.morphing.p_morph_type);
// Loop over all loaded libs
for(uint32_t i=0;i<glob_xmount.morphing.libs_count;i++) {
LOG_DEBUG("Checking morphing library %s\n",
glob_xmount.morphing.pp_libs[i]->p_name);
p_buf=glob_xmount.morphing.pp_libs[i]->p_supported_morphing_types;
while(*p_buf!='\0') {
if(strcmp(p_buf,glob_xmount.morphing.p_morph_type)==0) {
// Library supports morph type, set lib functions
LOG_DEBUG("Morphing library '%s' pretends to handle that morph type.\n",
glob_xmount.morphing.pp_libs[i]->p_name);
glob_xmount.morphing.p_functions=
&(glob_xmount.morphing.pp_libs[i]->lib_functions);
return TRUE;
}
p_buf+=(strlen(p_buf)+1);
}
}
LOG_DEBUG("Couldn't find any suitable library.\n");
// No library supporting morph type found
return FALSE;
}
//! Search an appropriate output lib for the specified output format
/*!
* \return TRUE on success, FALSE on error
*/
static int FindOutputLib() {
char *p_buf;
LOG_DEBUG("Trying to find suitable library for output format '%s'.\n",
glob_xmount.output.p_output_format);
// Loop over all loaded output libs
for(uint32_t i=0;i<glob_xmount.output.libs_count;i++) {
LOG_DEBUG("Checking output library %s\n",
glob_xmount.output.pp_libs[i]->p_name);
p_buf=glob_xmount.output.pp_libs[i]->p_supported_output_formats;
while(*p_buf!='\0') {
if(strcmp(p_buf,glob_xmount.output.p_output_format)==0) {
// Library supports output type, set lib functions
LOG_DEBUG("Output library '%s' pretends to handle that output format.\n",
glob_xmount.output.pp_libs[i]->p_name);
glob_xmount.output.p_functions=
&(glob_xmount.output.pp_libs[i]->lib_functions);
return TRUE;
}
p_buf+=(strlen(p_buf)+1);
}
}
LOG_DEBUG("Couldn't find any suitable library.\n");
// No library supporting output format found
return FALSE;
}
static void InitResources() {
// Input
glob_xmount.input.libs_count=0;
glob_xmount.input.pp_libs=NULL;
glob_xmount.input.lib_params_count=0;
glob_xmount.input.pp_lib_params=NULL;
glob_xmount.input.images_count=0;
glob_xmount.input.pp_images=NULL;
glob_xmount.input.image_offset=0;
glob_xmount.input.image_size_limit=0;
glob_xmount.input.image_hash_lo=0;
glob_xmount.input.image_hash_hi=0;
// Morphing
glob_xmount.morphing.libs_count=0;
glob_xmount.morphing.pp_libs=NULL;
glob_xmount.morphing.p_morph_type=NULL;
glob_xmount.morphing.lib_params_count=0;
glob_xmount.morphing.pp_lib_params=NULL;
glob_xmount.morphing.p_handle=NULL;
glob_xmount.morphing.p_functions=NULL;
glob_xmount.morphing.input_image_functions.ImageCount=
&LibXmount_Morphing_ImageCount;
glob_xmount.morphing.input_image_functions.Size=&LibXmount_Morphing_Size;
glob_xmount.morphing.input_image_functions.Read=&LibXmount_Morphing_Read;
// Cache
glob_xmount.cache.overwrite_cache=FALSE;
glob_xmount.cache.p_cache_file=NULL;
glob_xmount.cache.h_cache_file=NULL;
glob_xmount.cache.h_block_cache=NULL;
glob_xmount.cache.h_block_cache_index=NULL;
glob_xmount.cache.p_block_cache_index=NULL;
glob_xmount.cache.block_cache_index_len=0;
// Output
glob_xmount.output.libs_count=0;
glob_xmount.output.pp_libs=NULL;
glob_xmount.output.p_output_format=NULL;
glob_xmount.output.lib_params_count=0;
glob_xmount.output.pp_lib_params=NULL;
glob_xmount.output.p_handle=NULL;
glob_xmount.output.p_functions=NULL;
glob_xmount.output.input_functions.Size=&LibXmount_Output_Size;
glob_xmount.output.input_functions.Read=&LibXmount_Output_Read;
glob_xmount.output.input_functions.Write=&LibXmount_Output_Write;
glob_xmount.output.image_size=0;
glob_xmount.output.writable=FALSE;
glob_xmount.output.p_virtual_image_path=NULL;
glob_xmount.output.p_info_path=NULL;
glob_xmount.output.p_info_file=NULL;
// Misc data
glob_xmount.debug=FALSE;
glob_xmount.may_set_fuse_allow_other=FALSE;
glob_xmount.fuse_argc=0;
glob_xmount.pp_fuse_argv=NULL;
glob_xmount.p_mountpoint=NULL;
}
/*
* FreeResources
*/
static void FreeResources() {
int ret;
teGidaFsError gidafs_ret=eGidaFsError_None;
LOG_DEBUG("Freeing all resources\n");
// Misc
if(glob_xmount.pp_fuse_argv!=NULL) {
for(int i=0;i<glob_xmount.fuse_argc;i++) free(glob_xmount.pp_fuse_argv[i]);
free(glob_xmount.pp_fuse_argv);
}
if(glob_xmount.p_mountpoint!=NULL) free(glob_xmount.p_mountpoint);
// Output
if(glob_xmount.output.p_functions!=NULL) {
if(glob_xmount.output.p_handle!=NULL) {
// Destroy output handle
ret=glob_xmount.output.p_functions->
DestroyHandle(&(glob_xmount.output.p_handle));
if(ret!=0) {
LOG_ERROR("Unable to destroy output handle: %s!\n",
glob_xmount.output.p_functions->GetErrorMessage(ret));
}
}
}
if(glob_xmount.output.pp_lib_params!=NULL) {
for(uint32_t i=0;i<glob_xmount.output.lib_params_count;i++)
free(glob_xmount.output.pp_lib_params[i]);
free(glob_xmount.output.pp_lib_params);
}
if(glob_xmount.output.p_output_format!=NULL)
free(glob_xmount.output.p_output_format);
if(glob_xmount.output.pp_libs!=NULL) {
// Unload output libs
for(uint32_t i=0;i<glob_xmount.output.libs_count;i++) {
if(glob_xmount.output.pp_libs[i]==NULL) continue;
if(glob_xmount.output.pp_libs[i]->p_supported_output_formats!=NULL)
free(glob_xmount.output.pp_libs[i]->p_supported_output_formats);
if(glob_xmount.output.pp_libs[i]->p_lib!=NULL)
dlclose(glob_xmount.output.pp_libs[i]->p_lib);
if(glob_xmount.output.pp_libs[i]->p_name!=NULL)
free(glob_xmount.output.pp_libs[i]->p_name);
free(glob_xmount.output.pp_libs[i]);
}
free(glob_xmount.output.pp_libs);
}
if(glob_xmount.output.p_info_path!=NULL)
free(glob_xmount.output.p_info_path);
if(glob_xmount.output.p_info_file!=NULL)
free(glob_xmount.output.p_info_file);
if(glob_xmount.output.p_virtual_image_path!=NULL)
free(glob_xmount.output.p_virtual_image_path);
// Cache
if(glob_xmount.cache.h_cache_file!=NULL) {
if(glob_xmount.cache.p_block_cache_index!=NULL)
free(glob_xmount.cache.p_block_cache_index);
if(glob_xmount.cache.h_block_cache_index!=NULL) {
gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file,
&(glob_xmount.cache.h_block_cache_index));
if(gidafs_ret!=eGidaFsError_None) {
LOG_ERROR("Unable to close block cache index file: Error code %u: "
"Ignoring!\n",
gidafs_ret)
}
}
if(glob_xmount.cache.h_block_cache!=NULL) {
gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file,
&(glob_xmount.cache.h_block_cache));
if(gidafs_ret!=eGidaFsError_None) {
LOG_ERROR("Unable to close block cache file: Error code %u: "
"Ignoring!\n",
gidafs_ret)
}
}
gidafs_ret=GidaFsLib_CloseFs(&(glob_xmount.cache.h_cache_file));
if(gidafs_ret!=eGidaFsError_None) {
LOG_ERROR("Unable to close cache file: Error code %u: Ignoring!\n",
gidafs_ret)
}
}
if(glob_xmount.cache.p_cache_file!=NULL) free(glob_xmount.cache.p_cache_file);
// Morphing
if(glob_xmount.morphing.p_functions!=NULL) {
if(glob_xmount.morphing.p_handle!=NULL) {
// Destroy morphing handle
ret=glob_xmount.morphing.p_functions->
DestroyHandle(&(glob_xmount.morphing.p_handle));
if(ret!=0) {
LOG_ERROR("Unable to destroy morphing handle: %s!\n",
glob_xmount.morphing.p_functions->GetErrorMessage(ret));
}
}
}
if(glob_xmount.morphing.pp_lib_params!=NULL) {
for(uint32_t i=0;i<glob_xmount.morphing.lib_params_count;i++)
free(glob_xmount.morphing.pp_lib_params[i]);
free(glob_xmount.morphing.pp_lib_params);
}
if(glob_xmount.morphing.p_morph_type!=NULL)
free(glob_xmount.morphing.p_morph_type);
if(glob_xmount.morphing.pp_libs!=NULL) {
// Unload morphing libs
for(uint32_t i=0;i<glob_xmount.morphing.libs_count;i++) {
if(glob_xmount.morphing.pp_libs[i]==NULL) continue;
if(glob_xmount.morphing.pp_libs[i]->p_supported_morphing_types!=NULL)
free(glob_xmount.morphing.pp_libs[i]->p_supported_morphing_types);
if(glob_xmount.morphing.pp_libs[i]->p_lib!=NULL)
dlclose(glob_xmount.morphing.pp_libs[i]->p_lib);
if(glob_xmount.morphing.pp_libs[i]->p_name!=NULL)
free(glob_xmount.morphing.pp_libs[i]->p_name);
free(glob_xmount.morphing.pp_libs[i]);
}
free(glob_xmount.morphing.pp_libs);
}
// Input
if(glob_xmount.input.pp_images!=NULL) {
// Close all input images
for(uint64_t i=0;i<glob_xmount.input.images_count;i++) {
if(glob_xmount.input.pp_images[i]==NULL) continue;
if(glob_xmount.input.pp_images[i]->p_functions!=NULL) {
if(glob_xmount.input.pp_images[i]->p_handle!=NULL) {
ret=glob_xmount.input.pp_images[i]->p_functions->
Close(glob_xmount.input.pp_images[i]->p_handle);
if(ret!=0) {
LOG_ERROR("Unable to close input image: %s\n",
glob_xmount.input.pp_images[i]->p_functions->
GetErrorMessage(ret));
}
ret=glob_xmount.input.pp_images[i]->p_functions->
DestroyHandle(&(glob_xmount.input.pp_images[i]->p_handle));
if(ret!=0) {
LOG_ERROR("Unable to destroy input image handle: %s\n",
glob_xmount.input.pp_images[i]->p_functions->
GetErrorMessage(ret));
}
}
}
if(glob_xmount.input.pp_images[i]->pp_files!=NULL) {
for(uint64_t ii=0;ii<glob_xmount.input.pp_images[i]->files_count;ii++) {
if(glob_xmount.input.pp_images[i]->pp_files[ii]!=NULL)
free(glob_xmount.input.pp_images[i]->pp_files[ii]);
}
free(glob_xmount.input.pp_images[i]->pp_files);
}
if(glob_xmount.input.pp_images[i]->p_type!=NULL)
free(glob_xmount.input.pp_images[i]->p_type);
free(glob_xmount.input.pp_images[i]);
}
free(glob_xmount.input.pp_images);
}
if(glob_xmount.input.pp_lib_params!=NULL) {
for(uint32_t i=0;i<glob_xmount.input.lib_params_count;i++)
free(glob_xmount.input.pp_lib_params[i]);
free(glob_xmount.input.pp_lib_params);
}
if(glob_xmount.input.pp_libs!=NULL) {
// Unload all input libs
for(uint32_t i=0;i<glob_xmount.input.libs_count;i++) {
if(glob_xmount.input.pp_libs[i]->p_supported_input_types!=NULL)
free(glob_xmount.input.pp_libs[i]->p_supported_input_types);
if(glob_xmount.input.pp_libs[i]->p_lib!=NULL)
dlclose(glob_xmount.input.pp_libs[i]->p_lib);
if(glob_xmount.input.pp_libs[i]->p_name!=NULL)
free(glob_xmount.input.pp_libs[i]->p_name);
free(glob_xmount.input.pp_libs[i]);
}
free(glob_xmount.input.pp_libs);
}
// Before we return, initialize everything in case ReleaseResources would be
// called again.
InitResources();
}
//! Function to split given library options
static int SplitLibraryParameters(char *p_params,
uint32_t *p_ret_opts_count,
pts_LibXmountOptions **ppp_ret_opt)
{
pts_LibXmountOptions p_opts=NULL;
pts_LibXmountOptions *pp_opts=NULL;
uint32_t params_len;
uint32_t opts_count=0;
uint32_t sep_pos=0;
char *p_buf=p_params;
if(p_params==NULL) return FALSE;
// Get params length
params_len=strlen(p_params);
// Return if no params specified
if(params_len==0) {
*ppp_ret_opt=NULL;
p_ret_opts_count=0;
return TRUE;
}
// Split params
while(*p_buf!='\0') {
XMOUNT_MALLOC(p_opts,pts_LibXmountOptions,sizeof(ts_LibXmountOptions));
p_opts->valid=0;
#define FREE_PP_OPTS() { \
if(pp_opts!=NULL) { \
for(uint32_t i=0;i<opts_count;i++) free(pp_opts[i]); \
free(pp_opts); \
} \
}
// Search next assignment operator
sep_pos=0;
while(p_buf[sep_pos]!='\0' && p_buf[sep_pos]!='=') sep_pos++;
if(sep_pos==0 || p_buf[sep_pos]=='\0') {
LOG_ERROR("Library parameter '%s' is missing an assignment operator!\n",
p_buf);
free(p_opts);
FREE_PP_OPTS();
return FALSE;
}
// Save option key
XMOUNT_STRNSET(p_opts->p_key,p_buf,sep_pos);
p_buf+=(sep_pos+1);
// Search next separator
sep_pos=0;
while(p_buf[sep_pos]!='\0' && p_buf[sep_pos]!=',') sep_pos++;
if(sep_pos==0) {
LOG_ERROR("Library parameter '%s' is not of format key=value!\n",
p_opts->p_key);
free(p_opts->p_key);
free(p_opts);
FREE_PP_OPTS();
return FALSE;
}
// Save option value
XMOUNT_STRNSET(p_opts->p_value,p_buf,sep_pos);
p_buf+=sep_pos;
LOG_DEBUG("Extracted library option: '%s' = '%s'\n",
p_opts->p_key,
p_opts->p_value);
#undef FREE_PP_OPTS
// Add current option to return array
XMOUNT_REALLOC(pp_opts,
pts_LibXmountOptions*,
sizeof(pts_LibXmountOptions)*(opts_count+1));
pp_opts[opts_count++]=p_opts;
// If we're not at the end of p_params, skip over separator for next run
if(*p_buf!='\0') p_buf++;
}
LOG_DEBUG("Extracted a total of %" PRIu32 " library options\n",opts_count);
*p_ret_opts_count=opts_count;
*ppp_ret_opt=pp_opts;
return TRUE;
}
/*******************************************************************************
* LibXmount_Morphing function implementation
******************************************************************************/
//! Function to get the amount of input images
/*!
* \param p_count Count of input images
* \return 0 on success
*/
static int LibXmount_Morphing_ImageCount(uint64_t *p_count) {
*p_count=glob_xmount.input.images_count;
return 0;
}
//! Function to get the size of the morphed data
/*!
* \param image Image number
* \param p_size Pointer to store input image's size to
* \return 0 on success
*/
static int LibXmount_Morphing_Size(uint64_t image, uint64_t *p_size) {
if(image>=glob_xmount.input.images_count) return -1;
*p_size=glob_xmount.input.pp_images[image]->size;
return 0;
}
//! Function to read data from input image
/*!
* \param image Image number
* \param p_buf Buffer to store read data to
* \param offset Position at which to start reading
* \param count Amount of bytes to read
* \param p_read Number of read bytes on success
* \return 0 on success or negated error code on error
*/
static int LibXmount_Morphing_Read(uint64_t image,
char *p_buf,
off_t offset,
size_t count,
size_t *p_read)
{
if(image>=glob_xmount.input.images_count) return -EIO;
return ReadInputImageData(glob_xmount.input.pp_images[image],
p_buf,
offset,
count,
p_read);
}
/*******************************************************************************
* LibXmount_Output function implementation
******************************************************************************/
//! Function to get the size of the morphed image
/*!
* \param p_size Pointer to store morphed image's size to
* \return 0 on success
*/
static int LibXmount_Output_Size(uint64_t *p_size) {
int ret=0;
ret=GetMorphedImageSize(p_size);
return ret==TRUE ? 0 : ret;
}
//! Function to read data from the morphed image
/*!
* \param p_buf Buffer to store read data to
* \param offset Position at which to start reading
* \param count Amount of bytes to read
* \param p_read Number of read bytes on success
* \return 0 on success or negated error code on error
*/
static int LibXmount_Output_Read(char *p_buf,
off_t offset,
size_t count,
size_t *p_read)
{
return ReadMorphedImageData(p_buf,offset,count,p_read);
}
//! Function to write data to the morphed image
/*!
* \param p_buf Buffer with data to write
* \param offset Position at which to start writing
* \param count Amount of bytes to write
* \param p_written Number of written bytes on success
* \return 0 on success or negated error code on error
*/
static int LibXmount_Output_Write(char *p_buf,
off_t offset,
size_t count,
size_t *p_written)
{
return WriteMorphedImageData(p_buf,offset,count,p_written);
}
/*******************************************************************************
* Main
******************************************************************************/
int main(int argc, char *argv[]) {
struct stat file_stat;
int ret;
int fuse_ret;
char *p_err_msg;
// Set implemented FUSE functions
struct fuse_operations xmount_operations = {
//.access=FuseAccess,
.getattr=Xmount_FuseGetAttr,
.mkdir=Xmount_FuseMkDir,
.mknod=Xmount_FuseMkNod,
.open=Xmount_FuseOpen,
.readdir=Xmount_FuseReadDir,
.read=Xmount_FuseRead,
.rename=Xmount_FuseRename,
.rmdir=Xmount_FuseRmDir,
//.statfs=FuseStatFs,
.unlink=Xmount_FuseUnlink,
.write=Xmount_FuseWrite
};
// Disable std output / input buffering
setbuf(stdout,NULL);
setbuf(stderr,NULL);
// Init glob_xmount
InitResources();
// Load input and morphing libs
if(!LoadLibs()) {
LOG_ERROR("Unable to load any libraries!\n")
return 1;
}
// Check FUSE settings
CheckFuseSettings();
// Parse command line options
if(ParseCmdLine(argc,argv)!=TRUE) {
PrintUsage(argv[0]);
FreeResources();
return 1;
}
// Check command line options
if(glob_xmount.input.images_count==0) {
LOG_ERROR("No --in command line option specified!\n")
PrintUsage(argv[0]);
FreeResources();
return 1;
}
if(glob_xmount.fuse_argc<2) {
LOG_ERROR("Couldn't parse command line options!\n")
PrintUsage(argv[0]);
FreeResources();
return 1;
}
if(glob_xmount.morphing.p_morph_type==NULL) {
XMOUNT_STRSET(glob_xmount.morphing.p_morph_type,"combine");
}
// Check if mountpoint is a valid dir
if(stat(glob_xmount.p_mountpoint,&file_stat)!=0) {
LOG_ERROR("Unable to stat mount point '%s'!\n",glob_xmount.p_mountpoint);
PrintUsage(argv[0]);
FreeResources();
return 1;
}
if(!S_ISDIR(file_stat.st_mode)) {
LOG_ERROR("Mount point '%s' is not a directory!\n",
glob_xmount.p_mountpoint);
PrintUsage(argv[0]);
FreeResources();
return 1;
}
if(glob_xmount.debug==TRUE) {
LOG_DEBUG("Options passed to FUSE: ")
for(int i=0;i<glob_xmount.fuse_argc;i++) {
printf("%s ",glob_xmount.pp_fuse_argv[i]);
}
printf("\n");
}
// Init mutexes
pthread_mutex_init(&(glob_xmount.mutex_image_rw),NULL);
pthread_mutex_init(&(glob_xmount.mutex_info_read),NULL);
// Load input images
for(uint64_t i=0;i<glob_xmount.input.images_count;i++) {
if(glob_xmount.debug==TRUE) {
if(glob_xmount.input.pp_images[i]->files_count==1) {
LOG_DEBUG("Loading image file \"%s\"...\n",
glob_xmount.input.pp_images[i]->pp_files[0])
} else {
LOG_DEBUG("Loading image files \"%s .. %s\"...\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.pp_images[i]->
pp_files[glob_xmount.input.pp_images[i]->files_count-1])
}
}
// Find input lib
if(!FindInputLib(glob_xmount.input.pp_images[i])) {
LOG_ERROR("Unknown input image type '%s' for input image '%s'!\n",
glob_xmount.input.pp_images[i]->p_type,
glob_xmount.input.pp_images[i]->pp_files[0])
PrintUsage(argv[0]);
FreeResources();
return 1;
}
// Init input image handle
ret=glob_xmount.input.pp_images[i]->p_functions->
CreateHandle(&(glob_xmount.input.pp_images[i]->p_handle),
glob_xmount.input.pp_images[i]->p_type,
glob_xmount.debug);
if(ret!=0) {
LOG_ERROR("Unable to init input handle for input image '%s': %s!\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.pp_images[i]->p_functions->
GetErrorMessage(ret));
FreeResources();
return 1;
}
// Parse input lib specific options
if(glob_xmount.input.pp_lib_params!=NULL) {
ret=glob_xmount.input.pp_images[i]->p_functions->
OptionsParse(glob_xmount.input.pp_images[i]->p_handle,
glob_xmount.input.lib_params_count,
glob_xmount.input.pp_lib_params,
(const char**)&p_err_msg);
if(ret!=0) {
if(p_err_msg!=NULL) {
LOG_ERROR("Unable to parse input library specific options for image "
"'%s': %s: %s!\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.pp_images[i]->p_functions->
GetErrorMessage(ret),
p_err_msg);
glob_xmount.input.pp_images[i]->p_functions->FreeBuffer(p_err_msg);
FreeResources();
return 1;
} else {
LOG_ERROR("Unable to parse input library specific options for image "
"'%s': %s!\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.pp_images[i]->p_functions->
GetErrorMessage(ret));
FreeResources();
return 1;
}
}
}
// Open input image
ret=
glob_xmount.input.pp_images[i]->
p_functions->
Open(glob_xmount.input.pp_images[i]->p_handle,
(const char**)(glob_xmount.input.pp_images[i]->pp_files),
glob_xmount.input.pp_images[i]->files_count);
if(ret!=0) {
LOG_ERROR("Unable to open input image file '%s': %s!\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.pp_images[i]->p_functions->
GetErrorMessage(ret));
FreeResources();
return 1;
}
// Determine input image size
ret=glob_xmount.input.pp_images[i]->
p_functions->
Size(glob_xmount.input.pp_images[i]->p_handle,
&(glob_xmount.input.pp_images[i]->size));
if(ret!=0) {
LOG_ERROR("Unable to determine size of input image '%s': %s!\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.pp_images[i]->
p_functions->GetErrorMessage(ret));
FreeResources();
return 1;
}
// If an offset was specified, check it against offset and change size
if(glob_xmount.input.image_offset!=0) {
if(glob_xmount.input.image_offset>glob_xmount.input.pp_images[i]->size) {
LOG_ERROR("The specified offset is larger than the size of the input "
"image '%s'! (%" PRIu64 " > %" PRIu64 ")\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.image_offset,
glob_xmount.input.pp_images[i]->size);
FreeResources();
return 1;
}
glob_xmount.input.pp_images[i]->size-=glob_xmount.input.image_offset;
}
// If a size limit was specified, check it and change size
if(glob_xmount.input.image_size_limit!=0) {
if(glob_xmount.input.pp_images[i]->size<
glob_xmount.input.image_size_limit)
{
LOG_ERROR("The specified size limit is larger than the size of the "
"input image '%s'! (%" PRIu64 " > %" PRIu64 ")\n",
glob_xmount.input.pp_images[i]->pp_files[0],
glob_xmount.input.image_size_limit,
glob_xmount.input.pp_images[i]->size);
FreeResources();
return 1;
}
glob_xmount.input.pp_images[i]->size=glob_xmount.input.image_size_limit;
}
LOG_DEBUG("Input image loaded successfully\n")
}
// Find morphing lib
if(FindMorphingLib()!=TRUE) {
LOG_ERROR("Unable to find a library supporting the morphing type '%s'!\n",
glob_xmount.morphing.p_morph_type);
FreeResources();
return 1;
}
// Init morphing
ret=glob_xmount.morphing.p_functions->
CreateHandle(&glob_xmount.morphing.p_handle,
glob_xmount.morphing.p_morph_type,
glob_xmount.debug);
if(ret!=0) {
LOG_ERROR("Unable to create morphing handle: %s!\n",
glob_xmount.morphing.p_functions->GetErrorMessage(ret));
FreeResources();
return 1;
}
// Parse morphing lib specific options
if(glob_xmount.morphing.pp_lib_params!=NULL) {
p_err_msg=NULL;
ret=glob_xmount.morphing.p_functions->
OptionsParse(glob_xmount.morphing.p_handle,
glob_xmount.morphing.lib_params_count,
glob_xmount.morphing.pp_lib_params,
(const char**)&p_err_msg);
if(ret!=0) {
if(p_err_msg!=NULL) {
LOG_ERROR("Unable to parse morphing library specific options: %s: %s!\n",
glob_xmount.morphing.p_functions->GetErrorMessage(ret),
p_err_msg);
glob_xmount.morphing.p_functions->FreeBuffer(p_err_msg);
FreeResources();
return 1;
} else {
LOG_ERROR("Unable to parse morphing library specific options: %s!\n",
glob_xmount.morphing.p_functions->GetErrorMessage(ret));
FreeResources();
return 1;
}
}
}
// Morph image
ret=glob_xmount.morphing.p_functions->
Morph(glob_xmount.morphing.p_handle,
&(glob_xmount.morphing.input_image_functions));
if(ret!=0) {
LOG_ERROR("Unable to start morphing: %s!\n",
glob_xmount.morphing.p_functions->GetErrorMessage(ret));
FreeResources();
return 1;
}
// Init random generator
srand(time(NULL));
// Calculate partial MD5 hash of input image file
if(CalculateInputImageHash(&(glob_xmount.input.image_hash_lo),
&(glob_xmount.input.image_hash_hi))==FALSE)
{
LOG_ERROR("Couldn't calculate partial hash of morphed image!\n")
return 1;
}
if(glob_xmount.debug==TRUE) {
LOG_DEBUG("Partial MD5 hash of morphed image: ")
for(int i=0;i<8;i++)
printf("%02hhx",*(((char*)(&(glob_xmount.input.image_hash_lo)))+i));
for(int i=0;i<8;i++)
printf("%02hhx",*(((char*)(&(glob_xmount.input.image_hash_hi)))+i));
printf("\n");
}
if(!ExtractOutputFileNames(glob_xmount.input.pp_images[0]->pp_files[0])) {
LOG_ERROR("Couldn't extract virtual file names!\n");
FreeResources();
return 1;
}
LOG_DEBUG("Virtual file names extracted successfully\n")
// Find output lib
if(FindOutputLib()!=TRUE) {
LOG_ERROR("Unable to find a library supporting the output format '%s'!\n",
glob_xmount.output.p_output_format);
FreeResources();
return 1;
}
// Init output
ret=glob_xmount.output.p_functions->
CreateHandle(&glob_xmount.output.p_handle,
glob_xmount.output.p_output_format,
glob_xmount.debug);
if(ret!=0) {
LOG_ERROR("Unable to create output handle: %s!\n",
glob_xmount.output.p_functions->GetErrorMessage(ret));
FreeResources();
return 1;
}
// Parse output lib specific options
if(glob_xmount.output.pp_lib_params!=NULL) {
p_err_msg=NULL;
ret=glob_xmount.output.p_functions->
OptionsParse(glob_xmount.output.p_handle,
glob_xmount.output.lib_params_count,
glob_xmount.output.pp_lib_params,
(const char**)&p_err_msg);
if(ret!=0) {
if(p_err_msg!=NULL) {
LOG_ERROR("Unable to parse output library specific options: %s: %s!\n",
glob_xmount.output.p_functions->GetErrorMessage(ret),
p_err_msg);
glob_xmount.output.p_functions->FreeBuffer(p_err_msg);
FreeResources();
return 1;
} else {
LOG_ERROR("Unable to parse output library specific options: %s!\n",
glob_xmount.output.p_functions->GetErrorMessage(ret));
FreeResources();
return 1;
}
}
}
// Morph image
ret=glob_xmount.morphing.p_functions->
Morph(glob_xmount.morphing.p_handle,
&(glob_xmount.morphing.input_image_functions));
if(ret!=0) {
LOG_ERROR("Unable to start morphing: %s!\n",
glob_xmount.morphing.p_functions->GetErrorMessage(ret));
FreeResources();
return 1;
}
// Gather infos for info file
if(!InitInfoFile()) {
LOG_ERROR("Couldn't gather infos for virtual image info file!\n")
FreeResources();
return 1;
}
LOG_DEBUG("Virtual image info file build successfully\n")
if(glob_xmount.output.writable) {
// Init cache file and cache file block index
if(!InitCacheFile()) {
LOG_ERROR("Couldn't initialize cache file!\n")
FreeResources();
return 1;
}
LOG_DEBUG("Cache file initialized successfully\n")
}
// Call fuse_main to do the fuse magic
fuse_ret=fuse_main(glob_xmount.fuse_argc,
glob_xmount.pp_fuse_argv,
&xmount_operations,
NULL);
// Destroy mutexes
pthread_mutex_destroy(&(glob_xmount.mutex_image_rw));
pthread_mutex_destroy(&(glob_xmount.mutex_info_read));
// Free allocated memory
FreeResources();
return fuse_ret;
}
diff --git a/src/xmount.h b/src/xmount.h
index 72e993c..58bfb58 100755
--- a/src/xmount.h
+++ b/src/xmount.h
@@ -1,312 +1,83 @@
/*******************************************************************************
* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef XMOUNT_H
#define XMOUNT_H
-#include <gidafs.h>
-
-#include "../libxmount_input/libxmount_input.h"
-#include "../libxmount_morphing/libxmount_morphing.h"
-#include "../libxmount_output/libxmount_output.h"
+#include "xmount_input.h"
+#include "xmount_morphing.h"
+#include "xmount_cache.h"
+#include "xmount_output.h"
#undef FALSE
#undef TRUE
#define FALSE 0
#define TRUE 1
/*
* Constants
*/
#define IMAGE_INFO_INPUT_HEADER \
"------> The following values are supplied by the used input library(ies) " \
"<------\n"
#define IMAGE_INFO_MORPHING_HEADER \
"\n------> The following values are supplied by the used morphing library " \
"<------\n\n"
/*******************************************************************************
* Xmount specific structures
******************************************************************************/
-
-#ifdef __LP64__
- #define CACHE_BLOCK_FREE 0xFFFFFFFFFFFFFFFF
-#else
- #define CACHE_BLOCK_FREE 0xFFFFFFFFFFFFFFFFLL
-#endif
-#ifdef __LP64__
- #define XMOUNT_BLOCK_CACHE_INVALID_INDEX 0xFFFFFFFFFFFFFFFF
-#else
- #define XMOUNT_BLOCK_CACHE_INVALID_INDEX 0xFFFFFFFFFFFFFFFFLL
-#endif
-//! Cache file block index array element
-typedef uint64_t t_CacheFileBlockIndex;
-// TODO: Remove
-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)) ts_CacheFileBlockIndex, *pts_CacheFileBlockIndex;
-
-#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)
-//! Cache file header structure
-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 to get 512 byte alignment and ease further additions
- char HeaderPadding[432];
-} __attribute__ ((packed)) ts_CacheFileHeader, *pts_CacheFileHeader;
-
-//! Cache file header structure - Old v1 header
-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
-} ts_CacheFileHeader_v1, *pts_CacheFileHeader_v1;
-
-//! Structure containing infos about input libs
-typedef struct s_InputLib {
- //! Filename of lib (without path)
- char *p_name;
- //! Handle to the loaded lib
- void *p_lib;
- //! Array of supported input types
- char *p_supported_input_types;
- //! Struct containing lib functions
- ts_LibXmountInputFunctions lib_functions;
-} ts_InputLib, *pts_InputLib;
-
-//! Structure containing infos about input images
-typedef struct s_InputImage {
- //! Image type
- char *p_type;
- //! Image source file count
- uint64_t files_count;
- //! Image source files
- char **pp_files;
- //! Input lib functions for this image
- pts_LibXmountInputFunctions p_functions;
- //! Image handle
- void *p_handle;
- //! Image size
- uint64_t size;
-} ts_InputImage, *pts_InputImage;
-
-typedef struct s_InputData {
- //! Loaded input lib count
- uint32_t libs_count;
- //! Array containing infos about loaded input libs
- pts_InputLib *pp_libs;
- //! Amount of input lib params (--inopts)
- uint32_t lib_params_count;
- //! Input lib params (--inopts)
- pts_LibXmountOptions *pp_lib_params;
- //! Input image count
- uint64_t images_count;
- //! Input images
- pts_InputImage *pp_images;
- //! Input image offset (--offset)
- uint64_t image_offset;
- //! Input image size limit (--sizelimit)
- uint64_t image_size_limit;
- //! MD5 hash of partial input image (lower 64 bit) (after morph)
- uint64_t image_hash_lo;
- //! MD5 hash of partial input image (higher 64 bit) (after morph)
- uint64_t image_hash_hi;
-} ts_InputData;
-
-//! Structure containing infos about morphing libs
-typedef struct s_MorphingLib {
- //! Filename of lib (without path)
- char *p_name;
- //! Handle to the loaded lib
- void *p_lib;
- //! Array of supported morphing types
- char *p_supported_morphing_types;
- //! Struct containing lib functions
- ts_LibXmountMorphingFunctions lib_functions;
-} ts_MorphingLib, *pts_MorphingLib;
-
-//! Structures and vars needed for morph support
-typedef struct s_MorphingData {
- //! Loaded morphing lib count
- uint32_t libs_count;
- //! Array containing infos about loaded morphing libs
- pts_MorphingLib *pp_libs;
- //! Specified morphing type (--morph)
- char *p_morph_type;
- //! Amount of specified morphing lib params (--morphopts)
- uint32_t lib_params_count;
- //! Specified morphing lib params (--morphopts)
- pts_LibXmountOptions *pp_lib_params;
- //! Handle to initialized morphing lib
- void *p_handle;
- //! Morphing functions of initialized lib
- pts_LibXmountMorphingFunctions p_functions;
- //! Input image functions passed to morphing lib
- ts_LibXmountMorphingInputFunctions input_image_functions;
-} ts_MorphingData;
-
-//! Structures and vars needed for write access
-#define XMOUNT_CACHE_FOLDER "/.xmount"
-#define XMOUNT_CACHE_BLOCK_FILE XMOUNT_CACHE_FOLDER "/blocks.data"
-#define XMOUNT_CACHE_BLOCK_INDEX_FILE XMOUNT_CACHE_FOLDER "/blocks.index"
-typedef struct s_CacheData {
- //! Cache file to save changes to
- char *p_cache_file;
- //! Handle to cache file
- hGidaFs h_cache_file;
- //! Handle to block cache
- hGidaFsFile h_block_cache;
- //! Handle to block cache index
- hGidaFsFile h_block_cache_index;
- //! In-memory copy of cache index
- t_CacheFileBlockIndex *p_block_cache_index;
- //! Length (in elements) of in-memory block cache index
- uint64_t block_cache_index_len;
- // TODO: Move to s_XmountData
- //! Overwrite existing cache
- uint8_t overwrite_cache;
-} ts_CacheData;
-
-//! Structure containing infos about output libs
-typedef struct s_OutputLib {
- //! Filename of lib (without path)
- char *p_name;
- //! Handle to the loaded lib
- void *p_lib;
- //! Array of supported output formats
- char *p_supported_output_formats;
- //! Struct containing lib functions
- ts_LibXmountOutput_Functions lib_functions;
-} ts_OutputLib, *pts_OutputLib;
-
-//! Structure containing infos about output image
-typedef struct s_OutputData {
- //! Loaded output lib count
- uint32_t libs_count;
- //! Array containing infos about loaded output libs
- pts_OutputLib *pp_libs;
- //! Specified output format (--out)
- char *p_output_format;
- //! Amount of specified output lib params
- uint32_t lib_params_count;
- //! Specified output lib params (--outopts)
- pts_LibXmountOptions *pp_lib_params;
- //! Handle to initialized output lib
- void *p_handle;
- //! Transformation functions of initialized lib
- pts_LibXmountOutput_Functions p_functions;
- //! Input image functions passed to output lib
- ts_LibXmountOutput_InputFunctions input_functions;
- //! Size
- uint64_t image_size;
- //! Writable? (Set to 1 if --cache was specified)
- uint8_t writable;
- //! Path of virtual image file
- char *p_virtual_image_path;
- //! Path of virtual image info file
- char *p_info_path;
- //! Pointer to virtual info file
- char *p_info_file;
-} ts_OutputData;
-
//! Structure containing global xmount runtime infos
typedef struct s_XmountData {
//! Input image related data
ts_InputData input;
//! Morphing related data
ts_MorphingData morphing;
//! Cache file related data
ts_CacheData cache;
//! Output image related data
ts_OutputData output;
//! Enable debug output
uint8_t debug;
//! Set if we are allowed to set fuse's allow_other option
uint8_t may_set_fuse_allow_other;
//! Argv for FUSE
int fuse_argc;
//! Argv for FUSE
char **pp_fuse_argv;
//! Mount point
char *p_mountpoint;
//! Mutex to control concurrent read & write access on output image
pthread_mutex_t mutex_image_rw;
//! Mutex to control concurrent read access on info file
pthread_mutex_t mutex_info_read;
} ts_XmountData;
/*******************************************************************************
* Global vars
******************************************************************************/
//! Struct that contains various runtime configuration options
ts_XmountData glob_xmount;
/*******************************************************************************
* Xmount functions
******************************************************************************/
-int GetOutputImageSize(uint64_t*);
-int ReadOutputImageData(char*, off_t, size_t);
-int WriteOutputImageData(const char*, off_t, size_t);
#endif // XMOUNT_H
diff --git a/src/xmount_cache.c b/src/xmount_cache.c
new file mode 100644
index 0000000..576b3ef
--- /dev/null
+++ b/src/xmount_cache.c
@@ -0,0 +1,957 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "xmount_cache.h"
+#include "xmount.h"
+#include "macros.h"
+
+/*******************************************************************************
+ * Private definitions / macros
+ ******************************************************************************/
+#define LOG_WARNING(...) { \
+ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \
+}
+#define LOG_ERROR(...) { \
+ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \
+}
+#define LOG_DEBUG(...) { \
+ LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \
+}
+
+#ifndef __LP64__
+ //! Value used to indicate an uncached block entry
+ #define XMOUNT_CACHE_INVALID_INDEX 0xFFFFFFFFFFFFFFFFLL
+#else
+ #define XMOUNT_CACHE_INVALID_INDEX 0xFFFFFFFFFFFFFFFF
+#endif
+
+//! Structures and vars needed for write access
+#define XMOUNT_CACHE_FOLDER "/.xmount"
+#define XMOUNT_CACHE_BLOCK_FILE XMOUNT_CACHE_FOLDER "/blocks.data"
+#define XMOUNT_CACHE_BLOCK_INDEX_FILE XMOUNT_CACHE_FOLDER "/blocks.index"
+
+/*******************************************************************************
+ * Private types / structures / enums
+ ******************************************************************************/
+typedef struct s_XmountCacheHandle {
+ //! Cache file to save changes to
+ char *p_cache_file;
+ //! Handle to cache file
+ hGidaFs h_cache_file;
+ //! Handle to block cache
+ hGidaFsFile h_block_cache;
+ //! Handle to block cache index
+ hGidaFsFile h_block_cache_index;
+ //! In-memory copy of cache index
+ uint64_t *p_block_cache_index;
+ //! Length (in elements) of in-memory block cache index
+ uint64_t block_cache_index_len;
+ // TODO: Move to s_XmountData
+ //! Overwrite existing cache
+ uint8_t overwrite_cache;
+} ts_XmountCacheHandle, *pts_XmountCacheHandle;
+
+/*******************************************************************************
+ * Private functions declarations
+ ******************************************************************************/
+/*!
+ * \brief Create a new xmount cache handle
+ *
+ * \param pp_h Pointer to an xmount cache handle
+ * \param p_file Cache file path / name
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_CreateHandle(pts_XmountCacheHandle *pp_h,
+ const char *p_file);
+
+/*!
+ * \brief Destroy an xmount cache handle
+ *
+ * \param pp_h Pointer to an xmount cache handle
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_DestroyHandle(pts_XmountCacheHandle *pp_h);
+
+/*!
+ * \brief Check if a file exists
+ *
+ * Checks if the given file p_file exists.
+ *
+ * \param p_file File to check for
+ * \return e_XmountCache_Error_None if file exists
+ */
+te_XmountCache_Error XmountCache_FileExists(const char *p_file);
+
+/*******************************************************************************
+ * Public functions implementations
+ ******************************************************************************/
+/*
+ * XmountCache_Create
+ */
+te_XmountCache_Error XmountCache_Create(pts_XmountCacheHandle *pp_h,
+ const char *p_file,
+ uint64_t image_size,
+ uint8_t overwrite)
+{
+ pts_XmountCacheHandle p_h=NULL;
+ teGidaFsError gidafs_ret=eGidaFsError_None;
+ te_XmountCache_Error ret=e_XmountCache_Error_None;
+
+ // Check params
+ if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer;
+ if(p_file==NULL) return e_XmountCache_Error_InvalidString;
+ if(strlen(p_file)==0) return e_XmountCache_Error_InvalidFile;
+
+ // Make sure file does not exist when overwrite was not specified
+ if(overwrite==0 && XmountCache_FileExists(p_file)==e_XmountCache_Error_None) {
+ // Given file exists and overwrite was not specified. This is fatal!
+ return e_XmountCache_Error_ExistingFile;
+ }
+
+ // Create new handle
+ ret=XmountCache_CreateHandle(&p_h,p_file);
+ if(ret!=e_XmountCache_Error_None) return ret;
+
+#define XMOUNTCACHE_CREATE__DESTROY_HANDLE do { \
+ ret=XmountCache_DestroyHandle(&p_h); \
+ if(ret!=e_XmountCache_Error_None) { \
+ LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", \
+ ret); \
+ } \
+ *pp_h=NULL; \
+} while(0)
+
+ // Create new cache file
+ gidafs_ret=GidaFsLib_NewFs(&(p_h->h_cache_file),
+ p_h->p_cache_file,
+ 0);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to create new xmount cache file '%s': Error code %u!\n",
+ p_h->p_cache_file,
+ gidafs_ret);
+ XMOUNTCACHE_CREATE__DESTROY_HANDLE;
+ return FALSE;
+ }
+
+#define XMOUNTCACHE_CREATE__CLOSE_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close xmount cache file '%s': " \
+ "Error code %u: Ignoring!\n", \
+ p_h->p_cache_file, \
+ gidafs_ret); \
+ } \
+} while(0)
+
+ // TODO: Check if cache file uses same block size as we do
+
+ // Create needed xmount subdirectory
+ gidafs_ret=GidaFsLib_CreateDir(p_h->h_cache_file,
+ XMOUNT_CACHE_FOLDER,
+ eGidaFsNodeFlag_RWXu);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to create cache file directory '%s': Error code %u!\n",
+ XMOUNT_CACHE_FOLDER,
+ gidafs_ret);
+ XMOUNTCACHE_CREATE__CLOSE_CACHE;
+ XMOUNTCACHE_CREATE__DESTROY_HANDLE;
+ return e_XmountCache_Error_FailedCacheInit;
+ }
+
+ // Create block cache file
+ gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file,
+ XMOUNT_CACHE_BLOCK_FILE,
+ &(p_h->h_block_cache),
+ eGidaFsOpenFileFlag_ReadWrite |
+ eGidaFsOpenFileFlag_CreateAlways,
+ eGidaFsNodeFlag_Rall | eGidaFsNodeFlag_Wusr);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to create block cache file '%s': Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret);
+ XMOUNTCACHE_CREATE__CLOSE_CACHE;
+ XMOUNTCACHE_CREATE__DESTROY_HANDLE;
+ return e_XmountCache_Error_FailedCacheInit;
+ }
+
+#define XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \
+ &(p_h->h_block_cache)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache file: Error code %u: " \
+ "Ignoring!\n", \
+ gidafs_ret); \
+ } \
+} while(0)
+
+ // Create block cache index file
+ gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file,
+ XMOUNT_CACHE_BLOCK_INDEX_FILE,
+ &(p_h->h_block_cache_index),
+ eGidaFsOpenFileFlag_ReadWrite |
+ eGidaFsOpenFileFlag_CreateAlways,
+ eGidaFsNodeFlag_Rall | eGidaFsNodeFlag_Wusr);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to create block cache index file '%s': Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret);
+ XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE;
+ XMOUNTCACHE_CREATE__CLOSE_CACHE;
+ XMOUNTCACHE_CREATE__DESTROY_HANDLE;
+ return e_XmountCache_Error_FailedCacheInit;
+ }
+
+#define XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX do { \
+ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \
+ &(p_h->h_block_cache_index)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache index file: Error code %u: " \
+ "Ignoring!\n", \
+ gidafs_ret); \
+ } \
+} while(0)
+
+ // Calculate how many cache blocks are needed and how big the cache block
+ // index must be
+ p_h->block_cache_index_len=image_size/XMOUNT_CACHE_BLOCK_SIZE;
+ if((image_size%XMOUNT_CACHE_BLOCK_SIZE)!=0) p_h->block_cache_index_len++;
+
+ LOG_DEBUG("Cache blocks: %" PRIu64 " entries using %" PRIu64 " bytes\n",
+ p_h->block_cache_index_len,
+ p_h->block_cache_index_len*sizeof(uint8_t));
+
+ // Prepare in-memory buffer for block cache index
+ p_h->p_block_cache_index=
+ (uint64_t*)calloc(1,p_h->block_cache_index_len*sizeof(uint64_t));
+ if(p_h->p_block_cache_index==NULL) {
+ XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX;
+ XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE;
+ XMOUNTCACHE_CREATE__CLOSE_CACHE;
+ XMOUNTCACHE_CREATE__DESTROY_HANDLE;
+ return e_XmountCache_Error_Alloc;
+ }
+
+ // Generate initial block cache index
+ for(uint64_t i=0;i<p_h->block_cache_index_len;i++) {
+ p_h->p_block_cache_index[i]=XMOUNT_CACHE_INVALID_INDEX;
+ }
+
+ // Write initial block cache index to cache file
+ if(UpdateBlockCacheIndex(XMOUNT_BLOCK_CACHE_INVALID_INDEX,0)!=TRUE) {
+ LOG_ERROR("Unable to generate initial block cache index file '%s': "
+ "Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret);
+ XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX;
+ XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE;
+ XMOUNTCACHE_CREATE__CLOSE_CACHE;
+ XMOUNTCACHE_CREATE__DESTROY_HANDLE;
+ return e_XmountCache_Error_FailedCacheInit;
+ }
+
+#undef XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX
+#undef XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE
+#undef XMOUNTCACHE_CREATE__CLOSE_CACHE
+#undef XMOUNTCACHE_CREATE__DESTROY_HANDLE
+
+ *pp_h=p_h;
+ return e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_Open
+ */
+te_XmountCache_Error XmountCache_Open(pts_XmountCacheHandle *pp_h,
+ const char *p_file,
+ uint64_t image_size)
+{
+ pts_XmountCacheHandle p_h=NULL;
+ teGidaFsError gidafs_ret=eGidaFsError_None;
+ te_XmountCache_Error ret=e_XmountCache_Error_None;
+
+ // Check params
+ if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer;
+ if(p_file==NULL) return e_XmountCache_Error_InvalidString;
+ if(strlen(p_file)==0) return e_XmountCache_Error_InvalidFile;
+
+ // Make sure file exists
+ if(XmountCache_FileExists(p_file)!=e_XmountCache_Error_None) {
+ // Given file does not exist. This is fatal!
+ return e_XmountCache_Error_InexistingFile;
+ }
+
+ // Create new handle
+ ret=XmountCache_CreateHandle(&p_h,p_file);
+ if(ret!=e_XmountCache_Error_None) return ret;
+
+#define XMOUNTCACHE_OPEN__DESTROY_HANDLE do { \
+ ret=XmountCache_DestroyHandle(&p_h); \
+ if(ret!=e_XmountCache_Error_None) { \
+ LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", \
+ ret); \
+ } \
+ *pp_h=NULL; \
+} while(0)
+
+ // Open cache file
+ gidafs_ret=GidaFsLib_OpenFs(&(p_h->h_cache_file),p_h->p_cache_file);
+ if(gidafs_ret!=eGidaFsError_None) {
+ // TODO: Check for old cache file type and inform user it isn't supported
+ // anymore!
+ LOG_ERROR("Couldn't open xmount cache file '%s': Error code %u!\n",
+ p_h->p_cache_file,
+ gidafs_ret)
+ return e_XmountCache_Error_FailedOpeningCache;
+ }
+
+#define XMOUNTCACHE_OPEN__CLOSE_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close xmount cache file '%s': " \
+ "Error code %u: Ignoring!\n", \
+ p_h->p_cache_file, \
+ gidafs_ret); \
+ } \
+} while(0)
+
+#define XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \
+ &(p_h->h_block_cache)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache file: Error code %u: " \
+ "Ignoring!\n", \
+ gidafs_ret); \
+ } \
+} while(0)
+
+#define XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX do { \
+ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \
+ &(p_h->h_block_cache_index)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache index file: Error code %u: " \
+ "Ignoring!\n", \
+ gidafs_ret); \
+ } \
+} while(0)
+
+
+
+
+
+
+
+
+
+/*
+
+
+#define INITCACHEFILE__CLOSE_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFs(&(glob_xmount.cache.h_cache_file)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close cache file: Error code %u: Ignoring!\n", \
+ gidafs_ret) \
+ } \
+} while(0)
+
+#define INITCACHEFILE__CLOSE_BLOCK_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file, \
+ &(glob_xmount.cache.h_block_cache)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache file: Error code %u: Ignoring!\n", \
+ gidafs_ret) \
+ } \
+} while(0)
+
+#define INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX do { \
+ gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file, \
+ &(glob_xmount.cache.h_block_cache_index)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache index file: Error code %u: " \
+ "Ignoring!\n", \
+ gidafs_ret) \
+ } \
+} while(0)
+
+ // TODO: Check if cache file uses same block size as we do
+
+ if(is_new_cache_file==1) {
+ // New cache file, create needed xmount subdirectory
+ gidafs_ret=GidaFsLib_CreateDir(glob_xmount.cache.h_cache_file,
+ XMOUNT_CACHE_FOLDER,
+ eGidaFsNodeFlag_RWXu);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to create cache file directory '%s': Error code %u!\n",
+ XMOUNT_CACHE_FOLDER,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_CACHE;
+ return FALSE;
+ }
+ }
+
+ // Open / Create block cache file
+ gidafs_ret=GidaFsLib_OpenFile(glob_xmount.cache.h_cache_file,
+ XMOUNT_CACHE_BLOCK_FILE,
+ &(glob_xmount.cache.h_block_cache),
+ eGidaFsOpenFileFlag_ReadWrite |
+ (is_new_cache_file==1 ?
+ eGidaFsOpenFileFlag_CreateAlways : 0),
+ eGidaFsNodeFlag_Rall |
+ eGidaFsNodeFlag_Wusr);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to open / create block cache file '%s': Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_CACHE;
+ return FALSE;
+ }
+
+ // Open / Create block cache index file
+ gidafs_ret=GidaFsLib_OpenFile(glob_xmount.cache.h_cache_file,
+ XMOUNT_CACHE_BLOCK_INDEX_FILE,
+ &(glob_xmount.cache.h_block_cache_index),
+ eGidaFsOpenFileFlag_ReadWrite |
+ (is_new_cache_file==1 ?
+ eGidaFsOpenFileFlag_CreateAlways : 0),
+ eGidaFsNodeFlag_Rall |
+ eGidaFsNodeFlag_Wusr);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to open / create block cache index file '%s': "
+ "Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ return FALSE;
+ }
+
+ // Calculate how many cache blocks are needed and how big the cache block
+ // index must be
+ glob_xmount.cache.block_cache_index_len=image_size/CACHE_BLOCK_SIZE;
+ if((image_size%CACHE_BLOCK_SIZE)!=0) {
+ glob_xmount.cache.block_cache_index_len++;
+ }
+
+ LOG_DEBUG("Cache blocks: %u (0x%04X) entries using %zd (0x%08zX) bytes\n",
+ glob_xmount.cache.block_cache_index_len,
+ glob_xmount.cache.block_cache_index_len,
+ glob_xmount.cache.block_cache_index_len*
+ sizeof(t_CacheFileBlockIndex),
+ glob_xmount.cache.block_cache_index_len*
+ sizeof(t_CacheFileBlockIndex))
+
+ // Prepare in-memory buffer for block cache index
+ XMOUNT_MALLOC(glob_xmount.cache.p_block_cache_index,
+ t_CacheFileBlockIndex*,
+ glob_xmount.cache.block_cache_index_len*
+ sizeof(t_CacheFileBlockIndex))
+
+ if(is_new_cache_file==1) {
+ // Generate initial block cache index
+ for(uint64_t i=0;i<glob_xmount.cache.block_cache_index_len;i++) {
+ glob_xmount.cache.p_block_cache_index[i]=CACHE_BLOCK_FREE;
+ }
+ // Write initial block cache index to cache file
+ if(UpdateBlockCacheIndex(XMOUNT_BLOCK_CACHE_INVALID_INDEX,0)!=TRUE) {
+ LOG_ERROR("Unable to generate initial block cache index file '%s': "
+ "Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ } else {
+ // Existing cache file, make sure block cache index has correct size
+ gidafs_ret=GidaFsLib_GetFileSize(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache_index,
+ &blockindex_size);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to get block cache index file size: Error code %u!\n",
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ if(blockindex_size%sizeof(t_CacheFileBlockIndex)!=0 ||
+ (blockindex_size/sizeof(t_CacheFileBlockIndex))!=
+ glob_xmount.cache.block_cache_index_len)
+ {
+ // TODO: Be more helpfull in error message
+ LOG_ERROR("Block cache index size is incorrect for given input image!\n")
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ // Read block cache index into memory
+ gidafs_ret=GidaFsLib_ReadFile(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache_index,
+ 0,
+ blockindex_size,
+ glob_xmount.cache.p_block_cache_index,
+ &read);
+ if(gidafs_ret!=eGidaFsError_None || read!=blockindex_size) {
+ LOG_ERROR("Unable to read block cache index: Error code %u!\n",
+ gidafs_ret);
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ }
+
+#undef INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX
+#undef INITCACHEFILE__CLOSE_BLOCK_CACHE
+#undef INITCACHEFILE__CLOSE_CACHE
+*/
+
+#undef XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX
+#undef XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE
+#undef XMOUNTCACHE_OPEN__CLOSE_CACHE
+#undef XMOUNTCACHE_OPEN__DESTROY_HANDLE
+
+ *pp_h=p_h;
+ return e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_Close
+ */
+te_XmountCache_Error XmountCache_Close(pts_XmountCacheHandle *pp_h) {
+ pts_XmountCacheHandle p_h=NULL;
+ te_XmountCache_Error ret=e_XmountCache_Error_None;
+
+
+
+ *pp_h=NULL;
+ return e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_BlockCacheRead
+ */
+te_XmountCache_Error XmountCache_BlockCacheRead(pts_XmountCacheHandle p_h,
+ char *p_buf,
+ uint64_t block,
+ uint64_t block_offset,
+ uint64_t count)
+{
+ te_XmountCache_Error ret=e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_BlockCacheWrite
+ */
+te_XmountCache_Error XmountCache_BlockCacheWrite(pts_XmountCacheHandle p_h,
+ char *p_buf,
+ uint64_t block,
+ uint64_t block_offset,
+ uint64_t count)
+{
+ te_XmountCache_Error ret=e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_BlockCacheAppend
+ */
+te_XmountCache_Error XmountCache_BlockCacheAppend(pts_XmountCacheHandle p_h,
+ char *p_buf,
+ uint64_t block)
+{
+ te_XmountCache_Error ret=e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_IsBlockCached
+ */
+te_XmountCache_Error XmountCache_IsBlockCached(pts_XmountCacheHandle p_h,
+ uint64_t block)
+{
+ te_XmountCache_Error ret=e_XmountCache_Error_None;
+}
+
+/*******************************************************************************
+ * Private functions implementations
+ ******************************************************************************/
+/*
+ * XmountCache_CreateHandle
+ */
+te_XmountCache_Error XmountCache_CreateHandle(pts_XmountCacheHandle *pp_h,
+ const char *p_file)
+{
+ pts_XmountCacheHandle p_h=NULL;
+
+ // Check given handle pointer
+ if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer;
+
+ // Alloc memory for handle
+ p_h=(pts_XmountCacheHandle)calloc(1,sizeof(ts_XmountCacheHandle));
+ if(p_h==NULL) {
+ *pp_h=NULL;
+ return e_XmountCache_Error_Alloc;
+ }
+
+ // Init values. The p_cache_file alloc and memcpy works corrently as strlen()
+ // counts the amount of bytes, not chars. No UTF8-issue here.
+ p_h->p_cache_file=(char*)calloc(1,strlen(p_file)+1);
+ if(p_h->p_cache_file==NULL) {
+ free(p_h);
+ *pp_h=NULL;
+ return e_XmountCache_Error_Alloc;
+ }
+ memcpy(p_h->p_cache_file,p_file,strlen(p_file));
+ p_h->h_cache_file=NULL;
+ p_h->h_block_cache=NULL;
+ p_h->h_block_cache_index=NULL;
+ p_h->p_block_cache_index=NULL;
+
+ // Return new handle
+ *pp_h=p_h;
+ return e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_DestroyHandle
+ */
+te_XmountCache_Error XmountCache_DestroyHandle(pts_XmountCacheHandle *pp_h) {
+ pts_XmountCacheHandle p_h=NULL;
+
+ // Check given handle pointer
+ if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer;
+ if(*pp_h==NULL) return e_XmountCache_Error_InvalidHandle;
+ p_h=*pp_h;
+
+ // Free handle
+ if(p_h->p_cache_file!=NULL) free(p_h->p_cache_file);
+ if(p_h->p_block_cache_index!=NULL) free(p_h->p_block_cache_index);
+ free(p_h);
+
+ // Return destroyed handle
+ *pp_h=NULL;
+ return e_XmountCache_Error_None;
+}
+
+/*
+ * XmountCache_FileExists
+ */
+te_XmountCache_Error XmountCache_FileExists(const char *p_file) {
+ struct stat statbuf;
+
+ if(lstat(p_file,&statbuf)==0) return e_XmountCache_Error_None;
+ else return e_XmountCache_Error_InexistingFile;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//! Create / load cache file to enable virtual write support
+/*!
+ * \return TRUE on success, FALSE on error
+ */
+int InitCacheFile() {
+ uint64_t blockindex_size=0;
+ uint64_t image_size=0;
+ uint64_t read=0;
+ uint8_t is_new_cache_file=0;
+ teGidaFsError gidafs_ret=eGidaFsError_None;
+
+ // Get input image size for later use
+ if(!GetMorphedImageSize(&image_size)) {
+ LOG_ERROR("Couldn't get morphed image size!\n")
+ return FALSE;
+ }
+
+ if(!glob_xmount.cache.overwrite_cache) {
+ // Try to open an existing cache file or create a new one
+ gidafs_ret=GidaFsLib_OpenFs(&(glob_xmount.cache.h_cache_file),
+ glob_xmount.cache.p_cache_file);
+ if(gidafs_ret!=eGidaFsError_None &&
+ gidafs_ret!=eGidaFsError_FailedOpeningFsFile)
+ {
+ // TODO: Check for old cache file type and inform user it isn't supported
+ // anymore!
+ LOG_ERROR("Couldn't open cache file '%s': Error code %u!\n",
+ glob_xmount.cache.p_cache_file,
+ gidafs_ret)
+ return FALSE;
+ } else if(gidafs_ret==eGidaFsError_FailedOpeningFsFile) {
+ // Unable to open cache file. It might simply not exist.
+ LOG_DEBUG("Cache file '%s' does not exist. Creating new one\n",
+ glob_xmount.cache.p_cache_file)
+ gidafs_ret=GidaFsLib_NewFs(&(glob_xmount.cache.h_cache_file),
+ glob_xmount.cache.p_cache_file,
+ 0);
+ if(gidafs_ret!=eGidaFsError_None) {
+ // There is really a problem opening/creating the file
+ LOG_ERROR("Couldn't open cache file '%s': Error code %u!\n",
+ glob_xmount.cache.p_cache_file,
+ gidafs_ret)
+ return FALSE;
+ }
+ is_new_cache_file=1;
+ }
+ } else {
+ // Overwrite existing cache file or create a new one
+ gidafs_ret=GidaFsLib_NewFs(&(glob_xmount.cache.h_cache_file),
+ glob_xmount.cache.p_cache_file,
+ 0);
+ if(gidafs_ret!=eGidaFsError_None) {
+ // There is really a problem opening/creating the file
+ LOG_ERROR("Couldn't open cache file '%s': Error code %u!\n",
+ glob_xmount.cache.p_cache_file,
+ gidafs_ret)
+ return FALSE;
+ }
+ is_new_cache_file=1;
+ }
+
+#define INITCACHEFILE__CLOSE_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFs(&(glob_xmount.cache.h_cache_file)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close cache file: Error code %u: Ignoring!\n", \
+ gidafs_ret) \
+ } \
+} while(0)
+
+#define INITCACHEFILE__CLOSE_BLOCK_CACHE do { \
+ gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file, \
+ &(glob_xmount.cache.h_block_cache)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache file: Error code %u: Ignoring!\n", \
+ gidafs_ret) \
+ } \
+} while(0)
+
+#define INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX do { \
+ gidafs_ret=GidaFsLib_CloseFile(glob_xmount.cache.h_cache_file, \
+ &(glob_xmount.cache.h_block_cache_index)); \
+ if(gidafs_ret!=eGidaFsError_None) { \
+ LOG_ERROR("Unable to close block cache index file: Error code %u: " \
+ "Ignoring!\n", \
+ gidafs_ret) \
+ } \
+} while(0)
+
+ // TODO: Check if cache file uses same block size as we do
+
+ if(is_new_cache_file==1) {
+ // New cache file, create needed xmount subdirectory
+ gidafs_ret=GidaFsLib_CreateDir(glob_xmount.cache.h_cache_file,
+ XMOUNT_CACHE_FOLDER,
+ eGidaFsNodeFlag_RWXu);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to create cache file directory '%s': Error code %u!\n",
+ XMOUNT_CACHE_FOLDER,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_CACHE;
+ return FALSE;
+ }
+ }
+
+ // Open / Create block cache file
+ gidafs_ret=GidaFsLib_OpenFile(glob_xmount.cache.h_cache_file,
+ XMOUNT_CACHE_BLOCK_FILE,
+ &(glob_xmount.cache.h_block_cache),
+ eGidaFsOpenFileFlag_ReadWrite |
+ (is_new_cache_file==1 ?
+ eGidaFsOpenFileFlag_CreateAlways : 0),
+ eGidaFsNodeFlag_Rall |
+ eGidaFsNodeFlag_Wusr);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to open / create block cache file '%s': Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_CACHE;
+ return FALSE;
+ }
+
+ // Open / Create block cache index file
+ gidafs_ret=GidaFsLib_OpenFile(glob_xmount.cache.h_cache_file,
+ XMOUNT_CACHE_BLOCK_INDEX_FILE,
+ &(glob_xmount.cache.h_block_cache_index),
+ eGidaFsOpenFileFlag_ReadWrite |
+ (is_new_cache_file==1 ?
+ eGidaFsOpenFileFlag_CreateAlways : 0),
+ eGidaFsNodeFlag_Rall |
+ eGidaFsNodeFlag_Wusr);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to open / create block cache index file '%s': "
+ "Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ return FALSE;
+ }
+
+ // Calculate how many cache blocks are needed and how big the cache block
+ // index must be
+ glob_xmount.cache.block_cache_index_len=image_size/CACHE_BLOCK_SIZE;
+ if((image_size%CACHE_BLOCK_SIZE)!=0) {
+ glob_xmount.cache.block_cache_index_len++;
+ }
+
+ LOG_DEBUG("Cache blocks: %u (0x%04X) entries using %zd (0x%08zX) bytes\n",
+ glob_xmount.cache.block_cache_index_len,
+ glob_xmount.cache.block_cache_index_len,
+ glob_xmount.cache.block_cache_index_len*
+ sizeof(t_CacheFileBlockIndex),
+ glob_xmount.cache.block_cache_index_len*
+ sizeof(t_CacheFileBlockIndex))
+
+ // Prepare in-memory buffer for block cache index
+ XMOUNT_MALLOC(glob_xmount.cache.p_block_cache_index,
+ t_CacheFileBlockIndex*,
+ glob_xmount.cache.block_cache_index_len*
+ sizeof(t_CacheFileBlockIndex))
+
+ if(is_new_cache_file==1) {
+ // Generate initial block cache index
+ for(uint64_t i=0;i<glob_xmount.cache.block_cache_index_len;i++) {
+ glob_xmount.cache.p_block_cache_index[i]=CACHE_BLOCK_FREE;
+ }
+ // Write initial block cache index to cache file
+ if(UpdateBlockCacheIndex(XMOUNT_BLOCK_CACHE_INVALID_INDEX,0)!=TRUE) {
+ LOG_ERROR("Unable to generate initial block cache index file '%s': "
+ "Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_FILE,
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ } else {
+ // Existing cache file, make sure block cache index has correct size
+ gidafs_ret=GidaFsLib_GetFileSize(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache_index,
+ &blockindex_size);
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to get block cache index file size: Error code %u!\n",
+ gidafs_ret)
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ if(blockindex_size%sizeof(t_CacheFileBlockIndex)!=0 ||
+ (blockindex_size/sizeof(t_CacheFileBlockIndex))!=
+ glob_xmount.cache.block_cache_index_len)
+ {
+ // TODO: Be more helpfull in error message
+ LOG_ERROR("Block cache index size is incorrect for given input image!\n")
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ // Read block cache index into memory
+ gidafs_ret=GidaFsLib_ReadFile(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache_index,
+ 0,
+ blockindex_size,
+ glob_xmount.cache.p_block_cache_index,
+ &read);
+ if(gidafs_ret!=eGidaFsError_None || read!=blockindex_size) {
+ LOG_ERROR("Unable to read block cache index: Error code %u!\n",
+ gidafs_ret);
+ INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX;
+ INITCACHEFILE__CLOSE_BLOCK_CACHE;
+ INITCACHEFILE__CLOSE_CACHE;
+ XMOUNT_FREE(glob_xmount.cache.p_block_cache_index);
+ return FALSE;
+ }
+ }
+
+#undef INITCACHEFILE__CLOSE_BLOCK_CACHE_INDEX
+#undef INITCACHEFILE__CLOSE_BLOCK_CACHE
+#undef INITCACHEFILE__CLOSE_CACHE
+
+ return TRUE;
+}
+
+//! Update block cache index
+/*!
+ * \return TRUE on success, FALSE on error
+ */
+int UpdateBlockCacheIndex(uint64_t index, t_CacheFileBlockIndex value) {
+ uint64_t update_size=0;
+ uint64_t written=0;
+ teGidaFsError gidafs_ret=eGidaFsError_None;
+ t_CacheFileBlockIndex *p_buf;
+
+ if(index!=XMOUNT_BLOCK_CACHE_INVALID_INDEX) {
+ // Update specific index element in cache file
+ p_buf=glob_xmount.cache.p_block_cache_index+index;
+ update_size=sizeof(t_CacheFileBlockIndex);
+ } else {
+ // Dump whole block cache index to cache file
+ p_buf=glob_xmount.cache.p_block_cache_index;
+ update_size=glob_xmount.cache.block_cache_index_len*
+ sizeof(t_CacheFileBlockIndex);
+ }
+
+ // Update cache file
+ gidafs_ret=GidaFsLib_WriteFile(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache_index,
+ 0,
+ update_size,
+ p_buf,
+ &written);
+ if(gidafs_ret!=eGidaFsError_None || written!=update_size) {
+ LOG_ERROR("Unable to update block cache index file '%s': "
+ "Error code %u!\n",
+ XMOUNT_CACHE_BLOCK_INDEX_FILE,
+ gidafs_ret)
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/src/xmount_cache.h b/src/xmount_cache.h
new file mode 100644
index 0000000..cfc318a
--- /dev/null
+++ b/src/xmount_cache.h
@@ -0,0 +1,176 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef XMOUNT_CACHE_H
+#define XMOUNT_CACHE_H
+
+#include <gidafs.h>
+
+/*******************************************************************************
+ * Public definitions / macros
+ ******************************************************************************/
+//! Default block cache block size to use (1 megabyte)
+#define XMOUNT_CACHE_BLOCK_SIZE (1024*1024)
+
+/*******************************************************************************
+ * Public types / structures / enums
+ ******************************************************************************/
+typedef struct s_XmountCacheHandle *pts_XmountCacheHandle;
+
+typedef enum e_XmountCache_Error {
+ //! No error
+ e_XmountCache_Error_None=0,
+ //! Error to allocate memory
+ e_XmountCache_Error_Alloc,
+ //! Invalid cache handle
+ e_XmountCache_Error_InvalidHandle,
+ //! Invalid pointer to a cache handle
+ e_XmountCache_Error_InvalidHandlePointer,
+ //! A given string is invalid
+ e_XmountCache_Error_InvalidString,
+ //! A given file path / name is invalid
+ e_XmountCache_Error_InvalidFile,
+ //! A given file does not exist
+ e_XmountCache_Error_InexistingFile,
+ //! A given file exists
+ e_XmountCache_Error_ExistingFile,
+ //! Unable to create needed xmount structures inside cache file
+ e_XmountCache_Error_FailedCacheInit,
+ //! Unable to open xmount cache file
+ e_XmountCache_Error_FailedOpeningCache,
+} te_XmountCache_Error;
+
+/*******************************************************************************
+ * Public functions declarations
+ ******************************************************************************/
+/*!
+ * \brief Create new xmount cache file
+ *
+ * Creates a new xmount cache file in the given file. If the given file already
+ * exists, this function will fail except if overwrite is set to 1.
+ *
+ * \param pp_handle Pointer to an xmount cache handle
+ * \param p_file File to use as cache file
+ * \param image_size Size of image in bytes for which this cache will be used
+ * \param overwrite If set to 1, overwrites existig cache file
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_Create(pts_XmountCacheHandle *pp_h,
+ const char *p_file,
+ uint64_t image_size,
+ uint8_t overwrite);
+
+/*!
+ * \brief Open an existing xmount cache file
+ *
+ * Opens the given xmount cache file.
+ *
+ * \param pp_handle Pointer to an xmount cache handle
+ * \param p_file File to use as cache file
+ * \param image_size Size of image in bytes for which this cache will be used
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_Open(pts_XmountCacheHandle *pp_h,
+ const char *p_file,
+ uint64_t image_size);
+
+/*!
+ * \brief Closes a previously openend xmount cache file
+ *
+ * Closes the given xmount cache file and frees any used resources.
+ *
+ * \param pp_handle Pointer to an xmount cache handle
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_Close(pts_XmountCacheHandle *pp_h);
+
+/*!
+ * \brief Read data from block cache
+ *
+ * Reads count bytes at offset block_offset from block number block and writes
+ * the read data into the pre-allocated buffer p_buf. The given block has to
+ * have been previously cached by a call to XmountCache_BlockCacheAppend().
+ *
+ * WARNING: This function does only work on single blocks. It is not possible to
+ * read beyond a block end.
+ *
+ * \param p_handle Xmount cache handle
+ * \param p_buf Buffer to store read data into
+ * \param block Number of block to read data from
+ * \param block_offset Offset inside block to start reading from
+ * \param count Amount of bytes to read
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_BlockCacheRead(pts_XmountCacheHandle p_h,
+ char *p_buf,
+ uint64_t block,
+ uint64_t block_offset,
+ uint64_t count);
+
+/*!
+ * \brief Write data to block cache
+ *
+ * Writes count bytes from buffer p_buf to block number block at offset
+ * block_offset. The given block has to have been previously cached by a call to
+ * XmountCache_BlockCacheAppend().
+ *
+ * WARNING: This function does only work on single blocks. It is not possible to
+ * write beyond a block end.
+ *
+ * \param p_handle Xmount cache handle
+ * \param p_buf Buffer with data to write
+ * \param block Number of block to write data to
+ * \param block_offset Offset inside block to start writing from
+ * \param count Amount of bytes to write
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_BlockCacheWrite(pts_XmountCacheHandle p_h,
+ char *p_buf,
+ uint64_t block,
+ uint64_t block_offset,
+ uint64_t count);
+
+/*!
+ * \brief Add a new block to the cache
+ *
+ * Adds the data inside p_buf to the cache file and saves it under the block
+ * number block. Every block must contain exactly XMOUNT_CACHE_BLOCK_SIZE bytes.
+ * Every block can only be cached once. Appending the same block twice will
+ * fail.
+ *
+ * \param p_handle Xmount cache handle
+ * \param p_buf Buffer with block data
+ * \param block Number of block under which to save given data
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_BlockCacheAppend(pts_XmountCacheHandle p_h,
+ char *p_buf,
+ uint64_t block);
+
+/*!
+ * \brief Chech if a block has previously been chached
+ *
+ * Checks if the given block has previously been cached.
+ *
+ * \param p_handle Xmount cache handle
+ * \param block Number of block to check
+ * \return e_XmountCache_Error_None on success
+ */
+te_XmountCache_Error XmountCache_IsBlockCached(pts_XmountCacheHandle p_h,
+ uint64_t block);
+
+#endif // XMOUNT_CACHE_H
diff --git a/src/xmount_input.c b/src/xmount_input.c
new file mode 100644
index 0000000..66fa81f
--- /dev/null
+++ b/src/xmount_input.c
@@ -0,0 +1,95 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <errno.h>
+
+#include "xmount_input.h"
+#include "xmount.h"
+
+#define LOG_WARNING(...) { \
+ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \
+}
+#define LOG_ERROR(...) { \
+ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \
+}
+#define LOG_DEBUG(...) { \
+ LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \
+}
+
+//! Read data from input image
+/*!
+ * \param p_image Image from which to read data
+ * \param p_buf Pointer to buffer to write read data to (must be preallocated!)
+ * \param offset Offset at which data should be read
+ * \param size Size of data which should be read (size of buffer)
+ * \param p_read Number of read bytes on success
+ * \return 0 on success, negated error code on error
+ */
+int ReadInputImageData(pts_InputImage p_image,
+ char *p_buf,
+ off_t offset,
+ size_t size,
+ size_t *p_read)
+{
+ int ret;
+ size_t to_read=0;
+ int read_errno=0;
+
+ LOG_DEBUG("Reading %zu bytes at offset %zu from input image '%s'\n",
+ size,
+ offset,
+ p_image->pp_files[0]);
+
+ // Make sure we aren't reading past EOF of image file
+ if(offset>=p_image->size) {
+ // Offset is beyond image size
+ LOG_DEBUG("Offset %zu is at / beyond size of input image '%s'\n",
+ offset,
+ p_image->pp_files[0]);
+ *p_read=0;
+ return 0;
+ }
+ if(offset+size>p_image->size) {
+ // Attempt to read data past EOF of image file
+ to_read=p_image->size-offset;
+ LOG_DEBUG("Attempt to read data past EOF of input image '%s'. "
+ "Correcting size from %zu to %zu\n",
+ p_image->pp_files[0],
+ size,
+ to_read);
+ } else to_read=size;
+
+ // Read data from image file (adding input image offset if one was specified)
+ ret=p_image->p_functions->Read(p_image->p_handle,
+ p_buf,
+ offset+glob_xmount.input.image_offset,
+ to_read,
+ p_read,
+ &read_errno);
+ if(ret!=0) {
+ LOG_ERROR("Couldn't read %zu bytes at offset %zu from input image "
+ "'%s': %s!\n",
+ to_read,
+ offset,
+ p_image->pp_files[0],
+ p_image->p_functions->GetErrorMessage(ret));
+ if(read_errno==0) return -EIO;
+ else return (read_errno*(-1));
+ }
+
+ return 0;
+}
diff --git a/src/xmount_input.h b/src/xmount_input.h
new file mode 100644
index 0000000..1d23d43
--- /dev/null
+++ b/src/xmount_input.h
@@ -0,0 +1,76 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef XMOUNT_INPUT_H
+#define XMOUNT_INPUT_H
+
+#include "../libxmount_input/libxmount_input.h"
+
+//! Structure containing infos about input libs
+typedef struct s_InputLib {
+ //! Filename of lib (without path)
+ char *p_name;
+ //! Handle to the loaded lib
+ void *p_lib;
+ //! Array of supported input types
+ char *p_supported_input_types;
+ //! Struct containing lib functions
+ ts_LibXmountInputFunctions lib_functions;
+} ts_InputLib, *pts_InputLib;
+
+//! Structure containing infos about input images
+typedef struct s_InputImage {
+ //! Image type
+ char *p_type;
+ //! Image source file count
+ uint64_t files_count;
+ //! Image source files
+ char **pp_files;
+ //! Input lib functions for this image
+ pts_LibXmountInputFunctions p_functions;
+ //! Image handle
+ void *p_handle;
+ //! Image size
+ uint64_t size;
+} ts_InputImage, *pts_InputImage;
+
+typedef struct s_InputData {
+ //! Loaded input lib count
+ uint32_t libs_count;
+ //! Array containing infos about loaded input libs
+ pts_InputLib *pp_libs;
+ //! Amount of input lib params (--inopts)
+ uint32_t lib_params_count;
+ //! Input lib params (--inopts)
+ pts_LibXmountOptions *pp_lib_params;
+ //! Input image count
+ uint64_t images_count;
+ //! Input images
+ pts_InputImage *pp_images;
+ //! Input image offset (--offset)
+ uint64_t image_offset;
+ //! Input image size limit (--sizelimit)
+ uint64_t image_size_limit;
+ //! MD5 hash of partial input image (lower 64 bit) (after morph)
+ uint64_t image_hash_lo;
+ //! MD5 hash of partial input image (higher 64 bit) (after morph)
+ uint64_t image_hash_hi;
+} ts_InputData;
+
+int ReadInputImageData(pts_InputImage, char*, off_t, size_t, size_t*);
+
+#endif // XMOUNT_INPUT_H
diff --git a/src/xmount_morphing.c b/src/xmount_morphing.c
new file mode 100644
index 0000000..bcc5a44
--- /dev/null
+++ b/src/xmount_morphing.c
@@ -0,0 +1,324 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <errno.h>
+
+#include "xmount_morphing.h"
+#include "xmount.h"
+#include "macros.h"
+
+#define LOG_WARNING(...) { \
+ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \
+}
+#define LOG_ERROR(...) { \
+ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \
+}
+#define LOG_DEBUG(...) { \
+ LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \
+}
+
+//! Get size of morphed image
+/*!
+ * \param p_size Buf to save size to
+ * \return TRUE on success, FALSE on error
+ */
+int GetMorphedImageSize(uint64_t *p_size) {
+ int ret;
+
+ ret=glob_xmount.morphing.p_functions->Size(glob_xmount.morphing.p_handle,
+ p_size);
+ if(ret!=0) {
+ LOG_ERROR("Unable to get morphed image size: %s!\n",
+ glob_xmount.morphing.p_functions->GetErrorMessage(ret));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//! Read data from morphed image
+/*!
+ * \param p_buf Pointer to buffer to write read data to (must be preallocated!)
+ * \param offset Offset at which data should be read
+ * \param size Size of data which should be read (size of buffer)
+ * \param p_read Number of read bytes on success
+ * \return TRUE on success, negated error code on error
+ */
+int ReadMorphedImageData(char *p_buf,
+ off_t offset,
+ size_t size,
+ size_t *p_read)
+{
+ uint64_t block_off=0;
+ uint64_t cur_block=0;
+ uint64_t cur_to_read=0;
+ uint64_t image_size=0;
+ size_t read=0;
+ size_t to_read=0;
+ int ret;
+ teGidaFsError gidafs_ret=eGidaFsError_None;
+
+ // Make sure we aren't reading past EOF of image file
+ if(GetMorphedImageSize(&image_size)!=TRUE) {
+ LOG_ERROR("Couldn't get size of morphed image!\n");
+ return -EIO;
+ }
+ if(offset>=image_size) {
+ // Offset is beyond image size
+ LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset);
+ *p_read=0;
+ return FALSE;
+ }
+ if(offset+size>image_size) {
+ // Attempt to read data past EOF of morphed image file
+ to_read=image_size-offset;
+ LOG_DEBUG("Attempt to read data past EOF of morphed image. Corrected size "
+ "from %zu to %" PRIu64 ".\n",
+ size,
+ to_read);
+ } else to_read=size;
+
+ // Calculate block to start reading data from
+ cur_block=offset/CACHE_BLOCK_SIZE;
+ block_off=offset%CACHE_BLOCK_SIZE;
+
+ // Read image data
+ while(to_read!=0) {
+ // Calculate how many bytes we have to read from this block
+ if(block_off+to_read>CACHE_BLOCK_SIZE) {
+ cur_to_read=CACHE_BLOCK_SIZE-block_off;
+ } else cur_to_read=to_read;
+
+ // Check if block is cached
+ if(glob_xmount.output.writable==TRUE &&
+ glob_xmount.cache.p_block_cache_index[cur_block]!=CACHE_BLOCK_FREE)
+ {
+ // Write support enabled and need to read altered data from cachefile
+ LOG_DEBUG("Reading %zu bytes at offset %" PRIu64
+ " from block cache file\n",
+ cur_to_read,
+ glob_xmount.cache.p_block_cache_index[cur_block]+block_off)
+
+ gidafs_ret=GidaFsLib_ReadFile(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache,
+ glob_xmount.cache.
+ p_block_cache_index[cur_block]+block_off,
+ cur_to_read,
+ p_buf,
+ &read);
+ if(gidafs_ret!=eGidaFsError_None || read!=cur_to_read) {
+ LOG_ERROR("Unable to read cached data from block %" PRIu64
+ ": Error code %u!\n",
+ cur_block,
+ gidafs_ret);
+ return -EIO;
+ }
+ } else {
+ // No write support or data not cached
+ ret=glob_xmount.morphing.p_functions->Read(glob_xmount.morphing.p_handle,
+ p_buf,
+ (cur_block*CACHE_BLOCK_SIZE)+
+ block_off,
+ cur_to_read,
+ &read);
+ if(ret!=0 || read!=cur_to_read) {
+ LOG_ERROR("Couldn't read %zu bytes at offset %zu from morphed image: "
+ "%s!\n",
+ cur_to_read,
+ offset,
+ glob_xmount.morphing.p_functions->GetErrorMessage(ret));
+ return -EIO;
+ }
+ LOG_DEBUG("Read %" PRIu64 " bytes at offset %" PRIu64
+ " from morphed image file\n",
+ cur_to_read,
+ (cur_block*CACHE_BLOCK_SIZE)+block_off);
+ }
+
+ cur_block++;
+ block_off=0;
+ p_buf+=cur_to_read;
+ to_read-=cur_to_read;
+ }
+
+ *p_read=to_read;
+ return TRUE;
+}
+
+//! Write data to morphed image
+/*!
+ * \param p_buf Buffer with data to write
+ * \param offset Offset to start writing at
+ * \param count Amount of bytes to write
+ * \param p_written Amount of successfully written bytes
+ * \return TRUE on success, negated error code on error
+ */
+int WriteMorphedImageData(const char *p_buf,
+ off_t offset,
+ size_t count,
+ size_t *p_written)
+{
+ uint64_t block_off=0;
+ uint64_t cur_block=0;
+ uint64_t cur_to_read=0;
+ uint64_t cur_to_write=0;
+ uint64_t image_size=0;
+ uint64_t read=0;
+ size_t written=0;
+ size_t to_write=0;
+ int ret;
+ teGidaFsError gidafs_ret=eGidaFsError_None;
+ char *p_buf2=NULL;
+
+ // Make sure we aren't writing past EOF of image file
+ if(GetMorphedImageSize(&image_size)!=TRUE) {
+ LOG_ERROR("Couldn't get size of morphed image!\n");
+ return -EIO;
+ }
+ if(offset>=image_size) {
+ // Offset is beyond image size
+ LOG_DEBUG("Offset %zu is at / beyond size of morphed image.\n",offset);
+ *p_written=0;
+ return 0;
+ }
+ if(offset+count>image_size) {
+ // Attempt to write data past EOF of morphed image file
+ to_write=image_size-offset;
+ LOG_DEBUG("Attempt to write data past EOF of morphed image. Corrected size "
+ "from %zu to %" PRIu64 ".\n",
+ count,
+ to_write);
+ } else to_write=count;
+
+ // Calculate block to start writing data to
+ cur_block=offset/CACHE_BLOCK_SIZE;
+ block_off=offset%CACHE_BLOCK_SIZE;
+
+ while(to_write!=0) {
+ // Calculate how many bytes we have to write to this block
+ if(block_off+to_write>CACHE_BLOCK_SIZE) {
+ cur_to_write=CACHE_BLOCK_SIZE-block_off;
+ } else cur_to_write=to_write;
+
+ // Check if block is cached
+ if(glob_xmount.cache.p_block_cache_index[cur_block]!=CACHE_BLOCK_FREE) {
+ // Block is cached
+ gidafs_ret=GidaFsLib_WriteFile(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache,
+ glob_xmount.cache.
+ p_block_cache_index[cur_block]+block_off,
+ cur_to_write,
+ p_buf,
+ &written);
+ if(gidafs_ret!=eGidaFsError_None || written!=cur_to_write) {
+ LOG_ERROR("Unable to write data to cached block %" PRIu64
+ ": Error code %u!\n",
+ cur_block,
+ gidafs_ret);
+ return -EIO;
+ }
+
+ LOG_DEBUG("Wrote %" PRIu64 " bytes at offset %" PRIu64
+ " to block cache file\n",
+ cur_to_write,
+ glob_xmount.cache.p_block_cache_index[cur_block]+block_off);
+ } else {
+ // Uncached block. Need to cache entire new block
+ // Prepare new write buffer
+ XMOUNT_MALLOC(p_buf2,char*,CACHE_BLOCK_SIZE);
+ memset(p_buf2,0x00,CACHE_BLOCK_SIZE);
+
+ // Read full block from morphed image
+ cur_to_read=CACHE_BLOCK_SIZE;
+ if((cur_block*CACHE_BLOCK_SIZE)+CACHE_BLOCK_SIZE>image_size) {
+ cur_to_read=CACHE_BLOCK_SIZE-(((cur_block*CACHE_BLOCK_SIZE)+
+ CACHE_BLOCK_SIZE)-image_size);
+ }
+ ret=glob_xmount.morphing.p_functions->Read(glob_xmount.morphing.p_handle,
+ p_buf2,
+ cur_block*CACHE_BLOCK_SIZE,
+ cur_to_read,
+ &read);
+ if(ret!=0 || read!=cur_to_read) {
+ LOG_ERROR("Couldn't read %" PRIu64 " bytes at offset %zu "
+ "from morphed image: %s!\n",
+ cur_to_read,
+ offset,
+ glob_xmount.morphing.p_functions->GetErrorMessage(ret));
+ XMOUNT_FREE(p_buf2);
+ return -EIO;
+ }
+
+ // Set changed data
+ memcpy(p_buf2+block_off,p_buf,cur_to_write);
+
+ // Write new block to block cache
+ // Get current block cache size
+ gidafs_ret=GidaFsLib_GetFileSize(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache,
+ &(glob_xmount.cache.
+ p_block_cache_index[cur_block]));
+ if(gidafs_ret!=eGidaFsError_None) {
+ LOG_ERROR("Unable to get current block cache size: Error code %u!\n",
+ gidafs_ret);
+ XMOUNT_FREE(p_buf2);
+ return -EIO;
+ }
+ // Append new block
+ gidafs_ret=GidaFsLib_WriteFile(glob_xmount.cache.h_cache_file,
+ glob_xmount.cache.h_block_cache,
+ glob_xmount.cache.
+ p_block_cache_index[cur_block],
+ CACHE_BLOCK_SIZE,
+ p_buf2,
+ &written);
+ if(gidafs_ret!=eGidaFsError_None || written!=cur_to_write) {
+ LOG_ERROR("Unable to write data to cached block %" PRIu64
+ ": Error code %u!\n",
+ cur_block,
+ gidafs_ret);
+ XMOUNT_FREE(p_buf2);
+ return -EIO;
+ }
+ XMOUNT_FREE(p_buf2);
+ // Update on-disk block cache index
+ ret=UpdateBlockCacheIndex(cur_block,
+ glob_xmount.cache.p_block_cache_index[
+ cur_block]);
+ if(ret!=TRUE) {
+ LOG_ERROR("Unable to update block cache index %" PRIu64
+ ": Error code %u!\n",
+ cur_block,
+ gidafs_ret);
+ return -EIO;
+ }
+
+ LOG_DEBUG("Updated cache file block index: Number=%" PRIu64
+ ", Data offset=%" PRIu64 "\n",
+ cur_block,
+ glob_xmount.cache.p_block_cache_index[cur_block]);
+ }
+
+ block_off=0;
+ cur_block++;
+ p_buf+=cur_to_write;
+ to_write-=cur_to_write;
+ }
+
+ *p_written=to_write;
+ return TRUE;
+}
diff --git a/src/xmount_morphing.h b/src/xmount_morphing.h
new file mode 100644
index 0000000..d0c0e10
--- /dev/null
+++ b/src/xmount_morphing.h
@@ -0,0 +1,59 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef XMOUNT_MORPHING_H
+#define XMOUNT_MORPHING_H
+
+#include "../libxmount_morphing/libxmount_morphing.h"
+
+//! Structure containing infos about morphing libs
+typedef struct s_MorphingLib {
+ //! Filename of lib (without path)
+ char *p_name;
+ //! Handle to the loaded lib
+ void *p_lib;
+ //! Array of supported morphing types
+ char *p_supported_morphing_types;
+ //! Struct containing lib functions
+ ts_LibXmountMorphingFunctions lib_functions;
+} ts_MorphingLib, *pts_MorphingLib;
+
+//! Structures and vars needed for morph support
+typedef struct s_MorphingData {
+ //! Loaded morphing lib count
+ uint32_t libs_count;
+ //! Array containing infos about loaded morphing libs
+ pts_MorphingLib *pp_libs;
+ //! Specified morphing type (--morph)
+ char *p_morph_type;
+ //! Amount of specified morphing lib params (--morphopts)
+ uint32_t lib_params_count;
+ //! Specified morphing lib params (--morphopts)
+ pts_LibXmountOptions *pp_lib_params;
+ //! Handle to initialized morphing lib
+ void *p_handle;
+ //! Morphing functions of initialized lib
+ pts_LibXmountMorphingFunctions p_functions;
+ //! Input image functions passed to morphing lib
+ ts_LibXmountMorphingInputFunctions input_image_functions;
+} ts_MorphingData;
+
+int GetMorphedImageSize(uint64_t*);
+int ReadMorphedImageData(char*, off_t, size_t, size_t*);
+int WriteMorphedImageData(const char*, off_t, size_t, size_t*);
+
+#endif // XMOUNT_MORPHING_H
diff --git a/src/xmount_output.c b/src/xmount_output.c
new file mode 100644
index 0000000..b389258
--- /dev/null
+++ b/src/xmount_output.c
@@ -0,0 +1,155 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <errno.h>
+
+#include "xmount_output.h"
+#include "xmount.h"
+
+#define LOG_WARNING(...) { \
+ LIBXMOUNT_LOG_WARNING(__VA_ARGS__); \
+}
+#define LOG_ERROR(...) { \
+ LIBXMOUNT_LOG_ERROR(__VA_ARGS__); \
+}
+#define LOG_DEBUG(...) { \
+ LIBXMOUNT_LOG_DEBUG(glob_xmount.debug,__VA_ARGS__); \
+}
+
+//! Get size of output image
+/*!
+ * \param p_size Pointer to an uint64_t to which the size will be written to
+ * \return TRUE on success, FALSE on error
+ */
+int GetOutputImageSize(uint64_t *p_size) {
+ int ret;
+ uint64_t output_image_size=0;
+
+ if(glob_xmount.output.image_size!=0) {
+ *p_size=glob_xmount.output.image_size;
+ return TRUE;
+ }
+
+ ret=glob_xmount.output.p_functions->Size(glob_xmount.output.p_handle,
+ &output_image_size);
+ if(ret!=0) {
+ LOG_ERROR("Couldn't get output image size!\n")
+ return FALSE;
+ }
+
+ glob_xmount.output.image_size=output_image_size;
+ *p_size=output_image_size;
+ return TRUE;
+}
+
+//! Read data from output image
+/*!
+ * \param p_buf Pointer to buffer to write read data to
+ * \param offset Offset at which data should be read
+ * \param size Size of data which should be read
+ * \return Number of read bytes on success or negated error code on error
+ */
+int ReadOutputImageData(char *p_buf, off_t offset, size_t size) {
+ uint64_t output_image_size;
+ size_t read=0;
+ int ret;
+
+ // Get output image size
+ if(GetOutputImageSize(&output_image_size)!=TRUE) {
+ LOG_ERROR("Couldn't get size of output image!\n")
+ return -EIO;
+ }
+
+ // Make sure request is within output image
+ if(offset>=output_image_size) {
+ LOG_DEBUG("Offset %zu is at / beyond size of output image.\n",offset);
+ return 0;
+ }
+ if(offset+size>output_image_size) {
+ LOG_DEBUG("Attempt to read data past EOF of output image. Correcting size "
+ "from %zu to %zu.\n",
+ size,
+ output_image_size-offset);
+ size=output_image_size-offset;
+ }
+
+ // Read data
+ ret=glob_xmount.output.p_functions->Read(glob_xmount.output.p_handle,
+ p_buf,
+ offset,
+ size,
+ &read);
+ if(ret!=0) {
+ LOG_ERROR("Unable to read %zu bytes at offset %zu from output image!\n",
+ size,
+ offset)
+ return ret;
+ } else if(read!=size) {
+ LOG_WARNING("Unable to read all requested data from output image!\n")
+ return read;
+ }
+
+ return size;
+}
+
+//! Write data to output image
+/*!
+ * \param p_buf Buffer with data to write
+ * \param offset Offset to write to
+ * \param size Amount of bytes to write
+ * \return Number of written bytes on success or "-1" on error
+ */
+int WriteOutputImageData(const char *p_buf, off_t offset, size_t size) {
+ uint64_t output_image_size;
+ int ret;
+ size_t written;
+
+ // Get output image size
+ if(!GetOutputImageSize(&output_image_size)) {
+ LOG_ERROR("Couldn't get output image size!\n")
+ return -1;
+ }
+
+ // Make sure write is within output image
+ if(offset>=output_image_size) {
+ LOG_ERROR("Attempt to write beyond EOF of output image file!\n")
+ return -1;
+ }
+ if(offset+size>output_image_size) {
+ LOG_DEBUG("Attempt to write past EOF of output image file. Correcting size "
+ "from %zu to %zu.\n",
+ size,
+ output_image_size-offset);
+ size=output_image_size-offset;
+ }
+
+ ret=glob_xmount.output.p_functions->Write(glob_xmount.output.p_handle,
+ p_buf,
+ offset,
+ size,
+ &written);
+ if(ret!=0) {
+ LOG_ERROR("Unable to write %zu bytes at offset %zu to output image!\n",
+ offset,
+ size)
+ return ret;
+ } else if(written!=size) {
+ LOG_WARNING("Unable to write all requested data to output image!\n")
+ }
+
+ return size;
+}
diff --git a/src/xmount_output.h b/src/xmount_output.h
new file mode 100644
index 0000000..ca4f67e
--- /dev/null
+++ b/src/xmount_output.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+* xmount Copyright (c) 2008-2016 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef XMOUNT_OUTPUT_H
+#define XMOUNT_OUTPUT_H
+
+#include "../libxmount_output/libxmount_output.h"
+
+//! Structure containing infos about output libs
+typedef struct s_OutputLib {
+ //! Filename of lib (without path)
+ char *p_name;
+ //! Handle to the loaded lib
+ void *p_lib;
+ //! Array of supported output formats
+ char *p_supported_output_formats;
+ //! Struct containing lib functions
+ ts_LibXmountOutput_Functions lib_functions;
+} ts_OutputLib, *pts_OutputLib;
+
+//! Structure containing infos about output image
+typedef struct s_OutputData {
+ //! Loaded output lib count
+ uint32_t libs_count;
+ //! Array containing infos about loaded output libs
+ pts_OutputLib *pp_libs;
+ //! Specified output format (--out)
+ char *p_output_format;
+ //! Amount of specified output lib params
+ uint32_t lib_params_count;
+ //! Specified output lib params (--outopts)
+ pts_LibXmountOptions *pp_lib_params;
+ //! Handle to initialized output lib
+ void *p_handle;
+ //! Transformation functions of initialized lib
+ pts_LibXmountOutput_Functions p_functions;
+ //! Input image functions passed to output lib
+ ts_LibXmountOutput_InputFunctions input_functions;
+ //! Size
+ uint64_t image_size;
+ //! Writable? (Set to 1 if --cache was specified)
+ uint8_t writable;
+ //! Path of virtual image file
+ char *p_virtual_image_path;
+ //! Path of virtual image info file
+ char *p_info_path;
+ //! Pointer to virtual info file
+ char *p_info_file;
+} ts_OutputData;
+
+int GetOutputImageSize(uint64_t*);
+int ReadOutputImageData(char*, off_t, size_t);
+int WriteOutputImageData(const char*, off_t, size_t);
+
+#endif // XMOUNT_OUTPUT_H

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 10:56 AM (6 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1176900
Default Alt Text
(210 KB)

Event Timeline