source: trunk/dll/filldir.c@ 1570

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

Added IdleIfNeeded to place load and free loops to idle priority when dealing with large numbers of items. Used SleepIfNeeded more places for a similar purpose.

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