source: trunk/dll/filldir.c@ 1844

Last change on this file since 1844 was 1838, checked in by Gregg Young, 10 years ago

Serialize local hard drive scanning to reduce drive thrashing continue to scan all other drive types in separate threads. Ticket [561] Remove unneed SubbyScan code and improve suppression of blank lines and duplicate subdirectory name caused by running Stubby in worker threads.

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