source: trunk/dll/filldir.c@ 1649

Last change on this file since 1649 was 1649, checked in by Gregg Young, 14 years ago

Cleanup the scanning code to try to improve scan times.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.6 KB
Line 
1
2/***********************************************************************
3
4 $Id: filldir.c 1649 2011-11-19 20:38:33Z gyoung $
5
6 Fill Directory Tree Containers
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2001, 2011 Steven H. Levine
10
11 10 Jan 04 SHL ProcessDirectory: avoid most large drive failures
12 24 May 05 SHL Rework Win_Error usage
13 24 May 05 SHL Rework for CNRITEM.szSubject
14 25 May 05 SHL Rework for ULONGLONG
15 25 May 05 SHL Rework FillInRecordFromFFB
16 25 May 05 SHL Rework FillTreeCnr
17 28 May 05 SHL Drop stale debug code
18 05 Jun 05 SHL Comments
19 09 Jun 05 SHL Rework WinLoadFileIcon enables
20 09 Jun 05 SHL Rework IDFile
21 13 Aug 05 SHL Renames
22 24 Oct 05 SHL FillInRecordFromFFB: correct longname display enable
23 24 Oct 05 SHL FillInRecordFromFSA: correct longname display enable
24 24 Oct 05 SHL Drop obsolete code
25 22 Jul 06 SHL Check more run time errors
26 20 Oct 06 SHL Sync . .. check code
27 22 Oct 06 GKY Add NDFS32 support
28 17 Feb 07 GKY Additional archive and image file tyoes identifed by extension
29 17 Feb 07 GKY Add more drive types
30 09 Mar 07 GKY Use SelectDriveIcon
31 20 Mar 07 GKY Increase extention check to 4 letters for icon selections
32 23 Jun 07 GKY Fixed ram disk without a directory not appearing on states drive list
33 23 Jul 07 SHL Sync with CNRITEM updates (ticket#24)
34 29 Jul 07 SHL Add CNRITEM free and remove support (ticket#24)
35 02 Aug 07 SHL Add FileAttrToString
36 03 Aug 07 GKY Enlarged and made setable everywhere Findbuf (speed file loading)
37 04 Aug 07 SHL Update #pragma alloc_test for new functions
38 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
39 13 Aug 07 SHL Sync code with other FilesToGet usage and optimize
40 13 Aug 07 SHL Move #pragma alloc_text to end for OpenWatcom compat
41 04 Nov 07 GKY Use commaFmtULL to display large file sizes
42 29 Feb 08 GKY Use xfree where appropriate
43 07 Jul 08 SHL Use NULL rather than NullStr in FreeCnrItemData
44 16 JUL 08 GKY Use TMP directory for temp files
45 20 Jul 08 JBS Ticket 114: Support user-selectable env. strings in Tree container.
46 21 Jul 08 JBS Ticket 114: Change env var separator from blank to semicolon
47 02 Aug 08 GKY Remove redundant strcpys from inner loop
48 23 Aug 08 GKY Free pszDisplayName when appropriate
49 01 Sep 08 GKY Updated FreeCnrItemData to prevent trap in strrchr if pci->pszFileName is NULL.
50 05 Sep 08 SHL Correct FreeCnrItemData pszDisplayName pointer overlap check
51 08 Sep 08 SHL Remove extra pszLongName logic in FreeCnrItemData
52 18 Oct 08 GKY Scan drives in 4 passes (local, virtual, remote, flagged slow) to speed tree scans
53 19 Nov 08 SHL Correct and sanitize 4 pass scan logic
54 21 Nov 08 SHL FillTreeCnr: ensure any unchecked drives checked in pass 4
55 24 Nov 08 GKY Add StubyScanThread to treecnr scan/rescan drives all on separate threads
56 24 Nov 08 GKY Replace 4 pass drive scan code with StubyScanThread multithread scan
57 28 Nov 08 SHL FreeCnrItemData: optimize and always NULL pointers
58 28 Nov 08 SHL StubbyScanThread: add else lost in translation
59 30 Nov 08 SHL StubbyScanThread: restore else - we want all drives listed
60 30 Nov 08 SHL FreeCnrItemData: report double free with Runtime_Error
61 04 Dec 08 GKY Use event semaphore to prevent scan of "last" directory container prior to
62 tree scan completion; prevents duplicate directory names in tree.
63 10 Dec 08 SHL Integrate exception handler support
64 25 Dec 08 GKY Add code to allow write verify to be turned off on a per drive basis
65 25 Dec 08 GKY Add ProcessDirectoryThread to allow optional recursive drive scan at startup.
66 07 Feb 09 GKY Eliminate Win_Error2 by moving function names to PCSZs used in Win_Error
67 08 Mar 09 GKY Renamed commafmt.h i18nutil.h
68 08 Mar 09 GKY Additional strings move to PCSZs
69 08 Mar 09 GKY Removed variable aurguments from docopyf and unlinkf (not used)
70 14 Mar 09 GKY Prevent execution of UM_SHOWME while drive scan is occuring
71 06 Jun 09 GKY Add option to show file system type or drive label in tree
72 28 Jun 09 GKY Added AddBackslashToPath() to remove repeatative code.
73 06 Jul 09 SHL Refactor .LONGNAME and .SUBJECT EA fetch to FetchCommonEAs
74 12 Jul 09 GKY Add szFSType to FillInRecordFromFSA use to bypass EA scan and size formatting
75 for tree container
76 13 Jul 09 SHL Avoid trap in FillInRecordFromFSA if pszFSType NULL
77 22 Jul 09 GKY Code changes to use semaphores to serialize drive scanning
78 22 Jul 09 GKY Consolidated driveflag setting code in DriveFlagsOne
79 22 Jul 09 GKY Streamline scanning code for faster Tree rescans
80 15 Sep 09 SHL Show rescan progress while filling container
81 26 Sep 09 SHL Add FreeCnrItemData debug code - do not let into the wild
82 13 Oct 09 SHL Avoid szDriver overflow in FillTreeCnr
83 13 Oct 09 SHL Restore missing drives in drive drop-down listbox; optimize updates
84 15 Nov 09 GKY Avoid szBuf overflow in FillTreeCnr
85 15 Nov 09 GKY Optimize some check code
86 17 JAN 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10).
87 Mostly cast CHAR CONSTANT * as CHAR *.
88 09 MAY 10 JBS Ticket 434 bug fixes, message box text improvements and parameter update
89 improvements.
90 20 Nov 10 GKY Rework scanning code to remove redundant scans, prevent double directory
91 entries in the tree container, fix related semaphore performance using
92 combination of event and mutex semaphores
93 30 May 11 GKY Fixed trap caused by passing a nonexistant pci to FillInRecordFromFFB in FillDir
94 because pci is limited to 65535 files. (nRecord is a USHORT) SHL's single loop
95 30 May 11 GKY Added SleepIfNeeded to DosFind and container load loops to improve WPS responsiveness
96 31 May 11 SHL Disable antique debug code in RemoveCnrItems - really speeds up container close
97 12 Jun 11 GKY Added IdleIfNeeded to the container "free" loops to improve system
98 responsiveness when closing containers with large numbers of items
99 12 Jun 11 GKY Replaced SleepIfNeeded with IdleIfNeeded in the container loade loop
100 22 Oct 11 GKY Removing unneeded UnFlesh call from StubbyScanThread appears to significantly speed opening of FM/2
101
102***********************************************************************/
103
104#include <stdlib.h>
105#include <string.h>
106#include <malloc.h> // _msize _heapchk
107#include <ctype.h>
108#include <limits.h>
109// #include <process.h> // _beginthread
110
111#define INCL_DOS
112#define INCL_WIN
113#define INCL_DOSERRORS
114#define INCL_LONGLONG
115
116#include "fm3dll.h"
117#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
118#include "draglist.h" // Data declaration(s)
119#include "treecnr.h" // Data declaration(s)
120#include "info.h" // Data declaration(s)
121#include "newview.h" // Data declaration(s)
122#include "mainwnd.h" // hwndDrivelist
123#include "fm3str.h"
124#include "filldir.h"
125#include "errutil.h" // Dos_Error...
126#include "strutil.h" // GetPString
127#include "misc.h" // GetTidForWindow
128#include "fortify.h" // 06 May 08 SHL
129#include "notebook.h" // INI file fields
130#include "flesh.h" // FleshEnv, Stubby
131#include "update.h" // SelectDriveIcon
132#include "valid.h" // CheckDrive
133#include "filter.h" // Filter
134#include "subj.h" // Subject
135#include "grep.h" // hwndStatus
136#include "copyf.h" // unlinkf
137#include "literal.h" // wildcard
138#include "i18nutil.h" // CommaFmtULL
139#include "wrappers.h" // xDosFindNext
140#include "init.h" // GetTidForWindow
141#include "common.h" // IncrThreadUsage
142#include "excputil.h" // xbeginthread
143#include "fm3dlg.h" // INFO_LABEL
144#include "pathutil.h" // AddBackslashToPath
145#include "tmrsvcs.h" // ITIMER_DESC
146
147VOID StubbyScanThread(VOID * arg);
148
149// Data definitions
150static PSZ pszSrcFile = __FILE__;
151static BOOL fFirstTime;
152INT FixedVolume = 0;
153
154#pragma data_seg(GLOBAL1)
155HPOINTER hptrEnv;
156HPOINTER hptrHidden;
157HPOINTER hptrReadonly;
158HPOINTER hptrSystem;
159
160#pragma data_seg(GLOBAL2)
161PCSZ FM3Tools = "<FM3_Tools>";
162PCSZ WPProgram = "WPProgram";
163
164typedef struct {
165 PCNRITEM pci;
166 HWND hwndCnr; // hwnd you want the message posted to
167}
168STUBBYSCAN;
169
170/**
171 * Return display string given standard file attribute mask
172 * @param fileAttr attribute mask in FILEFINDBUF format
173 * @return fixed length string for display
174 */
175
176const PSZ FileAttrToString(ULONG fileAttr)
177{
178 // From os2win.h
179 // FILE_ATTRIBUTE_READONLY 0x00000001
180 // FILE_ATTRIBUTE_HIDDEN 0x00000002
181 // FILE_ATTRIBUTE_SYSTEM 0x00000004
182 // 0x00000008
183 // FILE_ATTRIBUTE_DIRECTORY 0x00000010
184 // FILE_ATTRIBUTE_ARCHIVE 0x00000020
185
186 static CHAR *apszAttrString[] = {
187 // RHSDA
188 "-----",
189 "R----",
190 "-H---",
191 "RH---",
192 "--S--",
193 "R-S--",
194 "-HS--",
195 "RHS--",
196 "---D-",
197 "R--D-",
198 "-H-D-",
199 "RH-D-",
200 "--SD-",
201 "R-SD-",
202 "-HSD-",
203 "RHSD-",
204 "----A",
205 "R---A",
206 "-H--A",
207 "RH--A",
208 "--S-A",
209 "R-S-A",
210 "-HS-A",
211 "RHS-A",
212 "---DA",
213 "R--DA",
214 "-H-DA",
215 "RH-DA",
216 "--SDA",
217 "R-SDA",
218 "-HSDA",
219 "RHSDA"
220 };
221
222 fileAttr = ((fileAttr & 0x30) >> 1) | (fileAttr & 7); // Drop don't care bit from index
223
224 return apszAttrString[fileAttr];
225
226}
227
228VOID StubbyScanThread(VOID * arg)
229{
230 STUBBYSCAN *StubbyScan;
231 HAB thab;
232 HMQ hmq = (HMQ) 0;
233 //BOOL ok;
234 static INT ProcessDirCount = 0;
235
236 DosError(FERR_DISABLEHARDERR);
237
238# ifdef FORTIFY
239 Fortify_EnterScope();
240# endif
241
242 StubbyScan = (STUBBYSCAN *)arg;
243 if (StubbyScan && StubbyScan->pci && StubbyScan->pci->pszFileName && StubbyScan->hwndCnr) {
244 thab = WinInitialize(0);
245 if (thab) {
246 hmq = WinCreateMsgQueue(thab, 0);
247 if (hmq) {
248 IncrThreadUsage();
249 priority_normal();
250 if (WinIsWindow((HAB)0, StubbyScan->hwndCnr)) {
251 ULONG flags = driveflags[toupper(*StubbyScan->pci->pszFileName) - 'A'];
252
253 if ((fRScanLocal && ~flags & DRIVE_REMOTE && ~flags & DRIVE_VIRTUAL) ||
254 (fRScanRemote && flags & DRIVE_REMOTE) ||
255 (fRScanVirtual && flags & DRIVE_VIRTUAL)) {
256 if (!(flags & ((fRScanNoWrite ? 0 : DRIVE_NOTWRITEABLE) ||
257 (fRScanSlow ? 0 : DRIVE_SLOW)))) {
258 Flesh(StubbyScan->hwndCnr, StubbyScan->pci);
259 }
260 else {
261 Stubby(StubbyScan->hwndCnr, StubbyScan->pci);
262 }
263 }
264 else {
265 Stubby(StubbyScan->hwndCnr, StubbyScan->pci);
266 }
267 }
268 WinDestroyMsgQueue(hmq);
269 }
270 DecrThreadUsage();
271 WinTerminate(thab);
272 }
273 free(StubbyScan);
274 } // if StubbyScan
275 ProcessDirCount++;
276 // DbgMsg(pszSrcFile, __LINE__, "ProcessDirCount %i FixedVolume %i", ProcessDirCount, FixedVolume);
277 if (ProcessDirCount >= FixedVolume) {
278 DosReleaseMutexSem(hmtxScanning);
279 DosPostEventSem(hevTreeCnrScanComplete);
280 if (fInitialDriveScan && fSwitchTree && hwndTree && fSaveState && pszFocusDir) {
281 // Keep drive tree in sync with directory container
282 if (!PostMsg(hwndTree, UM_SHOWME, MPFROMP(pszFocusDir), MPVOID))
283 free(pszFocusDir);
284 }
285 ProcessDirCount = 0;
286 FixedVolume = 0;
287 fInitialDriveScan = FALSE;
288 }
289# ifdef FORTIFY
290 Fortify_LeaveScope();
291# endif
292
293}
294
295static HPOINTER IDFile(PSZ p)
296{
297 HPOINTER hptr;
298 ULONG cmp;
299 CHAR cmps[5];
300
301 p = strrchr(p, '.');
302 if (p) {
303 cmps[0] = '.';
304 cmps[1] = toupper(p[1]);
305 cmps[2] = toupper(p[2]);
306 cmps[3] = toupper(p[3]);
307 if (p[4]) {
308 cmps[4] = toupper(p[4]);
309 cmps[5] = 0;
310 }
311 else
312 cmps[4] = 0;
313
314 cmp = *(ULONG *) cmps;
315
316 if (cmp == *(ULONG *) PCSZ_DOTEXE || cmp == *(ULONG *) PCSZ_DOTCMD ||
317 cmp == *(ULONG *) PCSZ_DOTBAT || cmp == *(ULONG *) PCSZ_DOTCOM ||
318 cmp == *(ULONG *) PCSZ_DOTBTM)
319 hptr = hptrApp;
320 else if (cmp == *(ULONG *) ".ZIP" || cmp == *(ULONG *) ".LZH" ||
321 cmp == *(ULONG *) ".ARJ" || cmp == *(ULONG *) ".ARC" ||
322 cmp == *(ULONG *) ".ZOO" || cmp == *(ULONG *) ".RAR" ||
323 cmp == *(ULONG *) ".TAR" || cmp == *(ULONG *) ".TGZ" ||
324 cmp == *(ULONG *) ".GZ" || cmp == *(ULONG *) ".Z" ||
325 cmp == *(ULONG *) ".CAB" || cmp == *(ULONG *) ".BZ2" ||
326 cmp == *(ULONG *) ".WPI")
327 hptr = hptrArc;
328 else if (cmp == *(ULONG *) PCSZ_DOTBMP ||
329 cmp == *(ULONG *) PCSZ_DOTICO ||
330 cmp == *(ULONG *) PCSZ_DOTPTR ||
331 cmp == *(ULONG *) PCSZ_DOTJPEG ||
332 cmp == *(ULONG *) PCSZ_DOTJPG ||
333 cmp == *(ULONG *) ".GIF" ||
334 cmp == *(ULONG *) ".TIF" || cmp == *(ULONG *) ".PCX" ||
335 cmp == *(ULONG *) ".TGA" || cmp == *(ULONG *) ".XBM" ||
336 cmp == *(ULONG *) ".PNG" || cmp == *(ULONG *) ".PSD" ||
337 cmp == *(ULONG *) ".LGO" || cmp == *(ULONG *) ".EPS" ||
338 cmp == *(ULONG *) ".RLE" || cmp == *(ULONG *) ".RAS" ||
339 cmp == *(ULONG *) ".PLC" || cmp == *(ULONG *) ".MSP" ||
340 cmp == *(ULONG *) ".IFF" || cmp == *(ULONG *) ".FIT" ||
341 cmp == *(ULONG *) ".DCX" || cmp == *(ULONG *) ".MAC" ||
342 cmp == *(ULONG *) ".SFF" || cmp == *(ULONG *) ".SGI" ||
343 cmp == *(ULONG *) ".XWD" || cmp == *(ULONG *) ".XPM" ||
344 cmp == *(ULONG *) ".WPG" || cmp == *(ULONG *) ".CUR" ||
345 cmp == *(ULONG *) ".PNM" || cmp == *(ULONG *) ".PPM" ||
346 cmp == *(ULONG *) ".PGM" || cmp == *(ULONG *) ".PBM")
347 hptr = hptrArt;
348 else
349 hptr = (HPOINTER) 0;
350 }
351 else
352 hptr = (HPOINTER) 0;
353
354 return hptr;
355}
356
357static BOOL IsDefaultIcon(HPOINTER hptr)
358{
359 HPOINTER hptr2;
360 HPOINTER hptr3;
361 UINT u;
362
363 static HPOINTER hptrPMFile;
364 static HPOINTER hptrWPSFile;
365
366 if (!hptrPMFile) {
367 hptrPMFile = WinQuerySysPointer(HWND_DESKTOP, SPTR_FILE, FALSE);
368 }
369
370 // try to guess WPS default file icon
371 hptr2 = (HPOINTER) 0;
372 for (u = 0; !hptrWPSFile && u < 10; u++) {
373 char szFileName[CCHMAXPATH];
374 char *psz;
375
376 if (pTmpDir) {
377 psz = pTmpDir;
378 strcpy(szFileName, psz);
379 psz = szFileName + strlen(szFileName) - 1;
380 if (*psz != '\\') {
381 psz++;
382 *psz++ = '\\';
383 }
384 }
385 else
386 psz = szFileName;
387
388 sprintf(psz, "%08x.%03x", rand() & 0xffffffff, rand() & 0xfff);
389 if (IsFile(szFileName) != 1) {
390 FILE *fp;
391 CHAR *modew = "w";
392
393 fp = xfopen(szFileName, modew, pszSrcFile, __LINE__, TRUE);
394
395 if (fp) {
396 fclose(fp);
397 hptr3 = WinLoadFileIcon(szFileName, FALSE);
398 unlinkf(szFileName);
399 if (!hptr2)
400 hptr2 = hptr3;
401 else if (hptr3 == hptr3) {
402 hptrWPSFile = hptr3; // Got same icon twice
403 break;
404 }
405 }
406 }
407 DosSleep(rand() % 100);
408
409 } // for
410
411 return hptr == hptrPMFile || hptr == hptrWPSFile;
412
413} // IsDefaultIcon
414
415static VOID FetchCommonEAs(PCNRITEM pci)
416{
417 ULONG flags = driveflags[toupper(*pci->pszFileName) - 'A'];
418 BOOL fLoadSubjectForDrive = fLoadSubject && ~flags & DRIVE_NOLOADSUBJS;
419 BOOL fLoadLongNameForDrive = fLoadLongnames && //~flags & DRIVE_NOLONGNAMES &&
420 ~flags & DRIVE_NOLOADLONGS;
421 if (fLoadSubjectForDrive || fLoadLongNameForDrive) {
422 // Allocate space to hold GEA2s and .SUBJECT and .LONGNAME strings
423 PGEA2LIST pgealist = xmallocz(sizeof(GEA2LIST) + sizeof(GEA2) + 64, pszSrcFile, __LINE__);
424 if (pgealist) {
425 APIRET rc;
426 PFEA2LIST pfealist;
427 ULONG offset;
428 PGEA2 pgeaPrev = NULL;
429 PGEA2 pgea = pgealist->list; // Point at first available
430 EAOP2 eaop;
431 UINT state;
432 //DbgMsg(pszSrcFile, __LINE__, "pszFileName %s", pci->pszFileName);
433 for (state = 0; state < 2; state++) {
434 PCSZ pcsz;
435 switch (state) {
436 case 0:
437 pcsz = fLoadSubjectForDrive ? SUBJECT : NULL;
438 break;
439 case 1:
440 pcsz = fLoadLongNameForDrive ? LONGNAME : NULL;
441 break;
442 }
443 if (pcsz) {
444 if (pgeaPrev) {
445 pgeaPrev->oNextEntryOffset = (PSZ)pgea - (PSZ)pgeaPrev;
446 //DbgMsg(pszSrcFile, __LINE__, "pgea %p oNextEntryOffset %u", pgeaPrev, pgeaPrev->oNextEntryOffset);
447 }
448 strcpy(pgea->szName, pcsz);
449 pgea->cbName = strlen(pgea->szName);
450 pgea->oNextEntryOffset = 0;
451 //DbgMsg(pszSrcFile, __LINE__, "pgea %p cbName %u szName %s", pgea, pgea->cbName, pgea->szName);
452 offset = sizeof(GEA2) + pgea->cbName; // Calc length including null
453 offset = (offset + 3) & ~3; // Doubleword align
454 pgeaPrev = pgea;
455 pgea = (PGEA2)((PSZ)pgea + offset); // Point at next available
456 }
457 } // for
458
459 pgealist->cbList = (PSZ)pgea - (PSZ)pgealist;
460 //DbgMsg(pszSrcFile, __LINE__, "pgealist %p cbList %u", pgealist, pgealist->cbList);
461
462 pfealist = xmallocz(4096, pszSrcFile, __LINE__);
463 if (pfealist) {
464 pfealist->cbList = 4096;
465 eaop.fpGEA2List = pgealist;
466 eaop.fpFEA2List = pfealist;
467 eaop.oError = 0;
468 rc = DosQueryPathInfo(pci->pszFileName, FIL_QUERYEASFROMLIST,
469 (PVOID) &eaop, (ULONG) sizeof(EAOP2));
470 // Prevent this error from occuring when scanning a directory
471 // that contains a locked data file
472 if (rc && rc != ERROR_SHARING_VIOLATION) {
473 CHAR s[80];
474 sprintf(s, "%s %s",PCSZ_DOSQUERYPATHINFO, "%s");
475 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
476 s, pci->pszFileName);
477 }
478 //DbgMsg(pszSrcFile, __LINE__, "DosQueryPathInfo %s failed with rc %u ", pci->pszFileName, rc);
479 else {
480 PFEA2 pfea = eaop.fpFEA2List->list;
481 while (pfea) {
482 if (pfea->cbValue) {
483 CHAR *achValue = pfea->szName + pfea->cbName + 1;
484 if (*(USHORT *)achValue != EAT_ASCII)
485 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
486 GetPString(IDS_ERROREATYPETEXT),
487 achValue, pfea->cbName, pfea->szName);
488 //DbgMsg(pszSrcFile, __LINE__, "EA type 0x%x unexpected for %.*s", achValue, pfea->cbName, pfea->szName);
489 else {
490 CHAR ch = achValue[pfea->cbValue];
491 PSZ pszValue;
492 achValue[pfea->cbValue] = 0;
493 pszValue = xstrdup(achValue + (sizeof(USHORT) * 2), pszSrcFile, __LINE__);
494 achValue[pfea->cbValue] = ch;
495 //DbgMsg(pszSrcFile, __LINE__, "pfea %p %.*s cbValue %u %s", pfea, pfea->cbName, pfea->szName, pfea->cbValue, pszValue);
496 if (strncmp(pfea->szName, LONGNAME, pfea->cbName) == 0)
497 pci->pszLongName = pszValue;
498 else if (strncmp(pfea->szName, SUBJECT, pfea->cbName) == 0)
499 pci->pszSubject = pszValue;
500 else
501 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
502 GetPString(IDS_ERROREATYPETEXT), pfea, pfea->cbName, pfea->szName);
503 //DbgMsg(pszSrcFile, __LINE__, "pfea %p EA %.*s unexpected", pfea, pfea->cbName, pfea->szName);
504 }
505 }
506 if (!pfea->oNextEntryOffset)
507 break;
508 pfea = (PFEA2)((PSZ)pfea + pfea->oNextEntryOffset);
509 } // while
510 }
511 free(pfealist);
512 }
513 free(pgealist);
514 }
515 }
516} // FetchCommonEAs
517
518ULONGLONG FillInRecordFromFFB(HWND hwndCnr,
519 PCNRITEM pci,
520 const PSZ pszDirectory,
521 const PFILEFINDBUF4L pffb,
522 const BOOL partial,
523 DIRCNRDATA *dcd)
524{
525 // fill in a container record from a FILEFINDBUF4L structure
526
527 CHAR *p;
528 HPOINTER hptr;
529 ULONG flags;
530
531 pci->hwndCnr = hwndCnr;
532
533 /* note that we cheat below, and accept the full pathname in pszDirectory
534 if !*pffb->achName. This speeds up and simplifies processing elsewhere
535 (like in update.c)
536 */
537 if (!*pffb->achName) {
538 pci->pszFileName = xstrdup(pszDirectory, pszSrcFile, __LINE__);
539 }
540 else {
541 INT c = strlen(pszDirectory);
542 INT c2 = pffb->cchName + 1;
543 if (pszDirectory[c - 1] != '\\')
544 c2++;
545 pci->pszFileName = xmalloc(c + c2, pszSrcFile, __LINE__);
546# ifdef FORTIFY
547 {
548 if (dcd->type != TREE_FRAME)
549 Fortify_ChangeScope(pci->pszFileName, -1);
550 else {
551 Fortify_SetOwner(pci->pszFileName, 1);
552 Fortify_SetScope(pci->pszFileName, 2);
553 }
554 }
555# endif
556 memcpy(pci->pszFileName, pszDirectory, c + 1);
557 p = pci->pszFileName + c - 1;
558 if (*p != '\\') {
559 p++;
560 *p = '\\';
561 }
562 p++;
563 memcpy(p, pffb->achName, pffb->cchName + 1);
564 }
565
566 // load Subject and/or Longname EAs, if required and have EAs
567 if (pffb->cbList > 4L && dcd &&
568 !(driveflags[toupper(*pci->pszFileName) - 'A'] & DRIVE_NOEASUPPORT))
569 FetchCommonEAs(pci);
570
571 if (!pci->pszSubject)
572 pci->pszSubject = NullStr;
573
574 // load the object's longname
575 if (!pci->pszLongName)
576 pci->pszLongName = NullStr;
577
578 // do anything required to case of filename
579 if (fForceUpper)
580 strupr(pci->pszFileName);
581 else if (fForceLower)
582 strlwr(pci->pszFileName);
583
584 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
585
586 // get an icon to use with it
587 if (pffb->attrFile & FILE_DIRECTORY) {
588 // is directory
589 if (fNoIconsDirs ||
590 (flags & DRIVE_NOLOADICONS) ||
591 !isalpha(*pci->pszFileName)) {
592 hptr = (HPOINTER) 0;
593 }
594 else
595 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
596 }
597 else {
598 // is file
599 if (fNoIconsFiles ||
600 (flags & DRIVE_NOLOADICONS) ||
601 !isalpha(*pci->pszFileName)) {
602 hptr = (HPOINTER) 0;
603 }
604 else
605 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
606
607 if (!hptr || IsDefaultIcon(hptr))
608 hptr = IDFile(pci->pszFileName);
609 }
610
611 if (!hptr) {
612 hptr = pffb->attrFile & FILE_DIRECTORY ?
613 hptrDir : pffb->attrFile & FILE_SYSTEM ?
614 hptrSystem : pffb->attrFile & FILE_HIDDEN ?
615 hptrHidden : pffb->attrFile & FILE_READONLY ?
616 hptrReadonly : hptrFile;
617 }
618
619 // Tell container what part of pathname to display
620 if (partial) {
621 p = strrchr(pci->pszFileName, '\\');
622 if (!p) {
623 p = strrchr(pci->pszFileName, ':');
624 if (!p)
625 p = pci->pszFileName;
626 else
627 p++;
628 }
629 else if ((dcd && dcd->type == TREE_FRAME) ||
630 (!(pffb->attrFile & FILE_DIRECTORY) || !*(p + 1))) {
631 p++;
632 }
633 if (!*p)
634 p = pci->pszFileName;
635 }
636 else
637 p = pci->pszFileName;
638 pci->pszDisplayName = p;
639
640 //comma format the file size for large file support
641 {
642 CHAR szBuf[30];
643 CommaFmtULL(szBuf, sizeof(szBuf), pffb->cbFile, ' ');
644 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
645# ifdef FORTIFY
646 {
647 unsigned tid = GetTidForWindow(hwndCnr);
648 if (tid == 1)
649 Fortify_ChangeScope(pci->pszFmtFileSize, -1);
650 else
651 Fortify_SetOwner(pci->pszFmtFileSize, 1);
652 }
653# endif
654 }
655
656 // now fill the darned thing in...
657 pci->date.day = pffb->fdateLastWrite.day;
658 pci->date.month = pffb->fdateLastWrite.month;
659 pci->date.year = pffb->fdateLastWrite.year + 1980;
660 pci->time.seconds = pffb->ftimeLastWrite.twosecs * 2;
661 pci->time.minutes = pffb->ftimeLastWrite.minutes;
662 pci->time.hours = pffb->ftimeLastWrite.hours;
663 pci->ladate.day = pffb->fdateLastAccess.day;
664 pci->ladate.month = pffb->fdateLastAccess.month;
665 pci->ladate.year = pffb->fdateLastAccess.year + 1980;
666 pci->latime.seconds = pffb->ftimeLastAccess.twosecs * 2;
667 pci->latime.minutes = pffb->ftimeLastAccess.minutes;
668 pci->latime.hours = pffb->ftimeLastAccess.hours;
669 pci->crdate.day = pffb->fdateCreation.day;
670 pci->crdate.month = pffb->fdateCreation.month;
671 pci->crdate.year = pffb->fdateCreation.year + 1980;
672 pci->crtime.seconds = pffb->ftimeCreation.twosecs * 2;
673 pci->crtime.minutes = pffb->ftimeCreation.minutes;
674 pci->crtime.hours = pffb->ftimeCreation.hours;
675 pci->easize = CBLIST_TO_EASIZE(pffb->cbList);
676 pci->cbFile = pffb->cbFile;
677 pci->attrFile = pffb->attrFile;
678 pci->pszDispAttr = FileAttrToString(pci->attrFile);
679 pci->rc.pszIcon = pci->pszDisplayName;
680 pci->rc.hptrIcon = hptr;
681
682 // check to see if record should be visible
683 if (dcd && (*dcd->mask.szMask || dcd->mask.antiattr ||
684 ((dcd->mask.attrFile &
685 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED))
686 !=
687 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED))))
688 {
689 if (*dcd->mask.szMask || dcd->mask.antiattr) {
690 if (!Filter((PMINIRECORDCORE) pci, (PVOID) & dcd->mask))
691 pci->rc.flRecordAttr |= CRA_FILTERED;
692 }
693 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
694 (pci->attrFile & FILE_HIDDEN)) ||
695 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
696 (pci->attrFile & FILE_SYSTEM)) ||
697 (!(dcd->mask.attrFile & FILE_READONLY) &&
698 (pci->attrFile & FILE_READONLY)) ||
699 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
700 (pci->attrFile & FILE_ARCHIVED))) {
701 pci->rc.flRecordAttr |= CRA_FILTERED;
702 }
703 }
704
705 return pffb->cbFile + pci->easize;
706
707} // FillInRecordFromFFB
708
709ULONGLONG FillInRecordFromFSA(HWND hwndCnr,
710 PCNRITEM pci,
711 const PSZ pszFileName,
712 const PFILESTATUS4L pfsa4,
713 const BOOL partial,
714 CHAR *pszFSType, // Optional
715 DIRCNRDATA *dcd) // Optional
716{
717 HPOINTER hptr;
718 ULONG flags;
719 CHAR *p;
720 CHAR szBuf[CCHMAXPATH];
721
722 // fill in a container record from a FILESTATUS4L structure
723
724 pci->hwndCnr = hwndCnr;
725 pci->pszFileName = xstrdup(pszFileName, pszSrcFile, __LINE__);
726
727 // 13 Jul 09 SHL fixme to know if fetch can be bypassed if pszFSType already filled
728 // If FSType not supplied, assume don't need EAs either
729 if (pfsa4->cbList > 4L && dcd &&
730 !(driveflags[toupper(*pci->pszFileName) - 'A'] & DRIVE_NOEASUPPORT))
731 FetchCommonEAs(pci);
732
733 if (!pci->pszSubject)
734 pci->pszSubject = NullStr;
735 if (!pci->pszLongName)
736 pci->pszLongName = NullStr;
737
738 if (fForceUpper)
739 strupr(pci->pszFileName);
740 else if (fForceLower)
741 strlwr(pci->pszFileName);
742
743 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
744
745 if (pfsa4->attrFile & FILE_DIRECTORY) {
746 if (fNoIconsDirs ||
747 (flags & DRIVE_NOLOADICONS) ||
748 !isalpha(*pci->pszFileName)) {
749 hptr = (HPOINTER) 0;
750 }
751 else
752 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
753 }
754 else {
755 if (fNoIconsFiles ||
756 (flags & DRIVE_NOLOADICONS) ||
757 !isalpha(*pci->pszFileName)) {
758 hptr = IDFile(pci->pszFileName);
759 }
760 else
761 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
762 }
763 if (!hptr) {
764 hptr = pfsa4->attrFile & FILE_DIRECTORY ?
765 hptrDir :
766 pfsa4->attrFile & FILE_SYSTEM ?
767 hptrSystem :
768 pfsa4->attrFile & FILE_HIDDEN ?
769 hptrHidden : pfsa4->attrFile & FILE_READONLY ? hptrReadonly : hptrFile;
770 }
771
772 // Tell container what part of pathname to display
773 if (partial) {
774 p = strrchr(pci->pszFileName, '\\');
775 if (!p) {
776 p = strrchr(pci->pszFileName, ':');
777 if (!p)
778 p = pci->pszFileName;
779 else
780 p++;
781 }
782 else if ((dcd && dcd->type == TREE_FRAME) ||
783 !(pfsa4->attrFile & FILE_DIRECTORY) || !*(p + 1))
784 p++;
785 if (!*p)
786 p = pci->pszFileName;
787 }
788 else
789 p = pci->pszFileName;
790 if (pszFSType && (fShowFSTypeInTree || fShowDriveLabelInTree)) {
791 strcpy(szBuf, p);
792 strcat(szBuf, " [");
793 strcat(szBuf, pszFSType);
794 strcat(szBuf, "]");
795 pci->pszDisplayName = xstrdup(szBuf, pszSrcFile, __LINE__);
796 }
797 else
798 pci->pszDisplayName = p;
799
800 // 13 Jul 09 SHL fixme to know why pszFSType check needed
801 // comma format the file size for large file support
802 if (!pszFSType || *pszFSType == 0) {
803 CHAR szBuf[30];
804 CommaFmtULL(szBuf, sizeof(szBuf), pfsa4->cbFile, ' ');
805 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
806# ifdef FORTIFY
807 {
808 if (dcd && dcd->type == TREE_FRAME) {
809 // Will be freed in TreeCnrWndProc WM_DESTROY
810 // Fortify_SetOwner(pci->pszFmtFileSize, 1);
811 Fortify_SetScope(pci->pszFmtFileSize, 2);
812 }
813 }
814# endif
815 }
816 else {
817 pci->pszFmtFileSize = NullStr;
818 //DbgMsg(pszSrcFile, __LINE__, "Bypassed Format size %s", pci->pszDisplayName);
819 }
820 pci->date.day = pfsa4->fdateLastWrite.day;
821 pci->date.month = pfsa4->fdateLastWrite.month;
822 pci->date.year = pfsa4->fdateLastWrite.year + 1980;
823 pci->time.seconds = pfsa4->ftimeLastWrite.twosecs * 2;
824 pci->time.minutes = pfsa4->ftimeLastWrite.minutes;
825 pci->time.hours = pfsa4->ftimeLastWrite.hours;
826 pci->ladate.day = pfsa4->fdateLastAccess.day;
827 pci->ladate.month = pfsa4->fdateLastAccess.month;
828 pci->ladate.year = pfsa4->fdateLastAccess.year + 1980;
829 pci->latime.seconds = pfsa4->ftimeLastAccess.twosecs * 2;
830 pci->latime.minutes = pfsa4->ftimeLastAccess.minutes;
831 pci->latime.hours = pfsa4->ftimeLastAccess.hours;
832 pci->crdate.day = pfsa4->fdateCreation.day;
833 pci->crdate.month = pfsa4->fdateCreation.month;
834 pci->crdate.year = pfsa4->fdateCreation.year + 1980;
835 pci->crtime.seconds = pfsa4->ftimeCreation.twosecs * 2;
836 pci->crtime.minutes = pfsa4->ftimeCreation.minutes;
837 pci->crtime.hours = pfsa4->ftimeCreation.hours;
838 pci->easize = CBLIST_TO_EASIZE(pfsa4->cbList);
839 pci->cbFile = pfsa4->cbFile;
840 pci->attrFile = pfsa4->attrFile;
841 pci->pszDispAttr = FileAttrToString(pci->attrFile);
842 pci->rc.pszIcon = pci->pszDisplayName;
843 pci->rc.hptrIcon = hptr;
844
845 if (dcd &&
846 (*dcd->mask.szMask || dcd->mask.antiattr ||
847 ((dcd->mask.attrFile &
848 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)) !=
849 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)))) {
850 if (*dcd->mask.szMask || dcd->mask.antiattr) {
851 if (!Filter((PMINIRECORDCORE) pci, (PVOID) & dcd->mask))
852 pci->rc.flRecordAttr |= CRA_FILTERED;
853 }
854 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
855 (pci->attrFile & FILE_HIDDEN)) ||
856 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
857 (pci->attrFile & FILE_SYSTEM)) ||
858 (!(dcd->mask.attrFile & FILE_READONLY) &&
859 (pci->attrFile & FILE_READONLY)) ||
860 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
861 (pci->attrFile & FILE_ARCHIVED)))
862 pci->rc.flRecordAttr |= CRA_FILTERED;
863 }
864
865 return pfsa4->cbFile + pci->easize;
866
867} // FillInRecordFromFSA
868
869VOID ProcessDirectory(const HWND hwndCnr,
870 const PCNRITEM pciParent,
871 const CHAR *szDirBase,
872 const BOOL filestoo,
873 const BOOL recurse,
874 const BOOL partial,
875 CHAR *stopflag,
876 DIRCNRDATA *dcd, // Optional
877 ULONG *pulTotalFiles, // Optional
878 PULONGLONG pullTotalBytes) // Optional
879{
880 /* put all the directories (and files if filestoo is TRUE) from a
881 * directory into the container. recurse through subdirectories if
882 * recurse is TRUE.
883 */
884
885 PSZ pszFileSpec;
886 PFILEFINDBUF4L paffbFound;
887 PFILEFINDBUF4L *papffbSelected;
888 PFILEFINDBUF4L pffbFile;
889 PFILEFINDBUF4L paffbTotal = NULL;
890 PFILEFINDBUF4L paffbTemp;
891 HDIR hdir = HDIR_CREATE;
892 ULONG ulFindCnt;
893 ULONG ulFindMax;
894 ULONG ulSelCnt;
895 ULONG cAffbTotal = 0;
896 ULONGLONG ullBytes;
897 ULONGLONG ullTotalBytes;
898 ULONG ulReturnFiles = 0;
899 ULONGLONG ullReturnBytes = 0;
900 APIRET rc;
901 PCNRITEM pci;
902 PCNRITEM pciFirst;
903 RECORDINSERT ri;
904 BOOL ok = TRUE;
905 ULONG ulBufBytes;
906 ULONG x;
907 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
908
909 if (isalpha(*szDirBase) && szDirBase[1] == ':' && szDirBase[2] == '\\') {
910 if ((driveflags[toupper(*szDirBase) - 'A'] & DRIVE_REMOTE) && fRemoteBug)
911 ulFindMax = 1; // file system gets confused
912 else if (driveflags[toupper(*szDirBase) - 'A'] & DRIVE_ZIPSTREAM)
913 ulFindMax = min(FilesToGet, 225); // anything more is wasted
914 else
915 ulFindMax = FilesToGet; // full-out
916 }
917 else
918 ulFindMax = FilesToGet;
919
920 if (OS2ver[0] == 20 && OS2ver[1] < 30)
921 ulFindMax = min(ulFindMax, (65535 / sizeof(FILEFINDBUF4L)));
922
923 ulBufBytes = ulFindMax * sizeof(FILEFINDBUF4L);
924
925 pszFileSpec = xmalloc(CCHMAXPATH + 2, pszSrcFile, __LINE__);
926 paffbFound = xmalloc(ulBufBytes, pszSrcFile, __LINE__);
927 papffbSelected = xmalloc(sizeof(PFILEFINDBUF4L) * ulFindMax, pszSrcFile, __LINE__);
928
929 if (paffbFound && papffbSelected && pszFileSpec) {
930 strcpy(pszFileSpec, szDirBase);
931 AddBackslashToPath(pszFileSpec);
932 strcat(pszFileSpec, "*");
933 DosError(FERR_DISABLEHARDERR);
934 ulFindCnt = ulFindMax;
935 rc = xDosFindFirst(pszFileSpec,
936 &hdir,
937 FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
938 FILE_SYSTEM | FILE_HIDDEN |
939 (filestoo ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY),
940 paffbFound,
941 ulBufBytes,
942 &ulFindCnt,
943 FIL_QUERYEASIZEL);
944 priority_normal();
945 pszFileSpec[strlen(pszFileSpec) - 1] = 0; // Chop off wildcard
946 if (!rc) {
947 InitITimer(&itdSleep, 500);
948 do {
949 /*
950 * remove . and .. from list if present
951 * also counter file system bugs that sometimes
952 * allows normal files to slip through when
953 * only directories should appear (only a few
954 * network file systems exhibit such a problem).
955 */
956
957 if (stopflag && *stopflag)
958 goto Abort;
959 pffbFile = paffbFound;
960 ulSelCnt = 0;
961 for (;;) {
962 if (!*pffbFile->achName ||
963 (!filestoo && ~pffbFile->attrFile & FILE_DIRECTORY) ||
964 (pffbFile->attrFile & FILE_DIRECTORY &&
965 pffbFile->achName[0] == '.' &&
966 (!pffbFile->achName[1] ||
967 (pffbFile->achName[1] == '.' && !pffbFile->achName[2])))) {
968 // ulFindCnt--; // Got . or .. or file to be skipped
969 }
970 else
971 papffbSelected[ulSelCnt++] = pffbFile; // Remember selected file
972 if (!pffbFile->oNextEntryOffset) {
973 // ulFindCnt = ulSelCnt; // Remember number selected
974 break;
975 }
976 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + pffbFile->oNextEntryOffset);
977 } // for
978 if (ulSelCnt) {
979 // One or more entries selected
980 if (stopflag && *stopflag)
981 goto Abort;
982 if (fSyncUpdates) {
983 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
984 MPFROMLONG(EXTRA_RECORD_BYTES),
985 MPFROMLONG(ulSelCnt));
986 if (!pciFirst) {
987 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
988 GetPString(IDS_CMALLOCRECERRTEXT));
989 ok = FALSE;
990 ullTotalBytes = 0;
991 }
992 else {
993 // 04 Jan 08 SHL fixme like comp.c to handle less than ulSelCnt records
994 pci = pciFirst;
995 ullTotalBytes = 0;
996 // Finish filling pci items
997 for (x = 0; x < ulSelCnt; x++) {
998 pffbFile = papffbSelected[x];
999 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1000 pffbFile, partial, dcd);
1001 pci = (PCNRITEM) pci->rc.preccNextRecord;
1002 ullTotalBytes += ullBytes;
1003 } // for
1004 // Insert selected in container
1005 memset(&ri, 0, sizeof(RECORDINSERT));
1006 ri.cb = sizeof(RECORDINSERT);
1007 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1008 ri.pRecordParent = (PRECORDCORE) pciParent;
1009 ri.zOrder = (ULONG) CMA_TOP;
1010 ri.cRecordsInsert = ulSelCnt;
1011 ri.fInvalidateRecord = TRUE;
1012 if (!WinSendMsg(hwndCnr,
1013 CM_INSERTRECORD,
1014 MPFROMP(pciFirst), MPFROMP(&ri))) {
1015 DosSleep(10); // Give GUI time to work
1016 WinSetFocus(HWND_DESKTOP, hwndCnr);
1017 if (!WinSendMsg(hwndCnr,
1018 CM_INSERTRECORD,
1019 MPFROMP(pciFirst), MPFROMP(&ri))) {
1020 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1021 GetPString(IDS_CMINSERTERRTEXT));
1022 ok = FALSE;
1023 ullTotalBytes = 0;
1024 if (WinIsWindow((HAB) 0, hwndCnr))
1025 FreeCnrItemList(hwndCnr, pciFirst);
1026 }
1027 }
1028 }
1029 if (ok) {
1030 ullReturnBytes += ullTotalBytes;
1031 ulReturnFiles += ulSelCnt;
1032 if (dcd) {
1033 dcd->totalfiles += ulSelCnt;
1034 dcd->ullTotalBytes += ullTotalBytes;
1035 }
1036 }
1037 } // if sync updates
1038 else {
1039 // Append newly selected entries to aggregate list
1040 paffbTemp = xrealloc(paffbTotal,
1041 sizeof(FILEFINDBUF4L) * (ulSelCnt + cAffbTotal),
1042 pszSrcFile, __LINE__);
1043 if (paffbTemp) {
1044 // 13 Aug 07 SHL fixme to optimize copy
1045 paffbTotal = paffbTemp;
1046 ullTotalBytes = 0; // 15 Sep 09 SHL
1047 for (x = 0; x < ulSelCnt; x++) {
1048 paffbTotal[x + cAffbTotal] = *papffbSelected[x];
1049 ullTotalBytes += papffbSelected[x]->cbFile; // 15 Sep 09 SHL
1050 }
1051 cAffbTotal += ulSelCnt;
1052 // 15 Sep 09 SHL allow timed updates to see
1053 /*if (dcd) {
1054 dcd->totalfiles += ulSelCnt;
1055 dcd->ullTotalBytes += ullTotalBytes;
1056 } */ //30 May 11 GKY caused counter to increment twice
1057 }
1058 else {
1059 saymsg(MB_ENTER,
1060 HWND_DESKTOP,
1061 GetPString(IDS_ERRORTEXT), GetPString(IDS_OUTOFMEMORY));
1062 break;
1063 }
1064 }
1065 } // if entries selected
1066 if (stopflag && *stopflag)
1067 goto Abort;
1068 DosError(FERR_DISABLEHARDERR);
1069 ulFindCnt = ulFindMax;
1070 rc = xDosFindNext(hdir, paffbFound, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
1071 priority_normal();
1072 if (rc)
1073 DosError(FERR_DISABLEHARDERR);
1074 SleepIfNeeded(&itdSleep, 1);
1075 } while (!rc);
1076
1077 DosFindClose(hdir);
1078 xfree(paffbFound, pszSrcFile, __LINE__);
1079 paffbFound = NULL;
1080 xfree(papffbSelected, pszSrcFile, __LINE__);
1081 papffbSelected = NULL;
1082
1083 if (cAffbTotal && paffbTotal) {
1084 // Not fSyncUpdates and have work
1085 if (stopflag && *stopflag)
1086 goto Abort;
1087
1088 InitITimer(&itdSleep, 500);
1089 pci = NULL;
1090 ullTotalBytes = 0;
1091 pffbFile = paffbTotal;
1092 for (x = 0; x < cAffbTotal; x++) {
1093 ULONG ulRecsToInsert;
1094
1095 if (pci ==NULL) {
1096 ulRecsToInsert = cAffbTotal - x < USHRT_MAX ? cAffbTotal - x : USHRT_MAX;
1097 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
1098 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(ulRecsToInsert));
1099
1100 if (!pciFirst) {
1101 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1102 GetPString(IDS_CMALLOCRECERRTEXT));
1103 ok = FALSE;
1104 ullTotalBytes = 0;
1105 break;
1106 }
1107 else {
1108 // 04 Jan 08 SHL fixme like comp.c to handle less than ulSelCnt records
1109 if (hwndStatus && dcd &&
1110 dcd->hwndFrame == WinQueryActiveWindow(dcd->hwndParent)) {
1111 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_PLEASEWAITCOUNTINGTEXT));
1112 }
1113 pci = pciFirst;
1114 }
1115 }
1116 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1117 pffbFile, partial, dcd);
1118 pci = (PCNRITEM) pci->rc.preccNextRecord;
1119 ullTotalBytes += ullBytes;
1120 // 15 Sep 09 SHL allow timed updates to see
1121 if (dcd) {
1122 dcd->totalfiles = x;
1123 dcd->ullTotalBytes = ullTotalBytes;
1124 }
1125 // Can not use offset since we have merged lists - this should be equivalent
1126 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + sizeof(FILEFINDBUF4L));
1127
1128 if (!IdleIfNeeded(&itdSleep, 30)) {
1129 for (x = x+1; x < cAffbTotal; x++) {
1130 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1131 pffbFile, partial, dcd);
1132 pci = (PCNRITEM) pci->rc.preccNextRecord;
1133 ullTotalBytes += ullBytes;
1134 if (dcd) {
1135 dcd->totalfiles = x;
1136 dcd->ullTotalBytes = ullTotalBytes;
1137 }
1138 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + sizeof(FILEFINDBUF4L));
1139 if (pci == NULL) {
1140 priority_normal();
1141 InitITimer(&itdSleep, 500);
1142 break;
1143 }
1144 }
1145 }
1146
1147 if (pci == NULL && ulRecsToInsert) {
1148 memset(&ri, 0, sizeof(RECORDINSERT));
1149 ri.cb = sizeof(RECORDINSERT);
1150 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1151 ri.pRecordParent = (PRECORDCORE) pciParent;
1152 ri.zOrder = (ULONG) CMA_TOP;
1153 ri.cRecordsInsert = ulRecsToInsert;
1154 ri.fInvalidateRecord = (!fSyncUpdates && dcd &&
1155 dcd->type == DIR_FRAME) ? FALSE : TRUE;
1156 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1157 MPFROMP(pciFirst), MPFROMP(&ri))) {
1158 DosSleep(10); // Give GUI time to work
1159 WinSetFocus(HWND_DESKTOP, hwndCnr);
1160 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1161 MPFROMP(pciFirst), MPFROMP(&ri))) {
1162 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1163 GetPString(IDS_CMINSERTERRTEXT));
1164 ok = FALSE;
1165 ullTotalBytes = 0;
1166 if (WinIsWindow((HAB) 0, hwndCnr))
1167 FreeCnrItemList(hwndCnr, pciFirst);
1168 pciFirst = NULL;
1169 break;
1170 }
1171 }
1172 }
1173 //SleepIfNeeded(&itdSleep, 1);
1174 }
1175 priority_normal();
1176 if (ok) {
1177 ullReturnBytes += ullTotalBytes;
1178 ulReturnFiles += ulFindCnt;
1179 }
1180 }
1181 }
1182
1183 /**
1184 * DosFind for subdirectories of a read-only directory on a FAT volume
1185 * returns path not found if there are no subdirectories
1186 * FAT FS seems to ignore . and .. in this case
1187 * Map to no more files
1188 * We could verify that directory is marked read-only, it's probably not
1189 * worth the extra code since we do verify 2 out of 3 prerequisites
1190 * 15 Jan 08 SHL
1191 */
1192 if (rc == ERROR_PATH_NOT_FOUND && !filestoo) {
1193 ULONG ulDriveType = 0;
1194 CHAR szFSType[CCHMAXPATH];
1195 INT removable = CheckDrive(*pszFileSpec, szFSType, &ulDriveType);
1196 if (removable != -1 && strcmp(szFSType, "FAT") == 0)
1197 rc = ERROR_NO_MORE_FILES;
1198 }
1199
1200 // 13 Oct 09 SHL fixme to be saymsg if ERROR_NOT_READY and first try on volume
1201 if (rc && rc != ERROR_NO_MORE_FILES) {
1202 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1203 GetPString(IDS_CANTFINDDIRTEXT), pszFileSpec);
1204 }
1205
1206 if (!fSyncUpdates && dcd && dcd->type == DIR_FRAME)
1207 WinSendMsg(hwndCnr, CM_INVALIDATERECORD, MPVOID,
1208 MPFROM2SHORT(0, CMA_ERASE));
1209 }
1210Abort:
1211 xfree(paffbTotal, pszSrcFile, __LINE__);
1212 xfree(pszFileSpec, pszSrcFile, __LINE__);
1213 xfree(paffbFound, pszSrcFile, __LINE__);
1214 xfree(papffbSelected, pszSrcFile, __LINE__);
1215
1216 if (recurse) {
1217 pci = WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMP(pciParent),
1218 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
1219 while (pci && (INT)pci != -1) {
1220 if ((pci->attrFile & FILE_DIRECTORY))
1221 Stubby(hwndCnr, pci);
1222 pci = WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMP(pci),
1223 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1224 }
1225 }
1226
1227 // Reset counts in case errors occurred after initially counted
1228 if (pulTotalFiles)
1229 *pulTotalFiles = ulReturnFiles;
1230
1231 if (pullTotalBytes)
1232 *pullTotalBytes = ullReturnBytes;
1233
1234} // ProcessDirectory
1235
1236VOID FillDirCnr(HWND hwndCnr,
1237 CHAR * pszDirectory,
1238 DIRCNRDATA * dcd,
1239 PULONGLONG pullTotalBytes)
1240{
1241 ProcessDirectory(hwndCnr,
1242 (PCNRITEM)NULL,
1243 pszDirectory,
1244 TRUE, // filestoo
1245 FALSE, // recurse
1246 TRUE, // partial
1247 dcd ? &dcd->stopflag : NULL,
1248 dcd,
1249 NULL, // total files
1250 pullTotalBytes);
1251 DosPostEventSem(CompactSem);
1252
1253#if 0 // 2011-05-31 SHL fixme to be gone or to be configurable
1254 {
1255 int state = _heapchk();
1256 if (state != _HEAPOK)
1257 Runtime_Error(pszSrcFile, __LINE__, "heap corrupted %d", state);
1258 else
1259 DbgMsg(pszSrcFile, __LINE__, "_memavl %u", _memavl());
1260 }
1261#endif
1262
1263} // FillDirCnr
1264
1265/**
1266 * Fill tree container and drives list
1267 * Offer to update command line options if not already done and not suppressed
1268 */
1269
1270VOID FillTreeCnr(HWND hwndCnr, HWND hwndParent)
1271{
1272 ULONG ulCurDriveNum;
1273 ULONG ulDriveMap;
1274 ULONG numtoinsert = 0;
1275 ULONG ulDriveType;
1276 PCNRITEM pci, pciFirst = NULL;
1277 PCNRITEM pciNext;
1278 PCNRITEM pciParent = NULL;
1279 UINT iDrvNum;
1280 ULONG ulDriveMapMask;
1281 CHAR szSuggest[32]; // Suggested startup command line parameters
1282 CHAR szDrive[CCHMAXPATH] = " :\\"; // 13 Oct 09 SHL
1283 CHAR szFSType[CCHMAXPATH];
1284 FILESTATUS4L fsa4;
1285 APIRET rc;
1286 ULONG startdrive = 3;
1287 HWND hwndDrivelist;
1288
1289 static BOOL didonce;
1290 static ULONG ulLastDriveMap;
1291
1292 fDummy = TRUE;
1293 *szSuggest = 0;
1294 for (iDrvNum = 0; iDrvNum < 26; iDrvNum++) {
1295 driveflags[iDrvNum] &= (DRIVE_IGNORE | DRIVE_NOPRESCAN | DRIVE_NOLOADICONS |
1296 DRIVE_NOLOADSUBJS | DRIVE_NOLOADLONGS |
1297 DRIVE_INCLUDEFILES | DRIVE_SLOW | DRIVE_NOSTATS |
1298 DRIVE_WRITEVERIFYOFF);
1299 }
1300 memset(driveserial, -1, sizeof(driveserial));
1301
1302 DosError(FERR_DISABLEHARDERR);
1303 if (!DosQuerySysInfo(QSV_BOOT_DRIVE,
1304 QSV_BOOT_DRIVE,
1305 (PVOID) &startdrive,
1306 (ULONG) sizeof(ULONG)) &&
1307 startdrive)
1308 {
1309 driveflags[startdrive - 1] |= DRIVE_BOOT;
1310 }
1311
1312 DosError(FERR_DISABLEHARDERR);
1313 rc = DosQCurDisk(&ulCurDriveNum, &ulDriveMap);
1314 if (rc) {
1315 Dos_Error(MB_CANCEL,
1316 rc,
1317 HWND_DESKTOP,
1318 pszSrcFile, __LINE__, PCSZ_FILLDIRQCURERRTEXT);
1319 exit(0);
1320 }
1321
1322 // Find drive list combobox if it exists
1323 if (hwndParent) {
1324 hwndDrivelist = WinWindowFromID(WinQueryWindow(hwndParent, QW_PARENT),
1325 MAIN_DRIVELIST);
1326 }
1327 else
1328 hwndDrivelist = NULLHANDLE;
1329
1330 // Calc number of top level drive tree items to create
1331 for (iDrvNum = 0; iDrvNum < 26; iDrvNum++) {
1332 if ((ulDriveMap & (1L << iDrvNum)) && ~driveflags[iDrvNum] & DRIVE_IGNORE)
1333 numtoinsert++;
1334 }
1335
1336 if (numtoinsert) {
1337 pciFirst = WinSendMsg(hwndCnr,
1338 CM_ALLOCRECORD,
1339 MPFROMLONG(EXTRA_RECORD_BYTES),
1340 MPFROMLONG((ULONG) numtoinsert));
1341 }
1342
1343 if (!pciFirst) {
1344 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__, GetPString(IDS_CMALLOCRECERRTEXT));
1345 // 04 Jan 08 SHL fixme not just up and die
1346 exit(0);
1347 }
1348
1349 // 04 Jan 08 SHL fixme like comp.c to handle less than ulSelCnt records
1350 pci = pciFirst;
1351 for (iDrvNum = 0; iDrvNum < 26; iDrvNum++) {
1352 ulDriveMapMask = 1L << iDrvNum;
1353 if (ulDriveMap & ulDriveMapMask && ~driveflags[iDrvNum] & DRIVE_IGNORE) {
1354 CHAR s[80];
1355 ULONG flags = 0;
1356 ULONG size = sizeof(ULONG);
1357 struct {
1358 ULONG serial;
1359 CHAR volumelength;
1360 CHAR volumelabel[CCHMAXPATH];
1361 } volser;
1362
1363 *szDrive = (CHAR)iDrvNum + 'A'; // Stuff drive letter - assume already have rest of path
1364
1365 sprintf(s, "%c.DriveFlags", toupper(*szDrive));
1366 if (PrfQueryProfileData(fmprof, appname, s, &flags, &size)) {
1367 driveflags[iDrvNum] |= flags;
1368 }
1369
1370 if (iDrvNum > 1) {
1371 // Hard drive (2..N)
1372 if (~driveflags[iDrvNum] & DRIVE_NOPRESCAN) {
1373 *szFSType = 0;
1374 ulDriveType = 0;
1375 memset(&volser, 0, sizeof(volser));
1376 DriveFlagsOne(iDrvNum, szFSType, &volser);
1377 driveserial[iDrvNum] = volser.serial;
1378 memset(&fsa4, 0, sizeof(FILESTATUS4L));
1379 if (!fVerifyOffChecked[iDrvNum]) {
1380 if (driveflags[iDrvNum] & DRIVE_REMOVABLE)
1381 driveflags[iDrvNum] |= DRIVE_WRITEVERIFYOFF;
1382 if (~driveflags[iDrvNum] & DRIVE_INVALID) {
1383 CHAR Key[80];
1384
1385 sprintf(Key, "%c.VerifyOffChecked", (CHAR) (iDrvNum + 'A'));
1386 fVerifyOffChecked[iDrvNum] = TRUE;
1387 PrfWriteProfileData(fmprof, appname, Key, &fVerifyOffChecked[iDrvNum], sizeof(BOOL));
1388 }
1389 }
1390 if (fShowDriveLabelInTree && stricmp(volser.volumelabel, NullStr) != 0)
1391 strcpy(szFSType, volser.volumelabel);
1392 pci->rc.flRecordAttr |= CRA_RECORDREADONLY;
1393 if ((ULONG)(toupper(*szDrive) - '@') == ulCurDriveNum)
1394 pci->rc.flRecordAttr |= (CRA_CURSORED | CRA_SELECTED);
1395
1396 if (~driveflags[iDrvNum] & DRIVE_REMOVABLE) {
1397 // Fixed volume
1398 if (~flags & DRIVE_INVALID && ~flags & DRIVE_NOPRESCAN)
1399 FixedVolume++;
1400 pci->attrFile |= FILE_DIRECTORY;
1401 DosError(FERR_DISABLEHARDERR);
1402 rc = DosQueryPathInfo(szDrive,
1403 FIL_QUERYEASIZEL,
1404 &fsa4, (ULONG) sizeof(FILESTATUS4L));
1405 if (rc == ERROR_BAD_NET_RESP) {
1406 DosError(FERR_DISABLEHARDERR);
1407 rc = DosQueryPathInfo(szDrive,
1408 FIL_STANDARDL,
1409 &fsa4, (ULONG) sizeof(FILESTATUS4L));
1410 fsa4.cbList = 0;
1411 }
1412 if (rc && !didonce) {
1413 // Guess drive letter
1414 if (!*szSuggest) {
1415 *szSuggest = '/';
1416 szSuggest[1] = 0;
1417 }
1418
1419 sprintf(szSuggest + strlen(szSuggest), "%c" , toupper(*szDrive));
1420 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1421 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1422 sprintf(szDrive + strlen(szDrive), " [%s]", szFSType);
1423 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1424 szDrive[3] = 0; // Restore nul
1425 pci->rc.pszIcon = pci->pszDisplayName;
1426 pci->attrFile = FILE_DIRECTORY;
1427 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1428 driveserial[iDrvNum] = -1;
1429 }
1430 else
1431 FillInRecordFromFSA(hwndCnr, pci, szDrive, &fsa4, TRUE, szFSType, NULL);
1432 }
1433 else {
1434 // Removable volume
1435 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1436 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1437 sprintf(szDrive + strlen(szDrive), " [%s]", szFSType);
1438 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1439 szDrive[3] = 0; // Restore nul
1440 pci->rc.pszIcon = pci->pszDisplayName;
1441 pci->attrFile = FILE_DIRECTORY;
1442 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1443 }
1444 SelectDriveIcon(pci);
1445# ifdef FORTIFY
1446 // Will be freed by TreeCnrWndProc WM_DESTROY
1447 Fortify_SetScope(pci->pszFileName, 2);
1448# endif
1449 }
1450 else {
1451 *szFSType = 0;
1452 pci->rc.hptrIcon = hptrDunno;
1453 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1454 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1455 strcat(szDrive, " [?]");
1456 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1457 szDrive[3] = 0;
1458# ifdef FORTIFY
1459 // Will be freed by TreeCnrWndProc WM_DESTROY
1460 Fortify_SetScope(pci->pszFileName, 2);
1461# endif
1462 pci->rc.pszIcon = pci->pszDisplayName;
1463 pci->attrFile = FILE_DIRECTORY;
1464 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1465 driveserial[iDrvNum] = -1;
1466 }
1467 }
1468 else {
1469 // diskette drive (A or B)
1470 pci->rc.hptrIcon = hptrFloppy;
1471 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1472 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1473 strcat(szDrive, " [Floppy]");
1474 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1475 szDrive[3] = 0;
1476 pci->rc.pszIcon = pci->pszDisplayName;
1477 pci->attrFile = FILE_DIRECTORY;
1478 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1479 driveflags[iDrvNum] |= (DRIVE_REMOVABLE | DRIVE_NOLONGNAMES);
1480 driveserial[iDrvNum] = -1;
1481 }
1482 pci->rc.flRecordAttr |= CRA_RECORDREADONLY;
1483 pci = (PCNRITEM) pci->rc.preccNextRecord; // next rec
1484 }
1485 else if (~ulDriveMap & ulDriveMapMask)
1486 driveflags[iDrvNum] |= DRIVE_INVALID;
1487
1488 // 13 Oct 09 SHL
1489 // Update drives list dropdown
1490 if ((ulDriveMap ^ ulLastDriveMap) & ulDriveMapMask) {
1491 if (ulDriveMap & ulDriveMapMask) {
1492 WinSendMsg(hwndDrivelist,
1493 LM_INSERTITEM,
1494 MPFROM2SHORT(LIT_SORTASCENDING, 0),
1495 MPFROMP(szDrive));
1496 }
1497 else {
1498 // Drive went away
1499 SHORT sSelect = (SHORT)WinSendMsg(hwndDrivelist,
1500 LM_SEARCHSTRING,
1501 MPFROM2SHORT(0, LIT_FIRST),
1502 MPFROMP(szDrive));
1503 if (sSelect >= 0)
1504 WinSendMsg(hwndDrivelist, LM_DELETEITEM, MPFROMSHORT(sSelect), MPVOID);
1505 }
1506 }
1507 } // for drives
1508
1509 ulLastDriveMap = ulDriveMap; // 13 Oct 09 SHL
1510
1511 // insert the drives
1512 if (numtoinsert && pciFirst) {
1513 RECORDINSERT ri;
1514
1515 memset(&ri, 0, sizeof(RECORDINSERT));
1516 ri.cb = sizeof(RECORDINSERT);
1517 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1518 ri.pRecordParent = (PRECORDCORE) NULL;
1519 ri.zOrder = (ULONG) CMA_TOP;
1520 ri.cRecordsInsert = numtoinsert;
1521 ri.fInvalidateRecord = FALSE;
1522 if (!WinSendMsg(hwndCnr,
1523 CM_INSERTRECORD, MPFROMP(pciFirst), MPFROMP(&ri)))
1524 {
1525 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1526 GetPString(IDS_CMINSERTERRTEXT));
1527 }
1528 }
1529
1530 // move cursor onto the default drive rather than the first drive
1531 if (!fSwitchTree) {
1532 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1533 CM_QUERYRECORD,
1534 MPVOID,
1535 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1536 while (pci && (INT)pci != -1) {
1537 if ((ULONG) (toupper(*pci->pszFileName) - '@') == ulCurDriveNum) {
1538 WinSendMsg(hwndCnr,
1539 CM_SETRECORDEMPHASIS,
1540 MPFROMP(pci), MPFROM2SHORT(TRUE, CRA_CURSORED));
1541 break;
1542 }
1543 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1544 CM_QUERYRECORD,
1545 MPFROMP(pci),
1546 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1547 }
1548 }
1549
1550 if (fShowEnv) {
1551 RECORDINSERT ri;
1552
1553 pciParent = WinSendMsg(hwndCnr,
1554 CM_ALLOCRECORD,
1555 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(1));
1556 if (pciParent) {
1557 pciParent->flags |= RECFLAGS_ENV;
1558 pciParent->pszFileName = xstrdup(GetPString(IDS_ENVVARSTEXT), pszSrcFile, __LINE__);
1559 pciParent->pszDisplayName = pciParent->pszFileName; // 03 Aug 07 SHL
1560 pciParent->rc.hptrIcon = hptrEnv;
1561 pciParent->rc.pszIcon = pciParent->pszFileName;
1562 pciParent->pszDispAttr = FileAttrToString(0);
1563 memset(&ri, 0, sizeof(RECORDINSERT));
1564 ri.cb = sizeof(RECORDINSERT);
1565 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1566 ri.pRecordParent = (PRECORDCORE) NULL;
1567 ri.zOrder = (ULONG) CMA_TOP;
1568 ri.cRecordsInsert = 1;
1569 ri.fInvalidateRecord = FALSE;
1570 if (WinSendMsg(hwndCnr,
1571 CM_INSERTRECORD, MPFROMP(pciParent), MPFROMP(&ri))) {
1572
1573 char *p, *pp;
1574
1575 p = pszTreeEnvVarList;
1576 while (*p == ';')
1577 p++;
1578 while (*p) {
1579 *szFSType = 0;
1580 pp = szFSType;
1581 while (*p && *p != ';')
1582 *pp++ = *p++;
1583 *pp = 0;
1584 while (*p == ';')
1585 p++;
1586 if (*szFSType &&
1587 (!stricmp(szFSType, PCSZ_LIBPATH) || getenv(szFSType))) {
1588 pci = WinSendMsg(hwndCnr,
1589 CM_ALLOCRECORD,
1590 MPFROMLONG(EXTRA_RECORD_BYTES),
1591 MPFROMLONG(1));
1592 if (pci) {
1593 CHAR fname[CCHMAXPATH];
1594 pci->flags |= RECFLAGS_ENV;
1595 sprintf(fname, "%%%s%%", szFSType);
1596 pci->pszFileName = xstrdup(fname, pszSrcFile, __LINE__);
1597 pci->rc.hptrIcon = hptrEnv;
1598 pci->rc.pszIcon = pci->pszFileName;
1599 pci->pszDispAttr = FileAttrToString(0);
1600 memset(&ri, 0, sizeof(RECORDINSERT));
1601 ri.cb = sizeof(RECORDINSERT);
1602 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1603 ri.pRecordParent = (PRECORDCORE) pciParent;
1604 ri.zOrder = (ULONG) CMA_TOP;
1605 ri.cRecordsInsert = 1;
1606 ri.fInvalidateRecord = FALSE;
1607 if (!WinSendMsg(hwndCnr,
1608 CM_INSERTRECORD,
1609 MPFROMP(pci), MPFROMP(&ri))) {
1610 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1611 GetPString(IDS_CMINSERTERRTEXT));
1612 FreeCnrItem(hwndCnr, pci);
1613 }
1614 }
1615 }
1616 }
1617 WinSendMsg(hwndCnr,
1618 CM_INVALIDATERECORD,
1619 MPFROMP(&pciParent),
1620 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
1621 }
1622 else
1623 FreeCnrItem(hwndCnr, pciParent);
1624 }
1625 } // if show env
1626 {
1627 STUBBYSCAN *stubbyScan;
1628
1629 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1630 CM_QUERYRECORD,
1631 MPVOID,
1632 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1633 while (pci && (INT)pci != -1) {
1634 stubbyScan = xmallocz(sizeof(STUBBYSCAN), pszSrcFile, __LINE__);
1635 if (!stubbyScan)
1636 break;
1637 stubbyScan->pci = pci;
1638 stubbyScan->hwndCnr = hwndCnr;
1639 pciNext = (PCNRITEM) WinSendMsg(hwndCnr,
1640 CM_QUERYRECORD,
1641 MPFROMP(pci),
1642 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1643 if (~pci->flags & RECFLAGS_ENV) {
1644 iDrvNum = toupper(*pci->pszFileName) - 'A'; // 0..25
1645 if (iDrvNum == ulCurDriveNum || iDrvNum >= 2) {
1646 // Hard drive or current drive
1647 ULONG flags = driveflags[iDrvNum]; // Speed up
1648 if (~flags & DRIVE_INVALID &&
1649 ~flags & DRIVE_NOPRESCAN && (!fNoRemovableScan || ~flags & DRIVE_REMOVABLE)) {
1650 // DbgMsg(pszSrcFile, __LINE__, "Begin Thread %s", pci->pszFileName);
1651 if (xbeginthread(StubbyScanThread,
1652 65536,
1653 stubbyScan,
1654 pszSrcFile, __LINE__) == -1)
1655 xfree(stubbyScan, pszSrcFile, __LINE__);
1656
1657 } // if drive needs to be scanned
1658 }
1659 else {
1660 // Diskette and not current drive
1661 WinSendMsg(hwndCnr,
1662 CM_INVALIDATERECORD,
1663 MPFROMP(&pci),
1664 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
1665 }
1666 }
1667 pci = pciNext;
1668 } // while
1669 }
1670
1671 // 13 Oct 09 SHL
1672 if (hwndDrivelist)
1673 WinSendMsg(hwndDrivelist, LM_SELECTITEM, MPFROM2SHORT(0, 0), MPFROMLONG(TRUE));
1674
1675 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1676 CM_QUERYRECORD,
1677 MPVOID,
1678 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1679 while (pci && (INT)pci != -1) {
1680 pciNext = (PCNRITEM) WinSendMsg(hwndCnr,
1681 CM_QUERYRECORD,
1682 MPFROMP(pci),
1683 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1684 if (pci->flags & RECFLAGS_ENV) {
1685 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1686 CM_QUERYRECORD,
1687 MPFROMP(pci),
1688 MPFROM2SHORT(CMA_FIRSTCHILD,
1689 CMA_ITEMORDER));
1690 while (pci && (INT)pci != -1) {
1691 if (pci->flags & RECFLAGS_ENV)
1692 FleshEnv(hwndCnr, pci);
1693 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1694 CM_QUERYRECORD,
1695 MPFROMP(pci),
1696 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1697 }
1698 break;
1699 }
1700 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1701 CM_QUERYRECORD,
1702 MPFROMP(pci),
1703 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1704 }
1705
1706 if (hwndMain)
1707 PostMsg(hwndMain, UM_BUILDDRIVEBAR, MPVOID, MPVOID);
1708 DosSleep(16); // 05 Aug 07 GKY 33
1709 fDummy = FALSE;
1710 DosPostEventSem(CompactSem);
1711
1712 if (!fDontSuggestAgain) {
1713 BYTE info;
1714 BOOL includesyours = FALSE;
1715
1716 // 10 Jan 08 SHL fixme to understand fFirstTime - looks obsolete to me - probably mean didonce?
1717 if (*szSuggest || ~driveflags[1] & DRIVE_IGNORE && fFirstTime) {
1718 if (!DosDevConfig(&info, DEVINFO_FLOPPY) && info == 1) {
1719 if (!*szSuggest) {
1720 *szSuggest = '/';
1721 szSuggest[1] = 0;
1722 }
1723 else
1724 memmove(szSuggest + 2, szSuggest + 1, strlen(szSuggest));
1725 szSuggest[1] = 'B';
1726 }
1727 }
1728 if (*szSuggest) {
1729 APIRET rc;
1730 for (iDrvNum = 2; iDrvNum < 26; iDrvNum++) {
1731 if (driveflags[iDrvNum] & DRIVE_IGNORE) {
1732 includesyours = TRUE;
1733 sprintf(szSuggest + strlen(szSuggest), "%c", (char)(iDrvNum + 'A'));
1734 }
1735 }
1736 strcat(szSuggest, " %*");
1737 rc = saymsg(MB_YESNOCANCEL | MB_ICONEXCLAMATION,
1738 hwndParent ? hwndParent : hwndCnr,
1739 GetPString(IDS_SUGGESTTITLETEXT),
1740 GetPString(IDS_SUGGEST1TEXT),
1741 (includesyours) ? GetPString(IDS_SUGGEST2TEXT) : NullStr,
1742 szSuggest);
1743 if (rc == MBID_YES) {
1744 HOBJECT hFM2Object;
1745 char s[64];
1746 sprintf(s, "PARAMETERS=%s", szSuggest);
1747 hFM2Object = WinQueryObject("<FM/2>");
1748 if (hFM2Object) {
1749 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1750 }
1751 hFM2Object = WinQueryObject("<FM/2 LITE>");
1752 if (hFM2Object) {
1753 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1754 }
1755 hFM2Object = WinQueryObject("<FM/2_AV/2>");
1756 if (hFM2Object) {
1757 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1758 }
1759 hFM2Object = WinQueryObject("<FM/2_DIRSIZE>");
1760 if (hFM2Object) {
1761 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1762 }
1763 hFM2Object = WinQueryObject("<FM/2_VTREE>");
1764 if (hFM2Object) {
1765 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1766 }
1767 hFM2Object = WinQueryObject("<FM/2_VDIR>");
1768 if (hFM2Object) {
1769 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1770 }
1771 hFM2Object = WinQueryObject("<FM/2_SEEALL>");
1772 if (hFM2Object) {
1773 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1774 }
1775 hFM2Object = WinQueryObject("<FM/2_DATABAR>");
1776 if (hFM2Object) {
1777 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1778 }
1779 }
1780 else if (rc == MBID_CANCEL) {
1781 fDontSuggestAgain = TRUE;
1782 PrfWriteProfileData(fmprof, FM3Str, "DontSuggestAgain", &fDontSuggestAgain, sizeof(BOOL));
1783 }
1784 } // if suggest
1785 } // if !fDontSuggestAgain
1786 didonce = TRUE;
1787} // FillTreeCnr
1788
1789
1790/**
1791 * Empty all records from a container and free associated storage and
1792 * Free up field infos
1793 */
1794
1795VOID EmptyCnr(HWND hwnd)
1796{
1797 PFIELDINFO pfi;
1798
1799#if 0 // fixme to be gone or to be configurable
1800 {
1801 int state = _heapchk();
1802 if (state != _HEAPOK)
1803 Runtime_Error(pszSrcFile, __LINE__, "heap corrupted %d", state);
1804 }
1805#endif
1806
1807 // Remove all records
1808 RemoveCnrItems(hwnd, NULL, 0, CMA_FREE);
1809
1810 // Remove field info descriptors
1811 pfi = (PFIELDINFO) WinSendMsg(hwnd, CM_QUERYDETAILFIELDINFO, MPVOID,
1812 MPFROMSHORT(CMA_FIRST));
1813 if (pfi &&
1814 (INT)WinSendMsg(hwnd, CM_REMOVEDETAILFIELDINFO, MPVOID,
1815 MPFROM2SHORT(0, CMA_FREE)) == -1) {
1816 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVEDETAILFIELDINFO hwnd %x", hwnd);
1817 }
1818}
1819
1820/**
1821 * Free storage associated with container item
1822 */
1823
1824VOID FreeCnrItemData(PCNRITEM pci)
1825{
1826 if (pci->pszSubject) {
1827 if (pci->pszSubject != NullStr)
1828 free(pci->pszSubject);
1829 pci->pszSubject = NULL; // Catch illegal references
1830 }
1831
1832 // 08 Sep 08 SHL Remove excess logic
1833 if (pci->pszLongName) {
1834 if (pci->pszLongName != NullStr)
1835 free(pci->pszLongName);
1836 pci->pszLongName = NULL; // Catch illegal references
1837 }
1838
1839 // Bypass free if pszDisplayName points into pszFileName buffer
1840 // 05 Sep 08 SHL Correct pointer overlap compare logic
1841 if (pci->pszDisplayName) {
1842 if (pci->pszDisplayName != NullStr) {
1843 if (!pci->pszFileName ||
1844 pci->pszDisplayName < pci->pszFileName ||
1845 pci->pszDisplayName >= pci->pszFileName + _msize(pci->pszFileName))
1846 {
1847 free(pci->pszDisplayName);
1848 }
1849 }
1850 pci->pszDisplayName = NULL; // Catch illegal references
1851 }
1852
1853#if 0 // 26 Sep 09 SHL debug dup free complaints
1854 if (!pci->pszFileName)
1855 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice", pci);
1856 else {
1857 if (pci->pszFileName != NullStr)
1858 free(pci->pszFileName);
1859 pci->pszFileName = NULL; // Catch illegal references
1860 }
1861#else
1862 {
1863 #define HIST_COUNT 50
1864 static struct {
1865 PCNRITEM pci;
1866 PSZ pszFileName;
1867 } history[HIST_COUNT];
1868 static volatile UINT iHistNdx;
1869 UINT i;
1870
1871 if (!pci->pszFileName) {
1872 // Looks like pci was already freed
1873 // Try to locate original file name in history buffer
1874 for (i = 0; i < HIST_COUNT && pci != history[i].pci; i++) { } // Scan
1875 if (i < HIST_COUNT) {
1876 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice, fileName was %.260s",
1877 pci, history[i].pszFileName);
1878 } else {
1879 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice", pci);
1880 }
1881 }
1882 else {
1883 PSZ psz;
1884 PSZ *ppsz;
1885 // Grab a history slot
1886 // This should work well enoungh to prevent MT/SMP conflicts
1887 for (;;) {
1888 i = iHistNdx;
1889 if (++i >= HIST_COUNT)
1890 i = 0;
1891 if (++iHistNdx >= HIST_COUNT)
1892 iHistNdx = 0;
1893 if (i == iHistNdx) break;
1894 }
1895 ppsz = &history[iHistNdx].pszFileName;
1896 psz = *ppsz;
1897 if (psz)
1898 free(psz);
1899 if (pci->pszFileName && pci->pszFileName != NullStr)
1900 *ppsz = strdup(pci->pszFileName);
1901 else
1902 *ppsz = NULL;
1903 history[iHistNdx].pci = pci;
1904 if (pci->pszFileName != NullStr)
1905 free(pci->pszFileName);
1906 pci->pszFileName = NULL; // Catch illegal references and dup free attempts
1907 }
1908 }
1909
1910
1911#endif
1912
1913 // 08 Sep 08 SHL Remove excess logic
1914 if (pci->pszLongName) {
1915 if (pci->pszLongName != NullStr)
1916 free(pci->pszLongName);
1917 pci->pszLongName = NULL; // Catch illegal references
1918 }
1919
1920 if (pci->pszFmtFileSize) {
1921 if (pci->pszFmtFileSize != NullStr)
1922 free(pci->pszFmtFileSize);
1923 pci->pszFmtFileSize = NULL; // Catch illegal references
1924 }
1925}
1926
1927/**
1928 * Free single container item and associated storage
1929 */
1930
1931VOID FreeCnrItem(HWND hwnd, PCNRITEM pci)
1932{
1933 // DbgMsg(pszSrcFile, __LINE__, "FreeCnrItem hwnd %x pci %p", hwnd, pci);
1934
1935 FreeCnrItemData(pci);
1936
1937 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(1))) {
1938 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,
1939 "CM_FREERECORD hwnd %x pci %p file %s",
1940 hwnd, pci,
1941 pci && pci->pszFileName ? pci->pszFileName : "n/a");
1942 }
1943}
1944
1945/**
1946 * Free container item list and associated storage
1947 */
1948
1949VOID FreeCnrItemList(HWND hwnd, PCNRITEM pciFirst)
1950{
1951 PCNRITEM pci = pciFirst;
1952 PCNRITEM pciNext;
1953 USHORT usCount;
1954 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
1955
1956 InitITimer(&itdSleep, 500);
1957 for (usCount = 0; pci; usCount++) {
1958 pciNext = (PCNRITEM) pci->rc.preccNextRecord;
1959 FreeCnrItemData(pci);
1960 pci = pciNext;
1961 if (!IdleIfNeeded(&itdSleep, 30)) {
1962 for (usCount = usCount + 1; pci; usCount++) {
1963 pciNext = (PCNRITEM) pci->rc.preccNextRecord;
1964 FreeCnrItemData(pci);
1965 pci = pciNext;
1966 }
1967 break;
1968 }
1969 }
1970 priority_normal();
1971 DosPostEventSem(CompactSem);
1972 if (usCount) {
1973 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(usCount))) {
1974 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_FREERECORD hwnd %x pci %p cnt %u", hwnd, pci, usCount);
1975 }
1976 }
1977}
1978
1979/**
1980 * Remove item(s) from container and free associated storage if requested
1981 * @param pciFirst points to first item to remove or NULL to remove all
1982 * @param usCnt is remove count or 0 to remove all
1983 * @returns count of items remaining in container or -1 if error
1984 */
1985
1986INT RemoveCnrItems(HWND hwnd, PCNRITEM pciFirst, USHORT usCnt, USHORT usFlags)
1987{
1988 INT remaining = usCnt;
1989 PCNRITEM pci;
1990 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
1991
1992
1993 if ((usCnt && !pciFirst) || (!usCnt && pciFirst)) {
1994 Runtime_Error(pszSrcFile, __LINE__, "pciFirst %p usCnt %u mismatch", pciFirst, usCnt);
1995 remaining = -1;
1996 }
1997 else {
1998 // Free our buffers if free requested
1999 if (usFlags & CMA_FREE) {
2000 if (pciFirst)
2001 pci = pciFirst;
2002 else {
2003 pci = (PCNRITEM)WinSendMsg(hwnd, CM_QUERYRECORD, MPVOID,
2004 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
2005 if ((INT)pci == -1) {
2006 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_QUERYRECORD");
2007 remaining = -1;
2008 pci = NULL;
2009 }
2010 }
2011 InitITimer(&itdSleep, 500);
2012 while (pci) {
2013#if 0 // 12 Sep 07 SHL dwg drivebar crash testing - ticket# ??? - fixme to be gone
2014 static PCNRITEM pciLast; // 12 Sep 07 SHL
2015 ULONG ulSize = sizeof(*pci);
2016 ULONG ulAttr;
2017 APIRET apiret = DosQueryMem((PVOID)pci, &ulSize, &ulAttr);
2018 if (apiret)
2019 Dos_Error(MB_ENTER, apiret, HWND_DESKTOP, pszSrcFile, __LINE__,
2020 "DosQueryMem failed pci %p pciLast %p", pci, pciLast);
2021#endif
2022 FreeCnrItemData(pci);
2023#if 0 // 12 Sep 07 SHL dwg drivebar crash testing - ticket# ??? - fixme to be gone
2024 pciLast = pci;
2025#endif
2026 pci = (PCNRITEM)pci->rc.preccNextRecord;
2027 if (remaining && --remaining == 0)
2028 break;
2029 if (!IdleIfNeeded(&itdSleep, 30)) {
2030 while (pci) {
2031 FreeCnrItemData(pci);
2032 pci = (PCNRITEM)pci->rc.preccNextRecord;
2033 if (remaining && --remaining == 0)
2034 break;
2035 }
2036 }
2037 }
2038 priority_normal();
2039 DosPostEventSem(CompactSem);
2040 }
2041 }
2042
2043 // DbgMsg(pszSrcFile, __LINE__, "RemoveCnrItems %p %u %s", pci, usCnt, pci->pszFileName);
2044
2045 if (remaining != - 1) {
2046 remaining = (INT)WinSendMsg(hwnd, CM_REMOVERECORD, MPFROMP(&pciFirst), MPFROM2SHORT(usCnt, usFlags));
2047 if (remaining == -1) {
2048 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVERECORD hwnd %x pci %p cnt %u", hwnd, pciFirst, usCnt);
2049 }
2050 }
2051
2052 return remaining;
2053}
2054
2055#pragma alloc_text(FILLDIR,FillInRecordFromFFB,FillInRecordFromFSA,IDFile)
2056#pragma alloc_text(FILLDIR1,ProcessDirectory,FillDirCnr,FillTreeCnr,FileAttrToString,StubbyScanThread)
2057#pragma alloc_text(EMPTYCNR,EmptyCnr,FreeCnrItemData,FreeCnrItem,FreeCnrItemList,RemoveCnrItems)
2058
Note: See TracBrowser for help on using the repository browser.