1 /*-
2 ***********************************************************************
3 *
4 * $Id: support.c,v 1.64 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 #ifdef WIN32
15 static int (*CompareFunction) () = strcasecmp;
16 static int (*NCompareFunction) () = strncasecmp;
17 #else
18 static int (*CompareFunction) () = strcmp;
19 static int (*NCompareFunction) () = strncmp;
20 #endif
21
22 /*-
23 ***********************************************************************
24 *
25 * SupportAddListItem
26 *
27 ***********************************************************************
28 */
29 FILE_LIST *
SupportAddListItem(FILE_LIST * psItem,FILE_LIST * psHead,char * pcError)30 SupportAddListItem(FILE_LIST *psItem, FILE_LIST *psHead, char *pcError)
31 {
32 const char acRoutine[] = "SupportAddListItem()";
33 FILE_LIST *psCurrent = NULL;
34 FILE_LIST *psTail = NULL;
35
36 /*-
37 *********************************************************************
38 *
39 * Check that the item is not NULL.
40 *
41 *********************************************************************
42 */
43 if (psItem == NULL)
44 {
45 snprintf(pcError, MESSAGE_SIZE, "%s: NULL input. That shouldn't happen.", acRoutine);
46 return NULL;
47 }
48
49 /*-
50 *********************************************************************
51 *
52 * If the head is NULL, return the new item as the head.
53 *
54 *********************************************************************
55 */
56 if (psHead == NULL)
57 {
58 return psItem;
59 }
60
61 /*-
62 *********************************************************************
63 *
64 * Otherwise, find the tail, and append the new item to it.
65 *
66 *********************************************************************
67 */
68 for (psCurrent = psTail = psHead; psCurrent != NULL; psCurrent = psCurrent->psNext)
69 {
70 if (psCurrent->psNext == NULL)
71 {
72 psTail = psCurrent;
73 }
74 }
75 psTail->psNext = psItem;
76
77 return psHead;
78 }
79
80
81 /*-
82 ***********************************************************************
83 *
84 * SupportAddToList
85 *
86 ***********************************************************************
87 */
88 int
SupportAddToList(char * pcPath,FILE_LIST ** ppsList,char * pcListName,char * pcError)89 SupportAddToList(char *pcPath, FILE_LIST **ppsList, char *pcListName, char *pcError)
90 {
91 const char acRoutine[] = "SupportAddToList()";
92 char acLocalError[MESSAGE_SIZE] = "";
93 char acLocalPath[FTIMES_MAX_PATH];
94 int iIndex = 0;
95 int iLocalIndex = 0;
96 int iLength = 0;
97 int iType = FILE_LIST_REGULAR;
98 FILE_LIST *psHead = NULL;
99 FILE_LIST *psItem = NULL;
100
101 /*-
102 *********************************************************************
103 *
104 * Make sure that the path has a valid length.
105 *
106 *********************************************************************
107 */
108 iLength = strlen(pcPath);
109 if (iLength < 1 || iLength > FTIMES_MAX_PATH - 1)
110 {
111 snprintf(pcError, MESSAGE_SIZE, "%s: List = [%s], Length = [%d]: Path must be at least 1 byte and less than %d bytes long.", acRoutine, pcListName, iLength, FTIMES_MAX_PATH);
112 return ER;
113 }
114
115 /*-
116 *********************************************************************
117 *
118 * Check to see if this is a URL-encoded path. If it is, advance the
119 * index to skip over the "file://" prefix, and set the path type.
120 *
121 *********************************************************************
122 */
123 if (strncmp(pcPath, "file://", 7) == 0)
124 {
125 iIndex = 7;
126 iType = FILE_LIST_ENCODED;
127 }
128
129 /*-
130 *********************************************************************
131 *
132 * Make sure that we have the start of a full path.
133 *
134 *********************************************************************
135 */
136 #ifdef WIN32
137 //THIS CHANGE IS PART OF EXTENDED PREFIX SUPPORT (\\?\)
138 // if (!(isalpha((int) pcPath[iIndex]) && pcPath[iIndex + 1] == ':'))
139 if (!(isalpha((int) pcPath[iIndex]) && pcPath[iIndex + 1] == ':' && pcPath[iIndex + 2] == FTIMES_SLASHCHAR))
140 //END (\\?\)
141 #else
142 if (pcPath[iIndex] != FTIMES_SLASHCHAR)
143 #endif
144 {
145 snprintf(pcError, MESSAGE_SIZE, "%s: List = [%s], Item = [%s]: A full path is required.", acRoutine, pcListName, pcPath);
146 return ER;
147 }
148
149 /*-
150 *********************************************************************
151 *
152 * Copy pcPath into acLocalPath removing extra slashes along the way.
153 *
154 *********************************************************************
155 */
156 for (iLocalIndex = 0; iIndex < iLength; iIndex++)
157 {
158 if
159 (
160 (
161 (iType == FILE_LIST_REGULAR && iIndex > 0) ||
162 (iType == FILE_LIST_ENCODED && iIndex > 7)
163 ) &&
164 pcPath[iIndex] == FTIMES_SLASHCHAR &&
165 pcPath[iIndex - 1] == FTIMES_SLASHCHAR
166 )
167 {
168 continue;
169 }
170 acLocalPath[iLocalIndex++] = pcPath[iIndex];
171 }
172 acLocalPath[iLocalIndex] = 0;
173 iLength = iLocalIndex;
174
175 /*-
176 *********************************************************************
177 *
178 * If this is not the root directory chop off any trailing slashes.
179 *
180 *********************************************************************
181 */
182 //THIS CHANGE IS PART OF EXTENDED PREFIX SUPPORT (\\?\)
183 #ifdef WIN32
184 if (strcmp(&acLocalPath[2], FTIMES_SLASH) != 0)
185 #else
186 if (strcmp(acLocalPath, FTIMES_SLASH) != 0)
187 #endif
188 //END (\\?\)
189 {
190 while (acLocalPath[iLength - 1] == FTIMES_SLASHCHAR && iLength > 1)
191 {
192 acLocalPath[--iLength] = 0;
193 }
194 }
195
196 /*-
197 *********************************************************************
198 *
199 * Allocate and initialize a new item.
200 *
201 *********************************************************************
202 */
203 psItem = SupportNewListItem(acLocalPath, iType, acLocalError);
204 if (psItem == NULL)
205 {
206 snprintf(pcError, MESSAGE_SIZE, "%s: List = [%s], Item = [%s]: %s", acRoutine, pcListName, pcPath, acLocalError);
207 return ER;
208 }
209
210 /*-
211 *********************************************************************
212 *
213 * If this is not a duplicate item, add it to the list.
214 *
215 *********************************************************************
216 */
217 if (SupportMatchExclude(*ppsList, psItem->pcRegularPath) == NULL)
218 {
219 psHead = SupportAddListItem(psItem, *ppsList, acLocalError);
220 if (psHead == NULL)
221 {
222 snprintf(pcError, MESSAGE_SIZE, "%s: List = [%s], Item = [%s]: %s", acRoutine, pcListName, pcPath, acLocalError);
223 SupportFreeListItem(psItem);
224 return ER;
225 }
226 if (*ppsList == NULL)
227 {
228 *ppsList = psHead;
229 }
230 }
231 else
232 {
233 snprintf(acLocalError, MESSAGE_SIZE, "List = [%s], Item = [%s]: Ignoring duplicate item.", pcListName, pcPath);
234 ErrorHandler(ER_Warning, acLocalError, ERROR_WARNING);
235 }
236
237 return ER_OK;
238 }
239
240
241 #ifdef WINNT
242 /*-
243 ***********************************************************************
244 *
245 * SupportAdjustPrivileges
246 *
247 ***********************************************************************
248 */
249 BOOL
SupportAdjustPrivileges(LPCTSTR lpcPrivilege)250 SupportAdjustPrivileges(LPCTSTR lpcPrivilege)
251 {
252 HANDLE hToken;
253 TOKEN_PRIVILEGES sTokenPrivileges;
254 BOOL bResult;
255
256 /*-
257 *********************************************************************
258 *
259 * Open the access token associated with this process.
260 *
261 *********************************************************************
262 */
263 bResult = OpenProcessToken
264 (
265 GetCurrentProcess(),
266 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
267 &hToken
268 );
269 if (bResult == FALSE)
270 {
271 return FALSE;
272 }
273
274 /*-
275 *********************************************************************
276 *
277 * Retrieve the locally unique identifier (LUID) used on this system
278 * that represents the specified privilege.
279 *
280 *********************************************************************
281 */
282 bResult = LookupPrivilegeValue(
283 NULL,
284 lpcPrivilege,
285 &sTokenPrivileges.Privileges[0].Luid
286 );
287
288 if (bResult == FALSE)
289 {
290 return FALSE;
291 }
292
293 sTokenPrivileges.PrivilegeCount = 1;
294
295 /*-
296 *********************************************************************
297 *
298 * One privilege to set.
299 *
300 *********************************************************************
301 */
302 sTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
303
304 /*-
305 *********************************************************************
306 *
307 * Enable the specified privilege. Note: Enabling and/or disabling
308 * privileges requires TOKEN_ADJUST_PRIVILEGES access.
309 *
310 *********************************************************************
311 */
312 bResult = AdjustTokenPrivileges(
313 hToken,
314 FALSE,
315 &sTokenPrivileges,
316 0,
317 (PTOKEN_PRIVILEGES) NULL,
318 0
319 );
320
321 if (bResult == FALSE || GetLastError() != ERROR_SUCCESS)
322 {
323 return FALSE;
324 }
325
326 return TRUE;
327 }
328 #endif
329
330
331 /*-
332 ***********************************************************************
333 *
334 * SupportCheckList
335 *
336 ***********************************************************************
337 */
338 int
SupportCheckList(FILE_LIST * psHead,char * pcListName,char * pcError)339 SupportCheckList(FILE_LIST *psHead, char *pcListName, char *pcError)
340 {
341 const char acRoutine[] = "SupportCheckList()";
342 char acLocalError[MESSAGE_SIZE] = "";
343 FILE_LIST *psList;
344
345 for (psList = psHead; psList != NULL; psList = psList->psNext)
346 {
347 if (SupportGetFileType(psList->pcRegularPath, acLocalError) == FTIMES_FILETYPE_ERROR)
348 {
349 snprintf(pcError, MESSAGE_SIZE, "%s: List = [%s], NeuteredItem = [%s]: %s", acRoutine, pcListName, psList->pcEncodedPath, acLocalError);
350 return ER;
351 }
352 }
353 return ER_OK;
354 }
355
356
357 /*-
358 ***********************************************************************
359 *
360 * SupportChopEOLs
361 *
362 ***********************************************************************
363 */
364 int
SupportChopEOLs(char * pcLine,int iStrict,char * pcError)365 SupportChopEOLs(char *pcLine, int iStrict, char *pcError)
366 {
367 const char acRoutine[] = "SupportChopEOLs()";
368 int iLineLength;
369 int iSaveLength;
370
371 /*-
372 *********************************************************************
373 *
374 * Calculate line length.
375 *
376 *********************************************************************
377 */
378 iLineLength = iSaveLength = strlen(pcLine);
379
380 /*-
381 *********************************************************************
382 *
383 * Scan backwards over EOL characters.
384 *
385 *********************************************************************
386 */
387 while (iLineLength > 0 && ((pcLine[iLineLength - 1] == '\r') || (pcLine[iLineLength - 1] == '\n')))
388 {
389 iLineLength--;
390 }
391
392 /*-
393 *********************************************************************
394 *
395 * If strict checking is on and EOL was not found, it's an error.
396 *
397 *********************************************************************
398 */
399 if (iStrict && iLineLength == iSaveLength)
400 {
401 snprintf(pcError, MESSAGE_SIZE, "%s: EOL required but not found.", acRoutine);
402 return ER;
403 }
404
405 /*-
406 *********************************************************************
407 *
408 * Terminate line excluding any EOL characters.
409 *
410 *********************************************************************
411 */
412 pcLine[iLineLength] = 0;
413
414 return ER_OK;
415 }
416
417
418 /*-
419 ***********************************************************************
420 *
421 * SupportDisplayRunStatistics
422 *
423 ***********************************************************************
424 */
425 void
SupportDisplayRunStatistics(FTIMES_PROPERTIES * psProperties)426 SupportDisplayRunStatistics(FTIMES_PROPERTIES *psProperties)
427 {
428 char acMessage[MESSAGE_SIZE];
429 double dStopTime = 0;
430
431 /*-
432 *********************************************************************
433 *
434 * Stop the RunTime clock. Report Warnings, Failures, and RunTime.
435 *
436 *********************************************************************
437 */
438 dStopTime = TimeGetTimeValueAsDouble();
439
440 snprintf(acMessage, MESSAGE_SIZE, "Warnings=%d", ErrorGetWarnings());
441 MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
442
443 snprintf(acMessage, MESSAGE_SIZE, "Failures=%d", ErrorGetFailures());
444 MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
445
446 snprintf(acMessage, MESSAGE_SIZE, "Duration=%.6f (s)", (double) (dStopTime - psProperties->dStartTime));
447 MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
448
449 switch (psProperties->iRunMode)
450 {
451 case FTIMES_DIGAUTO:
452 case FTIMES_DIGMODE:
453 case FTIMES_MAPAUTO:
454 case FTIMES_MAPMODE:
455 case FTIMES_MADMODE:
456 snprintf(acMessage, MESSAGE_SIZE, "AnalysisTime=%.6f (s)", AnalyzeGetAnalysisTime());
457 MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
458 snprintf(acMessage, MESSAGE_SIZE, "AverageDps=%.2f (KB/s)", AnalyzeGetDps());
459 MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
460 break;
461 }
462 }
463
464
465 /*-
466 ***********************************************************************
467 *
468 * SupportDropListItem
469 *
470 ***********************************************************************
471 */
472 FILE_LIST *
SupportDropListItem(FILE_LIST * psHead,FILE_LIST * psDrop)473 SupportDropListItem(FILE_LIST *psHead, FILE_LIST *psDrop)
474 {
475 FILE_LIST *psList;
476 FILE_LIST *psNewHead;
477
478 psNewHead = psHead;
479
480 if (psDrop == psHead)
481 {
482 psNewHead = psDrop->psNext;
483 free(psDrop);
484 }
485 else
486 {
487 for (psList = psHead; psList != NULL; psList = psList->psNext)
488 {
489 if (psDrop == psList->psNext)
490 {
491 psList->psNext = psDrop->psNext;
492 free(psDrop);
493 }
494 }
495 }
496 return psNewHead;
497 }
498
499
500 /*-
501 ***********************************************************************
502 *
503 * SupportEraseFile
504 *
505 ***********************************************************************
506 */
507 int
SupportEraseFile(char * pcName,char * pcError)508 SupportEraseFile(char *pcName, char *pcError)
509 {
510 const char acRoutine[] = "SupportEraseFile()";
511 #define WIPE_BUFSIZE 0x8000
512 char *apcWipe[WIPE_BUFSIZE];
513 long lFileLength;
514 long lNWiped;
515 FILE *pFile;
516
517 if ((pFile = fopen(pcName, "rb+")) != NULL)
518 {
519 fseek(pFile, 0, SEEK_END);
520 lFileLength = ftell(pFile);
521 rewind(pFile);
522 lNWiped = 0;
523 memset(apcWipe, 0xa5, WIPE_BUFSIZE);
524 while (((lNWiped += fwrite(apcWipe, 1, WIPE_BUFSIZE, pFile)) <= lFileLength) && !ferror(pFile));
525 fclose(pFile);
526 }
527
528 if (unlink(pcName) != ER_OK)
529 {
530 snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, strerror(errno));
531 return ER;
532 }
533
534 return ER_OK;
535 }
536
537
538 /*-
539 ***********************************************************************
540 *
541 * SupportExpandDirectoryPath
542 *
543 ***********************************************************************
544 */
545 int
SupportExpandDirectoryPath(char * pcPath,char * pcFullPath,int iFullPathSize,char * pcError)546 SupportExpandDirectoryPath(char *pcPath, char *pcFullPath, int iFullPathSize, char *pcError)
547 {
548 const char acRoutine[] = "SupportExpandDirectoryPath()";
549 char *pcCwdDir;
550 char *pcNewDir;
551 char *pcTempPath;
552 int iError;
553 int iLength;
554
555 iLength = strlen(pcPath);
556 if (iLength < 1)
557 {
558 snprintf(pcError, MESSAGE_SIZE, "%s: Directory = [%s], Length = [%d]: Length less than 1 byte.", acRoutine, pcPath, iLength);
559 return ER_Length;
560 }
561
562 if (iLength > iFullPathSize - 1)
563 {
564 snprintf(pcError, MESSAGE_SIZE, "%s: Directory = [%s]: Length (%d) exceeds %d bytes.", acRoutine, pcPath, iLength, iFullPathSize - 1);
565 return ER_Length;
566 }
567
568 pcTempPath = malloc(iLength + 2); /* +1 for a FTIMES_SLASHCHAR, +1 for a NULL */
569 if (pcTempPath == NULL)
570 {
571 snprintf(pcError, MESSAGE_SIZE, "%s: Directory = [%s]: %s", acRoutine, pcPath, strerror(errno));
572 return ER_BadHandle;
573 }
574
575 strcpy(pcTempPath, pcPath);
576
577 /*-
578 *********************************************************************
579 *
580 * We need to tack on a FTIMES_SLASHCHAR so that NT can figure out what we
581 * want to do. If you are in c:\xyz and type "cd c:", NT will simply
582 * print out the name of the directory that you are in (i.e. c:\xyz).
583 * To avoid this problem, you need to type "cd c:\". The same seems
584 * to be true for getwcd().
585 *
586 *********************************************************************
587 */
588 if (pcPath[iLength - 1] != FTIMES_SLASHCHAR)
589 {
590 pcTempPath[iLength] = FTIMES_SLASHCHAR;
591 pcTempPath[iLength + 1] = 0;
592 }
593
594 /*-
595 *********************************************************************
596 *
597 * Save the current directory entry after getting its full path.
598 *
599 *********************************************************************
600 */
601 pcCwdDir = getcwd(NULL, FTIMES_MAX_PATH);
602 if (pcCwdDir == NULL)
603 {
604 snprintf(pcError, MESSAGE_SIZE, "%s: Directory = [%s]: %s", acRoutine, pcPath, strerror(errno));
605 free(pcTempPath);
606 return ER;
607 }
608
609 /*-
610 *********************************************************************
611 *
612 * Change to the specified directory, and expand its path.
613 *
614 *********************************************************************
615 */
616 iError = chdir((const char *) pcTempPath);
617 if (iError != ER_OK)
618 {
619 snprintf(pcError, MESSAGE_SIZE, "%s: Directory = [%s]: %s", acRoutine, pcPath, strerror(errno));
620 free(pcTempPath);
621 free(pcCwdDir); /* Created by getcwd() */
622 return ER;
623 }
624
625 pcNewDir = getcwd(pcFullPath, iFullPathSize);
626 if (pcNewDir == NULL)
627 {
628 snprintf(pcError, MESSAGE_SIZE, "%s: Directory = [%s]: %s", acRoutine, pcPath, strerror(errno));
629 free(pcTempPath);
630 free(pcCwdDir); /* Created by getcwd() */
631 return ER;
632 }
633
634 /*-
635 *********************************************************************
636 *
637 * Chop off any trailing slashes.
638 *
639 *********************************************************************
640 */
641 iLength = strlen(pcFullPath);
642 while (pcFullPath[iLength - 1] == FTIMES_SLASHCHAR && iLength > 1)
643 {
644 pcFullPath[--iLength] = 0;
645 }
646
647 /*-
648 *********************************************************************
649 *
650 * Change back to the starting directory.
651 *
652 *********************************************************************
653 */
654 iError = chdir((const char *) pcCwdDir);
655 if (iError != ER_OK)
656 {
657 snprintf(pcError, MESSAGE_SIZE, "%s: Directory = [%s]: %s", acRoutine, pcPath, strerror(errno));
658 free(pcTempPath);
659 free(pcCwdDir); /* Created by getcwd() */
660 return ER;
661 }
662
663 free(pcTempPath);
664 free(pcCwdDir); /* Created by getcwd() */
665
666 return ER_OK;
667 }
668
669
670 /*-
671 ***********************************************************************
672 *
673 * SupportExpandPath
674 *
675 ***********************************************************************
676 */
677 int
SupportExpandPath(char * pcPath,char * pcFullPath,int iFullPathSize,int iForceExpansion,char * pcError)678 SupportExpandPath(char *pcPath, char *pcFullPath, int iFullPathSize, int iForceExpansion, char *pcError)
679 {
680 const char acRoutine[] = "SupportExpandPath()";
681 char acLocalError[MESSAGE_SIZE] = "";
682 char *pcTempFile;
683 char *pcTempPath;
684 int iError;
685 int iLength;
686 int iTempLength;
687
688 iLength = iTempLength = strlen(pcPath);
689 if (iLength < 1)
690 {
691 snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s], Length = [%d]: Length less than 1 byte.", acRoutine, pcPath, iLength);
692 return ER_Length;
693 }
694
695 if (iLength > iFullPathSize - 1)
696 {
697 snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: Length (%d) exceeds %d bytes.", acRoutine, pcPath, iLength, iFullPathSize - 1);
698 return ER_Length;
699 }
700
701 /*-
702 *********************************************************************
703 *
704 * If the path is URL-encoded, no expansion is performed.
705 *
706 *********************************************************************
707 */
708 if (strncmp(pcPath, "file://", 7) == 0)
709 {
710 strncpy(pcFullPath, pcPath, iFullPathSize);
711 return ER_OK;
712 }
713
714 /*-
715 *********************************************************************
716 *
717 * If forced expansion is disabled, fully qualified paths are copied
718 * directly into the output buffer. However, relative paths must be
719 * expanded in any case.
720 *
721 *********************************************************************
722 */
723 if (!iForceExpansion)
724 {
725 #ifdef WIN32
726 if (
727 (iLength == 2 && isalpha((int) pcPath[0]) && pcPath[1] == ':') ||
728 (iLength >= 3 && isalpha((int) pcPath[0]) && pcPath[1] == ':' && pcPath[2] == FTIMES_SLASHCHAR)
729 )
730 {
731 strncpy(pcFullPath, pcPath, iFullPathSize);
732 return ER_OK;
733 }
734 #endif
735 #ifdef UNIX
736 if (pcPath[0] == FTIMES_SLASHCHAR)
737 {
738 strncpy(pcFullPath, pcPath, iFullPathSize);
739 return ER_OK;
740 }
741 #endif
742 }
743
744 switch (SupportGetFileType(pcPath, acLocalError))
745 {
746 case FTIMES_FILETYPE_ERROR:
747 snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, pcPath, acLocalError);
748 return ER_BadValue;
749 break;
750
751 case FTIMES_FILETYPE_DIRECTORY:
752 iError = SupportExpandDirectoryPath(pcPath, pcFullPath, iFullPathSize, acLocalError);
753 if (iError != ER_OK)
754 {
755 snprintf(pcError, MESSAGE_SIZE, "%s: Path = [%s]: %s", acRoutine, pcPath, acLocalError);
756 return iError;
757 }
758 break;
759
760 default:
761 /*-
762 *******************************************************************
763 *
764 * Create a working copy of the input path.
765 *
766 *******************************************************************
767 */
768 pcTempFile = malloc(iLength + 1); /* +1 for a NULL */
769 if (pcTempFile == NULL)
770 {
771 snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, pcPath, strerror(errno));
772 return ER_BadHandle;
773 }
774
775 pcTempPath = malloc(iLength + 1); /* +1 for a NULL */
776 if (pcTempPath == NULL)
777 {
778 snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, pcPath, strerror(errno));
779 free(pcTempFile);
780 return ER_BadHandle;
781 }
782
783 strcpy(pcTempPath, pcPath);
784
785 /*-
786 *******************************************************************
787 *
788 * Scan backwards looking for a directory separator. If found, note
789 * the location.
790 *
791 *******************************************************************
792 */
793 while (iTempLength > 0)
794 {
795 if (pcTempPath[iTempLength - 1] == FTIMES_SLASHCHAR)
796 {
797 break;
798 }
799 iTempLength--;
800 }
801
802 /*-
803 *******************************************************************
804 *
805 * Copy off the filename portion of the path. It will be referenced
806 * during construction of the full path. Insert a null after the
807 * last directory separator to terminate the directory portion of
808 * the path.
809 *
810 *******************************************************************
811 */
812 strcpy(pcTempFile, &pcTempPath[iTempLength]);
813 pcTempPath[iTempLength] = 0;
814
815 /*-
816 *******************************************************************
817 *
818 * Expand the directory path. If length is zero, a valid directory
819 * separator was not found. In that case, expand cwd (i.e. FTIMES_DOT).
820 *
821 *******************************************************************
822 */
823 if (iTempLength == 0)
824 {
825 iError = SupportExpandDirectoryPath(FTIMES_DOT, pcFullPath, iFullPathSize, acLocalError);
826 }
827 else
828 {
829 iError = SupportExpandDirectoryPath(pcTempPath, pcFullPath, iFullPathSize, acLocalError);
830 }
831 if (iError != ER_OK)
832 {
833 snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, pcPath, acLocalError);
834 free(pcTempPath);
835 free(pcTempFile);
836 return iError;
837 }
838
839 /*-
840 *******************************************************************
841 *
842 * Construct the full path. Abort, if the size limit is exceeded.
843 *
844 *******************************************************************
845 */
846 iLength = strlen(pcFullPath) + strlen(FTIMES_SLASH) + strlen(pcTempFile);
847 if (iLength > iFullPathSize - 1)
848 {
849 snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: Length (%d) exceeds %d bytes.", acRoutine, pcPath, iLength, iFullPathSize - 1);
850 free(pcTempPath);
851 free(pcTempFile);
852 return ER_Length;
853 }
854 strcat(pcFullPath, FTIMES_SLASH);
855 strcat(pcFullPath, pcTempFile);
856
857 free(pcTempPath);
858 free(pcTempFile);
859
860 break;
861 }
862
863 return ER_OK;
864 }
865
866
867 /*-
868 ***********************************************************************
869 *
870 * SupportFreeData
871 *
872 ***********************************************************************
873 */
874 void
SupportFreeData(void * pcData)875 SupportFreeData(void *pcData)
876 {
877 if (pcData != NULL)
878 {
879 free(pcData);
880 }
881 }
882
883
884 /*-
885 ***********************************************************************
886 *
887 * SupportFreeListItem
888 *
889 ***********************************************************************
890 */
891 void
SupportFreeListItem(FILE_LIST * psItem)892 SupportFreeListItem(FILE_LIST *psItem)
893 {
894 if (psItem != NULL)
895 {
896 if (psItem->pcRegularPath != NULL)
897 {
898 free(psItem->pcRegularPath);
899 }
900 if (psItem->pcEncodedPath != NULL)
901 {
902 free(psItem->pcEncodedPath);
903 }
904 free(psItem);
905 }
906 }
907
908
909 /*-
910 ***********************************************************************
911 *
912 * SupportGetFileHandle
913 *
914 ***********************************************************************
915 */
916 FILE *
SupportGetFileHandle(char * pcFile,char * pcError)917 SupportGetFileHandle(char *pcFile, char *pcError)
918 {
919 const char acRoutine[] = "SupportGetFileHandle()";
920 static int iStdinTaken = 0;
921 FILE *pFile = NULL;
922
923 /*-
924 *********************************************************************
925 *
926 * Open the specified file. If "-" was specified, bind the handle to
927 * stdin, but do not do this more than once per invocation.
928 *
929 *********************************************************************
930 */
931 if (strcmp(pcFile, "-") == 0 && iStdinTaken == 0)
932 {
933 pFile = stdin;
934 iStdinTaken = 1;
935 }
936 else
937 {
938 pFile = fopen(pcFile, "rb");
939 if (pFile == NULL)
940 {
941 snprintf(pcError, MESSAGE_SIZE, "%s: fopen(): %s", acRoutine, strerror(errno));
942 return NULL;
943 }
944 }
945
946 return pFile;
947 }
948
949
950 /*-
951 ***********************************************************************
952 *
953 * SupportGetFileType
954 *
955 ***********************************************************************
956 */
957 int
SupportGetFileType(char * pcPath,char * pcError)958 SupportGetFileType(char *pcPath, char *pcError)
959 {
960 const char acRoutine[] = "SupportGetFileType()";
961 struct stat sStatEntry;
962
963 #ifdef UNIX
964 if (lstat(pcPath, &sStatEntry) == ER)
965 {
966 snprintf(pcError, MESSAGE_SIZE, "%s: lstat(): %s", acRoutine, strerror(errno));
967 return FTIMES_FILETYPE_ERROR;
968 }
969
970 switch (sStatEntry.st_mode & S_IFMT)
971 {
972 case S_IFBLK:
973 return FTIMES_FILETYPE_BLOCK;
974 break;
975 case S_IFCHR:
976 return FTIMES_FILETYPE_CHARACTER;
977 break;
978 case S_IFDIR:
979 return FTIMES_FILETYPE_DIRECTORY;
980 break;
981 #ifdef S_IFDOOR
982 case S_IFDOOR:
983 return FTIMES_FILETYPE_DOOR;
984 break;
985 #endif
986 case S_IFIFO:
987 return FTIMES_FILETYPE_FIFO;
988 break;
989 case S_IFLNK:
990 return FTIMES_FILETYPE_LINK;
991 break;
992 case S_IFREG:
993 return FTIMES_FILETYPE_REGULAR;
994 break;
995 case S_IFSOCK:
996 return FTIMES_FILETYPE_SOCKET;
997 break;
998 #ifdef S_IFWHT
999 case S_IFWHT:
1000 return FTIMES_FILETYPE_WHITEOUT;
1001 break;
1002 #endif
1003 default:
1004 return FTIMES_FILETYPE_UNKNOWN;
1005 break;
1006 }
1007 #endif
1008
1009 #ifdef WIN32
1010 char acWorkingPath[4];
1011
1012 if ((isalpha((int) pcPath[0]) && pcPath[1] == ':' && pcPath[2] == 0))
1013 {
1014 acWorkingPath[0] = pcPath[0];
1015 acWorkingPath[1] = pcPath[1];
1016 acWorkingPath[2] = FTIMES_SLASHCHAR;
1017 acWorkingPath[3] = 0;
1018
1019 if (stat(acWorkingPath, &sStatEntry) == ER)
1020 {
1021 snprintf(pcError, MESSAGE_SIZE, "%s: stat(): %s", acRoutine, strerror(errno));
1022 return FTIMES_FILETYPE_ERROR;
1023 }
1024 }
1025 else
1026 {
1027 if (stat(pcPath, &sStatEntry) == ER)
1028 {
1029 snprintf(pcError, MESSAGE_SIZE, "%s: stat(): %s", acRoutine, strerror(errno));
1030 return FTIMES_FILETYPE_ERROR;
1031 }
1032 }
1033
1034 switch (sStatEntry.st_mode & _S_IFMT)
1035 {
1036 case _S_IFCHR:
1037 return FTIMES_FILETYPE_CHARACTER;
1038 break;
1039 case _S_IFDIR:
1040 return FTIMES_FILETYPE_DIRECTORY;
1041 break;
1042 case _S_IFIFO:
1043 return FTIMES_FILETYPE_FIFO;
1044 break;
1045 case _S_IFREG:
1046 return FTIMES_FILETYPE_REGULAR;
1047 break;
1048 default:
1049 return FTIMES_FILETYPE_UNKNOWN;
1050 break;
1051 }
1052 #endif
1053 }
1054
1055
1056 /*-
1057 ***********************************************************************
1058 *
1059 * SupportGetHostname
1060 *
1061 ***********************************************************************
1062 */
1063 char *
SupportGetHostname(void)1064 SupportGetHostname(void)
1065 {
1066 #define MAX_HOSTNAME_LENGTH 256
1067 static char acHostname[MAX_HOSTNAME_LENGTH] = "NA";
1068 #ifdef UNIX
1069 struct utsname sUTSName;
1070
1071 memset(&sUTSName, 0, sizeof(struct utsname));
1072 if (uname(&sUTSName) != -1)
1073 {
1074 snprintf(acHostname, MAX_HOSTNAME_LENGTH, "%s", (sUTSName.nodename[0]) ? sUTSName.nodename : "NA");
1075 }
1076 #endif
1077 #ifdef WIN32
1078 char acTempname[MAX_HOSTNAME_LENGTH];
1079 DWORD dwTempNameLength = sizeof(acTempname);
1080
1081 if (GetComputerName(acTempname, &dwTempNameLength) == TRUE)
1082 {
1083 snprintf(acHostname, MAX_HOSTNAME_LENGTH, "%s", acTempname);
1084 }
1085 #endif
1086 return acHostname;
1087 }
1088
1089
1090 /*-
1091 ***********************************************************************
1092 *
1093 * SupportGetSystemOS
1094 *
1095 ***********************************************************************
1096 */
1097 char *
SupportGetSystemOS(void)1098 SupportGetSystemOS(void)
1099 {
1100 #define MAX_SYSTEMOS_LENGTH 256
1101 static char acSystemOS[MAX_SYSTEMOS_LENGTH] = "NA";
1102 #ifdef UNIX
1103 struct utsname sUTSName;
1104
1105 memset(&sUTSName, 0, sizeof(struct utsname));
1106 if (uname(&sUTSName) != -1)
1107 {
1108 #ifdef FTimes_AIX
1109 snprintf(acSystemOS, MAX_SYSTEMOS_LENGTH, "%s %s %s.%s", sUTSName.machine, sUTSName.sysname, sUTSName.version, sUTSName.release);
1110 #else
1111 snprintf(acSystemOS, MAX_SYSTEMOS_LENGTH, "%s %s %s", sUTSName.machine, sUTSName.sysname, sUTSName.release);
1112 #endif
1113 }
1114 #endif
1115 #ifdef WIN32
1116 char acOS[16];
1117 char acPlatform[16];
1118 OSVERSIONINFO sOSVersionInfo;
1119 SYSTEM_INFO sSystemInfo;
1120
1121 memset(&sSystemInfo, 0, sizeof(SYSTEM_INFO));
1122 GetSystemInfo(&sSystemInfo);
1123 switch (sSystemInfo.wProcessorArchitecture)
1124 {
1125 case PROCESSOR_ARCHITECTURE_INTEL:
1126 strncpy(acPlatform, "INTEL", sizeof(acPlatform));
1127 break;
1128 case PROCESSOR_ARCHITECTURE_MIPS:
1129 strncpy(acPlatform, "MIPS", sizeof(acPlatform));
1130 break;
1131 case PROCESSOR_ARCHITECTURE_ALPHA:
1132 strncpy(acPlatform, "ALPHA", sizeof(acPlatform));
1133 break;
1134 case PROCESSOR_ARCHITECTURE_PPC:
1135 strncpy(acPlatform, "PPC", sizeof(acPlatform));
1136 break;
1137 default:
1138 strncpy(acPlatform, "NA", sizeof(acPlatform));
1139 break;
1140 }
1141
1142 memset(&sOSVersionInfo, 0, sizeof(OSVERSIONINFO));
1143 sOSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1144 if (GetVersionEx(&sOSVersionInfo) == TRUE)
1145 {
1146 switch (sOSVersionInfo.dwPlatformId)
1147 {
1148 case VER_PLATFORM_WIN32s:
1149 strncpy(acOS, "Windows 3.1", sizeof(acOS));
1150 break;
1151 case VER_PLATFORM_WIN32_WINDOWS:
1152 strncpy(acOS, "Windows 98", sizeof(acOS));
1153 break;
1154 case VER_PLATFORM_WIN32_NT:
1155 strncpy(acOS, "Windows NT", sizeof(acOS));
1156 break;
1157 default:
1158 strncpy(acOS, "NA", sizeof(acOS));
1159 break;
1160 }
1161
1162 snprintf(
1163 acSystemOS, MAX_SYSTEMOS_LENGTH, "%s %s %u.%u Build %u %s",
1164 acPlatform,
1165 acOS,
1166 sOSVersionInfo.dwMajorVersion,
1167 sOSVersionInfo.dwMinorVersion,
1168 sOSVersionInfo.dwBuildNumber,
1169 sOSVersionInfo.szCSDVersion
1170 );
1171 }
1172 #endif
1173 return acSystemOS;
1174 }
1175
1176
1177 /*-
1178 ***********************************************************************
1179 *
1180 * SupportIncludeEverything
1181 *
1182 ***********************************************************************
1183 */
1184 FILE_LIST *
SupportIncludeEverything(char * pcError)1185 SupportIncludeEverything(char *pcError)
1186 {
1187 const char acRoutine[] = "SupportIncludeEverything()";
1188 char acLocalError[MESSAGE_SIZE] = "";
1189 FILE_LIST *psHead = NULL;
1190 FILE_LIST *psItem = NULL;
1191 #ifdef WIN32
1192 char acDriveList[26 * 4 + 2];
1193 char *pcDrive;
1194 int iLength;
1195 int iTempLength;
1196 #endif
1197
1198 #ifdef WIN32
1199 if (GetLogicalDriveStrings(26 * 4 + 2, acDriveList) == 0)
1200 {
1201 snprintf(pcError, MESSAGE_SIZE, "%s: GetLogicalDriveStrings: %u", acRoutine, GetLastError());
1202 return NULL;
1203 }
1204
1205 /*-
1206 *******************************************************************
1207 *
1208 * Strip off backslash characters, and add the drive to the Include
1209 * list. Remember the total length of the original drive as it is
1210 * needed to update pcDrive next time through the loop.
1211 *
1212 *******************************************************************
1213 */
1214 for (pcDrive = acDriveList; *pcDrive; pcDrive += iLength + 1)
1215 {
1216 iLength = iTempLength = strlen(pcDrive);
1217 //THIS CHANGE IS PART OF EXTENDED PREFIX SUPPORT (\\?\)
1218 // while (pcDrive[iTempLength - 1] == FTIMES_SLASHCHAR)
1219 // {
1220 // pcDrive[--iTempLength] = 0;
1221 // }
1222 //END (\\?\)
1223
1224 /*-
1225 *******************************************************************
1226 *
1227 * Allocate and initialize a new list item.
1228 *
1229 *******************************************************************
1230 */
1231 psItem = SupportNewListItem(pcDrive, FILE_LIST_REGULAR, acLocalError);
1232 if (psItem == NULL)
1233 {
1234 snprintf(pcError, MESSAGE_SIZE, "%s: Include = [%s]: %s", acRoutine, FTIMES_ROOT_PATH, acLocalError);
1235 return NULL;
1236 }
1237
1238 /*-
1239 *******************************************************************
1240 *
1241 * Now, add it to the list.
1242 *
1243 *******************************************************************
1244 */
1245 psHead = SupportAddListItem(psItem, psHead, acLocalError);
1246 if (psHead == NULL)
1247 {
1248 snprintf(pcError, MESSAGE_SIZE, "%s: Include = [%s]: %s", acRoutine, pcDrive, acLocalError);
1249 SupportFreeListItem(psItem);
1250 return NULL;
1251 }
1252 }
1253
1254 if (psHead == NULL)
1255 {
1256 snprintf(pcError, MESSAGE_SIZE, "%s: No supported drives found.", acRoutine);
1257 }
1258 #else
1259 /*-
1260 *********************************************************************
1261 *
1262 * Allocate and initialize a new list item.
1263 *
1264 *********************************************************************
1265 */
1266 psItem = SupportNewListItem(FTIMES_ROOT_PATH, FILE_LIST_REGULAR, acLocalError);
1267 if (psItem == NULL)
1268 {
1269 snprintf(pcError, MESSAGE_SIZE, "%s: Include = [%s]: %s", acRoutine, FTIMES_ROOT_PATH, acLocalError);
1270 return NULL;
1271 }
1272
1273 /*-
1274 *********************************************************************
1275 *
1276 * Now, add it to the list.
1277 *
1278 *********************************************************************
1279 */
1280 psHead = SupportAddListItem(psItem, psHead, acLocalError);
1281 if (psHead == NULL)
1282 {
1283 snprintf(pcError, MESSAGE_SIZE, "%s: Include = [%s]: %s", acRoutine, FTIMES_ROOT_PATH, acLocalError);
1284 SupportFreeListItem(psItem);
1285 return NULL;
1286 }
1287 #endif
1288
1289 return psHead;
1290 }
1291
1292
1293 /*-
1294 ***********************************************************************
1295 *
1296 * SupportMakeName
1297 *
1298 ***********************************************************************
1299 */
1300 int
SupportMakeName(char * pcDir,char * pcBaseName,char * pcBaseNameSuffix,char * pcExtension,char * pcFilename,char * pcError)1301 SupportMakeName(char *pcDir, char *pcBaseName, char *pcBaseNameSuffix, char *pcExtension, char *pcFilename, char *pcError)
1302 {
1303 const char acRoutine[] = "SupportMakeName()";
1304 int iLength;
1305
1306 iLength = strlen(pcDir);
1307 iLength += 1; /* FTIMES_SLASH */
1308 iLength += strlen(pcBaseName);
1309 iLength += (pcBaseNameSuffix[0] != 0) ? 1 : 0; /* "_" */
1310 iLength += strlen(pcBaseNameSuffix);
1311 iLength += strlen(pcExtension);
1312
1313 if (iLength > FTIMES_MAX_PATH - 1)
1314 {
1315 snprintf(pcError, MESSAGE_SIZE, "%s: Length (%d) exceeds %d bytes", acRoutine, iLength, (FTIMES_MAX_PATH - 1));
1316 return ER_Length;
1317 }
1318 snprintf(pcFilename, FTIMES_MAX_PATH, "%s%s%s%s%s%s",
1319 pcDir,
1320 FTIMES_SLASH,
1321 pcBaseName,
1322 (pcBaseNameSuffix[0] != 0) ? "_" : "",
1323 pcBaseNameSuffix,
1324 pcExtension
1325 );
1326
1327 return ER_OK;
1328 }
1329
1330
1331 /*-
1332 ***********************************************************************
1333 *
1334 * SupportMatchExclude
1335 *
1336 ***********************************************************************
1337 */
1338 FILE_LIST *
SupportMatchExclude(FILE_LIST * psHead,char * pcPath)1339 SupportMatchExclude(FILE_LIST *psHead, char *pcPath)
1340 {
1341 FILE_LIST *psList;
1342
1343 for (psList = psHead; psList != NULL; psList = psList->psNext)
1344 {
1345 if (CompareFunction(psList->pcRegularPath, pcPath) == 0)
1346 {
1347 return psList;
1348 }
1349 }
1350 return NULL;
1351 }
1352
1353
1354 /*-
1355 ***********************************************************************
1356 *
1357 * SupportMatchSubTree
1358 *
1359 ***********************************************************************
1360 */
1361 FILE_LIST *
SupportMatchSubTree(FILE_LIST * psHead,FILE_LIST * psTarget)1362 SupportMatchSubTree(FILE_LIST *psHead, FILE_LIST *psTarget)
1363 {
1364 int x;
1365 int y;
1366 FILE_LIST *psList;
1367
1368 x = psTarget->iLength;
1369 for (psList = psHead; psList != NULL; psList = psList->psNext)
1370 {
1371 y = psList->iLength;
1372 if (NCompareFunction(psTarget->pcRegularPath, psList->pcRegularPath, MIN(x, y)) == 0)
1373 {
1374 if (x <= y)
1375 {
1376 if ((psList->pcRegularPath[x - 1] == FTIMES_SLASHCHAR && psList->pcRegularPath[x] != FTIMES_SLASHCHAR) ||
1377 (psList->pcRegularPath[x - 1] != FTIMES_SLASHCHAR && psList->pcRegularPath[x] == FTIMES_SLASHCHAR) ||
1378 (psList->pcRegularPath[x - 1] == FTIMES_SLASHCHAR && psList->pcRegularPath[x] == FTIMES_SLASHCHAR))
1379 {
1380 return psList;
1381 }
1382 }
1383 else
1384 {
1385 if ((psTarget->pcRegularPath[y - 1] == FTIMES_SLASHCHAR && psTarget->pcRegularPath[y] != FTIMES_SLASHCHAR) ||
1386 (psTarget->pcRegularPath[y - 1] != FTIMES_SLASHCHAR && psTarget->pcRegularPath[y] == FTIMES_SLASHCHAR) ||
1387 (psTarget->pcRegularPath[y - 1] == FTIMES_SLASHCHAR && psTarget->pcRegularPath[y] == FTIMES_SLASHCHAR))
1388 {
1389 return psTarget;
1390 }
1391 }
1392 }
1393 }
1394 return NULL;
1395 }
1396
1397
1398 /*-
1399 ***********************************************************************
1400 *
1401 * SupportNeuterString
1402 *
1403 ***********************************************************************
1404 */
1405 char *
SupportNeuterString(char * pcData,int iLength,char * pcError)1406 SupportNeuterString(char *pcData, int iLength, char *pcError)
1407 {
1408 const char acRoutine[] = "SupportNeuterString()";
1409 char *pcNeutered;
1410 int i;
1411 int n;
1412
1413 /*-
1414 *********************************************************************
1415 *
1416 * The caller is expected to free this memory.
1417 *
1418 *********************************************************************
1419 */
1420 pcNeutered = malloc((3 * iLength) + 1);
1421 if (pcNeutered == NULL)
1422 {
1423 snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, strerror(errno));
1424 return NULL;
1425 }
1426 pcNeutered[0] = 0;
1427
1428 /*-
1429 *********************************************************************
1430 *
1431 * Neuter non-printables and [|"'`%+#]. Convert spaces to '+'. Avoid
1432 * isprint() here because it has led to unexpected results on Windows
1433 * platforms. In the past, isprint() on certain Windows systems has
1434 * decided that several characters in the range 0x7f - 0xff are
1435 * printable.
1436 *
1437 *********************************************************************
1438 */
1439 for (i = n = 0; i < iLength; i++)
1440 {
1441 if (pcData[i] > '~' || pcData[i] < ' ')
1442 {
1443 n += sprintf(&pcNeutered[n], "%%%02x", (unsigned char) pcData[i]);
1444 }
1445 else
1446 {
1447 switch (pcData[i])
1448 {
1449 case '|':
1450 case '"':
1451 case '\'':
1452 case '`':
1453 case '%':
1454 case '+':
1455 case '#':
1456 n += sprintf(&pcNeutered[n], "%%%02x", (unsigned char) pcData[i]);
1457 break;
1458 case ' ':
1459 pcNeutered[n++] = '+';
1460 break;
1461 default:
1462 pcNeutered[n++] = pcData[i];
1463 break;
1464 }
1465 }
1466 }
1467 pcNeutered[n] = 0;
1468
1469 return pcNeutered;
1470 }
1471
1472
1473 /*-
1474 ***********************************************************************
1475 *
1476 * SupportPruneList
1477 *
1478 ***********************************************************************
1479 */
1480 FILE_LIST *
SupportPruneList(FILE_LIST * psList,char * pcListName)1481 SupportPruneList(FILE_LIST *psList, char *pcListName)
1482 {
1483 char acLocalError[MESSAGE_SIZE] = "";
1484 FILE_LIST *psListHead;
1485 FILE_LIST *psListTree;
1486 FILE_LIST *psListKill;
1487
1488 /*-
1489 *********************************************************************
1490 *
1491 * If there's nothing to prune, just return.
1492 *
1493 *********************************************************************
1494 */
1495 if (psList == NULL)
1496 {
1497 return psList;
1498 }
1499
1500 /*-
1501 *********************************************************************
1502 *
1503 * Eliminate any subtree components from the tree list. For example,
1504 * /usr/local would be eliminated from /usr. We also eliminate any
1505 * duplicate entries in the process. However, there should not be any
1506 * duplicates because they should have been automatically pruned as
1507 * the list was being created.
1508 *
1509 *********************************************************************
1510 */
1511 for (psListTree = psListHead = psList; psListTree->psNext != NULL;)
1512 {
1513 psListKill = SupportMatchSubTree(psListTree->psNext, psListTree);
1514
1515 /*-
1516 *******************************************************************
1517 *
1518 * When a match is found, another search is performed to ensure
1519 * that there are no more matches further down in the list. This is
1520 * done implicitly by setting psListTree to psListHead after the
1521 * drop.
1522 *
1523 *******************************************************************
1524 */
1525 if (psListKill != NULL)
1526 {
1527 snprintf(acLocalError, MESSAGE_SIZE, "List = [%s], NeuteredItem = [%s]: Pruning item because it is part of a larger branch.", pcListName, psListKill->pcEncodedPath);
1528 ErrorHandler(ER_Warning, acLocalError, ERROR_WARNING);
1529 psListHead = SupportDropListItem(psListHead, psListKill);
1530 psListTree = psListHead;
1531 }
1532 else
1533 {
1534 psListTree = psListTree->psNext;
1535 }
1536 }
1537 return psListHead;
1538 }
1539
1540
1541 /*-
1542 ***********************************************************************
1543 *
1544 * SupportRequirePrivilege
1545 *
1546 ***********************************************************************
1547 */
1548 int
SupportRequirePrivilege(char * pcError)1549 SupportRequirePrivilege(char *pcError)
1550 {
1551 const char acRoutine[] = "SupportRequirePrivilege()";
1552
1553 #ifdef WINNT
1554 char acLocalError[MESSAGE_SIZE] = "";
1555
1556 if (SupportSetPrivileges(acLocalError) != ER_OK)
1557 {
1558 snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1559 return ER;
1560 }
1561 #endif
1562
1563 #ifdef UNIX
1564 if (getuid() != 0)
1565 {
1566 snprintf(pcError, MESSAGE_SIZE, "%s: Need root privilege to continue.", acRoutine);
1567 return ER;
1568 }
1569 #endif
1570
1571 return ER_OK;
1572 }
1573
1574
1575 /*-
1576 ***********************************************************************
1577 *
1578 * SupportSetLogLevel
1579 *
1580 ***********************************************************************
1581 */
1582 int
SupportSetLogLevel(char * pcLevel,int * piLevel,char * pcError)1583 SupportSetLogLevel(char *pcLevel, int *piLevel, char *pcError)
1584 {
1585 if ((int) strlen(pcLevel) != 1)
1586 {
1587 snprintf(pcError, MESSAGE_SIZE, "Level must be %d-%d.", MESSAGE_DEBUGGER, MESSAGE_CRITICAL);
1588 return ER_Length;
1589 }
1590 switch (pcLevel[0])
1591 {
1592 case '0':
1593 case '1':
1594 case '2':
1595 case '3':
1596 case '4':
1597 case '5':
1598 case '6':
1599 *piLevel = pcLevel[0] - '0';
1600 MessageSetLogLevel(*piLevel);
1601 break;
1602 default:
1603 snprintf(pcError, MESSAGE_SIZE, "Level must be %d-%d.", MESSAGE_DEBUGGER, MESSAGE_CRITICAL);
1604 return ER_Length;
1605 break;
1606 }
1607
1608 return ER_OK;
1609 }
1610
1611
1612 /*-
1613 ***********************************************************************
1614 *
1615 * SupportSetPriority
1616 *
1617 ***********************************************************************
1618 */
1619 int
SupportSetPriority(FTIMES_PROPERTIES * psProperties,char * pcError)1620 SupportSetPriority(FTIMES_PROPERTIES *psProperties, char *pcError)
1621 {
1622 const char acRoutine[] = "SupportSetPriority()";
1623 char *pcPriority = NULL;
1624 int i = 0;
1625 #ifndef WIN32
1626 int iError = 0;
1627 #endif
1628
1629 /*-
1630 *********************************************************************
1631 *
1632 * A priority specified in the environment trumps one specified in a
1633 * config file.
1634 *
1635 *********************************************************************
1636 */
1637 pcPriority = FTimesGetEnvValue("FTIMES_PRIORITY");
1638 if (pcPriority && strlen(pcPriority) < FTIMES_MAX_PRIORITY_LENGTH)
1639 {
1640 strncpy(psProperties->acPriority, pcPriority, FTIMES_MAX_PRIORITY_LENGTH);
1641 }
1642
1643 /*-
1644 *********************************************************************
1645 *
1646 * If a priority was specified, convert it into a platform-specific
1647 * value and set it. Otherwise, do nothing.
1648 *
1649 *********************************************************************
1650 */
1651 if (psProperties->acPriority[0])
1652 {
1653 if (strcasecmp(psProperties->acPriority, "LOW") == 0)
1654 {
1655 psProperties->iPriority = FTIMES_PRIORITY_LOW;
1656 }
1657 else if (strcasecmp(psProperties->acPriority, "BELOW_NORMAL") == 0)
1658 {
1659 psProperties->iPriority = FTIMES_PRIORITY_BELOW_NORMAL;
1660 }
1661 else if (strcasecmp(psProperties->acPriority, "NORMAL") == 0)
1662 {
1663 psProperties->iPriority = FTIMES_PRIORITY_NORMAL;
1664 }
1665 else if (strcasecmp(psProperties->acPriority, "ABOVE_NORMAL") == 0)
1666 {
1667 psProperties->iPriority = FTIMES_PRIORITY_ABOVE_NORMAL;
1668 }
1669 else if (strcasecmp(psProperties->acPriority, "HIGH") == 0)
1670 {
1671 psProperties->iPriority = FTIMES_PRIORITY_HIGH;
1672 }
1673 else
1674 {
1675 snprintf(pcError, MESSAGE_SIZE, "%s: Priority (%s) must be one of [low|below_normal|normal|above_normal|high].", acRoutine, psProperties->acPriority);
1676 return ER;
1677 }
1678 for (i = 0; i < (int) strlen(psProperties->acPriority); i++)
1679 {
1680 psProperties->acPriority[i] = tolower(psProperties->acPriority[i]);
1681 }
1682 #ifdef WIN32
1683 if (!SetPriorityClass(GetCurrentProcess(), (DWORD) psProperties->iPriority))
1684 {
1685 char *pcMessage = NULL;
1686 ErrorFormatWinxError(GetLastError(), &pcMessage);
1687 snprintf(pcError, MESSAGE_SIZE, "%s: SetPriorityClass(): %s", acRoutine, pcMessage);
1688 return ER;
1689 }
1690 #else
1691 iError = setpriority(PRIO_PROCESS, 0, psProperties->iPriority);
1692 if (iError == -1)
1693 {
1694 snprintf(pcError, MESSAGE_SIZE, "%s: setpriority(): %s", acRoutine, strerror(errno));
1695 return ER;
1696 }
1697 #endif
1698 }
1699
1700 return ER_OK;
1701 }
1702
1703
1704 #ifdef WINNT
1705 /*-
1706 ***********************************************************************
1707 *
1708 * SupportSetPrivileges
1709 *
1710 ***********************************************************************
1711 */
1712 int
SupportSetPrivileges(char * pcError)1713 SupportSetPrivileges(char *pcError)
1714 {
1715 const char acRoutine[] = "SupportSetPrivileges()";
1716
1717 /*-
1718 *********************************************************************
1719 *
1720 * Attempt to obtain backup user rights.
1721 *
1722 *********************************************************************
1723 */
1724 if (SupportAdjustPrivileges(SE_BACKUP_NAME) == FALSE)
1725 {
1726 snprintf(pcError, MESSAGE_SIZE, "%s: Can't set SE_BACKUP_NAME privilege.", acRoutine);
1727 return ER;
1728 }
1729
1730 /*-
1731 *********************************************************************
1732 *
1733 * Attempt to obtain restore user rights.
1734 *
1735 *********************************************************************
1736 */
1737 if (SupportAdjustPrivileges(SE_RESTORE_NAME) == FALSE)
1738 {
1739 snprintf(pcError, MESSAGE_SIZE, "%s: Can't set SE_RESTORE_NAME privilege.", acRoutine);
1740 return ER;
1741 }
1742
1743 return ER_OK;
1744 }
1745 #endif
1746
1747
1748 /*-
1749 ***********************************************************************
1750 *
1751 * SupportStringToUInt64
1752 *
1753 ***********************************************************************
1754 */
1755 int
SupportStringToUInt64(char * pcData,APP_UI64 * pui64Value,char * pcError)1756 SupportStringToUInt64(char *pcData, APP_UI64 *pui64Value, char *pcError)
1757 {
1758 const char acRoutine[] = "SupportStringTo64BitDecimal()";
1759 int i = 0;
1760 int iLength = 0;
1761 APP_UI64 ui64Value = 0;
1762 APP_UI64 ui64Multiplier = 1;
1763
1764 iLength = strlen(pcData);
1765
1766 #define SUPPORT_MAX_64BIT_NUMBER_SIZE 20 /* strlen("18446744073709551615") */
1767 if (iLength < 1 || iLength > SUPPORT_MAX_64BIT_NUMBER_SIZE)
1768 {
1769 snprintf(pcError, MESSAGE_SIZE, "%s: The specified number (%s) is either too small or too large to be a valid 64-bit value.", acRoutine, pcData);
1770 return ER;
1771 }
1772
1773 for (i = iLength - 1; i >= 0; i--)
1774 {
1775 switch ((int) pcData[i])
1776 {
1777 case '0': case '1': case '2': case '3': case '4':
1778 case '5': case '6': case '7': case '8': case '9':
1779 ui64Value += ((int) pcData[i] - 0x30) * ui64Multiplier;
1780 ui64Multiplier *= 10;
1781 break;
1782 default:
1783 snprintf(pcError, MESSAGE_SIZE, "%s: The specified number (%s) contains one or more invalid digits.", acRoutine, pcData);
1784 return ER;
1785 break;
1786 }
1787 }
1788 *pui64Value = ui64Value;
1789
1790 return ER_OK;
1791 }
1792
1793
1794 /*-
1795 ***********************************************************************
1796 *
1797 * SupportWriteData
1798 *
1799 ***********************************************************************
1800 */
1801 int
SupportWriteData(FILE * pFile,char * pcData,int iLength,char * pcError)1802 SupportWriteData(FILE *pFile, char *pcData, int iLength, char *pcError)
1803 {
1804 const char acRoutine[] = "SupportWriteData()";
1805 int iNWritten;
1806
1807 iNWritten = fwrite(pcData, 1, iLength, pFile);
1808 if (ferror(pFile))
1809 {
1810 if (iNWritten != iLength)
1811 {
1812 snprintf(pcError, MESSAGE_SIZE, "%s: fwrite(): NWritten = [%d] != [%d]: WriteLength mismatch!: %s",
1813 acRoutine,
1814 iNWritten,
1815 iLength,
1816 (errno == 0) ? "unexpected error -- check device for sufficient space" : strerror(errno)
1817 );
1818 }
1819 else
1820 {
1821 snprintf(pcError, MESSAGE_SIZE, "%s: fwrite(): %s",
1822 acRoutine,
1823 (errno == 0) ? "unexpected error -- check device for sufficient space" : strerror(errno)
1824 );
1825 }
1826 return ER;
1827 }
1828 if (fflush(pFile) != 0)
1829 {
1830 snprintf(pcError, MESSAGE_SIZE, "%s: fflush(): %s", acRoutine, strerror(errno));
1831 return ER;
1832 }
1833
1834 return ER_OK;
1835 }
1836
1837
1838 #ifdef USE_PCRE
1839 /*-
1840 ***********************************************************************
1841 *
1842 * SupportAddFilter
1843 *
1844 ***********************************************************************
1845 */
1846 int
SupportAddFilter(char * pcFilter,FILTER_LIST ** psHead,char * pcError)1847 SupportAddFilter(char *pcFilter, FILTER_LIST **psHead, char *pcError)
1848 {
1849 const char acRoutine[] = "SupportAddFilter()";
1850 char acLocalError[MESSAGE_SIZE] = "";
1851 FILTER_LIST *psCurrent = NULL;
1852 FILTER_LIST *psFilter = NULL;
1853
1854 /*-
1855 *********************************************************************
1856 *
1857 * Allocate and initialize a new Filter.
1858 *
1859 *********************************************************************
1860 */
1861 psFilter = SupportNewFilter(pcFilter, acLocalError);
1862 if (psFilter == NULL)
1863 {
1864 snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1865 return ER;
1866 }
1867
1868 /*-
1869 *********************************************************************
1870 *
1871 * If the head is NULL, insert the new filter and return. Otherwise,
1872 * append the new filter to the end of the list.
1873 *
1874 *********************************************************************
1875 */
1876 if (*psHead == NULL)
1877 {
1878 *psHead = psFilter;
1879 }
1880 else
1881 {
1882 psCurrent = *psHead;
1883 while (psCurrent != NULL)
1884 {
1885 if (psCurrent->psNext == NULL)
1886 {
1887 psCurrent->psNext = psFilter;
1888 break;
1889 }
1890 psCurrent = psCurrent->psNext;
1891 }
1892 }
1893
1894 return ER_OK;
1895 }
1896
1897
1898 /*-
1899 ***********************************************************************
1900 *
1901 * SupportFreeFilter
1902 *
1903 ***********************************************************************
1904 */
1905 void
SupportFreeFilter(FILTER_LIST * psFilter)1906 SupportFreeFilter(FILTER_LIST *psFilter)
1907 {
1908 if (psFilter != NULL)
1909 {
1910 if (psFilter->pcFilter != NULL)
1911 {
1912 free(psFilter->pcFilter);
1913 }
1914 if (psFilter->psPcre != NULL)
1915 {
1916 pcre_free(psFilter->psPcre);
1917 }
1918 if (psFilter->psPcreExtra != NULL)
1919 {
1920 pcre_free(psFilter->psPcreExtra);
1921 }
1922 free(psFilter);
1923 }
1924 }
1925
1926
1927 /*-
1928 ***********************************************************************
1929 *
1930 * SupportMatchFilter
1931 *
1932 ***********************************************************************
1933 */
1934 FILTER_LIST *
SupportMatchFilter(FILTER_LIST * psFilterList,char * pcPath)1935 SupportMatchFilter(FILTER_LIST *psFilterList, char *pcPath)
1936 {
1937 FILTER_LIST *psFilter;
1938 #ifndef PCRE_OVECTOR_ARRAY_SIZE
1939 #define PCRE_OVECTOR_ARRAY_SIZE 30
1940 #endif
1941 int aiPcreOVector[PCRE_OVECTOR_ARRAY_SIZE];
1942 int iError = 0;
1943
1944 for (psFilter = psFilterList; psFilter != NULL; psFilter = psFilter->psNext)
1945 {
1946 /*-
1947 *******************************************************************
1948 *
1949 * PCRE_NOTEMPTY is used here to squash any attempts to match
1950 * empty strings. Even though a value of zero would mean that that
1951 * there was an overflow in ovector, accept those matches as
1952 * valid. This should be OK since the elements in ovector are
1953 * ignored anyway. Note that any value less than zero is currently
1954 * being treated as if it were not a match. If that turns out to
1955 * be an issue, this routine will need to be modified such that it
1956 * can throw an error, and the upstream code will need to be
1957 * adjusted accordingly.
1958 *
1959 *******************************************************************
1960 */
1961 iError = pcre_exec(psFilter->psPcre, psFilter->psPcreExtra, pcPath, strlen(pcPath), 0, PCRE_NOTEMPTY, aiPcreOVector, PCRE_OVECTOR_ARRAY_SIZE);
1962 if (iError >= 0)
1963 {
1964 return psFilter;
1965 }
1966 }
1967
1968 return NULL;
1969 }
1970
1971
1972 /*-
1973 ***********************************************************************
1974 *
1975 * SupportNewFilter
1976 *
1977 ***********************************************************************
1978 */
1979 FILTER_LIST *
SupportNewFilter(char * pcFilter,char * pcError)1980 SupportNewFilter(char *pcFilter, char *pcError)
1981 {
1982 const char acRoutine[] = "SupportNewFilter()";
1983 const char *pcPcreError = NULL;
1984 FILTER_LIST *psFilter = NULL;
1985 int iError = 0;
1986 int iCaptureCount = 0;
1987 int iLength = 0;
1988 int iPcreErrorOffset = 0;
1989
1990 /*-
1991 *********************************************************************
1992 *
1993 * Check that the input filter is not NULL and that it has length.
1994 *
1995 *********************************************************************
1996 */
1997 if (pcFilter == NULL)
1998 {
1999 snprintf(pcError, MESSAGE_SIZE, "%s: NULL input. That shouldn't happen.", acRoutine);
2000 return NULL;
2001 }
2002
2003 iLength = strlen(pcFilter);
2004 if (iLength < 1)
2005 {
2006 snprintf(pcError, MESSAGE_SIZE, "%s: Length = [%d]: Length must be greater than zero.", acRoutine, iLength);
2007 return NULL;
2008 }
2009
2010 /*-
2011 *********************************************************************
2012 *
2013 * Allocate memory for a new Filter. The caller should free this
2014 * memory with SupportFreeFilter().
2015 *
2016 *********************************************************************
2017 */
2018 psFilter = calloc(sizeof(FILTER_LIST), 1);
2019 if (psFilter == NULL)
2020 {
2021 snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
2022 return NULL;
2023 }
2024
2025 psFilter->pcFilter = calloc(iLength + 1, 1);
2026 if (psFilter->pcFilter == NULL)
2027 {
2028 snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
2029 return NULL;
2030 }
2031 strncpy(psFilter->pcFilter, pcFilter, iLength);
2032
2033 /*-
2034 *********************************************************************
2035 *
2036 * Compile and study the regular expression. Compile-time options
2037 * (?imsx) are not set here because the user can specify them as
2038 * needed in the filter.
2039 *
2040 *********************************************************************
2041 */
2042 psFilter->psPcre = pcre_compile(pcFilter, 0, &pcPcreError, &iPcreErrorOffset, NULL);
2043 if (psFilter->psPcre == NULL)
2044 {
2045 snprintf(pcError, MESSAGE_SIZE, "%s: pcre_compile(): %s", acRoutine, pcPcreError);
2046 SupportFreeFilter(psFilter);
2047 return NULL;
2048 }
2049 psFilter->psPcreExtra = pcre_study(psFilter->psPcre, 0, &pcPcreError);
2050 if (pcPcreError != NULL)
2051 {
2052 snprintf(pcError, MESSAGE_SIZE, "%s: pcre_study(): %s", acRoutine, pcPcreError);
2053 SupportFreeFilter(psFilter);
2054 return NULL;
2055 }
2056 iError = pcre_fullinfo(psFilter->psPcre, psFilter->psPcreExtra, PCRE_INFO_CAPTURECOUNT, (void *) &iCaptureCount);
2057 if (iError == ER_OK)
2058 {
2059 if (iCaptureCount > PCRE_MAX_CAPTURE_COUNT)
2060 {
2061 snprintf(pcError, MESSAGE_SIZE, "%s: Invalid capture count [%d]. The maximum number of capturing '()' subpatterns allowed is %d. Use '(?:)' if grouping is required.", acRoutine, iCaptureCount, PCRE_MAX_CAPTURE_COUNT);
2062 SupportFreeFilter(psFilter);
2063 return NULL;
2064 }
2065 }
2066 else
2067 {
2068 snprintf(pcError, MESSAGE_SIZE, "%s: pcre_fullinfo(): Unexpected return value [%d]. That shouldn't happen.", acRoutine, iError);
2069 SupportFreeFilter(psFilter);
2070 return NULL;
2071 }
2072 psFilter->psNext = NULL;
2073
2074 return psFilter;
2075 }
2076 #endif
2077
2078
2079 /*-
2080 ***********************************************************************
2081 *
2082 * SupportNewListItem
2083 *
2084 ***********************************************************************
2085 */
2086 FILE_LIST *
SupportNewListItem(char * pcPath,int iType,char * pcError)2087 SupportNewListItem(char *pcPath, int iType, char *pcError)
2088 {
2089 const char acRoutine[] = "SupportNewListItem()";
2090 char acLocalError[MESSAGE_SIZE] = "";
2091 int iIndex = 0;
2092 int iLength = 0;
2093 FILE_LIST *psItem = NULL;
2094
2095 /*-
2096 *********************************************************************
2097 *
2098 * Check that the input string is not NULL and that it has length.
2099 *
2100 *********************************************************************
2101 */
2102 if (pcPath == NULL)
2103 {
2104 snprintf(pcError, MESSAGE_SIZE, "%s: NULL input. That shouldn't happen.", acRoutine);
2105 return NULL;
2106 }
2107
2108 iLength = strlen(pcPath);
2109 if (iLength < 1)
2110 {
2111 snprintf(pcError, MESSAGE_SIZE, "%s: Length = [%d]: Length must be greater than zero.", acRoutine, iLength);
2112 return NULL;
2113 }
2114
2115 /*-
2116 *********************************************************************
2117 *
2118 * Allocate memory for a new list item, and initialize its members.
2119 * If the path is encoded (i.e., it was specified using the
2120 * "file://" prefix), decode it. Otherwise, just copy it into place.
2121 * Once the regular path has been set, neuter it and carry it around
2122 * in the structure -- the neutered form is used in various print
2123 * statements.
2124 *
2125 *********************************************************************
2126 */
2127 psItem = calloc(sizeof(FILE_LIST), 1);
2128 if (psItem == NULL)
2129 {
2130 snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
2131 return NULL;
2132 }
2133
2134 if (iType == FILE_LIST_ENCODED)
2135 {
2136 psItem->pcRegularPath = HttpUnEscape(pcPath, &iLength, acLocalError);
2137 if (psItem->pcRegularPath == NULL)
2138 {
2139 snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
2140 SupportFreeListItem(psItem);
2141 return NULL;
2142 }
2143 /* NOTE: The realloc() below is needed so we can append a NULL byte to the string. HttpUnEscape() does not do that. */
2144 psItem->pcRegularPath = realloc(psItem->pcRegularPath, iLength + 1);
2145 if (psItem->pcRegularPath == NULL)
2146 {
2147 snprintf(pcError, MESSAGE_SIZE, "%s: realloc(): %s", acRoutine, strerror(errno));
2148 SupportFreeListItem(psItem);
2149 return NULL;
2150 }
2151 psItem->pcRegularPath[iLength] = 0;
2152 psItem->iLength = iLength;
2153 for (iIndex = 0; iIndex < iLength; iIndex++)
2154 {
2155 if (psItem->pcRegularPath[iIndex] == 0)
2156 {
2157 snprintf(pcError, MESSAGE_SIZE, "%s: Path contains a NULL byte, which is not allowed.", acRoutine);
2158 SupportFreeListItem(psItem);
2159 return NULL;
2160 }
2161 }
2162 }
2163 else
2164 {
2165 psItem->pcRegularPath = calloc(iLength + 1, 1);
2166 if (psItem->pcRegularPath == NULL)
2167 {
2168 snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
2169 SupportFreeListItem(psItem);
2170 return NULL;
2171 }
2172 strncpy(psItem->pcRegularPath, pcPath, iLength + 1);
2173 psItem->iLength = iLength;
2174 }
2175
2176 psItem->pcEncodedPath = SupportNeuterString(psItem->pcRegularPath, psItem->iLength, acLocalError);
2177 if (psItem->pcEncodedPath == NULL)
2178 {
2179 snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
2180 SupportFreeListItem(psItem);
2181 return NULL;
2182 }
2183
2184 psItem->iType = iType;
2185 psItem->psNext = NULL;
2186
2187 return psItem;
2188 }
2189