source: trunk/dll/filldir.c@ 1836

Last change on this file since 1836 was 1836, checked in by Gregg Young, 10 years ago

Fix trap in collector if a pci-pszFileName = NullStr and fix heap corruption problem and its related traps. This code reverts John double free fix. Ticket [551][555]

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