source: trunk/dll/filldir.c@ 1736

Last change on this file since 1736 was 1690, checked in by Gregg Young, 12 years ago

Changes to fix .tar.gz list because of changes in tar 1.20 (maybe earlier). Added lzip support with ungly hack to work around its lack of a list option. Tickets 493, 494

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