File: aaff.cpp

package info (click to toggle)
guymager 0.4.2-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 932 kB
  • ctags: 1,580
  • sloc: cpp: 8,522; ansic: 2,571; makefile: 49; sh: 23
file content (355 lines) | stat: -rw-r--r-- 11,215 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// ****************************************************************************
//  Project:        GUYMAGER
// ****************************************************************************
//  Programmer:     Guy Voncken
//                  Police Grand-Ducale
//                  Service de Police Judiciaire
//                  Section Nouvelles Technologies
// ****************************************************************************
//  Module:         Multithreaded AFF (AAFF = Avanced AFF)
// ****************************************************************************

#include "common.h"
#include "compileinfo.h"

#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <zlib.h>

#include <QString>

#include "util.h"
#include "config.h"
#include "aaff.h"

// -----------------
//  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 AFF_PAGEFLAGS_UNCOMPRESSED    0x0000
#define AFF_PAGEFLAGS_COMPRESSED_ZLIB 0x0001
#define AFF_PAGEFLAGS_COMPRESSED_ZERO 0x0033    // Compressed, Zero and MaxCompression

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.
} t_AffSegmentHeader;

// Between header and footer lie the segment name and the data

typedef struct
{
   char         Magic[4];
   unsigned int SegmentLen;
} t_AffSegmentFooter;


// ------------------
//  Aaff definitions
// ------------------

typedef struct _t_Aaff
{
   FILE               *pFile;
   unsigned long long   PagesWritten;

   t_AffSegmentHeader   SegmentHeader;  // Optimisation: This header and this footer only need to be
   t_AffSegmentFooter   SegmentFooter;  // allocated and initialised once, and can be used again and again
} t_Aaff;

#define AAFF_MD5_LEN                16
#define AAFF_SHA256_LEN             32
#define AAFF_BADSECTORMARKER_MAXLEN 65536
unsigned char AaffBadSectorMarker[AAFF_BADSECTORMARKER_MAXLEN];

// ----------------
//  Error handling
// ----------------

#define CHK_FWRITE(Fn)                    \
   if ((Fn) != 1)                         \
      CHK (ERROR_AAFF_CANNOT_WRITE_FILE)


// -------------------
//  Utility functions
// -------------------

static bool AaffIsZero (unsigned char *pData, int DataLen)
{
   long long *pBuff    = (long long *)pData;
   const int   CmpSize = sizeof (long long);   // 64 bit operations for optimal performance on amd64 processors

   while (DataLen >= CmpSize)
   {
      if (*pBuff++)
        return false;
      DataLen -= CmpSize;
   }

   pData = (unsigned char *) pBuff;
   while (DataLen--)
   {
      if (*pData++)
         return false;
   }

   return true;
}

// -------------------
//  Segment functions
// -------------------

static APIRET AaffWriteSegment (t_pAaff pAaff, const char *pName, unsigned int Argument, const unsigned char *pData, unsigned int DataLen)
{
   int NameLen0 = strlen(pName);

   pAaff->SegmentHeader.NameLen    = htonl(NameLen0);
   pAaff->SegmentHeader.DataLen    = htonl(DataLen);
   pAaff->SegmentHeader.Argument   = htonl(Argument);
   pAaff->SegmentFooter.SegmentLen = htonl(sizeof(t_AffSegmentHeader) + sizeof(t_AffSegmentFooter) + NameLen0 + DataLen);

   CHK_FWRITE(fwrite (&pAaff->SegmentHeader, sizeof(t_AffSegmentHeader), 1, pAaff->pFile))
   CHK_FWRITE(fwrite (pName, NameLen0, 1, pAaff->pFile))
   if (pData && DataLen)
      CHK_FWRITE(fwrite (pData, DataLen, 1, pAaff->pFile))
   CHK_FWRITE(fwrite (&pAaff->SegmentFooter, sizeof(t_AffSegmentFooter), 1, pAaff->pFile))

   return NO_ERROR;
}

APIRET AaffWriteSegmentStr (t_pAaff pAaff, const char *pName, unsigned int Argument, const char *pStr)
{
   CHK (AaffWriteSegment (pAaff, pName, Argument, (const unsigned char *) pStr, strlen (pStr)))
   return NO_ERROR;
}

