source: trunk/dll/filldir.c

Last change on this file was 1916, checked in by Gregg Young, 8 days ago

Fix easize so that EAs larger than 32767 show their actual size instead of 32767

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.9 KB
Line 
1
2/***********************************************************************
3
4 $Id: filldir.c 1916 2025-11-01 18:30:47Z gyoung $
5
6 Fill Directory Tree Containers
7
8 Copyright (c) 1993-1998 M. Kimes
9 Copyright (c) 2001-2020 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 28 Jan 20 SHL EmptyCnr: report more errors
127 29 Jan 20 SHL Rework RemoveCnrItems removal to not use prev/next chain
128 30 Jan 20 SHL Rework RemoveCnrItems to avoid possible traps on bad input
129 30 Jan 20 SHL Clean up some inconsistent formatting
130
131***********************************************************************/
132
133#include <stdlib.h>
134#include <string.h>
135#include <malloc.h> // _msize _heapchk
136#include <ctype.h>
137#include <limits.h>
138
139#define INCL_DOS
140#define INCL_WIN
141#define INCL_DOSERRORS
142#define INCL_LONGLONG
143
144#include "fm3dll.h"
145#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
146#include "draglist.h" // Data declaration(s)
147#include "treecnr.h" // Data declaration(s)
148#include "info.h" // Data declaration(s)
149#include "newview.h" // Data declaration(s)
150#include "mainwnd.h" // hwndDrivelist
151#include "fm3str.h"
152#include "filldir.h"
153#include "errutil.h" // Dos_Error...
154#include "strutil.h" // GetPString
155#include "misc.h" // GetTidForWindow
156#include "fortify.h" // 06 May 08 SHL
157#include "notebook.h" // INI file fields
158#include "flesh.h" // AddFleshWorkRequest
159#include "update.h" // SelectDriveIcon
160#include "valid.h" // CheckDrive
161#include "filter.h" // Filter
162#include "subj.h" // Subject
163#include "grep.h" // hwndStatus
164#include "copyf.h" // unlinkf
165#include "literal.h" // wildcard
166#include "i18nutil.h" // CommaFmtULL
167#include "wrappers.h" // xDosFindNext
168#include "init.h"
169#include "common.h"
170#include "excputil.h" // xbeginthread
171#include "fm3dlg.h" // INFO_LABEL
172#include "pathutil.h" // AddBackslashToPath
173#include "tmrsvcs.h" // ITIMER_DESC
174#include "eas.h" // GetLargeEASize
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,
417 FIL_QUERYEASFROMLIST,
418 (PVOID)&eaop,
419 (ULONG)sizeof(EAOP2));
420 // Prevent this error from occuring when scanning a directory
421 // that contains a locked data file
422 if (rc && rc != ERROR_SHARING_VIOLATION) {
423 CHAR s[80];
424 sprintf(s, "%s %s",PCSZ_DOSQUERYPATHINFO, "%s");
425 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
426 s, pci->pszFileName);
427 }
428 else {
429 PFEA2 pfea = eaop.fpFEA2List->list;
430 while (pfea) {
431 if (pfea->cbValue) {
432 CHAR *achValue = pfea->szName + pfea->cbName + 1;
433 if (*(USHORT *)achValue != EAT_ASCII)
434 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
435 GetPString(IDS_ERROREATYPETEXT),
436 achValue, pfea->cbName, pfea->szName);
437 else {
438 CHAR ch = achValue[pfea->cbValue];
439 PSZ pszValue;
440 achValue[pfea->cbValue] = 0;
441 pszValue = xstrdup(achValue + (sizeof(USHORT) * 2), pszSrcFile, __LINE__);
442 achValue[pfea->cbValue] = ch;
443 if (strncmp(pfea->szName, LONGNAME, pfea->cbName) == 0)
444 pci->pszLongName = pszValue;
445 else if (strncmp(pfea->szName, SUBJECT, pfea->cbName) == 0)
446 pci->pszSubject = pszValue;
447 else
448 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
449 GetPString(IDS_ERROREATYPETEXT), pfea, pfea->cbName, pfea->szName);
450 }
451 }
452 if (!pfea->oNextEntryOffset)
453 break;
454 pfea = (PFEA2)((PSZ)pfea + pfea->oNextEntryOffset);
455 } // while
456 }
457 free(pfealist);
458 }
459 free(pgealist);
460 }
461 }
462} // FetchCommonEAs
463
464ULONGLONG FillInRecordFromFFB(HWND hwndCnr,
465 PCNRITEM pci,
466 const PSZ pszDirectory,
467 const PFILEFINDBUF4L pffb,
468 const BOOL partial,
469 DIRCNRDATA *dcd)
470{
471 // fill in a container record from a FILEFINDBUF4L structure
472
473 CHAR *p;
474 HPOINTER hptr;
475 ULONG flags;
476
477 pci->hwndCnr = hwndCnr;
478
479 /**
480 * note that we cheat below, and accept the full pathname in pszDirectory
481 * if !*pffb->achName. This speeds up and simplifies processing elsewhere
482 * (like in update.c)
483 */
484
485 if (!*pffb->achName) {
486 pci->pszFileName = xstrdup(pszDirectory, pszSrcFile, __LINE__);
487 }
488 else {
489 INT c = strlen(pszDirectory);
490 INT c2 = pffb->cchName + 1;
491 if (pszDirectory[c - 1] != '\\')
492 c2++;
493 pci->pszFileName = xmalloc(c + c2, pszSrcFile, __LINE__);
494# ifdef FORTIFY
495 {
496 if (dcd->type != TREE_FRAME)
497 Fortify_ChangeScope(pci->pszFileName, -1);
498 else {
499 Fortify_SetOwner(pci->pszFileName, 1);
500 Fortify_SetScope(pci->pszFileName, 2);
501 }
502 }
503# endif
504 memcpy(pci->pszFileName, pszDirectory, c + 1);
505 p = pci->pszFileName + c - 1;
506 if (*p != '\\') {
507 p++;
508 *p = '\\';
509 }
510 p++;
511 memcpy(p, pffb->achName, pffb->cchName + 1);
512 }
513
514 // load Subject and/or Longname EAs, if required and have EAs
515 if (pffb->cbList > 4L && dcd &&
516 !(driveflags[toupper(*pci->pszFileName) - 'A'] & DRIVE_NOEASUPPORT))
517 FetchCommonEAs(pci);
518
519 if (!pci->pszSubject)
520 pci->pszSubject = NullStr;
521
522 // load the object's longname
523 if (!pci->pszLongName)
524 pci->pszLongName = NullStr;
525
526 // do anything required to case of filename
527 if (fForceUpper)
528 strupr(pci->pszFileName);
529 else if (fForceLower)
530 strlwr(pci->pszFileName);
531
532 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
533
534 // get an icon to use with it
535 if (pffb->attrFile & FILE_DIRECTORY) {
536 // is directory
537 if (fNoIconsDirs ||
538 (flags & DRIVE_NOLOADICONS) ||
539 !isalpha(*pci->pszFileName)) {
540 hptr = (HPOINTER)0;
541 }
542 else
543 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
544 }
545 else {
546 // is file
547 if (fNoIconsFiles ||
548 (flags & DRIVE_NOLOADICONS) ||
549 !isalpha(*pci->pszFileName)) {
550 hptr = (HPOINTER)0;
551 }
552 else
553 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
554
555 if (!hptr || IsDefaultIcon(hptr))
556 hptr = IDFile(pci->pszFileName);
557 }
558
559 if (!hptr) {
560 hptr = pffb->attrFile & FILE_DIRECTORY ?
561 hptrDir : pffb->attrFile & FILE_SYSTEM ?
562 hptrSystem : pffb->attrFile & FILE_HIDDEN ?
563 hptrHidden : pffb->attrFile & FILE_READONLY ?
564 hptrReadonly : hptrFile;
565 }
566
567 // Tell container what part of pathname to display
568 if (partial) {
569 p = strrchr(pci->pszFileName, '\\');
570 if (!p) {
571 p = strrchr(pci->pszFileName, ':');
572 if (!p)
573 p = pci->pszFileName;
574 else
575 p++;
576 }
577 else if ((dcd && dcd->type == TREE_FRAME) ||
578 (!(pffb->attrFile & FILE_DIRECTORY) || !*(p + 1))) {
579 p++;
580 }
581 if (!*p)
582 p = pci->pszFileName;
583 }
584 else
585 p = pci->pszFileName;
586 pci->pszDisplayName = p;
587
588 // Comma format the file size for large file support
589 {
590 CHAR szBuf[30];
591 CommaFmtULL(szBuf, sizeof(szBuf), pffb->cbFile, ' ');
592 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
593# ifdef FORTIFY
594 {
595 UINT tid = GetTidForWindow(hwndCnr);
596 if (tid == 1)
597 Fortify_ChangeScope(pci->pszFmtFileSize, -1);
598 else
599 Fortify_SetOwner(pci->pszFmtFileSize, 1);
600 }
601# endif
602 }
603
604 // now fill the darned thing in...
605 pci->date.day = pffb->fdateLastWrite.day;
606 pci->date.month = pffb->fdateLastWrite.month;
607 pci->date.year = pffb->fdateLastWrite.year + 1980;
608 pci->time.seconds = pffb->ftimeLastWrite.twosecs * 2;
609 pci->time.minutes = pffb->ftimeLastWrite.minutes;
610 pci->time.hours = pffb->ftimeLastWrite.hours;
611 pci->ladate.day = pffb->fdateLastAccess.day;
612 pci->ladate.month = pffb->fdateLastAccess.month;
613 pci->ladate.year = pffb->fdateLastAccess.year + 1980;
614 pci->latime.seconds = pffb->ftimeLastAccess.twosecs * 2;
615 pci->latime.minutes = pffb->ftimeLastAccess.minutes;
616 pci->latime.hours = pffb->ftimeLastAccess.hours;
617 pci->crdate.day = pffb->fdateCreation.day;
618 pci->crdate.month = pffb->fdateCreation.month;
619 pci->crdate.year = pffb->fdateCreation.year + 1980;
620 pci->crtime.seconds = pffb->ftimeCreation.twosecs * 2;
621 pci->crtime.minutes = pffb->ftimeCreation.minutes;
622 pci->crtime.hours = pffb->ftimeCreation.hours;
623 if (pffb->cbList < 65535)
624 pci->easize = CBLIST_TO_EASIZE(pffb->cbList);
625 else
626 pci->easize = GetLargeEASize(pci->pszFileName);
627 pci->cbFile = pffb->cbFile;
628 pci->attrFile = pffb->attrFile;
629 pci->pszDispAttr = FileAttrToString(pci->attrFile);
630 pci->rc.pszIcon = pci->pszDisplayName;
631 pci->rc.hptrIcon = hptr;
632
633 // check to see if record should be visible
634 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
635 if (dcd && (*dcd->mask.szMask || dcd->mask.antiattr ||
636 ((dcd->mask.attrFile &
637 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED))
638 != (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)))) {
639 if (*dcd->mask.szMask || dcd->mask.antiattr) {
640 if (!Filter((PMINIRECORDCORE)pci, (PVOID)&dcd->mask))
641 pci->rc.flRecordAttr |= CRA_FILTERED;
642 }
643 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
644 (pci->attrFile & FILE_HIDDEN)) ||
645 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
646 (pci->attrFile & FILE_SYSTEM)) ||
647 (!(dcd->mask.attrFile & FILE_READONLY) &&
648 (pci->attrFile & FILE_READONLY)) ||
649 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
650 (pci->attrFile & FILE_ARCHIVED))) {
651 pci->rc.flRecordAttr |= CRA_FILTERED;
652 }
653 }
654 DosReleaseMutexSem(hmtxFiltering);
655
656 return pffb->cbFile + pci->easize;
657
658} // FillInRecordFromFFB
659
660ULONGLONG FillInRecordFromFSA(HWND hwndCnr,
661 PCNRITEM pci,
662 const PSZ pszFileName,
663 const PFILESTATUS4L pfsa4,
664 const BOOL partial,
665 CHAR *pszFSType, // Optional
666 DIRCNRDATA *dcd) // Optional
667{
668 HPOINTER hptr;
669 ULONG flags;
670 CHAR *p;
671 CHAR szBuf[CCHMAXPATH];
672
673 // fill in a container record from a FILESTATUS4L structure
674
675 pci->hwndCnr = hwndCnr;
676 pci->pszFileName = xstrdup(pszFileName, pszSrcFile, __LINE__);
677
678 // 13 Jul 09 SHL FIXME to know if fetch can be bypassed if pszFSType already filled
679 // If FSType not supplied, assume don't need EAs either
680 if (pfsa4->cbList > 4L && dcd &&
681 !(driveflags[toupper(*pci->pszFileName) - 'A'] & DRIVE_NOEASUPPORT))
682 FetchCommonEAs(pci);
683
684 if (!pci->pszSubject)
685 pci->pszSubject = NullStr;
686 if (!pci->pszLongName)
687 pci->pszLongName = NullStr;
688
689 if (fForceUpper)
690 strupr(pci->pszFileName);
691 else if (fForceLower)
692 strlwr(pci->pszFileName);
693
694 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
695
696 if (pfsa4->attrFile & FILE_DIRECTORY) {
697 if (fNoIconsDirs ||
698 (flags & DRIVE_NOLOADICONS) ||
699 !isalpha(*pci->pszFileName)) {
700 hptr = (HPOINTER) 0;
701 }
702 else
703 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
704 }
705 else {
706 if (fNoIconsFiles ||
707 (flags & DRIVE_NOLOADICONS) ||
708 !isalpha(*pci->pszFileName)) {
709 hptr = IDFile(pci->pszFileName);
710 }
711 else
712 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
713 }
714 if (!hptr) {
715 hptr = pfsa4->attrFile & FILE_DIRECTORY ?
716 hptrDir :
717 pfsa4->attrFile & FILE_SYSTEM ?
718 hptrSystem :
719 pfsa4->attrFile & FILE_HIDDEN ?
720 hptrHidden : pfsa4->attrFile & FILE_READONLY ? hptrReadonly : hptrFile;
721 }
722
723 // Tell container what part of pathname to display
724 if (partial) {
725 p = strrchr(pci->pszFileName, '\\');
726 if (!p) {
727 p = strrchr(pci->pszFileName, ':');
728 if (!p)
729 p = pci->pszFileName;
730 else
731 p++;
732 }
733 else if ((dcd && dcd->type == TREE_FRAME) ||
734 !(pfsa4->attrFile & FILE_DIRECTORY) || !*(p + 1))
735 p++;
736 if (!*p)
737 p = pci->pszFileName;
738 }
739 else
740 p = pci->pszFileName;
741 if (pszFSType && (fShowFSTypeInTree || fShowDriveLabelInTree)) {
742 strcpy(szBuf, p);
743 strcat(szBuf, " [");
744 strcat(szBuf, pszFSType);
745 strcat(szBuf, "]");
746 pci->pszDisplayName = xstrdup(szBuf, pszSrcFile, __LINE__);
747 }
748 else
749 pci->pszDisplayName = p;
750
751 // 13 Jul 09 SHL FIXME to know why pszFSType check needed
752 // comma format the file size for large file support
753 if (!pszFSType || *pszFSType == 0) {
754 CHAR szBuf[30];
755 CommaFmtULL(szBuf, sizeof(szBuf), pfsa4->cbFile, ' ');
756 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
757# ifdef FORTIFY
758 {
759 if (dcd && dcd->type == TREE_FRAME) {
760 // Will be freed in TreeCnrWndProc WM_DESTROY
761 // Fortify_SetOwner(pci->pszFmtFileSize, 1);
762 Fortify_SetScope(pci->pszFmtFileSize, 2);
763 }
764 }
765# endif
766 }
767 else {
768 pci->pszFmtFileSize = NullStr;
769 }
770 pci->date.day = pfsa4->fdateLastWrite.day;
771 pci->date.month = pfsa4->fdateLastWrite.month;
772 pci->date.year = pfsa4->fdateLastWrite.year + 1980;
773 pci->time.seconds = pfsa4->ftimeLastWrite.twosecs * 2;
774 pci->time.minutes = pfsa4->ftimeLastWrite.minutes;
775 pci->time.hours = pfsa4->ftimeLastWrite.hours;
776 pci->ladate.day = pfsa4->fdateLastAccess.day;
777 pci->ladate.month = pfsa4->fdateLastAccess.month;
778 pci->ladate.year = pfsa4->fdateLastAccess.year + 1980;
779 pci->latime.seconds = pfsa4->ftimeLastAccess.twosecs * 2;
780 pci->latime.minutes = pfsa4->ftimeLastAccess.minutes;
781 pci->latime.hours = pfsa4->ftimeLastAccess.hours;
782 pci->crdate.day = pfsa4->fdateCreation.day;
783 pci->crdate.month = pfsa4->fdateCreation.month;
784 pci->crdate.year = pfsa4->fdateCreation.year + 1980;
785 pci->crtime.seconds = pfsa4->ftimeCreation.twosecs * 2;
786 pci->crtime.minutes = pfsa4->ftimeCreation.minutes;
787 pci->crtime.hours = pfsa4->ftimeCreation.hours;
788 if (pfsa4->cbList < 65535)
789 pci->easize = CBLIST_TO_EASIZE(pfsa4->cbList);
790 else
791 pci->easize = GetLargeEASize(pszFileName);
792 pci->cbFile = pfsa4->cbFile;
793 pci->attrFile = pfsa4->attrFile;
794 pci->pszDispAttr = FileAttrToString(pci->attrFile);
795 pci->rc.pszIcon = pci->pszDisplayName;
796 pci->rc.hptrIcon = hptr;
797
798 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
799 if (dcd &&
800 (*dcd->mask.szMask || dcd->mask.antiattr ||
801 ((dcd->mask.attrFile &
802 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)) !=
803 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)))) {
804 if (*dcd->mask.szMask || dcd->mask.antiattr) {
805 if (!Filter((PMINIRECORDCORE)pci, (PVOID)&dcd->mask))
806 pci->rc.flRecordAttr |= CRA_FILTERED;
807 }
808 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
809 (pci->attrFile & FILE_HIDDEN)) ||
810 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
811 (pci->attrFile & FILE_SYSTEM)) ||
812 (!(dcd->mask.attrFile & FILE_READONLY) &&
813 (pci->attrFile & FILE_READONLY)) ||
814 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
815 (pci->attrFile & FILE_ARCHIVED)))
816 pci->rc.flRecordAttr |= CRA_FILTERED;
817 }
818 DosReleaseMutexSem(hmtxFiltering);
819
820 return pfsa4->cbFile + pci->easize;
821
822} // FillInRecordFromFSA
823
824VOID ProcessDirectory(const HWND hwndCnr,
825 const PCNRITEM pciParent,
826 const CHAR *szDirBase,
827 const BOOL filestoo,
828 const BOOL recurse,
829 const BOOL partial,
830 CHAR *stopflag,
831 DIRCNRDATA *dcd, // Optional
832 ULONG *pulTotalFiles, // Optional
833 PULONGLONG pullTotalBytes, // Optional
834 CHAR *LoadedFirstChild) // Optional
835{
836 /**
837 * put all the directories (and files if filestoo is TRUE) from a
838 * directory into the container. recurse through subdirectories if
839 * recurse is TRUE.
840 */
841
842 PSZ pszFileSpec;
843 PFILEFINDBUF4L paffbFound;
844 PFILEFINDBUF4L *papffbSelected;
845 PFILEFINDBUF4L pffbFile;
846 PFILEFINDBUF4L paffbTotal = NULL;
847 PFILEFINDBUF4L paffbTemp;
848 HDIR hdir = HDIR_CREATE;
849 ULONG ulFindCnt;
850 ULONG ulFindMax;
851 ULONG ulSelCnt;
852 ULONG cAffbTotal = 0;
853 ULONGLONG ullBytes;
854 ULONGLONG ullTotalBytes;
855 ULONG ulReturnFiles = 0;
856 ULONGLONG ullReturnBytes = 0;
857 APIRET rc;
858 PCNRITEM pci;
859 PCNRITEM pciFirst;
860 PCNRITEM pciNext;
861 RECORDINSERT ri;
862 BOOL ok = TRUE;
863 ULONG ulBufBytes;
864 ULONG x;
865 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
866
867 if (isalpha(*szDirBase) && szDirBase[1] == ':' && szDirBase[2] == '\\') {
868 if ((driveflags[toupper(*szDirBase) - 'A'] & DRIVE_REMOTE) && fRemoteBug)
869 ulFindMax = 1; // file system gets confused
870 else if (driveflags[toupper(*szDirBase) - 'A'] & DRIVE_ZIPSTREAM)
871 ulFindMax = min(FilesToGet, 225); // anything more is wasted
872 else
873 ulFindMax = FilesToGet; // full-out
874 }
875 else
876 ulFindMax = FilesToGet;
877
878 if (OS2ver[0] == 20 && OS2ver[1] < 30)
879 ulFindMax = min(ulFindMax, (65535 / sizeof(FILEFINDBUF4L)));
880
881 ulBufBytes = ulFindMax * sizeof(FILEFINDBUF4L);
882
883 pszFileSpec = xmalloc(CCHMAXPATH + 2, pszSrcFile, __LINE__);
884 paffbFound = xmalloc(ulBufBytes, pszSrcFile, __LINE__);
885 papffbSelected = xmalloc(sizeof(PFILEFINDBUF4L) * ulFindMax, pszSrcFile, __LINE__);
886
887 if (paffbFound && papffbSelected && pszFileSpec) {
888 strcpy(pszFileSpec, szDirBase);
889 AddBackslashToPath(pszFileSpec);
890 strcat(pszFileSpec, "*");
891 DosError(FERR_DISABLEHARDERR);
892 ulFindCnt = ulFindMax;
893 rc = xDosFindFirst(pszFileSpec,
894 &hdir,
895 FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
896 FILE_SYSTEM | FILE_HIDDEN |
897 (filestoo ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY),
898 paffbFound,
899 ulBufBytes,
900 &ulFindCnt,
901 FIL_QUERYEASIZEL);
902 priority_normal();
903 pszFileSpec[strlen(pszFileSpec) - 1] = 0; // Chop off wildcard
904 if (!rc) {
905 InitITimer(&itdSleep, 500);
906 do {
907 /**
908 * remove . and .. and directories already added
909 * by Stubby from list if present
910 * also counter file system bugs that sometimes
911 * allows normal files to slip through when
912 * only directories should appear (only a few
913 * network file systems exhibit such a problem).
914 */
915
916 if (stopflag && *stopflag)
917 goto Abort;
918 pffbFile = paffbFound;
919 ulSelCnt = 0;
920 for (;;) {
921 if (!*pffbFile->achName ||
922 (!filestoo && ~pffbFile->attrFile & FILE_DIRECTORY) ||
923 (pffbFile->attrFile & FILE_DIRECTORY &&
924 !pffbFile->achName[0] || pffbFile->achName[0] == '.' &&
925 (!pffbFile->achName[1] ||
926 (pffbFile->achName[1] == '.' && !pffbFile->achName[2])) ||
927 (LoadedFirstChild && !stricmp(LoadedFirstChild, pffbFile->achName)))) {
928 // Got . or .. or file to be skipped
929 }
930 else
931 papffbSelected[ulSelCnt++] = pffbFile; // Remember selected file
932 if (!pffbFile->oNextEntryOffset) {
933 // ulFindCnt = ulSelCnt; // Remember number selected
934 break;
935 }
936 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + pffbFile->oNextEntryOffset);
937 } // for
938 if (ulSelCnt) {
939 // One or more entries selected
940 if (stopflag && *stopflag)
941 goto Abort;
942 if (fSyncUpdates) {
943 if (!WinIsWindow(WinQueryAnchorBlock(hwndCnr), hwndCnr)) {
944 ok = FALSE;
945 ullTotalBytes = 0;
946 break;
947 }
948 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
949 MPFROMLONG(EXTRA_RECORD_BYTES),
950 MPFROMLONG(ulSelCnt));
951 if (!pciFirst) {
952 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
953 GetPString(IDS_CMALLOCRECERRTEXT));
954 ok = FALSE;
955 ullTotalBytes = 0;
956 }
957 else {
958 // 04 Jan 08 SHL FIXME like comp.c to handle less than ulSelCnt records
959 pci = pciFirst;
960 ullTotalBytes = 0;
961 // Finish filling pci items
962 for (x = 0; x < ulSelCnt; x++) {
963 pffbFile = papffbSelected[x];
964 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
965 pffbFile, partial, dcd);
966 pciNext = pci;
967 pci = (PCNRITEM)pci->rc.preccNextRecord;
968 ullTotalBytes += ullBytes;
969 } // for
970 // Insert selected in container
971 memset(&ri, 0, sizeof(RECORDINSERT));
972 ri.cb = sizeof(RECORDINSERT);
973 ri.pRecordOrder = (PRECORDCORE)CMA_END;
974 ri.pRecordParent = (PRECORDCORE)pciParent;
975 ri.zOrder = (ULONG)CMA_TOP;
976 ri.cRecordsInsert = ulSelCnt;
977 ri.fInvalidateRecord = TRUE;
978 if (!WinSendMsg(hwndCnr,
979 CM_INSERTRECORD,
980 MPFROMP(pciFirst), MPFROMP(&ri))) {
981 DosSleep(10); // Give GUI time to work
982 WinSetFocus(HWND_DESKTOP, hwndCnr);
983 // Retry
984 if (!WinSendMsg(hwndCnr,
985 CM_INSERTRECORD,
986 MPFROMP(pciFirst), MPFROMP(&ri))) {
987 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
988 GetPString(IDS_CMINSERTERRTEXT));
989 ok = FALSE;
990 ullTotalBytes = 0;
991 if (WinIsWindow((HAB)0, hwndCnr))
992 FreeCnrItemList(hwndCnr, pciFirst);
993 }
994 }
995 }
996 if (ok) {
997 ullReturnBytes += ullTotalBytes;
998 ulReturnFiles += ulSelCnt;
999 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
1000 if (dcd) {
1001 dcd->totalfiles += ulSelCnt;
1002 dcd->ullTotalBytes += ullTotalBytes;
1003 }
1004 DosReleaseMutexSem(hmtxFiltering);
1005 }
1006 } // if sync updates
1007 else {
1008 // Append newly selected entries to aggregate list
1009 paffbTemp = xrealloc(paffbTotal,
1010 sizeof(FILEFINDBUF4L) * (ulSelCnt + cAffbTotal),
1011 pszSrcFile, __LINE__);
1012 if (paffbTemp) {
1013 // 13 Aug 07 SHL FIXME to optimize copy
1014 paffbTotal = paffbTemp;
1015 ullTotalBytes = 0; // 15 Sep 09 SHL
1016 for (x = 0; x < ulSelCnt; x++) {
1017 paffbTotal[x + cAffbTotal] = *papffbSelected[x];
1018 ullTotalBytes += papffbSelected[x]->cbFile;
1019 }
1020 cAffbTotal += ulSelCnt;
1021 }
1022 else {
1023 saymsg(MB_ENTER,
1024 HWND_DESKTOP,
1025 GetPString(IDS_ERRORTEXT), GetPString(IDS_OUTOFMEMORY));
1026 break;
1027 }
1028 }
1029 } // if entries selected
1030 if (stopflag && *stopflag)
1031 goto Abort;
1032 DosError(FERR_DISABLEHARDERR);
1033 ulFindCnt = ulFindMax;
1034 rc = xDosFindNext(hdir, paffbFound, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
1035 priority_normal();
1036 if (rc)
1037 DosError(FERR_DISABLEHARDERR);
1038 SleepIfNeeded(&itdSleep, 1);
1039 } while (!rc);
1040
1041 DosFindClose(hdir);
1042 xfree(paffbFound, pszSrcFile, __LINE__);
1043 paffbFound = NULL;
1044 xfree(papffbSelected, pszSrcFile, __LINE__);
1045 papffbSelected = NULL;
1046
1047 if (cAffbTotal && paffbTotal) {
1048 // Not fSyncUpdates and have work
1049 if (stopflag && *stopflag)
1050 goto Abort;
1051
1052 InitITimer(&itdSleep, 500);
1053 pci = NULL;
1054 ullTotalBytes = 0;
1055 pffbFile = paffbTotal;
1056 for (x = 0; x < cAffbTotal; x++) {
1057 ULONG ulRecsToInsert;
1058
1059 if (pci == NULL) {
1060 if (!WinIsWindow(WinQueryAnchorBlock(hwndCnr), hwndCnr)) {
1061 ok = FALSE;
1062 ullTotalBytes = 0;
1063 break;
1064 }
1065 ulRecsToInsert = cAffbTotal - x < USHRT_MAX ? cAffbTotal - x : USHRT_MAX;
1066 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
1067 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(ulRecsToInsert));
1068
1069 if (!pciFirst) {
1070 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1071 GetPString(IDS_CMALLOCRECERRTEXT));
1072 ok = FALSE;
1073 ullTotalBytes = 0;
1074 break;
1075 }
1076 else {
1077 // 04 Jan 08 SHL FIXME like comp.c to handle less than ulSelCnt records
1078 if (hwndStatus && dcd && dcd->hwndFrame ==
1079 WinQueryActiveWindow(dcd->hwndParent)) {
1080 WinSetWindowText(hwndStatus, (CHAR *) GetPString(LoadedFirstChild ?
1081 IDS_PLEASEWAITEXPANDINGTEXT :
1082 IDS_PLEASEWAITCOUNTINGTEXT));
1083 }
1084 pci = pciFirst;
1085 }
1086 }
1087 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1088 pffbFile, partial, dcd);
1089 pciNext = pci;
1090 pci = (PCNRITEM)pci->rc.preccNextRecord;
1091 ullTotalBytes += ullBytes;
1092 // 15 Sep 09 SHL allow timed updates to see
1093 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
1094 if (dcd) {
1095 dcd->totalfiles = x;
1096 dcd->ullTotalBytes = ullTotalBytes;
1097 }
1098 DosReleaseMutexSem(hmtxFiltering);
1099 // Can not use offset since we have merged lists - this should be equivalent
1100 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + sizeof(FILEFINDBUF4L));
1101
1102 if (!IdleIfNeeded(&itdSleep, 30)) {
1103 for (x = x+1; x < cAffbTotal; x++) {
1104 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1105 pffbFile, partial, dcd);
1106 pci = (PCNRITEM)pci->rc.preccNextRecord;
1107 ullTotalBytes += ullBytes;
1108 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
1109 if (dcd) {
1110 dcd->totalfiles = x;
1111 dcd->ullTotalBytes = ullTotalBytes;
1112 }
1113 DosReleaseMutexSem(hmtxFiltering);
1114 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + sizeof(FILEFINDBUF4L));
1115 if (pci == NULL) {
1116 priority_normal();
1117 InitITimer(&itdSleep, 500);
1118 break;
1119 }
1120 }
1121 }
1122
1123 if (pci == NULL && ulRecsToInsert) {
1124 memset(&ri, 0, sizeof(RECORDINSERT));
1125 ri.cb = sizeof(RECORDINSERT);
1126 ri.pRecordOrder = (PRECORDCORE)CMA_END;
1127 ri.pRecordParent = (PRECORDCORE)pciParent;
1128 ri.zOrder = (ULONG)CMA_TOP;
1129 ri.cRecordsInsert = ulRecsToInsert;
1130 ri.fInvalidateRecord = (!fSyncUpdates && dcd &&
1131 dcd->type == DIR_FRAME) ? FALSE : TRUE;
1132 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1133 MPFROMP(pciFirst), MPFROMP(&ri))) {
1134 DosSleep(10); // Give GUI time to work
1135 // Retry
1136 WinSetFocus(HWND_DESKTOP, hwndCnr);
1137 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1138 MPFROMP(pciFirst), MPFROMP(&ri))) {
1139 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1140 GetPString(IDS_CMINSERTERRTEXT));
1141 ok = FALSE;
1142 ullTotalBytes = 0;
1143 if (WinIsWindow((HAB)0, hwndCnr))
1144 FreeCnrItemList(hwndCnr, pciFirst);
1145 pciFirst = NULL;
1146 break;
1147 }
1148 }
1149 }
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,
1384 (ULONG)sizeof(FILESTATUS4L));
1385 if (rc == ERROR_BAD_NET_RESP) {
1386 DosError(FERR_DISABLEHARDERR);
1387 rc = DosQueryPathInfo(szDrive,
1388 FIL_STANDARDL,
1389 &fsa4,
1390 (ULONG)sizeof(FILESTATUS4L));
1391 fsa4.cbList = 0;
1392 }
1393 if (rc && !didonce) {
1394 // Guess drive letter
1395 if (!*szSuggest) {
1396 *szSuggest = '/';
1397 szSuggest[1] = 0;
1398 }
1399
1400 sprintf(szSuggest + strlen(szSuggest), "%c" , toupper(*szDrive));
1401 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1402 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1403 sprintf(szDrive + strlen(szDrive), " [%s]", szFSType);
1404 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1405 szDrive[3] = 0; // Restore nul
1406 pci->rc.pszIcon = pci->pszDisplayName;
1407 pci->attrFile = FILE_DIRECTORY;
1408 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1409 driveserial[iDrvNum] = -1;
1410 }
1411 else
1412 FillInRecordFromFSA(hwndCnr, pci, szDrive, &fsa4, TRUE, szFSType, NULL);
1413 }
1414 else {
1415 // Removable volume
1416 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1417 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1418 sprintf(szDrive + strlen(szDrive), " [%s]", szFSType);
1419 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1420 szDrive[3] = 0; // Restore nul
1421 pci->rc.pszIcon = pci->pszDisplayName;
1422 pci->attrFile = FILE_DIRECTORY;
1423 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1424 }
1425 SelectDriveIcon(pci);
1426# ifdef FORTIFY
1427 // Will be freed by TreeCnrWndProc WM_DESTROY
1428 Fortify_SetScope(pci->pszFileName, 2);
1429# endif
1430 }
1431 else {
1432 *szFSType = 0;
1433 pci->rc.hptrIcon = hptrDunno;
1434 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1435 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1436 strcat(szDrive, " [No Prescan]");
1437 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1438 szDrive[3] = 0;
1439# ifdef FORTIFY
1440 // Will be freed by TreeCnrWndProc WM_DESTROY
1441 Fortify_SetScope(pci->pszFileName, 2);
1442# endif
1443 pci->rc.pszIcon = pci->pszDisplayName;
1444 pci->attrFile = FILE_DIRECTORY;
1445 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1446 driveserial[iDrvNum] = -1;
1447 }
1448 } // if not diskette
1449 else {
1450 // diskette drive (A or B)
1451 pci->rc.hptrIcon = hptrFloppy;
1452 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
1453 if (fShowFSTypeInTree || fShowDriveLabelInTree)
1454 strcat(szDrive, " [Floppy]");
1455 pci->pszDisplayName = xstrdup(szDrive, pszSrcFile, __LINE__);
1456 szDrive[3] = 0;
1457 pci->rc.pszIcon = pci->pszDisplayName;
1458 pci->attrFile = FILE_DIRECTORY;
1459 pci->pszDispAttr = FileAttrToString(pci->attrFile);
1460 driveflags[iDrvNum] |= (DRIVE_REMOVABLE | DRIVE_NOLONGNAMES);
1461 driveserial[iDrvNum] = -1;
1462 }
1463 pci->rc.flRecordAttr |= CRA_RECORDREADONLY;
1464 pci = (PCNRITEM)pci->rc.preccNextRecord; // next rec
1465 }
1466 else if (~ulDriveMap & ulDriveMapMask)
1467 driveflags[iDrvNum] |= DRIVE_INVALID;
1468
1469 // Update drives list dropdown
1470 if ((ulDriveMap ^ ulLastDriveMap) & ulDriveMapMask) {
1471 if (ulDriveMap & ulDriveMapMask) {
1472 WinSendMsg(hwndDrivelist,
1473 LM_INSERTITEM,
1474 MPFROM2SHORT(LIT_SORTASCENDING, 0),
1475 MPFROMP(szDrive));
1476 }
1477 else {
1478 // Drive went away
1479 SHORT sSelect = (SHORT)WinSendMsg(hwndDrivelist,
1480 LM_SEARCHSTRING,
1481 MPFROM2SHORT(0, LIT_FIRST),
1482 MPFROMP(szDrive));
1483 if (sSelect >= 0)
1484 WinSendMsg(hwndDrivelist, LM_DELETEITEM, MPFROMSHORT(sSelect), MPVOID);
1485 }
1486 }
1487 } // for drives
1488
1489 ulLastDriveMap = ulDriveMap;
1490
1491 // insert the drives in container
1492 if (numtoinsert && pciFirst) {
1493 RECORDINSERT ri;
1494
1495 memset(&ri, 0, sizeof(RECORDINSERT));
1496 ri.cb = sizeof(RECORDINSERT);
1497 ri.pRecordOrder = (PRECORDCORE)CMA_END;
1498 ri.pRecordParent = (PRECORDCORE)NULL;
1499 ri.zOrder = (ULONG)CMA_TOP;
1500 ri.cRecordsInsert = numtoinsert;
1501 ri.fInvalidateRecord = FALSE;
1502 if (!WinSendMsg(hwndCnr,
1503 CM_INSERTRECORD, MPFROMP(pciFirst), MPFROMP(&ri)))
1504 {
1505 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1506 GetPString(IDS_CMINSERTERRTEXT));
1507 }
1508 }
1509
1510 // move cursor onto the default drive rather than the first drive
1511 pci = (PCNRITEM)WinSendMsg(hwndCnr,
1512 CM_QUERYRECORD,
1513 MPVOID,
1514 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1515 while (pci && (INT)pci != -1) {
1516 if ((ULONG)(toupper(*pci->pszFileName) - '@') == ulCurDriveNum) {
1517 WinSendMsg(hwndCnr,
1518 CM_SETRECORDEMPHASIS,
1519 MPFROMP(pci), MPFROM2SHORT(TRUE, CRA_CURSORED));
1520 break;
1521 }
1522 pci = (PCNRITEM)WinSendMsg(hwndCnr,
1523 CM_QUERYRECORD,
1524 MPFROMP(pci),
1525 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1526 }
1527
1528 if (fShowEnv) {
1529 RECORDINSERT ri;
1530
1531 pciParent = WinSendMsg(hwndCnr,
1532 CM_ALLOCRECORD,
1533 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(1));
1534 if (pciParent) {
1535 pciParent->flags |= RECFLAGS_ENV;
1536 pciParent->pszFileName = xstrdup(GetPString(IDS_ENVVARSTEXT), pszSrcFile, __LINE__);
1537 pciParent->pszDisplayName = pciParent->pszFileName;
1538 pciParent->rc.hptrIcon = hptrEnv;
1539 pciParent->rc.pszIcon = pciParent->pszFileName;
1540 pciParent->pszDispAttr = FileAttrToString(0);
1541 memset(&ri, 0, sizeof(RECORDINSERT));
1542 ri.cb = sizeof(RECORDINSERT);
1543 ri.pRecordOrder = (PRECORDCORE)CMA_END;
1544 ri.pRecordParent = (PRECORDCORE)NULL;
1545 ri.zOrder = (ULONG)CMA_TOP;
1546 ri.cRecordsInsert = 1;
1547 ri.fInvalidateRecord = FALSE;
1548 if (WinSendMsg(hwndCnr,
1549 CM_INSERTRECORD, MPFROMP(pciParent), MPFROMP(&ri))) {
1550
1551 char *p, *pp;
1552
1553 p = pszTreeEnvVarList;
1554 while (*p == ';')
1555 p++;
1556 while (*p) {
1557 *szFSType = 0;
1558 pp = szFSType;
1559 while (*p && *p != ';')
1560 *pp++ = *p++;
1561 *pp = 0;
1562 while (*p == ';')
1563 p++;
1564 if (*szFSType &&
1565 (!stricmp(szFSType, PCSZ_LIBPATH) || getenv(szFSType))) {
1566 pci = WinSendMsg(hwndCnr,
1567 CM_ALLOCRECORD,
1568 MPFROMLONG(EXTRA_RECORD_BYTES),
1569 MPFROMLONG(1));
1570 if (pci) {
1571 CHAR fname[CCHMAXPATH];
1572 pci->flags |= RECFLAGS_ENV;
1573 sprintf(fname, "%%%s%%", szFSType);
1574 pci->pszFileName = xstrdup(fname, pszSrcFile, __LINE__);
1575 pci->rc.hptrIcon = hptrEnv;
1576 pci->rc.pszIcon = pci->pszFileName;
1577 pci->pszDispAttr = FileAttrToString(0);
1578 memset(&ri, 0, sizeof(RECORDINSERT));
1579 ri.cb = sizeof(RECORDINSERT);
1580 ri.pRecordOrder = (PRECORDCORE)CMA_END;
1581 ri.pRecordParent = (PRECORDCORE)pciParent;
1582 ri.zOrder = (ULONG)CMA_TOP;
1583 ri.cRecordsInsert = 1;
1584 ri.fInvalidateRecord = FALSE;
1585 if (!WinSendMsg(hwndCnr,
1586 CM_INSERTRECORD,
1587 MPFROMP(pci), MPFROMP(&ri))) {
1588 Win_Error(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1589 GetPString(IDS_CMINSERTERRTEXT));
1590 FreeCnrItem(hwndCnr, pci);
1591 }
1592 }
1593 }
1594 }
1595 WinSendMsg(hwndCnr,
1596 CM_INVALIDATERECORD,
1597 MPFROMP(&pciParent),
1598 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
1599 }
1600 else
1601 FreeCnrItem(hwndCnr, pciParent);
1602 }
1603 } // if show env
1604
1605 // Run Stubby on each hard drive to ensure expand/collapse buttons correct
1606 pci = (PCNRITEM)WinSendMsg(hwndCnr,
1607 CM_QUERYRECORD,
1608 MPVOID,
1609 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1610 while (pci && (INT)pci != -1) {
1611 pciNext = (PCNRITEM)WinSendMsg(hwndCnr,
1612 CM_QUERYRECORD,
1613 MPFROMP(pci),
1614 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1615 if (~pci->flags & RECFLAGS_ENV) {
1616 iDrvNum = toupper(*pci->pszFileName) - 'A'; // 0..25
1617 if (iDrvNum == ulCurDriveNum || iDrvNum >= 2) {
1618 // Hard drive or current drive
1619 ULONG flags = driveflags[iDrvNum]; // Speed up
1620 if (~flags & DRIVE_INVALID &&
1621 ~flags & DRIVE_NOPRESCAN &&
1622 (!fNoRemovableScan || ~flags & DRIVE_REMOVABLE)) {
1623 AddFleshWorkRequest(hwndCnr, pci, eStubby);
1624 } // if drive needs to be scanned
1625 }
1626 else {
1627 // Diskette or not current drive
1628 WinSendMsg(hwndCnr,
1629 CM_INVALIDATERECORD,
1630 MPFROMP(&pci),
1631 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
1632 }
1633 }
1634 pci = pciNext;
1635 } // while pci
1636
1637 // Deselect all
1638 if (hwndDrivelist)
1639 WinSendMsg(hwndDrivelist, LM_SELECTITEM, MPFROM2SHORT(0, 0), MPFROMLONG(TRUE));
1640
1641 // Fill in environment CNRITEMs, if any
1642 pci = (PCNRITEM)WinSendMsg(hwndCnr,
1643 CM_QUERYRECORD,
1644 MPVOID,
1645 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1646 while (pci && (INT)pci != -1) {
1647 pciNext = (PCNRITEM)WinSendMsg(hwndCnr,
1648 CM_QUERYRECORD,
1649 MPFROMP(pci),
1650 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1651 if (pci->flags & RECFLAGS_ENV) {
1652 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1653 CM_QUERYRECORD,
1654 MPFROMP(pci),
1655 MPFROM2SHORT(CMA_FIRSTCHILD,
1656 CMA_ITEMORDER));
1657 while (pci && (INT)pci != -1) {
1658 if (pci->flags & RECFLAGS_ENV)
1659 AddFleshWorkRequest(hwndCnr, pci, eFleshEnv);
1660 pci = (PCNRITEM)WinSendMsg(hwndCnr,
1661 CM_QUERYRECORD,
1662 MPFROMP(pci),
1663 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1664 }
1665 break;
1666 }
1667 pci = (PCNRITEM)WinSendMsg(hwndCnr,
1668 CM_QUERYRECORD,
1669 MPFROMP(pci),
1670 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1671 } // while pci
1672
1673 if (hwndMain)
1674 PostMsg(hwndMain, UM_BUILDDRIVEBAR, MPVOID, MPVOID);
1675
1676 DosSleep(16);
1677 DosPostEventSem(CompactSem);
1678
1679 if (!fDontSuggestAgain) {
1680 BYTE info;
1681 BOOL includesyours = FALSE;
1682
1683 // 02 Mar 14 GKY !didonce for fFirstTime so it works again
1684 if (*szSuggest || ~driveflags[1] & DRIVE_IGNORE && !didonce) {
1685 if (!DosDevConfig(&info, DEVINFO_FLOPPY) && info == 1) {
1686 if (!*szSuggest) {
1687 *szSuggest = '/';
1688 szSuggest[1] = 0;
1689 }
1690 else
1691 memmove(szSuggest + 2, szSuggest + 1, strlen(szSuggest));
1692 szSuggest[1] = 'B';
1693 }
1694 }
1695 if (*szSuggest) {
1696 APIRET rc;
1697 for (iDrvNum = 2; iDrvNum < 26; iDrvNum++) {
1698 if (driveflags[iDrvNum] & DRIVE_IGNORE) {
1699 includesyours = TRUE;
1700 sprintf(szSuggest + strlen(szSuggest), "%c", (char)(iDrvNum + 'A'));
1701 }
1702 }
1703 strcat(szSuggest, " %*");
1704 rc = saymsg2(NULL, 3, HWND_DESKTOP,
1705 GetPString(IDS_SUGGESTTITLETEXT),
1706 GetPString(IDS_SUGGEST1TEXT),
1707 (includesyours) ? GetPString(IDS_SUGGEST2TEXT) : NullStr,
1708 szSuggest);
1709 if (rc == SM2_YES || rc == SM2_DONTASK) {
1710 HOBJECT hFM2Object;
1711 char s[64];
1712 sprintf(s, "PARAMETERS=%s", szSuggest);
1713 hFM2Object = WinQueryObject("<FM/2>");
1714 if (hFM2Object) {
1715 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1716 }
1717 hFM2Object = WinQueryObject("<FM/2 LITE>");
1718 if (hFM2Object) {
1719 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1720 }
1721 hFM2Object = WinQueryObject("<FM/2_AV/2>");
1722 if (hFM2Object) {
1723 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1724 }
1725 hFM2Object = WinQueryObject("<FM/2_DIRSIZE>");
1726 if (hFM2Object) {
1727 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1728 }
1729 hFM2Object = WinQueryObject("<FM/2_VTREE>");
1730 if (hFM2Object) {
1731 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1732 }
1733 hFM2Object = WinQueryObject("<FM/2_VDIR>");
1734 if (hFM2Object) {
1735 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1736 }
1737 hFM2Object = WinQueryObject("<FM/2_SEEALL>");
1738 if (hFM2Object) {
1739 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1740 }
1741 hFM2Object = WinQueryObject("<FM/2_DATABAR>");
1742 if (hFM2Object) {
1743 rc = WinSetObjectData(hFM2Object, (PSZ)s);
1744 }
1745 }
1746 if (rc == SM2_NO || rc == SM2_DONTASK) {
1747 fDontSuggestAgain = TRUE;
1748 PrfWriteProfileData(fmprof, FM3Str, "DontSuggestAgain",
1749 &fDontSuggestAgain, sizeof(BOOL));
1750 }
1751 } // if suggest
1752 } // if !fDontSuggestAgain
1753 didonce = TRUE;
1754} // FillTreeCnr
1755
1756/**
1757 * Empty all records from a container and free associated storage and
1758 * Free up field infos
1759 */
1760
1761VOID EmptyCnr(HWND hwnd)
1762{
1763 PFIELDINFO pfi;
1764
1765#if 0 // FIXME to be gone or to be configurable
1766 {
1767 int state = _heapchk();
1768 if (state != _HEAPOK)
1769 Runtime_Error(pszSrcFile, __LINE__, "heap corrupted %d", state);
1770 }
1771#endif
1772
1773 // Remove all records
1774 if (RemoveCnrItems(hwnd, NULL, 0, CMA_FREE))
1775 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"RemoveCnrItems");
1776
1777 // Remove field info descriptors
1778 pfi = (PFIELDINFO)WinSendMsg(hwnd,
1779 CM_QUERYDETAILFIELDINFO,
1780 MPVOID,
1781 MPFROMSHORT(CMA_FIRST));
1782 if (pfi &&
1783 (INT)WinSendMsg(hwnd, CM_REMOVEDETAILFIELDINFO, MPVOID,
1784 MPFROM2SHORT(0, CMA_FREE)) == -1) {
1785 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVEDETAILFIELDINFO hwnd %x", hwnd);
1786 }
1787}
1788
1789/**
1790 * Free storage associated with container item
1791 */
1792
1793VOID FreeCnrItemData(PCNRITEM pci)
1794{
1795 // 2015-08-23 SHL FIXME debug
1796 if ((pci->pszSubject && (ULONG)pci->pszSubject < 0x10000) ||
1797 (pci->pszLongName && (ULONG)pci->pszLongName < 0x10000) ||
1798 (pci->pszDisplayName && (ULONG)pci->pszDisplayName < 0x10000) ||
1799 (pci->pszFileName && (ULONG)pci->pszFileName < 0x10000) ||
1800 (pci->pszLongName && (ULONG)pci->pszLongName < 0x10000) ||
1801 (pci->pszFmtFileSize && (ULONG)pci->pszFmtFileSize < 0x10000))
1802 {
1803 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free bogus %p", pci);
1804 }
1805
1806# ifdef PMPRINTF
1807 {
1808 PSZ psz = pci->pszFileName;
1809 if (!psz)
1810 psz = "(NULL)";
1811 else if (psz == NullStr)
1812 psz = "NullStr";
1813 PmPrintf_Report(pszSrcFile, __LINE__, "FreeCnrItemData freeing pci %p data for fileName \"%.260s\"",
1814 pci, psz);
1815 }
1816# endif
1817
1818 if (pci->pszSubject) {
1819 if (pci->pszSubject != NullStr)
1820 free(pci->pszSubject);
1821 pci->pszSubject = NULL; // Catch illegal references
1822 }
1823
1824 if (pci->pszLongName) {
1825 if (pci->pszLongName != NullStr)
1826 free(pci->pszLongName);
1827 pci->pszLongName = NULL; // Catch illegal references
1828 }
1829
1830 // Bypass free if pszDisplayName points into pszFileName buffer
1831 if (pci->pszDisplayName) {
1832 if (pci->pszDisplayName != NullStr) {
1833 if (!pci->pszFileName ||
1834 pci->pszDisplayName < pci->pszFileName ||
1835 pci->pszDisplayName >= pci->pszFileName + _msize(pci->pszFileName))
1836 {
1837 free(pci->pszDisplayName);
1838 }
1839 }
1840 pci->pszDisplayName = NULL; // Catch illegal references
1841 }
1842
1843#if 0 // 2009-09-26 SHL FIXME debug dup free complaints
1844 if (!pci->pszFileName)
1845 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice", pci);
1846 else {
1847 if (pci->pszFileName != NullStr)
1848 free(pci->pszFileName);
1849 pci->pszFileName = NULL; // Catch illegal references
1850 }
1851#else
1852# if 0 // FIXME to be gone
1853 {
1854 static BOOL first;
1855 if (!first) {
1856 first=1;
1857 DebugHereIAm();
1858 }
1859 }
1860# endif
1861 {
1862 // Add CNRITEM to history list
1863 // 2015-08-23 SHL FIXME to verify OK now that Flesh/Stubby on thread
1864 #define HIST_CNT 5000
1865 static INT volatile iHistLock; // Cheap spin lock
1866 static struct {
1867 PCNRITEM pci;
1868 PSZ pszFileName;
1869 } histList[HIST_CNT];
1870 static volatile UINT iHistNdx; // Last used
1871 UINT iCurNdx;
1872
1873 if (!pci->pszFileName) {
1874 // Looks like pci was already freed
1875 // Try to locate original file name in history list
1876 for (iCurNdx = 0; iCurNdx < HIST_CNT && pci != histList[iCurNdx].pci; iCurNdx++) { } // Scan
1877 if (iCurNdx < HIST_CNT) {
1878 PSZ psz = histList[iCurNdx].pszFileName;
1879# ifdef PMPRINTF
1880 PmPrintf_Report(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice, fileName was \"%.260s\"",
1881 pci, psz == NullStr ? "NullStr" : psz);
1882# endif
1883 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice, fileName was \"%.260s\"",
1884 pci, psz == NullStr ? "NullStr" : psz);
1885 } else {
1886
1887# ifdef PMPRINTF
1888 PmPrintf_Report(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice", pci);
1889# endif
1890 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting to free %p data twice", pci);
1891 }
1892 }
1893 else {
1894 // Add to history list
1895 PSZ psz;
1896 PSZ *ppsz;
1897 static PSZ pszNull = "(NULL)";
1898 // This should work well enoungh to prevent MT/SMP conflicts
1899 for (; ++iHistLock > 1; iHistLock--)
1900 DosSleep(0); // Spin if list locked
1901 if (++iHistNdx >= HIST_CNT)
1902 iHistNdx = 0;
1903 ppsz = &histList[iHistNdx].pszFileName;
1904 psz = *ppsz;
1905 if (psz && psz != NullStr && psz != pszNull)
1906 free(psz);
1907 if (pci->pszFileName) {
1908 if (pci->pszFileName != NullStr)
1909 *ppsz = strdup(pci->pszFileName);
1910 else
1911 *ppsz = NullStr;
1912 }
1913 else
1914 *ppsz = pszNull;
1915 histList[iHistNdx].pci = pci;
1916 iHistLock--;
1917
1918 if (pci->pszFileName != NullStr)
1919 free(pci->pszFileName);
1920 pci->pszFileName = NULL; // Catch illegal references and dup free attempts
1921 }
1922 }
1923
1924#endif // FIXME debug dup free
1925
1926 if (pci->pszLongName) {
1927 if (pci->pszLongName != NullStr)
1928 free(pci->pszLongName);
1929 pci->pszLongName = NULL; // Catch illegal references
1930 }
1931
1932 if (pci->pszFmtFileSize) {
1933 if (pci->pszFmtFileSize != NullStr)
1934 free(pci->pszFmtFileSize);
1935 pci->pszFmtFileSize = NULL; // Catch illegal references
1936 }
1937}
1938
1939/**
1940 * Free single container item and associated storage
1941 */
1942
1943VOID FreeCnrItem(HWND hwnd, PCNRITEM pci)
1944{
1945# ifdef PMPRINTF
1946 PmPrintf_Report(pszSrcFile, __LINE__, "FreeCnrItem freeing pci %p");
1947# endif
1948
1949 FreeCnrItemData(pci);
1950
1951 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(1))) {
1952 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,
1953 "CM_FREERECORD hwnd %x pci %p file %s",
1954 hwnd, pci,
1955 pci && pci->pszFileName ? pci->pszFileName : "n/a");
1956 }
1957}
1958
1959/**
1960 * Free container item list and associated storage
1961 */
1962
1963VOID FreeCnrItemList(HWND hwnd, PCNRITEM pciFirst)
1964{
1965 PCNRITEM pci = pciFirst;
1966 PCNRITEM pciNext;
1967 USHORT usCount;
1968 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
1969
1970 InitITimer(&itdSleep, 500);
1971 for (usCount = 0; pci; usCount++) {
1972 pciNext = (PCNRITEM)pci->rc.preccNextRecord;
1973 FreeCnrItemData(pci);
1974 pci = pciNext;
1975 if (!IdleIfNeeded(&itdSleep, 30)) {
1976 for (usCount = usCount + 1; pci; usCount++) {
1977 pciNext = (PCNRITEM)pci->rc.preccNextRecord;
1978 FreeCnrItemData(pci);
1979 pci = pciNext;
1980 }
1981 break;
1982 }
1983 }
1984 priority_normal();
1985 DosPostEventSem(CompactSem);
1986 if (usCount) {
1987 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(usCount))) {
1988 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_FREERECORD hwnd %x pci %p cnt %u", hwnd, pci, usCount);
1989 }
1990 }
1991}
1992
1993/**
1994 * Remove item(s) from container and free associated storage if requested
1995 * @param pciFirst points to specific item to remove or NULL to remove all
1996 * @param usCnt is 0 to remove all or 1 to remove specific record
1997 * @param usFlags for CM_REMOVERECORD
1998 * @returns count of items remaining to delete or -1 if error
1999 */
2000
2001INT RemoveCnrItems(HWND hwnd, PCNRITEM pciFirst, USHORT usCnt, USHORT usFlags)
2002{
2003 INT remaining = usCnt;
2004 BOOL bIdlePrioritySet = FALSE;
2005 PCNRITEM pci;
2006 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
2007
2008 // Counted remove requires pciFirst and can only remove 1 record
2009 // Remove all does not allow pciFirst
2010 if ((usCnt && !pciFirst) || (usCnt != 1 && pciFirst)) {
2011 Runtime_Error(pszSrcFile, __LINE__, "pciFirst %p usCnt %u mismatch", pciFirst, usCnt);
2012 remaining = -1;
2013 }
2014 if (!usFlags & CMA_FREE) {
2015 Runtime_Error(pszSrcFile, __LINE__, "usFlags must have CMA_FREE set");
2016 remaining = -1;
2017 }
2018 if (!pciFirst) {
2019 // Removing all - query first
2020 pciFirst = (PCNRITEM)WinSendMsg(hwnd, CM_QUERYRECORD, MPVOID,
2021 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
2022 if ((INT)pciFirst == -1) {
2023 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_QUERYRECORD");
2024 remaining = -1;
2025 }
2026 }
2027
2028 InitITimer(&itdSleep, 500);
2029
2030# ifdef PMPRINTF
2031 PmPrintf_Report(pszSrcFile, __LINE__, "RemoveCnrItems freeing data pciFirst %p usCnt %d remaining %d",
2032 pciFirst, usCnt, remaining);
2033# endif
2034
2035 // Free data
2036 // 2020-01-28 SHL Rework to use CMA_NEXT - preccNextRecord method was never reliable
2037 pci = pciFirst;
2038 while (pci && (INT)pci != -1 && remaining > 0) {
2039 FreeCnrItemData(pci);
2040 if (--remaining == 0)
2041 break;
2042 pci = WinSendMsg(hwnd, CM_QUERYRECORD, MPFROMP(pci),
2043 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
2044 if (!bIdlePrioritySet)
2045 bIdlePrioritySet = !IdleIfNeeded(&itdSleep, 30);
2046 } // while
2047
2048 if (bIdlePrioritySet)
2049 priority_normal();
2050
2051 DosPostEventSem(CompactSem);
2052
2053 // Free CNRITEM record(s) if OK so far
2054 if (remaining != -1 && pciFirst && (INT)pciFirst != -1) {
2055# ifdef PMPRINTF
2056 PmPrintf_Report(pszSrcFile, __LINE__, "RemoveCnrItems CM_REMOVERECORD pciFirst %p usCnt %d", pciFirst, usCnt);
2057# endif
2058 remaining = (INT)WinSendMsg(hwnd, CM_REMOVERECORD, MPFROMP(&pciFirst), MPFROM2SHORT(usCnt, usFlags));
2059 if (remaining == -1)
2060 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVERECORD hwnd %x pciFirst %p cnt %u", hwnd, pciFirst, usCnt);
2061 else if (usCnt == 0 && remaining != 0)
2062 Runtime_Error(pszSrcFile, __LINE__, "%u records remain after CM_REMOVERECORD", remaining);
2063 }
2064
2065 return remaining;
2066}
2067
2068#pragma alloc_text(FILLDIR,FillInRecordFromFFB,FillInRecordFromFSA,IDFile)
2069#pragma alloc_text(FILLDIR1,ProcessDirectory,FillDirCnr,FillTreeCnr,FileAttrToString)
2070#pragma alloc_text(EMPTYCNR,EmptyCnr,FreeCnrItemData,FreeCnrItem,FreeCnrItemList,RemoveCnrItems)
2071
Note: See TracBrowser for help on using the repository browser.