source: trunk/dll/filldir.c@ 1550

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

This actually fixes the double names in the tree container. It also streamlines the initial scan code by eliminating multiple redundant scans.

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