static APIRET AaffWriteSegmentArg (t_pAaff pAaff, const char *pName, unsigned int Argument)
{
   CHK (AaffWriteSegment (pAaff, pName, Argument, NULL, 0))
   return NO_ERROR;
}

static APIRET AaffWriteSegmentU64 (t_pAaff pAaff, const char *pName, unsigned long long Value)
{
   unsigned int Data[2];

   Data[0] = htonl ((unsigned int)(Value &  0xFFFFFFFF));
   Data[1] = htonl ((unsigned int)(Value >> 32));

   CHK (AaffWriteSegment (pAaff, pName, AFF_SEGARG_U64, (unsigned char *)&Data[0], sizeof(Data)))

   return NO_ERROR;
}

static APIRET AaffWriteSegmentGID (t_pAaff pAaff)
{
   unsigned char GID[AFF_GID_LENGTH];
   int           i;

   for (i=0; i<AFF_GID_LENGTH; i++)
      GID[i] = (unsigned char) random();

   CHK (AaffWriteSegment (pAaff, AFF_SEGNAME_GID, 0, GID, AFF_GID_LENGTH))

   return NO_ERROR;
}


// ---------------
//  API functions
// ---------------

APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long DeviceSize, unsigned int SectorSize, unsigned int PageSize)
{
   t_pAaff pAaff;
   char     Buff[512];

   // Open file and intialise
   // -----------------------
   if (SectorSize > AAFF_BADSECTORMARKER_MAXLEN)
      CHK (ERROR_AAFF_SECTORSIZE_TOO_BIG)

   *ppAaff = NULL;
   pAaff = (t_pAaff) UTIL_MEM_ALLOC(sizeof(t_Aaff));
   if (pAaff == NULL)
      CHK (ERROR_AAFF_MEMALLOC_FAILED)

   pAaff->pFile = fopen64 (pFilename, "w");
   if (pAaff->pFile == NULL)
   {
      UTIL_MEM_FREE (pAaff);
      CHK (ERROR_AAFF_CANNOT_CREATE_FILE)
   }
   *ppAaff = pAaff;

   CHK_FWRITE(fwrite (AFF_HEADER, sizeof(AFF_HEADER), 1, pAaff->pFile))

   pAaff->PagesWritten = 0;
   memset (&pAaff->SegmentHeader, 0, sizeof (t_AffSegmentHeader));
   memset (&pAaff->SegmentFooter, 0, sizeof (t_AffSegmentFooter));
   strcpy (&pAaff->SegmentHeader.Magic[0], AFF_SEGMENT_HEADER_MAGIC);
   strcpy (&pAaff->SegmentFooter.Magic[0], AFF_SEGMENT_FOOTER_MAGIC);

   // Write standard segments
   // -----------------------
   snprintf (&Buff[0], sizeof(Buff), "aaff module of Guymager %s", pCompileInfoVersion);
   CHK (AaffWriteSegmentGID (pAaff))
   if CONFIG (AffMarkBadSectors)
      CHK (AaffWriteSegment (pAaff, AFF_SEGNAME_BADFLAG       , 0, AaffBadSectorMarker, SectorSize))
   CHK (AaffWriteSegmentStr (pAaff, AFF_SEGNAME_AFFLIB_VERSION, 0, &Buff[0]))
   CHK (AaffWriteSegmentStr (pAaff, AFF_SEGNAME_FILETYPE      , 0, AFF_FILE_TYPE))
   CHK (AaffWriteSegmentArg (pAaff, AFF_SEGNAME_PAGESIZE      , PageSize))
   CHK (AaffWriteSegmentArg (pAaff, AFF_SEGNAME_SECTORSIZE    , SectorSize))
   CHK (AaffWriteSegmentU64 (pAaff, AFF_SEGNAME_SECTORS       , DeviceSize / SectorSize))
   CHK (AaffWriteSegmentU64 (pAaff, AFF_SEGNAME_IMAGESIZE     , DeviceSize))

   return NO_ERROR;
}

