source: trunk/dll/filldir.c@ 1867

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

Correct WaitFleshWorkListEmpty typo that could corrupt heap
Protect some read-only strings from overwriting

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