source: trunk/dll/filldir.c@ 1522

Last change on this file since 1522 was 1522, checked in by John Small, 15 years ago

Ticket 434: Startup parameter suggestion improvements and bug fixes.

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