source: trunk/dll/grep.c@ 1707

Last change on this file since 1707 was 1707, checked in by Steven Levine, 12 years ago

Support git, svn, hg etc. version control metadata directory excludes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.0 KB
Line 
1
2/***********************************************************************
3
4 $Id: grep.c 1707 2014-02-08 20:14:08Z stevenhl $
5
6 grep tools
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2001, 2014 Steven H. Levine
10
11 12 Feb 03 SHL InsertGrepFile: standardize EA math
12 12 Feb 03 SHL doonefile: standardize EA math
13 25 May 05 SHL Rework for ULONGLONG
14 25 May 05 SHL Rework for FillInRecordFromFFB
15 06 Jun 05 SHL Drop unused code
16 24 Oct 05 SHL dononefile: do not free EA list twice
17 22 Jul 06 SHL Use Runtime_Error
18 26 Jul 06 SHL Check more run time errors
19 19 Oct 06 SHL Correct . and .. detect
20 03 Nov 06 SHL Count thread usage
21 03 Aug 07 GKY Enlarged and made setable everywhere Findbuf (speed file loading)
22 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
23 13 Aug 07 SHL Avoid pointer errors; sanitize code
24 13 Aug 07 SHL Move #pragma alloc_text to end for OpenWatcom compat
25 15 Aug 07 SHL Use FilesToGet directly
26 26 Aug 07 GKY Improved performance of FillDups
27 26 Aug 07 GKY DosSleep(1) in loops changed to (0)
28 21 Sep 07 GKY Fix trap on search that includes filenames that exceed maxpath
29 07 Feb 08 SHL Use ITIMER_DESC to control sleeps and reporting
30 29 Feb 08 GKY Use xfree where appropriate
31 29 Nov 08 GKY Remove or replace with a mutex semaphore DosEnterCriSec where appropriate.
32 07 Feb 09 GKY Allow user to turn off alert and/or error beeps in settings notebook.
33 08 Mar 09 GKY Additional strings move to String Table
34 28 Jun 09 GKY Added AddBackslashToPath() to remove repeatative code.
35 17 JAN 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10).
36 Mostly cast CHAR CONSTANT * as CHAR *.
37 29 May 10 GKY Suppress ERROR_FILENAME_EXCED_RANGE error because of problem with NTFS
38 30 May 11 GKY Fixed potential trap caused by passing a nonexistant pci to FillInRecordFromFFB
39 in DoInsertion because pci is limited to 65535 files. (nRecord is a USHORT)
40 SHL's single loop fix.
41 05 Aug 12 GKY Replace SleepIfNeeded with IdleIfNeeded to improve IU response during long searches; it
42 will switch between normal and idle priority and back.
43 05 Aug 12 GKY Always sort "Find Dups" by filename in the collector.
44 08 Feb 14 SHL Support Ignore SVN option
45
46***********************************************************************/
47
48#include <stdlib.h>
49#include <string.h>
50#include <ctype.h>
51#include <share.h>
52#include <limits.h>
53
54#define INCL_DOS
55#define INCL_DOSERRORS
56#define INCL_WIN
57#define INCL_LONGLONG
58
59#include "fm3dll.h"
60#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
61#include "notebook.h" // Data declaration(s)
62#include "newview.h" // Data declarations
63#include "fm3str.h"
64#include "grep.h"
65#include "pathutil.h" // BldFullPathName
66#include "filldir.h" // FillInRecordFromFFB
67#include "makelist.h" // AddToList
68#include "errutil.h" // Dos_Error...
69#include "strutil.h" // GetPString
70#include "tmrsvcs.h" // ITIMER_DESC
71#include "common.h" // DecrThreadUsage, IncrThreadUsage
72#include "valid.h" // MakeFullName
73#include "literal.h" // wildcard
74#include "wrappers.h" // xDosFindNext
75#include "eas.h" // Free_FEAList
76#include "stristr.h" // findstring
77#include "misc.h" // PostMsg
78#include "fortify.h"
79#include "init.h" // Golbal semaphore
80#include "sortcnr.h" // SortCollectorCnr
81#include "collect.h"
82
83static VOID DoAllSubdirs(GREP *grep,
84 CHAR *searchPath,
85 BOOL recursing,
86 char **fileMasks,
87 UINT numFileMasks,
88 ITIMER_DESC *pitdSleep,
89 ITIMER_DESC *pitdReport);
90static INT DoMatchingFiles(GREP *grep,
91 CHAR *path,
92 CHAR **fileMasks,
93 UINT numFileMasks,
94 ITIMER_DESC *pitdSleep,
95 ITIMER_DESC *pitdReport);
96static BOOL DoOneFile(GREP *grep,
97 CHAR *fileName,
98 FILEFINDBUF4L *pffb,
99 ITIMER_DESC *pitdSleep,
100 ITIMER_DESC *pitdReport);
101static BOOL DoInsertion(GREP *grep,
102 ITIMER_DESC *pitdSleep,
103 ITIMER_DESC *pitdReport);
104static BOOL InsertDupe(GREP *grep, CHAR *dir, FILEFINDBUF4L *pffb);
105static VOID FillDupes(GREP *grep,
106 ITIMER_DESC *pitdSleep,
107 ITIMER_DESC *pitdReport);
108
109static VOID FreeDupes(GREP *grep);
110
111#define GREPCHARS "*?[] \\"
112
113#define isleap(year) ((((year%4)==0) && ((year%100)!=0)) || \
114 ((year%400)==0))
115
116// Data definitions
117#pragma data_seg(DATA2)
118static PSZ pszSrcFile = __FILE__;
119static INT monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
120
121#pragma data_seg(GLOBAL1)
122HWND hwndStatus;
123
124
125ULONG SecsSince1980(FDATE *date, FTIME *time)
126{
127 ULONG total = 0;
128 UINT x;
129
130 for (x = 1980; x < date->year + 1980; x++) {
131 if (isleap(x))
132 total += (366 * (24 * 60 * 60));
133 else
134 total += (365 * (24 * 60 * 60));
135 }
136 for (x = 1; x < date->month; x++) {
137 if (x == 2 && isleap(date->year + 1980))
138 total += (29 * (24 * 60 * 60));
139 else
140 total += ((long)monthdays[x - 1] * (24 * 60 * 60));
141 }
142 total += (((long)date->day - 1) * (24 * 60 * 60));
143 total += ((long)time->hours * (60 * 60));
144 total += ((long)time->minutes * 60);
145 total += ((long)time->twosecs * 2);
146 return total;
147}
148
149/**
150 * this function originally from C_ECHO's Snippets -- modified
151 * brute force methodology
152 */
153
154static BOOL m_match(CHAR *string, CHAR *pattern, BOOL absolute, BOOL ignore,
155 LONG len)
156{
157 // return TRUE if pattern found in string
158 register CHAR *tn = pattern;
159 register LONG len2 = 0;
160 LONG lastlen = 0;
161 CHAR lo, hi;
162
163 if (len && string && pattern) {
164 if (absolute) // no pattern matching
165 return (findstring(pattern, strlen(pattern), string, len,
166 (ignore == FALSE)) != NULL);
167
168 while (*tn && len2 < len) {
169 switch (*tn) {
170 case ' ':
171 while (*tn == ' ')
172 tn++;
173 while (len2 < len && isspace(string[len2]))
174 len2++;
175 break;
176
177 case '*':
178 while (*tn == '*' || *tn == '?')
179 tn++;
180 if (!*tn)
181 return TRUE;
182 if (ignore) {
183 while (len2 < len && string[len2] != *tn)
184 len2++;
185 }
186 else {
187 while (len2 < len && toupper(string[len2] != *tn))
188 len2++;
189 }
190 break;
191
192 case '[':
193 tn++;
194 if (!*tn)
195 return FALSE;
196 lo = *tn;
197 tn++;
198 if (*tn != '-')
199 return FALSE;
200 tn++;
201 if (!*tn)
202 return FALSE;
203 hi = *tn;
204 tn++;
205 if (*tn != ']')
206 return FALSE;
207 tn++;
208 if (ignore) {
209 if ((toupper(string[len2]) >= toupper(lo)) &&
210 (toupper(string[len2]) <= toupper(hi)))
211 len2++;
212 else {
213 tn = pattern;
214 len2 = lastlen = lastlen + 1;
215 }
216 }
217 else {
218 if ((string[len2] >= lo) && (string[len2] <= hi))
219 len2++;
220 else {
221 tn = pattern;
222 len2 = lastlen = lastlen + 1;
223 }
224 }
225 break;
226
227 case '?':
228 tn++;
229 len2++;
230 break;
231
232 case '\\':
233 tn++;
234 if (!*tn)
235 return FALSE;
236 // else intentional fallthru
237 default:
238 if (ignore) {
239 if (toupper(*tn) == toupper(string[len2])) {
240 tn++;
241 len2++;
242 }
243 else {
244 tn = pattern;
245 len2 = lastlen = lastlen + 1;
246 }
247 }
248 else {
249 if (*tn == string[len2]) {
250 tn++;
251 len2++;
252 }
253 else {
254 tn = pattern;
255 len2 = lastlen = lastlen + 1;
256 }
257 }
258 break;
259 }
260 }
261 while (*tn == '*')
262 tn++;
263
264 if (!*tn)
265 return TRUE;
266 }
267 return FALSE;
268}
269
270static BOOL match(CHAR *string, CHAR *patterns, BOOL absolute, BOOL ignore,
271 LONG len, ULONG numlines, CHAR *matched, BOOL matchall)
272{
273 BOOL ret = FALSE;
274 register CHAR *p;
275 register ULONG x = 0;
276
277 p = patterns;
278 while (!ret && *p) {
279 ret = m_match(string, p, absolute, ignore, len);
280 if (matchall && ret)
281 break;
282 if (matched && ret && x < numlines)
283 matched[x] = 1;
284 p += strlen(p); // check each pattern in 0-terminated list
285 p++;
286 x++;
287 }
288 return ret;
289}
290
291VOID GrepThread(VOID *arg)
292{
293 HAB ghab;
294 HMQ ghmq;
295 GREP grep;
296 UINT x;
297 UINT numFileMasks;
298 static CHAR *fileMasks[512]; // 06 Feb 08 SHL FIXME to not be static
299 CHAR *p, *pp, searchPath[CCHMAXPATH * 2];
300
301 ITIMER_DESC itdSleep = { 0 }; // 06 Feb 08 SHL
302 ITIMER_DESC itdReport = { 0 };
303
304 if (!arg) {
305 Runtime_Error(pszSrcFile, __LINE__, NULL);
306 return;
307 }
308
309# ifdef FORTIFY
310 Fortify_EnterScope();
311# endif
312 grep = *(GREP *)arg;
313 *grep.stopflag = 0; // reset thread-killing flag
314 DosError(FERR_DISABLEHARDERR);
315 priority_normal();
316
317 ghab = WinInitialize(0);
318 if (ghab) {
319 grep.ghab = ghab;
320 ghmq = WinCreateMsgQueue(ghab, 0);
321 if (ghmq) {
322 WinCancelShutdown(ghmq, TRUE);
323 IncrThreadUsage();
324 // DosSleep(100); //05 Aug 07 GKY 128 // 07 Feb 08 SHL
325 // hwndStatus does not exist for applet
326 WinSetWindowText(hwndStatus ? hwndStatus : grep.hwndCurFile,
327 (CHAR *) GetPString(grep.finddupes ? IDS_GREPDUPETEXT :
328 IDS_GREPSCANTEXT));
329
330 pp = grep.searchPattern;
331 while (*pp) {
332 if (!grep.absFlag) {
333 p = GREPCHARS; // see if any sense in pattern matching
334 while (*p) {
335 if (strchr(pp, *p))
336 break;
337 p++;
338 }
339 if (!*p) // nope, turn it off
340 grep.absFlag = TRUE;
341 }
342 pp = pp + strlen(pp) + 1;
343 }
344
345 grep.attrFile &= (~FILE_DIRECTORY);
346 grep.antiattr &= (~FILE_DIRECTORY);
347 if (grep.antiattr & FILE_READONLY)
348 grep.antiattr |= MUST_HAVE_READONLY;
349 if (grep.antiattr & FILE_HIDDEN)
350 grep.antiattr |= MUST_HAVE_HIDDEN;
351 if (grep.antiattr & FILE_SYSTEM)
352 grep.antiattr |= MUST_HAVE_SYSTEM;
353 if (grep.antiattr & FILE_ARCHIVED)
354 grep.antiattr |= MUST_HAVE_ARCHIVED;
355
356 grep.anyexcludes = FALSE;
357 numFileMasks = 0;
358 fileMasks[numFileMasks++] = strtok(grep.fileMasks, ";");
359
360 while ((fileMasks[numFileMasks] = strtok(NULL, ";")) != NULL && numFileMasks < 511) {
361 if (*fileMasks[numFileMasks] == '/')
362 grep.anyexcludes = TRUE;
363 numFileMasks++;
364 }
365
366 InitITimer(&itdSleep, 100); // Sleep every 100 mSec (was 500) GKY 8/11/13
367 InitITimer(&itdReport, 2000); // Report every 2 sec
368
369 // loop through search masks
370 for (x = 0; x < numFileMasks; x++) {
371
372 // Ignore exclude masks here
373 if (*fileMasks[x] == '/')
374 goto ExcludeSkip;
375
376 // Split directory pathname from mask
377 p = (char *)(fileMasks[x] + (strlen(fileMasks[x]) - 1));
378 while (*p != '\\' && *p != ':' && p != fileMasks[x])
379 --p;
380
381 if (p == fileMasks[x]) { // no path
382 strcpy(searchPath, grep.curdir);
383 strncpy(grep.fileMask, fileMasks[x], CCHMAXPATH);
384 grep.fileMask[CCHMAXPATH - 1] = 0;
385 }
386 else { // got to deal with a path
387 if (*p == ':') { // just a drive, start in root dir
388 *p = 0;
389 p++;
390 strncpy(searchPath, fileMasks[x], CCHMAXPATH - 2);
391 searchPath[CCHMAXPATH - 3] = 0;
392 strcat(searchPath, ":\\");
393 strcpy(grep.fileMask, p);
394 }
395 if (*p == '\\') {
396 // got a 'full' path
397 CHAR temp;
398
399 p++;
400 temp = *p; // Save for restore
401 *p = 0; // Chop after backslash
402 strncpy(searchPath, fileMasks[x], CCHMAXPATH);
403 searchPath[CCHMAXPATH - 1] = 0;
404 *p = temp;
405 strcpy(grep.fileMask, p);
406 }
407 if (!*grep.fileMask)
408 strcpy(grep.fileMask, "*");
409 }
410 if (*grep.stopflag)
411 break;
412 // do top level directory
413 DoMatchingFiles(&grep, searchPath, fileMasks, numFileMasks, &itdSleep, &itdReport);
414 // Recurse subdirectories if requested
415 if (grep.dirFlag)
416 DoAllSubdirs(&grep, searchPath, FALSE, fileMasks, numFileMasks, &itdSleep, &itdReport);
417
418 ExcludeSkip:
419 if (*grep.stopflag)
420 break;
421 if (WinIsWindow(grep.ghab, grep.hwndFiles))
422 DoInsertion(&grep, &itdSleep, &itdReport); // insert any remaining objects
423 } // for
424
425 if (WinIsWindow(grep.ghab, grep.hwndFiles))
426 DoInsertion(&grep, &itdSleep, &itdReport); // insert any remaining objects
427
428 if (WinIsWindow(grep.ghab, grep.hwndFiles) &&
429 grep.finddupes &&
430 !*grep.stopflag)
431 {
432 FillDupes(&grep, &itdSleep, &itdReport);
433 CollectorsortFlags = 0;
434 CollectorsortFlags |= SORT_FILENAME;
435 WinSendMsg(grep.hwndFiles, CM_SORTRECORD, MPFROMP(SortCollectorCnr),
436 MPFROMLONG(CollectorsortFlags));
437 SaySort(WinWindowFromID(WinQueryWindow(grep.hwndFiles, QW_PARENT),
438 DIR_SORT), CollectorsortFlags, FALSE);
439 }
440 if (!PostMsg(grep.hwndFiles, UM_CONTAINER_FILLED, MPVOID, MPVOID)) // tell window we're done
441 WinSendMsg(grep.hwndFiles, UM_CONTAINER_FILLED, MPVOID, MPVOID);
442 WinDestroyMsgQueue(ghmq);
443 }
444 DecrThreadUsage();
445 WinTerminate(ghab);
446 }
447 if (!ghmq || !ghab)
448 WinPostMsg(grep.hwndFiles, UM_CONTAINER_FILLED, MPVOID, MPVOID);
449 if (grep.dupehead)
450 FreeDupes(&grep);
451 if (grep.numlines && grep.matched) {
452 free(grep.matched);
453 }
454 // 07 Feb 08 SHL FIXME to free grep here when not static
455# ifdef FORTIFY
456 Fortify_LeaveScope();
457# endif
458 DosPostEventSem(CompactSem);
459}
460
461static BOOL IsExcluded(CHAR *name, CHAR **fileMasks, UINT numFileMasks)
462{
463 UINT x;
464 CHAR *n;
465
466 n = strrchr(name, '\\');
467 if (!n)
468 n = strrchr(name, ':');
469 if (n)
470 n++;
471 else
472 n = name;
473 for (x = 0; x < numFileMasks; x++) {
474 if (*fileMasks[x] == '/' &&
475 wildcard((strchr(fileMasks[x], '\\') ||
476 strchr(fileMasks[x], ':')) ? name : n, fileMasks[x] + 1, FALSE))
477 return TRUE;
478 }
479 return FALSE;
480}
481
482/**
483 * Recurse though subdirectories selecting files
484 */
485
486static VOID DoAllSubdirs(GREP *grep,
487 CHAR *searchPath,
488 BOOL recursing,
489 CHAR **fileMasks,
490 UINT numFileMasks,
491 ITIMER_DESC *pitdSleep,
492 ITIMER_DESC *pitdReport)
493{
494 FILEFINDBUF4 ffb;
495 HDIR findHandle = HDIR_CREATE;
496 ULONG ulFindCnt = 1;
497 CHAR *p = NULL;
498
499 // Append wildcard mask to directory pathname
500 AddBackslashToPath(searchPath);
501 strcat(searchPath, "*");
502 DosError(FERR_DISABLEHARDERR);
503 // Find first directory
504 if (!DosFindFirst(searchPath,
505 &findHandle,
506 (MUST_HAVE_DIRECTORY | FILE_ARCHIVED | FILE_SYSTEM |
507 FILE_HIDDEN | FILE_READONLY),
508 &ffb,
509 sizeof(ffb),
510 &ulFindCnt,
511 FIL_QUERYEASIZE))
512 {
513 // Point p at appended wildcard pattern to speed up pathname build
514 p = strrchr(searchPath, '\\');
515 if (p)
516 p++;
517 else
518 p = searchPath;
519 do { // Process each directory that matches the mask
520 int skip;
521 if (*grep->stopflag)
522 break;
523 // 2014-02-08 SHL
524 // Skip . and ..
525 skip = ffb.achName[0] == '.' &&
526 (ffb.achName[1] == 0 ||
527 (ffb.achName[1] == '.' && ffb.achName[2] == 0));
528 if (!skip && grep->ignoreSVN) {
529 // Skip version control meta data directories
530 skip = stricmp(ffb.achName, ".svn") == 0 ||
531 stricmp(ffb.achName, ".git") == 0 ||
532 stricmp(ffb.achName, ".hg") == 0 ||
533 stricmp(ffb.achName, "CVS") == 0;
534 }
535 if (!skip) {
536 strcpy(p, ffb.achName); // Build full directory pathname
537 skip = grep->anyexcludes && IsExcluded(searchPath, fileMasks, numFileMasks);
538 }
539 if (!skip) {
540 // Directory is selected
541 // 07 Feb 08 SHL
542 if (IsITimerExpired(pitdReport)) {
543 if (!hwndStatus)
544 WinSetWindowText(grep->hwndCurFile, searchPath);
545 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles) {
546 CHAR s[CCHMAXPATH + 64];
547 sprintf(s, "%s %s", GetPString(IDS_SCANNINGTEXT), searchPath);
548 WinSetWindowText(hwndStatus, s);
549 }
550 }
551 // Select files from directory
552 DoMatchingFiles(grep, searchPath, fileMasks, numFileMasks, pitdSleep, pitdReport);
553 // 07 Feb 08 SHL
554 if (IsITimerExpired(pitdReport)) {
555 priority_normal();
556 if (!hwndStatus)
557 WinSetWindowText(grep->hwndCurFile, searchPath);
558 else {
559 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles) {
560 CHAR s[CCHMAXPATH + 64];
561 sprintf(s, "%s %s", GetPString(IDS_SCANNINGTEXT), searchPath);
562 WinSetWindowText(hwndStatus, s);
563 }
564 };
565 }
566 // Recurse
567 DoAllSubdirs(grep, searchPath, TRUE, fileMasks, numFileMasks, pitdSleep, pitdReport);
568 } // if !skip
569 ulFindCnt = 1;
570 // Get next directory
571 } while (!DosFindNext(findHandle,
572 &ffb,
573 sizeof(ffb),
574 &ulFindCnt));
575 DosFindClose(findHandle);
576 } // if at least one directory
577 if (p) // Restore orginal directory pathname
578 *p = 0;
579}
580
581/**
582 * Select files matching wildcard masks in single directory
583 */
584
585static INT DoMatchingFiles(GREP *grep,
586 CHAR *path,
587 CHAR **fileMasks,
588 UINT numFileMasks,
589 ITIMER_DESC *pitdSleep,
590 ITIMER_DESC *pitdReport)
591{
592 PFILEFINDBUF4L pffbArray;
593 PFILEFINDBUF4L pffbFile;
594 ULONG x;
595 HDIR findHandle = HDIR_CREATE;
596 ULONG ulFindCnt;
597 CHAR szFindPath[CCHMAXPATH];
598 PSZ p;
599 APIRET rc;
600 ULONG ulBufBytes = FilesToGet * sizeof(FILEFINDBUF4L);
601 static BOOL fDone;
602
603 pffbArray = xmalloc(ulBufBytes, pszSrcFile, __LINE__);
604 if (!pffbArray)
605 return 0;
606
607 BldFullPathName(szFindPath, path, grep->fileMask);
608
609 MakeFullName(szFindPath);
610
611 // Point p at wildcard mask to speed up pathname build
612 p = strrchr(szFindPath, '\\');
613 if (p)
614 p++;
615 else
616 p = szFindPath;
617
618 // Step through matching files
619 DosError(FERR_DISABLEHARDERR);
620 ulFindCnt = FilesToGet;
621 rc = xDosFindFirst(szFindPath,
622 &findHandle,
623 FILE_NORMAL | grep->attrFile | grep->antiattr,
624 pffbArray,
625 ulBufBytes,
626 &ulFindCnt,
627 FIL_QUERYEASIZEL);
628 if (!rc) {
629 do {
630 // Process each file that matches the mask
631 pffbFile = pffbArray;
632 for (x = 0; x < ulFindCnt; x++) {
633 if (*grep->stopflag)
634 break;
635 // 2014-02-08 SHL FIXME to know if really need to skip . and .. here
636 // We should only be selecting files
637 if (*pffbFile->achName != '.' ||
638 (pffbFile->achName[1] && pffbFile->achName[1] != '.')) {
639 strcpy(p, pffbFile->achName); // build full file pathname
640 if (strlen(szFindPath) > CCHMAXPATH){
641 // Complain if pathnames exceeds max
642 DosFindClose(findHandle);
643 if (!fDone) {
644 fDone = TRUE;
645 saymsg(MB_OK | MB_ICONASTERISK,
646 HWND_DESKTOP,
647 GetPString(IDS_WARNINGTEXT),
648 GetPString(IDS_LENGTHEXCEEDSMAXPATHTEXT));
649 }
650 return 1;
651 }
652
653 // 07 Feb 08 SHL
654 if (IsITimerExpired(pitdReport)) {
655 if (!hwndStatus)
656 WinSetWindowText(grep->hwndCurFile, szFindPath);
657 else {
658 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles) {
659 CHAR s[CCHMAXPATH + 64];
660 sprintf(s, "%s %s", GetPString(IDS_SCANNINGTEXT), szFindPath);
661 WinSetWindowText(hwndStatus, s);
662 }
663 }
664 }
665
666 if (!grep->anyexcludes || !IsExcluded(szFindPath, fileMasks, numFileMasks)) {
667 // File selected
668 if (!grep->finddupes)
669 DoOneFile(grep, szFindPath, pffbFile, pitdSleep, pitdReport);
670 else if (!InsertDupe(grep, szFindPath, pffbFile)) {
671 DosFindClose(findHandle);
672 free(pffbArray);
673# ifdef FORTIFY
674 Fortify_LeaveScope();
675# endif
676 return 1;
677 }
678 }
679 }
680 if (!pffbFile->oNextEntryOffset)
681 break;
682 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + pffbFile->oNextEntryOffset);
683 } // for
684 if (*grep->stopflag)
685 break;
686 IdleIfNeeded(pitdSleep, 30);
687 ulFindCnt = FilesToGet;
688 // Next file
689 rc = xDosFindNext(findHandle, pffbArray, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
690 } while (!rc);
691
692 DosFindClose(findHandle);
693 } // if at least one file
694
695 if (rc && rc != ERROR_NO_MORE_FILES) {
696 if (rc == ERROR_FILENAME_EXCED_RANGE) {
697 CHAR FileSystem[CCHMAXPATH];
698
699 CheckDrive(toupper(*szFindPath), FileSystem, NULL);
700 if (strcmp(FileSystem, NTFS))
701 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
702 GetPString(IDS_CANTFINDDIRTEXT), szFindPath);
703 }
704 else
705 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
706 GetPString(IDS_CANTFINDDIRTEXT), szFindPath);
707 }
708
709 free(pffbArray);
710# ifdef FORTIFY
711 Fortify_LeaveScope();
712# endif
713 return 0;
714}
715
716static VOID freegreplist(GREP *grep)
717{
718 UINT x;
719
720 if (grep) {
721 if (grep->insertffb) {
722 for (x = 0; grep->insertffb[x]; x++) {
723 free(grep->insertffb[x]);
724 }
725 free(grep->insertffb);
726 }
727 if (grep->dir) {
728 for (x = 0; grep->dir[x]; x++) {
729 free(grep->dir[x]);
730 }
731 free(grep->dir);
732 }
733 grep->dir = NULL;
734 grep->insertffb = NULL;
735 grep->toinsert = 0L;
736 grep->insertedbytes = 0L;
737# ifdef FORTIFY
738 Fortify_LeaveScope();
739# endif
740 }
741}
742
743/**
744 * Insert one or more records into container
745 */
746
747static BOOL DoInsertion(GREP *grep,
748 ITIMER_DESC *pitdSleep,
749 ITIMER_DESC *pitdReport)
750{
751 RECORDINSERT ri;
752 DIRCNRDATA *dcd;
753 PCNRITEM pci, pciFirst;
754 UINT x;
755 ULONG ulRecsToInsert;
756
757 if (!grep || !grep->toinsert || !grep->insertffb || !grep->dir)
758 return FALSE;
759
760 pci = NULL;
761 dcd = INSTDATA(grep->hwndFiles);
762 for (x = 0; grep->insertffb[x]; x++) {
763 if (pci == NULL) {
764 ulRecsToInsert = grep->toinsert - x < USHRT_MAX ? grep->toinsert - x : USHRT_MAX;
765 pciFirst = WinSendMsg(grep->hwndFiles, CM_ALLOCRECORD,
766 MPFROMLONG(EXTRA_RECORD_BYTES),
767 MPFROMLONG(ulRecsToInsert));
768 if (!pciFirst) {
769 Win_Error(grep->hwndFiles, grep->hwndFiles, pszSrcFile, __LINE__,
770 PCSZ_CM_ALLOCRECORD);
771 freegreplist(grep);
772 return FALSE;
773 }
774 else {
775 pci = pciFirst;
776 if (grep->sayfiles) {
777 if (!hwndStatus)
778 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPINSERTINGTEXT));
779 else {
780 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
781 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPINSERTINGTEXT));
782 }
783 }
784 }
785 }
786 FillInRecordFromFFB(grep->hwndFiles,
787 pci, grep->dir[x], grep->insertffb[x], FALSE, dcd);
788 pci = (PCNRITEM) pci->rc.preccNextRecord;
789 //SleepIfNeeded(pitdSleep, 1);
790 if (pci == NULL && ulRecsToInsert) {
791 memset(&ri, 0, sizeof(RECORDINSERT));
792 ri.cb = sizeof(RECORDINSERT);
793 ri.pRecordOrder = (PRECORDCORE) CMA_END;
794 ri.pRecordParent = (PRECORDCORE) NULL;
795 ri.zOrder = (USHORT) CMA_TOP;
796 ri.cRecordsInsert = ulRecsToInsert;
797 ri.fInvalidateRecord = TRUE;
798 WinSendMsg(grep->hwndFiles,
799 CM_INSERTRECORD, MPFROMP(pciFirst), MPFROMP(&ri));
800 if (dcd) {
801 DosRequestMutexSem(hmtxFM2Globals, SEM_INDEFINITE_WAIT);
802 dcd->ullTotalBytes += grep->insertedbytes;
803 DosReleaseMutexSem(hmtxFM2Globals);
804 }
805 pciFirst = NULL;
806 }
807 SleepIfNeeded(pitdSleep, 1);
808 }//for
809 // if (grep->toinsert == FilesToGet) // 07 Feb 08 SHL
810 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
811 freegreplist(grep);
812 PostMsg(grep->hwndFiles, UM_RESCAN, MPVOID, MPVOID);
813 return TRUE;
814}
815
816/**
817 * Insert file ffb and directory name into lists
818 */
819
820static BOOL InsertGrepFile(GREP *grep,
821 CHAR *pszFileName,
822 PFILEFINDBUF4L pffb,
823 ITIMER_DESC *pitdSleep,
824 ITIMER_DESC *pitdReport)
825{
826 PSZ p;
827 CHAR szDirectory[CCHMAXPATH];
828
829 if (!WinIsWindow(grep->ghab, grep->hwndFiles)) {
830 // Window closed - clean up and go away
831 freegreplist(grep);
832 }
833 else {
834 grep->numfiles++;
835 strcpy(szDirectory, pszFileName);
836 p = strrchr(szDirectory, '\\');
837
838 if (p) {
839 // Got directory
840 if (p < szDirectory + 4)
841 p++; // Include root backslash
842 *p = 0;
843
844 if (!grep->insertffb) {
845 // Allocate 1 extra for end marker?
846 grep->insertffb = xmallocz(sizeof(PFILEFINDBUF4L) * (FilesToGet + 1),
847 pszSrcFile, __LINE__);
848 if (!grep->insertffb)
849 return FALSE;
850 grep->dir = xmallocz(sizeof(CHAR *) * (FilesToGet + 1),
851 pszSrcFile, __LINE__);
852 if (!grep->dir) {
853 free(grep->insertffb);
854# ifdef FORTIFY
855 Fortify_LeaveScope();
856# endif
857 return FALSE;
858 }
859 }
860
861 grep->insertffb[grep->toinsert] =
862 xmalloc(sizeof(FILEFINDBUF4L), pszSrcFile, __LINE__);
863 if (!grep->insertffb[grep->toinsert])
864 return FALSE;
865 memcpy(grep->insertffb[grep->toinsert], pffb, sizeof(FILEFINDBUF4L));
866
867 grep->dir[grep->toinsert] = xstrdup(szDirectory, pszSrcFile, __LINE__);
868 if (!grep->dir) {
869 free(grep->insertffb[grep->toinsert]);
870# ifdef FORTIFY
871 Fortify_LeaveScope();
872# endif
873 return FALSE;
874 }
875
876 grep->insertedbytes += pffb->cbFile + CBLIST_TO_EASIZE(pffb->cbList);
877 grep->toinsert++;
878 // 07 Oct 09 SHL honor sync updates
879 if (grep->toinsert == FilesToGet || fSyncUpdates)
880 return DoInsertion(grep, pitdSleep, pitdReport);
881 return TRUE;
882 }
883 }
884 return FALSE;
885}
886
887/**
888 * Check file matches search criteria
889 */
890
891static BOOL DoOneFile(GREP *grep,
892 CHAR *pszFileName,
893 FILEFINDBUF4L *pffb,
894 ITIMER_DESC *pitdSleep,
895 ITIMER_DESC *pitdReport)
896{
897 // process a single file
898 CHAR *input;
899 FILE *inputFile;
900 ULONG pos;
901 BOOL ret = FALSE, strmatch = FALSE;
902
903 grep->fileCount++;
904 if (grep->sayfiles) {
905 if (!hwndStatus)
906 WinSetWindowText(grep->hwndCurFile, pszFileName);
907 else {
908 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
909 WinSetWindowText(hwndStatus, pszFileName);
910 }
911 }
912
913 if (grep->greaterthan || grep->lessthan) {
914
915 BOOL keep = TRUE;
916 ULONG adjsize;
917
918 adjsize = pffb->cbFile + (grep->searchEAs ? CBLIST_TO_EASIZE(pffb->cbList) : 0);
919 if (grep->greaterthan) {
920 if (adjsize < grep->greaterthan)
921 keep = FALSE;
922 }
923 if (keep && grep->lessthan) {
924 if (adjsize > grep->lessthan)
925 keep = FALSE;
926 }
927 if (!keep)
928 return ret;
929 }
930
931 if (grep->newerthan || grep->olderthan) {
932
933 BOOL keep = TRUE;
934 ULONG numsecs;
935
936 numsecs = SecsSince1980(&pffb->fdateLastWrite, &pffb->ftimeLastWrite);
937 if (grep->newerthan) {
938 if (numsecs < grep->newerthan)
939 keep = FALSE;
940 }
941 if (keep && grep->olderthan) {
942 if (numsecs > grep->olderthan)
943 keep = FALSE;
944 }
945 if (!keep)
946 return ret;
947 }
948
949 if ((!grep->searchEAs && !grep->searchFiles) || !*grep->searchPattern) // just a find
950 return InsertGrepFile(grep, pszFileName, pffb, pitdSleep, pitdReport);
951
952 if (grep->searchEAs) {
953
954 HOLDFEA *head, *info;
955 USHORT type, len;
956 BOOL alltext;
957 CHAR *data, temp;
958
959 head = GetFileEAs(pszFileName, FALSE, TRUE);
960 if (head) {
961 info = head;
962 while (info && !strmatch) {
963 alltext = TRUE;
964 switch (*(USHORT *)info->value) {
965 case EAT_ASCII:
966 if (match(info->value + (sizeof(USHORT) * 2),
967 grep->searchPattern, grep->absFlag,
968 grep->caseFlag == FALSE,
969 info->cbValue - (sizeof(USHORT) * 2),
970 grep->numlines,
971 grep->matched,
972 !grep->findifany)) {
973 strmatch = TRUE;
974 }
975 break;
976 case EAT_MVST:
977 type = *(USHORT *)(info->value + (sizeof(USHORT) * 3));
978 if (type == EAT_ASCII) {
979 data = info->value + (sizeof(USHORT) * 4);
980 len = *(USHORT *) data;
981 data += sizeof(USHORT);
982 while ((data - info->value) + len <= info->cbValue) {
983 temp = *(data + len);
984 *(data + len) = 0;
985 if (match(data,
986 grep->searchPattern,
987 grep->absFlag,
988 (grep->caseFlag == FALSE),
989 len,
990 grep->numlines, grep->matched, !grep->findifany)) {
991 strmatch = TRUE;
992 break;
993 }
994 data += len;
995 if (data - info->value >= info->cbValue)
996 break;
997 *data = temp;
998 len = *(USHORT *) data;
999 data += sizeof(USHORT);
1000 }
1001 }
1002 break;
1003 case EAT_MVMT:
1004 data = info->value + (sizeof(USHORT) * 3);
1005 type = *(USHORT *) data;
1006 data += sizeof(USHORT);
1007 len = *(USHORT *) data;
1008 data += sizeof(USHORT);
1009 while ((data - info->value) - len <= info->cbValue) {
1010 if (type != EAT_ASCII) {
1011 alltext = FALSE;
1012 break;
1013 }
1014 data += len;
1015 if (data - info->value >= info->cbValue)
1016 break;
1017 type = *(USHORT *) data;
1018 data += sizeof(USHORT);
1019 len = *(USHORT *) data;
1020 data += sizeof(USHORT);
1021 }
1022 if (alltext) {
1023 data = info->value + (sizeof(USHORT) * 3);
1024 type = *(USHORT *) data;
1025 data += sizeof(USHORT);
1026 len = *(USHORT *) data;
1027 data += sizeof(USHORT);
1028 while ((data - info->value) - len <= info->cbValue) {
1029 temp = *(data + len);
1030 *(data + len) = 0;
1031 if (match(data,
1032 grep->searchPattern,
1033 grep->absFlag,
1034 (grep->caseFlag == FALSE),
1035 len,
1036 grep->numlines, grep->matched, !grep->findifany)) {
1037 strmatch = TRUE;
1038 break;
1039 }
1040 data += len;
1041 *data = temp;
1042 if (data - info->value >= info->cbValue)
1043 break;
1044 type = *(USHORT *) data;
1045 data += sizeof(USHORT);
1046 len = *(USHORT *) data;
1047 data += sizeof(USHORT);
1048 }
1049 }
1050 break;
1051 default:
1052 break;
1053 }
1054 info = info->next;
1055 } // while
1056 Free_FEAList(head);
1057 // DosSleep(1); // 07 Feb 08 SHL
1058 }
1059 }
1060
1061 if (grep->searchFiles) {
1062 input = xmalloc(65537, pszSrcFile, __LINE__);
1063 if (input) {
1064 LONG len;
1065 CHAR *moderb = "rb";
1066
1067 inputFile = xfsopen(pszFileName, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
1068 if (inputFile) {
1069 pos = ftell(inputFile);
1070 while (!feof(inputFile)) {
1071 if (pos)
1072 fseek(inputFile, pos - 1024, SEEK_SET);
1073 len = fread(input, 1, 65536, inputFile);
1074 if (len >= 0) {
1075 if (*grep->stopflag)
1076 break;
1077 if (match(input,
1078 grep->searchPattern,
1079 grep->absFlag,
1080 (grep->caseFlag == FALSE),
1081 len, grep->numlines, grep->matched, !grep->findifany)) {
1082 strmatch = TRUE;
1083 break;
1084 }
1085 }
1086 else
1087 break;
1088 }
1089 fclose(inputFile);
1090 }
1091 free(input);
1092# ifdef FORTIFY
1093 Fortify_LeaveScope();
1094# endif
1095 // DosSleep(1); // 07 Feb 08 SHL
1096 }
1097 } // if
1098
1099 if (strmatch)
1100 ret = InsertGrepFile(grep, pszFileName, pffb, pitdSleep, pitdReport);
1101 return ret;
1102}
1103
1104static LONG cr3tab[] = { // CRC polynomial 0xEDB88320
1105
1106 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
1107 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
1108 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1109 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
1110 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1111 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1112 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
1113 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
1114 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1115 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1116 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
1117 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1118 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
1119 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
1120 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1121 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
1122 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
1123 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1124 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
1125 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1126 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1127 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
1128 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
1129 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1130 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1131 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
1132 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1133 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
1134 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
1135 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1136 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
1137 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
1138 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1139 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
1140 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1141 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1142 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
1143 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
1144 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1145 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1146 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
1147 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1148 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
1149 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
1150 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1151 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
1152 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
1153 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1154 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
1155 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1156 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1157 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
1158 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
1159 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1160 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1161 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1162 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1163 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1164 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
1165 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1166 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
1167 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1168 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1169 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
1170};
1171
1172LONG CRCBlock(register CHAR *str, register INT blklen, register LONG crc)
1173{
1174 while (blklen--) {
1175 crc =
1176 cr3tab[((INT) crc ^ *str) & 0xff] ^ (((ULONG) crc >> 8) & 0x00FFFFFF);
1177 str++;
1178 }
1179 return crc;
1180}
1181
1182LONG CRCFile(CHAR *pszFileName, INT *error)
1183{
1184 LONG CRC = -1L, len;
1185 FILE *fp;
1186 CHAR *buffer;
1187 CHAR *moderb = "rb";
1188
1189 *error = 0;
1190 buffer = xmalloc(65535, pszSrcFile, __LINE__);
1191 if (!buffer)
1192 *error = -1;
1193 else {
1194 fp = xfsopen(pszFileName, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
1195 if (!fp)
1196 *error = -2;
1197 else {
1198 while (!feof(fp)) {
1199 len = fread(buffer, 1, 65535, fp);
1200 if (len && len < 65536L)
1201 CRC = CRCBlock(buffer, len, CRC);
1202 else
1203 break;
1204 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
1205 }
1206 fclose(fp);
1207 // DosSleep(1); // 07 Feb 08 SHL
1208 }
1209 free(buffer);
1210# ifdef FORTIFY
1211 Fortify_LeaveScope();
1212# endif
1213 }
1214 return CRC;
1215}
1216
1217static VOID FreeDupes(GREP *grep)
1218{
1219 DUPES *i, *next;
1220
1221 i = grep->dupehead;
1222 while (i) {
1223 next = i->next;
1224 if (i->name) {
1225 free(i->name);
1226 }
1227 free(i);
1228 i = next;
1229 }
1230 grep->dupehead = grep->dupelast = NULL;
1231 xfree(grep->dupenames, pszSrcFile, __LINE__);
1232 xfree(grep->dupesizes, pszSrcFile, __LINE__);
1233 grep->dupesizes = grep->dupenames = NULL;
1234# ifdef FORTIFY
1235 Fortify_LeaveScope();
1236# endif
1237}
1238
1239INT comparenamesq(const VOID *v1, const VOID *v2)
1240{
1241 DUPES *d1 = *(DUPES **) v1;
1242 DUPES *d2 = *(DUPES **) v2;
1243 CHAR *p1, *p2;
1244
1245 p1 = strrchr(d1->name, '\\');
1246 if (p1)
1247 p1++;
1248 else
1249 p1 = d1->name;
1250 p2 = strrchr(d2->name, '\\');
1251 if (p2)
1252 p2++;
1253 else
1254 p2 = d2->name;
1255 return stricmp(p1, p2);
1256}
1257
1258INT comparenamesqe(const VOID *v1, const VOID *v2)
1259{
1260 DUPES *d1 = *(DUPES **) v1;
1261 DUPES *d2 = *(DUPES **) v2;
1262 CHAR *p1, *p2, *p1e, *p2e, e1, e2;
1263 INT ret;
1264
1265 p1 = strrchr(d1->name, '\\');
1266 if (p1)
1267 p1++;
1268 else
1269 p1 = d1->name;
1270 p1e = strrchr(p1, '.');
1271 if (p1e) {
1272 e1 = *p1e;
1273 *p1e = 0;
1274 }
1275 p2 = strrchr(d2->name, '\\');
1276 if (p2)
1277 p2++;
1278 else
1279 p2 = d2->name;
1280 p2e = strrchr(p2, '.');
1281 if (p2e) {
1282 e2 = *p2e;
1283 *p2e = 0;
1284 }
1285 ret = stricmp(p1, p2);
1286 if (p1e)
1287 *p1e = e1;
1288 if (p2e)
1289 *p2e = e2;
1290 return ret;
1291}
1292
1293INT comparesizesq(const void *v1, const void *v2)
1294{
1295 DUPES *d1 = *(DUPES **) v1;
1296 DUPES *d2 = *(DUPES **) v2;
1297
1298 return (d1->size > d2->size) ? 1 : (d1->size == d2->size) ? 0 : -1;
1299}
1300
1301INT comparenamesb(const void *v1, const void *v2)
1302{
1303 DUPES *d1 = (DUPES *) v1;
1304 DUPES *d2 = *(DUPES **) v2;
1305 CHAR *p1, *p2;
1306
1307 p1 = strrchr(d1->name, '\\');
1308 if (p1)
1309 p1++;
1310 else
1311 p1 = d1->name;
1312 p2 = strrchr(d2->name, '\\');
1313 if (p2)
1314 p2++;
1315 else
1316 p2 = d2->name;
1317 return stricmp(p1, p2);
1318}
1319
1320INT comparenamesbe(const VOID *v1, const VOID *v2)
1321{
1322 DUPES *d1 = (DUPES *) v1;
1323 DUPES *d2 = *(DUPES **) v2;
1324 CHAR *p1, *p2, *p1e, *p2e, e1, e2;
1325 INT ret;
1326
1327 p1 = strrchr(d1->name, '\\');
1328 if (p1)
1329 p1++;
1330 else
1331 p1 = d1->name;
1332 p1e = strrchr(p1, '.');
1333 if (p1e) {
1334 e1 = *p1e;
1335 *p1e = 0;
1336 }
1337 p2 = strrchr(d2->name, '\\');
1338 if (p2)
1339 p2++;
1340 else
1341 p2 = d2->name;
1342 p2e = strrchr(p2, '.');
1343 if (p2e) {
1344 e2 = *p2e;
1345 *p2e = 0;
1346 }
1347 ret = stricmp(p1, p2);
1348 if (p1e)
1349 *p1e = e1;
1350 if (p2e)
1351 *p2e = e2;
1352 return ret;
1353}
1354
1355INT comparesizesb(const VOID *v1, const VOID *v2)
1356{
1357 DUPES *d1 = (DUPES *) v1;
1358 DUPES *d2 = *(DUPES **) v2;
1359
1360 return (d1->size > d2->size) ? 1 : (d1->size == d2->size) ? 0 : -1;
1361}
1362
1363static VOID FillDupes(GREP *grep,
1364 ITIMER_DESC *pitdSleep,
1365 ITIMER_DESC *pitdReport)
1366{
1367 DUPES *c, *i, **r;
1368 register CHAR *pc, *pi;
1369 CHAR **list = NULL;
1370 UINT numfiles = 0, numalloced = 0;
1371 INT error;
1372 ULONG x;
1373 ULONG y;
1374 // ULONG cntr = 1000; // 09 Feb 08 SHL
1375
1376 // if (grep->CRCdupes) // 09 Feb 08 SHL
1377 // cntr = 100; // 09 Feb 08 SHL
1378 x = 0;
1379 for (i = grep->dupehead; i; i = i->next)
1380 x++; // Count
1381
1382 if (x) {
1383 if (!hwndStatus)
1384 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPDUPESORTINGTEXT));
1385 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1386 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPDUPESORTINGTEXT));
1387 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
1388 grep->dupenames = xmalloc(sizeof(DUPES *) * (x + 1), pszSrcFile, __LINE__);
1389 if (!grep->nosizedupes)
1390 grep->dupesizes = xmalloc(sizeof(DUPES *) * (x + 1), pszSrcFile, __LINE__);
1391 if (grep->dupenames && (grep->nosizedupes || grep->dupesizes)) {
1392 y = 0;
1393 for (i = grep->dupehead; i; i = i->next) {
1394 grep->dupenames[y] = i;
1395 if (!grep->nosizedupes)
1396 grep->dupesizes[y] = i;
1397 y++;
1398 }
1399 grep->dupenames[y] = NULL; // Mark end
1400 if (!grep->nosizedupes)
1401 grep->dupesizes[y] = NULL;
1402
1403 InitITimer(pitdSleep, 0); // Reset rate estimator
1404 SleepIfNeeded(pitdSleep, 1);
1405 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
1406
1407 qsort(grep->dupenames,
1408 x,
1409 sizeof(DUPES *),
1410 grep->ignoreextdupes ? comparenamesqe : comparenamesq);
1411 SleepIfNeeded(pitdSleep, 1);
1412 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
1413 if (!grep->nosizedupes) {
1414 qsort(grep->dupesizes, x, sizeof(DUPES *), comparesizesq);
1415 SleepIfNeeded(pitdSleep, 1);
1416 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
1417 }
1418
1419 if (!hwndStatus)
1420 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1421 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1422 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1423
1424 InitITimer(pitdSleep, 0); // Reset rate estimator
1425 i = grep->dupehead;
1426 y = 0;
1427 while (i) {
1428 if (*grep->stopflag)
1429 break;
1430 SleepIfNeeded(pitdSleep, 1); // 07 Feb 08 SHL
1431 if (!(i->flags & GF_SKIPME)) {
1432 r = (DUPES **) bsearch(i, grep->dupenames, x, sizeof(DUPES *),
1433 ((grep->ignoreextdupes) ? comparenamesbe :
1434 comparenamesb));
1435 if (r) {
1436 while (r > grep->dupenames && ((grep->ignoreextdupes) ?
1437 !comparenamesqe((r - 1), &i) :
1438 !comparenamesq((r - 1), &i)))
1439 r--;
1440 while (*r && ((grep->ignoreextdupes) ?
1441 !comparenamesqe(r, &i) : !comparenamesq(r, &i))) {
1442 if (*r == i || ((*r)->flags & (GF_INSERTED | GF_SKIPME))) {
1443 r++;
1444 continue;
1445 }
1446 if (grep->CRCdupes) {
1447 if ((*r)->CRC == -1L) {
1448 (*r)->CRC = CRCFile((*r)->name, &error);
1449 if (error)
1450 (*r)->CRC = -1L;
1451 else if ((*r)->CRC == -1L)
1452 (*r)->CRC = 0L;
1453 }
1454 if (i->CRC == -1L) {
1455 i->CRC = CRCFile(i->name, &error);
1456 if (error)
1457 i->CRC = -1L;
1458 else if (i->CRC == -1L)
1459 i->CRC = 0L;
1460 }
1461 if (((*r)->size != i->size) || ((*r)->CRC != -1L &&
1462 i->CRC != -1L
1463 && (*r)->CRC != i->CRC)) {
1464 r++;
1465 continue;
1466 }
1467 }
1468 if (!AddToList((*r)->name, &list, &numfiles, &numalloced)) {
1469 (*r)->flags |= GF_INSERTED;
1470 if (grep->sayfiles) {
1471 if (!hwndStatus)
1472 WinSetWindowText(grep->hwndFiles, (*r)->name);
1473 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1474 WinSetWindowText(hwndStatus, (*r)->name);
1475 }
1476 if ((*r)->size == i->size &&
1477 (i->date.year == (*r)->date.year &&
1478 i->date.month == (*r)->date.month &&
1479 i->date.day == (*r)->date.day &&
1480 i->time.hours == (*r)->time.hours &&
1481 i->time.minutes == (*r)->time.minutes &&
1482 i->time.twosecs == (*r)->time.twosecs))
1483 (*r)->flags |= GF_SKIPME;
1484 }
1485 if (!(i->flags & (GF_INSERTED | GF_SKIPME))) {
1486 if (!AddToList(i->name, &list, &numfiles, &numalloced)) {
1487 i->flags |= GF_INSERTED;
1488 if ((*r)->flags & GF_SKIPME)
1489 i->flags |= GF_SKIPME;
1490 }
1491 }
1492 r++;
1493 }
1494 }
1495 if (!grep->nosizedupes) {
1496 r = (DUPES **) bsearch(i,
1497 grep->dupesizes,
1498 x, sizeof(DUPES *), comparesizesb);
1499 if (r) {
1500 while (r > grep->dupesizes && !comparesizesq((r - 1), &i))
1501 r--;
1502 while (*r && !comparesizesq(r, &i)) {
1503 if (*r == i || ((*r)->flags & (GF_INSERTED | GF_SKIPME)) ||
1504 (i->date.year != (*r)->date.year ||
1505 i->date.month != (*r)->date.month ||
1506 i->date.day != (*r)->date.day ||
1507 i->time.hours != (*r)->time.hours ||
1508 i->time.minutes != (*r)->time.minutes ||
1509 i->time.twosecs != (*r)->time.twosecs)) {
1510 r++;
1511 continue;
1512 }
1513 if (grep->CRCdupes) {
1514 if ((*r)->CRC == -1L) {
1515 (*r)->CRC = CRCFile((*r)->name, &error);
1516 if (error)
1517 (*r)->CRC = -1L;
1518 else if ((*r)->CRC == -1L)
1519 (*r)->CRC = 0L;
1520 }
1521 if (i->CRC == -1L) {
1522 i->CRC = CRCFile(i->name, &error);
1523 if (error)
1524 i->CRC = -1L;
1525 else if (i->CRC == -1L)
1526 i->CRC = 0L;
1527 }
1528 if ((*r)->CRC != -1L && i->CRC != -1L &&
1529 (*r)->CRC != i->CRC) {
1530 *r += 1;
1531 continue;
1532 }
1533 }
1534 if (!AddToList((*r)->name, &list, &numfiles, &numalloced)) {
1535 if (grep->sayfiles) {
1536 if (!hwndStatus)
1537 WinSetWindowText(grep->hwndCurFile, (*r)->name);
1538 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1539 WinSetWindowText(hwndStatus, (*r)->name);
1540 }
1541 (*r)->flags |= GF_INSERTED;
1542 if (((grep->ignoreextdupes) ?
1543 comparenamesqe(r, &i) : comparenamesq(r, &i)))
1544 (*r)->flags |= GF_SKIPME;
1545 }
1546 if (!(i->flags & (GF_INSERTED | GF_SKIPME))) {
1547 if (!AddToList(i->name, &list, &numfiles, &numalloced)) {
1548 i->flags |= GF_INSERTED;
1549 if ((*r)->flags & GF_SKIPME)
1550 i->flags |= GF_SKIPME;
1551 }
1552 }
1553 r++;
1554 }
1555 }
1556 }
1557 }
1558 i = i->next;
1559 y++;
1560 // 08 Feb 08 SHL
1561 if (IsITimerExpired(pitdReport)) {
1562 CHAR s[44];
1563 sprintf(s, GetPString(IDS_GREPDUPECHECKPROGTEXT), y, grep->numfiles);
1564 if (!hwndStatus)
1565 WinSetWindowText(grep->hwndCurFile, s);
1566 else {
1567 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1568 WinSetWindowText(hwndStatus, s);
1569 }
1570 }
1571 } // while
1572 }
1573 else {
1574 // Insufficient memory - fall back to slow method - FIXME to saymsg?
1575 if (!fErrorBeepOff)
1576 DosBeep(50, 100);
1577 if (!hwndStatus)
1578 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1579 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1580 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1581 x = y = 0;
1582 xfree(grep->dupenames, pszSrcFile, __LINE__);
1583 grep->dupenames = NULL;
1584 xfree(grep->dupesizes, pszSrcFile, __LINE__);
1585 grep->dupesizes = NULL;
1586# ifdef FORTIFY
1587 Fortify_LeaveScope();
1588# endif
1589
1590 InitITimer(pitdSleep, 0); // Reset rate estimator
1591 i = grep->dupehead;
1592 while (i) {
1593 if (*grep->stopflag)
1594 break;
1595 SleepIfNeeded(pitdSleep, 1);
1596 if (!(i->flags & GF_SKIPME)) {
1597 if (IsITimerExpired(pitdReport)) {
1598 // if (!(y % cntr)) { }
1599 CHAR s[44];
1600 sprintf(s, GetPString(IDS_GREPDUPECHECKPROGTEXT), y, grep->numfiles);
1601 if (!hwndStatus)
1602 WinSetWindowText(grep->hwndCurFile, s);
1603 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1604 WinSetWindowText(hwndStatus, s);
1605 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
1606 }
1607 y++;
1608 pi = strrchr(i->name, '\\');
1609 if (pi)
1610 pi++;
1611 else
1612 pi = i->name;
1613 c = grep->dupehead;
1614 while (c) {
1615 if (*grep->stopflag)
1616 break;
1617 if (c != i && !(c->flags & (GF_INSERTED | GF_SKIPME))) {
1618 x++;
1619 pc = strrchr(c->name, '\\');
1620 if (pc)
1621 pc++;
1622 else
1623 pc = c->name;
1624 if ((!grep->nosizedupes && i->size == c->size && i->date.year == c->date.year && i->date.month == c->date.month && i->date.day == c->date.day && i->time.hours == c->time.hours && i->time.minutes == c->time.minutes && i->time.twosecs == c->time.twosecs) || !stricmp(pc, pi)) { // potential dupe
1625 if (grep->CRCdupes) {
1626 if (grep->CRCdupes) {
1627 if (c->CRC == -1L) {
1628 c->CRC = CRCFile(c->name, &error);
1629 if (error)
1630 c->CRC = -1L;
1631 else if (c->CRC == -1L)
1632 c->CRC = 0L;
1633 }
1634 if (i->CRC == -1L) {
1635 i->CRC = CRCFile(i->name, &error);
1636 if (error)
1637 i->CRC = -1L;
1638 else if (i->CRC == -1L)
1639 i->CRC = 0L;
1640 }
1641 if ((c->size != i->size) || (c->CRC != -1L &&
1642 i->CRC != -1L
1643 && c->CRC != i->CRC)) {
1644 c = c->next;
1645 continue;
1646 }
1647 }
1648 }
1649 if (AddToList(c->name, &list, &numfiles, &numalloced))
1650 goto BreakOut; // Failed
1651 if (!(i->flags & GF_INSERTED)) {
1652 if (AddToList(i->name, &list, &numfiles, &numalloced))
1653 goto BreakOut; // Failed
1654 }
1655 if (grep->sayfiles) {
1656 if (!hwndStatus)
1657 WinSetWindowText(grep->hwndCurFile, pc);
1658 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1659 WinSetWindowText(hwndStatus, pc);
1660 }
1661 c->flags |= GF_INSERTED;
1662 i->flags |= GF_INSERTED;
1663 if (!stricmp(pc, pi)) {
1664 c->flags |= GF_SKIPME;
1665 i->flags |= GF_SKIPME;
1666 }
1667 }
1668 // else if (!(x % 100)) // 07 Feb 08 SHL
1669 // DosSleep(0); //26 Aug 07 GKY 1 // 07 Feb 08 SHL
1670 }
1671 c = c->next;
1672 }
1673 }
1674 i = i->next;
1675 } // while
1676 }
1677 }
1678BreakOut:
1679 FreeDupes(grep);
1680 if (numfiles && list) {
1681 if (!PostMsg(grep->hwndFiles,
1682 WM_COMMAND,
1683 MPFROM2SHORT(IDM_COLLECTOR, 0),
1684 MPFROMP(list)))
1685 FreeList(list);
1686 }
1687 else
1688 DosPostEventSem(CompactSem);
1689}
1690
1691static BOOL InsertDupe(GREP *grep, CHAR *dir, FILEFINDBUF4L *pffb)
1692{
1693 DUPES *info;
1694
1695 if (*dir) {
1696 info = xmallocz(sizeof(DUPES), pszSrcFile, __LINE__);
1697 if (!info)
1698 return FALSE;
1699
1700 info->name = xstrdup(dir, pszSrcFile, __LINE__);
1701 if (!info->name) {
1702 free(info);
1703# ifdef FORTIFY
1704 Fortify_LeaveScope();
1705# endif
1706 return FALSE;
1707 }
1708
1709 info->size = pffb->cbFile;
1710 info->date = pffb->fdateLastWrite;
1711 info->time = pffb->ftimeLastWrite;
1712 info->CRC = -1L;
1713 grep->numfiles++;
1714 if (!grep->dupehead)
1715 grep->dupehead = info;
1716 if (grep->dupelast)
1717 grep->dupelast->next = info;
1718 grep->dupelast = info;
1719 info->next = NULL;
1720 }
1721 return TRUE;
1722}
1723
1724#pragma alloc_text(GREP,InsertGrepFile,DoOneFile,DoInsertion,freegreplist)
1725#pragma alloc_text(GREP,SecsSince1980,match,mmatch,GrepThread)
1726#pragma alloc_text(GREP,DoAllSubdirs,DoMatchingFiles,InsertDupes,FreeDupes)
1727
1728#pragma alloc_text(DUPES,InsertDupe,FillDupes,FreeDupes,CRCFile,CRCBlock)
1729#pragma alloc_text(DUPES,comparenamesq,comparenamesqe,comparenamesb)
1730#pragma alloc_text(DUPES,comparenamesbe,comparesizesq,comparesizesb)
Note: See TracBrowser for help on using the repository browser.