source: trunk/dll/filldir.c@ 1877

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

Remove debug code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.7 KB
Line 
1
2/***********************************************************************
3
4 $Id: filldir.c 1877 2015-10-11 21:43:27Z gyoung $
5
6 Fill Directory Tree Containers
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2001, 2015 Steven H. Levine
10
11 10 Jan 04 SHL ProcessDirectory: avoid most large drive failures
12 24 May 05 SHL Rework Win_Error usage
13 24 May 05 SHL Rework for CNRITEM.szSubject
14 25 May 05 SHL Rework for ULONGLONG
15 25 May 05 SHL Rework FillInRecordFromFFB
16 25 May 05 SHL Rework FillTreeCnr
17 28 May 05 SHL Drop stale debug code
18 05 Jun 05 SHL Comments
19 09 Jun 05 SHL Rework WinLoadFileIcon enables
20 09 Jun 05 SHL Rework IDFile
21 13 Aug 05 SHL Renames
22 24 Oct 05 SHL FillInRecordFromFFB: correct longname display enable
23 24 Oct 05 SHL FillInRecordFromFSA: correct longname display enable
24 24 Oct 05 SHL Drop obsolete code
25 22 Jul 06 SHL Check more run time errors
26 20 Oct 06 SHL Sync . .. check code
27 22 Oct 06 GKY Add NDFS32 support
28 17 Feb 07 GKY Additional archive and image file tyoes identifed by extension
29 17 Feb 07 GKY Add more drive types
30 09 Mar 07 GKY Use SelectDriveIcon
31 20 Mar 07 GKY Increase extention check to 4 letters for icon selections
32 23 Jun 07 GKY Fixed ram disk without a directory not appearing on states drive list
33 23 Jul 07 SHL Sync with CNRITEM updates (ticket#24)
34 29 Jul 07 SHL Add CNRITEM free and remove support (ticket#24)
35 02 Aug 07 SHL Add FileAttrToString
36 03 Aug 07 GKY Enlarged and made setable everywhere Findbuf (speed file loading)
37 04 Aug 07 SHL Update #pragma alloc_test for new functions
38 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
39 13 Aug 07 SHL Sync code with other FilesToGet usage and optimize
40 13 Aug 07 SHL Move #pragma alloc_text to end for OpenWatcom compat
41 04 Nov 07 GKY Use commaFmtULL to display large file sizes
42 29 Feb 08 GKY Use xfree where appropriate
43 07 Jul 08 SHL Use NULL rather than NullStr in FreeCnrItemData
44 16 JUL 08 GKY Use TMP directory for temp files
45 20 Jul 08 JBS Ticket 114: Support user-selectable env. strings in Tree container.
46 21 Jul 08 JBS Ticket 114: Change env var separator from blank to semicolon
47 02 Aug 08 GKY Remove redundant strcpys from inner loop
48 23 Aug 08 GKY Free pszDisplayName when appropriate
49 01 Sep 08 GKY Updated FreeCnrItemData to prevent trap in strrchr if pci->pszFileName is NULL.
50 05 Sep 08 SHL Correct FreeCnrItemData pszDisplayName pointer overlap check
51 08 Sep 08 SHL Remove extra pszLongName logic in FreeCnrItemData
52 18 Oct 08 GKY Scan drives in 4 passes (local, virtual, remote, flagged slow) to speed tree scans
53 19 Nov 08 SHL Correct and sanitize 4 pass scan logic
54 21 Nov 08 SHL FillTreeCnr: ensure any unchecked drives checked in pass 4
55 24 Nov 08 GKY Add StubyScanThread to treecnr scan/rescan drives all on separate threads
56 24 Nov 08 GKY Replace 4 pass drive scan code with StubyScanThread multithread scan
57 28 Nov 08 SHL FreeCnrItemData: optimize and always NULL pointers
58 28 Nov 08 SHL StubbyThread: add else lost in translation
59 30 Nov 08 SHL StubbyThread: restore else - we want all drives listed
60 30 Nov 08 SHL FreeCnrItemData: report double free with Runtime_Error
61 04 Dec 08 GKY Use event semaphore to prevent scan of "last" directory container prior to
62 tree scan completion; prevents duplicate directory names in tree.
63 10 Dec 08 SHL Integrate exception handler support
64 25 Dec 08 GKY Add code to allow write verify to be turned off on a per drive basis
65 25 Dec 08 GKY Add ProcessDirectoryThread to allow optional recursive drive scan at startup.
66 07 Feb 09 GKY Eliminate Win_Error2 by moving function names to PCSZs used in Win_Error
67 08 Mar 09 GKY Renamed commafmt.h i18nutil.h
68 08 Mar 09 GKY Additional strings move to PCSZs
69 08 Mar 09 GKY Removed variable aurguments from docopyf and unlinkf (not used)
70 14 Mar 09 GKY Prevent execution of UM_SHOWME while drive scan is occuring
71 06 Jun 09 GKY Add option to show file system type or drive label in tree
72 28 Jun 09 GKY Added AddBackslashToPath() to remove repeatative code.
73 06 Jul 09 SHL Refactor .LONGNAME and .SUBJECT EA fetch to FetchCommonEAs
74 12 Jul 09 GKY Add szFSType to FillInRecordFromFSA use to bypass EA scan and size formatting
75 for tree container
76 13 Jul 09 SHL Avoid trap in FillInRecordFromFSA if pszFSType NULL
77 22 Jul 09 GKY Code changes to use semaphores to serialize drive scanning
78 22 Jul 09 GKY Consolidated driveflag setting code in DriveFlagsOne
79 22 Jul 09 GKY Streamline scanning code for faster Tree rescans
80 15 Sep 09 SHL Show rescan progress while filling container
81 26 Sep 09 SHL Add FreeCnrItemData debug code - do not let into the wild
82 13 Oct 09 SHL Avoid szDriver overflow in FillTreeCnr
83 13 Oct 09 SHL Restore missing drives in drive drop-down listbox; optimize updates
84 15 Nov 09 GKY Avoid szBuf overflow in FillTreeCnr
85 15 Nov 09 GKY Optimize some check code
86 17 JAN 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10).
87 Mostly cast CHAR CONSTANT * as CHAR *.
88 09 MAY 10 JBS Ticket 434 bug fixes, message box text improvements and parameter update
89 improvements.
90 20 Nov 10 GKY Rework scanning code to remove redundant scans, prevent double directory
91 entries in the tree container, fix related semaphore performance using
92 combination of event and mutex semaphores
93 30 May 11 GKY Fixed trap caused by passing a nonexistant pci to FillInRecordFromFFB in FillDir
94 because pci is limited to 65535 files. (nRecord is a USHORT) SHL's single loop
95 30 May 11 GKY Added SleepIfNeeded to DosFind and container load loops to improve WPS responsiveness
96 31 May 11 SHL Disable antique debug code in RemoveCnrItems - really speeds up container close
97 12 Jun 11 GKY Added IdleIfNeeded to the container "free" loops to improve system
98 responsiveness when closing containers with large numbers of items
99 12 Jun 11 GKY Replaced SleepIfNeeded with IdleIfNeeded in the container loade loop
100 22 Oct 11 GKY Removing unneeded UnFlesh call from StubbyThread appears to significantly speed opening of FM/2
101 02 Mar 14 GKY !didone for fFirstTime so the suggest code works again. Also clear out the
102 garbage that was appearing in the string.
103 02 Mar 14 GKY Speed up intial drive scans Ticket 528
104 19 Mar 14 SHL RemoveCnrItems: clean up odd code
105 22 Mar 14 GKY Reverted some code from the RemoveCnrItems changes adding a previously
106 missing break and comments explaining the code structure.
107 28 Jun 14 GKY Fix errors identified with CPPCheck
108 30 Aug 14 GKY Use saymsg2 for Suggest dialog
109 14 Jun 15 GKY Changes to prevent trap in Filter, heap corruption and traps associated with it
110 19 Jun 15 JBS Ticket 514: Double free fix (which also fixes a memory leak)
111 02 Aug 15 GKY Serialize local hard drive scanning to reduce drive thrashing continue to scan
112 all other drive types in separate threads.
113 02 Aug 15 GKY Remove unneeded SubbyScan code and improve suppression of blank lines and
114 duplicate subdirectory name caused by running Stubby in worker threads.
115 04 Aug 15 SHL Comments
116 04 Aug 15 SHL Move StubbyThread to flesh.c
117 07 Aug 15 SHL Rework to use AddFleshWorkRequest rather than direct calls to Stubby/Flesh/Unflesh
118 22 Aug 15 GKY Remove recurse scan code.
119 22 Aug 15 GKY Minimize the occurence of an A:\ Drive not ready error by moving the cursor
120 to the default drive.
121 24 Aug 15 GKY Remove fDummy code
122 20 Sep 15 GKY Add code for Flesh to skip the directory entry added by Stubby (eliminate
123 use of NULL/Nullstr pszFileNames by Stubby). Add code to relink pci chain
124 following rename, delete, etc. Add "Expanding" window text.
125 26 Sep 15 GKY Remove fInitialDriveScan code
126
127***********************************************************************/
128
129#include <stdlib.h>
130#include <string.h>
131#include <malloc.h> // _msize _heapchk
132#include <ctype.h>
133#include <limits.h>
134// #include <process.h> // _beginthread
135
136#define INCL_DOS
137#define INCL_WIN
138#define INCL_DOSERRORS
139#define INCL_LONGLONG
140
141#include "fm3dll.h"
142#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
143#include "draglist.h" // Data declaration(s)
144#include "treecnr.h" // Data declaration(s)
145#include "info.h" // Data declaration(s)
146#include "newview.h" // Data declaration(s)
147#include "mainwnd.h" // hwndDrivelist
148#include "fm3str.h"
149#include "filldir.h"
150#include "errutil.h" // Dos_Error...
151#include "strutil.h" // GetPString
152#include "misc.h" // GetTidForWindow
153#include "fortify.h" // 06 May 08 SHL
154#include "notebook.h" // INI file fields
155#include "flesh.h" // AddFleshWorkRequest
156#include "update.h" // SelectDriveIcon
157#include "valid.h" // CheckDrive
158#include "filter.h" // Filter
159#include "subj.h" // Subject
160#include "grep.h" // hwndStatus
161#include "copyf.h" // unlinkf
162#include "literal.h" // wildcard
163#include "i18nutil.h" // CommaFmtULL
164#include "wrappers.h" // xDosFindNext
165#include "init.h"
166#include "common.h"
167#include "excputil.h" // xbeginthread
168#include "fm3dlg.h" // INFO_LABEL
169#include "pathutil.h" // AddBackslashToPath
170#include "tmrsvcs.h" // ITIMER_DESC
171#if 0
172#define __PMPRINTF__
173#include "PMPRINTF.H"
174#endif
175
176// Data definitions
177static PSZ pszSrcFile = __FILE__;
178INT FixedVolume = 0;
179
180#pragma data_seg(GLOBAL1)
181HPOINTER hptrEnv;
182HPOINTER hptrHidden;
183HPOINTER hptrReadonly;
184HPOINTER hptrSystem;
185
186#pragma data_seg(GLOBAL2)
187PCSZ FM3Tools = "<FM3_Tools>";
188PCSZ WPProgram = "WPProgram";
189
190/**
191 * Return display string given standard file attribute mask
192 * @param fileAttr attribute mask in FILEFINDBUF format
193 * @return fixed length string for display
194 */
195
196const PSZ FileAttrToString(ULONG fileAttr)
197{
198 // From os2win.h
199 // FILE_ATTRIBUTE_READONLY 0x00000001
200 // FILE_ATTRIBUTE_HIDDEN 0x00000002
201 // FILE_ATTRIBUTE_SYSTEM 0x00000004
202 // 0x00000008
203 // FILE_ATTRIBUTE_DIRECTORY 0x00000010
204 // FILE_ATTRIBUTE_ARCHIVE 0x00000020
205
206 static CHAR *apszAttrString[] = {
207 // RHSDA
208 "-----",
209 "R----",
210 "-H---",
211 "RH---",
212 "--S--",
213 "R-S--",
214 "-HS--",
215 "RHS--",
216 "---D-",
217 "R--D-",
218 "-H-D-",
219 "RH-D-",
220 "--SD-",
221 "R-SD-",
222 "-HSD-",
223 "RHSD-",
224 "----A",
225 "R---A",
226 "-H--A",
227 "RH--A",
228 "--S-A",
229 "R-S-A",
230 "-HS-A",
231 "RHS-A",
232 "---DA",
233 "R--DA",
234 "-H-DA",
235 "RH-DA",
236 "--SDA",
237 "R-SDA",
238 "-HSDA",
239 "RHSDA"
240 };
241
242 fileAttr = ((fileAttr & 0x30) >> 1) | (fileAttr & 7); // Drop don't care bit from index
243
244 return apszAttrString[fileAttr];
245
246}
247
248HPOINTER IDFile(PSZ p)
249{
250 HPOINTER hptr;
251 ULONG cmp;
252 CHAR cmps[6];
253
254 p = strrchr(p, '.');
255 if (p) {
256 cmps[0] = '.';
257 cmps[1] = toupper(p[1]);
258 cmps[2] = toupper(p[2]);
259 cmps[3] = toupper(p[3]);
260 if (p[4]) {
261 cmps[4] = toupper(p[4]);
262 cmps[5] = 0;
263 }
264 else
265 cmps[4] = 0;
266
267 cmp = *(ULONG *) cmps;
268
269 if (cmp == *(ULONG *) PCSZ_DOTEXE || cmp == *(ULONG *) PCSZ_DOTCMD ||
270 cmp == *(ULONG *) PCSZ_DOTBAT || cmp == *(ULONG *) PCSZ_DOTCOM ||
271 cmp == *(ULONG *) PCSZ_DOTBTM)
272 hptr = hptrApp;
273 else if (cmp == *(ULONG *) ".ZIP" || cmp == *(ULONG *) ".LZH" ||
274 cmp == *(ULONG *) ".ARJ" || cmp == *(ULONG *) ".ARC" ||
275 cmp == *(ULONG *) ".ZOO" || cmp == *(ULONG *) ".RAR" ||
276 cmp == *(ULONG *) ".TAR" || cmp == *(ULONG *) ".TGZ" ||
277 cmp == *(ULONG *) ".GZ" || cmp == *(ULONG *) ".Z" ||
278 cmp == *(ULONG *) ".CAB" || cmp == *(ULONG *) ".BZ2" ||
279 cmp == *(ULONG *) ".WPI" || cmp == *(ULONG *) ".7Z")
280 hptr = hptrArc;
281 else if (cmp == *(ULONG *) PCSZ_DOTBMP ||
282 cmp == *(ULONG *) PCSZ_DOTICO ||
283 cmp == *(ULONG *) PCSZ_DOTPTR ||
284 cmp == *(ULONG *) PCSZ_DOTJPEG ||
285 cmp == *(ULONG *) PCSZ_DOTJPG ||
286 cmp == *(ULONG *) ".GIF" ||
287 cmp == *(ULONG *) ".TIF" || cmp == *(ULONG *) ".PCX" ||
288 cmp == *(ULONG *) ".TGA" || cmp == *(ULONG *) ".XBM" ||
289 cmp == *(ULONG *) ".PNG" || cmp == *(ULONG *) ".PSD" ||
290 cmp == *(ULONG *) ".LGO" || cmp == *(ULONG *) ".EPS" ||
291 cmp == *(ULONG *) ".RLE" || cmp == *(ULONG *) ".RAS" ||
292 cmp == *(ULONG *) ".PLC" || cmp == *(ULONG *) ".MSP" ||
293 cmp == *(ULONG *) ".IFF" || cmp == *(ULONG *) ".FIT" ||
294 cmp == *(ULONG *) ".DCX" || cmp == *(ULONG *) ".MAC" ||
295 cmp == *(ULONG *) ".SFF" || cmp == *(ULONG *) ".SGI" ||
296 cmp == *(ULONG *) ".XWD" || cmp == *(ULONG *) ".XPM" ||
297 cmp == *(ULONG *) ".WPG" || cmp == *(ULONG *) ".CUR" ||
298 cmp == *(ULONG *) ".PNM" || cmp == *(ULONG *) ".PPM" ||
299 cmp == *(ULONG *) ".PGM" || cmp == *(ULONG *) ".PBM")
300 hptr = hptrArt;
301 else
302 hptr = (HPOINTER) 0;
303 }
304 else
305 hptr = (HPOINTER) 0;
306
307 return hptr;
308}
309
310BOOL IsDefaultIcon(HPOINTER hptr)
311{
312 HPOINTER hptr2;
313 HPOINTER hptr3;
314 UINT u;
315
316 static HPOINTER hptrPMFile;
317 static HPOINTER hptrWPSFile;
318
319 if (!hptrPMFile) {
320 hptrPMFile = WinQuerySysPointer(HWND_DESKTOP, SPTR_FILE, FALSE);
321 }
322
323 // try to guess WPS default file icon
324 hptr2 = (HPOINTER) 0;
325 for (u = 0; !hptrWPSFile && u < 10; u++) {
326 char szFileName[CCHMAXPATH];
327 char *psz;
328
329 if (pTmpDir) {
330 psz = pTmpDir;
331 strcpy(szFileName, psz);
332 psz = szFileName + strlen(szFileName) - 1;
333 if (*psz != '\\') {
334 psz++;
335 *psz++ = '\\';
336 }
337 }
338 else
339 psz = szFileName;
340
341 sprintf(psz, "%08x.%03x", rand() & 0xffffffff, rand() & 0xfff);
342 if (IsFile(szFileName) != 1) {
343 FILE *fp;
344 CHAR *modew = "w";
345
346 fp = xfopen(szFileName, modew, pszSrcFile, __LINE__, TRUE);
347
348 if (fp) {
349 fclose(fp);
350 hptr3 = WinLoadFileIcon(szFileName, FALSE);
351 unlinkf(szFileName);
352 if (!hptr2)
353 hptr2 = hptr3;
354 else if (hptr3 == hptr3) {
355 hptrWPSFile = hptr3; // Got same icon twice
356 break;
357 }
358 }
359 }
360 DosSleep(rand() % 100);
361
362 } // for
363
364 return hptr == hptrPMFile || hptr == hptrWPSFile;
365
366} // IsDefaultIcon
367
368static VOID FetchCommonEAs(PCNRITEM pci)
369{
370 ULONG flags = driveflags[toupper(*pci->pszFileName) - 'A'];
371 BOOL fLoadSubjectForDrive = fLoadSubject && ~flags & DRIVE_NOLOADSUBJS;
372 BOOL fLoadLongNameForDrive = fLoadLongnames && //~flags & DRIVE_NOLONGNAMES &&
373 ~flags & DRIVE_NOLOADLONGS;
374 if (fLoadSubjectForDrive || fLoadLongNameForDrive) {
375 // Allocate space to hold GEA2s and .SUBJECT and .LONGNAME strings
376 PGEA2LIST pgealist = xmallocz(sizeof(GEA2LIST) + (sizeof(GEA2) * 2) + 32,
377 pszSrcFile, __LINE__);
378 if (pgealist) {
379 APIRET rc;
380 PFEA2LIST pfealist;
381 ULONG offset;
382 PGEA2 pgeaPrev = NULL;
383 PGEA2 pgea = pgealist->list; // Point at first available
384 EAOP2 eaop;
385 UINT state;
386 for (state = 0; state < 2; state++) {
387 PCSZ pcsz;
388 switch (state) {
389 case 0:
390 pcsz = fLoadSubjectForDrive ? SUBJECT : NULL;
391 break;
392 case 1:
393 pcsz = fLoadLongNameForDrive ? LONGNAME : NULL;
394 break;
395 }
396 if (pcsz) {
397 if (pgeaPrev) {
398 pgeaPrev->oNextEntryOffset = (PSZ)pgea - (PSZ)pgeaPrev;
399 }
400 strcpy(pgea->szName, pcsz);
401 pgea->cbName = strlen(pgea->szName);
402 pgea->oNextEntryOffset = 0;
403 offset = sizeof(GEA2) + pgea->cbName; // Calc length including null
404 offset = (offset + 3) & ~3; // Doubleword align
405 pgeaPrev = pgea;
406 pgea = (PGEA2)((PSZ)pgea + offset); // Point at next available
407 }
408 } // for
409 pgealist->cbList = (PSZ)pgea - (PSZ)pgealist;
410 pfealist = xmallocz(65536, pszSrcFile, __LINE__);
411 if (pfealist) {
412 pfealist->cbList = 65536;
413 eaop.fpGEA2List = pgealist;
414 eaop.fpFEA2List = pfealist;
415 eaop.oError = 0;
416 rc = DosQueryPathInfo(pci->pszFileName, FIL_QUERYEASFROMLIST,
417 (PVOID) &eaop, (ULONG) sizeof(EAOP2));
418 // Prevent this error from occuring when scanning a directory
419 // that contains a locked data file
420 if (rc && rc != ERROR_SHARING_VIOLATION) {
421 CHAR s[80];
422 sprintf(s, "%s %s",PCSZ_DOSQUERYPATHINFO, "%s");
423 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
424 s, pci->pszFileName);
425 }
426 else {
427 PFEA2 pfea = eaop.fpFEA2List->list;
428 while (pfea) {
429 if (pfea->cbValue) {
430 CHAR *achValue = pfea->szName + pfea->cbName + 1;
431 if (*(USHORT *)achValue != EAT_ASCII)
432 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
433 GetPString(IDS_ERROREATYPETEXT),
434 achValue, pfea->cbName, pfea->szName);
435 else {
436 CHAR ch = achValue[pfea->cbValue];
437 PSZ pszValue;
438 achValue[pfea->cbValue] = 0;
439 pszValue = xstrdup(achValue + (sizeof(USHORT) * 2), pszSrcFile, __LINE__);
440 achValue[pfea->cbValue] = ch;
441 if (strncmp(pfea->szName, LONGNAME, pfea->cbName) == 0)
442 pci->pszLongName = pszValue;
443 else if (strncmp(pfea->szName, SUBJECT, pfea->cbName) == 0)
444 pci->pszSubject = pszValue;
445 else
446 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
447 GetPString(IDS_ERROREATYPETEXT), pfea, pfea->cbName, pfea->szName);
448 }
449 }
450 if (!pfea->oNextEntryOffset)
451 break;
452 pfea = (PFEA2)((PSZ)pfea + pfea->oNextEntryOffset);
453 } // while
454 }
455 free(pfealist);
456 }
457 free(pgealist);
458 }
459 }
460} // FetchCommonEAs
461
462ULONGLONG FillInRecordFromFFB(HWND hwndCnr,
463 PCNRITEM pci,
464 const PSZ pszDirectory,
465 const PFILEFINDBUF4L pffb,
466 const BOOL partial,
467 DIRCNRDATA *dcd)
468{
469 // fill in a container record from a FILEFINDBUF4L structure
470
471 CHAR *p;
472 HPOINTER hptr;
473 ULONG flags;
474
475 pci->hwndCnr = hwndCnr;
476
477 /**
478 * note that we cheat below, and accept the full pathname in pszDirectory
479 * if !*pffb->achName. This speeds up and simplifies processing elsewhere
480 * (like in update.c)
481 */
482
483 if (!*pffb->achName) {
484 pci->pszFileName = xstrdup(pszDirectory, pszSrcFile, __LINE__);
485 }
486 else {
487 INT c = strlen(pszDirectory);
488 INT c2 = pffb->cchName + 1;
489 if (pszDirectory[c - 1] != '\\')
490 c2++;
491 pci->pszFileName = xmalloc(c + c2, pszSrcFile, __LINE__);
492# ifdef FORTIFY
493 {
494 if (dcd->type != TREE_FRAME)
495 Fortify_ChangeScope(pci->pszFileName, -1);
496 else {
497 Fortify_SetOwner(pci->pszFileName, 1);
498 Fortify_SetScope(pci->pszFileName, 2);
499 }
500 }
501# endif
502 memcpy(pci->pszFileName, pszDirectory, c + 1);
503 p = pci->pszFileName + c - 1;
504 if (*p != '\\') {
505 p++;
506 *p = '\\';
507 }
508 p++;
509 memcpy(p, pffb->achName, pffb->cchName + 1);
510 }
511
512 // load Subject and/or Longname EAs, if required and have EAs
513 if (pffb->cbList > 4L && dcd &&
514 !(driveflags[toupper(*pci->pszFileName) - 'A'] & DRIVE_NOEASUPPORT))
515 FetchCommonEAs(pci);
516
517 if (!pci->pszSubject)
518 pci->pszSubject = NullStr;
519
520 // load the object's longname
521 if (!pci->pszLongName)
522 pci->pszLongName = NullStr;
523
524 // do anything required to case of filename
525 if (fForceUpper)
526 strupr(pci->pszFileName);
527 else if (fForceLower)
528 strlwr(pci->pszFileName);
529
530 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
531
532 // get an icon to use with it
533 if (pffb->attrFile & FILE_DIRECTORY) {
534 // is directory
535 if (fNoIconsDirs ||
536 (flags & DRIVE_NOLOADICONS) ||
537 !isalpha(*pci->pszFileName)) {
538 hptr = (HPOINTER) 0;
539 }
540 else
541 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
542 }
543 else {
544 // is file
545 if (fNoIconsFiles ||
546 (flags & DRIVE_NOLOADICONS) ||
547 !isalpha(*pci->pszFileName)) {
548 hptr = (HPOINTER) 0;
549 }
550 else
551 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
552
553 if (!hptr || IsDefaultIcon(hptr))
554 hptr = IDFile(pci->pszFileName);
555 }
556
557 if (!hptr) {
558 hptr = pffb->attrFile & FILE_DIRECTORY ?
559 hptrDir : pffb->attrFile & FILE_SYSTEM ?
560 hptrSystem : pffb->attrFile & FILE_HIDDEN ?
561 hptrHidden : pffb->attrFile & FILE_READONLY ?
562 hptrReadonly : hptrFile;
563 }
564
565 // Tell container what part of pathname to display
566 if (partial) {
567 p = strrchr(pci->pszFileName, '\\');
568 if (!p) {
569 p = strrchr(pci->pszFileName, ':');
570 if (!p)
571 p = pci->pszFileName;
572 else
573 p++;
574 }
575 else if ((dcd && dcd->type == TREE_FRAME) ||
576 (!(pffb->attrFile & FILE_DIRECTORY) || !*(p + 1))) {
577 p++;
578 }
579 if (!*p)
580 p = pci->pszFileName;
581 }
582 else
583 p = pci->pszFileName;
584 pci->pszDisplayName = p;
585
586 // Comma format the file size for large file support
587 {
588 CHAR szBuf[30];
589 CommaFmtULL(szBuf, sizeof(szBuf), pffb->cbFile, ' ');
590 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
591# ifdef FORTIFY
592 {
593 UINT tid = GetTidForWindow(hwndCnr);
594 if (tid == 1)
595 Fortify_ChangeScope(pci->pszFmtFileSize, -1);
596 else
597 Fortify_SetOwner(pci->pszFmtFileSize, 1);
598 }
599# endif
600 }
601
602 // now fill the darned thing in...
603 pci->date.day = pffb->fdateLastWrite.day;
604 pci->date.month = pffb->fdateLastWrite.month;
605 pci->date.year = pffb->fdateLastWrite.year + 1980;
606 pci->time.seconds = pffb->ftimeLastWrite.twosecs * 2;
607 pci->time.minutes = pffb->ftimeLastWrite.minutes;
608 pci->time.hours = pffb->ftimeLastWrite.hours;
609 pci->ladate.day = pffb->fdateLastAccess.day;
610 pci->ladate.month = pffb->fdateLastAccess.month;
611 pci->ladate.year = pffb->fdateLastAccess.year + 1980;
612 pci->latime.seconds = pffb->ftimeLastAccess.twosecs * 2;
613 pci->latime.minutes = pffb->ftimeLastAccess.minutes;
614 pci->latime.hours = pffb->ftimeLastAccess.hours;
615 pci->crdate.day = pffb->fdateCreation.day;
616 pci->crdate.month = pffb->fdateCreation.month;
617 pci->crdate.year = pffb->fdateCreation.year + 1980;
618 pci->crtime.seconds = pffb->ftimeCreation.twosecs * 2;
619 pci->crtime.minutes = pffb->ftimeCreation.minutes;
620 pci->crtime.hours = pffb->ftimeCreation.hours;
621 pci->easize = CBLIST_TO_EASIZE(pffb->cbList);
622 pci->cbFile = pffb->cbFile;
623 pci->attrFile = pffb->attrFile;
624 pci->pszDispAttr = FileAttrToString(pci->attrFile);
625 pci->rc.pszIcon = pci->pszDisplayName;
626 pci->rc.hptrIcon = hptr;
627
628
629 // check to see if record should be visible
630 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
631 if (dcd && (*dcd->mask.szMask || dcd->mask.antiattr ||
632 ((dcd->mask.attrFile &
633 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED))
634 != (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)))) {
635 if (*dcd->mask.szMask || dcd->mask.antiattr) {
636 if (!Filter((PMINIRECORDCORE) pci, (PVOID) & dcd->mask))
637 pci->rc.flRecordAttr |= CRA_FILTERED;
638 }
639 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
640 (pci->attrFile & FILE_HIDDEN)) ||
641 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
642 (pci->attrFile & FILE_SYSTEM)) ||
643 (!(dcd->mask.attrFile & FILE_READONLY) &&
644 (pci->attrFile & FILE_READONLY)) ||
645 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
646 (pci->attrFile & FILE_ARCHIVED))) {
647 pci->rc.flRecordAttr |= CRA_FILTERED;
648 }
649 }
650 DosReleaseMutexSem(hmtxFiltering);
651
652 return pffb->cbFile + pci->easize;
653
654} // FillInRecordFromFFB
655
656ULONGLONG FillInRecordFromFSA(HWND hwndCnr,
657 PCNRITEM pci,
658 const PSZ pszFileName,
659 const PFILESTATUS4L pfsa4,
660 const BOOL partial,
661 CHAR *pszFSType, // Optional
662 DIRCNRDATA *dcd) // Optional
663{
664 HPOINTER hptr;
665 ULONG flags;
666 CHAR *p;
667 CHAR szBuf[CCHMAXPATH];
668
669 // fill in a container record from a FILESTATUS4L structure
670
671 pci->hwndCnr = hwndCnr;
672 pci->pszFileName = xstrdup(pszFileName, pszSrcFile, __LINE__);
673
674 // 13 Jul 09 SHL FIXME to know if fetch can be bypassed if pszFSType already filled
675 // If FSType not supplied, assume don't need EAs either
676 if (pfsa4->cbList > 4L && dcd &&
677 !(driveflags[toupper(*pci->pszFileName) - 'A'] & DRIVE_NOEASUPPORT))
678 FetchCommonEAs(pci);
679
680 if (!pci->pszSubject)
681 pci->pszSubject = NullStr;
682 if (!pci->pszLongName)
683 pci->pszLongName = NullStr;
684
685 if (fForceUpper)
686 strupr(pci->pszFileName);
687 else if (fForceLower)
688 strlwr(pci->pszFileName);
689
690 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
691
692 if (pfsa4->attrFile & FILE_DIRECTORY) {
693 if (fNoIconsDirs ||
694 (flags & DRIVE_NOLOADICONS) ||
695 !isalpha(*pci->pszFileName)) {
696 hptr = (HPOINTER) 0;
697 }
698 else
699 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
700 }
701 else {
702 if (fNoIconsFiles ||
703 (flags & DRIVE_NOLOADICONS) ||
704 !isalpha(*pci->pszFileName)) {
705 hptr = IDFile(pci->pszFileName);
706 }
707 else
708 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
709 }
710 if (!hptr) {
711 hptr = pfsa4->attrFile & FILE_DIRECTORY ?
712 hptrDir :
713 pfsa4->attrFile & FILE_SYSTEM ?
714 hptrSystem :
715 pfsa4->attrFile & FILE_HIDDEN ?
716 hptrHidden : pfsa4->attrFile & FILE_READONLY ? hptrReadonly : hptrFile;
717 }
718
719 // Tell container what part of pathname to display
720 if (partial) {
721 p = strrchr(pci->pszFileName, '\\');
722 if (!p) {
723 p = strrchr(pci->pszFileName, ':');
724 if (!p)
725 p = pci->pszFileName;
726 else
727 p++;
728 }
729 else if ((dcd && dcd->type == TREE_FRAME) ||
730 !(pfsa4->attrFile & FILE_DIRECTORY) || !*(p + 1))
731 p++;
732 if (!*p)
733 p = pci->pszFileName;
734 }
735 else
736 p = pci->pszFileName;
737 if (pszFSType && (fShowFSTypeInTree || fShowDriveLabelInTree)) {
738 strcpy(szBuf, p);
739 strcat(szBuf, " [");
740 strcat(szBuf, pszFSType);
741 strcat(szBuf, "]");
742 pci->pszDisplayName = xstrdup(szBuf, pszSrcFile, __LINE__);
743 }
744 else
745 pci->pszDisplayName = p;
746
747 // 13 Jul 09 SHL FIXME to know why pszFSType check needed
748 // comma format the file size for large file support
749 if (!pszFSType || *pszFSType == 0) {
750 CHAR szBuf[30];
751 CommaFmtULL(szBuf, sizeof(szBuf), pfsa4->cbFile, ' ');
752 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
753# ifdef FORTIFY
754 {
755 if (dcd && dcd->type == TREE_FRAME) {
756 // Will be freed in TreeCnrWndProc WM_DESTROY
757 // Fortify_SetOwner(pci->pszFmtFileSize, 1);
758 Fortify_SetScope(pci->pszFmtFileSize, 2);
759 }
760 }
761# endif
762 }
763 else {
764 pci->pszFmtFileSize = NullStr;
765 }
766 pci->date.day = pfsa4->fdateLastWrite.day;
767 pci->date.month = pfsa4->fdateLastWrite.month;
768 pci->date.year = pfsa4->fdateLastWrite.year + 1980;
769 pci->time.seconds = pfsa4->ftimeLastWrite.twosecs * 2;
770 pci->time.minutes = pfsa4->ftimeLastWrite.minutes;
771 pci->time.hours = pfsa4->ftimeLastWrite.hours;
772 pci->ladate.day = pfsa4->fdateLastAccess.day;
773 pci->ladate.month = pfsa4->fdateLastAccess.month;
774 pci->ladate.year = pfsa4->fdateLastAccess.year + 1980;
775 pci->latime.seconds = pfsa4->ftimeLastAccess.twosecs * 2;
776 pci->latime.minutes = pfsa4->ftimeLastAccess.minutes;
777 pci->latime.hours = pfsa4->ftimeLastAccess.hours;
778 pci->crdate.day = pfsa4->fdateCreation.day;
779 pci->crdate.month = pfsa4->fdateCreation.month;
780 pci->crdate.year = pfsa4->fdateCreation.year + 1980;
781 pci->crtime.seconds = pfsa4->ftimeCreation.twosecs * 2;
782 pci->crtime.minutes = pfsa4->ftimeCreation.minutes;
783 pci->crtime.hours = pfsa4->ftimeCreation.hours;
784 pci->easize = CBLIST_TO_EASIZE(pfsa4->cbList);
785 pci->cbFile = pfsa4->cbFile;
786 pci->attrFile = pfsa4->attrFile;
787 pci->pszDispAttr = FileAttrToString(pci->attrFile);
788 pci->rc.pszIcon = pci->pszDisplayName;
789 pci->rc.hptrIcon = hptr;
790
791 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
792 if (dcd &&
793 (*dcd->mask.szMask || dcd->mask.antiattr ||
794 ((dcd->mask.attrFile &
795 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)) !=
796 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)))) {
797 if (*dcd->mask.szMask || dcd->mask.antiattr) {
798 if (!Filter((PMINIRECORDCORE) pci, (PVOID) & dcd->mask))
799 pci->rc.flRecordAttr |= CRA_FILTERED;
800 }
801 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
802 (pci->attrFile & FILE_HIDDEN)) ||
803 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
804 (pci->attrFile & FILE_SYSTEM)) ||
805 (!(dcd->mask.attrFile & FILE_READONLY) &&
806 (pci->attrFile & FILE_READONLY)) ||
807 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
808 (pci->attrFile & FILE_ARCHIVED)))
809 pci->rc.flRecordAttr |= CRA_FILTERED;
810 }
811 DosReleaseMutexSem(hmtxFiltering);
812
813 return pfsa4->cbFile + pci->easize;
814
815} // FillInRecordFromFSA
816
817VOID ProcessDirectory(const HWND hwndCnr,
818 const PCNRITEM pciParent,
819 const CHAR *szDirBase,
820 const BOOL filestoo,
821 const BOOL recurse,
822 const BOOL partial,
823 CHAR *stopflag,
824 DIRCNRDATA *dcd, // Optional
825 ULONG *pulTotalFiles, // Optional
826 PULONGLONG pullTotalBytes, // Optional
827 CHAR *LoadedFirstChild) // Optional
828{
829 /**
830 * put all the directories (and files if filestoo is TRUE) from a
831 * directory into the container. recurse through subdirectories if
832 * recurse is TRUE.
833 */
834
835 PSZ pszFileSpec;
836 PFILEFINDBUF4L paffbFound;
837 PFILEFINDBUF4L *papffbSelected;
838 PFILEFINDBUF4L pffbFile;
839 PFILEFINDBUF4L paffbTotal = NULL;
840 PFILEFINDBUF4L paffbTemp;
841 HDIR hdir = HDIR_CREATE;
842 ULONG ulFindCnt;
843 ULONG ulFindMax;
844 ULONG ulSelCnt;
845 ULONG cAffbTotal = 0;
846 ULONGLONG ullBytes;
847 ULONGLONG ullTotalBytes;
848 ULONG ulReturnFiles = 0;
849 ULONGLONG ullReturnBytes = 0;
850 APIRET rc;
851 PCNRITEM pci;
852 PCNRITEM pciFirst;
853 PCNRITEM pciNext;
854 RECORDINSERT ri;
855 BOOL ok = TRUE;
856 ULONG ulBufBytes;
857 ULONG x;
858 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
859
860 if (isalpha(*szDirBase) && szDirBase[1] == ':' && szDirBase[2] == '\\') {
861 if ((driveflags[toupper(*szDirBase) - 'A'] & DRIVE_REMOTE) && fRemoteBug)
862 ulFindMax = 1; // file system gets confused
863 else if (driveflags[toupper(*szDirBase) - 'A'] & DRIVE_ZIPSTREAM)
864 ulFindMax = min(FilesToGet, 225); // anything more is wasted
865 else
866 ulFindMax = FilesToGet; // full-out
867 }
868 else
869 ulFindMax = FilesToGet;
870
871 if (OS2ver[0] == 20 && OS2ver[1] < 30)
872 ulFindMax = min(ulFindMax, (65535 / sizeof(FILEFINDBUF4L)));
873
874 ulBufBytes = ulFindMax * sizeof(FILEFINDBUF4L);
875
876 pszFileSpec = xmalloc(CCHMAXPATH + 2, pszSrcFile, __LINE__);
877 paffbFound = xmalloc(ulBufBytes, pszSrcFile, __LINE__);
878 papffbSelected = xmalloc(sizeof(PFILEFINDBUF4L) * ulFindMax, pszSrcFile, __LINE__);
879
880 if (paffbFound && papffbSelected && pszFileSpec) {
881 strcpy(pszFileSpec, szDirBase);
882 AddBackslashToPath(pszFileSpec);
883 strcat(pszFileSpec, "*");
884 DosError(FERR_DISABLEHARDERR);
885 ulFindCnt = ulFindMax;
886 rc = xDosFindFirst(pszFileSpec,
887 &hdir,
888 FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
889 FILE_SYSTEM | FILE_HIDDEN |
890 (filestoo ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY),
891 paffbFound,
892 ulBufBytes,
893 &ulFindCnt,
894 FIL_QUERYEASIZEL);
895 priority_normal();
896 pszFileSpec[strlen(pszFileSpec) - 1] = 0; // Chop off wildcard
897 if (!rc) {
898 InitITimer(&itdSleep, 500);
899 do {
900 /**
901 * remove . and .. and directories already added
902 * by Stubby from list if present
903 * also counter file system bugs that sometimes
904 * allows normal files to slip through when
905 * only directories should appear (only a few
906 * network file systems exhibit such a problem).
907 */
908
909 if (stopflag && *stopflag)
910 goto Abort;
911 pffbFile = paffbFound;
912 ulSelCnt = 0;
913 for (;;) {
914 if (!*pffbFile->achName ||
915 (!filestoo && ~pffbFile->attrFile & FILE_DIRECTORY) ||
916 (pffbFile->attrFile & FILE_DIRECTORY &&
917 !pffbFile->achName[0] || pffbFile->achName[0] == '.' &&
918 (!pffbFile->achName[1] ||
919 (pffbFile->achName[1] == '.' && !pffbFile->achName[2])) ||
920 (LoadedFirstChild && !stricmp(LoadedFirstChild, pffbFile->achName)))) {
921 // ulFindCnt--; // Got . or .. or file to be skipped
922 }
923 else
924 papffbSelected[ulSelCnt++] = pffbFile; // Remember selected file
925 if (!pffbFile->oNextEntryOffset) {
926 // ulFindCnt = ulSelCnt; // Remember number selected
927 break;
928 }
929 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + pffbFile->oNextEntryOffset);
930 } // for
931 if (ulSelCnt) {
932 // One or more entries selected
933 if (stopflag && *stopflag)
934 goto Abort;
935 if (fSyncUpdates) {
936 if (!WinIsWindow(WinQueryAnchorBlock(hwndCnr), hwndCnr)) {
937 ok = FALSE;
938 ullTotalBytes = 0;
939 break;
940 }
941 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
942 MPFROMLONG(EXTRA_RECORD_BYTES),
943 MPFROMLONG(ulSelCnt));
944 if (!pciFirst) {
945 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
946 GetPString(IDS_CMALLOCRECERRTEXT));
947 ok = FALSE;
948 ullTotalBytes = 0;
949 }
950 else {
951 // 04 Jan 08 SHL FIXME like comp.c to handle less than ulSelCnt records
952 pci = pciFirst;
953 ullTotalBytes = 0;
954 // Finish filling pci items
955 for (x = 0; x < ulSelCnt; x++) {
956 pffbFile = papffbSelected[x];
957 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
958 pffbFile, partial, dcd);
959 pciNext = pci;
960 pci = (PCNRITEM) pci->rc.preccNextRecord;
961 if (pci && (INT) pci != -1)
962 pci->pciPrevious = pciNext;
963 ullTotalBytes += ullBytes;
964 } // for
965 // Insert selected in container
966 memset(&ri, 0, sizeof(RECORDINSERT));
967 ri.cb = sizeof(RECORDINSERT);
968 ri.pRecordOrder = (PRECORDCORE) CMA_END;
969 ri.pRecordParent = (PRECORDCORE) pciParent;
970 ri.zOrder = (ULONG) CMA_TOP;
971 ri.cRecordsInsert = ulSelCnt;
972 ri.fInvalidateRecord = TRUE;
973 if (!WinSendMsg(hwndCnr,
974 CM_INSERTRECORD,
975 MPFROMP(pciFirst), MPFROMP(&ri))) {
976 DosSleep(10); // Give GUI time to work
977 WinSetFocus(HWND_DESKTOP, hwndCnr);
978 // Retry
979 if (!WinSendMsg(hwndCnr,
980 CM_INSERTRECORD,
981 MPFROMP(pciFirst), MPFROMP(&ri))) {
982 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
983 GetPString(IDS_CMINSERTERRTEXT));
984 ok = FALSE;
985 ullTotalBytes = 0;
986 if (WinIsWindow((HAB) 0, hwndCnr))
987 FreeCnrItemList(hwndCnr, pciFirst);
988 }
989 }
990 }
991 if (ok) {
992 ullReturnBytes += ullTotalBytes;
993 ulReturnFiles += ulSelCnt;
994 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
995 if (dcd) {
996 dcd->totalfiles += ulSelCnt;
997 dcd->ullTotalBytes += ullTotalBytes;
998 }
999 DosReleaseMutexSem(hmtxFiltering);
1000 }
1001 } // if sync updates
1002 else {
1003 // Append newly selected entries to aggregate list
1004 paffbTemp = xrealloc(paffbTotal,
1005 sizeof(FILEFINDBUF4L) * (ulSelCnt + cAffbTotal),
1006 pszSrcFile, __LINE__);
1007 if (paffbTemp) {
1008 // 13 Aug 07 SHL FIXME to optimize copy
1009 paffbTotal = paffbTemp;
1010 ullTotalBytes = 0; // 15 Sep 09 SHL
1011 for (x = 0; x < ulSelCnt; x++) {
1012 paffbTotal[x + cAffbTotal] = *papffbSelected[x];
1013 ullTotalBytes += papffbSelected[x]->cbFile;
1014 }
1015 cAffbTotal += ulSelCnt;
1016 }
1017 else {
1018 saymsg(MB_ENTER,
1019 HWND_DESKTOP,
1020 GetPString(IDS_ERRORTEXT), GetPString(IDS_OUTOFMEMORY));
1021 break;
1022 }
1023 }
1024 } // if entries selected
1025 if (stopflag && *stopflag)
1026 goto Abort;
1027 DosError(FERR_DISABLEHARDERR);
1028 ulFindCnt = ulFindMax;
1029 rc = xDosFindNext(hdir, paffbFound, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
1030 priority_normal();
1031 if (rc)
1032 DosError(FERR_DISABLEHARDERR);
1033 SleepIfNeeded(&itdSleep, 1);
1034 } while (!rc);
1035
1036 DosFindClose(hdir);
1037 xfree(paffbFound, pszSrcFile, __LINE__);
1038 paffbFound = NULL;
1039 xfree(papffbSelected, pszSrcFile, __LINE__);
1040 papffbSelected = NULL;
1041
1042 if (cAffbTotal && paffbTotal) {
1043 // Not fSyncUpdates and have work
1044 if (stopflag && *stopflag)
1045 goto Abort;
1046
1047 InitITimer(&itdSleep, 500);
1048 pci = NULL;
1049 ullTotalBytes = 0;
1050 pffbFile = paffbTotal;
1051 for (x = 0; x < cAffbTotal; x++) {
1052 ULONG ulRecsToInsert;
1053
1054 if (pci == NULL) {
1055 if (!WinIsWindow(WinQueryAnchorBlock(hwndCnr), hwndCnr)) {
1056 ok = FALSE;
1057 ullTotalBytes = 0;
1058 break;
1059 }
1060 ulRecsToInsert = cAffbTotal - x < USHRT_MAX ? cAffbTotal - x : USHRT_MAX;
1061 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
1062 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(ulRecsToInsert));
1063
1064 if (!pciFirst) {
1065 //ERRORID erridErrorCode = WinGetLastError(WinQueryAnchorBlock(hwndCnr));
1066 //PmpfF(("Allocation failed %i", erridErrorCode));
1067 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1068 GetPString(IDS_CMALLOCRECERRTEXT));
1069 ok = FALSE;
1070 ullTotalBytes = 0;
1071 break;
1072 }
1073 else {
1074 // 04 Jan 08 SHL FIXME like comp.c to handle less than ulSelCnt records
1075 if (hwndStatus && dcd && dcd->hwndFrame ==
1076 WinQueryActiveWindow(dcd->hwndParent)) {
1077 WinSetWindowText(hwndStatus, (CHAR *) GetPString(LoadedFirstChild ?
1078 IDS_PLEASEWAITEXPANDINGTEXT :
1079 IDS_PLEASEWAITCOUNTINGTEXT));
1080 }
1081 pci = pciFirst;
1082 }
1083 }
1084 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1085 pffbFile, partial, dcd);
1086 pciNext = pci;
1087 pci = (PCNRITEM) pci->rc.preccNextRecord;
1088 if (pci && (INT) pci != -1)
1089 pci->pciPrevious = pciNext;
1090 ullTotalBytes += ullBytes;
1091 // 15 Sep 09 SHL allow timed updates to see
1092 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
1093 if (dcd) {
1094 dcd->totalfiles = x;
1095 dcd->ullTotalBytes = ullTotalBytes;
1096 }
1097 DosReleaseMutexSem(hmtxFiltering);
1098 // Can not use offset since we have merged lists - this should be equivalent
1099 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + sizeof(FILEFINDBUF4L));
1100
1101 if (!IdleIfNeeded(&itdSleep, 30)) {
1102 for (x = x+1; x < cAffbTotal; x++) {
1103 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1104 pffbFile, partial, dcd);
1105 pci = (PCNRITEM) pci->rc.preccNextRecord;
1106 ullTotalBytes += ullBytes;
1107 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
1108 if (dcd) {
1109 dcd->totalfiles = x;
1110 dcd->ullTotalBytes = ullTotalBytes;
1111 }
1112 DosReleaseMutexSem(hmtxFiltering);
1113 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + sizeof(FILEFINDBUF4L));
1114 if (pci == NULL) {
1115 priority_normal();
1116 InitITimer(&itdSleep, 500);
1117 break;
1118 }
1119 }
1120 }
1121
1122 if (pci == NULL && ulRecsToInsert) {
1123 memset(&ri, 0, sizeof(RECORDINSERT));
1124 ri.cb = sizeof(RECORDINSERT);
1125 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1126 ri.pRecordParent = (PRECORDCORE) pciParent;
1127 ri.zOrder = (ULONG) CMA_TOP;
1128 ri.cRecordsInsert = ulRecsToInsert;
1129 ri.fInvalidateRecord = (!fSyncUpdates && dcd &&
1130 dcd->type == DIR_FRAME) ? FALSE : TRUE;
1131 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1132 MPFROMP(pciFirst), MPFROMP(&ri))) {
1133 DosSleep(10); // Give GUI time to work
1134 // Retry
1135 WinSetFocus(HWND_DESKTOP, hwndCnr);
1136 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1137 MPFROMP(pciFirst), MPFROMP(&ri))) {
1138 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1139 GetPString(IDS_CMINSERTERRTEXT));
1140 ok = FALSE;
1141 ullTotalBytes = 0;
1142 if (WinIsWindow((HAB) 0, hwndCnr))
1143 FreeCnrItemList(hwndCnr, pciFirst);
1144 pciFirst = NULL;
1145 break;
1146 }
1147 }
1148 }
1149 //SleepIfNeeded(&itdSleep, 1);
1150 }
1151 priority_normal();
1152 if (ok) {
1153 ullReturnBytes += ullTotalBytes;
1154 ulReturnFiles += ulFindCnt;
1155 }
1156 }
1157 }
1158
1159 /**
1160 * DosFind for subdirectories of a read-only directory on a FAT volume
1161 * returns path not found if there are no subdirectories
1162 * FAT FS seems to ignore . and .. in this case
1163 * Map to no more files
1164 * We could verify that directory is marked read-only, it's probably not
1165 * worth the extra code since we do verify 2 out of 3 prerequisites
1166 * 15 Jan 08 SHL
1167 */
1168 if (rc == ERROR_PATH_NOT_FOUND && !filestoo) {
1169 ULONG ulDriveType = 0;
1170 CHAR szFSType[CCHMAXPATH];
1171 INT removable = CheckDrive(*pszFileSpec, szFSType, &ulDriveType);
1172 if (removable != -1 && strcmp(szFSType, "FAT") == 0)
1173 rc = ERROR_NO_MORE_FILES;
1174 }
1175
1176 // 13 Oct 09 SHL FIXME to be saymsg if ERROR_NOT_READY and first try on volume
1177 if (rc && rc != ERROR_NO_MORE_FILES && fDontSuggestAgain) {
1178 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1179 GetPString(IDS_CANTFINDDIRTEXT), pszFileSpec);
1180 }
1181
1182 if (!fSyncUpdates && dcd && dcd->type == DIR_FRAME)
1183 WinSendMsg(hwndCnr, CM_INVALIDATERECORD, MPVOID,
1184 MPFROM2SHORT(0, CMA_ERASE));
1185 }
1186Abort:
1187 xfree(paffbTotal, pszSrcFile, __LINE__);
1188 xfree(pszFileSpec, pszSrcFile, __LINE__);
1189 xfree(paffbFound, pszSrcFile, __LINE__);
1190 xfree(papffbSelected, pszSrcFile, __LINE__);
1191
1192 if (recurse) {
1193 pci = WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMP(pciParent),
1194 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
1195 while (pci && (INT)pci != -1) {
1196 if (!pci->pszFileName || !strcmp(pci->pszFileName, NullStr)) {
1197 Runtime_Error(pszSrcFile, __LINE__, "pci->pszFileName NULL for %p", pci);
1198 return;
1199 }
1200 if ((pci->attrFile & FILE_DIRECTORY))
1201 AddFleshWorkRequest(hwndCnr, pci, eStubby);
1202 pci = WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMP(pci),
1203 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1204 }
1205 }
1206
1207 // Reset counts in case errors occurred after initially counted
1208 if (pulTotalFiles)
1209 *pulTotalFiles = ulReturnFiles;
1210
1211 if (pullTotalBytes)
1212 *pullTotalBytes = ullReturnBytes;
1213
1214} // ProcessDirectory
1215
1216VOID FillDirCnr(HWND hwndCnr,
1217 CHAR * pszDirectory,
1218 DIRCNRDATA * dcd,
1219 PULONGLONG pullTotalBytes)
1220{
1221 ProcessDirectory(hwndCnr,
1222 (PCNRITEM)NULL,
1223 pszDirectory,
1224 TRUE, // filestoo
1225 FALSE, // recurse
1226 TRUE, // partial
1227 dcd ? &dcd->stopflag : NULL,
1228 dcd,
1229 NULL, // total files
1230 pullTotalBytes,
1231 0);
1232 DosPostEventSem(CompactSem);
1233
1234#if 0 // 2011-05-31 SHL FIXME to be gone or to be configurable
1235 {
1236 int state = _heapchk();
1237 if (state != _HEAPOK)
1238 Runtime_Error(pszSrcFile, __LINE__, "heap corrupted %d", state);
1239 else
1240 DbgMsg(pszSrcFile, __LINE__, "_memavl %u", _memavl());
1241 }
1242#endif
1243
1244} // FillDirCnr
1245
1246/**
1247 * Fill tree container and drives list
1248 * Offer to update command line options if not already done and not suppressed
1249 */
1250
1251VOID FillTreeCnr(HWND hwndCnr, HWND hwndParent)
1252{
1253 ULONG ulCurDriveNum;
1254 ULONG ulDriveMap;
1255 ULONG numtoinsert = 0;
1256 ULONG ulDriveType;
1257 PCNRITEM pci, pciFirst = NULL;
1258 PCNRITEM pciNext;
1259 PCNRITEM pciParent = NULL;
1260 UINT iDrvNum;
1261 ULONG ulDriveMapMask;
1262 CHAR szSuggest[32] = {0}; // Suggested startup command line parameters
1263 CHAR szDrive[CCHMAXPATH] = " :\\";
1264 CHAR szFSType[CCHMAXPATH];
1265 FILESTATUS4L fsa4;
1266 APIRET rc;
1267 ULONG startdrive = 3;
1268 HWND hwndDrivelist;
1269 static BOOL didonce;
1270 static ULONG ulLastDriveMap;
1271
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 DosPostEventSem(CompactSem);
1676
1677 if (!fDontSuggestAgain) {
1678 BYTE info;
1679 BOOL includesyours = FALSE;
1680
1681 // 02 Mar 14 GKY !didonce for fFirstTime so it works again
1682 if (*szSuggest || ~driveflags[1] & DRIVE_IGNORE && !didonce) {
1683 if (!DosDevConfig(&info, DEVINFO_FLOPPY) && info == 1) {
1684 if (!*szSuggest) {
1685 *szSuggest = '/';
1686 szSuggest[1] = 0;
1687 }
1688 else
1689 memmove(szSuggest + 2, szSuggest + 1, strlen(szSuggest));
1690 szSuggest[1] = 'B';
1691 }
1692 }
1693 if (*szSuggest) {
1694 APIRET rc;
1695 for (iDrvNum = 2; iDrvNum < 26; iDrvNum++) {
1696 if (driveflags[iDrvNum] & DRIVE_IGNORE) {
1697 includesyours = TRUE;
1698 sprintf(szSuggest + strlen(szSuggest), "%c", (char)(iDrvNum + 'A'));
1699 }
1700 }
1701 strcat(szSuggest, " %*");
1702 rc = saymsg2(NULL, 3, HWND_DESKTOP,
1703 GetPString(IDS_SUGGESTTITLETEXT),
1704 GetPString(IDS_SUGGEST1TEXT),
1705 (includesyours) ? GetPString(IDS_SUGGEST2TEXT) : NullStr,
1706 szSuggest);
1707 if (rc == SM2_YES || rc == SM2_DONTASK) {
1708 HOBJECT hFM2Object;
1709 char s[64];
1710 sprintf(s, "PARAMETERS=%s", szSuggest);
1711 hFM2Object = WinQueryObject("<FM/2>");
1712 if (hFM2Object) {
1713 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1714 }
1715 hFM2Object = WinQueryObject("<FM/2 LITE>");
1716 if (hFM2Object) {
1717 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1718 }
1719 hFM2Object = WinQueryObject("<FM/2_AV/2>");
1720 if (hFM2Object) {
1721 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1722 }
1723 hFM2Object = WinQueryObject("<FM/2_DIRSIZE>");
1724 if (hFM2Object) {
1725 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1726 }
1727 hFM2Object = WinQueryObject("<FM/2_VTREE>");
1728 if (hFM2Object) {
1729 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1730 }
1731 hFM2Object = WinQueryObject("<FM/2_VDIR>");
1732 if (hFM2Object) {
1733 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1734 }
1735 hFM2Object = WinQueryObject("<FM/2_SEEALL>");
1736 if (hFM2Object) {
1737 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1738 }
1739 hFM2Object = WinQueryObject("<FM/2_DATABAR>");
1740 if (hFM2Object) {
1741 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1742 }
1743 }
1744 if (rc == SM2_NO || rc == SM2_DONTASK) {
1745 fDontSuggestAgain = TRUE;
1746 PrfWriteProfileData(fmprof, FM3Str, "DontSuggestAgain",
1747 &fDontSuggestAgain, sizeof(BOOL));
1748 }
1749 } // if suggest
1750 } // if !fDontSuggestAgain
1751 didonce = TRUE;
1752} // FillTreeCnr
1753
1754
1755/**
1756 * Empty all records from a container and free associated storage and
1757 * Free up field infos
1758 */
1759
1760VOID EmptyCnr(HWND hwnd)
1761{
1762 PFIELDINFO pfi;
1763
1764#if 0 // fixme to be gone or to be configurable
1765 {
1766 int state = _heapchk();
1767 if (state != _HEAPOK)
1768 Runtime_Error(pszSrcFile, __LINE__, "heap corrupted %d", state);
1769 }
1770#endif
1771
1772 // Remove all records
1773 RemoveCnrItems(hwnd, NULL, 0, CMA_FREE);
1774
1775 // Remove field info descriptors
1776 pfi = (PFIELDINFO) WinSendMsg(hwnd, CM_QUERYDETAILFIELDINFO, MPVOID,
1777 MPFROMSHORT(CMA_FIRST));
1778 if (pfi &&
1779 (INT)WinSendMsg(hwnd, CM_REMOVEDETAILFIELDINFO, MPVOID,
1780 MPFROM2SHORT(0, CMA_FREE)) == -1) {
1781 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVEDETAILFIELDINFO hwnd %x", hwnd);
1782 }
1783}
1784
1785/**
1786 * Free storage associated with container item
1787 */
1788
1789VOID FreeCnrItemData(PCNRITEM pci)
1790{
1791
1792 // 2015-08-23 SHL FIXME debug
1793 if ((pci->pszSubject && (ULONG)pci->pszSubject < 0x10000) ||
1794 (pci->pszLongName && (ULONG)pci->pszLongName < 0x10000) ||
1795 (pci->pszDisplayName && (ULONG)pci->pszDisplayName < 0x10000) ||
1796 (pci->pszFileName && (ULONG)pci->pszFileName < 0x10000) ||
1797 (pci->pszLongName && (ULONG)pci->pszLongName < 0x10000) ||
1798 (pci->pszFmtFileSize && (ULONG)pci->pszFmtFileSize < 0x10000))
1799 {
1800 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free bogus %p", pci);
1801 }
1802
1803 if (pci->pszSubject) {
1804 if (pci->pszSubject != NullStr)
1805 free(pci->pszSubject);
1806 pci->pszSubject = NULL; // Catch illegal references
1807 }
1808
1809 if (pci->pszLongName) {
1810 if (pci->pszLongName != NullStr)
1811 free(pci->pszLongName);
1812 pci->pszLongName = NULL; // Catch illegal references
1813 }
1814
1815 // Bypass free if pszDisplayName points into pszFileName buffer
1816 if (pci->pszDisplayName) {
1817 if (pci->pszDisplayName != NullStr) {
1818 if (!pci->pszFileName ||
1819 pci->pszDisplayName < pci->pszFileName ||
1820 pci->pszDisplayName >= pci->pszFileName + _msize(pci->pszFileName))
1821 {
1822 free(pci->pszDisplayName);
1823 }
1824 }
1825 pci->pszDisplayName = NULL; // Catch illegal references
1826 }
1827
1828#if 1 // 2009-09-26 SHL FIXME debug dup free complaints
1829 if (!pci->pszFileName)
1830 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice", pci);
1831 else {
1832 if (pci->pszFileName != NullStr)
1833 free(pci->pszFileName);
1834 pci->pszFileName = NULL; // Catch illegal references
1835 }
1836#else
1837 {
1838 // 2015-08-23 SHL FIXME to work again now that Flesh/Stubby on thread
1839 #define HIST_COUNT 50
1840 static struct {
1841 PCNRITEM pci;
1842 PSZ pszFileName;
1843 } history[HIST_COUNT];
1844 static volatile UINT iHistNdx;
1845 UINT i;
1846
1847 if (!pci->pszFileName) {
1848 // Looks like pci was already freed
1849 // Try to locate original file name in history buffer
1850 for (i = 0; i < HIST_COUNT && pci != history[i].pci; i++) { } // Scan
1851 if (i < HIST_COUNT) {
1852 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice, fileName was %.260s",
1853 pci, history[i].pszFileName);
1854 } else {
1855 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice", pci);
1856 }
1857 }
1858 else {
1859 PSZ psz;
1860 PSZ *ppsz;
1861 // Grab a history slot
1862 // This should work well enoungh to prevent MT/SMP conflicts
1863 for (;;) {
1864 i = iHistNdx;
1865 if (++i >= HIST_COUNT)
1866 i = 0;
1867 if (++iHistNdx >= HIST_COUNT)
1868 iHistNdx = 0;
1869 if (i == iHistNdx) break;
1870 }
1871 ppsz = &history[iHistNdx].pszFileName;
1872 psz = *ppsz;
1873 if (psz)
1874 free(psz);
1875 if (pci->pszFileName && pci->pszFileName != NullStr)
1876 *ppsz = strdup(pci->pszFileName);
1877 else
1878 *ppsz = NULL;
1879 history[iHistNdx].pci = pci;
1880 if (pci->pszFileName != NullStr)
1881 free(pci->pszFileName);
1882 pci->pszFileName = NULL; // Catch illegal references and dup free attempts
1883 }
1884 }
1885
1886#endif // FIXME debug dup free
1887
1888 if (pci->pszLongName) {
1889 if (pci->pszLongName != NullStr)
1890 free(pci->pszLongName);
1891 pci->pszLongName = NULL; // Catch illegal references
1892 }
1893
1894 if (pci->pszFmtFileSize) {
1895 if (pci->pszFmtFileSize != NullStr)
1896 free(pci->pszFmtFileSize);
1897 pci->pszFmtFileSize = NULL; // Catch illegal references
1898 }
1899}
1900
1901/**
1902 * Free single container item and associated storage
1903 */
1904
1905VOID FreeCnrItem(HWND hwnd, PCNRITEM pci)
1906{
1907 FreeCnrItemData(pci);
1908
1909 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(1))) {
1910 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,
1911 "CM_FREERECORD hwnd %x pci %p file %s",
1912 hwnd, pci,
1913 pci && pci->pszFileName ? pci->pszFileName : "n/a");
1914 }
1915}
1916
1917/**
1918 * Free container item list and associated storage
1919 */
1920
1921VOID FreeCnrItemList(HWND hwnd, PCNRITEM pciFirst)
1922{
1923 PCNRITEM pci = pciFirst;
1924 PCNRITEM pciNext;
1925 USHORT usCount;
1926 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
1927
1928 InitITimer(&itdSleep, 500);
1929 for (usCount = 0; pci; usCount++) {
1930 pciNext = (PCNRITEM) pci->rc.preccNextRecord;
1931 FreeCnrItemData(pci);
1932 pci = pciNext;
1933 if (!IdleIfNeeded(&itdSleep, 30)) {
1934 for (usCount = usCount + 1; pci; usCount++) {
1935 pciNext = (PCNRITEM) pci->rc.preccNextRecord;
1936 FreeCnrItemData(pci);
1937 pci = pciNext;
1938 }
1939 break;
1940 }
1941 }
1942 priority_normal();
1943 DosPostEventSem(CompactSem);
1944 if (usCount) {
1945 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(usCount))) {
1946 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_FREERECORD hwnd %x pci %p cnt %u", hwnd, pci, usCount);
1947 }
1948 }
1949}
1950
1951/**
1952 * Remove item(s) from container and free associated storage if requested
1953 * @param pciFirst points to first item to remove or NULL to remove all
1954 * @param usCnt is remove count or 0 to remove all
1955 * @returns count of items remaining in container or -1 if error
1956 */
1957
1958INT RemoveCnrItems(HWND hwnd, PCNRITEM pciFirst, USHORT usCnt, USHORT usFlags)
1959{
1960 INT remaining = usCnt;
1961 BOOL bIdlePrioritySet = FALSE;
1962 // #define RCI_ITEMS_PER_TIMER_CHECK (10)
1963 // 10 seems a very conservative number
1964 // USHORT usTimerCheckCountdown = RCI_ITEMS_PER_TIMER_CHECK;
1965 PCNRITEM pci;
1966 PCNRITEM pciPrevious;
1967 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
1968
1969 if ((usCnt && !pciFirst) || (!usCnt && pciFirst)) {
1970 Runtime_Error(pszSrcFile, __LINE__, "pciFirst %p usCnt %u mismatch", pciFirst, usCnt);
1971 remaining = -1;
1972 }
1973 else {
1974 // Free our buffers if free requested
1975 if (usFlags & CMA_FREE) {
1976 if (pciFirst)
1977 pci = pciFirst;
1978 else {
1979 pci = (PCNRITEM)WinSendMsg(hwnd, CM_QUERYRECORD, MPVOID,
1980 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1981 if ((INT)pci == -1) {
1982 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_QUERYRECORD");
1983 remaining = -1;
1984 pci = NULL;
1985 }
1986 }
1987 InitITimer(&itdSleep, 500);
1988 while (pci) {
1989 FreeCnrItemData(pci);
1990 if (usCnt > 0)
1991 pciPrevious = pci;
1992 pci = (PCNRITEM)pci->rc.preccNextRecord;
1993 if (!pci)
1994 break;
1995 if (usCnt > 0 && pciPrevious && pciPrevious->pciPrevious) {
1996 pciPrevious->pciPrevious->rc.preccNextRecord = (MINIRECORDCORE *) pci;
1997 pci->pciPrevious = pciPrevious->pciPrevious;
1998 pciPrevious->pciPrevious = NULL;
1999 pciPrevious->rc.preccNextRecord = NULL;
2000 }
2001 if (remaining && --remaining == 0)
2002 break;
2003 if (!bIdlePrioritySet) {
2004 bIdlePrioritySet = !IdleIfNeeded(&itdSleep, 30);
2005 }
2006 } // while
2007 if (bIdlePrioritySet)
2008 priority_normal();
2009
2010 DosPostEventSem(CompactSem);
2011 }
2012 }
2013 if (remaining != - 1) {
2014 remaining = (INT)WinSendMsg(hwnd, CM_REMOVERECORD, MPFROMP(&pciFirst), MPFROM2SHORT(usCnt, usFlags));
2015 if (remaining == -1) {
2016 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVERECORD hwnd %x pci %p cnt %u", hwnd, pciFirst, usCnt);
2017 }
2018 }
2019
2020 return remaining;
2021}
2022
2023#pragma alloc_text(FILLDIR,FillInRecordFromFFB,FillInRecordFromFSA,IDFile)
2024#pragma alloc_text(FILLDIR1,ProcessDirectory,FillDirCnr,FillTreeCnr,FileAttrToString)
2025#pragma alloc_text(EMPTYCNR,EmptyCnr,FreeCnrItemData,FreeCnrItem,FreeCnrItemList,RemoveCnrItems)
2026
Note: See TracBrowser for help on using the repository browser.