source: trunk/dll/filldir.c@ 1871

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

Create CollapseAll and modify ExpandAll to reduce code overhead both to try and speed drive expansion. Change ExpandAll to allow it to loop in UM_EXPAND until until drive is completely expanded. Changes were need to work with Flesh, Stubby and UnFlesh being moved to a thread. Add code for Flesh to skip the directory entry added by Stubby (eliminate use of NULL/Nullstr pszFileNames by Stubby). Add code in Stubby to insert a complete container item. Add a flag to indicate when a directory needed to be Fleshed. Get expand and switch code to work with Flesh, UnFlesh and Stubby running on a thread. Loop and idle ExpandAll; Move tree expand to a thread; Have ShowTreeRec wait for the Flesh thread. Add a correction factor so directories don't get placed above the top of the tree container when a large drive has been expanded. Debug is mostly still in but all turned off.

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