source: trunk/dll/filldir.c@ 1643

Last change on this file since 1643 was 1643, checked in by Gregg Young, 14 years ago

Removed UnFlesh call from StubbyScanThread; This seems to significantly cut load times.

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