source: trunk/dll/filldir.c@ 1555

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

Minor cleanup of the scanning code.

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