source: trunk/dll/filldir.c@ 1778

Last change on this file since 1778 was 1778, checked in by Steven Levine, 11 years ago

Rework dircnrs.c DirObjWndProc UM_RESCAN to avoid hanging FM/2 Lite when
drive tree hidden. Also speeds up startup if Switch Tree on directory change
not enabled.

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