source: trunk/dll/filldir.c@ 1672

Last change on this file since 1672 was 1672, checked in by Steven Levine, 13 years ago

Update comments

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