source: trunk/dll/grep.c

Last change on this file was 1916, checked in by Gregg Young, 7 days ago

Fix easize so that EAs larger than 32767 show their actual size instead of 32767

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