const uint64_t AEWF_DEFAULT_THREADS = 4; // There normally is no sense in using higher values, as - according to out statistics - we never get called for reading
// more than 128k of data (there's only 1 exception: the very 1st read request from xmount itself). With the default EWF
// chunk size of 32K, 4 threads are enough for running the whole decompression in parallel.
// ----------------------------
// Logging and error handling
// ----------------------------
#define LOG_HEADER_LEN 80
int LogvEntry (const char *pLogPath, uint8_t LogStdout, const char *pFileName, const char *pFunctionName, int LineNr, const char *pFormat, va_list pArguments)
// 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. But this line could lead to reading beyond EOF...
if (ReadLen > pAewf->ChunkBuffSize)
{
LOG ("Chunk too big %u / %u", ReadLen, pAewf->ChunkBuffSize);
return AEWF_CHUNK_TOO_BIG;
}
ChunkSize = pAewf->ChunkSize;
if (AbsoluteChunk == (pAewf->Chunks-1)) // The very last chunk of the image may be smaller than the default
{ // chunk size if the image isn't a multiple of the chunk size.
// 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. But this line could lead to reading beyond EOF...
if (ReadLen > pAewf->ChunkBuffSize)
{
LOG ("Chunk too big %u / %u", ReadLen, pAewf->ChunkBuffSize);
CHK (AEWF_CHUNK_TOO_BIG)
}
ChunkSize = pAewf->ChunkSize;
if (AbsoluteChunk == (pAewf->Chunks-1)) // The very last chunk of the image may be smaller than the default
{ // chunk size if the image isn't a multiple of the chunk size.
ChunkSize = pAewf->ImageSize % pAewf->ChunkSize;
if (ChunkSize == 0)
ChunkSize = pAewf->ChunkSize;
}
for (int i=0; i<pAewf->Threads; i++)
{
t_pAewfThread pThread = &(pAewf->pThreadArr[i]);
if (pThread->State == AEWF_IDLE)
{
pThread->State = AEWF_LAUNCHED;
pThread->ChunkBuffCompressedDataLen = ReadLen;
pThread->ChunkBuffUncompressedDataLen = ChunkSize; // uncompress should return this size (if it's a compressed chunk)
pThread->ChunkInBuff = AbsoluteChunk;
pThread->pBuf = pBuf; // These 3 parameters specify which part
pThread->Ofs = Ofs; // of the resulting chunk data should be
LOG ("Maybe some segment files are missing. Perhaps you specified E01 instead of E?? or the segments continue beyond extension .EZZ.");
return AEWF_WRONG_CHUNK_COUNT;
}
pAewf->ChunkBuffSize = pAewf->ChunkSize + 4096; // reserve some extra space (for CRC and as compressed data might be slightly larger than uncompressed data with some imagers)
FILE *pFile; // NULL if file is not opened (never read or kicked out form cache)
time_t LastUsed;
} t_Segment, *t_pSegment;
typedef struct
{
uint64_t Nr; // The table's position in the pAewf->pTableArr, for debug output only
uint64_t ChunkFrom; // Number of the chunk referred to by the first entry of this table (very first chunk has number 0)
uint64_t ChunkTo; // Number of the chunk referred to by the last entry of this table
t_pSegment pSegment; // The file segment where the table is located
uint64_t Offset; // The offset of the table inside the segment file (start of t_AewfSectionTable, not of the preceding t_AewfSection)
unsigned long Size; // The length of the table (same as allocated length for pEwfTable)
uint32_t ChunkCount; // The number of chunk; this is the same as pTableData->Chunkcount, however, pTableData might not be available (NULL)
uint64_t SectionSectorsPos; // Seek position of corresponding section SECTORS in segment file and its length. Silly EWF format has no clean way
uint32_t SectionSectorsSize; // of determining size of the last (possibly compressed) chunk of a table, that's why we need to memorise these values.
time_t LastUsed; // Last usage of this table, for cache management
t_pAewfSectionTable pEwfTable; // Contains the original EWF table section or NULL, if never read or kicked out from cache
} t_Table, *t_pTable;
#define AEWF_NONE UINT64_MAX
enum
{
READSIZE_32K = 0,
READSIZE_64K,
READSIZE_128K,
READSIZE_256K,
READSIZE_512K,
READSIZE_1M,
READSIZE_ABOVE_1M,
READSIZE_ARRLEN
};
typedef enum
{
AEWF_IDLE = 0,
AEWF_LAUNCHED
} t_AewfThreadState;
typedef struct _t_AewfThread
{
t_AewfThreadState State;
t_pcAewf pAewf; // Give the threads access to some Aewf constants - make sure the threads only have read access
pthread_t ID;
char *pChunkBuffCompressed;
uint64_t ChunkBuffCompressedDataLen;
char *pChunkBuffUncompressed; // This buffer serves as cache as well. ChunkInBuff contains the absolute chunk number whose data is stored here
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
uint64_t ChunkInBuff;
char *pBuf; // Job arguments to the thread: Copy the uncompressed
uint64_t Ofs; // chunk data starting at chunk offset Ofs to pBuf, Len
uint64_t Len; // bytes in total.
int ReturnCode;
} t_AewfThread, *t_pAewfThread;
typedef struct _t_Aewf
{
t_pSegment pSegmentArr; // Array of all segment files (in correct order)
t_pTable pTableArr; // Array of all chunk offset tables found in the segment files (in correct order)
uint64_t Segments;
uint64_t Tables;
uint64_t Chunks; // Total number of chunks in all tables
uint64_t TotalTableSize; // Total size of all tables
uint64_t TableCache; // Current amount RAM used by tables, in bytes
uint64_t OpenSegments; // Current number of open segment files
uint64_t SectorSize;
uint64_t Sectors;
uint64_t ChunkSize;
uint64_t ImageSize; // Equals to Sectors * SectorSize
char *pChunkBuffCompressed;
char *pChunkBuffUncompressed;
uint64_t ChunkBuffUncompressedDataLen; // This normally always is equal to the chunk size (32K), except maybe for the last chunk, if the image's total size is not a multiple of the chunk size
uint32_t ChunkBuffSize;
uint64_t ChunkInBuff; // Chunk currently residing in pChunkBuffUncompressed (AEWF_NONE if none)
char *pErrorText; // Used for assembling error text during option parsing
time_t LastStatsUpdate;
char *pInfo;
t_pAewfThread pThreadArr;
// Statistics
uint64_t SegmentCacheHits;
uint64_t SegmentCacheMisses;
uint64_t TableCacheHits;
uint64_t TableCacheMisses;
uint64_t ChunkCacheHits;
uint64_t ChunkCacheMisses;
uint64_t ReadOperations; // How many times did xmount call the function AewfRead
uint64_t DataReadFromImage; // The data (in bytes) read from the image
uint64_t DataReadFromImageRaw; // The same data (in bytes), after uncompression (if any)
uint64_t DataRequestedByCaller; // How much data was given back to the caller
uint64_t TablesReadFromImage; // The overhead of the table read operations (in bytes)
uint64_t ChunksRead;
uint64_t BytesRead;
uint64_t ReadSizesArr[READSIZE_ARRLEN]; // Distribution of the requested block sites to be read
uint64_t Errors;
int LastError;
// Options
uint64_t MaxTableCache; // Max. amount of bytes in pTableArr[x].pTableData, in bytes
uint64_t MaxOpenSegments; // Max. number of open files in pSegmentArr
char *pStatsPath; // Statistics path
uint64_t StatsRefresh; // The time in seconds between update of the stats file
char *pLogPath; // Path for log file
uint8_t LogStdout;
uint64_t Threads; // Max. number of threads to be used in parallel actions. Currently only used for uncompression
} t_Aewf;
// ----------------
// Error codes
// ----------------
// AEWF Error codes are automatically mapped to errno codes by means of the groups
// below. AEWF uses these errno codes:
// ENOMEM memory allocation errors
// EINVAL wrong parameter(s) passed to an AEWF function
// EIO all others: AEWF function errors, EWF image errors