source: trunk/dll/filldir.c@ 1549

Last change on this file since 1549 was 1549, checked in by Gregg Young, 15 years ago

This "fixes" the double entries in the tree container (Ticket 363); it also means the tree ignores the fSwitchTree* variables on startup. The only remaining problem is on the first focus changes between 2 directory containers the directory doesn't always get placed at the top of the tree container after the first switch to each it seems to work fine.

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