Page MenuHomePhabricator

No OneTemporary

Size
127 KB
Referenced Files
None
Subscribers
None
diff --git a/trunk/libxmount_input/CMakeLists.txt b/trunk/libxmount_input/CMakeLists.txt
index 43df12f..80cd466 100644
--- a/trunk/libxmount_input/CMakeLists.txt
+++ b/trunk/libxmount_input/CMakeLists.txt
@@ -1,28 +1,28 @@
add_subdirectory(libxmount_input_dd)
if(NOT STATIC_EWF)
find_package(LibEWF)
if(LIBEWF_FOUND)
add_subdirectory(libxmount_input_ewf)
endif(LIBEWF_FOUND)
else(NOT STATIC_EWF)
message(STATUS "Not checking for LibEWF (STATIC_EWF = 1)")
add_subdirectory(libxmount_input_ewf)
endif(NOT STATIC_EWF)
if(NOT STATIC_AFF)
find_package(LibAFF)
if(LIBAFF_FOUND)
add_subdirectory(libxmount_input_aff)
endif(LIBAFF_FOUND)
else(NOT STATIC_AFF)
message(STATUS "Not checking for LibAFF (STATIC_AFF = 1)")
add_subdirectory(libxmount_input_aff)
endif(NOT STATIC_AFF)
find_package(LibZ)
if(LIBZ_FOUND)
add_subdirectory(libxmount_input_aewf)
-# add_subdirectory(libxmount_input_aaff)
+ add_subdirectory(libxmount_input_aaff)
endif(LIBZ_FOUND)
diff --git a/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c
index 813e4ff..c35b76f 100644
--- a/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c
+++ b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c
@@ -1,738 +1,1050 @@
/*******************************************************************************
* xmount Copyright (c) 2008,2009, 2010, 2011, 2012 *
* by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* This module has been written by Guy Voncken. It contains the functions for *
* accessing simple AFF images created by Guymager. *
* *
* xmount is a small tool to "fuse mount" various image formats as dd or vdi *
* files 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/>. *
*******************************************************************************/
+// Please don't touch source code formatting!
+
+#ifdef LINTING
+// #define _LARGEFILE_SOURCE
+// #define _FILE_OFFSET_BITS 64
+ #define AAFF_STANDALONE
+#endif
+
+#ifdef AAFF_STANDALONE
+ #define LOG_STDOUT TRUE
+#endif
#include <netinet/in.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <limits.h>
#include <zlib.h>
+#include <time.h>
+#include <errno.h>
+
#include "../libxmount_input.h"
-//#define AAFF_DEBUG
#include "libxmount_input_aaff.h"
-/*******************************************************************************
- * Forward declarations
- ******************************************************************************/
-int AaffCreateHandle(void **pp_handle);
-int AaffDestroyHandle(void **pp_handle);
-int AaffOpen(void **pp_handle,
- const char **pp_filename_arr,
- uint64_t filename_arr_len);
-int AaffSize(void *p_handle,
- uint64_t *p_size);
-int AaffRead(void *p_handle,
- uint64_t seek,
- char *p_buf,
- uint32_t count);
-int AaffClose(void **pp_handle);
-const char* AaffOptionsHelp();
-int AaffOptionsParse(void *p_handle,
- char *p_options,
- char **pp_error);
-int AaffGetInfofileContent(void *p_handle,
- char **pp_info_buf);
-void AaffFreeBuffer(void *p_buf);
-
-/*******************************************************************************
- * LibXmount_Input API implementation
- ******************************************************************************/
-/*
- * LibXmount_Input_GetApiVersion
- */
-uint8_t LibXmount_Input_GetApiVersion() {
- return LIBXMOUNT_INPUT_API_VERSION;
-}
+static int AaffClose (void *pHandle);
+static const char* AaffGetErrorMessage (int ErrNum);
-/*
- * LibXmount_Input_GetSupportedFormats
- */
-const char* LibXmount_Input_GetSupportedFormats() {
- return "aaff\0\0";
-}
+#define AAFF_OPTION_MAXPAGEARRMEM "aaffmaxmem"
+#define AAFF_OPTION_LOG "aafflog"
-/*
- * LibXmount_Input_GetFunctions
- */
-void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions) {
- p_functions->CreateHandle=&AaffCreateHandle;
- p_functions->DestroyHandle=&AaffDestroyHandle;
- p_functions->Open=&AaffOpen;
- p_functions->Close=&AaffClose;
- p_functions->Size=&AaffSize;
- p_functions->Read=&AaffRead;
- p_functions->OptionsHelp=&AaffOptionsHelp;
- p_functions->OptionsParse=&AaffOptionsParse;
- p_functions->GetInfofileContent=&AaffGetInfofileContent;
- p_functions->FreeBuffer=&AaffFreeBuffer;
-}
+// ----------------------------
+// Logging and error handling
+// ----------------------------
-/*******************************************************************************
- * Private
- ******************************************************************************/
-
-// ---------------------------
-// Internal static functions
-// ---------------------------
+#define LOG_HEADER_LEN 80
-static int AaffCreateHandle0 (t_pAaff *ppAaff)
+int LogvEntry (const char *pLogFileName, uint8_t LogStdout, const char *pFileName, const char *pFunctionName, int LineNr, const char *pFormat, va_list pArguments)
{
- t_pAaff pAaff;
+ time_t NowT;
+ struct tm *pNowTM;
+ FILE *pFile;
+ int wr;
+ char *pFullLogFileName = NULL;
+ const char *pBase;
+ char LogLineHeader[1024];
+ pid_t OwnPID;
+
+ if (!LogStdout && (pLogFileName==NULL))
+ return AAFF_OK;
- pAaff = (t_pAaff) malloc (sizeof(t_Aaff));
- if (pAaff == NULL)
- return AAFF_MEMALLOC_FAILED;
+ time (&NowT);
+ pNowTM = localtime (&NowT);
+ OwnPID = getpid(); // pthread_self()
+ wr = (int) strftime (&LogLineHeader[0] , sizeof(LogLineHeader) , "%a %d.%b.%Y %H:%M:%S ", pNowTM); //lint !e713
+ wr += snprintf (&LogLineHeader[wr], sizeof(LogLineHeader)-wr, "%5d ", OwnPID); //lint !e737
- memset (pAaff, 0, sizeof(t_Aaff));
- *ppAaff = pAaff;
+ if (pFileName && pFunctionName)
+ {
+ pBase = strrchr(pFileName, '/');
+ if (pBase)
+ pFileName = pBase+1;
+ wr += snprintf (&LogLineHeader[wr], sizeof(LogLineHeader)-wr, "%s %s %d ", pFileName, pFunctionName, LineNr); //lint !e737
+ }
+// while (wr < LOG_HEADER_LEN)
+// LogLineHeader[wr++] = ' ';
+
+ if (pLogFileName)
+ {
+ wr = asprintf (&pFullLogFileName, "%s_%d", pLogFileName, OwnPID);
+ if ((wr <= 0) || (pFullLogFileName == NULL))
+ {
+ if (LogStdout)
+ printf ("\nLog file error: Can't build filename");
+ return AAFF_MEMALLOC_FAILED;
+ }
+ else
+ {
+ pFile = fopen64 (pFullLogFileName, "a");
+ if (pFile == NULL)
+ {
+ if (LogStdout)
+ printf ("\nLog file error: Can't be opened");
+ return AAFF_CANNOT_OPEN_LOGFILE;
+ }
+ else
+ {
+ fprintf (pFile, "%-*s", LOG_HEADER_LEN, &LogLineHeader[0]);
+ vfprintf (pFile, pFormat, pArguments);
+ fprintf (pFile, "\n");
+ fclose (pFile);
+ }
+ free (pFullLogFileName);
+ }
+ }
+ if (LogStdout)
+ {
+ printf ("%s", &LogLineHeader[0]);
+ vprintf (pFormat, pArguments);
+ printf ("\n");
+ }
return AAFF_OK;
}
-static int AaffDestroyHandle0 (t_pAaff *ppAaff)
+int LogEntry (const char *pLogFileName, uint8_t LogStdout, const char *pFileName, const char *pFunctionName, int LineNr, const char *pFormat, ...)
{
- t_pAaff pAaff = *ppAaff;
+ va_list VaList;
+ int rc;
- if (pAaff->pFilename) free (pAaff->pFilename);
- if (pAaff->pPageSeekArr) free (pAaff->pPageSeekArr);
- if (pAaff->pLibVersion) free (pAaff->pLibVersion);
- if (pAaff->pFileType) free (pAaff->pFileType);
- if (pAaff->pNameBuff) free (pAaff->pNameBuff);
- if (pAaff->pDataBuff) free (pAaff->pDataBuff);
- if (pAaff->pPageBuff) free (pAaff->pPageBuff);
- if (pAaff->pInfoBuffConst) free (pAaff->pInfoBuffConst);
- if (pAaff->pInfoBuff) free (pAaff->pInfoBuff);
+ if (!LogStdout && (pLogFileName==NULL))
+ return AAFF_OK;
- memset (pAaff, 0, sizeof(t_Aaff));
- free (pAaff);
- *ppAaff = NULL;
+ va_start (VaList, pFormat); //lint !e530 Symbol 'VaList' not initialized
+ rc = LogvEntry (pLogFileName, LogStdout, pFileName, pFunctionName, LineNr, pFormat, VaList);
+ va_end(VaList);
+ return rc;
+}
- return AAFF_OK;
+// CHK requires existance of pAaff handle
+
+#ifdef AAFF_STANDALONE
+ #define LOG_ERRORS_ON_STDOUT TRUE
+#else
+ #define LOG_ERRORS_ON_STDOUT pAaff->LogStdout
+#endif
+
+#define CHK(ChkVal) \
+{ \
+ int ChkValRc; \
+ if ((ChkValRc=(ChkVal)) != AAFF_OK) \
+ { \
+ const char *pErr = AaffGetErrorMessage (ChkValRc); \
+ LogEntry (pAaff->pLogFilename, LOG_ERRORS_ON_STDOUT, __FILE__, __FUNCTION__, __LINE__, "Error %d (%s) occured", ChkValRc, pErr); \
+ return ChkValRc; \
+ } \
+}
+
+#define LOG(...) \
+ LogEntry (pAaff->pLogFilename, pAaff->LogStdout, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__);
+
+
+// AaffCheckError is called before exiting AaffRead. It should not
+// be called elsewehere or else the statistics would become wrong.
+static void AaffCheckError (t_pAaff pAaff, int Ret, int *pErrno)
+{
+ *pErrno = 0;
+ if (Ret != AAFF_OK)
+ {
+ if ((Ret >= AAFF_ERROR_ENOMEM_START) && (Ret <= AAFF_ERROR_ENOMEM_END)) *pErrno = ENOMEM;
+ else if ((Ret >= AAFF_ERROR_EINVAL_START) && (Ret <= AAFF_ERROR_EINVAL_END)) *pErrno = EINVAL;
+ else *pErrno = EIO; // all other errors
+ }
}
+// ------------------------------------
+// Internal functions
+// ------------------------------------
+
uint64_t AaffU64 (char *pData)
{
uint64_t Val=0;
int i;
for (i=4; i<8; i++) Val = (Val << 8) | pData[i];
for (i=0; i<4; i++) Val = (Val << 8) | pData[i];
return Val;
}
static int AaffPageNumberFromSegmentName (char *pSegmentName, uint64_t *pPageNumber)
{
char *pSegmentNamePageNumber;
char *pTail;
pSegmentNamePageNumber = &pSegmentName[strlen(AFF_SEGNAME_PAGE)];
*pPageNumber = strtoull (pSegmentNamePageNumber, &pTail, 10);
if (*pTail != '\0')
return AAFF_INVALID_PAGE_NUMBER; // There should be no extra chars after the number
return AAFF_OK;
}
static inline uint64_t AaffGetCurrentSeekPos (t_Aaff *pAaff)
{
return ftello (pAaff->pFile);
}
static inline uint64_t AaffSetCurrentSeekPos (t_Aaff *pAaff, uint64_t Val, int Whence)
{
if (fseeko (pAaff->pFile, Val, Whence) != 0)
return AAFF_CANNOT_SEEK;
return AAFF_OK;
}
static int AaffReadFile (t_Aaff *pAaff, void *pData, uint32_t DataLen)
{
if (fread (pData, DataLen, 1, pAaff->pFile) != 1)
return AAFF_CANNOT_READ_DATA;
return AAFF_OK;
}
static int AaffRealloc (void **ppBuff, uint32_t *pCurrentLen, uint32_t NewLen)
{
if (NewLen > *pCurrentLen)
{
*ppBuff = realloc (*ppBuff, NewLen);
if (*ppBuff == NULL)
return AAFF_MEMALLOC_FAILED;
*pCurrentLen = NewLen;
}
return AAFF_OK;
}
static int AaffReadSegment (t_pAaff pAaff, char **ppName, uint32_t *pArg, char **ppData, uint32_t *pDataLen)
{
t_AffSegmentHeader Header;
t_AffSegmentFooter Footer;
CHK (AaffReadFile (pAaff, &Header, offsetof(t_AffSegmentHeader, Name)))
if (strcmp (&Header.Magic[0], AFF_SEGMENT_HEADER_MAGIC) != 0)
return AAFF_INVALID_HEADER;
Header.NameLen = ntohl (Header.NameLen );
Header.DataLen = ntohl (Header.DataLen );
Header.Argument = ntohl (Header.Argument);
CHK (AaffRealloc ((void**)&pAaff->pNameBuff, &pAaff->NameBuffLen, Header.NameLen+1)) // alloc +1, as is might be a string which can be more
CHK (AaffRealloc ((void**)&pAaff->pDataBuff, &pAaff->DataBuffLen, Header.DataLen+1)) // easily handled by the calling fn when adding a \0
CHK (AaffReadFile (pAaff, pAaff->pNameBuff, Header.NameLen))
if (Header.DataLen)
CHK (AaffReadFile (pAaff, pAaff->pDataBuff, Header.DataLen))
pAaff->pNameBuff[Header.NameLen] = '\0';
pAaff->pDataBuff[Header.DataLen] = '\0';
if (ppName) *ppName = pAaff->pNameBuff;
if (pArg ) *pArg = Header.Argument;
if (ppData) *ppData = pAaff->pDataBuff;
if (pDataLen) *pDataLen = Header.DataLen;
// Read footer and position file pointer to next segemnt at the same time
// ----------------------------------------------------------------------
CHK (AaffReadFile (pAaff, &Footer, sizeof(Footer)))
if (strcmp (&Footer.Magic[0], AFF_SEGMENT_FOOTER_MAGIC) != 0)
return AAFF_INVALID_FOOTER;
return AAFF_OK;
}
static int AaffReadSegmentPage (t_pAaff pAaff, uint64_t SearchPage, uint64_t *pFoundPage, char **ppData, uint32_t *pDataLen)
{
t_AffSegmentHeader Header;
t_AffSegmentFooter Footer;
char SearchPageStr[128];
int rc = AAFF_OK;
*ppData = NULL;
*pDataLen = 0;
sprintf (SearchPageStr, "page%" PRIu64, SearchPage);
CHK (AaffReadFile (pAaff, &Header, offsetof(t_AffSegmentHeader, Name)))
if (strcmp (&Header.Magic[0], AFF_SEGMENT_HEADER_MAGIC) != 0)
return AAFF_INVALID_HEADER;
Header.NameLen = ntohl (Header.NameLen );
Header.DataLen = ntohl (Header.DataLen );
Header.Argument = ntohl (Header.Argument);
CHK (AaffRealloc ((void**)&pAaff->pNameBuff, &pAaff->NameBuffLen, Header.NameLen+1))
CHK (AaffReadFile (pAaff, pAaff->pNameBuff, Header.NameLen))
pAaff->pNameBuff[Header.NameLen] = '\0';
if (strncmp (pAaff->pNameBuff, AFF_SEGNAME_PAGE, strlen(AFF_SEGNAME_PAGE)) != 0)
return AAFF_WRONG_SEGMENT;
CHK (AaffPageNumberFromSegmentName (pAaff->pNameBuff, pFoundPage))
if (*pFoundPage == SearchPage)
{
unsigned int Len;
uLongf ZLen;
int zrc;
switch (Header.Argument)
{
case AFF_PAGEFLAGS_UNCOMPRESSED:
- DEBUG_PRINTF ("\nuncompressed");
CHK (AaffReadFile (pAaff, pAaff->pPageBuff, Header.DataLen))
pAaff->PageBuffDataLen = Header.DataLen;
break;
case AFF_PAGEFLAGS_COMPRESSED_ZERO:
- DEBUG_PRINTF ("\nzero");
CHK (AaffReadFile (pAaff, &Len, sizeof(Len)))
Len = ntohl (Len);
memset (pAaff->pPageBuff, 0, Len);
pAaff->PageBuffDataLen = Len;
break;
case AFF_PAGEFLAGS_COMPRESSED_ZLIB:
- DEBUG_PRINTF ("\ncompressed");
CHK (AaffRealloc ((void**)&pAaff->pDataBuff, &pAaff->DataBuffLen, Header.DataLen));
CHK (AaffReadFile (pAaff, pAaff->pDataBuff, Header.DataLen)) // read into pDataBuff
ZLen = pAaff->PageSize; // size of pPageBuff
zrc = uncompress ((unsigned char*)(pAaff->pPageBuff), &ZLen, (unsigned char*)(pAaff->pDataBuff), Header.DataLen); // uncompress into pPageBuff
pAaff->PageBuffDataLen = ZLen;
if (zrc != Z_OK)
return AAFF_UNCOMPRESS_FAILED;
break;
default:
return AAFF_INVALID_PAGE_ARGUMENT;
}
*ppData = pAaff->pPageBuff;
*pDataLen = pAaff->PageBuffDataLen;
pAaff->CurrentPage = *pFoundPage;
rc = AAFF_FOUND;
}
else
{
CHK (AaffSetCurrentSeekPos (pAaff, Header.DataLen, SEEK_CUR))
}
// Read footer and position file pointer to next segemnt at the same time
// ----------------------------------------------------------------------
CHK (AaffReadFile (pAaff, &Footer, sizeof(Footer)))
if (strcmp (&Footer.Magic[0], AFF_SEGMENT_FOOTER_MAGIC) != 0)
return AAFF_INVALID_FOOTER;
return rc;
}
static int AaffReadPage (t_pAaff pAaff, uint64_t Page, char **ppBuffer, uint32_t *pLen)
{
if (Page >= pAaff->TotalPages)
return AAFF_READ_BEYOND_LAST_PAGE;
// Check if it's the current page
// ------------------------------
if (Page == pAaff->CurrentPage)
{
*ppBuffer = pAaff->pPageBuff;
*pLen = pAaff->PageBuffDataLen;
return AAFF_OK;
}
- // Set the seek position for startig the search
- // --------------------------------------------
+ // Set the seek position for starting the search
+ // ---------------------------------------------
int MaxHops;
if ((pAaff->CurrentPage != AAFF_CURRENTPAGE_NOTSET) &&
(pAaff->CurrentPage+1 == Page)) // The current seek pos already is the correct one
{
MaxHops = 1;
}
else // Find the closest entry in PageSeekArr
{
int64_t Entry;
Entry = Page / pAaff->Interleave;
while (pAaff->pPageSeekArr[Entry] == 0)
{
Entry--;
if (Entry<0)
return AAFF_SEEKARR_CORRUPT;
}
AaffSetCurrentSeekPos (pAaff, pAaff->pPageSeekArr[Entry], SEEK_SET);
MaxHops = Page - (Entry * pAaff->Interleave) +1;
}
// Run through segment list until page is found
// --------------------------------------------
uint64_t Seek;
- uint64_t FoundPage;
+ uint64_t FoundPage=0;
int rc;
- DEBUG_PRINTF ("\nSearching for page %" PRIu64 ", MaxHops=%d -- ", Page, MaxHops);
+ LOG ("Searching for page %" PRIu64 ", MaxHops=%d", Page, MaxHops);
while (MaxHops--)
{
Seek = AaffGetCurrentSeekPos (pAaff);
- rc = AaffReadSegmentPage (pAaff, Page, &FoundPage, ppBuffer, pLen);
- DEBUG_PRINTF (" %" PRIu64 " (%d)", FoundPage, rc);
+ rc = AaffReadSegmentPage (pAaff, Page, &FoundPage, ppBuffer, pLen);
+ if (rc != AAFF_FOUND)
+ CHK (rc)
+ LOG (" %" PRIu64 " (%d)", FoundPage, rc);
if ((FoundPage % pAaff->Interleave) == 0)
pAaff->pPageSeekArr[FoundPage/pAaff->Interleave] = Seek;
if (rc == AAFF_FOUND)
break;
}
- DEBUG_PRINTF ("\n");
- if (MaxHops<0)
+ if (MaxHops < 0)
return AAFF_PAGE_NOT_FOUND;
return AAFF_OK;
}
// ---------------
// API functions
// ---------------
-/*
- * AaffCreateHandle
- */
-int AaffCreateHandle(void **pp_handle) {
- *pp_handle=NULL;
- CHK(AaffCreateHandle0((t_pAaff*)pp_handle))
- return AAFF_OK;
+static int AaffCreateHandle (void **ppHandle, const char *pFormat, uint8_t Debug)
+{
+ t_pAaff pAaff;
+
+ *ppHandle = NULL;
+
+ pAaff = (t_pAaff) malloc (sizeof(t_Aaff));
+ if (pAaff == NULL)
+ return AAFF_MEMALLOC_FAILED;
+
+ memset (pAaff, 0, sizeof(t_Aaff));
+ pAaff->MaxPageArrMem = AAFF_DEFAULT_MAX_PAGE_ARR_MEM;
+ pAaff->LogStdout = Debug;
+
+ *ppHandle = (void*) pAaff;
+
+ return AAFF_OK;
}
-/*
- * AaffDestroyHandle
- */
-int AaffDestroyHandle(void **pp_handle) {
- // TODO: Implement
-/*
- CHK(AaffDestroyHandle0((t_pAaff*)pp_handle))
- *pp_handle=NULL;
-*/
- return AAFF_OK;
+static int AaffDestroyHandle (void **ppHandle)
+{
+ t_pAaff pAaff = (t_pAaff) *ppHandle;
+
+ if (pAaff->pFilename) free (pAaff->pFilename);
+ if (pAaff->pPageSeekArr) free (pAaff->pPageSeekArr);
+ if (pAaff->pLibVersion) free (pAaff->pLibVersion);
+ if (pAaff->pFileType) free (pAaff->pFileType);
+ if (pAaff->pNameBuff) free (pAaff->pNameBuff);
+ if (pAaff->pDataBuff) free (pAaff->pDataBuff);
+ if (pAaff->pPageBuff) free (pAaff->pPageBuff);
+ if (pAaff->pInfoBuffConst) free (pAaff->pInfoBuffConst);
+ if (pAaff->pInfoBuff) free (pAaff->pInfoBuff);
+
+ memset (pAaff, 0, sizeof(t_Aaff));
+ free (pAaff);
+ *ppHandle = NULL;
+
+ return AAFF_OK;
}
-/*
- * AaffOpen
- */
-int AaffOpen(void **pp_handle,
- const char **pp_filename_arr,
- uint64_t filename_arr_len)
+
+int AaffOpen (void *pHandle, const char **ppFilenameArr, uint64_t FilenameArrLen)
{
- t_pAaff pAaff=(t_pAaff)*pp_handle;
- char Signature[strlen(AFF_HEADER)+1];
- uint64_t Seek;
-
- if(filename_arr_len!=1) {
- // Split aff files are not supported
- // TODO: Set correct error
- return 1;
- }
-
- pAaff->pFilename=strdup(pp_filename_arr[0]);
- pAaff->pFile=fopen(pp_filename_arr[0],"r");
- if(pAaff->pFile==NULL) {
- AaffDestroyHandle0(&pAaff);
- return AAFF_FILE_OPEN_FAILED;
- }
-
- // Check signature
- // ---------------
- CHK(AaffReadFile(pAaff,&Signature,sizeof(Signature)))
- if(memcmp(Signature,AFF_HEADER,sizeof(Signature))!=0) {
- (void)AaffClose((void**)&pAaff);
- return AAFF_INVALID_SIGNATURE;
- }
-
- // Read header segments
- // --------------------
- char *pName;
- uint32_t Arg;
- char *pData;
- uint32_t DataLen;
- const int MAX_HEADER_SEGMENTS = 100;
- int Seg;
- unsigned int i;
- int wr;
- int Pos = 0;
- const unsigned HexStrLen = 32;
- char HexStr[HexStrLen+1];
-
- #define REM (AaffInfoBuffLen-Pos)
-
- pAaff->pInfoBuffConst = malloc (AaffInfoBuffLen);
- pAaff->pInfoBuff = malloc (AaffInfoBuffLen*2);
- // Search for known segments at the image start
- for (Seg=0; Seg<MAX_HEADER_SEGMENTS; Seg++) {
- Seek = AaffGetCurrentSeekPos (pAaff);
- CHK (AaffReadSegment (pAaff, &pName, &Arg, &pData, &DataLen))
-
- if(strcmp(pName,AFF_SEGNAME_PAGESIZE)==0) {
- pAaff->PageSize=Arg;
- } else if(strcmp(pName,AFF_SEGNAME_SECTORSIZE)==0) {
- pAaff->SectorSize=Arg;
- } else if(strcmp(pName,AFF_SEGNAME_SECTORS)==0) {
- pAaff->Sectors=AaffU64(pData);
- } else if(strcmp(pName,AFF_SEGNAME_IMAGESIZE)==0) {
- pAaff->ImageSize=AaffU64(pData);
- } else if(strcmp(pName,AFF_SEGNAME_AFFLIB_VERSION)==0) {
- pAaff->pLibVersion=strdup((char*)pData);
- } else if(strcmp(pName,AFF_SEGNAME_FILETYPE)==0) {
- pAaff->pFileType=strdup((char*)pData);
- } else if((strcmp(pName,AFF_SEGNAME_GID)==0) ||
- (strcmp(pName, AFF_SEGNAME_BADFLAG)==0))
- {
- wr=0;
- for (i=0; i<GETMIN(DataLen,HexStrLen/2); i++)
- wr += sprintf (&HexStr[wr], "%02X", pData[i]);
- HexStr[i] = '\0';
- Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"%-25s %s", pName, HexStr);
- if (i<DataLen) Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"...");
- Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"\n");
- } else if(strncmp(pName,AFF_SEGNAME_PAGE,strlen(AFF_SEGNAME_PAGE))==0) {
- break;
- } else {
- if ((Arg == 0) && DataLen)
- Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"%-25s %s\n", pName, pData);
- }
- }
- #undef REM
-
- if (Seg >= MAX_HEADER_SEGMENTS) {
- (void) AaffClose ((void**)&pAaff);
- return AAFF_TOO_MANY_HEADER_SEGEMENTS;
- }
-
- if (strstr (pAaff->pLibVersion, "Guymager") == NULL) {
- (void) AaffClose ((void**)&pAaff);
- return AAFF_NOT_CREATED_BY_GUYMAGER;
- }
-
- // Prepare page seek array
- // -----------------------
- uint64_t MaxEntries;
- int ArrBytes;
-
- pAaff->TotalPages = pAaff->ImageSize / pAaff->PageSize;
- if (pAaff->ImageSize % pAaff->PageSize) pAaff->TotalPages++;
-
- // TODO: MaxPageArrMem was a uint64_t parameter of this function
- MaxEntries = AAFF_DEFAULT_PAGE_SEEK_MAX_ENTRIES;
-/*
- if (MaxPageArrMem) {
- // +1 in order not to risk a result of 0
- MaxEntries = (MaxPageArrMem / sizeof (unsigned long long *)) + 1;
- } else MaxEntries = AAFF_DEFAULT_PAGE_SEEK_MAX_ENTRIES;
-*/
-
- MaxEntries = GETMIN (MaxEntries, pAaff->TotalPages);
- pAaff->Interleave = pAaff->TotalPages / MaxEntries;
- if (pAaff->TotalPages % MaxEntries) pAaff->Interleave++;
-
- pAaff->PageSeekArrLen = pAaff->TotalPages / pAaff->Interleave;
- ArrBytes = pAaff->PageSeekArrLen * sizeof(uint64_t *);
- pAaff->pPageSeekArr = (uint64_t*)malloc (ArrBytes);
- memset (pAaff->pPageSeekArr, 0, ArrBytes);
- CHK (AaffPageNumberFromSegmentName (pName, &pAaff->CurrentPage));
- if (pAaff->CurrentPage != 0)
- {
- (void) AaffClose ((void**)&pAaff);
- return AAFF_UNEXPECTED_PAGE_NUMBER;
- }
- pAaff->pPageSeekArr[0] = Seek;
-
- // Alloc Buffers
- // -------------
- pAaff->pPageBuff = malloc (pAaff->PageSize);
- pAaff->CurrentPage = AAFF_CURRENTPAGE_NOTSET;
-
- return AAFF_OK;
+ t_pAaff pAaff = (t_pAaff) pHandle;
+ char Signature[strlen(AFF_HEADER)+1];
+ uint64_t Seek;
+
+ LOG ("Called - Files=%" PRIu64, FilenameArrLen);
+
+ if (FilenameArrLen != 1)
+ CHK (AAFF_SPLIT_IMAGES_NOT_SUPPORTED)
+
+ pAaff->pFilename = strdup (ppFilenameArr[0]);
+ pAaff->pFile = fopen (ppFilenameArr[0],"r");
+ if(pAaff->pFile==NULL)
+ {
+ (void) AaffDestroyHandle ((void**) &pAaff);
+ CHK (AAFF_FILE_OPEN_FAILED)
+ }
+
+ // Check signature
+ // ---------------
+ CHK (AaffReadFile (pAaff, &Signature, sizeof(Signature)))
+ if (memcmp (Signature, AFF_HEADER, sizeof(Signature)) !=0)
+ {
+ (void)AaffClose((void**)&pAaff);
+ CHK (AAFF_INVALID_SIGNATURE)
+ }
+
+ // Read header segments
+ // --------------------
+ char *pName;
+ uint32_t Arg;
+ char *pData;
+ uint32_t DataLen;
+ const int MAX_HEADER_SEGMENTS = 100;
+ int Seg;
+ unsigned int i;
+ int wr;
+ int Pos = 0;
+ const unsigned HexStrLen = 32;
+ char HexStr[HexStrLen+1];
+
+ #define REM (AaffInfoBuffLen-Pos)
+
+ pAaff->pInfoBuffConst = (char *) malloc (AaffInfoBuffLen);
+ pAaff->pInfoBuff = (char *) malloc (AaffInfoBuffLen*2);
+
+ // Search for known segments at the image start
+ for (Seg=0; Seg<MAX_HEADER_SEGMENTS; Seg++)
+ {
+ Seek = AaffGetCurrentSeekPos (pAaff);
+ CHK (AaffReadSegment (pAaff, &pName, &Arg, &pData, &DataLen))
+
+ if (strcmp (pName, AFF_SEGNAME_PAGESIZE) == 0 ) pAaff->PageSize = Arg;
+ else if (strcmp (pName, AFF_SEGNAME_SECTORSIZE) == 0 ) pAaff->SectorSize = Arg;
+ else if (strcmp (pName, AFF_SEGNAME_SECTORS) == 0 ) pAaff->Sectors = AaffU64(pData);
+ else if (strcmp (pName, AFF_SEGNAME_IMAGESIZE) == 0 ) pAaff->ImageSize = AaffU64(pData);
+ else if (strcmp (pName, AFF_SEGNAME_AFFLIB_VERSION) == 0 ) pAaff->pLibVersion = strdup((char*)pData);
+ else if (strcmp (pName, AFF_SEGNAME_FILETYPE) == 0 ) pAaff->pFileType = strdup((char*)pData);
+ else if ((strcmp(pName, AFF_SEGNAME_GID) == 0 ) ||
+ (strcmp(pName, AFF_SEGNAME_BADFLAG) == 0 ))
+ {
+ wr=0;
+ for (i=0; i<GETMIN(DataLen,HexStrLen/2); i++)
+ wr += sprintf (&HexStr[wr], "%02X", pData[i]);
+ HexStr[i] = '\0';
+ Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"%-25s %s", pName, HexStr);
+ if (i<DataLen)
+ Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"...");
+ Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"\n");
+ }
+ else if (strncmp(pName,AFF_SEGNAME_PAGE,strlen(AFF_SEGNAME_PAGE))==0)
+ {
+ break;
+ }
+ else
+ {
+ if ((Arg == 0) && DataLen)
+ Pos += snprintf (&(pAaff->pInfoBuffConst[Pos]), REM,"%-25s %s\n", pName, pData);
+ }
+ }
+ #undef REM
+
+ if (Seg >= MAX_HEADER_SEGMENTS)
+ {
+ (void) AaffClose ((void**)&pAaff);
+ CHK (AAFF_TOO_MANY_HEADER_SEGEMENTS)
+ }
+
+ if (strstr (pAaff->pLibVersion, "Guymager") == NULL)
+ {
+ (void) AaffClose ((void**)&pAaff);
+ CHK (AAFF_NOT_CREATED_BY_GUYMAGER)
+ }
+
+ // Prepare page seek array
+ // -----------------------
+ uint64_t MaxEntries;
+ int ArrBytes;
+
+ pAaff->TotalPages = pAaff->ImageSize / pAaff->PageSize;
+ if (pAaff->ImageSize % pAaff->PageSize)
+ pAaff->TotalPages++;
+
+ MaxEntries = (pAaff->MaxPageArrMem*1024*1024) / (sizeof (unsigned long long *) + 1); // +1 in order not to risk a result of 0
+ MaxEntries = GETMIN (MaxEntries, pAaff->TotalPages);
+
+ pAaff->Interleave = pAaff->TotalPages / MaxEntries;
+ if (pAaff->TotalPages % MaxEntries)
+ pAaff->Interleave++;
+
+ pAaff->PageSeekArrLen = pAaff->TotalPages / pAaff->Interleave;
+ ArrBytes = pAaff->PageSeekArrLen * sizeof(uint64_t *);
+ pAaff->pPageSeekArr = (uint64_t*)malloc (ArrBytes);
+ memset (pAaff->pPageSeekArr, 0, ArrBytes);
+ CHK (AaffPageNumberFromSegmentName (pName, &pAaff->CurrentPage));
+ if (pAaff->CurrentPage != 0)
+ {
+ (void) AaffClose ((void**)&pAaff);
+ CHK (AAFF_UNEXPECTED_PAGE_NUMBER)
+ }
+ pAaff->pPageSeekArr[0] = Seek;
+
+ // Alloc Buffers
+ // -------------
+ pAaff->pPageBuff = (char *) malloc (pAaff->PageSize);
+ pAaff->CurrentPage = AAFF_CURRENTPAGE_NOTSET;
+
+ LOG ("Ret");
+ return AAFF_OK;
+}
+
+static int AaffClose (void *pHandle)
+{
+ t_pAaff pAaff = (t_pAaff) pHandle;
+ int rc = AAFF_OK;
+
+ LOG ("Called");
+
+ if (fclose (pAaff->pFile))
+ rc = AAFF_CANNOT_CLOSE_FILE;
+
+ LOG ("Ret");
+ return rc;
+}
+
+static int AaffSize (void *pHandle, uint64_t *pSize)
+{
+ t_pAaff pAaff = (t_pAaff) pHandle;
+
+ LOG ("Called");
+ *pSize = pAaff->ImageSize;
+
+ LOG ("Ret - Size=%" PRIu64, *pSize);
+ return AAFF_OK;
}
-/*
- * AaffClose
- */
-int AaffClose(void **pp_handle) {
- int rc=AAFF_OK;
+static int AaffRead (void *pHandle, char *pBuf, off_t Seek, size_t Count, size_t *pRead, int *pErrno)
+{
+ t_pAaff pAaff = (t_pAaff) pHandle;
+ char *pPageBuffer;
+ uint64_t Page;
+ uint64_t Seek64;
+ uint64_t Remaining;
+ uint32_t PageLen, Ofs, ToCopy;
+ int Ret = AAFF_OK;
+
+ LOG ("Called - Seek=%'" PRIu64 ",Count=%'" PRIu64, Seek, Count);
+ *pRead = 0;
+ *pErrno = 0;
+
+ if (Seek < 0)
+ {
+ Ret = AAFF_NEGATIVE_SEEK;
+ goto Leave;
+ }
+ Seek64 = Seek;
+
+ if (Seek64 >= pAaff->ImageSize) // If calling function asks
+ goto Leave; // for data beyond end of
+ if ((Seek64+Count) > pAaff->ImageSize) // image simply return what
+ Count = pAaff->ImageSize - Seek64; // is possible.
+
+ Page = Seek64 / pAaff->PageSize;
+ Ofs = Seek64 % pAaff->PageSize;
+ Remaining = Count;
+
+ while (Count)
+ {
+ Ret = AaffReadPage (pAaff, Page, &pPageBuffer, &PageLen);
+ if (Ret)
+ goto Leave;
+ if (PageLen == 0)
+ {
+ Ret = AAFF_PAGE_LENGTH_ZERO;
+ goto Leave;
+ }
+ ToCopy = GETMIN (PageLen-Ofs, Remaining);
+ memcpy (pBuf, pPageBuffer+Ofs, ToCopy);
+ Remaining -= ToCopy;
+ pBuf += ToCopy;
+ *pRead += ToCopy;
+ Ofs=0;
+ Page++;
+ }
+
+Leave:
+ AaffCheckError (pAaff, Ret, pErrno);
+ LOG ("Ret %d - Read=%" PRIu32, Ret, *pRead);
+ return Ret;
+}
- if(fclose((*(t_pAaff*)pp_handle)->pFile)) rc=AAFF_CANNOT_CLOSE_FILE;
- CHK(AaffDestroyHandle0((t_pAaff*)pp_handle))
+static int AaffOptionsHelp (const char **ppHelp)
+{
+ char *pHelp=NULL;
+ int wr;
+
+ wr = asprintf (&pHelp, " %-12s : Maximum amount of RAM cache, in MiB, for image seek offsets. Default: %"PRIu64" MiB\n"
+ " %-12s : Log file name.\n"
+ " Specify full path for %s. The given file name is extended by _<pid>.\n",
+ AAFF_OPTION_MAXPAGEARRMEM, AAFF_DEFAULT_MAX_PAGE_ARR_MEM,
+ AAFF_OPTION_LOG,
+ AAFF_OPTION_LOG);
+ if ((pHelp == NULL) || (wr<=0))
+ return AAFF_MEMALLOC_FAILED;
- return rc;
+ *ppHelp = pHelp;
+ return AAFF_OK;
}
-/*
- * AaffGetInfofileContent
- */
-int AaffGetInfofileContent(void *p_handle, char **pp_info_buf) {
+static int AaffOptionsParse (void *pHandle, uint32_t OptionCount, const pts_LibXmountOptions *ppOptions, const char **ppError)
+{
+ pts_LibXmountOptions pOption;
+ t_pAaff pAaff = (t_pAaff) pHandle;
+ const char *pError = NULL;
+ int rc = AAFF_OK;
+ int Ok;
+
+ LOG ("Called - OptionCount=%" PRIu32, OptionCount);
+ *ppError = NULL;
+
+ #define TEST_OPTION_UINT64(Opt,DestField) \
+ if (strcmp (pOption->p_key, Opt) == 0) \
+ { \
+ pAaff->DestField = StrToUint64 (pOption->p_value, &Ok); \
+ if (!Ok) \
+ { \
+ pError = "Error in option %s: Invalid value"; \
+ break; \
+ } \
+ LOG ("Option %s set to %" PRIu64, Opt, pAaff->DestField) \
+ }
+
+ for (uint32_t i=0; i<OptionCount; i++)
+ {
+ pOption = ppOptions[i];
+ if (strcmp (pOption->p_key, AAFF_OPTION_LOG) == 0)
+ {
+ pAaff->pLogFilename = strdup (pOption->p_value);
+ rc = LOG ("Logging for libxmount_input_aaff started")
+ if (rc != AAFF_OK)
+ {
+ pError = "Write test to log file failed";
+ break;
+ }
+ pOption->valid = TRUE;
+ LOG ("Option %s set to %s", AAFF_OPTION_LOG, pAaff->pLogFilename);
+ }
+ else TEST_OPTION_UINT64 (AAFF_OPTION_MAXPAGEARRMEM, MaxPageArrMem)
+ }
+ #undef TEST_OPTION_UINT64
+
+ if (pError)
+ *ppError = strdup (pError);
+ LOG ("Ret - rc=%d,Error=%s", rc, *ppError);
+ return rc;
+}
+
+static int AaffGetInfofileContent (void *pHandle, const char **ppInfoBuf)
+{
+ t_pAaff pAaff = (t_pAaff) pHandle;
uint64_t i;
uint64_t Entries = 0;
int Pos = 0;
+
+ LOG ("Called");
+
#define REM (AaffInfoBuffLen-Pos)
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "AFF IMAGE INFORMATION");
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\n---------------------");
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nAFF file %s" , ((t_pAaff)p_handle)->pFilename );
-
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nPage size %u" , ((t_pAaff)p_handle)->PageSize );
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nSector size %d" , ((t_pAaff)p_handle)->SectorSize );
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nSectors %" PRIu64, ((t_pAaff)p_handle)->Sectors );
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nImage size %" PRIu64 " (%0.1f GiB)", ((t_pAaff)p_handle)->ImageSize, ((t_pAaff)p_handle)->ImageSize/(1024.0*1024.0*1024.0));
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nTotal pages %" PRIu64, ((t_pAaff)p_handle)->TotalPages );
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\n");
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\n%s", ((t_pAaff)p_handle)->pInfoBuffConst);
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\n");
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nCurrent page ");
- if (((t_pAaff)p_handle)->CurrentPage == AAFF_CURRENTPAGE_NOTSET)
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "not set");
- else Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "%" PRIu64, ((t_pAaff)p_handle)->CurrentPage);
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nSeek array length %" PRIu64, ((t_pAaff)p_handle)->PageSeekArrLen);
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nSeek interleave %" PRIu64, ((t_pAaff)p_handle)->Interleave);
-
- for (i=0; i<((t_pAaff)p_handle)->PageSeekArrLen; i++)
- if (((t_pAaff)p_handle)->pPageSeekArr[i])
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "AFF IMAGE INFORMATION");
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\n---------------------");
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nAFF file %s" , pAaff->pFilename );
+
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nPage size %u" , pAaff->PageSize );
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSector size %d" , pAaff->SectorSize );
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSectors %" PRIu64, pAaff->Sectors);
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nImage size %" PRIu64 " (%0.1f GiB)", pAaff->ImageSize, pAaff->ImageSize/(1024.0*1024.0*1024.0));
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nTotal pages %" PRIu64, pAaff->TotalPages);
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\n");
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\n%s", pAaff->pInfoBuffConst);
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\n");
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nCurrent page ");
+ if (pAaff->CurrentPage == AAFF_CURRENTPAGE_NOTSET)
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "not set");
+ else Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "%" PRIu64, pAaff->CurrentPage);
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSeek array length %" PRIu64, pAaff->PageSeekArrLen);
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSeek interleave %" PRIu64, pAaff->Interleave);
+
+ for (i=0; i<pAaff->PageSeekArrLen; i++)
+ {
+ if (pAaff->pPageSeekArr[i])
Entries++;
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nSeek array entries %" PRIu64, Entries);
- Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\n");
+ }
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSeek array entries %" PRIu64, Entries);
+ Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\n");
#undef REM
- // TODO: Rather then copying, generate info text once here. It won't be used
- // after this anymore.
- *pp_info_buf=(char*)malloc(strlen(((t_pAaff)p_handle)->pInfoBuff)+1);
- if(*pp_info_buf==NULL) {
- return AAFF_MEMALLOC_FAILED;
- }
+ *ppInfoBuf = strdup (pAaff->pInfoBuff);
+ if (*ppInfoBuf == NULL)
+ CHK (AAFF_MEMALLOC_FAILED)
- strcpy(*pp_info_buf,((t_pAaff)p_handle)->pInfoBuff);
- return AAFF_OK;
+ LOG ("Ret - %d bytes of info", strlen(*ppInfoBuf)+1);
+ return AAFF_OK;
}
-/*
- * AaffSize
- */
-int AaffSize(void *p_handle, uint64_t *p_size) {
- *p_size=((t_pAaff)p_handle)->ImageSize;
- return AAFF_OK;
+static const char* AaffGetErrorMessage (int ErrNum)
+{
+ const char *pMsg;
+ #define ADD_ERR(ErrCode) \
+ case ErrCode: pMsg = #ErrCode; \
+ break;
+
+ switch (ErrNum)
+ {
+ ADD_ERR (AAFF_OK)
+ ADD_ERR (AAFF_FOUND)
+ ADD_ERR (AAFF_MEMALLOC_FAILED)
+ ADD_ERR (AAFF_OPTIONS_ERROR)
+ ADD_ERR (AAFF_SPLIT_IMAGES_NOT_SUPPORTED)
+ ADD_ERR (AAFF_INVALID_SIGNATURE)
+ ADD_ERR (AAFF_NOT_CREATED_BY_GUYMAGER)
+ ADD_ERR (AAFF_CANNOT_OPEN_LOGFILE)
+ ADD_ERR (AAFF_FILE_OPEN_FAILED)
+ ADD_ERR (AAFF_CANNOT_READ_DATA)
+ ADD_ERR (AAFF_INVALID_HEADER)
+ ADD_ERR (AAFF_INVALID_FOOTER)
+ ADD_ERR (AAFF_TOO_MANY_HEADER_SEGEMENTS)
+ ADD_ERR (AAFF_INVALID_PAGE_NUMBER)
+ ADD_ERR (AAFF_UNEXPECTED_PAGE_NUMBER)
+ ADD_ERR (AAFF_CANNOT_CLOSE_FILE)
+ ADD_ERR (AAFF_CANNOT_SEEK)
+ ADD_ERR (AAFF_WRONG_SEGMENT)
+ ADD_ERR (AAFF_UNCOMPRESS_FAILED)
+ ADD_ERR (AAFF_INVALID_PAGE_ARGUMENT)
+ ADD_ERR (AAFF_SEEKARR_CORRUPT)
+ ADD_ERR (AAFF_PAGE_NOT_FOUND)
+ ADD_ERR (AAFF_READ_BEYOND_IMAGE_LENGTH)
+ ADD_ERR (AAFF_READ_BEYOND_LAST_PAGE)
+ ADD_ERR (AAFF_PAGE_LENGTH_ZERO)
+ ADD_ERR (AAFF_NEGATIVE_SEEK)
+ default:
+ pMsg = "Unknown error";
+ }
+ #undef ARR_ERR
+ return pMsg;
}
-/*
- * AaffRead
- */
-int AaffRead(void *p_handle,
- uint64_t seek,
- char *p_buf,
- uint32_t count)
+static int AaffFreeBuffer (void *pBuf)
{
- uint64_t page;
- char *p_page_buffer;
- uint32_t page_len, ofs, to_copy;
-
- if((seek+count)>((t_pAaff)p_handle)->ImageSize) {
- return AAFF_READ_BEYOND_IMAGE_LENGTH;
- }
-
- page=seek/((t_pAaff)p_handle)->PageSize;
- ofs=seek%((t_pAaff)p_handle)->PageSize;
-
- while(count) {
- CHK(AaffReadPage((t_pAaff)p_handle,page,&p_page_buffer,&page_len))
- to_copy=GETMIN(page_len-ofs,count);
- memcpy(p_buf,p_page_buffer+ofs,to_copy);
- count-=to_copy;
- p_buf+=to_copy;
- ofs=0;
- page++;
- }
-
- return AAFF_OK;
+ free (pBuf);
+ return AAFF_OK;
}
-/*
- * AaffOptionsHelp
- */
-const char* AaffOptionsHelp() {
- return NULL;
+
+// ------------------------------------
+// LibXmount_Input API implementation
+// ------------------------------------
+
+uint8_t LibXmount_Input_GetApiVersion ()
+{
+ return LIBXMOUNT_INPUT_API_VERSION;
}
-/*
- * AaffOptionsParse
- */
-int AaffOptionsParse(void *p_handle, char *p_options, char **pp_error) {
- return AAFF_OK;
+const char* LibXmount_Input_GetSupportedFormats ()
+{
+ return "aaff\0\0";
}
-/*
- * AaffFreeBuffer
- */
-void AaffFreeBuffer(void *p_buf) {
- free(p_buf);
+void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *pFunctions)
+{
+ pFunctions->CreateHandle = &AaffCreateHandle;
+ pFunctions->DestroyHandle = &AaffDestroyHandle;
+ pFunctions->Open = &AaffOpen;
+ pFunctions->Close = &AaffClose;
+ pFunctions->Size = &AaffSize;
+ pFunctions->Read = &AaffRead;
+ pFunctions->OptionsHelp = &AaffOptionsHelp;
+ pFunctions->OptionsParse = &AaffOptionsParse;
+ pFunctions->GetInfofileContent = &AaffGetInfofileContent;
+ pFunctions->GetErrorMessage = &AaffGetErrorMessage;
+ pFunctions->FreeBuffer = &AaffFreeBuffer;
}
// -----------------------------------------------------
// Small main routine for testing
// It converts an aff file to dd
// -----------------------------------------------------
-#ifdef AAFF_MAIN_FOR_TESTING
+#ifdef AAFF_STANDALONE
+
+#define PRINT_ERROR_AND_EXIT(...) \
+{ \
+ printf (__VA_ARGS__); \
+ exit (1); \
+}
-int main(int argc, char *argv[])
+int ParseOptions (t_pAaff pAaff, char *pOptions)
{
- t_pAaff pAaff;
- char *pInfoBuff;
- uint64_t Remaining;
- uint64_t CurrentPos=0;
- int rc;
- int Percent;
- int PercentOld;
+ pts_LibXmountOptions pOptionArr;
+ pts_LibXmountOptions *ppOptionArr;
+ int OptionCount;
+ char *pSep;
+ char *pEqual;
+ char *pTmp;
+ const char *pError;
+ char *pOpt;
+ int rc;
+
+ if (pOptions == NULL)
+ return AAFF_OK;
+
+ if (*pOptions == '\0')
+ return AAFF_OK;
+
+ if (*pOptions == ',')
+ return AAFF_OPTIONS_ERROR;
+
+ if (pOptions[strlen(pOptions)-1] == ',')
+ return AAFF_OPTIONS_ERROR;
+
+ pOpt = strdup (pOptions);
+
+ // Count number of comma separated options
+ OptionCount = 1;
+ pTmp = pOpt;
+ while ((pTmp = strchr (pTmp, ',')) != NULL)
+ {
+ OptionCount++;
+ pTmp++;
+ }
+
+ // Create and fill option array
+ pOptionArr = (pts_LibXmountOptions) malloc (OptionCount * sizeof(ts_LibXmountOptions));
+ if (pOptionArr == NULL)
+ PRINT_ERROR_AND_EXIT ("Cannot allocate pOptionArr");
+ memset (pOptionArr, 0, OptionCount * sizeof(ts_LibXmountOptions));
+ pTmp = pOpt;
+ for (int i=0; i<OptionCount; i++)
+ {
+ pOptionArr[i].p_key = pTmp;
+ pSep = strchr (pTmp, ',');
+ if (pSep)
+ *pSep ='\0';
+ pEqual = strchr (pTmp, '=');
+ if (pEqual)
+ {
+ *pEqual = '\0';
+ pOptionArr[i].p_value = pEqual+1;
+ }
+ if (pSep != NULL)
+ pTmp = pSep+1;
+ }
+
+ // Create pointer array and call parse function
+ ppOptionArr = (pts_LibXmountOptions *)malloc (OptionCount*sizeof (pts_LibXmountOptions));
+ if (ppOptionArr == NULL)
+ PRINT_ERROR_AND_EXIT ("Cannot allocate ppOptionArr");
+ for (int i=0; i<OptionCount; i++)
+ ppOptionArr[i] = &pOptionArr[i];
+
+ rc = AaffOptionsParse ((void*) pAaff, OptionCount, ppOptionArr, &pError);
+ free (ppOptionArr);
+ free ( pOptionArr);
+ free ( pOpt);
+ if (pError)
+ PRINT_ERROR_AND_EXIT ("Error while setting options: %s", pError);
+ CHK (rc)
+
+ return AAFF_OK;
+}
+
+int main(int argc, const char *argv[])
+{
+ t_pAaff pAaff;
+ const char *pInfoBuff;
+ const char *pHelp;
+ uint64_t Remaining;
+ uint64_t CurrentPos=0;
+ int rc;
+ int Errno;
+ int Percent;
+ int PercentOld;
+ char *pOptions = NULL;
setbuf (stdout, NULL);
setbuf (stderr, NULL);
setlocale (LC_ALL, "");
printf ("AFF to DD converter\n");
if (argc != 3)
{
- printf ("Usage: %s <aff source file> <dd destination file>\n", argv[0]);
+ (void) AaffOptionsHelp (&pHelp);
+ printf ("Usage: %s <EWF segment file 1> <EWF segment file 2> <...> [-comma_separated_options]\n", argv[0]);
+ printf ("Possible options:\n%s\n", pHelp);
+ printf ("The output file will be named dd.\n");
+ CHK (AaffFreeBuffer ((void*) pHelp))
exit (1);
}
-
-// rc = AaffOpen (&pAaff, argv[1], 1024); // weird seek array size for testing
- rc = AaffOpen (&pAaff, argv[1], 1);
- if (rc)
+ if (argv[argc-1][0] == '-')
{
- printf ("Error %d while opening file %s\n", rc, argv[1]);
- exit (2);
+ pOptions = strdup (&(argv[argc-1][1]));
+ argc--;
}
- rc = AaffInfo (pAaff, &pInfoBuff);
+ rc = AaffCreateHandle ((void**) &pAaff, "aaff", LOG_STDOUT);
+ if (rc != AAFF_OK)
+ PRINT_ERROR_AND_EXIT ("Cannot create handle, rc=%d\n", rc)
+ if (pOptions)
+ CHK (ParseOptions(pAaff, pOptions))
+
+ rc = AaffOpen (pAaff, &argv[1], 1);
if (rc)
{
- printf ("Could not retrieve info\n");
+ printf ("Error %d while opening file %s\n", rc, argv[1]);
exit (2);
}
- printf ("%s", pInfoBuff);
+
+ CHK (AaffGetInfofileContent ((void*) pAaff, &pInfoBuff))
+ if (pInfoBuff)
+ printf ("Contents of info buffer:\n%s\n", pInfoBuff);
+ CHK (AaffFreeBuffer ((void*)pInfoBuff))
// Create destination file and fill it with data from aff
// ------------------------------------------------------
FILE *pFile;
pFile = fopen (argv[2], "w");
// const unsigned BuffSize = 13; // weird Buffsize for testing
- const unsigned BuffSize = 65536;
- unsigned char *pBuff;
- unsigned int Bytes;
+ const unsigned BuffSize = 65536;
+ char *pBuff;
+ uint64_t ToRead;
+ uint64_t Read;
+
Remaining = pAaff->ImageSize;
- pBuff = malloc (BuffSize);
+ pBuff = (char *) malloc (BuffSize);
CurrentPos=0;
+ Errno = 0;
PercentOld = -1;
+
while (Remaining)
{
- Bytes = GETMIN (Remaining, BuffSize);
- rc = AaffRead (pAaff, CurrentPos, pBuff, Bytes);
- if (rc != AAFF_OK)
- {
- printf ("Could not read data from aff file, error %d\n", rc);
- exit (2);
- }
- if (fwrite (pBuff, Bytes, 1, pFile) != 1)
+ ToRead = GETMIN (Remaining, BuffSize);
+ rc = AaffRead ((void*) pAaff, pBuff, CurrentPos, ToRead, &Read, &Errno);
+ if ((rc != AAFF_OK) || (Errno != 0))
+ PRINT_ERROR_AND_EXIT("Error %d while calling AewfRead (Errno %d)\n", rc, Errno);
+ if (Read != ToRead)
+ PRINT_ERROR_AND_EXIT("Only %" PRIu64 " out of %" PRIu64 " bytes read\n", Read, ToRead);
+
+ if (fwrite (pBuff, Read, 1, pFile) != 1)
{
printf ("Could not write to destinationfile\n");
exit (2);
}
- CurrentPos += Bytes;
- Remaining -= Bytes;
+ CurrentPos += Read;
+ Remaining -= Read;
Percent = (100*CurrentPos) / pAaff->ImageSize;
if (Percent != PercentOld)
{
printf ("\r%d%% done...", Percent);
PercentOld = Percent;
}
}
free (pBuff);
fclose (pFile);
return 0;
}
#endif
diff --git a/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h
index 08af468..07f3cbd 100644
--- a/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h
+++ b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h
@@ -1,187 +1,183 @@
/*******************************************************************************
* xmount Copyright (c) 2008-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* This module has been written by Guy Voncken. It contains the functions for *
* accessing simple AFF images created by Guymager. *
* *
* 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/>. *
*******************************************************************************/
+// Please don't touch source code formatting!
+
#ifndef AAFF_H
#define AAFF_H
typedef struct _t_Aaff *t_pAaff;
// ----------------------
// Constant definitions
// ----------------------
-#define AAFF_DEFAULT_PAGE_SEEK_MAX_ENTRIES 1000000 // Default max. number of cached seek points for fast page access
-
-#define AAFF_CURRENTPAGE_NOTSET ULONG_LONG_MAX
-
#define GETMAX(a,b) ((a)>(b)?(a):(b))
#define GETMIN(a,b) ((a)<(b)?(a):(b))
+#define FALSE 0
+#define TRUE 1
+
+const uint64_t AAFF_DEFAULT_MAX_PAGE_ARR_MEM = 10; // Default max. memory for caching seek points for fast page access (MiB)
+const uint64_t AAFF_CURRENTPAGE_NOTSET = UINT64_MAX;
+
// -----------------
// AFF definitions
// -----------------
#define AFF_GID_LENGTH 16
#define AFF_SEGARG_U64 2 // Used as argument for segments that contain a 64 bit unsigned in the data field
#define AFF_HEADER "AFF10\r\n"
#define AFF_SEGMENT_HEADER_MAGIC "AFF"
#define AFF_SEGMENT_FOOTER_MAGIC "ATT"
#define AFF_BADSECTOR_HEADER "BAD SECTOR"
#define AFF_FILE_TYPE "AFF"
#define AFF_SEGNAME_BADFLAG "badflag"
#define AFF_SEGNAME_AFFLIB_VERSION "afflib_version"
#define AFF_SEGNAME_FILETYPE "aff_file_type"
#define AFF_SEGNAME_GID "image_gid"
#define AFF_SEGNAME_SECTORS "devicesectors"
#define AFF_SEGNAME_SECTORSIZE "sectorsize"
#define AFF_SEGNAME_IMAGESIZE "imagesize"
#define AFF_SEGNAME_PAGESIZE "pagesize"
#define AFF_SEGNAME_BADSECTORS "badsectors"
#define AFF_SEGNAME_MD5 "md5"
#define AFF_SEGNAME_SHA256 "sha256"
#define AFF_SEGNAME_DURATION "acquisition_seconds"
#define AFF_SEGNAME_PAGE "page"
#define AAFF_SEGNAME_COMMAND_LINE "acquisition_commandline"
#define AAFF_SEGNAME_MACADDR "acquisition_macaddr"
#define AAFF_SEGNAME_DATE "acquisition_date" // Format: YYYY-MM-DD HH:MM:SS TZT
#define AAFF_SEGNAME_DEVICE "acquisition_device"
#define AAFF_SEGNAME_MODEL "device_model"
#define AAFF_SEGNAME_SN "device_sn"
#define AFF_PAGEFLAGS_UNCOMPRESSED 0x0000
#define AFF_PAGEFLAGS_COMPRESSED_ZLIB 0x0001
#define AFF_PAGEFLAGS_COMPRESSED_ZERO 0x0033
#define AAFF_MD5_LEN 16
#define AAFF_SHA256_LEN 32
#define AAFF_BADSECTORMARKER_MAXLEN 65536
typedef struct
{
char Magic[4];
unsigned int NameLen;
unsigned int DataLen;
unsigned int Argument; // Named "flags" in original aff source, named "arg" in afinfo output.
char Name[]; //lint !e1501
} __attribute__ ((packed)) t_AffSegmentHeader;
typedef t_AffSegmentHeader *t_pAffSegmentHeader;
// Between header and footer lie the segment name and the data
typedef struct
{
char Magic[4];
unsigned int SegmentLen;
} __attribute__ ((packed)) t_AffSegmentFooter;
const int AaffInfoBuffLen = 1024*1024;
typedef struct _t_Aaff
{
- char *pFilename;
- FILE *pFile;
-
- char *pLibVersion; // AFF File Header info
- char *pFileType;
- unsigned int PageSize;
- unsigned int SectorSize;
- uint64_t Sectors;
- uint64_t ImageSize;
- uint64_t TotalPages;
-
- char *pNameBuff; // Buffers
- char *pDataBuff;
- unsigned int NameBuffLen;
- unsigned int DataBuffLen;
-
- uint64_t CurrentPage;
- char *pPageBuff; // Length is PageSize, contains data of CurrentPage
- unsigned int PageBuffDataLen; // Length of current data in PageBuff (the same for all pages, but the last one might contain less data)
-
- char *pInfoBuff;
- char *pInfoBuffConst;
-
- uint64_t *pPageSeekArr;
- uint64_t PageSeekArrLen;
- uint64_t Interleave; // The number of pages lying between 2 entries in the PageSeekArr
+ char *pFilename;
+ FILE *pFile;
+
+ char *pLibVersion; // AFF File Header info
+ char *pFileType;
+ unsigned int PageSize;
+ unsigned int SectorSize;
+ uint64_t Sectors;
+ uint64_t ImageSize;
+ uint64_t TotalPages;
+
+ char *pNameBuff; // Buffers
+ char *pDataBuff;
+ unsigned int NameBuffLen;
+ unsigned int DataBuffLen;
+
+ uint64_t CurrentPage;
+ char *pPageBuff; // Length is PageSize, contains data of CurrentPage
+ unsigned int PageBuffDataLen; // Length of current data in PageBuff (the same for all pages, but the last one might contain less data)
+
+ char *pInfoBuff;
+ char *pInfoBuffConst;
+
+ uint64_t *pPageSeekArr;
+ uint64_t PageSeekArrLen;
+ uint64_t Interleave; // The number of pages lying between 2 entries in the PageSeekArr
+
+ // Options
+ char *pLogFilename;
+ uint64_t MaxPageArrMem; // Maximum amount of memory (in MiB) for storing page pointers
+ uint8_t LogStdout;
} t_Aaff;
-// ----------------
-// Error handling
-// ----------------
-
-#ifdef AAFF_DEBUG
- #define CHK(ChkVal) \
- { \
- int ChkValRc; \
- if ((ChkValRc=(ChkVal)) != AAFF_OK) \
- { \
- printf ("Err %d in %s, %d\n", ChkValRc, __FILE__, __LINE__); \
- return ChkValRc; \
- } \
- }
- #define DEBUG_PRINTF(pFormat, ...) \
- printf (pFormat, ##__VA_ARGS__);
-#else
- #define CHK(ChkVal) \
- { \
- int ChkValRc; \
- if ((ChkValRc=(ChkVal)) != AAFF_OK) \
- return ChkValRc; \
- }
- #define DEBUG_PRINTF(...)
-#endif
-
// Possible error codes
enum
{
- AAFF_OK = 0,
- AAFF_FOUND,
-
- AAFF_MEMALLOC_FAILED=100,
- AAFF_FILE_OPEN_FAILED,
- AAFF_INVALID_SIGNATURE,
- AAFF_CANNOT_READ_DATA,
- AAFF_INVALID_HEADER,
- AAFF_INVALID_FOOTER, // 105
- AAFF_TOO_MANY_HEADER_SEGEMENTS,
- AAFF_NOT_CREATED_BY_GUYMAGER,
- AAFF_INVALID_PAGE_NUMBER,
- AAFF_UNEXPECTED_PAGE_NUMBER,
- AAFF_CANNOT_CLOSE_FILE, // 110
- AAFF_CANNOT_SEEK,
- AAFF_WRONG_SEGMENT,
- AAFF_UNCOMPRESS_FAILED,
- AAFF_INVALID_PAGE_ARGUMENT,
- AAFF_SEEKARR_CORRUPT, // 115
- AAFF_PAGE_NOT_FOUND,
- AAFF_READ_BEYOND_IMAGE_LENGTH,
- AAFF_READ_BEYOND_LAST_PAGE
+ AAFF_OK = 0,
+ AAFF_FOUND,
+
+ AAFF_ERROR_ENOMEM_START=1000,
+ AAFF_MEMALLOC_FAILED,
+ AAFF_ERROR_ENOMEM_END,
+
+ AAFF_ERROR_EINVAL_START=2000,
+ AAFF_OPTIONS_ERROR,
+ AAFF_SPLIT_IMAGES_NOT_SUPPORTED,
+ AAFF_INVALID_SIGNATURE,
+ AAFF_NOT_CREATED_BY_GUYMAGER,
+ AAFF_CANNOT_OPEN_LOGFILE,
+ AAFF_ERROR_EINVAL_END,
+
+ AAFF_ERROR_EIO_START=3000,
+ AAFF_FILE_OPEN_FAILED,
+ AAFF_CANNOT_READ_DATA,
+ AAFF_INVALID_HEADER,
+ AAFF_INVALID_FOOTER,
+ AAFF_TOO_MANY_HEADER_SEGEMENTS,
+ AAFF_INVALID_PAGE_NUMBER,
+ AAFF_UNEXPECTED_PAGE_NUMBER,
+ AAFF_CANNOT_CLOSE_FILE,
+ AAFF_CANNOT_SEEK,
+ AAFF_WRONG_SEGMENT,
+ AAFF_UNCOMPRESS_FAILED,
+ AAFF_INVALID_PAGE_ARGUMENT,
+ AAFF_SEEKARR_CORRUPT,
+ AAFF_PAGE_NOT_FOUND,
+ AAFF_READ_BEYOND_IMAGE_LENGTH,
+ AAFF_READ_BEYOND_LAST_PAGE,
+ AAFF_PAGE_LENGTH_ZERO,
+ AAFF_NEGATIVE_SEEK,
+ AAFF_ERROR_EIO_END,
};
#endif
diff --git a/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c
index f68ea98..8447319 100644
--- a/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c
+++ b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c
@@ -1,1527 +1,1530 @@
/*******************************************************************************
* xmount Copyright (c) 2008-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* This module has been written by Guy Voncken. It contains the functions for *
* accessing EWF images created by Guymager and others. *
* *
* 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/>. *
*******************************************************************************/
// Aewf has been written in order to reduce xmount's memory footprint when
// operating on large EWF images. Before Aewf, xmount exclusively relied on
// libewf for accessing EWF images, resulting in enormous memory consumption.
//
// Aewf uses 2 main structures for handling image access: pAewf->pSegmentArr
// contains everything about the image files (segments) and pAewf->pTableArr
// handles the EWF chunk offset tables.
//
// At the same time, those structures serve as caches for the two most vital
// ressouces, namely the number of segment files opened in parallel and the
// memory consumed by the chunk offset tables.
//
// The max. values for both are configurable, see pAewf->MaxOpenSegments and
// pAewf->MaxTableCache.
// Please don't touch source code formatting!
#ifdef LINTING
// #define _LARGEFILE_SOURCE
// #define _FILE_OFFSET_BITS 64
#define AEWF_STANDALONE
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <limits.h>
#include <time.h> //lint !e537 !e451 Include file messages
#include <zlib.h>
#include <unistd.h> //lint !e537
#include <wchar.h> //lint !e537 !e451
#include <stdarg.h> //lint !e537 !e451
#include <limits.h> //lint !e537 !e451
#include <errno.h>
#include "../libxmount_input.h"
#include "libxmount_input_aewf.h"
#ifdef AEWF_STANDALONE
#define CREATE_REVERSE_FILE
// #define REVERSE_FILE_USES_SEPARATE_HANDLE
#define LOG_STDOUT TRUE
#endif
//#ifdef AEWF_STANDALONE
// #define _GNU_SOURCE
//#endif
#define AEWF_OPTION_TABLECACHE "aewfmaxmem"
#define AEWF_OPTION_MAXOPENSEGMENTS "aewfmaxfiles"
#define AEWF_OPTION_STATS "aewfstats"
#define AEWF_OPTION_STATSREFRESH "aewfrefresh"
#define AEWF_OPTION_LOG "aewflog"
static int AewfClose (void *pHandle);
static const char* AewfGetErrorMessage (int ErrNum);
-#define AEWF_DEFAULT_TABLECACHE 10LLU // MiB
-#define AEWF_DEFAULT_MAXOPENSEGMENTS 10LLU
-#define AEWF_DEFAULT_STATSREFRESH 10LLU
+const uint64_t AEWF_DEFAULT_TABLECACHE = 10; // MiB
+const uint64_t AEWF_DEFAULT_MAXOPENSEGMENTS = 10;
+const uint64_t AEWF_DEFAULT_STATSREFRESH = 10;
// ----------------------------
// Logging and error handling
// ----------------------------
#define LOG_HEADER_LEN 80
int LogvEntry (const char *pLogFileName, uint8_t LogStdout, const char *pFileName, const char *pFunctionName, int LineNr, const char *pFormat, va_list pArguments)
{
time_t NowT;
struct tm *pNowTM;
FILE *pFile;
int wr;
char *pFullLogFileName = NULL;
const char *pBase;
char LogLineHeader[1024];
pid_t OwnPID;
if (!LogStdout && (pLogFileName==NULL))
return AEWF_OK;
time (&NowT);
pNowTM = localtime (&NowT);
OwnPID = getpid(); // pthread_self()
wr = (int) strftime (&LogLineHeader[0] , sizeof(LogLineHeader) , "%a %d.%b.%Y %H:%M:%S ", pNowTM); //lint !e713
wr += snprintf (&LogLineHeader[wr], sizeof(LogLineHeader)-wr, "%5d ", OwnPID); //lint !e737
if (pFileName && pFunctionName)
{
pBase = strrchr(pFileName, '/');
if (pBase)
pFileName = pBase+1;
wr += snprintf (&LogLineHeader[wr], sizeof(LogLineHeader)-wr, "%s %s %d ", pFileName, pFunctionName, LineNr); //lint !e737
}
// while (wr < LOG_HEADER_LEN)
// LogLineHeader[wr++] = ' ';
if (pLogFileName)
{
wr = asprintf (&pFullLogFileName, "%s_%d", pLogFileName, OwnPID);
if ((wr <= 0) || (pFullLogFileName == NULL))
{
if (LogStdout)
printf ("\nLog file error: Can't build filename");
return AEWF_MEMALLOC_FAILED;
}
else
{
pFile = fopen64 (pFullLogFileName, "a");
if (pFile == NULL)
{
if (LogStdout)
printf ("\nLog file error: Can't be opened");
return AEWF_CANNOT_OPEN_LOGFILE;
}
else
{
fprintf (pFile, "%-*s", LOG_HEADER_LEN, &LogLineHeader[0]);
vfprintf (pFile, pFormat, pArguments);
fprintf (pFile, "\n");
fclose (pFile);
}
free (pFullLogFileName);
}
}
if (LogStdout)
{
printf ("%s", &LogLineHeader[0]);
vprintf (pFormat, pArguments);
printf ("\n");
}
return AEWF_OK;
}
int LogEntry (const char *pLogFileName, uint8_t LogStdout, const char *pFileName, const char *pFunctionName, int LineNr, const char *pFormat, ...)
{
va_list VaList;
int rc;
if (!LogStdout && (pLogFileName==NULL))
return AEWF_OK;
va_start (VaList, pFormat); //lint !e530 Symbol 'VaList' not initialized
rc = LogvEntry (pLogFileName, LogStdout, pFileName, pFunctionName, LineNr, pFormat, VaList);
va_end(VaList);
return rc;
}
// CHK requires existance of pAewf handle
#ifdef AEWF_STANDALONE
#define LOG_ERRORS_ON_STDOUT TRUE
#else
#define LOG_ERRORS_ON_STDOUT pAewf->LogStdout
#endif
#define CHK(ChkVal) \
{ \
int ChkValRc; \
if ((ChkValRc=(ChkVal)) != AEWF_OK) \
{ \
const char *pErr = AewfGetErrorMessage (ChkValRc); \
LogEntry (pAewf->pLogFilename, LOG_ERRORS_ON_STDOUT, __FILE__, __FUNCTION__, __LINE__, "Error %d (%s) occured", ChkValRc, pErr); \
return ChkValRc; \
} \
}
#define LOG(...) \
LogEntry (pAewf->pLogFilename, pAewf->LogStdout, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__);
// AewfCheckError is called before exiting AewfRead. It should not
// be called elsewehere or else the statistics would become wrong.
static void AewfCheckError (t_pAewf pAewf, int Ret, int *pErrno)
{
*pErrno = 0;
if (Ret != AEWF_OK)
{
pAewf->Errors++;
pAewf->LastError = Ret;
if ((Ret >= AEWF_ERROR_ENOMEM_START) && (Ret <= AEWF_ERROR_ENOMEM_END)) *pErrno = ENOMEM;
else if ((Ret >= AEWF_ERROR_EINVAL_START) && (Ret <= AEWF_ERROR_EINVAL_END)) *pErrno = EINVAL;
else *pErrno = EIO; // all other errors
}
}
// ------------------------------------
// Internal functions
// ------------------------------------
-static int AewfLogStdout (t_pAewf pAewf, uint8_t Flag)
-{
- pAewf->LogStdout = Flag;
- return AEWF_OK;
-}
-
static int OpenFile (FILE **ppFile, const char *pFilename)
{
*ppFile = fopen (pFilename, "r");
if (*ppFile == NULL)
return AEWF_FILE_OPEN_FAILED;
return AEWF_OK;
}
static int CloseFile (FILE **ppFile)
{
if (fclose (*ppFile))
return AEWF_FILE_CLOSE_FAILED;
*ppFile = NULL;
return AEWF_OK;
}
#define NO_SEEK ULLONG_MAX
static int ReadFilePos (t_pAewf pAewf, FILE *pFile, void *pMem, unsigned int Size, uint64_t Pos)
{
if (Size == 0)
return AEWF_OK;
if (Pos != NO_SEEK)
{
if (fseeko64 (pFile, Pos, SEEK_SET))
return AEWF_FILE_SEEK_FAILED;
}
if (fread (pMem, Size, 1UL, pFile) != 1)
return AEWF_FILE_READ_FAILED;
return AEWF_OK;
}
static int ReadFileAllocPos (t_pAewf pAewf, FILE *pFile, void **ppMem, unsigned int Size, uint64_t Pos)
{
*ppMem = (void*) malloc (Size);
if (*ppMem == NULL)
return AEWF_MEMALLOC_FAILED;
CHK (ReadFilePos (pAewf, pFile, *ppMem, Size, Pos))
return AEWF_OK;
}
static int ReadFileAlloc (t_pAewf pAewf, FILE *pFile, void **ppMem, unsigned int Size)
{
CHK (ReadFileAllocPos (pAewf, pFile, ppMem, Size, NO_SEEK))
return AEWF_OK;
}
static int QsortCompareSegments (const void *pA, const void *pB)
{
const t_pSegment pSegmentA = ((const t_pSegment)pA); //lint !e1773 Attempt to cast way const
const t_pSegment pSegmentB = ((const t_pSegment)pB); //lint !e1773 Attempt to cast way const
return (int)pSegmentA->Number - (int)pSegmentB->Number;
}
static int CreateInfoData (t_pAewf pAewf, t_pAewfSectionVolume pVolume, char *pHeader , unsigned HeaderLen,
char *pHeader2, unsigned Header2Len)
{
char *pInfo1 = NULL;
char *pInfo2 = NULL;
char *pInfo3 = NULL;
char *pInfo4 = NULL;
char *pInfo5 = NULL;
char *pHdr = NULL;
unsigned HdrLen= 0;
char *pText = NULL;
char *pCurrent;
char *pDesc = NULL;
char *pData = NULL;
char *pEnd;
uLongf DstLen0;
int zrc;
const int MaxTextSize = 65536;
unsigned UncompressedLen;
int rc = AEWF_OK;
#define RET_ERR(ErrCode) \
{ \
rc = ErrCode; \
goto CleanUp; \
}
#define ASPRINTF(...) \
{ \
if (asprintf(__VA_ARGS__) < 0) \
RET_ERR (AEWF_ASPRINTF_FAILED) \
}
ASPRINTF(&pInfo1, "Image size %" PRIu64 " (%0.2f GiB)\n"
"Bytes per sector %u\n"
"Sector count %" PRIu64 "\n"
"Sectors per chunk %u\n"
"Chunk count %u\n"
"Error block size %u\n"
"Compression level %u\n"
"Media type %02X\n"
"Cylinders/Heads/Sectors %u/%u/%u\n"
"Media flags %02X\n"
"Palm volume start sector %u\n"
"Smart logs start sector %u\n",
pAewf->ImageSize, pAewf->ImageSize / (1024.0 * 1024.0* 1024.0),
pVolume->BytesPerSector,
pVolume->SectorCount,
pVolume->SectorsPerChunk,
pVolume->ChunkCount,
pVolume->ErrorBlockSize,
pVolume->CompressionLevel,
pVolume->MediaType,
pVolume->CHS_Cylinders, pVolume->CHS_Heads, pVolume->CHS_Sectors,
pVolume->MediaFlags,
pVolume->PalmVolumeStartSector,
pVolume->SmartLogsStartSector);
ASPRINTF (&pInfo2, "AcquirySystemGUID %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
pVolume->AcquirySystemGUID[ 0], pVolume->AcquirySystemGUID[ 1], pVolume->AcquirySystemGUID[ 2], pVolume->AcquirySystemGUID[ 3],
pVolume->AcquirySystemGUID[ 4], pVolume->AcquirySystemGUID[ 4], pVolume->AcquirySystemGUID[ 6], pVolume->AcquirySystemGUID[ 7],
pVolume->AcquirySystemGUID[ 8], pVolume->AcquirySystemGUID[ 9], pVolume->AcquirySystemGUID[10], pVolume->AcquirySystemGUID[11],
pVolume->AcquirySystemGUID[12], pVolume->AcquirySystemGUID[13], pVolume->AcquirySystemGUID[14], pVolume->AcquirySystemGUID[15]);
if (pHeader2) { pHdr = pHeader2; HdrLen = Header2Len; }
else if (pHeader ) { pHdr = pHeader; HdrLen = HeaderLen; }
if (pHdr)
{
pText = (char *) malloc (MaxTextSize);
if (pText == NULL)
RET_ERR (AEWF_MEMALLOC_FAILED)
DstLen0 = MaxTextSize;
zrc = uncompress ((unsigned char *)pText, &DstLen0, (const Bytef*)pHdr, HdrLen);
UncompressedLen = DstLen0;
if (zrc != Z_OK)
RET_ERR (AEWF_UNCOMPRESS_HEADER_FAILED)
if (pHeader2) // We must convert from silly Windows 2 byte wchar_t to
{ // correct Unix 4 byte wchar_t, before we can convert to UTF8
wchar_t *pTemp = (wchar_t*) malloc ((UncompressedLen/2)*sizeof(wchar_t));
if (pTemp == NULL)
RET_ERR (AEWF_MEMALLOC_FAILED)
for (unsigned i=0; i<(UncompressedLen/2); i++)
pTemp[i] = (wchar_t) (((unsigned char*)pText)[2*i ]) |
(((wchar_t) (((unsigned char*)pText)[2*i+1])) << 8);
(void) wcstombs(pText, pTemp, UncompressedLen/2);
free (pTemp);
}
// Extract descriptor and data lines
// ---------------------------------
pCurrent = pText; // pText may start with BOM (Header2), but that's no problem as
while (pCurrent) // first line anyway never is the "main" line.
{
if (strcasestr(pCurrent, "main") == pCurrent) // The header line is the one that
break; // follows the line beginning with "main"
pCurrent = strstr (pCurrent, "\n");
if (pCurrent)
pCurrent++;
}
if (pCurrent)
{
pDesc = strstr (pCurrent, "\n");
if (pDesc)
{
*pDesc++ = '\0';
pData = strstr (pDesc, "\n");
if (pData)
{
*pData++ = '\0';
pEnd = strstr (pData, "\n");
if (pEnd)
*pEnd = '\0';
}
}
}
// Scan descriptor and data lines
// ------------------------------
char *pCurDesc = pDesc;
char *pCurData = pData;
const char *pField;
char *pTabDesc;
char *pTabData;
char *pValue;
int wr = 0;
time_t Time;
struct tm *pTM;
char TimeBuff[64];
if (pCurDesc && pCurData)
{
pInfo3 = (char *) malloc (strlen (pCurData) + 4096);
if (pInfo3 == NULL)
RET_ERR (AEWF_MEMALLOC_FAILED)
while (*pCurDesc && *pCurData)
{
pTabDesc = strstr (pCurDesc, "\t");
pTabData = strstr (pCurData, "\t");
if (pTabDesc) *pTabDesc = '\0';
if (pTabData) *pTabData = '\0';
if (strcasecmp(pCurDesc, "a" ) == 0) pField = "Description";
else if (strcasecmp(pCurDesc, "c" ) == 0) pField = "Case";
else if (strcasecmp(pCurDesc, "n" ) == 0) pField = "Evidence";
else if (strcasecmp(pCurDesc, "e" ) == 0) pField = "Examiner";
else if (strcasecmp(pCurDesc, "t" ) == 0) pField = "Notes";
else if (strcasecmp(pCurDesc, "md") == 0) pField = "Model";
else if (strcasecmp(pCurDesc, "sn") == 0) pField = "Serial number";
else if (strcasecmp(pCurDesc, "av") == 0) pField = "Imager version";
else if (strcasecmp(pCurDesc, "ov") == 0) pField = "OS version";
else if (strcasecmp(pCurDesc, "m" ) == 0) pField = "Acquired time";
else if (strcasecmp(pCurDesc, "u" ) == 0) pField = "System time";
else if (strcasecmp(pCurDesc, "p" ) == 0) pField = NULL;
else if (strcasecmp(pCurDesc, "dc") == 0) pField = NULL;
else pField = "--";
if (pField)
{
pValue = pCurData;
if (strstr (pField, "time"))
{
size_t w;
Time = atoll (pCurData);
pTM = localtime (&Time);
pValue = &TimeBuff[0];
w = strftime (pValue, sizeof(TimeBuff), "%Y-%m-%d %H:%M:%S (%z)", pTM);
sprintf (&pValue[w], " (epoch %s)", pCurData);
}
wr += sprintf (&pInfo3[wr], "%-17s %s\n", pField, pValue);
}
if (!pTabDesc || !pTabData)
break;
pCurDesc = pTabDesc+1;
pCurData = pTabData+1;
}
}
}
if (pAewf->Segments == 1)
ASPRINTF (&pInfo4, "%"PRIu64" segment file: %s\n",
pAewf->Segments,
pAewf->pSegmentArr[0].pName)
else ASPRINTF (&pInfo4, "%"PRIu64" segment files\n First: %s\n Last: %s\n",
pAewf->Segments,
pAewf->pSegmentArr[0 ].pName,
pAewf->pSegmentArr[pAewf->Segments-1].pName);
ASPRINTF (&pInfo5, "%"PRIu64" tables\n", pAewf->Tables);
if (pInfo3)
ASPRINTF (&pAewf->pInfo, "%s%s\n%s\n%s%s", pInfo1, pInfo2, pInfo3, pInfo4, pInfo5)
else ASPRINTF (&pAewf->pInfo, "%s%s%s%s" , pInfo1, pInfo2, pInfo4, pInfo5)
#undef RET_ERR
#undef ASPRINTF
CleanUp:
if (pText ) free (pText );
if (pInfo1) free (pInfo1);
if (pInfo2) free (pInfo2);
if (pInfo3) free (pInfo3);
if (pInfo4) free (pInfo4);
if (pInfo5) free (pInfo5);
return rc;
}
static int AewfOpenSegment (t_pAewf pAewf, t_pTable pTable)
{
t_pSegment pOldestSegment;
if (pTable->pSegment->pFile != NULL) // is already opened ?
{
pAewf->SegmentCacheHits++;
return AEWF_OK;
}
pAewf->SegmentCacheMisses++;
// Check if another segment file must be closed first
// --------------------------------------------------
while (pAewf->OpenSegments >= pAewf->MaxOpenSegments)
{
pOldestSegment = NULL;
for (unsigned i=0; i<pAewf->Segments; i++)
{
if (pAewf->pSegmentArr[i].pFile == NULL)
continue;
if (pOldestSegment == NULL)
{
pOldestSegment = &pAewf->pSegmentArr[i];
}
else
{
if (pAewf->pSegmentArr[i].LastUsed < pOldestSegment->LastUsed)
pOldestSegment = &pAewf->pSegmentArr[i];
}
}
if (pOldestSegment == NULL)
break;
LOG ("Closing %s\n", pOldestSegment->pName);
CHK (CloseFile (&pOldestSegment->pFile))
pAewf->OpenSegments--;
}
// Read the desired table into RAM
// -------------------------------
LOG ("Opening %s\n", pTable->pSegment->pName);
CHK (OpenFile(&pTable->pSegment->pFile, pTable->pSegment->pName))
pAewf->OpenSegments++;
return AEWF_OK;
}
static int AewfLoadEwfTable (t_pAewf pAewf, t_pTable pTable)
{
t_pTable pOldestTable = NULL;
if (pTable->pEwfTable != NULL) // is already loaded?
{
pAewf->TableCacheHits++;
return AEWF_OK;
}
pAewf->TableCacheMisses++;
// Check if another pEwfTable must be given up first
// -------------------------------------------------
while ((pAewf->TableCache + pTable->Size) > pAewf->MaxTableCache)
{
pOldestTable = NULL;
for (unsigned i=0; i<pAewf->Tables; i++)
{
if (pAewf->pTableArr[i].pEwfTable == NULL)
continue;
if (pOldestTable == NULL)
{
pOldestTable = &pAewf->pTableArr[i];
}
else
{
if (pAewf->pTableArr[i].LastUsed < pOldestTable->LastUsed)
pOldestTable = &pAewf->pTableArr[i];
}
}
if (pOldestTable == NULL)
break;
pAewf->TableCache -= pOldestTable->Size;
free (pOldestTable->pEwfTable);
pOldestTable->pEwfTable = NULL;
LOG ("Releasing table %" PRIu64 " (%lu bytes)\n", pOldestTable->Nr, pOldestTable->Size);
}
// Read the desired table into RAM
// -------------------------------
LOG ("Loading table %" PRIu64 " (%lu bytes)", pTable->Nr, pTable->Size);
CHK (AewfOpenSegment (pAewf, pTable));
CHK (ReadFileAllocPos (pAewf, pTable->pSegment->pFile, (void**) &pTable->pEwfTable, pTable->Size, pTable->Offset))
pAewf->TableCache += pTable->Size;
pAewf->TablesReadFromImage = pTable->Size;
return AEWF_OK;
}
// AewfReadChunk0 reads exactly one chunk. It expects the EWF table be present
// in memory and the required segment be opened.
static int AewfReadChunk0 (t_pAewf pAewf, t_pTable pTable, uint64_t AbsoluteChunk, unsigned TableChunk)
{
int Compressed;
uint64_t SeekPos;
t_pAewfSectionTable pEwfTable;
unsigned int Offset;
unsigned int ReadLen;
uLongf DstLen0;
int zrc;
uint CalcCRC;
uint *pStoredCRC;
uint64_t ChunkSize;
int Ret = AEWF_OK;
pEwfTable = pTable->pEwfTable;
if (pEwfTable == NULL)
return AEWF_ERROR_EWF_TABLE_NOT_READY;
if (pTable->pSegment->pFile == NULL)
return AEWF_ERROR_EWF_SEGMENT_NOT_READY;
Compressed = pEwfTable->OffsetArray[TableChunk] & AEWF_COMPRESSED;
Offset = pEwfTable->OffsetArray[TableChunk] & ~AEWF_COMPRESSED;
SeekPos = pEwfTable->TableBaseOffset + Offset;
if (TableChunk < (pEwfTable->ChunkCount-1))
ReadLen = (pEwfTable->OffsetArray[TableChunk+1] & ~AEWF_COMPRESSED) - Offset;
else ReadLen = (pTable->SectionSectorsSize - sizeof(t_AewfSection)) - (Offset - (pEwfTable->OffsetArray[0] & ~AEWF_COMPRESSED));
// else ReadLen = pAewf->ChunkBuffSize; // This also works! It looks as if uncompress is able to find out by itself the real size of the input data.
if (ReadLen > pAewf->ChunkBuffSize)
{
LOG ("Chunk too big %u / %u", ReadLen, pAewf->ChunkBuffSize);
return AEWF_CHUNK_TOO_BIG;
}
ChunkSize = pAewf->ChunkSize;
if (AbsoluteChunk == (pAewf->Chunks-1)) // The very last chunk of the image may be smaller than the default
{ // chunk size if the image isn't a multiple of the chunk size.
ChunkSize = pAewf->ImageSize % pAewf->ChunkSize;
if (ChunkSize == 0)
ChunkSize = pAewf->ChunkSize;
}
if (Compressed)
{
CHK (ReadFilePos (pAewf, pTable->pSegment->pFile, pAewf->pChunkBuffCompressed, ReadLen, SeekPos))
DstLen0 = pAewf->ChunkBuffSize;
zrc = uncompress ((unsigned char*)pAewf->pChunkBuffUncompressed, &DstLen0, (const Bytef*)pAewf->pChunkBuffCompressed, ReadLen);
if (zrc != Z_OK)
Ret = AEWF_UNCOMPRESS_FAILED;
if (DstLen0 != ChunkSize)
Ret = AEWF_BAD_UNCOMPRESSED_LENGTH;
}
else
{
CHK (ReadFilePos (pAewf, pTable->pSegment->pFile, pAewf->pChunkBuffUncompressed, ReadLen, SeekPos))
CalcCRC = adler32 (1, (const Bytef *) pAewf->pChunkBuffUncompressed, ChunkSize);
pStoredCRC = (uint *) (pAewf->pChunkBuffUncompressed + ChunkSize); //lint !e826 Suspicious pointer-to-pointer conversion (area too small)
if (CalcCRC != *pStoredCRC)
Ret = AEWF_CHUNK_CRC_ERROR;
}
pAewf->DataReadFromImage += ReadLen;
pAewf->DataReadFromImageRaw += ChunkSize;
if (Ret == AEWF_OK)
{
pAewf->ChunkInBuff = AbsoluteChunk;
pAewf->ChunkBuffUncompressedDataLen = ChunkSize;
}
else
{
pAewf->ChunkInBuff = AEWF_NONE;
pAewf->ChunkBuffUncompressedDataLen = 0;
}
return Ret;
}
static int AewfReadChunk (t_pAewf pAewf, uint64_t AbsoluteChunk, char **ppBuffer, unsigned int *pLen)
{
t_pTable pTable;
int Found=FALSE;
unsigned TableChunk;
unsigned TableNr;
*ppBuffer = pAewf->pChunkBuffUncompressed;
*pLen = 0;
if (pAewf->ChunkInBuff == AbsoluteChunk)
{
*pLen = pAewf->ChunkBuffUncompressedDataLen;
pAewf->ChunkCacheHits++;
return AEWF_OK;
}
pAewf->ChunkCacheMisses++;
// Find table containing desired chunk
// -----------------------------------
for (TableNr=0; TableNr<pAewf->Tables; TableNr++)
{
pTable = &pAewf->pTableArr[TableNr];
Found = (AbsoluteChunk >= pTable->ChunkFrom) &&
(AbsoluteChunk <= pTable->ChunkTo);
if (Found)
break;
}
if (!Found)
CHK (AEWF_CHUNK_NOT_FOUND)
// Load corresponding table and get chunk
// --------------------------------------
pTable->LastUsed = time(NULL); //lint !e771 pTable' (line 640) conceivably not initialized
pTable->pSegment->LastUsed = pTable->LastUsed; // Update LastUsed here, in order not to remove the required data from cache
CHK (AewfLoadEwfTable (pAewf, pTable))
CHK (AewfOpenSegment (pAewf, pTable));
if ((AbsoluteChunk - pTable->ChunkFrom) > UINT_MAX)
CHK (AEWF_ERROR_IN_CHUNK_NUMBER)
TableChunk = AbsoluteChunk - pTable->ChunkFrom;
// LOG ("table %d / entry %" PRIu64 " (%s)\n", TableNr, TableChunk, pTable->pSegment->pName)
CHK (AewfReadChunk0 (pAewf, pTable, AbsoluteChunk, TableChunk))
*pLen = pAewf->ChunkBuffUncompressedDataLen;
return AEWF_OK;
}
static int UpdateStats (t_pAewf pAewf, int Force)
{
time_t NowT;
pid_t pid;
FILE *pFile;
char *pFilename = NULL;
char *pCurrentWorkDir = NULL;
if (pAewf->pStatsFilename)
{
time (&NowT);
if (((NowT - pAewf->LastStatsUpdate) >= (int)pAewf->StatsRefresh) || Force)
{
pAewf->LastStatsUpdate = NowT;
pid = getpid ();
if (asprintf (&pFilename, "%s_%d", pAewf->pStatsFilename, pid) < 0)
return AEWF_MEMALLOC_FAILED;
pFile = fopen (pFilename, "w");
if (pFile == NULL) // May be the file is locked by someone else, let's retry in 1 second
{
pAewf->LastStatsUpdate = NowT - pAewf->StatsRefresh + 1;
return AEWF_OK;
}
fprintf (pFile, "Image segment files %6"PRIu64"\n" , pAewf->Segments);
fprintf (pFile, "Image tables %6"PRIu64"\n" , pAewf->Tables);
fprintf (pFile, "\n");
fprintf (pFile, "Cache hits misses ratio\n");
fprintf (pFile, "--------------------------------------\n");
fprintf (pFile, "Segment %10" PRIu64 " %10" PRIu64 " %5.1f%%\n", pAewf->SegmentCacheHits, pAewf->SegmentCacheMisses, (100.0*pAewf->SegmentCacheHits)/(pAewf->SegmentCacheHits+pAewf->SegmentCacheMisses));
fprintf (pFile, "Table %10" PRIu64 " %10" PRIu64 " %5.1f%%\n", pAewf->TableCacheHits , pAewf->TableCacheMisses , (100.0*pAewf->TableCacheHits) /(pAewf->TableCacheHits +pAewf->TableCacheMisses ));
fprintf (pFile, "Chunk %10" PRIu64 " %10" PRIu64 " %5.1f%%\n", pAewf->ChunkCacheHits , pAewf->ChunkCacheMisses , (100.0*pAewf->ChunkCacheHits) /(pAewf->ChunkCacheHits +pAewf->ChunkCacheMisses ));
fprintf (pFile, "\n");
fprintf (pFile, "Read operations %10" PRIu64 "\n", pAewf->ReadOperations);
fprintf (pFile, "Errors %10" PRIu64 "\n", pAewf->Errors);
fprintf (pFile, "Open segment files %10" PRIu64"\n" , pAewf->OpenSegments);
fprintf (pFile, "Last error %10d (%s)\n" , pAewf->LastError, AewfGetErrorMessage (pAewf->LastError));
fprintf (pFile, "Data read from image %10.1f MiB (compressed)\n", pAewf->DataReadFromImage / (1024.0*1024.0));
fprintf (pFile, "Data read from image %10.1f MiB (raw)\n" , pAewf->DataReadFromImageRaw / (1024.0*1024.0));
fprintf (pFile, "Data requested by caller %10.1f MiB\n" , pAewf->DataRequestedByCaller/ (1024.0*1024.0));
fprintf (pFile, "Tables read from image %10.1f MiB\n" , pAewf->TablesReadFromImage / (1024.0*1024.0));
fprintf (pFile, "RAM used as table cache %10.1f MiB\n", pAewf->TableCache/ (1024.0*1024.0));
pCurrentWorkDir = getcwd (NULL, 0);
if (pCurrentWorkDir == NULL)
return AEWF_MEMALLOC_FAILED;
fprintf (pFile, "\nCurrent working directory: %s\n", pCurrentWorkDir);
free (pCurrentWorkDir);
(void) fclose (pFile);
free (pFilename);
return AEWF_OK;
}
}
return AEWF_OK;
}
// ---------------
// API functions
// ---------------
static int AewfCreateHandle (void **ppHandle, const char *pFormat, uint8_t Debug)
{
t_pAewf pAewf;
*ppHandle = NULL;
// Create handle and clear it
// --------------------------
- pAewf=(t_pAewf)malloc(sizeof(t_Aewf));
+ pAewf = (t_pAewf) malloc (sizeof(t_Aewf));
if (pAewf == NULL)
return AEWF_MEMALLOC_FAILED;
memset(pAewf,0,sizeof(t_Aewf));
pAewf->ChunkInBuff = AEWF_NONE;
pAewf->pErrorText = NULL;
pAewf->StatsRefresh = 10;
pAewf->SegmentCacheHits = 0;
pAewf->SegmentCacheMisses = 0;
pAewf->TableCacheHits = 0;
pAewf->TableCacheMisses = 0;
pAewf->ChunkCacheHits = 0;
pAewf->ChunkCacheMisses = 0;
pAewf->ReadOperations = 0;
pAewf->DataReadFromImage = 0;
pAewf->DataReadFromImageRaw = 0;
pAewf->DataRequestedByCaller = 0;
pAewf->TablesReadFromImage = 0;
pAewf->ChunksRead = 0;
pAewf->BytesRead = 0;
pAewf->Errors = 0;
pAewf->LastError = AEWF_OK;
pAewf->MaxTableCache = 0;
pAewf->MaxOpenSegments = 0;
pAewf->pStatsFilename = NULL;
pAewf->StatsRefresh = 0;
pAewf->pLogFilename = NULL;
- pAewf->LogStdout = FALSE;
+ pAewf->LogStdout = Debug;
pAewf->MaxTableCache = AEWF_DEFAULT_TABLECACHE * 1024*1024;
pAewf->MaxOpenSegments = AEWF_DEFAULT_MAXOPENSEGMENTS;
pAewf->StatsRefresh = AEWF_DEFAULT_STATSREFRESH;
- CHK (AewfLogStdout (pAewf, Debug))
-
*ppHandle = (void*) pAewf;
return AEWF_OK;
}
int AewfDestroyHandle(void **ppHandle)
{
t_pAewf pAewf = (t_pAewf) *ppHandle;
LOG ("Called");
LOG ("Remark: 'Ret' won't be logged"); // Handle gets destroyed, 'ret' logging not possible
if (pAewf->pLogFilename) free(pAewf->pLogFilename);
if (pAewf->pStatsFilename) free(pAewf->pStatsFilename);
memset (pAewf, 0, sizeof(t_Aewf));
free (pAewf);
*ppHandle = NULL;
return AEWF_OK;
}
-int AewfOpen(void *pHandle, const char **ppFilenameArr, uint64_t FilenameArrLen)
+int AewfOpen (void *pHandle, const char **ppFilenameArr, uint64_t FilenameArrLen)
{
t_pAewf pAewf = (t_pAewf) pHandle;
t_AewfFileHeader FileHeader;
t_AewfSection Section;
FILE *pFile;
t_pSegment pSegment;
t_pTable pTable;
uint64_t Pos;
t_pAewfSectionTable pEwfTable = NULL;
t_pAewfSectionVolume pVolume = NULL;
char *pHeader = NULL;
char *pHeader2 = NULL;
int LastSection;
unsigned int SectionSectorsSize;
unsigned HeaderLen = 0;
unsigned Header2Len = 0;
LOG ("Called - Files=%" PRIu64, FilenameArrLen);
// Create pSegmentArr and put the segment files in it
// --------------------------------------------------
int SegmentArrLen = FilenameArrLen * sizeof(t_Segment);
pAewf->pSegmentArr = (t_pSegment) malloc (SegmentArrLen);
pAewf->Segments = FilenameArrLen;
if (pAewf->pSegmentArr == NULL)
return AEWF_MEMALLOC_FAILED;
memset (pAewf->pSegmentArr, 0, SegmentArrLen);
for (unsigned i=0; i<FilenameArrLen; i++)
{
pSegment = &pAewf->pSegmentArr[i];
pSegment->pName = canonicalize_file_name (ppFilenameArr[i]); // canonicalize_file_name allocates a buffer
CHK (OpenFile (&pFile, pSegment->pName))
CHK (ReadFilePos (pAewf, pFile, (void*)&FileHeader, sizeof(FileHeader), 0))
// LOG ("Segment %s - %d \n", ppFilenameArr[i], FileHeader.SegmentNumber);
pSegment->Number = FileHeader.SegmentNumber;
pSegment->LastUsed = 0;
pSegment->pFile = NULL;
CHK (CloseFile (&pFile))
}
// Put segment array into correct sequence and check if segment number are correct
// -------------------------------------------------------------------------------
qsort (pAewf->pSegmentArr, pAewf->Segments, sizeof (t_Segment), &QsortCompareSegments);
for (unsigned i=0; i<pAewf->Segments; i++)
{
if ((i+1) != pAewf->pSegmentArr[i].Number)
return AEWF_INVALID_SEGMENT_NUMBER;
}
// Find all tables in the segment files
// ------------------------------------
pAewf->pTableArr = NULL;
pAewf->Tables = 0;
pAewf->Chunks = 0;
SectionSectorsSize = 0;
LOG ("Reading tables\n");
for (unsigned i=0; i<pAewf->Segments; i++)
{
pSegment = &pAewf->pSegmentArr[i];
CHK (OpenFile (&pFile, pSegment->pName))
CHK (ReadFilePos (pAewf, pFile, &FileHeader, sizeof(FileHeader), 0))
Pos = sizeof (FileHeader);
LOG ("Segment %s ", pSegment->pName);
do
{
CHK (ReadFilePos (pAewf, pFile, &Section, sizeof (t_AewfSection), Pos))
if (strcasecmp ((char *)Section.Type, "sectors") == 0)
{
SectionSectorsSize = Section.Size;
}
else if (strcasecmp ((char *)Section.Type, "table") == 0)
{
if (pVolume == NULL)
return AEWF_VOLUME_MUST_PRECEDE_TABLES;
if (SectionSectorsSize == 0)
return AEWF_SECTORS_MUST_PRECEDE_TABLES;
pAewf->Tables++;
pAewf->pTableArr = (t_pTable) realloc (pAewf->pTableArr, pAewf->Tables * sizeof (t_Table));
CHK (ReadFileAlloc (pAewf, pFile, (void**) &pEwfTable, sizeof(t_AewfSectionTable))) // No need to read the actual offset table
pTable = &pAewf->pTableArr[pAewf->Tables-1];
pTable->Nr = pAewf->Tables-1;
pTable->pSegment = pSegment;
pTable->Offset = Pos + sizeof (t_AewfSection);
pTable->Size = Section.Size;
pTable->ChunkCount = pEwfTable->ChunkCount;
pTable->LastUsed = 0;
pTable->pEwfTable = NULL;
pTable->ChunkFrom = pAewf->Chunks;
pTable->SectionSectorsSize = SectionSectorsSize;
pAewf->Chunks += pTable->ChunkCount;
pTable->ChunkTo = pAewf->Chunks-1;
free (pEwfTable);
pEwfTable = NULL;
SectionSectorsSize = 0;
}
else if ((strcasecmp ((char *)Section.Type, "header") == 0) && (pHeader==NULL))
{
HeaderLen = Section.Size - sizeof(t_AewfSection);
CHK (ReadFileAlloc (pAewf, pFile, (void**) &pHeader, HeaderLen))
}
else if ((strcasecmp ((char *)Section.Type, "header2") == 0) && (pHeader2==NULL))
{
Header2Len = Section.Size - sizeof(t_AewfSection);
CHK (ReadFileAlloc (pAewf, pFile, (void**) &pHeader2, Header2Len))
}
else if ((strcasecmp ((char *)Section.Type, "volume") == 0) && (pVolume==NULL))
{
CHK (ReadFileAlloc (pAewf, pFile, (void**) &pVolume, sizeof(t_AewfSectionVolume)))
pAewf->Sectors = pVolume->SectorCount;
pAewf->SectorSize = pVolume->BytesPerSector;
pAewf->ChunkSize = pVolume->SectorsPerChunk * pVolume->BytesPerSector; //lint !e647 Suspicious truncation
pAewf->ImageSize = pAewf->Sectors * pAewf->SectorSize;
}
LastSection = (Pos == Section.OffsetNextSection);
Pos = Section.OffsetNextSection;
} while (!LastSection);
CHK (CloseFile (&pFile))
}
if (pVolume == NULL)
return AEWF_VOLUME_MISSING;
if (pAewf->Chunks != pVolume->ChunkCount)
{
LOG ("Error: Wrong chunk count: %"PRIu64" / %"PRIu64, pAewf->Chunks, pVolume->ChunkCount);
LOG ("Maybe some segment files are missing. Perhaps you specified E01 instead of E?? or the segments continue beyond extension .EZZ.");
return AEWF_WRONG_CHUNK_COUNT;
}
pAewf->ChunkBuffSize = pAewf->ChunkSize + 4096; // reserve some extra space (for CRC and as compressed data might be slightly larger than uncompressed data with some imagers)
pAewf->pChunkBuffCompressed = (char *) malloc (pAewf->ChunkBuffSize);
pAewf->pChunkBuffUncompressed = (char *) malloc (pAewf->ChunkBuffSize);
if ((pAewf->pChunkBuffCompressed == NULL) ||
(pAewf->pChunkBuffUncompressed == NULL))
return AEWF_MEMALLOC_FAILED;
pAewf->TableCache = 0;
pAewf->OpenSegments = 0;
CHK (CreateInfoData (pAewf, pVolume, pHeader, HeaderLen, pHeader2, Header2Len))
free (pVolume);
free (pHeader);
free (pHeader2);
LOG ("Ret");
return AEWF_OK;
}
static int AewfClose (void *pHandle)
{
t_pAewf pAewf = (t_pAewf) pHandle;
t_pTable pTable;
t_pSegment pSegment;
LOG ("Called");
CHK (UpdateStats (pAewf,TRUE))
for (unsigned i=0; i<pAewf->Tables; i++)
{
pTable = &pAewf->pTableArr[i];
if (pTable->pEwfTable)
free (pTable->pEwfTable);
}
for (unsigned i=0;i<pAewf->Segments;i++)
{
pSegment = &pAewf->pSegmentArr[i];
if (pSegment->pFile)
CHK (CloseFile (&pSegment->pFile));
free (pSegment->pName);
}
free (pAewf->pTableArr);
free (pAewf->pSegmentArr);
free (pAewf->pChunkBuffCompressed);
free (pAewf->pChunkBuffUncompressed);
LOG ("Ret");
return AEWF_OK;
}
static int AewfSize (void *pHandle, uint64_t *pSize)
{
t_pAewf pAewf = (t_pAewf) pHandle;
LOG ("Called");
*pSize = pAewf->ImageSize;
LOG ("Ret - Size=%" PRIu64, *pSize);
return AEWF_OK;
}
static int AewfRead (void *pHandle, char *pBuf, off_t Seek, size_t Count, size_t *pRead, int *pErrno)
{
t_pAewf pAewf = (t_pAewf) pHandle;
char *pChunkBuffer;
+ uint64_t Seek64;
uint64_t Chunk;
uint64_t Remaining;
unsigned int ChunkLen, Ofs, ToCopy;
int Ret = AEWF_OK;
- LOG ("Called - Seek=%" PRIu64 ",Count=%" PRIu64, Seek, Count);
+ LOG ("Called - Seek=%'" PRIu64 ",Count=%'" PRIu64, Seek, Count);
*pRead = 0;
*pErrno = 0;
+ if (Seek < 0)
+ {
+ Ret = AEWF_NEGATIVE_SEEK;
+ goto Leave;
+ }
+ Seek64 = Seek;
+
pAewf->ReadOperations++;
pAewf->DataRequestedByCaller+=Count;
- if (Seek >= pAewf->ImageSize) // If calling function asks
- goto Leave; // for data beyond end of
- if ((Seek+Count) > pAewf->ImageSize) // image simply return what
- Count = pAewf->ImageSize - Seek; // is possible.
+ if (Seek64 >= pAewf->ImageSize) // If calling function asks
+ goto Leave; // for data beyond end of
+ if ((Seek64+Count) > pAewf->ImageSize) // image simply return what
+ Count = pAewf->ImageSize - Seek64; // is possible.
- Ofs = Seek % pAewf->ChunkSize;
- Chunk = Seek / pAewf->ChunkSize;
+ Ofs = Seek64 % pAewf->ChunkSize;
+ Chunk = Seek64 / pAewf->ChunkSize;
Remaining = Count;
while (Remaining)
{
Ret = AewfReadChunk (pAewf, Chunk, &pChunkBuffer, &ChunkLen);
if (Ret)
goto Leave;
if (ChunkLen == 0)
{
Ret = AEWF_CHUNK_LENGTH_ZERO;
goto Leave;
}
ToCopy = GETMIN (ChunkLen-Ofs, Remaining);
memcpy (pBuf, pChunkBuffer+Ofs, ToCopy);
Remaining -= ToCopy;
pBuf += ToCopy;
*pRead += ToCopy;
Ofs = 0;
Chunk++;
}
Leave:
AewfCheckError (pAewf, Ret, pErrno);
CHK (UpdateStats (pAewf, (Ret != AEWF_OK)))
LOG ("Ret %d - Read=%" PRIu32, Ret, *pRead);
return Ret;
}
static int AewfOptionsHelp (const char **ppHelp)
{
char *pHelp=NULL;
int wr;
- wr = asprintf (&pHelp, " %-8s : Maximum amount of RAM cache, in MiB, for image offset tables. Default: %llu MiB\n"
- " %-8s : Maximum number of concurrently opened image segment files. Default: %llu\n"
- " %-8s : Output statistics at regular intervals to this file.\n"
- " %-8s : The update interval, in seconds, for the statistics. Ignored if %s is not set. Default: %llus.\n"
- " %-8s : Log file name.\n"
+ wr = asprintf (&pHelp, " %-12s : Maximum amount of RAM cache, in MiB, for image offset tables. Default: %"PRIu64" MiB\n"
+ " %-12s : Maximum number of concurrently opened image segment files. Default: %"PRIu64"\n"
+ " %-12s : Output statistics at regular intervals to this file.\n"
+ " %-12s : The update interval, in seconds, for the statistics. Ignored if %s is not set. Default: %"PRIu64"s.\n"
+ " %-12s : Log file name.\n"
" Specify full paths for %s and %s options. The given file names are extended by _<pid>.\n",
AEWF_OPTION_TABLECACHE, AEWF_DEFAULT_TABLECACHE,
AEWF_OPTION_MAXOPENSEGMENTS, AEWF_DEFAULT_MAXOPENSEGMENTS,
AEWF_OPTION_STATS,
AEWF_OPTION_STATSREFRESH, AEWF_OPTION_STATS, AEWF_DEFAULT_STATSREFRESH,
AEWF_OPTION_LOG,
AEWF_OPTION_STATS, AEWF_OPTION_LOG);
if ((pHelp == NULL) || (wr<=0))
return AEWF_MEMALLOC_FAILED;
*ppHelp = pHelp;
return AEWF_OK;
}
static int AewfOptionsParse (void *pHandle, uint32_t OptionCount, const pts_LibXmountOptions *ppOptions, const char **ppError)
{
pts_LibXmountOptions pOption;
t_pAewf pAewf = (t_pAewf) pHandle;
const char *pError = NULL;
int rc = AEWF_OK;
int Ok;
LOG ("Called - OptionCount=%" PRIu32, OptionCount);
*ppError = NULL;
#define TEST_OPTION_UINT64(Opt,DestField) \
if (strcmp (pOption->p_key, Opt) == 0) \
{ \
pAewf->DestField = StrToUint64 (pOption->p_value, &Ok); \
if (!Ok) \
{ \
pError = "Error in option %s: Invalid value"; \
break; \
} \
LOG ("Option %s set to %" PRIu64, Opt, pAewf->DestField) \
}
for (uint32_t i=0; i<OptionCount; i++)
{
pOption = ppOptions[i];
if (strcmp (pOption->p_key, AEWF_OPTION_LOG) == 0)
{
pAewf->pLogFilename = strdup (pOption->p_value);
rc = LOG ("Logging for libxmount_input_aewf started")
if (rc != AEWF_OK)
{
pError = "Write test to log file failed";
break;
}
pOption->valid = TRUE;
LOG ("Option %s set to %s", AEWF_OPTION_LOG, pAewf->pLogFilename);
}
if (strcmp (pOption->p_key, AEWF_OPTION_STATS) == 0)
{
pAewf->pStatsFilename = strdup (pOption->p_value);
pOption->valid = TRUE;
LOG ("Option %s set to %s", AEWF_OPTION_LOG, pAewf->pLogFilename);
}
else TEST_OPTION_UINT64 (AEWF_OPTION_MAXOPENSEGMENTS, MaxOpenSegments)
else TEST_OPTION_UINT64 (AEWF_OPTION_TABLECACHE , MaxTableCache)
else TEST_OPTION_UINT64 (AEWF_OPTION_STATSREFRESH , StatsRefresh)
}
#undef TEST_OPTION_UINT64
if (pError)
*ppError = strdup (pError);
LOG ("Ret - rc=%d,Error=%s", rc, *ppError);
return rc;
}
static int AewfGetInfofileContent (void *pHandle, const char **ppInfoBuf)
{
t_pAewf pAewf = (t_pAewf) pHandle;
char *pInfo;
LOG ("Called");
pInfo = strdup (pAewf->pInfo);
if (pInfo == NULL)
return AEWF_MEMALLOC_FAILED;
*ppInfoBuf = pInfo;
LOG ("Ret - %d bytes of info", strlen(pInfo)+1);
return AEWF_OK;
}
static const char* AewfGetErrorMessage (int ErrNum)
{
const char *pMsg;
#define ADD_ERR(AewfErrCode) \
case AewfErrCode: pMsg = #AewfErrCode; \
break;
switch (ErrNum)
{
ADD_ERR (AEWF_OK)
ADD_ERR (AEWF_MEMALLOC_FAILED)
ADD_ERR (AEWF_READ_BEYOND_END_OF_IMAGE)
ADD_ERR (AEWF_OPTIONS_ERROR)
+ ADD_ERR (AEWF_CANNOT_OPEN_LOGFILE)
ADD_ERR (AEWF_FILE_OPEN_FAILED)
ADD_ERR (AEWF_FILE_CLOSE_FAILED)
ADD_ERR (AEWF_FILE_SEEK_FAILED)
ADD_ERR (AEWF_FILE_READ_FAILED)
ADD_ERR (AEWF_READFILE_BAD_MEM)
ADD_ERR (AEWF_INVALID_SEGMENT_NUMBER)
ADD_ERR (AEWF_WRONG_SEGMENT_FILE_COUNT)
ADD_ERR (AEWF_VOLUME_MUST_PRECEDE_TABLES)
ADD_ERR (AEWF_SECTORS_MUST_PRECEDE_TABLES)
ADD_ERR (AEWF_WRONG_CHUNK_COUNT)
ADD_ERR (AEWF_CHUNK_NOT_FOUND)
ADD_ERR (AEWF_VOLUME_MISSING)
ADD_ERR (AEWF_ERROR_EWF_TABLE_NOT_READY)
ADD_ERR (AEWF_ERROR_EWF_SEGMENT_NOT_READY)
ADD_ERR (AEWF_CHUNK_TOO_BIG)
ADD_ERR (AEWF_UNCOMPRESS_FAILED)
ADD_ERR (AEWF_BAD_UNCOMPRESSED_LENGTH)
ADD_ERR (AEWF_CHUNK_CRC_ERROR)
ADD_ERR (AEWF_ERROR_IN_CHUNK_NUMBER)
ADD_ERR (AEWF_VASPRINTF_FAILED)
ADD_ERR (AEWF_UNCOMPRESS_HEADER_FAILED)
ADD_ERR (AEWF_ASPRINTF_FAILED)
- ADD_ERR (AEWF_CANNOT_OPEN_LOGFILE)
- ADD_ERR (AEWF_ERROR_EIO_END)
+ ADD_ERR (AEWF_CHUNK_LENGTH_ZERO)
+ ADD_ERR (AEWF_NEGATIVE_SEEK)
default:
pMsg = "Unknown error";
}
#undef ARR_ERR
return pMsg;
}
static int AewfFreeBuffer (void *pBuf)
{
free (pBuf);
return AEWF_OK;
}
// ------------------------------------
// LibXmount_Input API implementation
// ------------------------------------
uint8_t LibXmount_Input_GetApiVersion ()
{
return LIBXMOUNT_INPUT_API_VERSION;
}
const char* LibXmount_Input_GetSupportedFormats ()
{
return "aewf\0\0"; //lint !e840 Use of nul character in a string literal
}
void LibXmount_Input_GetFunctions (ts_LibXmountInputFunctions *pFunctions)
{
pFunctions->CreateHandle = &AewfCreateHandle;
pFunctions->DestroyHandle = &AewfDestroyHandle;
pFunctions->Open = &AewfOpen;
pFunctions->Close = &AewfClose;
pFunctions->Size = &AewfSize;
pFunctions->Read = &AewfRead;
pFunctions->OptionsHelp = &AewfOptionsHelp;
pFunctions->OptionsParse = &AewfOptionsParse;
pFunctions->GetInfofileContent = &AewfGetInfofileContent;
pFunctions->GetErrorMessage = &AewfGetErrorMessage;
pFunctions->FreeBuffer = &AewfFreeBuffer;
}
// -----------------------------------------------------
// Small main routine for testing
// It converts an EWF file into dd
// -----------------------------------------------------
#ifdef AEWF_STANDALONE
#define PRINT_ERROR_AND_EXIT(...) \
{ \
printf (__VA_ARGS__); \
exit (1); \
}
int ParseOptions (t_pAewf pAewf, char *pOptions)
{
pts_LibXmountOptions pOptionArr;
pts_LibXmountOptions *ppOptionArr;
int OptionCount;
char *pSep;
char *pEqual;
char *pTmp;
const char *pError;
char *pOpt;
int rc;
if (pOptions == NULL)
return AEWF_OK;
if (*pOptions == '\0')
return AEWF_OK;
if (*pOptions == ',')
return AEWF_OPTIONS_ERROR;
if (pOptions[strlen(pOptions)-1] == ',')
return AEWF_OPTIONS_ERROR;
pOpt = strdup (pOptions);
// Count number of comma separated options
OptionCount = 1;
pTmp = pOpt;
while ((pTmp = strchr (pTmp, ',')) != NULL)
{
OptionCount++;
pTmp++;
}
// Create and fill option array
pOptionArr = (pts_LibXmountOptions) malloc (OptionCount * sizeof(ts_LibXmountOptions));
if (pOptionArr == NULL)
PRINT_ERROR_AND_EXIT ("Cannot allocate pOptionArr");
memset (pOptionArr, 0, OptionCount * sizeof(ts_LibXmountOptions));
pTmp = pOpt;
for (int i=0; i<OptionCount; i++)
{
pOptionArr[i].p_key = pTmp;
pSep = strchr (pTmp, ',');
if (pSep)
*pSep ='\0';
pEqual = strchr (pTmp, '=');
if (pEqual)
{
*pEqual = '\0';
pOptionArr[i].p_value = pEqual+1;
}
if (pSep != NULL)
pTmp = pSep+1;
}
// Create pointer array and call AEWF parse function
ppOptionArr = (pts_LibXmountOptions *)malloc (OptionCount*sizeof (pts_LibXmountOptions));
if (ppOptionArr == NULL)
PRINT_ERROR_AND_EXIT ("Cannot allocate ppOptionArr");
for (int i=0; i<OptionCount; i++)
ppOptionArr[i] = &pOptionArr[i];
rc = AewfOptionsParse ((void*) pAewf, OptionCount, ppOptionArr, &pError);
free (ppOptionArr);
free ( pOptionArr);
free ( pOpt);
if (pError)
PRINT_ERROR_AND_EXIT ("Error while setting options: %s", pError);
CHK (rc)
return AEWF_OK;
}
int main(int argc, const char *argv[])
{
t_pAewf pAewf=NULL;
uint64_t TotalSize;
uint64_t Remaining;
uint64_t ToRead;
uint64_t Read;
uint64_t Pos;
unsigned int BuffSize = 13*65536; // A multiple of chunk size for good performance
char Buff[BuffSize];
FILE *pFile;
int Percent;
int PercentOld;
int rc;
+ int Errno;
char *pOptions = NULL;
const char *pHelp;
const char *pInfoBuff;
#ifdef CREATE_REVERSE_FILE
FILE *pFileRev;
uint64_t PosRev;
#ifdef REVERSE_FILE_USES_SEPARATE_HANDLE
t_pAewf pAewfRev;
#else
#define pAewfRev pAewf
#endif
#endif
setbuf(stdout, NULL);
setbuf(stderr, NULL);
(void) setlocale (LC_ALL, "");
printf ("EWF to DD converter - result file is named dd\n");
printf (" Result file is named dd");
#ifdef CREATE_REVERSE_FILE
printf ("; Also creates a backwards read file named rev");
#ifdef REVERSE_FILE_USES_SEPARATE_HANDLE
printf ("; Uses separate AEWF handle for reverse file");
#else
printf ("; Uses the same AEWF handle for reverse file");
#endif
#endif
printf ("\n");
if (argc < 2)
{
(void) AewfOptionsHelp (&pHelp);
printf ("Usage: %s <EWF segment file 1> <EWF segment file 2> <...> [-comma_separated_options]\n", argv[0]);
printf ("Possible options:\n%s\n", pHelp);
printf ("The output file will be named dd.\n");
+ CHK (AewfFreeBuffer ((void*) pHelp))
exit (1);
}
if (argv[argc-1][0] == '-')
{
pOptions = strdup (&(argv[argc-1][1]));
argc--;
}
- rc = AewfCreateHandle ((void**) &pAewf, "aewf");
+ rc = AewfCreateHandle ((void**) &pAewf, "aewf", LOG_STDOUT);
if (rc != AEWF_OK)
PRINT_ERROR_AND_EXIT ("Cannot create handle, rc=%d\n", rc)
- CHK (AewfLogStdout (pAewf, LOG_STDOUT))
-
if (pOptions)
CHK (ParseOptions(pAewf, pOptions))
rc = AewfOpen (pAewf, &argv[1], argc-1);
if (rc != AEWF_OK)
PRINT_ERROR_AND_EXIT ("Cannot open EWF files, rc=%d\n", rc)
#if defined(CREATE_REVERSE_FILE) && defined(REVERSE_FILE_USES_SEPARATE_HANDLE)
- rc = AewfCreateHandle ((void**) &pAewfRev, "aewf");
+ rc = AewfCreateHandle ((void**) &pAewfRev, "aewf", LOG_STDOUT);
if (rc != AEWF_OK)
PRINT_ERROR_AND_EXIT ("Cannot create reverse handle, rc=%d\n", rc)
- CHK (AewfLogStdout (pAewfRev, LOG_STDOUT))
if (pOptions)
CHK (ParseOptions (pAewfRev, pOptions))
rc = AewfOpen (pAewfRev, &argv[1], argc-1);
if (rc != AEWF_OK)
PRINT_ERROR_AND_EXIT ("Cannot open EWF files, rc=%d\n", rc)
#endif
CHK (AewfGetInfofileContent ((void*) pAewf, &pInfoBuff))
if (pInfoBuff)
printf ("Contents of info buffer:\n%s\n", pInfoBuff);
+ CHK (AewfFreeBuffer ((void*) pInfoBuff))
CHK (AewfSize (pAewf, &TotalSize))
printf ("Total size: %" PRIu64 " bytes\n", TotalSize);
pFile = fopen ("dd", "w");
if (pFile == NULL)
PRINT_ERROR_AND_EXIT("Cannot open destination file\n");
#ifdef CREATE_REVERSE_FILE
pFileRev = fopen ("rev", "w");
if (pFileRev == NULL)
PRINT_ERROR_AND_EXIT("Cannot open reverse destination file\n");
PosRev = TotalSize;
#endif
Remaining = TotalSize;
Pos = 0;
PercentOld = -1;
+ Errno = 0;
while (Remaining)
{
// LOG ("Pos %" PRIu64 " -- Remaining %" PRIu64 " ", Pos, Remaining);
ToRead = GETMIN (Remaining, BuffSize);
- rc = AewfRead ((void*) pAewf, &Buff[0], Pos, ToRead, &Read);
- if (rc != AEWF_OK)
- PRINT_ERROR_AND_EXIT("Error %d while calling AewfRead\n", rc);
+
+ rc = AewfRead ((void*) pAewf, &Buff[0], Pos, ToRead, &Read, &Errno);
+ if ((rc != AEWF_OK) || (Errno != 0))
+ PRINT_ERROR_AND_EXIT("Error %d while calling AewfRead (Errno %d)\n", rc, Errno);
if (Read != ToRead)
PRINT_ERROR_AND_EXIT("Only %" PRIu64 " out of %" PRIu64 " bytes read\n", Read, ToRead);
if (fwrite (Buff, Read, 1, pFile) != 1)
PRINT_ERROR_AND_EXIT("Could not write to destination file\n");
Remaining -= ToRead;
Pos += ToRead;
#ifdef CREATE_REVERSE_FILE
PosRev -= ToRead;
- rc = AewfRead ((void*) pAewfRev, &Buff[0], PosRev, ToRead, &Read);
- if (rc != AEWF_OK)
- PRINT_ERROR_AND_EXIT("Error %d while reverse calling AewfRead\n", rc);
+ rc = AewfRead ((void*) pAewfRev, &Buff[0], PosRev, ToRead, &Read, &Errno);
+ if ((rc != AEWF_OK) || (Errno != 0))
+ PRINT_ERROR_AND_EXIT("Error %d while reverse calling AewfRead (Errno %d)\n", rc, Errno);
if (Read != ToRead)
PRINT_ERROR_AND_EXIT("Only %" PRIu64 " out of %" PRIu64 " bytes read from rev file\n", Read, ToRead);
if (fseeko (pFileRev, PosRev, SEEK_SET))
return AEWF_FILE_SEEK_FAILED;
if (fwrite (Buff, Read, 1, pFileRev) != 1)
PRINT_ERROR_AND_EXIT("Could not write to reverse destination file\n");
#endif
Percent = (100*Pos) / TotalSize;
if (Percent != PercentOld)
{
printf ("\r%d%% done...", Percent);
PercentOld = Percent;
}
}
if (AewfClose (pAewf))
PRINT_ERROR_AND_EXIT("Error while closing AEWF files\n");
if (AewfDestroyHandle ((void**)&pAewf))
PRINT_ERROR_AND_EXIT("Error while destroying AEWF handle\n");
if (fclose (pFile))
PRINT_ERROR_AND_EXIT ("Error while closing destination file\n");
#ifdef CREATE_REVERSE_FILE
#ifdef REVERSE_FILE_USES_SEPARATE_HANDLE
if (AewfClose (pAewfRev))
PRINT_ERROR_AND_EXIT("Error while closing reverse AEWF files\n");
if (AewfDestroyHandle ((void**)&pAewfRev))
PRINT_ERROR_AND_EXIT("Error while destroying reverse AEWF handle\n");
#endif
if (fclose (pFileRev))
PRINT_ERROR_AND_EXIT ("Error while closing reverse destination file\n");
#endif
printf ("\n");
return 0;
}
#endif
diff --git a/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h
index 65f7f34..33818cb 100644
--- a/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h
+++ b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h
@@ -1,246 +1,248 @@
/*******************************************************************************
* xmount Copyright (c) 2008-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* This module has been written by Guy Voncken. It contains the functions for *
* accessing EWF images created by Guymager and others. *
* *
* 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/>. *
*******************************************************************************/
// Please don't touch source code formatting!
#ifndef AEWF_H
#define AEWF_H
typedef struct _t_Aewf *t_pAewf;
// ----------------------
// Constant definitions
// ----------------------
#define GETMAX(a,b) ((a)>(b)?(a):(b))
#define GETMIN(a,b) ((a)<(b)?(a):(b))
#define FALSE 0
#define TRUE 1
// ---------------------
// Types and strutures
// ---------------------
typedef struct
{
unsigned char Signature[8];
unsigned char StartOfFields; // 0x01;
unsigned short int SegmentNumber;
unsigned short int EndOfFields; // 0x0000
} __attribute__ ((packed)) t_AewfFileHeader, *t_AewfpFileHeader;
typedef struct
{
unsigned char Type[16];
uint64_t OffsetNextSection;
uint64_t Size;
unsigned char Padding[40];
uint32_t Checksum;
char Data[]; //lint !e1501 data member has zero size
} __attribute__ ((packed)) t_AewfSection, *t_pAewfSection;
typedef struct
{
unsigned char MediaType;
unsigned char Unknown1[3]; // contains 0x00
uint32_t ChunkCount;
uint32_t SectorsPerChunk;
uint32_t BytesPerSector;
uint64_t SectorCount;
uint32_t CHS_Cylinders;
uint32_t CHS_Heads;
uint32_t CHS_Sectors;
unsigned char MediaFlags;
unsigned char Unknown2[3]; // contains 0x00
uint32_t PalmVolumeStartSector;
unsigned char Padding1[4]; // contains 0x00
uint32_t SmartLogsStartSector;
unsigned char CompressionLevel;
unsigned char Unknown3[3]; // contains 0x00
uint32_t ErrorBlockSize;
unsigned char Unknown4[4];
unsigned char AcquirySystemGUID[16];
unsigned char Padding2[963];
unsigned char Reserved [5];
uint32_t Checksum;
} __attribute__ ((packed)) t_AewfSectionVolume, *t_pAewfSectionVolume;
typedef struct
{
uint32_t ChunkCount;
unsigned char Padding1 [4];
uint64_t TableBaseOffset;
unsigned char Padding2 [4];
uint32_t Checksum;
uint32_t OffsetArray[]; //lint !e1501 data member has zero size
} __attribute__ ((packed)) t_AewfSectionTable, *t_pAewfSectionTable;
const uint32_t AEWF_COMPRESSED = 0x80000000;
typedef struct
{
uint32_t FirstSector;
uint32_t NumberOfSectors;
} __attribute__ ((packed)) t_AewfSectionErrorEntry, *t_pAewfSectionErrorEntry;
typedef struct
{
uint32_t NumberOfErrors;
unsigned char Padding[512];
uint32_t Checksum;
t_AewfSectionErrorEntry ErrorArr[0]; //lint !e1501 data member 'ErrorArr' has zero size
uint32_t ChecksumArr;
} __attribute__ ((packed)) t_AewfSectionError, *t_pAewfSectionError;
typedef struct
{
unsigned char MD5[16];
unsigned char Unknown[16];
uint32_t Checksum;
} __attribute__ ((packed)) t_AewfSectionHash, *t_pAewfSectionHash;
typedef struct
{
char *pName;
unsigned Number;
FILE *pFile; // NULL if file is not opened (never read or kicked out form cache)
time_t LastUsed;
} t_Segment, *t_pSegment;
typedef struct
{
uint64_t Nr; // The table's position in the pAewf->pTableArr, for debug output only
uint64_t ChunkFrom; // Number of the chunk referred to by the first entry of this table (very first chunk has number 0)
uint64_t ChunkTo; // Number of the chunk referred to by the last entry of this table
t_pSegment pSegment; // The file segment where the table is located
uint64_t Offset; // The offset of the table inside the segment file (start of t_AewfSectionTable, not of the preceding t_AewfSection)
unsigned long Size; // The length of the table (same as allocated length for pEwfTable)
uint32_t ChunkCount; // The number of chunk; this is the same as pTableData->Chunkcount, however, pTableData might not be available (NULL)
uint32_t SectionSectorsSize; // Silly EWF format has no clean way of knowing size of the last (possibly compressed) chunk of a table
time_t LastUsed; // Last usage of this table, for cache management
t_pAewfSectionTable pEwfTable; // Contains the original EWF table section or NULL, if never read or kicked out from cache
} t_Table, *t_pTable;
-#define AEWF_NONE ULONG_LONG_MAX
+#define AEWF_NONE UINT64_MAX
+
typedef struct _t_Aewf
{
- t_pSegment pSegmentArr; // Array of all segment files (in correct order)
- t_pTable pTableArr; // Array of all chunk offset tables found in the segment files (in correct order)
- uint64_t Segments;
- uint64_t Tables;
- uint64_t Chunks; // Total number of chunks in all tables
- uint64_t TableCache; // Current amount RAM used by tables, in bytes
- uint64_t OpenSegments; // Current number of open segment files
- uint64_t SectorSize;
- uint64_t Sectors;
- uint64_t ChunkSize;
- uint64_t ImageSize; // Equals to Sectors * SectorSize
- char *pChunkBuffCompressed;
- char *pChunkBuffUncompressed;
- uint64_t ChunkBuffUncompressedDataLen; // This normally always is equal to the chunk size (32K), except maybe for the last chunk, if the image's total size is not a multiple of the chunk size
- uint32_t ChunkBuffSize;
- uint64_t ChunkInBuff; // Chunk currently residing in pChunkBuffUncompressed (AEWF_NONE if none)
- char *pErrorText; // Used for assembling error text during option parsing
- time_t LastStatsUpdate;
- char *pInfo;
+ t_pSegment pSegmentArr; // Array of all segment files (in correct order)
+ t_pTable pTableArr; // Array of all chunk offset tables found in the segment files (in correct order)
+ uint64_t Segments;
+ uint64_t Tables;
+ uint64_t Chunks; // Total number of chunks in all tables
+ uint64_t TableCache; // Current amount RAM used by tables, in bytes
+ uint64_t OpenSegments; // Current number of open segment files
+ uint64_t SectorSize;
+ uint64_t Sectors;
+ uint64_t ChunkSize;
+ uint64_t ImageSize; // Equals to Sectors * SectorSize
+ char *pChunkBuffCompressed;
+ char *pChunkBuffUncompressed;
+ uint64_t ChunkBuffUncompressedDataLen; // This normally always is equal to the chunk size (32K), except maybe for the last chunk, if the image's total size is not a multiple of the chunk size
+ uint32_t ChunkBuffSize;
+ uint64_t ChunkInBuff; // Chunk currently residing in pChunkBuffUncompressed (AEWF_NONE if none)
+ char *pErrorText; // Used for assembling error text during option parsing
+ time_t LastStatsUpdate;
+ char *pInfo;
// Statistics
uint64_t SegmentCacheHits;
uint64_t SegmentCacheMisses;
uint64_t TableCacheHits;
uint64_t TableCacheMisses;
uint64_t ChunkCacheHits;
uint64_t ChunkCacheMisses;
uint64_t ReadOperations; // How many times did xmount call the function AewfRead
uint64_t DataReadFromImage; // The data (in bytes) read from the image
uint64_t DataReadFromImageRaw; // The same data (in bytes), after uncompression (if any)
uint64_t DataRequestedByCaller; // How much data was given back to the caller
uint64_t TablesReadFromImage; // The overhead of the table read operations (in bytes)
uint64_t ChunksRead;
uint64_t BytesRead;
uint64_t Errors;
int LastError;
// Options
uint64_t MaxTableCache; // Max. amount of bytes in pTableArr[x].pTableData, in bytes
uint64_t MaxOpenSegments; // Max. number of open files in pSegmentArr
char *pStatsFilename; // Statistics file
uint64_t StatsRefresh; // The time in seconds between update of the stats file
char *pLogFilename;
uint8_t LogStdout;
} t_Aewf;
// ----------------
// Error codes
// ----------------
// AEWF Error codes are automatically mapped to errno codes by means of the groups
// below. AEWF uses these errno codes:
// ENOMEM memory allocation errors
// EINVAL wrong parameter(s) passed to an AEWF function
// EIO all others: AEWF function errors, EWF image errors
enum
{
AEWF_OK = 0,
AEWF_ERROR_ENOMEM_START=1000,
AEWF_MEMALLOC_FAILED,
AEWF_ERROR_ENOMEM_END,
AEWF_ERROR_EINVAL_START=2000,
AEWF_READ_BEYOND_END_OF_IMAGE,
AEWF_OPTIONS_ERROR,
AEWF_CANNOT_OPEN_LOGFILE,
AEWF_ERROR_EINVAL_END,
AEWF_ERROR_EIO_START=3000,
AEWF_FILE_OPEN_FAILED,
AEWF_FILE_CLOSE_FAILED,
AEWF_FILE_SEEK_FAILED,
AEWF_FILE_READ_FAILED,
AEWF_READFILE_BAD_MEM,
AEWF_INVALID_SEGMENT_NUMBER,
AEWF_WRONG_SEGMENT_FILE_COUNT,
AEWF_VOLUME_MUST_PRECEDE_TABLES,
AEWF_SECTORS_MUST_PRECEDE_TABLES,
AEWF_WRONG_CHUNK_COUNT,
AEWF_CHUNK_NOT_FOUND,
AEWF_VOLUME_MISSING,
AEWF_ERROR_EWF_TABLE_NOT_READY,
AEWF_ERROR_EWF_SEGMENT_NOT_READY,
AEWF_CHUNK_TOO_BIG,
AEWF_UNCOMPRESS_FAILED,
AEWF_BAD_UNCOMPRESSED_LENGTH,
AEWF_CHUNK_CRC_ERROR,
AEWF_ERROR_IN_CHUNK_NUMBER,
AEWF_VASPRINTF_FAILED,
AEWF_UNCOMPRESS_HEADER_FAILED,
AEWF_ASPRINTF_FAILED,
AEWF_CHUNK_LENGTH_ZERO,
+ AEWF_NEGATIVE_SEEK,
AEWF_ERROR_EIO_END,
};
#endif

File Metadata

Mime Type
text/x-diff
Expires
Tue, Dec 24, 3:13 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1177003
Default Alt Text
(127 KB)

Event Timeline