source: trunk/dll/filldir.c@ 1478

Last change on this file since 1478 was 1478, checked in by Gregg Young, 16 years ago

Fix trap on rescan following change of label/drive type or environment on SMP; Ticket 408

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