APIRET AaffClose (t_pAaff pAaff, unsigned long long BadSectors, unsigned char *pMD5, unsigned char *pSHA256, int Duration)
{
   CHK (AaffWriteSegmentU64 (pAaff, AFF_SEGNAME_BADSECTORS  , BadSectors))
   CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_MD5         , 0, pMD5   , AAFF_MD5_LEN   ))
   CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_SHA256      , 0, pSHA256, AAFF_SHA256_LEN))
   CHK (AaffWriteSegmentArg (pAaff, AFF_SEGNAME_DURATION    , Duration))

   if (fflush (pAaff->pFile))
   {
      (void) fclose (pAaff->pFile);
      CHK (ERROR_AAFF_CANNOT_FLUSH_FILE)
   }

   if (fclose (pAaff->pFile))
      CHK (ERROR_AAFF_CANNOT_CLOSE_FILE)

   return NO_ERROR;
}

APIRET AaffPreprocess (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, unsigned int DataLenOut)
{
   t_pAaffPreprocess pPreProcess;
   int                rc;
   uLongf             LenOut;

   *ppPreprocess = NULL;
   pPreProcess = (t_pAaffPreprocess) UTIL_MEM_ALLOC(sizeof(t_AaffPreprocess));
   if (pPreProcess == NULL)
      CHK (ERROR_AAFF_MEMALLOC_FAILED)
   *ppPreprocess = pPreProcess;
   pPreProcess->Zero       = false;
   pPreProcess->Compressed = false;

   // Check if zero
   // -------------
   pPreProcess->Zero = AaffIsZero (pDataIn, DataLenIn);
   if (pPreProcess->Zero)
      return NO_ERROR;

   // Try compression
   // ---------------
   LenOut = DataLenOut;
   rc = compress2 ((Bytef *)pDataOut, &LenOut, (Bytef *)pDataIn, DataLenIn, CONFIG (AffCompression));
   pPreProcess->DataLenOut = LenOut;
   if (rc != Z_OK)
   {
      if (rc != Z_BUF_ERROR)    // Do not log this one (the destination buffer was too small for the compressed result)
         LOG_ERROR ("compress2 returned %d", rc)
      return NO_ERROR;
   }

   pPreProcess->Compressed = (LenOut < DataLenIn);

   return NO_ERROR;
}

APIRET AaffWrite (t_pAaff pAaff, t_pAaffPreprocess pPreprocess, unsigned char *pData, unsigned int DataLen)
{
   char SegmentName[64];

   snprintf (&SegmentName[0], sizeof(SegmentName), "%s%llu", AFF_SEGNAME_PAGE, pAaff->PagesWritten++);

   if (pPreprocess->Zero)
   {
      int Len = htonl(DataLen);
      CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_COMPRESSED_ZERO, (unsigned char *) &Len, 4))
   }
   else if (pPreprocess->Compressed)
      CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_COMPRESSED_ZLIB, pData, pPreprocess->DataLenOut))
   else
      CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_UNCOMPRESSED   , pData, DataLen))

   UTIL_MEM_FREE (pPreprocess);

   return NO_ERROR;
}

APIRET AaffCopyBadSectorMarker (unsigned char *pBuffer, unsigned int Len)
{
   if (Len > AAFF_BADSECTORMARKER_MAXLEN)
      CHK (ERROR_AAFF_SECTORSIZE_TOO_BIG)

   memcpy (pBuffer, &AaffBadSectorMarker[0], Len);

   return NO_ERROR;
}

// -----------------------
//  Module initialisation
// -----------------------

APIRET AaffInit (void)
{
   int i;

   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_MEMALLOC_FAILED   ))
   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CREATE_FILE))
   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_WRITE_FILE ))
   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CLOSE_FILE ))
   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_FLUSH_FILE ))
   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_SECTORSIZE_TOO_BIG))
   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_COMPRESSION_FAILED))

   srandom (time (0));

   for (i=0; i<AAFF_BADSECTORMARKER_MAXLEN; i++)
      AaffBadSectorMarker[i] = (char)random();
   strcpy ((char *)AaffBadSectorMarker, AFF_BADSECTOR_HEADER);

   return NO_ERROR;
}

APIRET AaffDeInit (void)
{
   return NO_ERROR;
}