source: trunk/dll/filldir.c@ 1891

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

Rework FreeCnrItem to ensure all CNRITEMs deleted.
Use WinSendMsg CMA_NEXT.
Was using preccNextRecord which is not recommended because control does
not maintain linkage after inserts and deletes.
Note: arccnrs.c still needs to be reworked to use common functions from filldir.c.

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