source: trunk/dll/filldir.c@ 1873

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

Adjustments to ShowTreeRec to eliminate failures and reduce retries and container noise on tree switches. Remove fInitialDriveScan code. Changes to speed up ExpandAll. WaitFleshWorkListEmpty now gives error message and returns if semaphore request fails more than 5 consecutive times.

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