source: trunk/dll/filldir.c@ 1551

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

This code adds the semaphores to prevent a rescan from starting before the current one is finished; it fixes the double directory listing in the tree container and streamlines scanning. It update mapsym.pl to the latest version. Some code cleanup is included

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