source: trunk/dll/filldir.c@ 1890

Last change on this file since 1890 was 1890, checked in by Steven Levine, 6 years ago

Add PMPRINTF enable support to makefiles.
Correct PMPRINTF debug macro enables in sources.

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