diff --git a/src/xmount_cache.c b/src/xmount_cache.c index 9538c28..38b49de 100644 --- a/src/xmount_cache.c +++ b/src/xmount_cache.c @@ -1,798 +1,798 @@ /******************************************************************************* * xmount Copyright (c) 2008-2016 by Gillen Daniel * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include #include #include #include #include "xmount_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); /*! * \brief Updates a block cache entry * * Updates the given block cache index entry on disk. If the special value * XMOUNT_CACHE_INVALID_INDEX is given as entry value, the whole block cache * index is updated. * * \param p_h Cache handle * \param entry Block cache entry number to update * \return e_XmountCache_Error_None on success */ te_XmountCache_Error XmountCache_UpdateIndex(pts_XmountCacheHandle p_h, uint64_t entry); /******************************************************************************* * Public functions implementations ******************************************************************************/ /* * XmountCache_Create */ te_XmountCache_Error XmountCache_Create(pts_XmountCacheHandle *pp_h, const char *p_file, uint64_t image_size, uint8_t overwrite) { pts_XmountCacheHandle p_h=NULL; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer; if(p_file==NULL) return e_XmountCache_Error_InvalidString; if(strlen(p_file)==0) return e_XmountCache_Error_InvalidFile; // Make sure file does not exist when overwrite was not specified if(overwrite==0 && XmountCache_FileExists(p_file)==e_XmountCache_Error_None) { // Given file exists and overwrite was not specified. This is fatal! return e_XmountCache_Error_ExistingFile; } // Create new handle ret=XmountCache_CreateHandle(&p_h,p_file); if(ret!=e_XmountCache_Error_None) return ret; #define XMOUNTCACHE_CREATE__DESTROY_HANDLE do { \ ret=XmountCache_DestroyHandle(&p_h); \ if(ret!=e_XmountCache_Error_None) { \ LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", \ ret); \ } \ *pp_h=NULL; \ } while(0) // Create new cache file gidafs_ret=GidaFsLib_NewFs(&(p_h->h_cache_file), p_h->p_cache_file, 0); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create new xmount cache file '%s': Error code %u!\n", p_h->p_cache_file, gidafs_ret); XMOUNTCACHE_CREATE__DESTROY_HANDLE; return FALSE; } #define XMOUNTCACHE_CREATE__CLOSE_CACHE do { \ gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close xmount cache file '%s': " \ "Error code %u: Ignoring!\n", \ p_h->p_cache_file, \ gidafs_ret); \ } \ } while(0) // TODO: Check if cache file uses same block size as we do // Create needed xmount subdirectory gidafs_ret=GidaFsLib_CreateDir(p_h->h_cache_file, XMOUNT_CACHE_FOLDER, eGidaFsNodeFlag_RWXu); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create cache file directory '%s': Error code %u!\n", XMOUNT_CACHE_FOLDER, gidafs_ret); XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; return e_XmountCache_Error_FailedCacheInit; } // Create block cache file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_FILE, &(p_h->h_block_cache), eGidaFsOpenFileFlag_ReadWrite | eGidaFsOpenFileFlag_CreateAlways, eGidaFsNodeFlag_Rall | eGidaFsNodeFlag_Wusr); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create block cache file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedCacheInit; } #define XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Create block cache index file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_INDEX_FILE, &(p_h->h_block_cache_index), eGidaFsOpenFileFlag_ReadWrite | eGidaFsOpenFileFlag_CreateAlways, eGidaFsNodeFlag_Rall | eGidaFsNodeFlag_Wusr); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to create block cache index file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE; XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedCacheInit; } #define XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache_index)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache index file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Calculate how many cache blocks are needed and how big the cache block // index must be p_h->block_cache_index_len=image_size/XMOUNT_CACHE_BLOCK_SIZE; if((image_size%XMOUNT_CACHE_BLOCK_SIZE)!=0) p_h->block_cache_index_len++; LOG_DEBUG("Cache blocks: %" PRIu64 " entries using %" PRIu64 " bytes\n", p_h->block_cache_index_len, p_h->block_cache_index_len*sizeof(uint8_t)); // Prepare in-memory buffer for block cache index p_h->p_block_cache_index= (uint64_t*)calloc(1,p_h->block_cache_index_len*sizeof(uint64_t)); if(p_h->p_block_cache_index==NULL) { XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE; XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; return e_XmountCache_Error_Alloc; } // Generate initial block cache index for(uint64_t i=0;iblock_cache_index_len;i++) { p_h->p_block_cache_index[i]=XMOUNT_CACHE_INVALID_INDEX; } // Write initial block cache index to cache file ret=XmountCache_UpdateIndex(p_h,XMOUNT_CACHE_INVALID_INDEX); if(ret!=e_XmountCache_Error_None) { LOG_ERROR("Unable to update initial block cache index file: " "Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, ret); XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE; XMOUNTCACHE_CREATE__CLOSE_CACHE; XMOUNTCACHE_CREATE__DESTROY_HANDLE; return ret; } #undef XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE_INDEX #undef XMOUNTCACHE_CREATE__CLOSE_BLOCK_CACHE #undef XMOUNTCACHE_CREATE__CLOSE_CACHE #undef XMOUNTCACHE_CREATE__DESTROY_HANDLE *pp_h=p_h; return e_XmountCache_Error_None; } /* * XmountCache_Open */ te_XmountCache_Error XmountCache_Open(pts_XmountCacheHandle *pp_h, const char *p_file, uint64_t image_size) { uint64_t blockindex_size=0; uint64_t read=0; pts_XmountCacheHandle p_h=NULL; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer; if(p_file==NULL) return e_XmountCache_Error_InvalidString; if(strlen(p_file)==0) return e_XmountCache_Error_InvalidFile; - // Make sure file exists + // If file does not exist, create it if(XmountCache_FileExists(p_file)!=e_XmountCache_Error_None) { - // Given file does not exist. This is fatal! - return e_XmountCache_Error_InexistingFile; + // Given file does not exist. Call XmountCache_Create instead! + return XmountCache_Create(pp_h,p_file,image_size,0); } // Create new handle ret=XmountCache_CreateHandle(&p_h,p_file); if(ret!=e_XmountCache_Error_None) return ret; #define XMOUNTCACHE_OPEN__DESTROY_HANDLE do { \ ret=XmountCache_DestroyHandle(&p_h); \ if(ret!=e_XmountCache_Error_None) { \ LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", \ ret); \ } \ *pp_h=NULL; \ } while(0) // Open cache file gidafs_ret=GidaFsLib_OpenFs(&(p_h->h_cache_file),p_h->p_cache_file); if(gidafs_ret!=eGidaFsError_None) { // TODO: Check for old cache file type and inform user it isn't supported // anymore! LOG_ERROR("Couldn't open xmount cache file '%s': Error code %u!\n", p_h->p_cache_file, gidafs_ret) return e_XmountCache_Error_FailedOpeningCache; } #define XMOUNTCACHE_OPEN__CLOSE_CACHE do { \ gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close xmount cache file '%s': " \ "Error code %u: Ignoring!\n", \ p_h->p_cache_file, \ gidafs_ret); \ } \ } while(0) // Open block cache file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_FILE, &(p_h->h_block_cache), eGidaFsOpenFileFlag_ReadWrite, 0); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to open block cache file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedOpeningCache; } #define XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Open block cache index file gidafs_ret=GidaFsLib_OpenFile(p_h->h_cache_file, XMOUNT_CACHE_BLOCK_INDEX_FILE, &(p_h->h_block_cache_index), eGidaFsOpenFileFlag_ReadWrite, 0); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to open block cache index file '%s': Error code %u!\n", XMOUNT_CACHE_BLOCK_FILE, gidafs_ret); XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; // TODO: Own error code needed here return e_XmountCache_Error_FailedOpeningCache; } #define XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX do { \ gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file, \ &(p_h->h_block_cache_index)); \ if(gidafs_ret!=eGidaFsError_None) { \ LOG_ERROR("Unable to close block cache index file: Error code %u: " \ "Ignoring!\n", \ gidafs_ret); \ } \ } while(0) // Calculate how many cache blocks are needed and how big the cache block // index must be p_h->block_cache_index_len=image_size/XMOUNT_CACHE_BLOCK_SIZE; if((image_size%XMOUNT_CACHE_BLOCK_SIZE)!=0) p_h->block_cache_index_len++; LOG_DEBUG("Cache blocks: %" PRIu64 " entries using %" PRIu64 " bytes\n", p_h->block_cache_index_len, p_h->block_cache_index_len*sizeof(uint8_t)); // Make sure block cache index has correct size gidafs_ret=GidaFsLib_GetFileSize(p_h->h_cache_file, p_h->h_block_cache_index, &blockindex_size); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to get block cache index file size: Error code %u!\n", gidafs_ret) XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_FailedGettingIndexSize; } if(blockindex_size%sizeof(uint64_t)!=0 || (blockindex_size/sizeof(uint64_t))!=p_h->block_cache_index_len) { // TODO: Be more helpfull in error message LOG_ERROR("Block cache index size is incorrect for given input image!\n") XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_InvalidIndexSize; } // Prepare in-memory buffer for block cache index p_h->p_block_cache_index= (uint64_t*)calloc(1,p_h->block_cache_index_len*sizeof(uint64_t)); if(p_h->p_block_cache_index==NULL) { XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_Alloc; } // Read block cache index into memory gidafs_ret=GidaFsLib_ReadFile(p_h->h_cache_file, p_h->h_block_cache_index, 0, blockindex_size, p_h->p_block_cache_index, &read); if(gidafs_ret!=eGidaFsError_None || read!=blockindex_size) { LOG_ERROR("Unable to read block cache index: Error code %u!\n", gidafs_ret); XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX; XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE; XMOUNTCACHE_OPEN__CLOSE_CACHE; XMOUNTCACHE_OPEN__DESTROY_HANDLE; return e_XmountCache_Error_FailedReadingIndex; } #undef XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE_INDEX #undef XMOUNTCACHE_OPEN__CLOSE_BLOCK_CACHE #undef XMOUNTCACHE_OPEN__CLOSE_CACHE #undef XMOUNTCACHE_OPEN__DESTROY_HANDLE *pp_h=p_h; return e_XmountCache_Error_None; } /* * XmountCache_Close */ te_XmountCache_Error XmountCache_Close(pts_XmountCacheHandle *pp_h) { pts_XmountCacheHandle p_h=NULL; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error final_ret=e_XmountCache_Error_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(pp_h==NULL) return e_XmountCache_Error_InvalidHandlePointer; if(*pp_h==NULL) return e_XmountCache_Error_InvalidHandle; p_h=*pp_h; // Close block cache index gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file,&(p_h->h_block_cache_index)); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to close block cache index file: Error code %u: " "Ignoring!\n", gidafs_ret); if(final_ret==e_XmountCache_Error_None) { final_ret=e_XmountCache_Error_FailedClosingIndex; } } // Close block cache gidafs_ret=GidaFsLib_CloseFile(p_h->h_cache_file,&(p_h->h_block_cache)); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to close block cache file: Error code %u: " "Ignoring!\n", gidafs_ret); if(final_ret==e_XmountCache_Error_None) { final_ret=e_XmountCache_Error_FailedClosingBlockCache; } } // Close cache file gidafs_ret=GidaFsLib_CloseFs(&(p_h->h_cache_file)); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to close xmount cache file '%s': Error code %u: " "Ignoring!\n", p_h->p_cache_file, gidafs_ret); if(final_ret==e_XmountCache_Error_None) { final_ret=e_XmountCache_Error_FailedClosingCache; } } // Destroy handle ret=XmountCache_DestroyHandle(&p_h); if(ret!=e_XmountCache_Error_None) { LOG_ERROR("Unable to destroy cache handle: Error code %u: Ignoring!\n", ret); if(final_ret==e_XmountCache_Error_None) { final_ret=ret; } } *pp_h=NULL; return final_ret; } /* * XmountCache_BlockCacheRead */ te_XmountCache_Error XmountCache_BlockCacheRead(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block, uint64_t block_offset, uint64_t count) { uint64_t read=0; teGidaFsError gidafs_ret=eGidaFsError_None; // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(p_buf==NULL) return e_XmountCache_Error_InvalidBuffer; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; if(block_offset>XMOUNT_CACHE_BLOCK_SIZE || block_offset+count>XMOUNT_CACHE_BLOCK_SIZE) { return e_XmountCache_Error_ReadBeyondBlockBounds; } if(p_h->p_block_cache_index[block]==XMOUNT_CACHE_INVALID_INDEX) { return e_XmountCache_Error_UncachedBlock; } // Read requested data from block cache file gidafs_ret=GidaFsLib_ReadFile(p_h->h_cache_file, p_h->h_block_cache, p_h->p_block_cache_index[block]+block_offset, count, p_buf, &read); if(gidafs_ret!=eGidaFsError_None || read!=count) { LOG_ERROR("Unable to read cached data from block %" PRIu64 ": Error code %u!\n", block, gidafs_ret); return e_XmountCache_Error_FailedReadingBlockCache; } return e_XmountCache_Error_None; } /* * XmountCache_BlockCacheWrite */ te_XmountCache_Error XmountCache_BlockCacheWrite(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block, uint64_t block_offset, uint64_t count) { uint64_t written=0; teGidaFsError gidafs_ret=eGidaFsError_None; // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(p_buf==NULL) return e_XmountCache_Error_InvalidBuffer; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; if(block_offset>XMOUNT_CACHE_BLOCK_SIZE || block_offset+count>XMOUNT_CACHE_BLOCK_SIZE) { return e_XmountCache_Error_ReadBeyondBlockBounds; } if(p_h->p_block_cache_index[block]==XMOUNT_CACHE_INVALID_INDEX) { return e_XmountCache_Error_UncachedBlock; } gidafs_ret=GidaFsLib_WriteFile(p_h->h_cache_file, p_h->h_block_cache, p_h->p_block_cache_index[block]+block_offset, count, p_buf, &written); if(gidafs_ret!=eGidaFsError_None || written!=count) { LOG_ERROR("Unable to write data to cached block %" PRIu64 ": Error code %u!\n", block, gidafs_ret); return e_XmountCache_Error_FailedWritingBlockCache; } return e_XmountCache_Error_None; } /* * XmountCache_BlockCacheAppend */ te_XmountCache_Error XmountCache_BlockCacheAppend(pts_XmountCacheHandle p_h, char *p_buf, uint64_t block) { uint64_t written=0; teGidaFsError gidafs_ret=eGidaFsError_None; te_XmountCache_Error ret=e_XmountCache_Error_None; // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(p_buf==NULL) return e_XmountCache_Error_InvalidBuffer; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; // Get current block cache size gidafs_ret=GidaFsLib_GetFileSize(p_h->h_cache_file, p_h->h_block_cache, &(p_h->p_block_cache_index[block])); if(gidafs_ret!=eGidaFsError_None) { LOG_ERROR("Unable to get current block cache size: Error code %u!\n", gidafs_ret); return e_XmountCache_Error_FailedGettingIndexSize; } // Append new block gidafs_ret=GidaFsLib_WriteFile(p_h->h_cache_file, p_h->h_block_cache, p_h->p_block_cache_index[block], XMOUNT_CACHE_BLOCK_SIZE, p_buf, &written); if(gidafs_ret!=eGidaFsError_None || written!=XMOUNT_CACHE_BLOCK_SIZE) { LOG_ERROR("Unable to write data to cached block %" PRIu64 ": Error code %u!\n", block, gidafs_ret); return e_XmountCache_Error_FailedWritingBlockCache; } // Update on-disk block cache index ret=XmountCache_UpdateIndex(p_h,block); if(ret!=e_XmountCache_Error_None) { LOG_ERROR("Unable to update block cache index %" PRIu64 ": Error code %u!\n", block, ret); return ret; } return e_XmountCache_Error_None; } /* * XmountCache_IsBlockCached */ te_XmountCache_Error XmountCache_IsBlockCached(pts_XmountCacheHandle p_h, uint64_t block) { // Params check if(p_h==NULL) return e_XmountCache_Error_InvalidHandle; if(block>=p_h->block_cache_index_len) return e_XmountCache_Error_InvalidIndex; // Check if given block has been cached previously if(p_h->p_block_cache_index[block]==XMOUNT_CACHE_INVALID_INDEX) { // Block is not in cache return e_XmountCache_Error_UncachedBlock; } return e_XmountCache_Error_None; } /******************************************************************************* * Private functions implementations ******************************************************************************/ /* * XmountCache_CreateHandle */ te_XmountCache_Error XmountCache_CreateHandle(pts_XmountCacheHandle *pp_h, const char *p_file) { pts_XmountCacheHandle p_h=NULL; // Alloc memory for handle p_h=(pts_XmountCacheHandle)calloc(1,sizeof(ts_XmountCacheHandle)); if(p_h==NULL) { *pp_h=NULL; return e_XmountCache_Error_Alloc; } // Init values. The p_cache_file alloc and memcpy works corrently as strlen() // counts the amount of bytes, not chars. No UTF8-issue here. p_h->p_cache_file=(char*)calloc(1,strlen(p_file)+1); if(p_h->p_cache_file==NULL) { free(p_h); *pp_h=NULL; return e_XmountCache_Error_Alloc; } memcpy(p_h->p_cache_file,p_file,strlen(p_file)); p_h->h_cache_file=NULL; p_h->h_block_cache=NULL; p_h->h_block_cache_index=NULL; p_h->p_block_cache_index=NULL; // Return new handle *pp_h=p_h; return e_XmountCache_Error_None; } /* * XmountCache_DestroyHandle */ te_XmountCache_Error XmountCache_DestroyHandle(pts_XmountCacheHandle *pp_h) { pts_XmountCacheHandle p_h=*pp_h; // Free handle if(p_h->p_cache_file!=NULL) free(p_h->p_cache_file); if(p_h->p_block_cache_index!=NULL) free(p_h->p_block_cache_index); free(p_h); // Return destroyed handle *pp_h=NULL; return e_XmountCache_Error_None; } /* * XmountCache_FileExists */ te_XmountCache_Error XmountCache_FileExists(const char *p_file) { struct stat statbuf; if(lstat(p_file,&statbuf)==0) return e_XmountCache_Error_None; else return e_XmountCache_Error_InexistingFile; } /* * XmountCache_UpdateIndex */ te_XmountCache_Error XmountCache_UpdateIndex(pts_XmountCacheHandle p_h, uint64_t entry) { uint64_t update_size=0; uint64_t written=0; uint64_t *p_buf; teGidaFsError gidafs_ret=eGidaFsError_None; if(entry!=XMOUNT_CACHE_INVALID_INDEX) { // Update specific index entry in cache file p_buf=p_h->p_block_cache_index+entry; update_size=sizeof(uint64_t); } else { // Dump whole block cache index to cache file p_buf=p_h->p_block_cache_index; update_size=p_h->block_cache_index_len*sizeof(uint64_t); } // Update cache file gidafs_ret=GidaFsLib_WriteFile(p_h->h_cache_file, p_h->h_block_cache_index, 0, update_size, p_buf, &written); if(gidafs_ret!=eGidaFsError_None || written!=update_size) { LOG_ERROR("Unable to update block cache index: Error code %u!\n", gidafs_ret) return e_XmountCache_Error_FailedUpdatingIndex; } return e_XmountCache_Error_None; } diff --git a/src/xmount_input.c b/src/xmount_input.c index 66fa81f..44d722d 100644 --- a/src/xmount_input.c +++ b/src/xmount_input.c @@ -1,95 +1,170 @@ /******************************************************************************* * xmount Copyright (c) 2008-2016 by Gillen Daniel * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include "xmount_input.h" -#include "xmount.h" +//#include "xmount.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__); \ } +/******************************************************************************* + * Private types / structures / enums + ******************************************************************************/ + +//! 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_XmountInputHandle { + //! 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; + + // TODO: Move + //! 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_XmountInputHandle; + +/******************************************************************************* + * Private functions declarations + ******************************************************************************/ + + +/******************************************************************************* + * Public functions implementations + ******************************************************************************/ + + +/******************************************************************************* + * Private functions implementations + ******************************************************************************/ + //! 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 index 1d23d43..4a38470 100644 --- a/src/xmount_input.h +++ b/src/xmount_input.h @@ -1,76 +1,212 @@ /******************************************************************************* * xmount Copyright (c) 2008-2016 by Gillen Daniel * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef XMOUNT_INPUT_H #define XMOUNT_INPUT_H #include "../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*); + + + + +/******************************************************************************* + * Public definitions / macros + ******************************************************************************/ + + +/******************************************************************************* + * Public types / structures / enums + ******************************************************************************/ +typedef struct s_XmountInputHandle *pts_XmountInputHandle; + +typedef enum e_XmountInput_Error { + //! No error + e_XmountInput_Error_None=0, + //! Error to allocate memory + e_XmountInput_Error_Alloc, + //! Invalid input handle + e_XmountInput_Error_InvalidHandle, + //! Invalid pointer to an input handle + e_XmountInput_Error_InvalidHandlePointer, + +/* + //! A given string is invalid + e_XmountCache_Error_InvalidString, + //! A given file path / name is invalid + e_XmountCache_Error_InvalidFile, + //! A given file does not exist + e_XmountCache_Error_InexistingFile, + //! A given file exists + e_XmountCache_Error_ExistingFile, + //! Unable to create needed xmount structures inside cache file + e_XmountCache_Error_FailedCacheInit, + //! Unable to open xmount cache file + e_XmountCache_Error_FailedOpeningCache, + //! Failed to get block cache index size + e_XmountCache_Error_FailedGettingIndexSize, + //! Invalid block cache index size + e_XmountCache_Error_InvalidIndexSize, + //! Unable to read block cache index + e_XmountCache_Error_FailedReadingIndex, + //! Failed closing cache block index + e_XmountCache_Error_FailedClosingIndex, + //! Failed closing cache block index + e_XmountCache_Error_FailedClosingBlockCache, + //! Failed closing cache block index + e_XmountCache_Error_FailedClosingCache, + //! Failed to update block cache index + e_XmountCache_Error_FailedUpdatingIndex, + //! Invalid block cache index specified + e_XmountCache_Error_InvalidIndex, + //! Block has not yet been cached + e_XmountCache_Error_UncachedBlock, + //! Invalid buffer specified + e_XmountCache_Error_InvalidBuffer, + //! Request would read beyond a single cache block + e_XmountCache_Error_ReadBeyondBlockBounds, + //! Failed reading cached data + e_XmountCache_Error_FailedReadingBlockCache, + //! Failed writing cached data + e_XmountCache_Error_FailedWritingBlockCache, +*/ +} te_XmountInput_Error; + +/******************************************************************************* + * Public functions declarations + ******************************************************************************/ +/*! + * \brief Create new input handle + * + * Creates a new input handle. + * + * \param pp_h Pointer to input handle + * \return e_XmountInput_Error_None on success + */ +te_XmountInput_Error XmountInput_CreateHandle(pts_XmountInputHandle *pp_h); + +/*! + * \brief Destroy input handle + * + * Invalidates the given handle and frees all used resources. + * + * \param pp_h Pointer to input handle + * \return e_XmountInput_Error_None on success + */ +te_XmountInput_Error XmountInput_DestroyHandle(pts_XmountInputHandle *pp_h); + +/*! + * \brief XXX + * + * XXX + * + * \param p_h Input handle + */ +te_XmountInput_Error XmountInput_LoadLib(pts_XmountInputHandle p_h); + +/*! + * \brief Add an input image + * + * Adds the given input image to the list of available input images. + * + * \param p_h Input handle + * \param p_format Input image format string as given by the user + * \param files_count Amount of files specified by the user + * \param pp_files Array containing all specified files + * \return e_XmountInput_Error_None on success + */ +te_XmountInput_Error XmountInput_AddImage(pts_XmountInputHandle p_h, + const char *p_format, + uint64_t files_count, + const char **pp_files); + +te_XmountInput_Error XmountInput_SetInputOffset(pts_XmountInputHandle p_h, + uint64_t offset); + +te_XmountInput_Error XmountInput_SetInputSizeLimit(pts_XmountInputHandle p_h, + uint64_t size_limit); + +te_XmountInput_Error XmountInput_GetSize(pts_XmountInputHandle p_h, + uint64_t image_nr, + uint64_t *p_size); + +te_XmountInput_Error XmountInput_ReadData(pts_XmountInputHandle p_h, + uint64_t image_nr, + char *p_buf, + uint64_t offset, + uint64_t count); + +te_XmountInput_Error XmountInput_WriteData(pts_XmountInputHandle p_h, + uint64_t image_nr, + const char *p_buf, + uint64_t offset, + uint64_t count); + #endif // XMOUNT_INPUT_H