source: trunk/dll/filldir.c@ 1856

Last change on this file since 1856 was 1856, checked in by Steven Levine, 10 years ago

Rework Flesh/Stubby etc. to avoid running on thread 1
Should be ready for release after spurious traps resolved
DbgMsg calls retained - delete/disable before release

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