1 /*-
2  ***********************************************************************
3  *
4  * $Id: mapmode.c,v 1.57 2014/07/18 06:40:44 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  * MapModeInitialize
18  *
19  ***********************************************************************
20  */
21 int
MapModeInitialize(FTIMES_PROPERTIES * psProperties,char * pcError)22 MapModeInitialize(FTIMES_PROPERTIES *psProperties, char *pcError)
23 {
24   const char          acRoutine[] = "MapModeInitialize()";
25   char                acLocalError[MESSAGE_SIZE] = "";
26   char                acMapItem[FTIMES_MAX_PATH];
27   char               *pcMapItem = NULL;
28   int                 iError = 0;
29 
30   /*-
31    *******************************************************************
32    *
33    * Initialize variables.
34    *
35    *********************************************************************
36    */
37   psProperties->pFileLog = stderr;
38   psProperties->pFileOut = stdout;
39   if (psProperties->iRunMode == FTIMES_MAPAUTO)
40   {
41     psProperties->bAnalyzeDeviceFiles = TRUE;
42     psProperties->bAnalyzeRemoteFiles = TRUE;
43   }
44   psProperties->bHashSymbolicLinks = TRUE;
45 
46   /*-
47    *******************************************************************
48    *
49    * Conditionally read the config file.
50    *
51    *******************************************************************
52    */
53   if (psProperties->iRunMode == FTIMES_MAPMODE)
54   {
55     iError = PropertiesReadFile(psProperties->acConfigFile, psProperties, acLocalError);
56     if (iError != ER_OK)
57     {
58       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
59       return iError;
60     }
61   }
62 
63   /*-
64    *********************************************************************
65    *
66    * Set the priority.
67    *
68    *********************************************************************
69    */
70   iError = SupportSetPriority(psProperties, acLocalError);
71   if (iError != ER_OK)
72   {
73     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
74     return iError;
75   }
76 
77   /*-
78    *******************************************************************
79    *
80    * Add any command line items to the Include list.
81    *
82    *******************************************************************
83    */
84   while ((pcMapItem = OptionsGetNextOperand(psProperties->psOptionsContext)) != NULL)
85   {
86     iError = SupportExpandPath(pcMapItem, acMapItem, FTIMES_MAX_PATH, 0, acLocalError);
87     if (iError != ER_OK)
88     {
89       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
90       return iError;
91     }
92 
93     iError = SupportAddToList(acMapItem, &psProperties->psIncludeList, "Include", acLocalError);
94     if (iError != ER_OK)
95     {
96       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
97       return iError;
98     }
99   }
100 
101   /*-
102    *********************************************************************
103    *
104    * LogDir defaults to OutDir.
105    *
106    *********************************************************************
107    */
108   if (psProperties->acLogDirName[0] == 0)
109   {
110     snprintf(psProperties->acLogDirName, FTIMES_MAX_PATH, "%s", psProperties->acOutDirName);
111   }
112 
113   /*-
114    *********************************************************************
115    *
116    * Set up the DevelopOutput function pointer.
117    *
118    *********************************************************************
119    */
120   psProperties->piDevelopMapOutput = (psProperties->bCompress) ? DevelopCompressedOutput : DevelopNormalOutput;
121 
122   return ER_OK;
123 }
124 
125 
126 /*-
127  ***********************************************************************
128  *
129  * MapModeCheckDependencies
130  *
131  ***********************************************************************
132  */
133 int
MapModeCheckDependencies(FTIMES_PROPERTIES * psProperties,char * pcError)134 MapModeCheckDependencies(FTIMES_PROPERTIES *psProperties, char *pcError)
135 {
136   const char          acRoutine[] = "MapModeCheckDependencies()";
137 #ifdef USE_SSL
138   char                acLocalError[MESSAGE_SIZE] = "";
139 #endif
140 
141   if (psProperties->psFieldMask == NULL)
142   {
143     snprintf(pcError, MESSAGE_SIZE, "%s: Missing FieldMask.", acRoutine);
144     return ER_MissingControl;
145   }
146 
147 #ifdef USE_XMAGIC
148   /*-
149    *********************************************************************
150    *
151    * Conditionally check that the block size is big enough to support
152    * Magic.
153    *
154    *********************************************************************
155    */
156   if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
157   {
158     if (psProperties->iAnalyzeBlockSize < XMAGIC_READ_BUFSIZE)
159     {
160       snprintf(pcError, MESSAGE_SIZE, "%s: AnalyzeBlockSize (%d) must be at least %d bytes to support XMagic.", acRoutine, psProperties->iAnalyzeBlockSize, XMAGIC_READ_BUFSIZE);
161       return ER;
162     }
163   }
164 #endif
165 
166   /*-
167    *********************************************************************
168    *
169    * Check mode-specific properties.
170    *
171    *********************************************************************
172    */
173   if (psProperties->iRunMode == FTIMES_MAPMODE)
174   {
175     if (psProperties->acBaseName[0] == 0)
176     {
177       snprintf(pcError, MESSAGE_SIZE, "%s: Missing BaseName.", acRoutine);
178       return ER_MissingControl;
179     }
180 
181     if (strcmp(psProperties->acBaseName, "-") == 0)
182     {
183       if (psProperties->bURLPutSnapshot)
184       {
185         snprintf(pcError, MESSAGE_SIZE, "%s: Uploads are not allowed when the BaseName is \"-\". Either disable URLPutSnapshot or change the BaseName.", acRoutine);
186         return ER;
187       }
188     }
189     else
190     {
191       if (psProperties->acOutDirName[0] == 0)
192       {
193         snprintf(pcError, MESSAGE_SIZE, "%s: Missing OutDir.", acRoutine);
194         return ER_MissingControl;
195       }
196     }
197 
198     if (psProperties->bURLPutSnapshot && psProperties->psPutURL == NULL)
199     {
200       snprintf(pcError, MESSAGE_SIZE, "%s: Missing URLPutURL.", acRoutine);
201       return ER_MissingControl;
202     }
203 
204     if (psProperties->bURLPutSnapshot && psProperties->psPutURL->pcPath[0] == 0)
205     {
206       snprintf(pcError, MESSAGE_SIZE, "%s: Missing path in URLPutURL.", acRoutine);
207       return ER_MissingControl;
208     }
209 
210 #ifdef USE_SSL
211     if (SSLCheckDependencies(psProperties->psSslProperties, acLocalError) != ER_OK)
212     {
213       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
214       return ER_MissingControl;
215     }
216 #endif
217   }
218 
219 #ifdef USE_PCRE
220   /*-
221    *********************************************************************
222    *
223    * Attribute filters are not compatible with certain options.
224    *
225    *********************************************************************
226    */
227   if (psProperties->bHaveAttributeFilters)
228   {
229     if (psProperties->bCompress)
230     {
231       snprintf(pcError, MESSAGE_SIZE, "%s: Attribute filters are not supported when compression (Compress) is enabled.", acRoutine);
232       return ER_IncompatibleOptions;
233     }
234 
235     if (psProperties->bHashDirectories)
236     {
237       snprintf(pcError, MESSAGE_SIZE, "%s: Attribute filters are not supported when directory hashing (HashDirectories) is enabled.", acRoutine);
238       return ER_IncompatibleOptions;
239     }
240   }
241 
242   /*-
243    *********************************************************************
244    *
245    * Attribute filters require the corresponding attribute to be set.
246    *
247    *********************************************************************
248    */
249    if ((psProperties->psExcludeFilterMd5List || psProperties->psIncludeFilterMd5List) && !MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MD5))
250    {
251       snprintf(pcError, MESSAGE_SIZE, "%s: The specified attribute filter(s) require the MD5 attribute to be set. Either add this attribute to the FieldMask or remove/disable all include/exclude MD5 filters." , acRoutine);
252       return ER;
253    }
254 
255    if ((psProperties->psExcludeFilterSha1List || psProperties->psIncludeFilterSha1List) && !MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA1))
256    {
257       snprintf(pcError, MESSAGE_SIZE, "%s: The specified attribute filter(s) require the SHA1 attribute to be set. Either add this attribute to the FieldMask or remove/disable all include/exclude SHA1 filters." , acRoutine);
258       return ER;
259    }
260 
261    if ((psProperties->psExcludeFilterSha256List || psProperties->psIncludeFilterSha256List) && !MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_SHA256))
262    {
263       snprintf(pcError, MESSAGE_SIZE, "%s: The specified attribute filter(s) require the SHA256 attribute to be set. Either add this attribute to the FieldMask or remove/disable all include/exclude SHA256 filters." , acRoutine);
264       return ER;
265    }
266 #endif
267 
268   return ER_OK;
269 }
270 
271 
272 /*-
273  ***********************************************************************
274  *
275  * MapModeFinalize
276  *
277  ***********************************************************************
278  */
279 int
MapModeFinalize(FTIMES_PROPERTIES * psProperties,char * pcError)280 MapModeFinalize(FTIMES_PROPERTIES *psProperties, char *pcError)
281 {
282   const char          acRoutine[] = "MapModeFinalize()";
283   char                acLocalError[MESSAGE_SIZE] = "";
284 #ifdef USE_XMAGIC
285   char                acMessage[MESSAGE_SIZE];
286 #endif
287   int                 iError;
288 
289   /*-
290    *********************************************************************
291    *
292    * Enforce privilege requirements, if requested.
293    *
294    *********************************************************************
295    */
296   if (psProperties->bRequirePrivilege)
297   {
298     iError = SupportRequirePrivilege(acLocalError);
299     if (iError != ER_OK)
300     {
301       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
302       return iError;
303     }
304   }
305 
306   /*-
307    *********************************************************************
308    *
309    * Conditionally check the server uplink.
310    *
311    *********************************************************************
312    */
313   if (psProperties->bURLPutSnapshot && psProperties->iRunMode == FTIMES_MAPMODE)
314   {
315     iError = URLPingRequest(psProperties, acLocalError);
316     if (iError != ER_OK)
317     {
318       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
319       return ER_URLPingRequest;
320     }
321   }
322 
323   /*-
324    *********************************************************************
325    *
326    * Conditionally set up the Digest engine. NOTE: The conditionals are
327    * tested inside the subroutine.
328    *
329    *********************************************************************
330    */
331   AnalyzeEnableDigestEngine(psProperties);
332 
333 #ifdef USE_XMAGIC
334   /*-
335    *********************************************************************
336    *
337    * Conditionally set up the Magic engine.
338    *
339    *********************************************************************
340    */
341   if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
342   {
343     iError = AnalyzeEnableXMagicEngine(psProperties, acLocalError);
344     if (iError != ER_OK)
345     {
346       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
347       return iError;
348     }
349   }
350 #endif
351 
352   /*-
353    *********************************************************************
354    *
355    * If the Include list is NULL, include everything.
356    *
357    *********************************************************************
358    */
359   if (psProperties->psIncludeList == NULL)
360   {
361     psProperties->psIncludeList = SupportIncludeEverything(acLocalError);
362     if (psProperties->psIncludeList == NULL)
363     {
364       snprintf(pcError, MESSAGE_SIZE, "%s: Failed to build a default Include list: %s", acRoutine, acLocalError);
365       return ER_BadHandle;
366     }
367   }
368 
369   /*-
370    *********************************************************************
371    *
372    * Prune the Include list.
373    *
374    *********************************************************************
375    */
376   psProperties->psIncludeList = SupportPruneList(psProperties->psIncludeList, "Include");
377   if (psProperties->psIncludeList == NULL)
378   {
379     snprintf(pcError, MESSAGE_SIZE, "%s: There's nothing left to process in the Include list.", acRoutine);
380     return ER_NothingToDo;
381   }
382 
383   /*-
384    *********************************************************************
385    *
386    * Conditionally check the Include and Exclude lists.
387    *
388    *********************************************************************
389    */
390   if (psProperties->bExcludesMustExist)
391   {
392     iError = SupportCheckList(psProperties->psExcludeList, "Exclude", acLocalError);
393     if (iError != ER_OK)
394     {
395       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
396       return iError;
397     }
398   }
399 
400   if (psProperties->bIncludesMustExist)
401   {
402     iError = SupportCheckList(psProperties->psIncludeList, "Include", acLocalError);
403     if (iError != ER_OK)
404     {
405       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
406       return iError;
407     }
408   }
409 
410   /*-
411    *********************************************************************
412    *
413    * Establish Log file stream, and update Message Handler.
414    *
415    *********************************************************************
416    */
417   if (psProperties->iRunMode == FTIMES_MAPMODE && strcmp(psProperties->acBaseName, "-") != 0)
418   {
419     iError = SupportMakeName(psProperties->acLogDirName, psProperties->acBaseName, psProperties->acBaseNameSuffix, ".log", psProperties->acLogFileName, acLocalError);
420     if (iError != ER_OK)
421     {
422       snprintf(pcError, MESSAGE_SIZE, "%s: Log File: %s", acRoutine, acLocalError);
423       return iError;
424     }
425 
426     iError = SupportAddToList(psProperties->acLogFileName, &psProperties->psExcludeList, "Exclude", acLocalError);
427     if (iError != ER_OK)
428     {
429       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
430       return iError;
431     }
432 
433     psProperties->pFileLog = fopen(psProperties->acLogFileName, "wb+");
434     if (psProperties->pFileLog == NULL)
435     {
436       snprintf(pcError, MESSAGE_SIZE, "%s: LogFile = [%s]: %s", acRoutine, psProperties->acLogFileName, strerror(errno));
437       return ER_fopen;
438     }
439 /* FIXME Remove this #ifdef at some point in the future. */
440 #ifdef WIN32
441     /*-
442      *****************************************************************
443      *
444      * NOTE: The buffer size was explicitly set to prevent binaries
445      * made with Visual Studio 2005 (no service packs) from crashing
446      * when run in lean mode. This problem may have been fixed in
447      * Service Pack 1.
448      *
449      *****************************************************************
450      */
451     setvbuf(psProperties->pFileLog, NULL, _IOLBF, 1024);
452 #else
453     setvbuf(psProperties->pFileLog, NULL, _IOLBF, 0);
454 #endif
455   }
456   else
457   {
458     strncpy(psProperties->acLogFileName, "stderr", FTIMES_MAX_PATH);
459     psProperties->pFileLog = stderr;
460   }
461 
462   MessageSetNewLine(psProperties->acNewLine);
463   MessageSetOutputStream(psProperties->pFileLog);
464   MessageSetAutoFlush(MESSAGE_AUTO_FLUSH_ON);
465 
466   /*-
467    *******************************************************************
468    *
469    * Establish Out file stream.
470    *
471    *******************************************************************
472    */
473   if (psProperties->iRunMode == FTIMES_MAPMODE && strcmp(psProperties->acBaseName, "-") != 0)
474   {
475     iError = SupportMakeName(psProperties->acOutDirName, psProperties->acBaseName, psProperties->acBaseNameSuffix, ".map", psProperties->acOutFileName, acLocalError);
476     if (iError != ER_OK)
477     {
478       snprintf(pcError, MESSAGE_SIZE, "%s: Out File: %s", acRoutine, acLocalError);
479       return iError;
480     }
481 
482     iError = SupportAddToList(psProperties->acOutFileName, &psProperties->psExcludeList, "Exclude", acLocalError);
483     if (iError != ER_OK)
484     {
485       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
486       return iError;
487     }
488 
489     psProperties->pFileOut = fopen(psProperties->acOutFileName, "wb+");
490     if (psProperties->pFileOut == NULL)
491     {
492       snprintf(pcError, MESSAGE_SIZE, "%s: OutFile = [%s]: %s", acRoutine, psProperties->acOutFileName, strerror(errno));
493       return ER_fopen;
494     }
495 /* FIXME Remove this #ifdef at some point in the future. */
496 #ifdef WIN32
497     /*-
498      *****************************************************************
499      *
500      * NOTE: The buffer size was explicitly set to prevent binaries
501      * made with Visual Studio 2005 (no service packs) from crashing
502      * when run in lean mode. This problem may have been fixed in
503      * Service Pack 1.
504      *
505      *****************************************************************
506      */
507     setvbuf(psProperties->pFileOut, NULL, _IOLBF, 1024);
508 #else
509     setvbuf(psProperties->pFileOut, NULL, _IOLBF, 0);
510 #endif
511   }
512   else
513   {
514     strncpy(psProperties->acOutFileName, "stdout", FTIMES_MAX_PATH);
515     psProperties->pFileOut = stdout;
516   }
517 
518   /*-
519    *********************************************************************
520    *
521    * Display properties.
522    *
523    *********************************************************************
524    */
525   PropertiesDisplaySettings(psProperties);
526 
527 #ifdef USE_XMAGIC
528   if (MASK_BIT_IS_SET(psProperties->psFieldMask->ulMask, MAP_MAGIC))
529   {
530     snprintf(acMessage, MESSAGE_SIZE, "%s=%s", KEY_MagicFile, psProperties->acMagicFileName);
531     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
532 
533     snprintf(acMessage, MESSAGE_SIZE, "MagicHash=%s", psProperties->acMagicHash);
534     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
535   }
536 #endif
537 
538   /*-
539    *********************************************************************
540    *
541    * Write out a header.
542    *
543    *********************************************************************
544    */
545   iError = MapWriteHeader(psProperties, acLocalError);
546   if (iError != ER_OK)
547   {
548     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
549     return iError;
550   }
551 
552   return ER_OK;
553 }
554 
555 
556 /*-
557  ***********************************************************************
558  *
559  * MapModeWorkHorse
560  *
561  ***********************************************************************
562  */
563 int
MapModeWorkHorse(FTIMES_PROPERTIES * psProperties,char * pcError)564 MapModeWorkHorse(FTIMES_PROPERTIES *psProperties, char *pcError)
565 {
566   char                acLocalError[MESSAGE_SIZE] = "";
567   FILE_LIST           *psList = NULL;
568 
569   /*-
570    *********************************************************************
571    *
572    * Process the Include list.
573    *
574    *********************************************************************
575    */
576   for (psList = psProperties->psIncludeList; psList != NULL; psList = psList->psNext)
577   {
578     if (SupportMatchExclude(psProperties->psExcludeList, psList->pcRegularPath) == NULL)
579     {
580       MapFile(psProperties, psList->pcRegularPath, acLocalError);
581     }
582   }
583 
584   return ER_OK;
585 }
586 
587 
588 /*-
589  ***********************************************************************
590  *
591  * MapModeFinishUp
592  *
593  ***********************************************************************
594  */
595 int
MapModeFinishUp(FTIMES_PROPERTIES * psProperties,char * pcError)596 MapModeFinishUp(FTIMES_PROPERTIES *psProperties, char *pcError)
597 {
598   char                acMessage[MESSAGE_SIZE];
599   int                 i;
600   int                 iFirst;
601   int                 iIndex;
602   unsigned char       aucFileHash[MD5_HASH_SIZE];
603 
604   /*-
605    *********************************************************************
606    *
607    * Close up the output stream, and complete the file digest.
608    *
609    *********************************************************************
610    */
611   if (psProperties->pFileOut && psProperties->pFileOut != stdout)
612   {
613     fflush(psProperties->pFileOut);
614     fclose(psProperties->pFileOut);
615     psProperties->pFileOut = NULL;
616   }
617 
618   memset(aucFileHash, 0, MD5_HASH_SIZE);
619   MD5Omega(&psProperties->sOutFileHashContext, aucFileHash);
620   MD5HashToHex(aucFileHash, psProperties->acOutFileHash);
621 
622   /*-
623    *********************************************************************
624    *
625    * Print output filenames.
626    *
627    *********************************************************************
628    */
629   snprintf(acMessage, MESSAGE_SIZE, "LogFileName=%s", psProperties->acLogFileName);
630   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
631 
632   snprintf(acMessage, MESSAGE_SIZE, "OutFileName=%s", psProperties->acOutFileName);
633   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
634 
635   snprintf(acMessage, MESSAGE_SIZE, "OutFileHash=%s", psProperties->acOutFileHash);
636   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
637 
638   snprintf(acMessage, MESSAGE_SIZE, "DataType=%s", psProperties->acDataType);
639   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
640 
641   /*-
642    *********************************************************************
643    *
644    * Write out the statistics.
645    *
646    *********************************************************************
647    */
648   snprintf(acMessage, MESSAGE_SIZE, "DirectoriesEncountered=%d", MapGetDirectoryCount());
649   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
650 
651   snprintf(acMessage, MESSAGE_SIZE, "FilesEncountered=%d", MapGetFileCount());
652   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
653 
654 #ifdef UNIX
655   snprintf(acMessage, MESSAGE_SIZE, "SpecialsEncountered=%d", MapGetSpecialCount());
656   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
657 #endif
658 
659 #ifdef WINNT
660   snprintf(acMessage, MESSAGE_SIZE, "StreamsEncountered=%d", MapGetStreamCount());
661   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
662 #endif
663 
664   iIndex = 0;
665   if (psProperties->iLastAnalysisStage > 0)
666   {
667     iIndex = sprintf(&acMessage[iIndex], "AnalysisStages=");
668     for (i = 0, iFirst = 0; i < psProperties->iLastAnalysisStage; i++)
669     {
670       iIndex += sprintf(&acMessage[iIndex], "%s%s", (iFirst++ > 0) ? "," : "", psProperties->asAnalysisStages[i].acDescription);
671     }
672     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
673 
674     snprintf(acMessage, MESSAGE_SIZE, "ObjectsAnalyzed=%u", AnalyzeGetFileCount());
675     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
676 
677 #ifdef UNIX
678 #ifdef USE_AP_SNPRINTF
679     snprintf(acMessage, MESSAGE_SIZE, "BytesAnalyzed=%qu", (unsigned long long) AnalyzeGetByteCount());
680     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
681 #else
682     snprintf(acMessage, MESSAGE_SIZE, "BytesAnalyzed=%llu", (unsigned long long) AnalyzeGetByteCount());
683     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
684 #endif
685 #endif
686 
687 #ifdef WIN32
688     snprintf(acMessage, MESSAGE_SIZE, "BytesAnalyzed=%I64u", AnalyzeGetByteCount());
689     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
690 #endif
691   }
692   else
693   {
694     snprintf(acMessage, MESSAGE_SIZE, "AnalysisStages=None");
695     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
696   }
697 
698   /*-
699    *********************************************************************
700    *
701    * List the number of map records.
702    *
703    *********************************************************************
704    */
705   snprintf(acMessage, MESSAGE_SIZE, "MapRecords=%d", MapGetRecordCount());
706   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
707 
708   snprintf(acMessage, MESSAGE_SIZE, "PartialMapRecords=%d", MapGetIncompleteRecordCount());
709   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
710 
711   SupportDisplayRunStatistics(psProperties);
712 
713   return ER_OK;
714 }
715 
716 
717 /*-
718  ***********************************************************************
719  *
720  * MapModeFinalStage
721  *
722  ***********************************************************************
723  */
724 int
MapModeFinalStage(FTIMES_PROPERTIES * psProperties,char * pcError)725 MapModeFinalStage(FTIMES_PROPERTIES *psProperties, char *pcError)
726 {
727   const char          acRoutine[] = "MapModeFinalStage()";
728   char                acLocalError[MESSAGE_SIZE] = "";
729   int                 iError;
730 
731   /*-
732    *********************************************************************
733    *
734    * Conditionally upload the collected data.
735    *
736    *********************************************************************
737    */
738   if (psProperties->bURLPutSnapshot && psProperties->iRunMode == FTIMES_MAPMODE)
739   {
740     iError = URLPutRequest(psProperties, acLocalError);
741     if (iError != ER_OK)
742     {
743       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
744       return ER_URLPutRequest;
745     }
746 
747     if (psProperties->bURLUnlinkOutput)
748     {
749       FTimesEraseFiles(psProperties, pcError);
750     }
751   }
752 
753   return ER_OK;
754 }
755