source: trunk/dll/filldir.c@ 1780

Last change on this file since 1780 was 1780, checked in by Gregg Young, 11 years ago

Fixed errors found by cppcheck. Most had the potential to cause difficult to reproduce traps. Also fixed retry code for failure to create an archive work directory and the failure of the mailto code to drop trailing >.

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