source: trunk/dll/filldir.c@ 1796

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

Use saymsg2 for Suggest dialog Ticket [538] Add an @ to the end of the filters window label to indicate an attribute filter is set.

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