source: trunk/dll/filldir.c@ 1553

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

Rework scanning code to remove redundant scans, prevent double directory entries in the tree container, fix related semaphore performance using combination of event and mutex semaphores

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