source: trunk/dll/filldir.c@ 1880

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

Remove dead code and comments from remaining c files. #if 0 and #if NEVER were not addressed

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