source: trunk/dll/filldir.c@ 1756

Last change on this file since 1756 was 1756, checked in by Gregg Young, 12 years ago

Speed up intial drive scans Ticket 528

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