source: trunk/dll/filldir.c@ 1892

Last change on this file since 1892 was 1892, checked in by Steven Levine, 6 years ago

Rework RemoveCnrItems to avoid possible traps on bad input.
Rework RemoveArcItems like RemoveCnrItems.
Sync source with standards.

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