1 /*-
2 ***********************************************************************
3 *
4 * $Id: develop.c,v 1.52 2014/07/30 07:24:15 mavrik Exp $
5 *
6 ***********************************************************************
7 *
8 * Copyright 2000-2014 The FTimes Project, All Rights Reserved.
9 *
10 ***********************************************************************
11 */
12 #include "all-includes.h"
13
14 /*-
15 ***********************************************************************
16 *
17 * Defines
18 *
19 ***********************************************************************
20 */
21 #define COMPRESS_RECOVERY_RATE 100
22
23 static unsigned char gaucMd5ZeroHash[MD5_HASH_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
24 static unsigned char gaucSha1ZeroHash[SHA1_HASH_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
25 static unsigned char gaucSha256ZeroHash[SHA256_HASH_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
26
27 /*-
28 ***********************************************************************
29 *
30 * DevelopHaveNothingOutput
31 *
32 ***********************************************************************
33 */
34 int
DevelopHaveNothingOutput(FTIMES_PROPERTIES * psProperties,char * pcOutData,int * iWriteCount,FTIMES_FILE_DATA * psFTFileData,char * pcError)35 DevelopHaveNothingOutput(FTIMES_PROPERTIES *psProperties, char *pcOutData, int *iWriteCount, FTIMES_FILE_DATA *psFTFileData, char *pcError)
36 {
37 int i = 0;
38 int n = 0;
39 int m = 0;
40 int iMaskTableLength = MaskGetTableLength(MASK_RUNMODE_TYPE_MAP);
41 MASK_B2S_TABLE *psMaskTable = MaskGetTableReference(MASK_RUNMODE_TYPE_MAP);
42 unsigned long ul = 0;
43
44 /*-
45 *********************************************************************
46 *
47 * Loop over the mask table, and output a NULL value for each field
48 * that is set in the mask. Then, update the write count and return.
49 *
50 *********************************************************************
51 */
52 for (i = 0; i < iMaskTableLength; i++)
53 {
54 ul = (1 << i);
55 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, ul))
56 {
57 #ifdef WIN32
58 switch (ul)
59 {
60 case MAP_ATIME:
61 case MAP_MTIME:
62 case MAP_CTIME:
63 case MAP_CHTIME:
64 n += sprintf(&pcOutData[n], "||");
65 break;
66 default:
67 n += sprintf(&pcOutData[n], "|");
68 break;
69 }
70 #else
71 n += sprintf(&pcOutData[n], "|");
72 #endif
73 m += sprintf(&pcError[m], "%s%s", (i == 0) ? "" : ",", (char *) psMaskTable[i].acName);
74 }
75 }
76 n += sprintf(&pcOutData[n], "%s", psProperties->acNewLine);
77 *iWriteCount += n;
78
79 return ER_NullFields;
80 }
81
82
83 /*-
84 ***********************************************************************
85 *
86 * DevelopNoOutput
87 *
88 ***********************************************************************
89 */
90 int
DevelopNoOutput(FTIMES_PROPERTIES * psProperties,char * pcOutData,int * iWriteCount,FTIMES_FILE_DATA * psFTFileData,char * pcError)91 DevelopNoOutput(FTIMES_PROPERTIES *psProperties, char *pcOutData, int *iWriteCount, FTIMES_FILE_DATA *psFTFileData, char *pcError)
92 {
93 /*-
94 *********************************************************************
95 *
96 * Set the write count for the caller.
97 *
98 *********************************************************************
99 */
100 *iWriteCount = 0;
101
102 return ER_OK;
103 }
104
105
106 #ifdef UNIX
107 /*-
108 ***********************************************************************
109 *
110 * DevelopNormalOutput
111 *
112 ***********************************************************************
113 */
114 int
DevelopNormalOutput(FTIMES_PROPERTIES * psProperties,char * pcOutData,int * iWriteCount,FTIMES_FILE_DATA * psFTFileData,char * pcError)115 DevelopNormalOutput(FTIMES_PROPERTIES *psProperties, char *pcOutData, int *iWriteCount, FTIMES_FILE_DATA *psFTFileData, char *pcError)
116 {
117 char acTime[FTIMES_TIME_FORMAT_SIZE];
118 int n;
119 int iError;
120 int iStatus = ER_OK;
121
122 /*-
123 *********************************************************************
124 *
125 * This is required since only strcats are used below.
126 *
127 *********************************************************************
128 */
129 pcError[0] = 0;
130
131 /*-
132 *********************************************************************
133 *
134 * File Name = name
135 *
136 *********************************************************************
137 */
138 n = sprintf(pcOutData, "\"%s\"", psFTFileData->pcNeuteredPath);
139
140 /*-
141 *********************************************************************
142 *
143 * If there are no attributes to develop, just generate a series of
144 * NULL fields and return.
145 *
146 *********************************************************************
147 */
148 if (psFTFileData->ulAttributeMask == 0)
149 {
150 *iWriteCount = n;
151 return DevelopHaveNothingOutput(psProperties, &pcOutData[n], iWriteCount, psFTFileData, pcError);
152 }
153
154 /*-
155 *********************************************************************
156 *
157 * Device = dev
158 *
159 *********************************************************************
160 */
161 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_DEV))
162 {
163 n += sprintf(&pcOutData[n], "|%u", (unsigned) psFTFileData->sStatEntry.st_dev);
164 }
165
166 /*-
167 *********************************************************************
168 *
169 * Inode = inode
170 *
171 *********************************************************************
172 */
173 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_INODE))
174 {
175 n += sprintf(&pcOutData[n], "|%u", (unsigned) psFTFileData->sStatEntry.st_ino);
176 }
177
178 /*-
179 *********************************************************************
180 *
181 * Permissions and Mode = mode
182 *
183 *********************************************************************
184 */
185 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MODE))
186 {
187 n += sprintf(&pcOutData[n], "|%o", (unsigned) psFTFileData->sStatEntry.st_mode);
188 }
189
190 /*-
191 *********************************************************************
192 *
193 * Number of Links = nlink
194 *
195 *********************************************************************
196 */
197 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_NLINK))
198 {
199 n += sprintf(&pcOutData[n], "|%u", (unsigned) psFTFileData->sStatEntry.st_nlink);
200 }
201
202 /*-
203 *********************************************************************
204 *
205 * User ID = uid
206 *
207 *********************************************************************
208 */
209 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_UID))
210 {
211 n += sprintf(&pcOutData[n], "|%u", (unsigned) psFTFileData->sStatEntry.st_uid);
212 }
213
214 /*-
215 *********************************************************************
216 *
217 * Group ID = gid
218 *
219 *********************************************************************
220 */
221 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_GID))
222 {
223 n += sprintf(&pcOutData[n], "|%u", (unsigned) psFTFileData->sStatEntry.st_gid);
224 }
225
226 /*-
227 *********************************************************************
228 *
229 * Special Device Type = rdev
230 *
231 *********************************************************************
232 */
233 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_RDEV))
234 {
235 n += sprintf(&pcOutData[n], "|%u", (unsigned) psFTFileData->sStatEntry.st_rdev);
236 }
237
238 /*-
239 *********************************************************************
240 *
241 * Last Access Time = atime
242 *
243 *********************************************************************
244 */
245 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME))
246 {
247 iError = TimeFormatTime(&psFTFileData->sStatEntry.st_atime, acTime);
248 if (iError == ER_OK)
249 {
250 n += sprintf(&pcOutData[n], "|%s", acTime);
251 }
252 else
253 {
254 n += sprintf(&pcOutData[n], "|");
255 strcat(pcError, (pcError[0]) ? ",atime" : "atime");
256 iStatus = ER_NullFields;
257 }
258 }
259
260 /*-
261 *********************************************************************
262 *
263 * Last Modification Time = mtime
264 *
265 *********************************************************************
266 */
267 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MTIME))
268 {
269 iError = TimeFormatTime(&psFTFileData->sStatEntry.st_mtime, acTime);
270 if (iError == ER_OK)
271 {
272 n += sprintf(&pcOutData[n], "|%s", acTime);
273 }
274 else
275 {
276 n += sprintf(&pcOutData[n], "|");
277 strcat(pcError, (pcError[0]) ? ",mtime" : "mtime");
278 iStatus = ER_NullFields;
279 }
280 }
281
282 /*-
283 *********************************************************************
284 *
285 * Last Status Change Time = ctime
286 *
287 *********************************************************************
288 */
289 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_CTIME))
290 {
291 iError = TimeFormatTime(&psFTFileData->sStatEntry.st_ctime, acTime);
292 if (iError == ER_OK)
293 {
294 n += sprintf(&pcOutData[n], "|%s", acTime);
295 }
296 else
297 {
298 n += sprintf(&pcOutData[n], "|");
299 strcat(pcError, (pcError[0]) ? ",ctime" : "ctime");
300 iStatus = ER_NullFields;
301 }
302 }
303
304 /*-
305 *********************************************************************
306 *
307 * File Size = size
308 *
309 *********************************************************************
310 */
311 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SIZE))
312 {
313 #ifdef USE_AP_SNPRINTF
314 n += snprintf(&pcOutData[n], FTIMES_MAX_64BIT_SIZE, "|%qu", (unsigned long long) psFTFileData->sStatEntry.st_size);
315 #else
316 n += snprintf(&pcOutData[n], FTIMES_MAX_64BIT_SIZE, "|%llu", (unsigned long long) psFTFileData->sStatEntry.st_size);
317 #endif
318 }
319
320 /*-
321 *********************************************************************
322 *
323 * File MD5 = md5
324 *
325 *********************************************************************
326 */
327 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MD5))
328 {
329 #ifdef USE_PCRE
330 int iFilterIndex = n + 1;
331 #endif
332 pcOutData[n++] = '|';
333 if (S_ISDIR(psFTFileData->sStatEntry.st_mode))
334 {
335 if (psProperties->bHashDirectories)
336 {
337 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
338 {
339 n += MD5HashToHex(psFTFileData->aucFileMd5, &pcOutData[n]);
340 }
341 }
342 else
343 {
344 n += sprintf(&pcOutData[n], "DIRECTORY");
345 }
346 }
347 else if (S_ISREG(psFTFileData->sStatEntry.st_mode))
348 {
349 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
350 {
351 n += MD5HashToHex(psFTFileData->aucFileMd5, &pcOutData[n]);
352 }
353 else
354 {
355 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
356 iStatus = ER_NullFields;
357 }
358 }
359 else if (S_ISLNK(psFTFileData->sStatEntry.st_mode))
360 {
361 if (psProperties->bHashSymbolicLinks)
362 {
363 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
364 {
365 n += MD5HashToHex(psFTFileData->aucFileMd5, &pcOutData[n]);
366 }
367 else
368 {
369 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
370 iStatus = ER_NullFields;
371 }
372 }
373 else
374 {
375 n += sprintf(&pcOutData[n], "SYMLINK");
376 }
377 }
378 else
379 {
380 if (psProperties->bAnalyzeDeviceFiles && memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
381 {
382 n += MD5HashToHex(psFTFileData->aucFileMd5, &pcOutData[n]);
383 }
384 else
385 {
386 n += sprintf(&pcOutData[n], "SPECIAL");
387 }
388 }
389 #ifdef USE_PCRE
390 /*-
391 *******************************************************************
392 *
393 * Conditionally filter this record based on its MD5 value.
394 *
395 *******************************************************************
396 */
397 if
398 (
399 (psProperties->psExcludeFilterMd5List && SupportMatchFilter(psProperties->psExcludeFilterMd5List, &pcOutData[iFilterIndex]) != NULL) ||
400 (psProperties->psIncludeFilterMd5List && SupportMatchFilter(psProperties->psIncludeFilterMd5List, &pcOutData[iFilterIndex]) == NULL)
401 )
402 {
403 return ER_Filtered;
404 }
405 #endif
406 }
407
408 /*-
409 *********************************************************************
410 *
411 * File SHA1 = sha1
412 *
413 *********************************************************************
414 */
415 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA1))
416 {
417 #ifdef USE_PCRE
418 int iFilterIndex = n + 1;
419 #endif
420 pcOutData[n++] = '|';
421 if (S_ISDIR(psFTFileData->sStatEntry.st_mode))
422 {
423 if (psProperties->bHashDirectories)
424 {
425 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
426 {
427 n += SHA1HashToHex(psFTFileData->aucFileSha1, &pcOutData[n]);
428 }
429 }
430 else
431 {
432 n += sprintf(&pcOutData[n], "DIRECTORY");
433 }
434 }
435 else if (S_ISREG(psFTFileData->sStatEntry.st_mode))
436 {
437 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
438 {
439 n += SHA1HashToHex(psFTFileData->aucFileSha1, &pcOutData[n]);
440 }
441 else
442 {
443 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
444 iStatus = ER_NullFields;
445 }
446 }
447 else if (S_ISLNK(psFTFileData->sStatEntry.st_mode))
448 {
449 if (psProperties->bHashSymbolicLinks)
450 {
451 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
452 {
453 n += SHA1HashToHex(psFTFileData->aucFileSha1, &pcOutData[n]);
454 }
455 else
456 {
457 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
458 iStatus = ER_NullFields;
459 }
460 }
461 else
462 {
463 n += sprintf(&pcOutData[n], "SYMLINK");
464 }
465 }
466 else
467 {
468 if (psProperties->bAnalyzeDeviceFiles && memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, MD5_HASH_SIZE) != 0)
469 {
470 n += MD5HashToHex(psFTFileData->aucFileSha1, &pcOutData[n]);
471 }
472 else
473 {
474 n += sprintf(&pcOutData[n], "SPECIAL");
475 }
476 }
477 #ifdef USE_PCRE
478 /*-
479 *******************************************************************
480 *
481 * Conditionally filter this record based on its SHA1 value.
482 *
483 *******************************************************************
484 */
485 if
486 (
487 (psProperties->psExcludeFilterSha1List && SupportMatchFilter(psProperties->psExcludeFilterSha1List, &pcOutData[iFilterIndex]) != NULL) ||
488 (psProperties->psIncludeFilterSha1List && SupportMatchFilter(psProperties->psIncludeFilterSha1List, &pcOutData[iFilterIndex]) == NULL)
489 )
490 {
491 return ER_Filtered;
492 }
493 #endif
494 }
495
496 /*-
497 *********************************************************************
498 *
499 * File SHA256 = sha256
500 *
501 *********************************************************************
502 */
503 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA256))
504 {
505 #ifdef USE_PCRE
506 int iFilterIndex = n + 1;
507 #endif
508 pcOutData[n++] = '|';
509 if (S_ISDIR(psFTFileData->sStatEntry.st_mode))
510 {
511 if (psProperties->bHashDirectories)
512 {
513 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
514 {
515 n += SHA256HashToHex(psFTFileData->aucFileSha256, &pcOutData[n]);
516 }
517 }
518 else
519 {
520 n += sprintf(&pcOutData[n], "DIRECTORY");
521 }
522 }
523 else if (S_ISREG(psFTFileData->sStatEntry.st_mode))
524 {
525 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
526 {
527 n += SHA256HashToHex(psFTFileData->aucFileSha256, &pcOutData[n]);
528 }
529 else
530 {
531 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
532 iStatus = ER_NullFields;
533 }
534 }
535 else if (S_ISLNK(psFTFileData->sStatEntry.st_mode))
536 {
537 if (psProperties->bHashSymbolicLinks)
538 {
539 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
540 {
541 n += SHA256HashToHex(psFTFileData->aucFileSha256, &pcOutData[n]);
542 }
543 else
544 {
545 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
546 iStatus = ER_NullFields;
547 }
548 }
549 else
550 {
551 n += sprintf(&pcOutData[n], "SYMLINK");
552 }
553 }
554 else
555 {
556 if (psProperties->bAnalyzeDeviceFiles && memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, MD5_HASH_SIZE) != 0)
557 {
558 n += MD5HashToHex(psFTFileData->aucFileSha256, &pcOutData[n]);
559 }
560 else
561 {
562 n += sprintf(&pcOutData[n], "SPECIAL");
563 }
564 }
565 #ifdef USE_PCRE
566 /*-
567 *******************************************************************
568 *
569 * Conditionally filter this record based on its SHA256 value.
570 *
571 *******************************************************************
572 */
573 if
574 (
575 (psProperties->psExcludeFilterSha256List && SupportMatchFilter(psProperties->psExcludeFilterSha256List, &pcOutData[iFilterIndex]) != NULL) ||
576 (psProperties->psIncludeFilterSha256List && SupportMatchFilter(psProperties->psIncludeFilterSha256List, &pcOutData[iFilterIndex]) == NULL)
577 )
578 {
579 return ER_Filtered;
580 }
581 #endif
582 }
583
584 /*-
585 *********************************************************************
586 *
587 * File Magic = magic
588 *
589 *********************************************************************
590 */
591 #ifdef USE_XMAGIC
592 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
593 {
594 pcOutData[n++] = '|';
595 if (psFTFileData->acType[0])
596 {
597 n += sprintf(&pcOutData[n], "%s", psFTFileData->acType);
598 }
599 else
600 {
601 strcat(pcError, (pcError[0]) ? ",magic" : "magic");
602 iStatus = ER_NullFields;
603 }
604 }
605 #else
606 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
607 {
608 pcOutData[n++] = '|';
609 }
610 #endif
611
612 /*-
613 *********************************************************************
614 *
615 * EOL
616 *
617 *********************************************************************
618 */
619 n += sprintf(&pcOutData[n], "%s", psProperties->acNewLine);
620
621 /*-
622 *********************************************************************
623 *
624 * Set the write count for the caller.
625 *
626 *********************************************************************
627 */
628 *iWriteCount = n;
629
630 return iStatus;
631 }
632 #endif
633
634
635 #ifdef WIN32
636 /*-
637 ***********************************************************************
638 *
639 * DevelopNormalOutput
640 *
641 ***********************************************************************
642 */
643 int
DevelopNormalOutput(FTIMES_PROPERTIES * psProperties,char * pcOutData,int * iWriteCount,FTIMES_FILE_DATA * psFTFileData,char * pcError)644 DevelopNormalOutput(FTIMES_PROPERTIES *psProperties, char *pcOutData, int *iWriteCount, FTIMES_FILE_DATA *psFTFileData, char *pcError)
645 {
646 char acTime[FTIMES_TIME_FORMAT_SIZE];
647 int iError;
648 int n;
649 int iStatus = ER_OK;
650 unsigned __int64 ui64FileIndex;
651 unsigned __int64 ui64FileSize;
652
653 /*-
654 *********************************************************************
655 *
656 * This is required since only strcats are used below.
657 *
658 *********************************************************************
659 */
660 pcError[0] = 0;
661
662 /*-
663 *********************************************************************
664 *
665 * File Name = name
666 *
667 *********************************************************************
668 */
669 n = sprintf(pcOutData, "\"%s\"", psFTFileData->pcNeuteredPath);
670
671 /*-
672 *********************************************************************
673 *
674 * If there are no attributes to develop, just generate a series of
675 * NULL fields and return.
676 *
677 *********************************************************************
678 */
679 if (psFTFileData->ulAttributeMask == 0)
680 {
681 *iWriteCount = n;
682 return DevelopHaveNothingOutput(psProperties, &pcOutData[n], iWriteCount, psFTFileData, pcError);
683 }
684
685 /*-
686 *********************************************************************
687 *
688 * Volume Number = volume
689 *
690 *********************************************************************
691 */
692 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_VOLUME))
693 {
694 pcOutData[n++] = '|';
695 if (psFTFileData->dwVolumeSerialNumber != 0xffffffff)
696 {
697 n += sprintf(&pcOutData[n], "%u", (unsigned int) psFTFileData->dwVolumeSerialNumber);
698 }
699 else
700 {
701 strcat(pcError, (pcError[0]) ? ",volume" : "volume");
702 iStatus = ER_NullFields;
703 }
704 }
705
706 /*-
707 *********************************************************************
708 *
709 * File Index = findex
710 *
711 *********************************************************************
712 */
713 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_FINDEX))
714 {
715 pcOutData[n++] = '|';
716 if (psFTFileData->dwFileIndexHigh != 0xffffffff && psFTFileData->dwFileIndexLow != 0xffffffff)
717 {
718 ui64FileIndex = (((unsigned __int64) psFTFileData->dwFileIndexHigh) << 32) | psFTFileData->dwFileIndexLow;
719 n += sprintf(&pcOutData[n], "%I64u", (APP_UI64) ui64FileIndex);
720 }
721 else
722 {
723 strcat(pcError, (pcError[0]) ? ",findex" : "findex");
724 iStatus = ER_NullFields;
725 }
726 }
727
728 /*-
729 *********************************************************************
730 *
731 * Attributes = attributes
732 *
733 *********************************************************************
734 */
735 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATTRIBUTES))
736 {
737 n += sprintf(&pcOutData[n], "|%u", (unsigned int) psFTFileData->dwFileAttributes);
738 }
739
740 /*-
741 *********************************************************************
742 *
743 * Last Access Time = atime|ams
744 *
745 *********************************************************************
746 */
747 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME))
748 {
749 if (psFTFileData->sFTATime.dwLowDateTime == 0 && psFTFileData->sFTATime.dwHighDateTime == 0)
750 {
751 n += sprintf(&pcOutData[n], "||");
752 strcat(pcError, (pcError[0]) ? ",atime" : "atime");
753 iStatus = ER_NullFields;
754 }
755 else
756 {
757 iError = TimeFormatTime((FILETIME *) &psFTFileData->sFTATime, acTime);
758 if (iError == ER_OK)
759 {
760 n += sprintf(&pcOutData[n], "|%s", acTime);
761 }
762 else
763 {
764 n += sprintf(&pcOutData[n], "||");
765 strcat(pcError, (pcError[0]) ? ",atime" : "atime");
766 iStatus = ER_NullFields;
767 }
768 }
769 }
770
771 /*-
772 *********************************************************************
773 *
774 * Last Write Time = mtime|mms
775 *
776 *********************************************************************
777 */
778 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MTIME))
779 {
780 if (psFTFileData->sFTMTime.dwLowDateTime == 0 && psFTFileData->sFTMTime.dwHighDateTime == 0)
781 {
782 n += sprintf(&pcOutData[n], "||");
783 strcat(pcError, (pcError[0]) ? ",mtime" : "mtime");
784 iStatus = ER_NullFields;
785 }
786 else
787 {
788 iError = TimeFormatTime((FILETIME *) &psFTFileData->sFTMTime, acTime);
789 if (iError == ER_OK)
790 {
791 n += sprintf(&pcOutData[n], "|%s", acTime);
792 }
793 else
794 {
795 n += sprintf(&pcOutData[n], "||");
796 strcat(pcError, (pcError[0]) ? ",mtime" : "mtime");
797 iStatus = ER_NullFields;
798 }
799 }
800 }
801
802 /*-
803 *********************************************************************
804 *
805 * Creation Time = ctime|cms
806 *
807 *********************************************************************
808 */
809 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_CTIME))
810 {
811 if (psFTFileData->sFTCTime.dwLowDateTime == 0 && psFTFileData->sFTCTime.dwHighDateTime == 0)
812 {
813 n += sprintf(&pcOutData[n], "||");
814 strcat(pcError, (pcError[0]) ? ",ctime" : "ctime");
815 iStatus = ER_NullFields;
816 }
817 else
818 {
819 iError = TimeFormatTime((FILETIME *) &psFTFileData->sFTCTime, acTime);
820 if (iError == ER_OK)
821 {
822 n += sprintf(&pcOutData[n], "|%s", acTime);
823 }
824 else
825 {
826 n += sprintf(&pcOutData[n], "||");
827 strcat(pcError, (pcError[0]) ? ",ctime" : "ctime");
828 iStatus = ER_NullFields;
829 }
830 }
831 }
832
833 /*-
834 *********************************************************************
835 *
836 * Last Change Time = chtime|chms
837 *
838 *********************************************************************
839 */
840 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_CHTIME))
841 {
842 if (psFTFileData->sFTChTime.dwLowDateTime == 0 && psFTFileData->sFTChTime.dwHighDateTime == 0)
843 {
844 n += sprintf(&pcOutData[n], "||");
845 if (psFTFileData->iFSType == FSTYPE_NTFS)
846 {
847 strcat(pcError, (pcError[0]) ? ",chtime" : "chtime");
848 iStatus = ER_NullFields;
849 }
850 }
851 else
852 {
853 iError = TimeFormatTime((FILETIME *) &psFTFileData->sFTChTime, acTime);
854 if (iError == ER_OK)
855 {
856 n += sprintf(&pcOutData[n], "|%s", acTime);
857 }
858 else
859 {
860 n += sprintf(&pcOutData[n], "||");
861 if (psFTFileData->iFSType == FSTYPE_NTFS)
862 {
863 strcat(pcError, (pcError[0]) ? ",chtime" : "chtime");
864 iStatus = ER_NullFields;
865 }
866 }
867 }
868 }
869
870 /*-
871 *********************************************************************
872 *
873 * File Size = size
874 *
875 *********************************************************************
876 */
877 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SIZE))
878 {
879 ui64FileSize = (((unsigned __int64) psFTFileData->dwFileSizeHigh) << 32) | psFTFileData->dwFileSizeLow;
880 n += sprintf(&pcOutData[n], "|%I64u", (APP_UI64) ui64FileSize);
881 }
882
883 /*-
884 *********************************************************************
885 *
886 * Number of Alternate Streams = altstreams
887 *
888 *********************************************************************
889 */
890 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ALTSTREAMS))
891 {
892 pcOutData[n++] = '|';
893 if (psFTFileData->iStreamCount != FTIMES_INVALID_STREAM_COUNT)
894 {
895 n += sprintf(&pcOutData[n], "%u", psFTFileData->iStreamCount);
896 }
897 else
898 {
899 if (psFTFileData->iFSType == FSTYPE_NTFS)
900 {
901 strcat(pcError, (pcError[0]) ? ",altstreams" : "altstreams");
902 iStatus = ER_NullFields;
903 }
904 }
905 }
906
907 /*-
908 *********************************************************************
909 *
910 * File MD5 = md5
911 *
912 *********************************************************************
913 */
914 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MD5))
915 {
916 #ifdef USE_PCRE
917 int iFilterIndex = n + 1;
918 #endif
919 pcOutData[n++] = '|';
920 if ((psFTFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
921 {
922 if (psProperties->bHashDirectories)
923 {
924 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
925 {
926 n += MD5HashToHex(psFTFileData->aucFileMd5, &pcOutData[n]);
927 }
928 }
929 else
930 {
931 n += sprintf(&pcOutData[n], "DIRECTORY");
932 }
933 }
934 else
935 {
936 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
937 {
938 n += MD5HashToHex(psFTFileData->aucFileMd5, &pcOutData[n]);
939 }
940 else
941 {
942 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
943 iStatus = ER_NullFields;
944 }
945 }
946 #ifdef USE_PCRE
947 /*-
948 *******************************************************************
949 *
950 * Conditionally filter this record based on its MD5 value.
951 *
952 *******************************************************************
953 */
954 if
955 (
956 (psProperties->psExcludeFilterMd5List && SupportMatchFilter(psProperties->psExcludeFilterMd5List, &pcOutData[iFilterIndex]) != NULL) ||
957 (psProperties->psIncludeFilterMd5List && SupportMatchFilter(psProperties->psIncludeFilterMd5List, &pcOutData[iFilterIndex]) == NULL)
958 )
959 {
960 return ER_Filtered;
961 }
962 #endif
963 }
964
965 /*-
966 *********************************************************************
967 *
968 * File SHA1 = sha1
969 *
970 *********************************************************************
971 */
972 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA1))
973 {
974 #ifdef USE_PCRE
975 int iFilterIndex = n + 1;
976 #endif
977 pcOutData[n++] = '|';
978 if ((psFTFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
979 {
980 if (psProperties->bHashDirectories)
981 {
982 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
983 {
984 n += SHA1HashToHex(psFTFileData->aucFileSha1, &pcOutData[n]);
985 }
986 }
987 else
988 {
989 n += sprintf(&pcOutData[n], "DIRECTORY");
990 }
991 }
992 else
993 {
994 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
995 {
996 n += SHA1HashToHex(psFTFileData->aucFileSha1, &pcOutData[n]);
997 }
998 else
999 {
1000 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
1001 iStatus = ER_NullFields;
1002 }
1003 }
1004 #ifdef USE_PCRE
1005 /*-
1006 *******************************************************************
1007 *
1008 * Conditionally filter this record based on its SHA1 value.
1009 *
1010 *******************************************************************
1011 */
1012 if
1013 (
1014 (psProperties->psExcludeFilterSha1List && SupportMatchFilter(psProperties->psExcludeFilterSha1List, &pcOutData[iFilterIndex]) != NULL) ||
1015 (psProperties->psIncludeFilterSha1List && SupportMatchFilter(psProperties->psIncludeFilterSha1List, &pcOutData[iFilterIndex]) == NULL)
1016 )
1017 {
1018 return ER_Filtered;
1019 }
1020 #endif
1021 }
1022
1023 /*-
1024 *********************************************************************
1025 *
1026 * File SHA256 = sha256
1027 *
1028 *********************************************************************
1029 */
1030 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA256))
1031 {
1032 #ifdef USE_PCRE
1033 int iFilterIndex = n + 1;
1034 #endif
1035 pcOutData[n++] = '|';
1036 if ((psFTFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
1037 {
1038 if (psProperties->bHashDirectories)
1039 {
1040 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
1041 {
1042 n += SHA256HashToHex(psFTFileData->aucFileSha256, &pcOutData[n]);
1043 }
1044 }
1045 else
1046 {
1047 n += sprintf(&pcOutData[n], "DIRECTORY");
1048 }
1049 }
1050 else
1051 {
1052 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
1053 {
1054 n += SHA256HashToHex(psFTFileData->aucFileSha256, &pcOutData[n]);
1055 }
1056 else
1057 {
1058 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
1059 iStatus = ER_NullFields;
1060 }
1061 }
1062 #ifdef USE_PCRE
1063 /*-
1064 *******************************************************************
1065 *
1066 * Conditionally filter this record based on its SHA256 value.
1067 *
1068 *******************************************************************
1069 */
1070 if
1071 (
1072 (psProperties->psExcludeFilterSha256List && SupportMatchFilter(psProperties->psExcludeFilterSha256List, &pcOutData[iFilterIndex]) != NULL) ||
1073 (psProperties->psIncludeFilterSha256List && SupportMatchFilter(psProperties->psIncludeFilterSha256List, &pcOutData[iFilterIndex]) == NULL)
1074 )
1075 {
1076 return ER_Filtered;
1077 }
1078 #endif
1079 }
1080
1081 /*-
1082 *********************************************************************
1083 *
1084 * File Magic = magic
1085 *
1086 *********************************************************************
1087 */
1088 #ifdef USE_XMAGIC
1089 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
1090 {
1091 pcOutData[n++] = '|';
1092 if (psFTFileData->acType[0])
1093 {
1094 n += sprintf(&pcOutData[n], "%s", psFTFileData->acType);
1095 }
1096 else
1097 {
1098 strcat(pcError, (pcError[0]) ? ",magic" : "magic");
1099 iStatus = ER_NullFields;
1100 }
1101 }
1102 #else
1103 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
1104 {
1105 pcOutData[n++] = '|';
1106 }
1107 #endif
1108
1109 /*-
1110 *********************************************************************
1111 *
1112 * Owner SID = osid
1113 *
1114 *********************************************************************
1115 */
1116 #ifdef USE_SDDL
1117 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_OWNER))
1118 {
1119 char *pcSidOwner = NULL;
1120 pcOutData[n++] = '|';
1121 ConvertSidToStringSidA(psFTFileData->psSidOwner, &pcSidOwner);
1122 if (pcSidOwner)
1123 {
1124 n += sprintf(&pcOutData[n], "%s", pcSidOwner);
1125 LocalFree(pcSidOwner);
1126 }
1127 else
1128 {
1129 strcat(pcError, (pcError[0]) ? ",osid" : "osid");
1130 iStatus = ER_NullFields;
1131 }
1132 }
1133 #else
1134 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_OWNER))
1135 {
1136 pcOutData[n++] = '|';
1137 }
1138 #endif
1139
1140 /*-
1141 *********************************************************************
1142 *
1143 * Group SID = gsid
1144 *
1145 *********************************************************************
1146 */
1147 #ifdef USE_SDDL
1148 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_GROUP))
1149 {
1150 char *pcSidGroup = NULL;
1151 pcOutData[n++] = '|';
1152 ConvertSidToStringSidA(psFTFileData->psSidGroup, &pcSidGroup);
1153 if (pcSidGroup)
1154 {
1155 n += sprintf(&pcOutData[n], "%s", pcSidGroup);
1156 LocalFree(pcSidGroup);
1157 }
1158 else
1159 {
1160 strcat(pcError, (pcError[0]) ? ",gsid" : "gsid");
1161 iStatus = ER_NullFields;
1162 }
1163 }
1164 #else
1165 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_GROUP))
1166 {
1167 pcOutData[n++] = '|';
1168 }
1169 #endif
1170
1171 /*-
1172 *********************************************************************
1173 *
1174 * DACL = dacl
1175 *
1176 *********************************************************************
1177 */
1178 #ifdef USE_SDDL
1179 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_DACL))
1180 {
1181 char *pcAclDacl = NULL;
1182 DWORD dwLength = 0;
1183 pcOutData[n++] = '|';
1184 ConvertSecurityDescriptorToStringSecurityDescriptorA(psFTFileData->psSd, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &pcAclDacl, &dwLength);
1185 if (pcAclDacl && dwLength < FTIMES_MAX_ACL_SIZE)
1186 {
1187 n += sprintf(&pcOutData[n], "%s", pcAclDacl);
1188 LocalFree(pcAclDacl);
1189 }
1190 else
1191 {
1192 if (dwLength >= FTIMES_MAX_ACL_SIZE)
1193 {
1194 snprintf(pcError, MESSAGE_SIZE, "DevelopNormalOutput(): NeuteredPath = [%s], DaclLength = [%d]: Length exceeds %d bytes.", psFTFileData->pcNeuteredPath, (int) dwLength, FTIMES_MAX_ACL_SIZE - 1);
1195 ErrorHandler(ER_Failure, pcError, ERROR_FAILURE);
1196 pcError[0] = 0;
1197 }
1198 strcat(pcError, (pcError[0]) ? ",dacl" : "dacl");
1199 iStatus = ER_NullFields;
1200 }
1201 }
1202 #else
1203 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_DACL))
1204 {
1205 pcOutData[n++] = '|';
1206 }
1207 #endif
1208
1209 /*-
1210 *********************************************************************
1211 *
1212 * EOL
1213 *
1214 *********************************************************************
1215 */
1216 n += sprintf(&pcOutData[n], "%s", psProperties->acNewLine);
1217
1218 /*-
1219 *********************************************************************
1220 *
1221 * Set the write count for the caller.
1222 *
1223 *********************************************************************
1224 */
1225 *iWriteCount = n;
1226
1227 return iStatus;
1228 }
1229 #endif
1230
1231
1232 #ifdef UNIX
1233 /*-
1234 ***********************************************************************
1235 *
1236 * DevelopCompressedOutput
1237 *
1238 ***********************************************************************
1239 */
1240 int
DevelopCompressedOutput(FTIMES_PROPERTIES * psProperties,char * pcOutData,int * iWriteCount,FTIMES_FILE_DATA * psFTFileData,char * pcError)1241 DevelopCompressedOutput(FTIMES_PROPERTIES *psProperties, char *pcOutData, int *iWriteCount, FTIMES_FILE_DATA *psFTFileData, char *pcError)
1242 {
1243 int i;
1244 int n;
1245 int iStatus = ER_OK;
1246 static char acLastName[4 * FTIMES_MAX_PATH]; /* This is an encoded name. */
1247 static long lRecoveryCounter = 0;
1248 static struct stat sStatLastEntry;
1249
1250 /*-
1251 *********************************************************************
1252 *
1253 * This is required since only strcats are used below.
1254 *
1255 *********************************************************************
1256 */
1257 pcError[0] = 0;
1258
1259 /*-
1260 *********************************************************************
1261 *
1262 * File Name = name
1263 *
1264 *********************************************************************
1265 */
1266 if (lRecoveryCounter == 0)
1267 {
1268 n = sprintf(pcOutData, "00\"%s\"", psFTFileData->pcNeuteredPath);
1269 strncpy(acLastName, psFTFileData->pcNeuteredPath, (4 * FTIMES_MAX_PATH));
1270 }
1271 else
1272 {
1273 /*-
1274 *******************************************************************
1275 *
1276 * Compress name by appending repeat count and deleting letters in
1277 * common with previous name.
1278 *
1279 *******************************************************************
1280 */
1281 i = 0;
1282 if (acLastName[0] == '\0')
1283 {
1284 n = sprintf(pcOutData, "00\"%s\"", psFTFileData->pcNeuteredPath);
1285 }
1286 else
1287 {
1288 while ((i < 254) &&
1289 (acLastName[i] != '\0') &&
1290 (psFTFileData->pcNeuteredPath[i] != '\0') &&
1291 (acLastName[i] == psFTFileData->pcNeuteredPath[i]))
1292 {
1293 i++;
1294 }
1295 n = sprintf(pcOutData, "%02x%s\"", i + 1 /* Add 1 for the leading quote. */, &psFTFileData->pcNeuteredPath[i]);
1296 }
1297 strncpy(&acLastName[i], &psFTFileData->pcNeuteredPath[i], ((4 * FTIMES_MAX_PATH) - i) /* Must subtract i here to prevent overruns. */);
1298 }
1299
1300 /*-
1301 *********************************************************************
1302 *
1303 * If there are no attributes to develop, reset the recovery counter,
1304 * zero out state variables, generate a series of NULL fields, and
1305 * return.
1306 *
1307 *********************************************************************
1308 */
1309 if (psFTFileData->ulAttributeMask == 0)
1310 {
1311 *iWriteCount = n;
1312 lRecoveryCounter = 0;
1313 memset(acLastName, 0, (4 * FTIMES_MAX_PATH));
1314 memset(&sStatLastEntry, 0, sizeof(struct stat));
1315 return DevelopHaveNothingOutput(psProperties, &pcOutData[n], iWriteCount, psFTFileData, pcError);
1316 }
1317
1318 /*-
1319 *********************************************************************
1320 *
1321 * Device = dev
1322 *
1323 *********************************************************************
1324 */
1325 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_DEV))
1326 {
1327 pcOutData[n++] = '|';
1328 if (lRecoveryCounter == 0)
1329 {
1330 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_dev);
1331 }
1332 else
1333 {
1334 if (psFTFileData->sStatEntry.st_dev == sStatLastEntry.st_dev)
1335 {
1336 pcOutData[n++] = '#';
1337 }
1338 else
1339 {
1340 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_dev);
1341 }
1342 }
1343 }
1344
1345 /*-
1346 *********************************************************************
1347 *
1348 * Inode = inode
1349 *
1350 *********************************************************************
1351 */
1352 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_INODE))
1353 {
1354 pcOutData[n++] = '|';
1355 if (lRecoveryCounter == 0)
1356 {
1357 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_ino);
1358 }
1359 else
1360 {
1361 n += DevelopCompressHex(&pcOutData[n], psFTFileData->sStatEntry.st_ino, sStatLastEntry.st_ino);
1362 }
1363 }
1364
1365 /*-
1366 *********************************************************************
1367 *
1368 * Permissions and Mode = mode
1369 *
1370 *********************************************************************
1371 */
1372 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MODE))
1373 {
1374 pcOutData[n++] = '|';
1375 if (lRecoveryCounter == 0)
1376 {
1377 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_mode);
1378 }
1379 else
1380 {
1381 if (psFTFileData->sStatEntry.st_mode == sStatLastEntry.st_mode)
1382 {
1383 pcOutData[n++] = '#';
1384 }
1385 else
1386 {
1387 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_mode);
1388 }
1389 }
1390 }
1391
1392 /*-
1393 *********************************************************************
1394 *
1395 * Number of Links = nlink
1396 *
1397 *********************************************************************
1398 */
1399 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_NLINK))
1400 {
1401 pcOutData[n++] = '|';
1402 if (lRecoveryCounter == 0)
1403 {
1404 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_nlink);
1405 }
1406 else
1407 {
1408 if (psFTFileData->sStatEntry.st_nlink == sStatLastEntry.st_nlink)
1409 {
1410 pcOutData[n++] = '#';
1411 }
1412 else
1413 {
1414 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_nlink);
1415 }
1416 }
1417 }
1418
1419 /*-
1420 *********************************************************************
1421 *
1422 * User ID = uid
1423 *
1424 *********************************************************************
1425 */
1426 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_UID))
1427 {
1428 pcOutData[n++] = '|';
1429 if (lRecoveryCounter == 0)
1430 {
1431 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_uid);
1432 }
1433 else
1434 {
1435 if (psFTFileData->sStatEntry.st_uid == sStatLastEntry.st_uid)
1436 {
1437 pcOutData[n++] = '#';
1438 }
1439 else
1440 {
1441 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_uid);
1442 }
1443 }
1444 }
1445
1446 /*-
1447 *********************************************************************
1448 *
1449 * Group ID = gid
1450 *
1451 *********************************************************************
1452 */
1453 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_GID))
1454 {
1455 pcOutData[n++] = '|';
1456 if (lRecoveryCounter == 0)
1457 {
1458 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_gid);
1459 }
1460 else
1461 {
1462 if (psFTFileData->sStatEntry.st_gid == sStatLastEntry.st_gid)
1463 {
1464 pcOutData[n++] = '#';
1465 }
1466 else
1467 {
1468 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_gid);
1469 }
1470 }
1471 }
1472
1473 /*-
1474 *********************************************************************
1475 *
1476 * Special Device Type = rdev
1477 *
1478 *********************************************************************
1479 */
1480 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_RDEV))
1481 {
1482 pcOutData[n++] = '|';
1483 if (lRecoveryCounter == 0)
1484 {
1485 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_rdev);
1486 }
1487 else
1488 {
1489 if (psFTFileData->sStatEntry.st_rdev == sStatLastEntry.st_rdev)
1490 {
1491 pcOutData[n++] = '#';
1492 }
1493 else
1494 {
1495 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_rdev);
1496 }
1497 }
1498 }
1499
1500 /*-
1501 *********************************************************************
1502 *
1503 * Last Access Time = atime
1504 *
1505 *********************************************************************
1506 */
1507 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME))
1508 {
1509 pcOutData[n++] = '|';
1510 if (lRecoveryCounter == 0)
1511 {
1512 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_atime);
1513 }
1514 else if (psFTFileData->sStatEntry.st_atime == sStatLastEntry.st_atime)
1515 {
1516 pcOutData[n++] = '#';
1517 }
1518 else
1519 {
1520 n += DevelopCompressHex(&pcOutData[n], psFTFileData->sStatEntry.st_atime, sStatLastEntry.st_atime);
1521 }
1522 }
1523
1524 /*-
1525 *********************************************************************
1526 *
1527 * Last Modification Time = mtime
1528 *
1529 *********************************************************************
1530 */
1531 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MTIME))
1532 {
1533 pcOutData[n++] = '|';
1534 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME) && psFTFileData->sStatEntry.st_mtime == psFTFileData->sStatEntry.st_atime)
1535 {
1536 pcOutData[n++] = 'X';
1537 }
1538 else if (lRecoveryCounter == 0)
1539 {
1540 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_mtime);
1541 }
1542 else
1543 {
1544 if (psFTFileData->sStatEntry.st_mtime == sStatLastEntry.st_mtime)
1545 {
1546 pcOutData[n++] = '#';
1547 }
1548 else
1549 {
1550 n += DevelopCompressHex(&pcOutData[n], psFTFileData->sStatEntry.st_mtime, sStatLastEntry.st_mtime);
1551 }
1552 }
1553 }
1554
1555 /*-
1556 *********************************************************************
1557 *
1558 * Last Status Change Time = ctime
1559 *
1560 *********************************************************************
1561 */
1562 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_CTIME))
1563 {
1564 pcOutData[n++] = '|';
1565 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME) && psFTFileData->sStatEntry.st_ctime == psFTFileData->sStatEntry.st_atime)
1566 {
1567 pcOutData[n++] = 'X';
1568 }
1569 else if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MTIME) && psFTFileData->sStatEntry.st_ctime == psFTFileData->sStatEntry.st_mtime)
1570 {
1571 pcOutData[n++] = 'Y';
1572 }
1573 else if (lRecoveryCounter == 0)
1574 {
1575 n += sprintf(&pcOutData[n], "%x", (unsigned) psFTFileData->sStatEntry.st_ctime);
1576 }
1577 else
1578 {
1579 if (psFTFileData->sStatEntry.st_ctime == sStatLastEntry.st_ctime)
1580 {
1581 pcOutData[n++] = '#';
1582 }
1583 else
1584 {
1585 n += DevelopCompressHex(&pcOutData[n], psFTFileData->sStatEntry.st_ctime, sStatLastEntry.st_ctime);
1586 }
1587 }
1588 }
1589
1590 /*-
1591 *********************************************************************
1592 *
1593 * File Size = size
1594 *
1595 *********************************************************************
1596 */
1597 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SIZE))
1598 {
1599 pcOutData[n++] = '|';
1600 #ifdef USE_AP_SNPRINTF
1601 n += snprintf(&pcOutData[n], FTIMES_MAX_64BIT_SIZE, "%qx", (unsigned long long) psFTFileData->sStatEntry.st_size);
1602 #else
1603 n += snprintf(&pcOutData[n], FTIMES_MAX_64BIT_SIZE, "%llx", (unsigned long long) psFTFileData->sStatEntry.st_size);
1604 #endif
1605 }
1606
1607 /*-
1608 *********************************************************************
1609 *
1610 * File MD5 = md5
1611 *
1612 *********************************************************************
1613 */
1614 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MD5))
1615 {
1616 pcOutData[n++] = '|';
1617 if (S_ISDIR(psFTFileData->sStatEntry.st_mode))
1618 {
1619 if (psProperties->bHashDirectories)
1620 {
1621 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
1622 {
1623 n += MD5HashToBase64(psFTFileData->aucFileMd5, &pcOutData[n]);
1624 }
1625 else
1626 {
1627 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
1628 iStatus = ER_NullFields;
1629 }
1630 }
1631 else
1632 {
1633 pcOutData[n++] = 'D';
1634 }
1635 }
1636 else if (S_ISREG(psFTFileData->sStatEntry.st_mode))
1637 {
1638 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
1639 {
1640 n += MD5HashToBase64(psFTFileData->aucFileMd5, &pcOutData[n]);
1641 }
1642 else
1643 {
1644 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
1645 iStatus = ER_NullFields;
1646 }
1647 }
1648 else if (S_ISLNK(psFTFileData->sStatEntry.st_mode))
1649 {
1650 if (psProperties->bHashSymbolicLinks)
1651 {
1652 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
1653 {
1654 n += MD5HashToBase64(psFTFileData->aucFileMd5, &pcOutData[n]);
1655 }
1656 else
1657 {
1658 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
1659 iStatus = ER_NullFields;
1660 }
1661 }
1662 else
1663 {
1664 pcOutData[n++] = 'L';
1665 }
1666 }
1667 else
1668 {
1669 if (psProperties->bAnalyzeDeviceFiles && memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
1670 {
1671 n += MD5HashToBase64(psFTFileData->aucFileMd5, &pcOutData[n]);
1672 }
1673 else
1674 {
1675 pcOutData[n++] = 'S';
1676 }
1677 }
1678 }
1679
1680 /*-
1681 *********************************************************************
1682 *
1683 * File SHA1 = sha1
1684 *
1685 *********************************************************************
1686 */
1687 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA1))
1688 {
1689 pcOutData[n++] = '|';
1690 if (S_ISDIR(psFTFileData->sStatEntry.st_mode))
1691 {
1692 if (psProperties->bHashDirectories)
1693 {
1694 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
1695 {
1696 n += SHA1HashToBase64(psFTFileData->aucFileSha1, &pcOutData[n]);
1697 }
1698 else
1699 {
1700 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
1701 iStatus = ER_NullFields;
1702 }
1703 }
1704 else
1705 {
1706 pcOutData[n++] = 'D';
1707 }
1708 }
1709 else if (S_ISREG(psFTFileData->sStatEntry.st_mode))
1710 {
1711 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
1712 {
1713 n += SHA1HashToBase64(psFTFileData->aucFileSha1, &pcOutData[n]);
1714 }
1715 else
1716 {
1717 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
1718 iStatus = ER_NullFields;
1719 }
1720 }
1721 else if (S_ISLNK(psFTFileData->sStatEntry.st_mode))
1722 {
1723 if (psProperties->bHashSymbolicLinks)
1724 {
1725 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
1726 {
1727 n += SHA1HashToBase64(psFTFileData->aucFileSha1, &pcOutData[n]);
1728 }
1729 else
1730 {
1731 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
1732 iStatus = ER_NullFields;
1733 }
1734 }
1735 else
1736 {
1737 pcOutData[n++] = 'L';
1738 }
1739 }
1740 else
1741 {
1742 if (psProperties->bAnalyzeDeviceFiles && memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, MD5_HASH_SIZE) != 0)
1743 {
1744 n += MD5HashToBase64(psFTFileData->aucFileSha1, &pcOutData[n]);
1745 }
1746 else
1747 {
1748 pcOutData[n++] = 'S';
1749 }
1750 }
1751 }
1752
1753 /*-
1754 *********************************************************************
1755 *
1756 * File SHA256 = sha256
1757 *
1758 *********************************************************************
1759 */
1760 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA256))
1761 {
1762 pcOutData[n++] = '|';
1763 if (S_ISDIR(psFTFileData->sStatEntry.st_mode))
1764 {
1765 if (psProperties->bHashDirectories)
1766 {
1767 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
1768 {
1769 n += SHA256HashToBase64(psFTFileData->aucFileSha256, &pcOutData[n]);
1770 }
1771 else
1772 {
1773 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
1774 iStatus = ER_NullFields;
1775 }
1776 }
1777 else
1778 {
1779 pcOutData[n++] = 'D';
1780 }
1781 }
1782 else if (S_ISREG(psFTFileData->sStatEntry.st_mode))
1783 {
1784 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
1785 {
1786 n += SHA256HashToBase64(psFTFileData->aucFileSha256, &pcOutData[n]);
1787 }
1788 else
1789 {
1790 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
1791 iStatus = ER_NullFields;
1792 }
1793 }
1794 else if (S_ISLNK(psFTFileData->sStatEntry.st_mode))
1795 {
1796 if (psProperties->bHashSymbolicLinks)
1797 {
1798 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
1799 {
1800 n += SHA256HashToBase64(psFTFileData->aucFileSha256, &pcOutData[n]);
1801 }
1802 else
1803 {
1804 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
1805 iStatus = ER_NullFields;
1806 }
1807 }
1808 else
1809 {
1810 pcOutData[n++] = 'L';
1811 }
1812 }
1813 else
1814 {
1815 if (psProperties->bAnalyzeDeviceFiles && memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, MD5_HASH_SIZE) != 0)
1816 {
1817 n += MD5HashToBase64(psFTFileData->aucFileSha256, &pcOutData[n]);
1818 }
1819 else
1820 {
1821 pcOutData[n++] = 'S';
1822 }
1823 }
1824 }
1825
1826 /*-
1827 *********************************************************************
1828 *
1829 * File Magic = magic
1830 *
1831 *********************************************************************
1832 */
1833 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
1834 {
1835 pcOutData[n++] = '|';
1836 }
1837
1838 /*-
1839 *********************************************************************
1840 *
1841 * EOL
1842 *
1843 *********************************************************************
1844 */
1845 n += sprintf(&pcOutData[n], "%s", psProperties->acNewLine);
1846
1847 /*-
1848 *********************************************************************
1849 *
1850 * Copy psFTFileData->sStatEntry to sStatLastEntry for next time around.
1851 *
1852 *********************************************************************
1853 */
1854 memcpy(&sStatLastEntry, &psFTFileData->sStatEntry, sizeof(struct stat));
1855
1856 if (++lRecoveryCounter >= COMPRESS_RECOVERY_RATE)
1857 {
1858 lRecoveryCounter = 0;
1859 }
1860
1861 /*-
1862 *********************************************************************
1863 *
1864 * Set the write count for the caller.
1865 *
1866 *********************************************************************
1867 */
1868 *iWriteCount = n;
1869
1870 return iStatus;
1871 }
1872 #endif
1873
1874
1875 #ifdef WIN32
1876 /*-
1877 ***********************************************************************
1878 *
1879 * DevelopCompressedOutput
1880 *
1881 ***********************************************************************
1882 */
1883 int
DevelopCompressedOutput(FTIMES_PROPERTIES * psProperties,char * pcOutData,int * iWriteCount,FTIMES_FILE_DATA * psFTFileData,char * pcError)1884 DevelopCompressedOutput(FTIMES_PROPERTIES *psProperties, char *pcOutData, int *iWriteCount, FTIMES_FILE_DATA *psFTFileData, char *pcError)
1885 {
1886 char acTime[FTIMES_TIME_FORMAT_SIZE];
1887 int i;
1888 int n;
1889 int iError;
1890 int iStatus = ER_OK;
1891 unsigned long ulATimeSeconds;
1892 unsigned long ulMTimeSeconds;
1893 unsigned long ulCTimeSeconds;
1894 unsigned long ulChTimeSeconds;
1895 unsigned long ulATimeMilliseconds;
1896 unsigned long ulMTimeMilliseconds;
1897 unsigned long ulCTimeMilliseconds;
1898 unsigned long ulChTimeMilliseconds;
1899 unsigned long ulTempATimeSeconds;
1900 unsigned long ulTempMTimeSeconds;
1901 unsigned long ulTempCTimeSeconds;
1902 unsigned long ulTempChTimeSeconds;
1903 unsigned __int64 ui64ATime = 0;
1904 unsigned __int64 ui64MTime = 0;
1905 unsigned __int64 ui64CTime = 0;
1906 unsigned __int64 ui64ChTime = 0;
1907 unsigned __int64 ui64FileIndex = 0;
1908 unsigned __int64 ui64FileSize = 0;
1909 static char acLastName[4 * FTIMES_MAX_PATH]; /* This is an encoded name. */
1910 static DWORD dwLastVolumeSerialNumber;
1911 static DWORD dwLastFileIndexHigh;
1912 static DWORD dwLastFileIndexLow;
1913 static DWORD dwLastFileAttributes;
1914 static long lRecoveryCounter = 0;
1915 static unsigned __int64 ui64LastATime;
1916 static unsigned __int64 ui64LastMTime;
1917 static unsigned __int64 ui64LastCTime;
1918 static unsigned __int64 ui64LastChTime;
1919
1920 /*-
1921 *********************************************************************
1922 *
1923 * This is required since only strcats are used below.
1924 *
1925 *********************************************************************
1926 */
1927 pcError[0] = 0;
1928
1929 /*-
1930 *********************************************************************
1931 *
1932 * File Name = name
1933 *
1934 *********************************************************************
1935 */
1936 if (lRecoveryCounter == 0)
1937 {
1938 n = sprintf(pcOutData, "00\"%s\"", psFTFileData->pcNeuteredPath);
1939 strncpy(acLastName, psFTFileData->pcNeuteredPath, (4 * FTIMES_MAX_PATH));
1940 }
1941 else
1942 {
1943 /*-
1944 *******************************************************************
1945 *
1946 * Compress name by appending repeat count and deleting letters in
1947 * common with previous name.
1948 *
1949 *******************************************************************
1950 */
1951 i = 0;
1952 if (acLastName[0] == '\0')
1953 {
1954 n = sprintf(pcOutData, "00\"%s\"", psFTFileData->pcNeuteredPath);
1955 }
1956 else
1957 {
1958 while ((i < 254) &&
1959 (acLastName[i] != '\0') &&
1960 (psFTFileData->pcNeuteredPath[i] != '\0') &&
1961 (acLastName[i] == psFTFileData->pcNeuteredPath[i]))
1962 {
1963 i++;
1964 }
1965 n = sprintf(pcOutData, "%02x%s\"", i + 1 /* Add 1 for the leading quote. */, &psFTFileData->pcNeuteredPath[i]);
1966 }
1967 strncpy(&acLastName[i], &psFTFileData->pcNeuteredPath[i], ((4 * FTIMES_MAX_PATH) - i) /* Must subtract i here to prevent overruns. */);
1968 }
1969
1970 /*-
1971 *********************************************************************
1972 *
1973 * If there are no attributes to develop, reset the recovery counter,
1974 * zero out state variables, generate a series of NULL fields, and
1975 * return.
1976 *
1977 *********************************************************************
1978 */
1979 if (psFTFileData->ulAttributeMask == 0)
1980 {
1981 *iWriteCount = n;
1982 lRecoveryCounter = 0;
1983 memset(acLastName, 0, (4 * FTIMES_MAX_PATH));
1984 dwLastVolumeSerialNumber = 0;
1985 dwLastFileIndexHigh = 0;
1986 dwLastFileIndexLow = 0;
1987 dwLastFileAttributes = 0;
1988 ui64LastATime = 0;
1989 ui64LastMTime = 0;
1990 ui64LastCTime = 0;
1991 ui64LastChTime = 0;
1992 return DevelopHaveNothingOutput(psProperties, &pcOutData[n], iWriteCount, psFTFileData, pcError);
1993 }
1994
1995 /*-
1996 *********************************************************************
1997 *
1998 * Volume Number = volume
1999 *
2000 *********************************************************************
2001 */
2002 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_VOLUME))
2003 {
2004 pcOutData[n++] = '|';
2005 if (lRecoveryCounter == 0)
2006 {
2007 n += sprintf(&pcOutData[n], "%x", (unsigned int) psFTFileData->dwVolumeSerialNumber);
2008 }
2009 else
2010 {
2011 if (psFTFileData->dwVolumeSerialNumber != 0xffffffff)
2012 {
2013 if (psFTFileData->dwVolumeSerialNumber == dwLastVolumeSerialNumber)
2014 {
2015 pcOutData[n++] = '#';
2016 }
2017 else
2018 {
2019 n += sprintf(&pcOutData[n], "%x", (unsigned int) psFTFileData->dwVolumeSerialNumber);
2020 }
2021 }
2022 else
2023 {
2024 strcat(pcError, (pcError[0]) ? ",volume" : "volume");
2025 iStatus = ER_NullFields;
2026 }
2027 }
2028 }
2029
2030 /*-
2031 *********************************************************************
2032 *
2033 * File Index = findex
2034 *
2035 *********************************************************************
2036 */
2037 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_FINDEX))
2038 {
2039 pcOutData[n++] = '|';
2040 if (lRecoveryCounter == 0)
2041 {
2042 ui64FileIndex = (((unsigned __int64) psFTFileData->dwFileIndexHigh) << 32) | psFTFileData->dwFileIndexLow;
2043 n += sprintf(&pcOutData[n], "%I64x", (APP_UI64) ui64FileIndex);
2044 }
2045 else
2046 {
2047 if (psFTFileData->dwFileIndexHigh != 0xffffffff && psFTFileData->dwFileIndexLow != 0xffffffff)
2048 {
2049 if (psFTFileData->dwFileIndexHigh == dwLastFileIndexHigh)
2050 {
2051 pcOutData[n++] = '#';
2052 n += DevelopCompressHex(&pcOutData[n], psFTFileData->dwFileIndexLow, dwLastFileIndexLow);
2053 }
2054 else
2055 {
2056 ui64FileIndex = (((unsigned __int64) psFTFileData->dwFileIndexHigh) << 32) | psFTFileData->dwFileIndexLow;
2057 n += sprintf(&pcOutData[n], "%I64x", (APP_UI64) ui64FileIndex);
2058 }
2059 }
2060 else
2061 {
2062 strcat(pcError, (pcError[0]) ? ",findex" : "findex");
2063 iStatus = ER_NullFields;
2064 }
2065 }
2066 }
2067
2068 /*-
2069 *********************************************************************
2070 *
2071 * Attributes = attributes
2072 *
2073 *********************************************************************
2074 */
2075 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATTRIBUTES))
2076 {
2077 pcOutData[n++] = '|';
2078 if (lRecoveryCounter == 0)
2079 {
2080 n += sprintf(&pcOutData[n], "%x", (unsigned int) psFTFileData->dwFileAttributes);
2081 }
2082 else
2083 {
2084 if (psFTFileData->dwFileAttributes == dwLastFileAttributes)
2085 {
2086 pcOutData[n++] = '#';
2087 }
2088 else
2089 {
2090 n += sprintf(&pcOutData[n], "%x", (unsigned int) psFTFileData->dwFileAttributes);
2091 }
2092 }
2093 }
2094
2095 /*-
2096 *********************************************************************
2097 *
2098 * Last Access Time = atime|ams
2099 *
2100 *********************************************************************
2101 */
2102 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME))
2103 {
2104 pcOutData[n++] = '|';
2105 if (psFTFileData->sFTATime.dwLowDateTime == 0 && psFTFileData->sFTATime.dwHighDateTime == 0)
2106 {
2107 pcOutData[n++] = '|';
2108 strcat(pcError, (pcError[0]) ? ",atime" : "atime");
2109 iStatus = ER_NullFields;
2110 ui64ATime = 0; /* Ensure that ui64LastATime will be properly initialized. */
2111 }
2112 else
2113 {
2114 ui64ATime = (((unsigned __int64) psFTFileData->sFTATime.dwHighDateTime) << 32) | psFTFileData->sFTATime.dwLowDateTime;
2115 if (ui64ATime < UNIX_EPOCH_IN_NT_TIME || ui64ATime > UNIX_LIMIT_IN_NT_TIME)
2116 {
2117 iError = TimeFormatOutOfBandTime((FILETIME *) &psFTFileData->sFTATime, acTime);
2118 if (iError == ER_OK)
2119 {
2120 n += sprintf(&pcOutData[n], "~%s", acTime);
2121 }
2122 else
2123 {
2124 pcOutData[n++] = '|';
2125 strcat(pcError, (pcError[0]) ? ",atime" : "atime");
2126 iStatus = ER_NullFields;
2127 }
2128 }
2129 else
2130 {
2131 ulATimeSeconds = (unsigned long) ((ui64ATime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2132 ulATimeMilliseconds = (unsigned long) (((ui64ATime - UNIX_EPOCH_IN_NT_TIME) % 10000000) / 10000);
2133 if (lRecoveryCounter == 0)
2134 {
2135 n += sprintf(&pcOutData[n], "%lx|%lx", ulATimeSeconds, ulATimeMilliseconds);
2136 }
2137 else
2138 {
2139 if (ui64ATime == ui64LastATime)
2140 {
2141 pcOutData[n++] = '#';
2142 pcOutData[n++] = '|';
2143 pcOutData[n++] = '#';
2144 }
2145 else
2146 {
2147 ulTempATimeSeconds = (unsigned long) ((ui64LastATime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2148 n += DevelopCompressHex(&pcOutData[n], ulATimeSeconds, ulTempATimeSeconds);
2149 n += sprintf(&pcOutData[n], "|%lx", ulATimeMilliseconds);
2150 }
2151 }
2152 }
2153 }
2154 }
2155
2156 /*-
2157 *********************************************************************
2158 *
2159 * Last Write Time = mtime|mms
2160 *
2161 *********************************************************************
2162 */
2163 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MTIME))
2164 {
2165 pcOutData[n++] = '|';
2166 if (psFTFileData->sFTMTime.dwLowDateTime == 0 && psFTFileData->sFTMTime.dwHighDateTime == 0)
2167 {
2168 pcOutData[n++] = '|';
2169 strcat(pcError, (pcError[0]) ? ",mtime" : "mtime");
2170 iStatus = ER_NullFields;
2171 ui64MTime = 0; /* Ensure that ui64LastMTime will be properly initialized. */
2172 }
2173 else
2174 {
2175 ui64MTime = (((unsigned __int64) psFTFileData->sFTMTime.dwHighDateTime) << 32) | psFTFileData->sFTMTime.dwLowDateTime;
2176 if (ui64MTime < UNIX_EPOCH_IN_NT_TIME || ui64MTime > UNIX_LIMIT_IN_NT_TIME)
2177 {
2178 iError = TimeFormatOutOfBandTime((FILETIME *) &psFTFileData->sFTMTime, acTime);
2179 if (iError == ER_OK)
2180 {
2181 n += sprintf(&pcOutData[n], "~%s", acTime);
2182 }
2183 else
2184 {
2185 pcOutData[n++] = '|';
2186 strcat(pcError, (pcError[0]) ? ",mtime" : "mtime");
2187 iStatus = ER_NullFields;
2188 }
2189 }
2190 else
2191 {
2192 ulMTimeSeconds = (unsigned long) ((ui64MTime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2193 ulMTimeMilliseconds = (unsigned long) (((ui64MTime - UNIX_EPOCH_IN_NT_TIME) % 10000000) / 10000);
2194 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME) && ui64MTime == ui64ATime)
2195 {
2196 pcOutData[n++] = 'X';
2197 pcOutData[n++] = '|';
2198 pcOutData[n++] = 'X';
2199 }
2200 else if (lRecoveryCounter == 0)
2201 {
2202 n += sprintf(&pcOutData[n], "%lx|%lx", ulMTimeSeconds, ulMTimeMilliseconds);
2203 }
2204 else if (ui64MTime == ui64LastMTime)
2205 {
2206 pcOutData[n++] = '#';
2207 pcOutData[n++] = '|';
2208 pcOutData[n++] = '#';
2209 }
2210 else
2211 {
2212 ulTempMTimeSeconds = (unsigned long) ((ui64LastMTime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2213 n += DevelopCompressHex(&pcOutData[n], ulMTimeSeconds, ulTempMTimeSeconds);
2214 n += sprintf(&pcOutData[n], "|%lx", ulMTimeMilliseconds);
2215 }
2216 }
2217 }
2218 }
2219
2220 /*-
2221 *********************************************************************
2222 *
2223 * Creation Time = ctime|cms
2224 *
2225 *********************************************************************
2226 */
2227 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_CTIME))
2228 {
2229 pcOutData[n++] = '|';
2230 if (psFTFileData->sFTCTime.dwLowDateTime == 0 && psFTFileData->sFTCTime.dwHighDateTime == 0)
2231 {
2232 pcOutData[n++] = '|';
2233 strcat(pcError, (pcError[0]) ? ",ctime" : "ctime");
2234 iStatus = ER_NullFields;
2235 ui64CTime = 0; /* Ensure that ui64LastCTime will be properly initialized. */
2236 }
2237 else
2238 {
2239 ui64CTime = (((unsigned __int64) psFTFileData->sFTCTime.dwHighDateTime) << 32) | psFTFileData->sFTCTime.dwLowDateTime;
2240 if (ui64CTime < UNIX_EPOCH_IN_NT_TIME || ui64CTime > UNIX_LIMIT_IN_NT_TIME)
2241 {
2242 iError = TimeFormatOutOfBandTime((FILETIME *) &psFTFileData->sFTCTime, acTime);
2243 if (iError == ER_OK)
2244 {
2245 n += sprintf(&pcOutData[n], "~%s", acTime);
2246 }
2247 else
2248 {
2249 pcOutData[n++] = '|';
2250 strcat(pcError, (pcError[0]) ? ",ctime" : "ctime");
2251 iStatus = ER_NullFields;
2252 }
2253 }
2254 else
2255 {
2256 ulCTimeSeconds = (unsigned long) ((ui64CTime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2257 ulCTimeMilliseconds = (unsigned long) (((ui64CTime - UNIX_EPOCH_IN_NT_TIME) % 10000000) / 10000);
2258 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME) && ui64CTime == ui64ATime)
2259 {
2260 pcOutData[n++] = 'X';
2261 pcOutData[n++] = '|';
2262 pcOutData[n++] = 'X';
2263 }
2264 else if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MTIME) && ui64CTime == ui64MTime)
2265 {
2266 pcOutData[n++] = 'Y';
2267 pcOutData[n++] = '|';
2268 pcOutData[n++] = 'Y';
2269 }
2270 else if (lRecoveryCounter == 0)
2271 {
2272 n += sprintf(&pcOutData[n], "%lx|%lx", ulCTimeSeconds, ulCTimeMilliseconds);
2273 }
2274 else if (ui64CTime == ui64LastCTime)
2275 {
2276 pcOutData[n++] = '#';
2277 pcOutData[n++] = '|';
2278 pcOutData[n++] = '#';
2279 }
2280 else
2281 {
2282 ulTempCTimeSeconds = (unsigned long) ((ui64LastCTime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2283 n += DevelopCompressHex(&pcOutData[n], ulCTimeSeconds, ulTempCTimeSeconds);
2284 n += sprintf(&pcOutData[n], "|%lx", ulCTimeMilliseconds);
2285 }
2286 }
2287 }
2288 }
2289
2290 /*-
2291 *********************************************************************
2292 *
2293 * Last Change Time = chtime|chms
2294 *
2295 *********************************************************************
2296 */
2297 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_CHTIME))
2298 {
2299 pcOutData[n++] = '|';
2300 if (psFTFileData->sFTChTime.dwLowDateTime == 0 && psFTFileData->sFTChTime.dwHighDateTime == 0)
2301 {
2302 pcOutData[n++] = '|';
2303 if (psFTFileData->iFSType == FSTYPE_NTFS)
2304 {
2305 strcat(pcError, (pcError[0]) ? ",chtime" : "chtime");
2306 iStatus = ER_NullFields;
2307 }
2308 ui64ChTime = 0; /* Ensure that ui64LastChTime will be properly initialized. */
2309 }
2310 else
2311 {
2312 ui64ChTime = (((unsigned __int64) psFTFileData->sFTChTime.dwHighDateTime) << 32) | psFTFileData->sFTChTime.dwLowDateTime;
2313 if (ui64ChTime < UNIX_EPOCH_IN_NT_TIME || ui64ChTime > UNIX_LIMIT_IN_NT_TIME)
2314 {
2315 iError = TimeFormatOutOfBandTime((FILETIME *) &psFTFileData->sFTChTime, acTime);
2316 if (iError == ER_OK)
2317 {
2318 n += sprintf(&pcOutData[n], "~%s", acTime);
2319 }
2320 else
2321 {
2322 pcOutData[n++] = '|';
2323 if (psFTFileData->iFSType == FSTYPE_NTFS)
2324 {
2325 strcat(pcError, (pcError[0]) ? ",chtime" : "chtime");
2326 iStatus = ER_NullFields;
2327 }
2328 }
2329 }
2330 else
2331 {
2332 ulChTimeSeconds = (unsigned long) ((ui64ChTime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2333 ulChTimeMilliseconds = (unsigned long) (((ui64ChTime - UNIX_EPOCH_IN_NT_TIME) % 10000000) / 10000);
2334 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ATIME) && ui64ChTime == ui64ATime)
2335 {
2336 pcOutData[n++] = 'X';
2337 pcOutData[n++] = '|';
2338 pcOutData[n++] = 'X';
2339 }
2340 else if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MTIME) && ui64ChTime == ui64MTime)
2341 {
2342 pcOutData[n++] = 'Y';
2343 pcOutData[n++] = '|';
2344 pcOutData[n++] = 'Y';
2345 }
2346 else if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_CTIME) && ui64ChTime == ui64CTime)
2347 {
2348 pcOutData[n++] = 'Z';
2349 pcOutData[n++] = '|';
2350 pcOutData[n++] = 'Z';
2351 }
2352 else if (lRecoveryCounter == 0)
2353 {
2354 n += sprintf(&pcOutData[n], "%lx|%lx", ulChTimeSeconds, ulChTimeMilliseconds);
2355 }
2356 else if (ui64ChTime == ui64LastChTime)
2357 {
2358 pcOutData[n++] = '#';
2359 pcOutData[n++] = '|';
2360 pcOutData[n++] = '#';
2361 }
2362 else
2363 {
2364 ulTempChTimeSeconds = (unsigned long) ((ui64LastChTime - UNIX_EPOCH_IN_NT_TIME) / 10000000);
2365 n += DevelopCompressHex(&pcOutData[n], ulChTimeSeconds, ulTempChTimeSeconds);
2366 n += sprintf(&pcOutData[n], "|%lx", ulChTimeMilliseconds);
2367 }
2368 }
2369 }
2370 }
2371
2372 /*-
2373 *********************************************************************
2374 *
2375 * File Size = size
2376 *
2377 *********************************************************************
2378 */
2379 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SIZE))
2380 {
2381 pcOutData[n++] = '|';
2382 ui64FileSize = (((unsigned __int64) psFTFileData->dwFileSizeHigh) << 32) | psFTFileData->dwFileSizeLow;
2383 n += sprintf(&pcOutData[n], "%I64x", (APP_UI64) ui64FileSize);
2384 }
2385
2386 /*-
2387 *********************************************************************
2388 *
2389 * Number of Alternate Streams = altstreams
2390 *
2391 *********************************************************************
2392 */
2393 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_ALTSTREAMS))
2394 {
2395 pcOutData[n++] = '|';
2396 if (psFTFileData->iStreamCount != FTIMES_INVALID_STREAM_COUNT)
2397 {
2398 n += sprintf(&pcOutData[n], "%x", psFTFileData->iStreamCount);
2399 }
2400 else
2401 {
2402 if (psFTFileData->iFSType == FSTYPE_NTFS)
2403 {
2404 strcat(pcError, (pcError[0]) ? ",altstreams" : "altstreams");
2405 iStatus = ER_NullFields;
2406 }
2407 }
2408 }
2409
2410 /*-
2411 *********************************************************************
2412 *
2413 * File MD5 = md5
2414 *
2415 *********************************************************************
2416 */
2417 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MD5))
2418 {
2419 pcOutData[n++] = '|';
2420 if ((psFTFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
2421 {
2422 if (psProperties->bHashDirectories)
2423 {
2424 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
2425 {
2426 n += MD5HashToBase64(psFTFileData->aucFileMd5, &pcOutData[n]);
2427 }
2428 else
2429 {
2430 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
2431 iStatus = ER_NullFields;
2432 }
2433 }
2434 else
2435 {
2436 pcOutData[n++] = 'D';
2437 }
2438 }
2439 else
2440 {
2441 if (memcmp(psFTFileData->aucFileMd5, gaucMd5ZeroHash, MD5_HASH_SIZE) != 0)
2442 {
2443 n += MD5HashToBase64(psFTFileData->aucFileMd5, &pcOutData[n]);
2444 }
2445 else
2446 {
2447 strcat(pcError, (pcError[0]) ? ",md5" : "md5");
2448 iStatus = ER_NullFields;
2449 }
2450 }
2451 }
2452
2453 /*-
2454 *********************************************************************
2455 *
2456 * File SHA1 = sha1
2457 *
2458 *********************************************************************
2459 */
2460 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA1))
2461 {
2462 pcOutData[n++] = '|';
2463 if ((psFTFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
2464 {
2465 if (psProperties->bHashDirectories)
2466 {
2467 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
2468 {
2469 n += SHA1HashToBase64(psFTFileData->aucFileSha1, &pcOutData[n]);
2470 }
2471 else
2472 {
2473 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
2474 iStatus = ER_NullFields;
2475 }
2476 }
2477 else
2478 {
2479 pcOutData[n++] = 'D';
2480 }
2481 }
2482 else
2483 {
2484 if (memcmp(psFTFileData->aucFileSha1, gaucSha1ZeroHash, SHA1_HASH_SIZE) != 0)
2485 {
2486 n += SHA1HashToBase64(psFTFileData->aucFileSha1, &pcOutData[n]);
2487 }
2488 else
2489 {
2490 strcat(pcError, (pcError[0]) ? ",sha1" : "sha1");
2491 iStatus = ER_NullFields;
2492 }
2493 }
2494 }
2495
2496 /*-
2497 *********************************************************************
2498 *
2499 * File SHA256 = sha256
2500 *
2501 *********************************************************************
2502 */
2503 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA256))
2504 {
2505 pcOutData[n++] = '|';
2506 if ((psFTFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
2507 {
2508 if (psProperties->bHashDirectories)
2509 {
2510 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
2511 {
2512 n += SHA256HashToBase64(psFTFileData->aucFileSha256, &pcOutData[n]);
2513 }
2514 else
2515 {
2516 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
2517 iStatus = ER_NullFields;
2518 }
2519 }
2520 else
2521 {
2522 pcOutData[n++] = 'D';
2523 }
2524 }
2525 else
2526 {
2527 if (memcmp(psFTFileData->aucFileSha256, gaucSha256ZeroHash, SHA256_HASH_SIZE) != 0)
2528 {
2529 n += SHA256HashToBase64(psFTFileData->aucFileSha256, &pcOutData[n]);
2530 }
2531 else
2532 {
2533 strcat(pcError, (pcError[0]) ? ",sha256" : "sha256");
2534 iStatus = ER_NullFields;
2535 }
2536 }
2537 }
2538
2539 /*-
2540 *********************************************************************
2541 *
2542 * File Magic = magic
2543 *
2544 *********************************************************************
2545 */
2546 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
2547 {
2548 pcOutData[n++] = '|';
2549 }
2550
2551 /*-
2552 *********************************************************************
2553 *
2554 * Owner SID = osid (Compression for this field is not yet supported.)
2555 *
2556 *********************************************************************
2557 */
2558 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_OWNER))
2559 {
2560 pcOutData[n++] = '|';
2561 }
2562
2563 /*-
2564 *********************************************************************
2565 *
2566 * Group SID = gsid (Compression for this field is not yet supported.)
2567 *
2568 *********************************************************************
2569 */
2570 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_GROUP))
2571 {
2572 pcOutData[n++] = '|';
2573 }
2574
2575 /*-
2576 *********************************************************************
2577 *
2578 * DACL = dacl (Compression for this field is not yet supported.)
2579 *
2580 *********************************************************************
2581 */
2582 if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_OWNER))
2583 {
2584 pcOutData[n++] = '|';
2585 }
2586
2587 /*-
2588 *********************************************************************
2589 *
2590 * EOL
2591 *
2592 *********************************************************************
2593 */
2594 n += sprintf(&pcOutData[n], "%s", psProperties->acNewLine);
2595
2596 /*-
2597 *********************************************************************
2598 *
2599 * Save pertinent fields for next time around.
2600 *
2601 *********************************************************************
2602 */
2603 dwLastVolumeSerialNumber = psFTFileData->dwVolumeSerialNumber;
2604 dwLastFileIndexHigh = psFTFileData->dwFileIndexHigh;
2605 dwLastFileIndexLow = psFTFileData->dwFileIndexLow;
2606 dwLastFileAttributes = psFTFileData->dwFileAttributes;
2607 ui64LastATime = ui64ATime;
2608 ui64LastMTime = ui64MTime;
2609 ui64LastCTime = ui64CTime;
2610 ui64LastChTime = ui64ChTime;
2611
2612 if (++lRecoveryCounter >= COMPRESS_RECOVERY_RATE)
2613 {
2614 lRecoveryCounter = 0;
2615 }
2616
2617 /*-
2618 *********************************************************************
2619 *
2620 * Set the write count for the caller.
2621 *
2622 *********************************************************************
2623 */
2624 *iWriteCount = n;
2625
2626 return iStatus;
2627 }
2628 #endif
2629
2630
2631 /*-
2632 ***********************************************************************
2633 *
2634 * DevelopCompressHex
2635 *
2636 ***********************************************************************
2637 */
2638 int
DevelopCompressHex(char * pcData,unsigned long ulHex,unsigned long ulOldHex)2639 DevelopCompressHex(char *pcData, unsigned long ulHex, unsigned long ulOldHex)
2640 {
2641 int iHexDigitCount;
2642 int iHexDigitDeltaCount;
2643 unsigned long ulDelta;
2644
2645 /*-
2646 *********************************************************************
2647 *
2648 * We normally print ulHex in hex, taking up to 8 hex digits; maybe
2649 * fewer because we don't print leading zeros. However, if ulHex is
2650 * 'close to' ulOldHex, it may take less space to print the difference.
2651 * We have to be careful, because simply subtracting ulHex - ulOldHex
2652 * may overflow a signed number.
2653 *
2654 *********************************************************************
2655 */
2656 iHexDigitCount = DevelopCountHexDigits(ulHex);
2657
2658 if (ulHex >= ulOldHex)
2659 {
2660 ulDelta = ulHex - ulOldHex;
2661 iHexDigitDeltaCount = 1 + DevelopCountHexDigits(ulDelta);
2662 if (iHexDigitDeltaCount < iHexDigitCount)
2663 {
2664 return sprintf(pcData, "+%lx", ulDelta);
2665 }
2666 }
2667 else
2668 {
2669 ulDelta = ulOldHex - ulHex;
2670 iHexDigitDeltaCount = 1 + DevelopCountHexDigits(ulDelta);
2671 if (iHexDigitDeltaCount < iHexDigitCount)
2672 {
2673 return sprintf(pcData, "-%lx", ulDelta);
2674 }
2675 }
2676
2677 return sprintf(pcData, "%lx", ulHex);
2678 }
2679
2680
2681 /*-
2682 ***********************************************************************
2683 *
2684 * DevelopCountHexDigits
2685 *
2686 ***********************************************************************
2687 */
2688 int
DevelopCountHexDigits(unsigned long ulHex)2689 DevelopCountHexDigits(unsigned long ulHex)
2690 {
2691 int i = 8;
2692
2693 if (ulHex == 0)
2694 {
2695 return 1;
2696 }
2697 while ((ulHex & 0xf0000000) == 0)
2698 {
2699 ulHex <<= 4;
2700 i--;
2701 }
2702 return i;
2703 }
2704