Page MenuHomePhabricator

No OneTemporary

Size
45 KB
Referenced Files
None
Subscribers
None
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 <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);
/*!
* \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;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
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 <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"
+//#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 <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*);
+
+
+
+
+/*******************************************************************************
+ * 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

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 10:56 AM (2 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1176415
Default Alt Text
(45 KB)

Event Timeline