source: trunk/dll/filldir.c@ 1863

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

Remove recurse scan code; fix A:\ drive not ready error caused by not moving the cursor from drive A:\ fast enough. Have Flesh remove pcis that have NullStr FileNames.

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