diff --git a/trunk/cmake_modules/FindLibZ.cmake b/trunk/cmake_modules/FindLibZ.cmake new file mode 100644 index 0000000..634b2d7 --- /dev/null +++ b/trunk/cmake_modules/FindLibZ.cmake @@ -0,0 +1,18 @@ +find_package(PkgConfig) +pkg_check_modules(PC_LIBZ QUIET zlib) +set(LIBZ_DEFINITIONS ${PC_LIBZ_CFLAGS_OTHER}) + +find_path(LIBZ_INCLUDE_DIR zlib.h + HINTS ${PC_LIBZ_INCLUDEDIR} ${PC_LIBZ_INCLUDE_DIRS} + PATH_SUFFIXES zlib) + +find_library(LIBZ_LIBRARY NAMES z libz + HINTS ${PC_LIBZ_LIBDIR} ${PC_LIBZ_LIBRARY_DIRS} ) + +set(LIBZ_LIBRARIES ${LIBZ_LIBRARY}) +set(LIBZ_INCLUDE_DIRS ${LIBZ_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibZ DEFAULT_MSG LIBZ_LIBRARY LIBZ_INCLUDE_DIR) + +mark_as_advanced(LIBZ_INCLUDE_DIR LIBZ_LIBRARY) diff --git a/trunk/libxmount_input/CMakeLists.txt b/trunk/libxmount_input/CMakeLists.txt index a84c410..b99bd1e 100644 --- a/trunk/libxmount_input/CMakeLists.txt +++ b/trunk/libxmount_input/CMakeLists.txt @@ -1,10 +1,18 @@ +add_subdirectory(libxmount_input_dd) + find_package(LibEWF) if(LIBEWF_FOUND) add_subdirectory(libxmount_input_ewf) endif(LIBEWF_FOUND) #find_package(LibAFF) #if(LIBAFF_FOUND) # add_subdirectory(libxmount_input_aff) #endif(LIBAFF_FOUND) +find_package(LibZ) +if(LIBZ_FOUND) + add_subdirectory(libxmount_input_aewf) + add_subdirectory(libxmount_input_aaff) +endif(LIBZ_FOUND) + diff --git a/trunk/libxmount_input/libxmount_input.h b/trunk/libxmount_input/libxmount_input.h index dd77370..e5dbc5e 100644 --- a/trunk/libxmount_input/libxmount_input.h +++ b/trunk/libxmount_input/libxmount_input.h @@ -1,132 +1,133 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * xmount is a small tool to "fuse mount" various image formats and enable * * virtual write access. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef LIBXMOUNT_INPUT_H #define LIBXMOUNT_INPUT_H #define LIBXMOUNT_INPUT_API_VERSION 1 -#include +#include // For int*_t and uint*_t +#include // For PRI* //! Structure containing pointers to the lib's functions typedef struct s_LibXmountInputFunctions { /*! * Function to open input image * * \param pp_handle Pointer to store handle of opened image to * \param pp_filename_arr Array containing all specified input images * \param filename_arr_len Length of pp_filename_arr * \return 0 on success or error code */ int (*Open)(void **pp_handle, const char **pp_filename_arr, uint64_t filename_arr_len); /*! * Function to get the input image's size * * \param p_handle Handle to the opened image * \param p_size Pointer to store input image's size to * \return 0 on success or error code */ int (*Size)(void *p_handle, uint64_t *p_size); /*! * Function to read data from input image * * \param p_handle Handle to the opened image * \param offset Position at which to start reading * \param p_buf Buffer to store read data to * \param count Amount of bytes to read * \return 0 on success or error code */ int (*Read)(void *p_handle, uint64_t offset, char *p_buf, uint32_t count); /*! * Function to close an opened input image * * \param pp_handle Pointer to the handle of the opened image * \return 0 on success or error code */ int (*Close)(void **pp_handle); /*! * Function to return a string containing help messages for any supported * lib-specific options * * \param pp_help Pointer to a string to store null-terminated help text * \return 0 on success or error code */ int (*OptionsHelp)(const char **pp_help); /*! * Function to parse any lib-specific options * * \param p_handle Handle to the opened image * \param p_options String with specified options * \param pp_error Pointer to a string with error message * \return 0 on success or error code and error message */ int (*OptionsParse)(void *p_handle, char *p_options, char **pp_error); /*! * Function to get content to add to the info file * * \param p_handle Handle to the opened image * \param pp_info_buf Pointer to store the null-terminated content * \return 0 on success or error code */ int (*GetInfofileContent)(void *p_handle, const char **pp_info_buf); /*! * Function to free buffers that were allocated by lib * * \param p_buf Buffer to free */ void (*FreeBuffer)(void *p_buf); } ts_LibXmountInputFunctions, *pts_LibXmountInputFunctions; //! Get library API version /*! * \param p_ver Supported version */ uint8_t LibXmount_Input_GetApiVersion(); typedef uint8_t (*t_LibXmount_Input_GetApiVersion)(); //! Get a list of supported formats /*! * Gets a list of supported input image formats. These are the strings * specified with xmount's --in command line option. * * \param ppp_arr Array containing supported format strings * \return Length of ppp_arr */ const char* LibXmount_Input_GetSupportedFormats(); typedef const char* (*t_LibXmount_Input_GetSupportedFormats)(); //! Get the lib's s_LibXmountInputFunctions structure /*! * \param pp_functions Functions */ void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions); typedef void (*t_LibXmount_Input_GetFunctions)(ts_LibXmountInputFunctions*); #endif // LIBXMOUNT_INPUT_H diff --git a/trunk/libxmount_input/libxmount_input_aaff/CMakeLists.txt b/trunk/libxmount_input/libxmount_input_aaff/CMakeLists.txt new file mode 100644 index 0000000..5b82e5a --- /dev/null +++ b/trunk/libxmount_input/libxmount_input_aaff/CMakeLists.txt @@ -0,0 +1,8 @@ +project(libxmount_input_aaff) + +add_library(xmount_input_aaff SHARED libxmount_input_aaff.c) +include_directories(${LIBZ_INCLUDE_DIRS}) +target_link_libraries(xmount_input_aaff ${LIBZ_LIBRARIES}) + +install(TARGETS xmount_input_aaff DESTINATION lib/xmount) + 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 a801e74..f94e88f 100644 --- a/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c +++ b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.c @@ -1,741 +1,713 @@ /******************************************************************************* * xmount Copyright (c) 2008,2009, 2010, 2011, 2012 * * by Gillen Daniel * * * * 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 . * *******************************************************************************/ #include #include #include #include #include #include #include #include -#include "aaff.h" - -// ---------------------- -// Constant definitions -// ---------------------- +#include "../libxmount_input.h" //#define AAFF_DEBUG +#include "libxmount_input_aaff.h" -#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)) - -// ----------------- -// 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; +/******************************************************************************* + * Forward declarations + ******************************************************************************/ +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); +int AaffOptionsHelp(const char **pp_help); +int AaffOptionsParse(void *p_handle, + char *p_options, + char **pp_error); +int AaffGetInfofileContent(void *p_handle, + const char **pp_info_buf); +void AaffFreeBuffer(void *p_buf); -// Between header and footer lie the segment name and the data +/******************************************************************************* + * LibXmount_Input API implementation + ******************************************************************************/ +/* + * LibXmount_Input_GetApiVersion + */ +uint8_t LibXmount_Input_GetApiVersion() { + return LIBXMOUNT_INPUT_API_VERSION; +} -typedef struct -{ - char Magic[4]; - unsigned int SegmentLen; -} __attribute__ ((packed)) t_AffSegmentFooter; +/* + * LibXmount_Input_GetSupportedFormats + */ +const char* LibXmount_Input_GetSupportedFormats() { + return "aaff\0\0"; +} -const int AaffInfoBuffLen = 1024*1024; +/* + * LibXmount_Input_GetFunctions + */ +void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions) { + p_functions->Open=&AaffOpen; + p_functions->Size=&AaffSize; + p_functions->Read=&AaffRead; + p_functions->Close=&AaffClose; + p_functions->OptionsHelp=&AaffOptionsHelp; + p_functions->OptionsParse=&AaffOptionsParse; + p_functions->GetInfofileContent=&AaffGetInfofileContent; + p_functions->FreeBuffer=&AaffFreeBuffer; +} -typedef struct _t_Aaff -{ - char *pFilename; - FILE *pFile; - - char *pLibVersion; // AFF File Header info - char *pFileType; - unsigned int PageSize; - unsigned int SectorSize; - unsigned long long Sectors; - unsigned long long ImageSize; - unsigned long long TotalPages; - - char *pNameBuff; // Buffers - unsigned char *pDataBuff; - unsigned int NameBuffLen; - unsigned int DataBuffLen; - - unsigned long long CurrentPage; - unsigned 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; - - unsigned long long *pPageSeekArr; - unsigned long long PageSeekArrLen; - unsigned long long Interleave; // The number of pages lying between 2 entries in the PageSeekArr -} 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 +/******************************************************************************* + * Private + ******************************************************************************/ // --------------------------- // Internal static functions // --------------------------- static int AaffCreateHandle (t_pAaff *ppAaff) { t_pAaff pAaff; pAaff = (t_pAaff) malloc (sizeof(t_Aaff)); if (pAaff == NULL) return AAFF_MEMALLOC_FAILED; memset (pAaff, 0, sizeof(t_Aaff)); *ppAaff = pAaff; return AAFF_OK; } static int AaffDestroyHandle (t_pAaff *ppAaff) { t_pAaff pAaff = *ppAaff; 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); *ppAaff = NULL; return AAFF_OK; } -unsigned long long AaffU64 (unsigned char *pData) +uint64_t AaffU64 (char *pData) { - unsigned long long Val=0; - int i; + 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, unsigned long long *pPageNumber) +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 unsigned long long AaffGetCurrentSeekPos (t_Aaff *pAaff) +static inline uint64_t AaffGetCurrentSeekPos (t_Aaff *pAaff) { return ftello (pAaff->pFile); } -static inline unsigned long long AaffSetCurrentSeekPos (t_Aaff *pAaff, unsigned long long Val, int Whence) +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, unsigned int DataLen) +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, unsigned int *pCurrentLen, unsigned int NewLen) +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, unsigned int *pArg, unsigned char **ppData, unsigned int *pDataLen) +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, unsigned long long SearchPage, unsigned long long *pFoundPage, unsigned char **ppData, unsigned int *pDataLen) +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%llu", SearchPage); + 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 (pAaff->pPageBuff, &ZLen, pAaff->pDataBuff, Header.DataLen); // uncompress into 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, unsigned long long Page, unsigned char **ppBuffer, unsigned int *pLen) +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 // -------------------------------------------- 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 { - long long Entry; + 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 // -------------------------------------------- - unsigned long long Seek; - unsigned long long FoundPage; + uint64_t Seek; + uint64_t FoundPage; int rc; - DEBUG_PRINTF ("\nSearching for page %llu, MaxHops=%d -- ", Page, MaxHops); + DEBUG_PRINTF ("\nSearching for page %" PRIu64 ", MaxHops=%d -- ", Page, MaxHops); while (MaxHops--) { Seek = AaffGetCurrentSeekPos (pAaff); rc = AaffReadSegmentPage (pAaff, Page, &FoundPage, ppBuffer, pLen); - DEBUG_PRINTF (" %llu (%d)", FoundPage, rc); + DEBUG_PRINTF (" %" 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) return AAFF_PAGE_NOT_FOUND; return AAFF_OK; } // --------------- // API functions // --------------- -int AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long MaxPageArrMem) +/* + * AaffOpen + */ +int AaffOpen(void **pp_handle, + const char **pp_filename_arr, + uint64_t filename_arr_len) { - t_pAaff pAaff; - char Signature[strlen(AFF_HEADER)+1]; - unsigned long long Seek; - - *ppAaff = NULL; - CHK (AaffCreateHandle (&pAaff)) - - pAaff->pFilename = strdup (pFilename); - pAaff->pFile = fopen (pFilename, "r"); - if (pAaff->pFile == NULL) - { - AaffDestroyHandle (&pAaff); - return AAFF_FILE_OPEN_FAILED; - } - - // Check signature - // --------------- - CHK (AaffReadFile (pAaff, &Signature, sizeof(Signature))) - if (memcmp (Signature, AFF_HEADER, sizeof(Signature)) != 0) - { - (void) AaffClose (&pAaff); - return AAFF_INVALID_SIGNATURE; - } - - // Read header segments - // -------------------- - char *pName; - unsigned int Arg; - unsigned char *pData; - unsigned int 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); - for (Seg=0; SegPageSize = 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; ipInfoBuffConst[Pos]), REM,"%-25s %s", pName, HexStr); - if (ipInfoBuffConst[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 (&pAaff); - return AAFF_TOO_MANY_HEADER_SEGEMENTS; - } - - if (strstr (pAaff->pLibVersion, "Guymager") == NULL) - { - (void) AaffClose (&pAaff); - return AAFF_NOT_CREATED_BY_GUYMAGER; - } - - // Prepare page seek array - // ----------------------- - unsigned long long MaxEntries; - int ArrBytes; - - pAaff->TotalPages = pAaff->ImageSize / pAaff->PageSize; - if (pAaff->ImageSize % pAaff->PageSize) - pAaff->TotalPages++; - - if (MaxPageArrMem) - MaxEntries = (MaxPageArrMem / sizeof (unsigned long long *)) + 1; // +1 in order not to risk a result of 0 - 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(unsigned long long *); - pAaff->pPageSeekArr = (unsigned long long *)malloc (ArrBytes); - memset (pAaff->pPageSeekArr, 0, ArrBytes); - CHK (AaffPageNumberFromSegmentName (pName, &pAaff->CurrentPage)); - if (pAaff->CurrentPage != 0) - { - (void) AaffClose (&pAaff); - return AAFF_UNEXPECTED_PAGE_NUMBER; - } - pAaff->pPageSeekArr[0] = Seek; - - // Alloc Buffers - // ------------- - pAaff->pPageBuff = malloc (pAaff->PageSize); - pAaff->CurrentPage = AAFF_CURRENTPAGE_NOTSET; - - *ppAaff = pAaff; - - return AAFF_OK; + t_pAaff pAaff; + 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; + } + + *pp_handle=NULL; + CHK(AaffCreateHandle(&pAaff)) + + pAaff->pFilename=strdup(pp_filename_arr[0]); + pAaff->pFile=fopen(pp_filename_arr[0],"r"); + if(pAaff->pFile==NULL) { + AaffDestroyHandle(&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; SegPageSize=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; ipInfoBuffConst[Pos]), REM,"%-25s %s", pName, HexStr); + if (ipInfoBuffConst[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; + + *pp_handle=(void*)pAaff; + + return AAFF_OK; } -int AaffClose (t_pAaff *ppAaff) -{ - int rc = AAFF_OK; - - if (fclose ((*ppAaff)->pFile)) - rc = AAFF_CANNOT_CLOSE_FILE; +/* + * AaffClose + */ +int AaffClose(void **pp_handle) { + int rc=AAFF_OK; - CHK (AaffDestroyHandle (ppAaff)) + if(fclose((*(t_pAaff*)pp_handle)->pFile)) rc=AAFF_CANNOT_CLOSE_FILE; + CHK(AaffDestroyHandle((t_pAaff*)pp_handle)) - return rc; + return rc; } -int AaffInfo (t_pAaff pAaff, char **ppInfoBuff) -{ - unsigned long long i; - unsigned long long Entries = 0; - int Pos = 0; +/* + * AaffGetInfofileContent + */ +int AaffGetInfofileContent(void *p_handle, const char **pp_info_buf) { + uint64_t i; + uint64_t Entries = 0; + int Pos = 0; #define REM (AaffInfoBuffLen-Pos) - 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 %llu", pAaff->Sectors ); - Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nImage size %llu (%0.1f GiB)", pAaff->ImageSize, pAaff->ImageSize/(1024.0*1024.0*1024.0)); - Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nTotal pages %llu", 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, "%llu", pAaff->CurrentPage); - Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSeek array length %llu", pAaff->PageSeekArrLen); - Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSeek interleave %llu", pAaff->Interleave); - - for (i=0; iPageSeekArrLen; i++) - if (pAaff->pPageSeekArr[i]) + 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]) Entries++; - Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\nSeek array entries %llu", Entries); - Pos += snprintf (&pAaff->pInfoBuff[Pos], REM, "\n"); + Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\nSeek array entries %" PRIu64, Entries); + Pos += snprintf (&((t_pAaff)p_handle)->pInfoBuff[Pos], REM, "\n"); #undef REM - *ppInfoBuff = pAaff->pInfoBuff; + *pp_info_buf = ((t_pAaff)p_handle)->pInfoBuff; return AAFF_OK; } -int AaffSize (t_pAaff pAaff, unsigned long long *pSize) -{ - *pSize = pAaff->ImageSize; - return AAFF_OK; +/* + * AaffSize + */ +int AaffSize(void *p_handle, uint64_t *p_size) { + *p_size=((t_pAaff)p_handle)->ImageSize; + return AAFF_OK; } -int AaffRead (t_pAaff pAaff, unsigned long long Seek, unsigned char *pBuffer, unsigned int Count) +/* + * AaffRead + */ +int AaffRead(void *p_handle, + uint64_t seek, + char *p_buf, + uint32_t count) { - unsigned long long Page; - unsigned char *pPageBuffer; - unsigned int PageLen; - unsigned int Ofs; - unsigned int ToCopy; - - if ((Seek+Count) > pAaff->ImageSize) - return AAFF_READ_BEYOND_IMAGE_LENGTH; + 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; +} - Page = Seek / pAaff->PageSize; - Ofs = Seek % pAaff->PageSize; +/* + * AaffOptionsHelp + */ +int AaffOptionsHelp(const char **pp_help) { + *pp_help=NULL; + return AAFF_OK; +} - while (Count) - { - CHK (AaffReadPage (pAaff, Page, &pPageBuffer, &PageLen)) - ToCopy = GETMIN (PageLen-Ofs, Count); - memcpy (pBuffer, pPageBuffer+Ofs, ToCopy); - Count -= ToCopy; - pBuffer += ToCopy; - Ofs = 0; - Page++; - } +/* + * AaffOptionsParse + */ +int AaffOptionsParse(void *p_handle, char *p_options, char **pp_error) { + return AAFF_OK; +} - return AAFF_OK; +/* + * AaffFreeBuffer + */ +void AaffFreeBuffer(void *p_buf) { + free(p_buf); } // ----------------------------------------------------- // Small main routine for testing // It converts an aff file to dd // ----------------------------------------------------- #ifdef AAFF_MAIN_FOR_TESTING int main(int argc, char *argv[]) { - t_pAaff pAaff; - char *pInfoBuff; - unsigned long long Remaining; - unsigned long long CurrentPos=0; - int rc; - int Percent; - int PercentOld; + t_pAaff pAaff; + char *pInfoBuff; + uint64_t Remaining; + uint64_t CurrentPos=0; + int rc; + int Percent; + int PercentOld; setbuf (stdout, NULL); setbuf (stderr, NULL); setlocale (LC_ALL, ""); printf ("AFF to DD converter\n"); if (argc != 3) { printf ("Usage: %s
\n", argv[0]); exit (1); } // rc = AaffOpen (&pAaff, argv[1], 1024); // weird seek array size for testing - rc = AaffOpen (&pAaff, argv[1], 0); + rc = AaffOpen (&pAaff, argv[1], 1); if (rc) { printf ("Error %d while opening file %s\n", rc, argv[1]); exit (2); } rc = AaffInfo (pAaff, &pInfoBuff); if (rc) { printf ("Could not retrieve info\n"); exit (2); } printf ("%s", 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; Remaining = pAaff->ImageSize; pBuff = malloc (BuffSize); CurrentPos=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) { printf ("Could not write to destinationfile\n"); exit (2); } CurrentPos += Bytes; Remaining -= Bytes; 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 65925a6..08af468 100644 --- a/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h +++ b/trunk/libxmount_input/libxmount_input_aaff/libxmount_input_aaff.h @@ -1,64 +1,187 @@ /******************************************************************************* * xmount Copyright (c) 2008-2013 by Gillen Daniel * * * * 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 . * *******************************************************************************/ #ifndef AAFF_H #define AAFF_H typedef struct _t_Aaff *t_pAaff; -int AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long MaxPageArrMem); -int AaffInfo (t_pAaff pAaff, char **ppInfoBuff); -int AaffSize (t_pAaff pAaff, unsigned long long *pSize); -int AaffRead (t_pAaff pAaff, unsigned long long Seek, unsigned char *pBuffer, unsigned int Count); -int AaffClose (t_pAaff *ppAaff); +// ---------------------- +// 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)) + +// ----------------- +// 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 +} 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 }; #endif diff --git a/trunk/libxmount_input/libxmount_input_aewf/CMakeLists.txt b/trunk/libxmount_input/libxmount_input_aewf/CMakeLists.txt new file mode 100644 index 0000000..6a39f59 --- /dev/null +++ b/trunk/libxmount_input/libxmount_input_aewf/CMakeLists.txt @@ -0,0 +1,8 @@ +project(libxmount_input_aewf) + +add_library(xmount_input_aewf SHARED libxmount_input_aewf.c) +include_directories(${LIBZ_INCLUDE_DIRS}) +target_link_libraries(xmount_input_aewf ${LIBZ_LIBRARIES}) + +install(TARGETS xmount_input_aewf DESTINATION lib/xmount) + 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 c485bd8..d0851d7 100644 --- a/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c +++ b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.c @@ -1,1353 +1,1232 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 . * *******************************************************************************/ // 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. - -//#define AEWF_MAIN_FOR_TESTING -//#define AEWF_DEBUG - -#ifdef AEWF_MAIN_FOR_TESTING - #define CREATE_REVERSE_FILE -// #define REVERSE_FILE_USES_SEPARATE_HANDLE -#endif - -#ifdef AEWF_MAIN_FOR_TESTING - #define _GNU_SOURCE -#endif - -#ifdef LINT_CODE_CHECK - #define _LARGEFILE_SOURCE - #define _FILE_OFFSET_BITS 64 -#endif - #include #include #include #include #include #include //lint !e537 !e451 Repeated include #include #include //lint !e537 !e451 Repeated include #include //lint !e537 !e451 Repeated include #include //lint !e537 !e451 Repeated include #include //lint !e537 !e451 Repeated include -#include "aewf.h" - -// ---------------------- -// Constant definitions -// ---------------------- - -#define GETMAX(a,b) ((a)>(b)?(a):(b)) -#define GETMIN(a,b) ((a)<(b)?(a):(b)) - -#define FALSE 0 -#define TRUE 1 - +#include "../libxmount_input.h" -#define ASPRINTF(...) \ -{ \ - if (asprintf(__VA_ARGS__) < 0) \ - return AEWF_ASPRINTF_FAILED; \ -} +//#define AEWF_DEBUG +#include "libxmount_input_aewf.h" -// --------------------- -// Types and strutures -// --------------------- +//#define AEWF_MAIN_FOR_TESTING -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; +#ifdef AEWF_MAIN_FOR_TESTING + #define CREATE_REVERSE_FILE +// #define REVERSE_FILE_USES_SEPARATE_HANDLE +#endif -typedef struct -{ - unsigned char Type[16]; - unsigned long long OffsetNextSection; - unsigned long long Size; - unsigned char Padding[40]; - unsigned int 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 - unsigned int ChunkCount; - unsigned int SectorsPerChunk; - unsigned int BytesPerSector; - unsigned long long SectorCount; - unsigned int CHS_Cylinders; - unsigned int CHS_Heads; - unsigned int CHS_Sectors; - unsigned char MediaFlags; - unsigned char Unknown2[3]; // contains 0x00 - unsigned int PalmVolumeStartSector; - unsigned char Padding1[4]; // contains 0x00 - unsigned int SmartLogsStartSector; - unsigned char CompressionLevel; - unsigned char Unknown3[3]; // contains 0x00 - unsigned int ErrorBlockSize; - unsigned char Unknown4[4]; - unsigned char AcquirySystemGUID[16]; - unsigned char Padding2[963]; - unsigned char Reserved [5]; - unsigned int Checksum; -} __attribute__ ((packed)) t_AewfSectionVolume, *t_pAewfSectionVolume; - -typedef struct -{ - unsigned int ChunkCount; - unsigned char Padding1 [4]; - unsigned long long TableBaseOffset; - unsigned char Padding2 [4]; - unsigned int Checksum; - unsigned int OffsetArray[]; //lint !e1501 data member has zero size -} __attribute__ ((packed)) t_AewfSectionTable, *t_pAewfSectionTable; +#ifdef AEWF_MAIN_FOR_TESTING + #define _GNU_SOURCE +#endif -const unsigned int AEWF_COMPRESSED = 0x80000000; +#ifdef LINT_CODE_CHECK + #define _LARGEFILE_SOURCE + #define _FILE_OFFSET_BITS 64 +#endif -typedef struct -{ - unsigned int FirstSector; - unsigned int NumberOfSectors; -} __attribute__ ((packed)) t_AewfSectionErrorEntry, *t_pAewfSectionErrorEntry; +/******************************************************************************* + * Forward declarations + ******************************************************************************/ +int AewfOpen(void **pp_handle, + const char **pp_filename_arr, + uint64_t filename_arr_len); +int AewfSize(void *p_handle, + uint64_t *p_size); +int AewfRead(void *p_handle, + uint64_t seek, + char *p_buf, + uint32_t count); +int AewfClose(void **pp_handle); +int AewfOptionsHelp(const char **pp_help); +int AewfOptionsParse(void *p_handle, + char *p_options, + char **pp_error); +int AewfGetInfofileContent(void *p_handle, + const char **pp_info_buf); +void AewfFreeBuffer(void *p_buf); -typedef struct -{ - unsigned int NumberOfErrors; - unsigned char Padding[512]; - unsigned int Checksum; - t_AewfSectionErrorEntry ErrorArr[0]; //lint !e1501 data member has zero size - unsigned int ChecksumArr; -} __attribute__ ((packed)) t_AewfSectionError, *t_pAewfSectionError; - -typedef struct -{ - unsigned char MD5[16]; - unsigned char Unknown[16]; - unsigned int Checksum; -} __attribute__ ((packed)) t_AewfSectionHash, *t_pAewfSectionHash; +/******************************************************************************* + * LibXmount_Input API implementation + ******************************************************************************/ +/* + * LibXmount_Input_GetApiVersion + */ +uint8_t LibXmount_Input_GetApiVersion() { + return LIBXMOUNT_INPUT_API_VERSION; +} +/* + * LibXmount_Input_GetSupportedFormats + */ +const char* LibXmount_Input_GetSupportedFormats() { + return "aewf\0\0"; +} -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; +/* + * LibXmount_Input_GetFunctions + */ +void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions) { + p_functions->Open=&AewfOpen; + p_functions->Size=&AewfSize; + p_functions->Read=&AewfRead; + p_functions->Close=&AewfClose; + p_functions->OptionsHelp=&AewfOptionsHelp; + p_functions->OptionsParse=&AewfOptionsParse; + p_functions->GetInfofileContent=&AewfGetInfofileContent; + p_functions->FreeBuffer=&AewfFreeBuffer; +} -typedef struct -{ - unsigned long long Nr; // The table's position in the pAewf->pTableArr, for debug output only - unsigned long long ChunkFrom; // Number of the chunk referred to by the first entry of this table (very first chunk has number 0) - unsigned long long 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 - unsigned long long 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) - unsigned int ChunkCount; // The number of chunk; this is the same as pTableData->Chunkcount, however, pTableData might not be available (NULL) - unsigned int 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; - -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) - unsigned Segments; - unsigned Tables; - unsigned long long Chunks; // Total number of chunks in all tables - unsigned long long TableCache; // Current amount RAM used by tables, in bytes - unsigned long long OpenSegments; // Current number of open segment files - unsigned long long SectorSize; - unsigned long long Sectors; - unsigned long long ChunkSize; - unsigned long long ImageSize; // Equals to Sectors * SectorSize - unsigned char *pChunkBuffCompressed; - unsigned char *pChunkBuffUncompressed; - unsigned long long 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 - unsigned int ChunkBuffSize; - unsigned long long ChunkInBuff; // Chunk currently residing in pChunkBuffUncompressed - char *pErrorText; // Used for assembling error text during option parsing - time_t LastStatsUpdate; - char *pInfo; - - // Statistics - unsigned long long SegmentCacheHits; - unsigned long long SegmentCacheMisses; - unsigned long long TableCacheHits; - unsigned long long TableCacheMisses; - unsigned long long ChunkCacheHits; - unsigned long long ChunkCacheMisses; - unsigned long long ReadOperations; // How many times did xmount call the function AewfRead - unsigned long long DataReadFromImage; // The data (in bytes) read from the image - unsigned long long DataReadFromImageRaw; // The same data (in bytes), after uncompression (if any) - unsigned long long DataRequestedByCaller; // How much data was given back to the caller - unsigned long long TablesReadFromImage; // The overhead of the table read operations (in bytes) - - unsigned long long ChunksRead; - unsigned long long BytesRead; - - // Options - unsigned long long MaxTableCache; // Max. amount of bytes in pTableArr[x].pTableData, in bytes - unsigned long long MaxOpenSegments; // Max. number of open files in pSegmentArr - char *pStatsFilename; // Statistics file - unsigned long long StatsRefresh; // The time in seconds between update of the stats file -} t_Aewf; - -// ---------------- -// Error handling -// ---------------- - -#ifdef AEWF_DEBUG - #define CHK(ChkVal) \ - { \ - int ChkValRc; \ - if ((ChkValRc=(ChkVal)) != AEWF_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)) != AEWF_OK) \ - return ChkValRc; \ - } - #define DEBUG_PRINTF(...) -#endif +/******************************************************************************* + * Private + ******************************************************************************/ // --------------------------- // Internal static functions // --------------------------- 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; } -static int ReadFilePos (FILE *pFile, void *pMem, unsigned int Size, unsigned long long Pos) +static int ReadFilePos (FILE *pFile, void *pMem, unsigned int Size, uint64_t Pos) { if (Size == 0) return AEWF_OK; if (Pos != ULLONG_MAX) { if (fseeko (pFile, Pos, SEEK_SET)) return AEWF_FILE_SEEK_FAILED; } if (fread (pMem, Size, 1, pFile) != 1) return AEWF_FILE_READ_FAILED; return AEWF_OK; } //static int ReadFile (FILE *pFile, void *pMem, unsigned int Size) //{ // CHK (ReadFilePos (pFile, pMem, Size, ULLONG_MAX)) // // return AEWF_OK; //} -static int ReadFileAllocPos (FILE *pFile, void **ppMem, unsigned int Size, unsigned long long Pos) +static int ReadFileAllocPos (FILE *pFile, void **ppMem, unsigned int Size, uint64_t Pos) { *ppMem = (void*) malloc (Size); if (*ppMem == NULL) return AEWF_MEMALLOC_FAILED; CHK (ReadFilePos (pFile, *ppMem, Size, Pos)) return AEWF_OK; } static int ReadFileAlloc (FILE *pFile, void **ppMem, unsigned int Size) { CHK (ReadFileAllocPos (pFile, ppMem, Size, ULLONG_MAX)) 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; } // --------------- // API functions // --------------- -static int CreateInfoData (t_pAewf pAewf, t_pAewfSectionVolume pVolume, unsigned char *pHeader , unsigned HeaderLen, - unsigned char *pHeader2, unsigned Header2Len) +static int CreateInfoData (t_pAewf pAewf, t_pAewfSectionVolume pVolume, char *pHeader , unsigned HeaderLen, + char *pHeader2, unsigned Header2Len) { char *pInfo1; char *pInfo2; char *pInfo3 = NULL; char *pInfo4; char *pInfo5; - unsigned char *pHdr = 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; - ASPRINTF(&pInfo1, "Image size %llu (%0.2f GiB)\n" + ASPRINTF(&pInfo1, "Image size %" PRIu64 " (%0.2f GiB)\n" "Bytes per sector %u\n" - "Sector count %llu\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[ 5], 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; } // pHdr = pHeader; HdrLen = HeaderLen; if (pHdr) { pText = (char *) malloc (MaxTextSize); if (pText == NULL) return AEWF_MEMALLOC_FAILED; DstLen0 = MaxTextSize; - zrc = uncompress ((unsigned char *)pText, &DstLen0, pHdr, HdrLen); + zrc = uncompress ((unsigned char *)pText, &DstLen0, (const Bytef*)pHdr, HdrLen); UncompressedLen = DstLen0; if (zrc != Z_OK) return 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) return 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); 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 (pDesc && pData) { pInfo3 = (char *) malloc (strlen (pData) + 4096); if (pInfo3 == NULL) return 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, "%u segment file: %s\n", pAewf->Segments, pAewf->pSegmentArr[0].pName) else ASPRINTF (&pInfo4, "%u segment files\n First: %s\n Last: %s\n", pAewf->Segments, pAewf->pSegmentArr[0 ].pName, pAewf->pSegmentArr[pAewf->Segments-1].pName); ASPRINTF (&pInfo5, "%u 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) free (pInfo1); free (pInfo2); free (pInfo4); free (pInfo5); if (pText ) free (pText ); if (pInfo3) free (pInfo3); return AEWF_OK; } -int AewfOpen (t_pAewf *ppAewf, unsigned FilenameArrLen, const char **ppFilenameArr) +/* + * AewfOpen + */ +int AewfOpen(void **pp_handle, + const char **pp_filename_arr, + uint64_t filename_arr_len) { t_pAewf pAewf; t_AewfFileHeader FileHeader; t_AewfSection Section; FILE *pFile; t_pSegment pSegment; t_pTable pTable; - unsigned long long Pos; + uint64_t Pos; t_pAewfSectionTable pEwfTable = NULL; t_pAewfSectionVolume pVolume = NULL; - unsigned char *pHeader = NULL; - unsigned char *pHeader2 = NULL; + char *pHeader = NULL; + char *pHeader2 = NULL; int LastSection; unsigned int SectionSectorsSize; unsigned HeaderLen = 0; unsigned Header2Len = 0; // Create handle and clear it // -------------------------- - *ppAewf = NULL; + *pp_handle = NULL; pAewf = (t_pAewf) malloc (sizeof(t_Aewf)); if (pAewf == NULL) return AEWF_MEMALLOC_FAILED; memset (pAewf, 0, sizeof(t_Aewf)); pAewf->ChunkInBuff = ULONG_LONG_MAX; pAewf->pErrorText = NULL; pAewf->pStatsFilename = 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; // Create pSegmentArr and put the segment files in it // -------------------------------------------------- - int SegmentArrLen = FilenameArrLen * sizeof(t_Segment); + int SegmentArrLen = filename_arr_len * sizeof(t_Segment); pAewf->pSegmentArr = (t_pSegment) malloc (SegmentArrLen); - pAewf->Segments = FilenameArrLen; + pAewf->Segments = filename_arr_len; if (pAewf->pSegmentArr == NULL) return AEWF_MEMALLOC_FAILED; memset (pAewf->pSegmentArr, 0, SegmentArrLen); - for (unsigned i=0; ipSegmentArr[i]; - pSegment->pName = canonicalize_file_name (ppFilenameArr[i]); // canonicalize_file_name allocates a buffer + pSegment->pName = canonicalize_file_name (pp_filename_arr[i]); // canonicalize_file_name allocates a buffer CHK (OpenFile (&pFile, pSegment->pName)) CHK (ReadFilePos (pFile, (void*)&FileHeader, sizeof(FileHeader), 0)) -// DEBUG_PRINTF ("Segment %s - %d \n", ppFilenameArr[i], FileHeader.SegmentNumber); +// DEBUG_PRINTF ("Segment %s - %d \n", pp_filename_arr[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; iSegments; 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; DEBUG_PRINTF ("Reading tables\n"); for (unsigned i=0; iSegments; i++) { pSegment = &pAewf->pSegmentArr[i]; CHK (OpenFile (&pFile, pSegment->pName)) CHK (ReadFilePos (pFile, &FileHeader, sizeof(FileHeader), 0)) Pos = sizeof (FileHeader); DEBUG_PRINTF ("Segment %s ", pSegment->pName); do { CHK (ReadFilePos (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 (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; DEBUG_PRINTF ("t%d", pTable->ChunkCount) free (pEwfTable); pEwfTable = NULL; SectionSectorsSize = 0; } else if ((strcasecmp ((char *)Section.Type, "header") == 0) && (pHeader==NULL)) { HeaderLen = Section.Size - sizeof(t_AewfSection); CHK (ReadFileAlloc (pFile, (void**) &pHeader, HeaderLen)) } else if ((strcasecmp ((char *)Section.Type, "header2") == 0) && (pHeader2==NULL)) { Header2Len = Section.Size - sizeof(t_AewfSection); CHK (ReadFileAlloc (pFile, (void**) &pHeader2, Header2Len)) } else if ((strcasecmp ((char *)Section.Type, "volume") == 0) && (pVolume==NULL)) { CHK (ReadFileAlloc (pFile, (void**) &pVolume, sizeof(t_AewfSectionVolume))) pAewf->Sectors = pVolume->SectorCount; pAewf->SectorSize = pVolume->BytesPerSector; pAewf->ChunkSize = pVolume->SectorsPerChunk * pVolume->BytesPerSector; pAewf->ImageSize = pAewf->Sectors * pAewf->SectorSize; DEBUG_PRINTF ("%lld sectors à %lld bytes", pAewf->Sectors, pAewf->SectorSize) } LastSection = (Pos == Section.OffsetNextSection); Pos = Section.OffsetNextSection; } while (!LastSection); DEBUG_PRINTF ("\n"); CHK (CloseFile (&pFile)) } if (pVolume == NULL) return AEWF_VOLUME_MISSING; if (pAewf->Chunks != pVolume->ChunkCount) 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 = (unsigned char *) malloc (pAewf->ChunkBuffSize); - pAewf->pChunkBuffUncompressed = (unsigned char *) malloc (pAewf->ChunkBuffSize); + pAewf->pChunkBuffCompressed = (char *) malloc (pAewf->ChunkBuffSize); + pAewf->pChunkBuffUncompressed = (char *) malloc (pAewf->ChunkBuffSize); if ((pAewf->pChunkBuffCompressed == NULL) || (pAewf->pChunkBuffUncompressed == NULL)) return AEWF_MEMALLOC_FAILED; pAewf->MaxTableCache = 10*1024*1024; pAewf->MaxOpenSegments = 10; pAewf->TableCache = 0; pAewf->OpenSegments = 0; - *ppAewf = pAewf; + *((t_pAewf**)pp_handle)=(void*)pAewf; CHK (CreateInfoData (pAewf, pVolume, pHeader, HeaderLen, pHeader2, Header2Len)) free (pVolume); free (pHeader); free (pHeader2); return AEWF_OK; } -int AewfInfo (t_pAewf pAewf, const char **ppInfoBuff) -{ - *ppInfoBuff = pAewf->pInfo; - return AEWF_OK; +/* + * AewfInfo + */ +int AewfGetInfofileContent(void *p_handle, const char **pp_info_buf) { + *pp_info_buf=((t_pAewf)p_handle)->pInfo; + return AEWF_OK; } -int AewfSize (t_pAewf pAewf, unsigned long long *pSize) -{ - *pSize = pAewf->ImageSize; - return AEWF_OK; +/* + * AewfSize + */ +int AewfSize(void *p_handle, uint64_t *p_size) { + *p_size = ((t_pAewf)p_handle)->ImageSize; + return AEWF_OK; } 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; iSegments; 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; DEBUG_PRINTF ("Closing %s\n", pOldestSegment->pName); CHK (CloseFile (&pOldestSegment->pFile)) pAewf->OpenSegments--; } // Read the desired table into RAM // ------------------------------- DEBUG_PRINTF ("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; iTables; 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; - DEBUG_PRINTF ("Releasing table %llu (%lu bytes)\n", pOldestTable->Nr, pOldestTable->Size); + DEBUG_PRINTF ("Releasing table %" PRIu64 " (%lu bytes)\n", pOldestTable->Nr, pOldestTable->Size); } // Read the desired table into RAM // ------------------------------- - DEBUG_PRINTF ("Loading table %llu (%lu bytes)\n", pTable->Nr, pTable->Size); + DEBUG_PRINTF ("Loading table %" PRIu64 " (%lu bytes)\n", pTable->Nr, pTable->Size); CHK (AewfOpenSegment (pAewf, pTable)); CHK (ReadFileAllocPos (pTable->pSegment->pFile, (void**) &pTable->pEwfTable, pTable->Size, pTable->Offset)) pAewf->TableCache += pTable->Size; pAewf->TablesReadFromImage = pTable->Size; return AEWF_OK; } // AewfReadChunk0 reads one chunk. It expects that the EWF table is present // in memory and the required segment file is opened. -static int AewfReadChunk0 (t_pAewf pAewf, t_pTable pTable, unsigned long long AbsoluteChunk, unsigned TableChunk) +static int AewfReadChunk0 (t_pAewf pAewf, t_pTable pTable, uint64_t AbsoluteChunk, unsigned TableChunk) { int Compressed; - unsigned long long SeekPos; + uint64_t SeekPos; t_pAewfSectionTable pEwfTable; unsigned int Offset; unsigned int ReadLen; uLongf DstLen0; int zrc; uint CalcCRC; uint *pStoredCRC; - unsigned long long ChunkSize; + uint64_t ChunkSize; 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) return AEWF_CHUNK_TOO_BIG; if (Compressed) { CHK (ReadFilePos (pTable->pSegment->pFile, pAewf->pChunkBuffCompressed, ReadLen, SeekPos)) DstLen0 = pAewf->ChunkBuffSize; - zrc = uncompress (pAewf->pChunkBuffUncompressed, &DstLen0, pAewf->pChunkBuffCompressed, ReadLen); + zrc = uncompress ((unsigned char*)pAewf->pChunkBuffUncompressed, &DstLen0, (const Bytef*)pAewf->pChunkBuffCompressed, ReadLen); if (zrc != Z_OK) return AEWF_UNCOMPRESS_FAILED; else if (DstLen0 != pAewf->ChunkSize) return AEWF_BAD_UNCOMPRESSED_LENGTH; ChunkSize = DstLen0; } else { ChunkSize = pAewf->ChunkSize; if (AbsoluteChunk == (pAewf->Chunks-1)) { ChunkSize = pAewf->ImageSize % pAewf->ChunkSize; if (ChunkSize == 0) ChunkSize = pAewf->ChunkSize; - printf ("Last chunk size %llu\n", ChunkSize); + printf ("Last chunk size %" PRIu64 "\n", ChunkSize); printf ("ReadLen %u\n", ReadLen); } CHK (ReadFilePos (pTable->pSegment->pFile, pAewf->pChunkBuffUncompressed, ReadLen, SeekPos)) CalcCRC = adler32 (1, (const Bytef *) pAewf->pChunkBuffUncompressed, ChunkSize); pStoredCRC = (uint *) (pAewf->pChunkBuffUncompressed + ChunkSize); if (CalcCRC != *pStoredCRC) return AEWF_CHUNK_CRC_ERROR; } pAewf->ChunkInBuff = AbsoluteChunk; pAewf->ChunkBuffUncompressedDataLen = ChunkSize; pAewf->DataReadFromImage += ReadLen; pAewf->DataReadFromImageRaw += ChunkSize; return AEWF_OK; } -static int AewfReadChunk (t_pAewf pAewf, unsigned long long AbsoluteChunk, unsigned char **ppBuffer, unsigned int *pLen) +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; if (pAewf->ChunkInBuff == AbsoluteChunk) { *pLen = pAewf->ChunkBuffUncompressedDataLen; pAewf->ChunkCacheHits++; return AEWF_OK; } pAewf->ChunkCacheMisses++; // Find table containing desired chunk // ----------------------------------- for (TableNr=0; TableNrTables; TableNr++) { pTable = &pAewf->pTableArr[TableNr]; Found = (AbsoluteChunk >= pTable->ChunkFrom) && (AbsoluteChunk <= pTable->ChunkTo); if (Found) break; } if (!Found) return AEWF_CHUNK_NOT_FOUND; // Load corresponding table and get chunk // -------------------------------------- pTable->LastUsed = time(NULL); // Update LastUsed here, in order not to pTable->pSegment->LastUsed = pTable->LastUsed; // remove the required data from cache CHK (AewfLoadEwfTable (pAewf, pTable)) CHK (AewfOpenSegment (pAewf, pTable)); if ((AbsoluteChunk - pTable->ChunkFrom) > ULONG_MAX) return AEWF_ERROR_IN_CHUNK_NUMBER; TableChunk = AbsoluteChunk - pTable->ChunkFrom; -// DEBUG_PRINTF ("table %d / entry %llu (%s)\n", TableNr, TableChunk, pTable->pSegment->pName) +// DEBUG_PRINTF ("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; time (&NowT); if (pAewf->pStatsFilename) { if (((NowT - pAewf->LastStatsUpdate) >= (int)pAewf->StatsRefresh) || Force) { pAewf->LastStatsUpdate = NowT; pid = getpid (); ASPRINTF (&pFilename, "%s_%d", pAewf->pStatsFilename, pid) 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, "Cache hits misses ratio\n"); fprintf (pFile, "-------------------------------------\n"); - fprintf (pFile, "Segment %10llu %10llu %5.1f%%\n", pAewf->SegmentCacheHits, pAewf->SegmentCacheMisses, (100.0*pAewf->SegmentCacheHits)/(pAewf->SegmentCacheHits+pAewf->SegmentCacheMisses)); - fprintf (pFile, "Table %10llu %10llu %5.1f%%\n", pAewf->TableCacheHits , pAewf->TableCacheMisses , (100.0*pAewf->TableCacheHits) /(pAewf->TableCacheHits +pAewf->TableCacheMisses )); - fprintf (pFile, "Chunk %10llu %10llu %5.1f%%\n", pAewf->ChunkCacheHits , pAewf->ChunkCacheMisses , (100.0*pAewf->ChunkCacheHits) /(pAewf->ChunkCacheHits +pAewf->ChunkCacheMisses )); + 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 %10llu\n", pAewf->ReadOperations); + fprintf (pFile, "Read operations %10" PRIu64 "\n", pAewf->ReadOperations); 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)); 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; } -int AewfRead (t_pAewf pAewf, unsigned long long Seek, unsigned char *pBuffer, unsigned int Count) +/* + * AewfRead + */ +int AewfRead(void *p_handle, + uint64_t seek, + char *p_buf, + uint32_t count) { - unsigned long long Chunk; - unsigned char *pChunkBuffer; - unsigned int ChunkLen; - unsigned int Ofs; - unsigned int ToCopy; - - pAewf->ReadOperations++; - pAewf->DataRequestedByCaller += Count; - - if ((Seek+Count) > pAewf->ImageSize) - return AEWF_READ_BEYOND_IMAGE_LENGTH; - - Chunk = Seek / pAewf->ChunkSize; - Ofs = Seek % pAewf->ChunkSize; - - while (Count) - { -// DEBUG_PRINTF ("Reading chunk %llu -> ", Chunk) - CHK (AewfReadChunk (pAewf, Chunk, &pChunkBuffer, &ChunkLen)) - ToCopy = GETMIN (ChunkLen-Ofs, Count); - memcpy (pBuffer, pChunkBuffer+Ofs, ToCopy); - Count -= ToCopy; - pBuffer += ToCopy; - Ofs = 0; - Chunk++; - } - CHK(UpdateStats(pAewf, FALSE)) - - return AEWF_OK; + uint64_t chunk; + char *p_chunk_buffer; + unsigned int chunk_len, ofs, to_copy; + + ((t_pAewf)p_handle)->ReadOperations++; + ((t_pAewf)p_handle)->DataRequestedByCaller+=count; + + if((seek+count)>((t_pAewf)p_handle)->ImageSize) { + return AEWF_READ_BEYOND_IMAGE_LENGTH; + } + + chunk=seek/((t_pAewf)p_handle)->ChunkSize; + ofs=seek%((t_pAewf)p_handle)->ChunkSize; + + while(count) { + CHK(AewfReadChunk((t_pAewf)p_handle,chunk,&p_chunk_buffer,&chunk_len)) + to_copy=GETMIN(chunk_len-ofs,count); + memcpy(p_buf,p_chunk_buffer+ofs,to_copy); + count-=to_copy; + p_buf+=to_copy; + ofs=0; + chunk++; + } + CHK(UpdateStats((t_pAewf)p_handle,FALSE)) + + return AEWF_OK; } -int AewfClose (t_pAewf *ppAewf) -{ - t_pTable pTable; - t_pSegment pSegment; - t_pAewf pAewf = *ppAewf; - - CHK (UpdateStats (pAewf, TRUE)) - - for (unsigned i=0; iTables; i++) - { - pTable = &pAewf->pTableArr[i]; - if (pTable->pEwfTable) - free (pTable->pEwfTable); - } - - for (unsigned i=0; iSegments; i++) - { - pSegment = &pAewf->pSegmentArr[i]; - if (pSegment->pFile) - CloseFile(&pSegment->pFile); - free (pSegment->pName); - } - - free (pAewf->pTableArr); - free (pAewf->pSegmentArr); - free (pAewf->pChunkBuffCompressed ); - free (pAewf->pChunkBuffUncompressed); - if (pAewf->pStatsFilename) - free (pAewf->pStatsFilename); - memset (pAewf, 0, sizeof(t_Aewf)); - free (pAewf); - *ppAewf = NULL; - - return AEWF_OK; +/* + * AewfClose + */ +int AewfClose(void **pp_handle) { + t_pTable p_table; + t_pSegment p_segment; + t_pAewf p_aewf=*((t_pAewf*)pp_handle); + + CHK(UpdateStats(p_aewf,TRUE)) + + for(unsigned i=0;iTables;i++) { + p_table=&p_aewf->pTableArr[i]; + if(p_table->pEwfTable) free(p_table->pEwfTable); + } + + for(unsigned i=0;iSegments;i++) { + p_segment=&p_aewf->pSegmentArr[i]; + if(p_segment->pFile) CloseFile(&pSegment->pFile); + free(p_segment->pName); + } + + free(p_aewf->pTableArr); + free(p_aewf->pSegmentArr); + free(p_aewf->pChunkBuffCompressed); + free(p_aewf->pChunkBuffUncompressed); + if(p_aewf->pStatsFilename) free(p_aewf->pStatsFilename); + memset(p_aewf,0,sizeof(t_Aewf)); + free(p_aewf); + *pp_handle=NULL; + + return AEWF_OK; } // Option handling // --------------- static const char *pOptionPrefix = "aewf_"; static const char OptionSeparator = ','; static int SetError (t_pAewf pAewf, char **ppError, const char *pFormat, ...) { va_list VaList; if (pAewf->pErrorText) free (pAewf->pErrorText); va_start(VaList, pFormat); if (vasprintf (&pAewf->pErrorText, pFormat, VaList) < 0) return AEWF_VASPRINTF_FAILED; va_end(VaList); *ppError = pAewf->pErrorText; return AEWF_OK; } static int CheckOption (const char *pOption, int OptionLen, const char *pOptionName, const char **ppValue, int *pValueLen) { int Found; *ppValue = NULL; *pValueLen = 0; Found = (strcasestr (pOption, pOptionName) == pOption); if (Found) { *ppValue = pOption + strlen (pOptionName); *pValueLen = OptionLen - strlen (pOptionName); } return Found; } static int ValueToInt (t_pAewf pAewf, const char *pValue, int ValueLen, char **ppError) { char *pTail; int Value; *ppError = NULL; Value = strtoll (pValue, &pTail, 10); if (pTail != (pValue + ValueLen)) CHK (SetError(pAewf, ppError, "Invalid option value %s", pValue)) return Value; } static char *ValueToStr (t_pAewf pAewf, const char *pValue, int ValueLen, char **ppError) { *ppError = NULL; return strndup (pValue, ValueLen); } static int ReadOption (t_pAewf pAewf, char *pOption, int OptionLen, char **ppError) { const char *pValue; int ValueLen; *ppError = NULL; if (CheckOption (pOption, OptionLen, "maxfiles=", &pValue, &ValueLen)) pAewf->MaxOpenSegments = ValueToInt (pAewf, pValue, ValueLen, ppError); else if (CheckOption (pOption, OptionLen, "maxmem=" , &pValue, &ValueLen)) pAewf->MaxTableCache = ValueToInt (pAewf, pValue, ValueLen, ppError)*1024*1024; else if (CheckOption (pOption, OptionLen, "stats=" , &pValue, &ValueLen)) pAewf->pStatsFilename = ValueToStr (pAewf, pValue, ValueLen, ppError); else if (CheckOption (pOption, OptionLen, "refresh=" , &pValue, &ValueLen)) pAewf->StatsRefresh = ValueToInt (pAewf, pValue, ValueLen, ppError); else CHK (SetError(pAewf, ppError, "Unknown option %s%s", pOptionPrefix, pOption)) return AEWF_OK; } -int AewfOptions(t_pAewf pAewf, char *pOptions, char **ppError) -{ +/* + * AewfOptionsParse + */ +int AewfOptionsParse(void *p_handle, char *p_options, char **pp_error) { char *pCurrent; char *pOption; char *pSep; int Found; - pCurrent = pOptions; + pCurrent = p_options; while (*pCurrent) { pSep = strchr (pCurrent, OptionSeparator); if (pSep == NULL) pSep = pCurrent + strlen(pCurrent); Found = FALSE; if ((pSep - pCurrent) >= (int)strlen(pOptionPrefix)) // Check for options starting with our prefix { Found = (strncasecmp (pCurrent, pOptionPrefix, strlen(pOptionPrefix)) == 0); if (Found) { pOption = pCurrent + strlen(pOptionPrefix); - CHK (ReadOption (pAewf, pOption, pSep-pOption, ppError)) - if (*ppError) + CHK (ReadOption ((t_pAewf)p_handle, pOption, pSep-pOption, pp_error)) + if (*pp_error) break; memmove (pCurrent, pSep+1, strlen(pSep)+1); } } if (!Found) { if (*pSep) pCurrent = pSep+1; else pCurrent = pSep; } } - if (pOptions[strlen(pOptions)-1] == OptionSeparator) // Remove trailing separator if there is one - pOptions[strlen(pOptions)-1] = '\0'; + if (p_options[strlen(p_options)-1] == OptionSeparator) // Remove trailing separator if there is one + p_options[strlen(p_options)-1] = '\0'; - DEBUG_PRINTF ("Max open segment files %llu\n" , pAewf->MaxOpenSegments) - DEBUG_PRINTF ("Max table cache %llu bytes (%0.1f MiB)\n", pAewf->MaxTableCache, pAewf->MaxTableCache / (1024.0*1024.0)) - DEBUG_PRINTF ("Stats file %s\n" , pAewf->pStatsFilename ? pAewf->pStatsFilename : "-none-") - DEBUG_PRINTF ("Stats refresh %llus\n" , pAewf->StatsRefresh); + DEBUG_PRINTF ("Max open segment files %" PRIu64 "\n" , ((t_pAewf)p_handle)->MaxOpenSegments) + DEBUG_PRINTF ("Max table cache %" PRIu64 " bytes (%0.1f MiB)\n", ((t_pAewf)p_handle)->MaxTableCache, ((t_pAewf)p_handle)->MaxTableCache / (1024.0*1024.0)) + DEBUG_PRINTF ("Stats file %s\n" , ((t_pAewf)p_handle)->pStatsFilename ? ((t_pAewf)p_handle)->pStatsFilename : "-none-") + DEBUG_PRINTF ("Stats refresh %" PRIu64 "s\n" , ((t_pAewf)p_handle)->StatsRefresh); DEBUG_PRINTF ("Unused options %s\n" , pOptions); return AEWF_OK; } -int AewfOptionHelp (const char **ppHelp) -{ - *ppHelp = " aewf_maxmem The maximum amount of memory (in MiB) used for caching image offset\n" +int AewfOptionsHelp(const char **pp_help) { + *pp_help = " aewf_maxmem The maximum amount of memory (in MiB) used for caching image offset\n" " tables.\n" " aewf_maxfiles The maximum number of image segment files opened at the same time.\n" " aewf_stats A filename that will be used for outputting statistical data at\n" " regular intervals. The process id is automatically appended to the\n" " given filename.\n" " aewf_refresh The update interval, in seconds, for the statistical data output.\n" " Ignored if aewf_stats is not set. The default value is 10.\n" " Example: aewf_maxmem=64,aewf_stats=mystats,aewf_refresh=2" ; - return AEWF_OK; + return AEWF_OK; +} + +void AewfFreeBuffer(void *p_buf) { + free(p_buf); } // ----------------------------------------------------- // Small main routine for testing // It converts an EWF file into dd // ----------------------------------------------------- #ifdef AEWF_MAIN_FOR_TESTING int main(int argc, const char *argv[]) { t_pAewf pAewf; - unsigned long long TotalSize; - unsigned long long Remaining; - unsigned long long Read; - unsigned long long Pos; + uint64_t TotalSize; + uint64_t Remaining; + uint64_t Read; + uint64_t Pos; unsigned int BuffSize = 13*65536; // A multiple of chunk size for good performance - unsigned char Buff[BuffSize]; + char Buff[BuffSize]; FILE *pFile; int Percent; int PercentOld; int rc; char *pOptions = NULL; char *pError = NULL; const char *pHelp; const char *pInfoBuff; #ifdef CREATE_REVERSE_FILE FILE *pFileRev; - unsigned long long PosRev; + uint64_t PosRev; #ifdef REVERSE_FILE_USES_SEPARATE_HANDLE t_pAewf pAewfRev; #else #define pAewfRev pAewf #endif #endif setbuf(stdout, NULL); setbuf(stderr, NULL); setlocale (LC_ALL, ""); #define PRINT_ERROR_AND_EXIT(...) \ { \ printf (__VA_ARGS__); \ exit (1); \ } 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) AewfOptionHelp (&pHelp); printf ("Usage: %s <...> [-comma_separated_options]\n", argv[0]); printf ("Possible options:\n%s\n", pHelp); printf ("The output file will be named dd.\n"); exit (1); } if (argv[argc-1][0] == '-') { pOptions = strdup (&(argv[argc-1][1])); argc--; } rc = AewfOpen (&pAewf, argc-1, &argv[1]); if (rc != AEWF_OK) PRINT_ERROR_AND_EXIT ("Cannot open EWF files, rc=%d\n", rc) if (pOptions) CHK (AewfOptions(pAewf, pOptions, &pError)) if (pError) PRINT_ERROR_AND_EXIT ("Error while setting options: %s", pError); #if defined(CREATE_REVERSE_FILE) && defined(REVERSE_FILE_USES_SEPARATE_HANDLE) rc = AewfOpen (&pAewfRev, argc-1, &argv[1]); if (rc != AEWF_OK) PRINT_ERROR_AND_EXIT ("Cannot open EWF files, rc=%d\n", rc) if (pOptions) CHK (AewfOptions(pAewfRev, pOptions, &pError)) if (pError) PRINT_ERROR_AND_EXIT ("Error while setting options: %s", pError); #endif CHK (AewfInfo (pAewf, &pInfoBuff)) if (pInfoBuff) printf ("Contents of info buffer:\n%s\n", pInfoBuff); CHK (AewfSize (pAewf, &TotalSize)) - printf ("Total size: %llu bytes\n", TotalSize); + printf ("Total size: %" PRIu64 " bytes\n", TotalSize); Remaining = 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; while (Remaining) { -// DEBUG_PRINTF ("Pos %llu -- Remaining %llu ", Pos, Remaining); +// DEBUG_PRINTF ("Pos %" PRIu64 " -- Remaining %" PRIu64 " ", Pos, Remaining); Read = GETMIN (Remaining, BuffSize); rc = AewfRead (pAewf, Pos, &Buff[0], Read); if (rc != AEWF_OK) PRINT_ERROR_AND_EXIT("Error %d while calling AewfRead\n", rc); if (fwrite (Buff, Read, 1, pFile) != 1) PRINT_ERROR_AND_EXIT("Could not write to destination file\n"); Remaining -= Read; Pos += Read; #ifdef CREATE_REVERSE_FILE PosRev -= Read; rc = AewfRead (pAewf, PosRev, &Buff[0], Read); if (rc != AEWF_OK) PRINT_ERROR_AND_EXIT("Error %d while reverse calling AewfRead\n", rc); 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 EWF files\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 EWF files\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 7ab7065..5731684 100644 --- a/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h +++ b/trunk/libxmount_input/libxmount_input_aewf/libxmount_input_aewf.h @@ -1,71 +1,256 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 . * *******************************************************************************/ #ifndef AEWF_H #define AEWF_H typedef struct _t_Aewf *t_pAewf; -int AewfOptionHelp (const char **pHelp); -int AewfOpen (t_pAewf *ppAewf, unsigned FilenameArrLen, const char **ppFilenameArr); -int AewfOptions (t_pAewf pAewf, char *pOptions, char **pError); -int AewfInfo (t_pAewf pAewf, const char **ppInfoBuff); -int AewfSize (t_pAewf pAewf, unsigned long long *pSize); -int AewfRead (t_pAewf pAewf, unsigned long long Seek, unsigned char *pBuffer, unsigned int Count); -int AewfClose (t_pAewf *ppAewf); +// ---------------------- +// Constant definitions +// ---------------------- + +#define GETMAX(a,b) ((a)>(b)?(a):(b)) +#define GETMIN(a,b) ((a)<(b)?(a):(b)) + +#define FALSE 0 +#define TRUE 1 + + +#define ASPRINTF(...) \ +{ \ + if (asprintf(__VA_ARGS__) < 0) \ + return AEWF_ASPRINTF_FAILED; \ +} + +// --------------------- +// 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]; + unsigned int 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 + unsigned int ChunkCount; + unsigned int SectorsPerChunk; + unsigned int BytesPerSector; + uint64_t SectorCount; + unsigned int CHS_Cylinders; + unsigned int CHS_Heads; + unsigned int CHS_Sectors; + unsigned char MediaFlags; + unsigned char Unknown2[3]; // contains 0x00 + unsigned int PalmVolumeStartSector; + unsigned char Padding1[4]; // contains 0x00 + unsigned int SmartLogsStartSector; + unsigned char CompressionLevel; + unsigned char Unknown3[3]; // contains 0x00 + unsigned int ErrorBlockSize; + unsigned char Unknown4[4]; + unsigned char AcquirySystemGUID[16]; + unsigned char Padding2[963]; + unsigned char Reserved [5]; + unsigned int Checksum; +} __attribute__ ((packed)) t_AewfSectionVolume, *t_pAewfSectionVolume; + +typedef struct +{ + unsigned int ChunkCount; + unsigned char Padding1 [4]; + uint64_t TableBaseOffset; + unsigned char Padding2 [4]; + unsigned int Checksum; + unsigned int OffsetArray[]; //lint !e1501 data member has zero size +} __attribute__ ((packed)) t_AewfSectionTable, *t_pAewfSectionTable; + +const unsigned int AEWF_COMPRESSED = 0x80000000; + +typedef struct +{ + unsigned int FirstSector; + unsigned int NumberOfSectors; +} __attribute__ ((packed)) t_AewfSectionErrorEntry, *t_pAewfSectionErrorEntry; + +typedef struct +{ + unsigned int NumberOfErrors; + unsigned char Padding[512]; + unsigned int Checksum; + t_AewfSectionErrorEntry ErrorArr[0]; //lint !e1501 data member has zero size + unsigned int ChecksumArr; +} __attribute__ ((packed)) t_AewfSectionError, *t_pAewfSectionError; + +typedef struct +{ + unsigned char MD5[16]; + unsigned char Unknown[16]; + unsigned int 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) + unsigned int ChunkCount; // The number of chunk; this is the same as pTableData->Chunkcount, however, pTableData might not be available (NULL) + unsigned int 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; + +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) + unsigned Segments; + unsigned 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 + unsigned int ChunkBuffSize; + uint64_t ChunkInBuff; // Chunk currently residing in pChunkBuffUncompressed + 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; + + // 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 +} t_Aewf; + +// ---------------- +// Error handling +// ---------------- + +#ifdef AEWF_DEBUG + #define CHK(ChkVal) \ + { \ + int ChkValRc; \ + if ((ChkValRc=(ChkVal)) != AEWF_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)) != AEWF_OK) \ + return ChkValRc; \ + } + #define DEBUG_PRINTF(...) +#endif // Possible error codes for the above functions enum { AEWF_OK = 0, AEWF_FOUND, AEWF_MEMALLOC_FAILED=100, // 100 AEWF_FILE_OPEN_FAILED, AEWF_FILE_CLOSE_FAILED, AEWF_FILE_SEEK_FAILED, AEWF_FILE_READ_FAILED, AEWF_READFILE_BAD_MEM, // 105 AEWF_INVALID_SEGMENT_NUMBER, AEWF_WRONG_SEGMENT_FILE_COUNT, AEWF_VOLUME_MUST_PRECEDE_TABLES, AEWF_SECTORS_MUST_PRECEDE_TABLES, AEWF_WRONG_CHUNK_COUNT, // 110 AEWF_READ_BEYOND_IMAGE_LENGTH, AEWF_CHUNK_NOT_FOUND, AEWF_VOLUME_MISSING, AEWF_ERROR_EWF_TABLE_NOT_READY, AEWF_ERROR_EWF_SEGMENT_NOT_READY, // 115 AEWF_CHUNK_TOO_BIG, AEWF_UNCOMPRESS_FAILED, AEWF_BAD_UNCOMPRESSED_LENGTH, AEWF_CHUNK_CRC_ERROR, AEWF_ERROR_IN_CHUNK_NUMBER, // 120 AEWF_VASPRINTF_FAILED, AEWF_UNCOMPRESS_HEADER_FAILED, AEWF_ASPRINTF_FAILED, }; #endif diff --git a/trunk/libxmount_input/libxmount_input_dd/CMakeLists.txt b/trunk/libxmount_input/libxmount_input_dd/CMakeLists.txt new file mode 100644 index 0000000..5b8dc1f --- /dev/null +++ b/trunk/libxmount_input/libxmount_input_dd/CMakeLists.txt @@ -0,0 +1,6 @@ +project(libxmount_input_dd) + +add_library(xmount_input_dd SHARED libxmount_input_dd.c) + +install(TARGETS xmount_input_dd DESTINATION lib/xmount) + diff --git a/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.c b/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.c index fd2af78..4ac8c91 100644 --- a/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.c +++ b/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.c @@ -1,346 +1,444 @@ /******************************************************************************* * xmount Copyright (c) 2008-2013 by Gillen Daniel * * * * This module has been written by Guy Voncken. It contains the functions for * * accessing dd images. Split dd is supported as well. * * * * xmount is a small tool to "fuse mount" various harddisk image formats as dd, * * vdi, vhd or vmdk files and enable virtual write access to them. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include #include #include #include #include -#include "dd.h" +#include "../libxmount_input.h" + +#include "libxmount_input_dd.h" + +/******************************************************************************* + * Forward declarations + ******************************************************************************/ +int DdOpen(void **pp_handle, + const char **pp_filename_arr, + uint64_t filename_arr_len); +int DdSize(void *p_handle, + uint64_t *p_size); +int DdRead(void *p_handle, + uint64_t seek, + char *p_buf, + uint32_t count); +int DdClose(void **pp_handle); +int DdOptionsHelp(const char **pp_help); +int DdOptionsParse(void *p_handle, + char *p_options, + char **pp_error); +int DdGetInfofileContent(void *p_handle, + const char **pp_info_buf); +void DdFreeBuffer(void *p_buf); + +/******************************************************************************* + * LibXmount_Input API implementation + ******************************************************************************/ +/* + * LibXmount_Input_GetApiVersion + */ +uint8_t LibXmount_Input_GetApiVersion() { + return LIBXMOUNT_INPUT_API_VERSION; +} + +/* + * LibXmount_Input_GetSupportedFormats + */ +const char* LibXmount_Input_GetSupportedFormats() { + return "dd\0\0"; +} + +/* + * LibXmount_Input_GetFunctions + */ +void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions) { + p_functions->Open=&DdOpen; + p_functions->Size=&DdSize; + p_functions->Read=&DdRead; + p_functions->Close=&DdClose; + p_functions->OptionsHelp=&DdOptionsHelp; + p_functions->OptionsParse=&DdOptionsParse; + p_functions->GetInfofileContent=&DdGetInfofileContent; + p_functions->FreeBuffer=&DdFreeBuffer; +} + +/******************************************************************************* + * Private + ******************************************************************************/ // ---------------------- // Constant definitions // ---------------------- #define GETMAX(a,b) ((a)>(b)?(a):(b)) #define GETMIN(a,b) ((a)<(b)?(a):(b)) // --------------------- // Types and strutures // --------------------- typedef struct { char *pFilename; unsigned long long FileSize; FILE *pFile; } t_Piece, *t_pPiece; typedef struct _t_dd { t_pPiece pPieceArr; unsigned int Pieces; unsigned long long TotalSize; char *pInfo; } t_dd; // ---------------- // Error handling // ---------------- #ifdef DD_DEBUG #define CHK(ChkVal) \ { \ int ChkValRc; \ if ((ChkValRc=(ChkVal)) != DD_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)) != DD_OK) \ return ChkValRc; \ } #define DEBUG_PRINTF(...) #endif // --------------------------- // Internal static functions // --------------------------- -static inline unsigned long long ddGetCurrentSeekPos (t_pPiece pPiece) +static inline unsigned long long DdGetCurrentSeekPos (t_pPiece pPiece) { return ftello (pPiece->pFile); } -static inline int ddSetCurrentSeekPos (t_pPiece pPiece, unsigned long long Val, int Whence) +static inline int DdSetCurrentSeekPos (t_pPiece pPiece, unsigned long long Val, int Whence) { if (fseeko (pPiece->pFile, Val, Whence) != 0) return DD_CANNOT_SEEK; return DD_OK; } -int ddDestroyHandle (t_pdd *ppdd) +int DdDestroyHandle (t_pdd *ppdd) { t_pdd pdd = *ppdd; t_pPiece pPiece; int CloseErrors = 0; if (pdd->pPieceArr) { for (int i=0; i < pdd->Pieces; i++) { pPiece = &pdd->pPieceArr[i]; if (pPiece->pFile) if (fclose (pPiece->pFile)) CloseErrors++; if (pPiece->pFilename) free (pPiece->pFilename); } free (pdd->pPieceArr); } if (pdd->pInfo) free (pdd->pInfo); free (pdd); *ppdd = NULL; if (CloseErrors) return DD_CANNOT_CLOSE_FILE; return DD_OK; } -static int ddCreateHandle (t_pdd *ppdd, unsigned FilenameArrLen, const char **ppFilenameArr) +static int DdCreateHandle (t_pdd *ppdd, unsigned FilenameArrLen, const char **ppFilenameArr) { t_pdd pdd; t_pPiece pPiece; *ppdd = NULL; pdd = (t_pdd) malloc (sizeof(t_dd)); if (pdd == NULL) return DD_MEMALLOC_FAILED; memset (pdd, 0, sizeof(t_dd)); pdd->Pieces = FilenameArrLen; pdd->pPieceArr = (t_pPiece) malloc (pdd->Pieces * sizeof(t_Piece)); if (pdd->pPieceArr == NULL) { - (void) ddDestroyHandle (&pdd); + (void) DdDestroyHandle (&pdd); return DD_MEMALLOC_FAILED; } pdd->TotalSize = 0; for (int i=0; i < pdd->Pieces; i++) { pPiece = &pdd->pPieceArr[i]; pPiece->pFilename = strdup (ppFilenameArr[i]); if (pPiece->pFilename == NULL) { - (void) ddDestroyHandle (&pdd); + (void) DdDestroyHandle (&pdd); return DD_MEMALLOC_FAILED; } pPiece->pFile = fopen (pPiece->pFilename, "r"); if (pPiece->pFile == NULL) { - (void) ddDestroyHandle (&pdd); + (void) DdDestroyHandle (&pdd); return DD_FILE_OPEN_FAILED; } - CHK(ddSetCurrentSeekPos(pPiece, 0, SEEK_END)) - pPiece->FileSize = ddGetCurrentSeekPos (pPiece); + CHK(DdSetCurrentSeekPos(pPiece, 0, SEEK_END)) + pPiece->FileSize = DdGetCurrentSeekPos (pPiece); pdd->TotalSize += pPiece->FileSize; } asprintf (&pdd->pInfo, "dd image made of %u pieces, %llu bytes in total (%0.3f GiB)", pdd->Pieces, pdd->TotalSize, pdd->TotalSize / (1024.0*1024.0*1024.0)); *ppdd = pdd; return DD_OK; } // --------------- // API functions // --------------- -int ddOpen (t_pdd *ppdd, unsigned FilenameArrLen, const char **pFilenameArr) +/* + * DdOpen + */ +int DdOpen(void **pp_handle, + const char **pp_filename_arr, + uint64_t filename_arr_len) { - CHK (ddCreateHandle (ppdd, FilenameArrLen, pFilenameArr)) - - return DD_OK; + CHK(DdCreateHandle((t_pdd*)pp_handle,filename_arr_len,pp_filename_arr)) + return DD_OK; } -int ddSize (t_pdd pdd, unsigned long long *pSize) -{ - *pSize = pdd->TotalSize; - - return DD_OK; +/* + * DdSize + */ +int DdSize(void *p_handle, uint64_t *p_size) { + *p_size=((t_pdd)p_handle)->TotalSize; + return DD_OK; } -int ddRead0 (t_pdd pdd, unsigned long long Seek, unsigned char *pBuffer, unsigned int *pCount) +/* + * DdRead0 + */ +int DdRead0 (t_pdd pdd, uint64_t Seek, char *pBuffer, uint32_t *pCount) { t_pPiece pPiece; int i; // Find correct piece to read from // ------------------------------- for (i=0; iPieces; i++) { pPiece = &pdd->pPieceArr[i]; if (Seek < pPiece->FileSize) break; Seek -= pPiece->FileSize; } if (i >= pdd->Pieces) return DD_READ_BEYOND_END_OF_IMAGE; // Read from this piece // -------------------- - CHK (ddSetCurrentSeekPos (pPiece, Seek, SEEK_SET)) + CHK (DdSetCurrentSeekPos (pPiece, Seek, SEEK_SET)) *pCount = GETMIN (*pCount, pPiece->FileSize - Seek); if (fread (pBuffer, *pCount, 1, pPiece->pFile) != 1) return DD_CANNOT_READ_DATA; return DD_OK; } - -int ddRead (t_pdd pdd, unsigned long long Seek, unsigned char *pBuffer, unsigned int Count) +/* + * DdRead + */ +int DdRead(void *p_handle, + uint64_t seek, + char *p_buf, + uint32_t count) { - unsigned Remaining = Count; - unsigned Read; + uint32_t remaining=count; + uint32_t read; + + if((seek+count)>((t_pdd)p_handle)->TotalSize) { + return DD_READ_BEYOND_END_OF_IMAGE; + } + + do { + read=remaining; + CHK(DdRead0((t_pdd)p_handle,seek,p_buf,&read)) + remaining-=read; + p_buf+=read; + seek+=read; + } while(remaining); + + return DD_OK; +} - if ((Seek + Count) > pdd->TotalSize) - return DD_READ_BEYOND_END_OF_IMAGE; +/* + * DdInfo + */ +int DdGetInfofileContent(void *p_handle, const char **pp_info_buf) { + *pp_info_buf=((t_pdd)p_handle)->pInfo; + return DD_OK; +} - do - { - Read = Remaining; - CHK (ddRead0 (pdd, Seek, pBuffer, &Read)) - Remaining -= Read; - pBuffer += Read; - Seek += Read; - } while (Remaining); +/* + * DdClose + */ +int DdClose(void **pp_handle) { + CHK (DdDestroyHandle((t_pdd*)pp_handle)) + return DD_OK; +} - return DD_OK; +/* + * DdOptionsHelp + */ +int DdOptionsHelp(const char **pp_help) { + *pp_help=NULL; + return DD_OK; } -int ddInfo (t_pdd pdd, char **ppInfoBuff) -{ - *ppInfoBuff = pdd->pInfo; - return DD_OK; +/* + * DdOptionsParse + */ +int DdOptionsParse(void *p_handle, char *p_options, char **pp_error) { + return DD_OK; } -int ddClose (t_pdd *ppdd) -{ - CHK (ddDestroyHandle(ppdd)) - return DD_OK; +/* + * DdFreeBuffer + */ +void DdFreeBuffer(void *p_buf) { + free(p_buf); } // ----------------------------------------------------- // Small main routine for testing // It a split dd file to non-split dd // ----------------------------------------------------- #ifdef DD_MAIN_FOR_TESTING int main(int argc, const char *argv[]) { t_pdd pdd; - unsigned long long TotalSize; - unsigned long long Remaining; - unsigned long long Read; - unsigned long long Pos; - unsigned int BuffSize = 1024; - unsigned char Buff[BuffSize]; + uint64_t TotalSize; + uint64_t Remaining; + uint64_t Read; + uint64_t Pos; + uint32_t BuffSize = 1024; + char Buff[BuffSize]; FILE *pFile; int Percent; int PercentOld; int rc; printf ("Split DD to DD converter\n"); if (argc < 3) { printf ("Usage: %s
<...>
\n", argv[0]); exit (1); } - if (ddOpen (&pdd, argc-2, &argv[1]) != DD_OK) + if (DdOpen ((void**)&pdd, argc-2, &argv[1]) != DD_OK) { printf ("Cannot open split dd file\n"); exit (1); } - CHK (ddSize (pdd, &TotalSize)) + CHK (DdSize ((void*)pdd, &TotalSize)) printf ("Total size: %llu bytes\n", TotalSize); Remaining = TotalSize; pFile = fopen (argv[argc-1], "w"); if (pFile == NULL) { printf ("Cannot open destination file\n"); exit (1); } Remaining = TotalSize; Pos = 0; PercentOld = -1; while (Remaining) { Read = GETMIN (Remaining, BuffSize); - rc = ddRead (pdd, Pos, &Buff[0], Read); + rc = DdRead ((void*)pdd, Pos, &Buff[0], Read); if (rc != DD_OK) { - printf ("Error %d while calling ddRead\n", rc); + printf ("Error %d while calling DdRead\n", rc); exit (1); } if (fwrite (Buff, Read, 1, pFile) != 1) { printf ("Could not write to destinationfile\n"); exit (2); } Remaining -= Read; Pos += Read; Percent = (100*Pos) / TotalSize; if (Percent != PercentOld) { printf ("\r%d%% done...", Percent); PercentOld = Percent; } } if (fclose (pFile)) { printf ("Error while closing destinationfile\n"); exit (3); } printf ("\n"); return 0; } #endif + diff --git a/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.h b/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.h index da64c94..126fe4f 100644 --- a/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.h +++ b/trunk/libxmount_input/libxmount_input_dd/libxmount_input_dd.h @@ -1,51 +1,44 @@ /******************************************************************************* * xmount Copyright (c) 2008-2013 by Gillen Daniel * * * * This module has been written by Guy Voncken. It contains the functions for * * accessing dd images. Split dd is supported as well. * * * * 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 . * *******************************************************************************/ #ifndef DD_H #define DD_H typedef struct _t_dd *t_pdd; -int ddOpen (t_pdd *ppdd, unsigned FilenameArrLen, const char **pFilenameArr); -int ddInfo (t_pdd pdd, char **ppInfoBuff); -int ddSize (t_pdd pdd, unsigned long long *pSize); -int ddRead (t_pdd pdd, unsigned long long Seek, unsigned char *pBuffer, unsigned int Count); -int ddClose (t_pdd *ppdd); - - // Possible error codes enum { DD_OK = 0, DD_FOUND, DD_MEMALLOC_FAILED=100, DD_FILE_OPEN_FAILED, DD_CANNOT_READ_DATA, DD_CANNOT_CLOSE_FILE, DD_CANNOT_SEEK, DD_READ_BEYOND_END_OF_IMAGE }; #endif diff --git a/trunk/libxmount_input/libxmount_input_ewf/CMakeLists.txt b/trunk/libxmount_input/libxmount_input_ewf/CMakeLists.txt index f9f35e5..ade5dd2 100644 --- a/trunk/libxmount_input/libxmount_input_ewf/CMakeLists.txt +++ b/trunk/libxmount_input/libxmount_input_ewf/CMakeLists.txt @@ -1,7 +1,9 @@ -cmake_minimum_required(VERSION 2.8) project(libxmount_input_ewf) + add_library(xmount_input_ewf SHARED libxmount_input_ewf.c) -install(TARGETS xmount_input_ewf DESTINATION lib/xmount) include_directories(${LIBEWF_INCLUDE_DIRS}) set(LIBS ${LIBS} ${LIBEWF_LIBRARIES}) target_link_libraries(xmount_input_ewf ${LIBS}) + +install(TARGETS xmount_input_ewf DESTINATION lib/xmount) + diff --git a/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c b/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c index ec095d4..a514869 100644 --- a/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c +++ b/trunk/libxmount_input/libxmount_input_ewf/libxmount_input_ewf.c @@ -1,301 +1,284 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * xmount is a small tool to "fuse mount" various image formats and enable * * virtual write access. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #undef HAVE_LIBEWF_STATIC #include #include #include "../libxmount_input.h" #ifndef HAVE_LIBEWF_STATIC #include #else #include "libewf/include/libewf.h" #endif #if !defined(LIBEWF_HANDLE) // libewf version 2 no longer defines LIBEWF_HANDLE #define HAVE_LIBEWF_V2_API #endif /******************************************************************************* * Forward declarations ******************************************************************************/ int EwfOpen(void **pp_handle, const char **pp_filename_arr, uint64_t filename_arr_len); int EwfSize(void *p_handle, uint64_t *p_size); int EwfRead(void *p_handle, uint64_t seek, char *p_buf, uint32_t count); int EwfClose(void **pp_handle); int EwfOptionsHelp(const char **pp_help); int EwfOptionsParse(void *p_handle, char *p_options, char **pp_error); int EwfGetInfofileContent(void *p_handle, const char **pp_info_buf); void EwfFreeBuffer(void *p_buf); /******************************************************************************* * LibXmount_Input API implementation ******************************************************************************/ /* * LibXmount_Input_GetApiVersion */ uint8_t LibXmount_Input_GetApiVersion() { return LIBXMOUNT_INPUT_API_VERSION; } /* * LibXmount_Input_GetSupportedFormats */ const char* LibXmount_Input_GetSupportedFormats() { -/* - // Alloc array containing 1 element with content "ewf" - *ppp_arr=(char**)malloc(sizeof(char*)); - if(*ppp_arr==NULL) { - *p_arr_len=0; - return; - } - **ppp_arr=(char*)malloc(sizeof(char)*4); - if(**ppp_arr==NULL) { - free(*ppp_arr); - *ppp_arr=NULL; - *p_arr_len=0; - return; - } - strcpy(**ppp_arr,"ewf"); - *p_arr_len=1; -*/ return "ewf\0\0"; } /* * LibXmount_Input_GetFunctions */ void LibXmount_Input_GetFunctions(ts_LibXmountInputFunctions *p_functions) { p_functions->Open=&EwfOpen; p_functions->Size=&EwfSize; p_functions->Read=&EwfRead; p_functions->Close=&EwfClose; p_functions->OptionsHelp=&EwfOptionsHelp; p_functions->OptionsParse=&EwfOptionsParse; p_functions->GetInfofileContent=&EwfGetInfofileContent; p_functions->FreeBuffer=&EwfFreeBuffer; } /******************************************************************************* * Private ******************************************************************************/ /* * EwfOpen */ int EwfOpen(void **pp_handle, const char **pp_filename_arr, uint64_t filename_arr_len) { // We need at least one file if(filename_arr_len==0) return 1; // Make sure all files are EWF files for(uint64_t i=0;i