source: trunk/dll/flesh.c@ 1871

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

Create CollapseAll and modify ExpandAll to reduce code overhead both to try and speed drive expansion. Change ExpandAll to allow it to loop in UM_EXPAND until until drive is completely expanded. Changes were need to work with Flesh, Stubby and UnFlesh being moved to a thread. Add code for Flesh to skip the directory entry added by Stubby (eliminate use of NULL/Nullstr pszFileNames by Stubby). Add code in Stubby to insert a complete container item. Add a flag to indicate when a directory needed to be Fleshed. Get expand and switch code to work with Flesh, UnFlesh and Stubby running on a thread. Loop and idle ExpandAll; Move tree expand to a thread; Have ShowTreeRec wait for the Flesh thread. Add a correction factor so directories don't get placed above the top of the tree container when a large drive has been expanded. Debug is mostly still in but all turned off.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.7 KB
Line 
1
2/***********************************************************************
3
4 $Id: flesh.c 1871 2015-09-20 22:57:02Z gyoung $
5
6 Drive tree container management
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2005, 2015 Steven H. Levine
10
11 24 May 05 SHL Rework Win_Error usage
12 25 May 05 SHL Rework for ProcessDirectory
13 28 May 05 SHL Clean while reading code
14 24 Oct 05 SHL Delete obsolete code
15 22 Jul 06 SHL Check more run time errors
16 19 Oct 06 SHL Stubby - correct . and .. detect
17 22 Mar 07 GKY Use QWL_USER
18 01 Aug 07 SHL Sync with CNRITEM mods
19 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
20 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
21 29 Feb 08 GKY Use xfree where appropriate
22 24 Nov 08 GKY remove redundant code and minor speed up of Stubby
23 25 Dec 08 GKY Add ProcessDirectoryThread to allow optional recursive drive scan at startup.
24 25 Dec 08 GKY Add DRIVE_RSCANNED flag to monitor for the first recursive drive scan per session
25 to prevent duplicate directory names in tree following a copy before initial scan.
26 08 Mar 09 GKY Additional strings move to PCSZs in init.c
27 13 Dec 09 GKY Fixed separate paramenters. Please note that appname should be used in
28 profile calls for user settings that work and are setable in more than one
29 miniapp; FM3Str should be used for setting only relavent to FM/2 or that
30 aren't user settable; realappname should be used for setting applicable to
31 one or more miniapp but not to FM/2
32 17 Jan 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10). Mostly cast CHAR CONSTANT * as CHAR *.
33 04 Aug 12 GKY Fix trap on close during drive scan
34 02 Aug 15 GKY Fix trap in Stubby
35 03 Aug 15 SHL Document Stubby a bit better
36 07 Aug 15 SHL Rework to use AddFleshWorkRequest rather than direct calls to Stubby/Flesh/Unflesh
37 19 Aug 15 SHL Allow WaitFleshWorkListEmpty to wait for dependent items
38 23 Aug 15 GKY Fixed code to notify on drive with no subdirectories in first 64 entries
39 20 Sep 15 GKY Add code for Flesh to skip the directory entry added by Stubby (eliminate
40 use of NULL/Nullstr pszFileNames by Stubby). Add code in Stubby to insert a
41 complete container item. Add a flag to indicate when a directory needed to be
42 Fleshed
43
44***********************************************************************/
45
46#include <stdlib.h>
47#include <string.h>
48#include <ctype.h>
49//#include <malloc.h>
50
51#define INCL_DOS
52#define INCL_DOSERRORS
53#define INCL_WIN
54#define INCL_LONGLONG // dircnrs.h
55
56#include "fm3dll.h"
57#include "draglist.h" // Data declaration(s)
58#include "notebook.h" // Data declaration(s)
59#include "info.h" // Data declaration(s)
60#include "init.h" // Data declaration(s)
61#include "mainwnd.h" // Data declaration(s)
62#include "fm3str.h"
63#include "filldir.h" // FileAttrToString...
64#include "errutil.h" // Dos_Error...
65#include "strutil.h" // GetPString
66#include "flesh.h"
67#include "valid.h" // IsValidDir
68#include "misc.h" // LoadLibPath GetTidForThread
69#include "findrec.h" // FindCnrRecord
70#include "notify.h" // Notify
71#include "wrappers.h" // xfree
72#include "excputil.h" // xbeginthread
73#include "listutil.h" // List...
74#include "common.h" // IncrThreadUsage DecrThreadUsage
75#include "pathutil.h"
76#if 0
77#define __PMPRINTF__
78#include "PMPRINTF.H"
79#endif
80
81// Data definitions
82#pragma data_seg(DATA1)
83
84static PSZ pszSrcFile = __FILE__;
85
86
87static INT tidFleshWorkListThread = -1; // 2015-08-08 SHL
88
89static PCSZ pszFleshFocusPath; // 2015-08-20 SHL
90#if 0
91BOOL fNoFleshDbgMsg; // 2015-08-09 SHL FIXME to be gone
92#endif
93#pragma data_seg(GLOBAL1)
94ULONG NoBrokenNotify;
95BOOL fFilesInTree;
96
97BOOL Flesh(HWND hwndCnr, PCNRITEM pciParent);
98
99BOOL Stubby(HWND hwndCnr, PCNRITEM pciParent);
100BOOL FleshEnv(HWND hwndCnr, PCNRITEM pciParent);
101VOID UnFlesh(HWND hwndCnr, PCNRITEM pciParent);
102
103/**
104 * Insert CNRITEMs for members of PATH-like environment variable
105 * @param hwndCnr is the container to be populated
106 * @param pciParent is CNRITEM defining PATH-like environment variable
107 * @return TRUE if OK, FALSE is error detected
108 */
109
110BOOL FleshEnv(HWND hwndCnr, PCNRITEM pciParent)
111{
112 PCNRITEM pciL;
113 DIRCNRDATA *dcd;
114 CHAR path[CCHMAXPATH + 12],
115 fullpath[CCHMAXPATH + 12], *env, *p, *pp, *var = NULL;
116
117 if (!pciParent || (INT)pciParent == -1 || !hwndCnr)
118 return FALSE;
119
120 dcd = (DIRCNRDATA *) WinQueryWindowPtr(hwndCnr, QWL_USER);
121 if (!dcd)
122 return FALSE;
123
124 strcpy(path, pciParent->pszFileName + 1);
125 if (stricmp(path, GetPString(IDS_ENVVARSTEXT) + 1))
126 UnFlesh(hwndCnr, pciParent);
127 if (*path) {
128 path[strlen(path) - 1] = 0;
129 if (!stricmp(path, PCSZ_LIBPATH)) {
130 var = xmalloc(65536, pszSrcFile, __LINE__);
131 if (var)
132 LoadLibPath(var, 65536);
133 env = var;
134 }
135 else
136 env = getenv(path);
137 if (env && *env) {
138 p = env;
139 while (*p) {
140 pp = path;
141 while (*p == ';')
142 p++;
143 while (*p && *p != ';') {
144 *pp = *p;
145 p++;
146 pp++;
147 }
148 *pp = 0;
149 if (*path &&
150 strcmp(path, ".") &&
151 strcmp(path, ".\\") &&
152 strcmp(path, "..") &&
153 strcmp(path, "..\\") &&
154 strncmp(path, ".\\", 2) && strncmp(path, "..\\", 3)) {
155 if (!DosQueryPathInfo(path,
156 FIL_QUERYFULLNAME,
157 fullpath,
158 sizeof(fullpath)) && IsValidDir(fullpath)) {
159 pciL = FindCnrRecord(hwndCnr,
160 fullpath, pciParent, FALSE, FALSE, FALSE);
161 if (pciL) {
162 while (pciL && pciL != (PCNRITEM)-1 && pciL != pciParent)
163 pciL = WinSendMsg(hwndCnr,
164 CM_QUERYRECORD,
165 MPFROMP(pciL),
166 MPFROM2SHORT(CMA_PARENT, CMA_ITEMORDER));
167 }
168 if (!pciL) {
169
170 RECORDINSERT ri;
171
172 pciL = WinSendMsg(hwndCnr,
173 CM_ALLOCRECORD,
174 MPFROMLONG(EXTRA_RECORD_BYTES),
175 MPFROMLONG(1));
176 if (pciL) {
177 pciL->pszFileName = xstrdup(fullpath, pszSrcFile, __LINE__);
178 pciL->rc.pszIcon = pciL->pszFileName;
179 if (!fNoIconsDirs &&
180 (!isalpha(*fullpath) ||
181 !(driveflags[toupper(*fullpath) - 'A'] &
182 DRIVE_NOLOADICONS)))
183 pciL->rc.hptrIcon = WinLoadFileIcon(fullpath, FALSE);
184 if (!pciL->rc.hptrIcon)
185 pciL->rc.hptrIcon = hptrDir;
186 pciL->attrFile = FILE_DIRECTORY;
187 pciL->pszDispAttr = FileAttrToString(pciL->attrFile);
188 memset(&ri, 0, sizeof(ri));
189 ri.cb = sizeof(ri);
190 ri.pRecordOrder = (PRECORDCORE)CMA_END;
191 ri.pRecordParent = (PRECORDCORE)pciParent;
192 ri.zOrder = (ULONG)CMA_TOP;
193 ri.cRecordsInsert = 1;
194 ri.fInvalidateRecord = FALSE;
195#if 0 // 2015-08-03 SHL FIXME debug
196 if (pciL->pszFileName == NullStr)
197 DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD pci %p pszFileName \"%s\"", pciL, pciL->pszFileName); // 2015-08-03 SHL FIXME debug
198#endif
199 if (!WinSendMsg(hwndCnr,
200 CM_INSERTRECORD, MPFROMP(pciL), MPFROMP(&ri)))
201 FreeCnrItem(hwndCnr, pciL);
202 }
203 }
204 }
205 }
206 }
207 }
208 xfree(var, pszSrcFile, __LINE__);
209 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
210 CM_QUERYRECORD,
211 MPFROMP(pciParent),
212 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
213 while (pciL && (INT)pciL != -1) {
214 pciL->flags |= (RECFLAGS_NODRAG | RECFLAGS_UNDERENV);
215 WinSendMsg(hwndCnr,
216 CM_INVALIDATERECORD, MPFROMP(&pciL), MPFROM2SHORT(1, 0));
217 pciL = WinSendMsg(hwndCnr,
218 CM_QUERYRECORD,
219 MPFROMP(pciL), MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
220 }
221 }
222 return TRUE;
223}
224
225/**
226 * Insert CNRITEMs for all children of pciParent
227 * @param hwnCnr is container to receive CNRITEMs
228 * @param pciParent is CNRITEM to have children inserted
229 * @return TRUE if OK, FALSE is error detected
230 */
231
232BOOL Flesh(HWND hwndCnr, PCNRITEM pciParent)
233{
234 PCNRITEM pciL;
235 DIRCNRDATA *dcd;
236 BOOL includefiles;
237
238 if (!pciParent || (INT)pciParent == -1 || !hwndCnr)
239 return FALSE;
240
241 // 2015-08-13 SHL
242 if (fAmQuitting)
243 return FALSE;
244
245#if 0 // 2015-08-03 SHL FIXME debug
246 if (!fNoFleshDbgMsg) {
247 DbgMsg(pszSrcFile, __LINE__, "Flesh %s pciParent %p pszFileName %p",
248 pciParent && (INT)pciParent != -1 && pciParent->pszFileName ?
249 pciParent->pszFileName : "(null)",
250 pciParent,
251 pciParent && (INT)pciParent != -1 ? pciParent->pszFileName : (PVOID)-1); // 2015-08-03 SHL FIXME debug
252 }
253#endif
254 // 2015-08-06 SHL allow pciL -1
255 // 2015-08-06 SHL FIXME to not need pszFileName check
256 if (!pciParent->fleshed) {
257 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
258 CM_QUERYRECORD,
259 MPFROMP(pciParent),
260 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
261 // No children or filename null
262 if (pciL && (INT)pciL != -1) {
263 AddFleshWorkRequest(hwndCnr, pciL, eStubby);
264 // 2015-08-06 SHL FIXME to ensure this an not happen
265 if (!*pciL->pszFileName || !strcmp(pciL->pszFileName, NullStr))
266 Runtime_Error(pszSrcFile, __LINE__, "Flesh called with pci %p pszFileName (null)", pciL);
267#if 0
268 if (!fNoFleshDbgMsg)
269 DbgMsg(pszSrcFile, __LINE__, "Flesh RemoveCnrItems() pciL %p \"%s\"",
270 pciL,
271 pciL->pszFileName ? pciL->pszFileName : "(null)"); // 2015-08-04 SHL FIXME debug
272 // Assume refernces to pciL already removed from work list
273#endif
274 }
275 dcd = INSTDATA(hwndCnr);
276 if (dcd && dcd->size != sizeof(DIRCNRDATA))
277 dcd = NULL;
278
279 includefiles =
280 driveflags[toupper(*pciParent->pszFileName) - 'A'] & DRIVE_INCLUDEFILES ?
281 TRUE : fFilesInTree;
282
283 ProcessDirectory(hwndCnr,
284 pciParent,
285 pciParent->pszFileName,
286 includefiles, // filestoo
287 TRUE, // recurse
288 TRUE, // partial
289 NULL, // stop flag
290 dcd,
291 NULL, // total files
292 NULL, // total bytes
293 (pciL && (INT)pciL != -1) ? pciL->pszDisplayName : 0);
294 pciParent->fleshed = TRUE;
295 return TRUE;
296 }
297
298 return FALSE;
299}
300
301/**
302 * Remove children from container
303 * @param pciParent is parent of children to be removed
304 */
305
306VOID UnFlesh(HWND hwndCnr, PCNRITEM pciParent)
307{
308 BOOL removed = FALSE;
309 PCNRITEM pciL;
310
311 if (!pciParent || !hwndCnr)
312 return;
313#if 0
314 if (!fNoFleshDbgMsg)
315 DbgMsg(pszSrcFile, __LINE__, "UnFlesh pciParent %p pszFileName \"%s\"", pciParent, pciParent->pszFileName ? pciParent->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
316#endif
317 for (;;) {
318 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
319 CM_QUERYRECORD,
320 MPFROMP(pciParent),
321 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
322 if (!pciL || (INT)pciL == -1)
323 break; // Done
324#if 0
325 if (!fNoFleshDbgMsg)
326 DbgMsg(pszSrcFile, __LINE__, "UnFlesh RemoveCnrItems() pciL %p \"%s\"", pciL, pciL->pszFileName ? pciL->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
327#endif
328 RemoveCnrItems(hwndCnr, pciL, 1, CMA_FREE);
329 removed = TRUE;
330 } // for
331
332 if (removed) {
333 WinSendMsg(hwndCnr,
334 CM_INVALIDATERECORD,
335 MPFROMP(&pciParent),
336 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
337 pciParent->fleshed = FALSE;
338 DosSleep(1); // Let container items go away
339 }
340 return;
341}
342
343#define DDEPTH 64
344
345/**
346 * Insert CNRITEM for 1st subdirectory [or file] of pciParent
347 * @param hwdCnr is container to be filled
348 * @param pciParent is CNRITEM to receive child record
349 * @return TRUE if record inserted, else FALSE
350 * Ensures that expand/collapse button displays if directory has children
351 * Secondary purpose is to detect broken LANs and inaccesible mapped drives
352 */
353
354BOOL Stubby(HWND hwndCnr, PCNRITEM pciParent)
355{
356 /**
357 * this code is full of workarounds for screwed up LANs.
358 * let's hope all the current LAN programmers fall into
359 * a black hole and make way for people who can get it right...
360 */
361
362 BOOL ok = FALSE;
363 FILEFINDBUF3 ffb[DDEPTH];
364 PFILEFINDBUF3 pffb;
365 HDIR hDir = HDIR_CREATE;
366 ULONG nm, ulM = 1, total = 0, fl;
367 CHAR wildcard[CCHMAXPATH];
368 register INT len;
369 APIRET rc, prc;
370 BOOL isadir = FALSE;
371 BOOL isremote;
372 BOOL includefiles;
373 ULONG ddepth = DDEPTH;
374 ULONG drvNum;
375 ULONG flags;
376 static BOOL brokenlan = FALSE, isbroken = FALSE;
377
378 //DbgMsg(pszSrcFile, __LINE__,"Stubby pciParent %p", pciParent);
379 if (!pciParent || (INT)pciParent == -1 || !*pciParent->pszFileName
380 || pciParent->pszFileName == NullStr || !hwndCnr)
381 return FALSE;
382#if 0
383 if (!fNoFleshDbgMsg)
384 DbgMsg(pszSrcFile, __LINE__, "Stubby pciParent %p pszFileName %s", pciParent, pciParent->pszFileName); // 2015-08-03 SHL FIXME debug
385#endif
386 // Build wildcard
387 len = strlen(pciParent->pszFileName);
388 memcpy(wildcard, pciParent->pszFileName, len + 1);
389 if (wildcard[len - 1] != '\\')
390 wildcard[len++] = '\\';
391 wildcard[len++] = '*';
392 wildcard[len] = 0;
393
394 // 2015-08-19 SHL FIXME to know how this can happen
395 if (!isalpha(*wildcard) || wildcard[1] != ':' || wildcard[2] != '\\') {
396 MakeFullName(wildcard);
397 //DbgMsg(pszSrcFile, __LINE__, "Stubby MakeFullName returned %s", wildcard); // 2015-08-19 SHL FIXME debug
398 }
399 drvNum = toupper(*pciParent->pszFileName) - 'A';
400 flags = driveflags[drvNum];
401 if (!isalpha(*wildcard) ||
402 wildcard[1] != ':' ||
403 wildcard[2] != '\\' || ((flags & DRIVE_IGNORE)))
404 return FALSE; // Not a directory or ignore requested
405
406 includefiles = flags & DRIVE_INCLUDEFILES ? TRUE : fFilesInTree;
407
408 isremote = flags & DRIVE_REMOTE ? TRUE : FALSE;
409
410 if (isremote) {
411 if (fRemoteBug) {
412 if (brokenlan) {
413 ddepth = (ULONG)-1;
414 ddepth--;
415 }
416 ulM = 1;
417 }
418 }
419 else if (isbroken)
420 ddepth = 14;
421
422 if (!fRemoteBug)
423 ulM = ddepth <= DDEPTH ? ddepth : 1;
424
425 nm = ulM;
426
427 DosError(FERR_DISABLEHARDERR);
428
429 fl = includefiles ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY;
430
431 //DbgMsg(pszSrcFile, __LINE__, "Stubby DosFindFirst(%s)", wildcard); // 2015-08-19 SHL FIXME debug
432
433 rc = DosFindFirst(wildcard,
434 &hDir,
435 FILE_NORMAL | fl |
436 FILE_READONLY | FILE_ARCHIVED |
437 FILE_SYSTEM | FILE_HIDDEN,
438 &ffb, ulM * sizeof(FILEFINDBUF3), &nm, FIL_STANDARD);
439 if (ulM == 1 && !rc) {
440 // Loop looking for 1st directory (or file)
441 do {
442 pffb = &ffb[0];
443 if (!includefiles && !(pffb->attrFile & FILE_DIRECTORY) && !brokenlan) {
444 // Find returned file when only directories requested
445 brokenlan = TRUE;
446 ddepth = (ULONG)-1;
447 ddepth--;
448 if (!NoBrokenNotify) {
449 prc = saymsg(MB_YESNO | MB_ICONEXCLAMATION,
450 HWND_DESKTOP,
451 GetPString(IDS_LANERRORTITLETEXT),
452 GetPString(IDS_LANERRORTEXT));
453 if (prc == MBID_NO) {
454 saymsg(MB_ENTER,
455 HWND_DESKTOP,
456 GetPString(IDS_LANERROR2TITLETEXT),
457 GetPString(IDS_LANERROR2TEXT));
458 NoBrokenNotify = 255;
459 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
460 &NoBrokenNotify, sizeof(ULONG));
461 }
462 }
463 else {
464 NoBrokenNotify--;
465 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
466 &NoBrokenNotify, sizeof(ULONG));
467 }
468 }
469
470 if (*pffb->achName &&
471 (includefiles || (pffb->attrFile & FILE_DIRECTORY)) &&
472 (pffb->achName[0] != '.' ||
473 (pffb->achName[1] &&
474 (pffb->achName[1] != '.' || pffb->achName[2])))) {
475 // Got directory other than . or .. (or a file)
476 DosFindClose(hDir);
477 isadir = TRUE;
478 goto Interruptus;
479 }
480 nm = 1;
481 DosError(FERR_DISABLEHARDERR);
482 } while (++total < ddepth && !(rc = (DosFindNext(hDir,
483 &ffb,
484 sizeof(FILEFINDBUF3),
485 &nm))));
486 DosFindClose(hDir);
487
488 if (toupper(*pciParent->pszFileName) > 'B' &&
489 (*(pciParent->pszFileName + 1)) == ':' &&
490 (*(pciParent->pszFileName + 2)) == '\\' && !(*(pciParent->pszFileName + 3))) {
491
492 // Searching root of hard or remote drive and find reported error
493 CHAR s[132];
494 sprintf(s,
495 GetPString(IDS_NOSUBDIRSTEXT),
496 total, toupper(*pciParent->pszFileName));
497 if (rc && rc != ERROR_NO_MORE_FILES)
498 sprintf(&s[strlen(s)], GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
499 else if (ddepth < 16)
500 brokenlan = TRUE;
501 Notify(s);
502 }
503 goto None; // Done
504 }
505 if (!rc) {
506 DosFindClose(hDir);
507 if (nm) {
508 PBYTE fb = (PBYTE)&ffb[0];
509 for (len = 0; len < nm; len++) {
510 pffb = (PFILEFINDBUF3) fb;
511 if (!includefiles && !(pffb->attrFile & FILE_DIRECTORY)) {
512 // Got file(s), but did not ask for files
513 if (!isbroken) {
514 isbroken = TRUE;
515 if (!NoBrokenNotify) {
516 prc = saymsg(MB_YESNO | MB_ICONEXCLAMATION,
517 HWND_DESKTOP,
518 GetPString(IDS_FSDERRORTITLETEXT),
519 GetPString(IDS_FSDERRORTEXT),
520 isremote ? GetPString(IDS_REMOTETEXT) :
521 GetPString(IDS_LOCALTEXT),
522 *wildcard);
523 if (prc == MBID_NO) {
524 saymsg(MB_ENTER,
525 HWND_DESKTOP,
526 GetPString(IDS_FSDERROR2TITLETEXT),
527 GetPString(IDS_FSDERROR2TEXT));
528 NoBrokenNotify = 255;
529 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
530 &NoBrokenNotify, sizeof(ULONG));
531 }
532 }
533 else {
534 NoBrokenNotify--;
535 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
536 &NoBrokenNotify, sizeof(ULONG));
537 }
538 } // if !broken
539 } // if !directory
540
541 if (*pffb->achName &&
542 (includefiles || (pffb->attrFile & FILE_DIRECTORY)) &&
543 ((pffb->achName[0] && pffb->achName[0] != '.') ||
544 (pffb->achName[1] &&
545 (pffb->achName[1] != '.' || pffb->achName[2]))))
546 {
547 // Got directory other than . or .. (or a file)
548 isadir = TRUE;
549 break;
550 }
551 fb += pffb->oNextEntryOffset;
552 } // for
553
554 Interruptus:
555
556 if (isadir) {
557
558 // Insert CNRITEM for selected directory (or file)
559 PCNRITEM pci;
560
561 if (WinIsWindow((HAB)0, hwndCnr)) {
562 pci = WinSendMsg(hwndCnr,
563 CM_ALLOCRECORD,
564 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(1));
565 if (!pci) {
566 Win_Error(hwndCnr, HWND_DESKTOP, __FILE__, __LINE__,
567 GetPString(IDS_RECORDALLOCFAILEDTEXT));
568 }
569 else {
570 RECORDINSERT ri;
571 CHAR szBuffer[CCHMAXPATH + 14];
572 CHAR *p;
573 HPOINTER hptr;
574
575 p = strchr(wildcard, '*');
576 *p = 0;;
577 BldFullPathName(szBuffer, wildcard, pffb->achName);
578 pci->pszFileName = xstrdup(szBuffer, pszSrcFile, __LINE__); //NullStr; // 2015-08-19 SHL FIXME to doc why
579 p = strrchr(pci->pszFileName, '\\');
580 p++;
581 pci->pszDisplayName = p; //NullStr;
582 pci->rc.pszIcon = pci->pszDisplayName;
583 if (fForceUpper)
584 strupr(pci->pszFileName);
585 else if (fForceLower)
586 strlwr(pci->pszFileName);
587
588 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
589
590 // get an icon to use with it
591 if (pffb->attrFile & FILE_DIRECTORY) {
592 // is directory
593 if (fNoIconsDirs ||
594 (flags & DRIVE_NOLOADICONS) ||
595 !isalpha(*pci->pszFileName)) {
596 hptr = (HPOINTER) 0;
597 }
598 else
599 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
600 }
601 else {
602 // is file
603 if (fNoIconsFiles ||
604 (flags & DRIVE_NOLOADICONS) ||
605 !isalpha(*pci->pszFileName)) {
606 hptr = (HPOINTER) 0;
607 }
608 else
609 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
610
611 if (!hptr || IsDefaultIcon(hptr))
612 hptr = IDFile(pci->pszFileName);
613 }
614
615 if (!hptr) {
616 hptr = pffb->attrFile & FILE_DIRECTORY ?
617 hptrDir : pffb->attrFile & FILE_SYSTEM ?
618 hptrSystem : pffb->attrFile & FILE_HIDDEN ?
619 hptrHidden : pffb->attrFile & FILE_READONLY ?
620 hptrReadonly : hptrFile;
621 }
622 pci->rc.hptrIcon = hptr;
623 memset(&ri, 0, sizeof(RECORDINSERT));
624 ri.cb = sizeof(RECORDINSERT);
625 ri.pRecordOrder = (PRECORDCORE)CMA_END;
626 ri.pRecordParent = (PRECORDCORE)pciParent;
627 ri.zOrder = (ULONG)CMA_TOP;
628 ri.cRecordsInsert = 1;
629 ri.fInvalidateRecord = TRUE;
630#if 0 // 2015-08-03 SHL FIXME debug
631 if (pci->pszFileName == NullStr)
632 DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD %p \"%s\" %.255s", pci, pci->pszFileName, pffb->achName);
633#endif
634 if (!WinSendMsg(hwndCnr,
635 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
636 // Assume busy and try again
637 DosSleep(50); //05 Aug 07 GKY 100
638 WinSetFocus(HWND_DESKTOP, hwndCnr);
639 if (WinIsWindow((HAB)0, hwndCnr)) {
640#if 0
641 if (!fNoFleshDbgMsg) {
642 // 2015-08-03 SHL FIXME debug
643 //if (pci->pszFileName == NullStr)
644 // DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD pci %p pszFileName \"%s\"", pci, pci->pszFileName); // 2015-08-03 SHL FIXME debug
645 }
646#endif
647 if (!WinSendMsg(hwndCnr,
648 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
649 Win_Error(hwndCnr, HWND_DESKTOP, __FILE__, __LINE__,
650 GetPString(IDS_RECORDINSERTFAILEDTEXT));
651 FreeCnrItem(hwndCnr, pci);
652 }
653 else
654 ok = TRUE;
655 }
656 }
657 else
658 ok = TRUE;
659 }
660 }
661 } // if isadir
662 }
663 } // if !rc
664 else if (toupper(*wildcard) > 'B' && wildcard[1] == ':' && wildcard[2] == '\\' &&
665 wildcard[3] == '*' && !wildcard[4]) {
666 // Is root and no subdirectories
667 CHAR s[162];
668
669 sprintf(s,
670 GetPString(IDS_NOSUBDIRS2TEXT),
671 nm,
672 toupper(*pciParent->pszFileName),
673 isremote ? GetPString(IDS_NOSUBDIRS3TEXT) : NullStr);
674 Notify(s);
675 }
676 else if (toupper(*wildcard) > 'B' && rc != ERROR_NO_MORE_FILES) {
677 // Find for remote or hard drive failed with error
678 CHAR s[CCHMAXPATH + 80];
679 sprintf(s, GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
680 Notify(s);
681 }
682
683None:
684
685 DosError(FERR_DISABLEHARDERR);
686 return ok;
687} // Stubby
688
689// Stubby/Flesh/Unflesh work list item
690
691typedef struct {
692 LIST2 list;
693 HWND hwndCnr;
694 PCNRITEM pci;
695 FLESHWORKACTION action;
696} FLESHWORKITEM;
697typedef FLESHWORKITEM *PFLESHWORKITEM;
698
699// Stubby/Flesh/Unflesh work list
700LIST2 FleshWorkList;
701
702HMTX hmtxFleshWork;
703HEV hevFleshWorkListChanged;
704
705/**
706 * Check work list item pci matches passed pci
707 */
708
709BOOL WorkListItemMatches(PLIST2 item, PVOID data)
710{
711 return ((PFLESHWORKITEM)data)->pci == ((PFLESHWORKITEM)item)->pci;
712}
713
714/**
715 * Delete stale items from flesh queue
716 */
717
718VOID DeleteStaleFleshWorkListItems(PCNRITEM pci)
719{
720 FLESHWORKITEM match;
721 PLIST2 item;
722
723 match.pci = pci;
724
725 for (;;) {
726 item = List2Search(&FleshWorkList, WorkListItemMatches, &match);
727 if (!item)
728 break;
729 //DbgMsg(pszSrcFile, __LINE__, "DeleteStaleFleshWorkListItems deleting %p %s", pci, pci->pszFileName ? pci->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
730 List2Delete(&FleshWorkList, item);
731 xfree(item, pszSrcFile, __LINE__);
732 }
733}
734
735/**
736 * Add item to flesh work list
737 * eUnFlesh requests get special handling
738 * eFlesh etc. items for the same CNRITEM are considered stale and are
739 * deleted because eUnFlesh will free the CNRITEM associated with the item
740 * before the work list item is processed
741 */
742
743#ifndef AddFleshWorkRequest // 2015-08-03 SHL FIXME debug
744BOOL AddFleshWorkRequest(HWND hwndCnr, PCNRITEM pci, FLESHWORKACTION action)
745#else
746BOOL AddFleshWorkRequestDbg(HWND hwndCnr, PCNRITEM pci, FLESHWORKACTION action, PCSZ pszSrcFile_, UINT uSrcLineNo)
747#endif
748{
749 PFLESHWORKITEM item = xmallocz(sizeof(FLESHWORKITEM), pszSrcFile, __LINE__);
750 item->hwndCnr = hwndCnr;
751 item->pci = pci;
752 item->action= action;
753
754 if (fAmQuitting)
755 return FALSE;
756
757 // 2015-08-03 SHL FIXME debug
758#if 0 // 2015-08-13 SHL FIXME to be gone
759 {
760 static PSZ itemNames[] = {
761 "eStubby", "eFlesh", "eFleshEnv", "eUnFlesh"
762 };
763
764# ifdef AddFleshWorkRequest
765 if (!pci || (INT)pci == -1) {
766 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p by %s:%u",
767 itemNames[item->action],
768 pci,
769 pszSrcFile_, uSrcLineNo);
770 }
771 else if (!pci->pszFileName) {
772 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest call with action %s pci %p pszFileName (null) by %s:%u",
773 itemNames[item->action],
774 pci,
775 pszSrcFile_, uSrcLineNo);
776 }
777 else if (!fNoFleshDbgMsg) {
778 DbgMsg(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p pszFileName %s by %s:%u",
779 itemNames[item->action],
780 pci,
781 pci->pszFileName,
782 pszSrcFile_, uSrcLineNo); // 2015-08-03 SHL FIXME debug
783 }
784#else
785 if (!pci || (INT)pci == -1) {
786 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest call with action %s pci %p",
787 itemNames[item->action],
788 pci);
789 }
790 else if (!pci->pszFileName) {
791 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p pszFileName (null)",
792 itemNames[item->action],
793 pci);
794 }
795 else if (!fNoFleshDbgMsg) {
796 DbgMsg(pszSrcFile, __LINE__, "AddFleshWorkRequest action %s pci %p pszFileName %s",
797 itemNames[item->action],
798 pci,
799 pci->pszFileName); // 2015-08-03 SHL FIXME debug
800 }
801#endif
802 }
803#endif
804
805 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
806
807 // Delete stale requests
808 if (item->action == eUnFlesh)
809 DeleteStaleFleshWorkListItems(pci);
810
811 List2Append(&FleshWorkList, (PLIST2)item);
812
813 xDosReleaseMutexSem(hmtxFleshWork);
814 xDosPostEventSem(hevFleshWorkListChanged);
815
816 return TRUE;
817}
818
819/**
820 * Return TRUE if work list empty
821 * Advisory only
822 */
823
824BOOL IsFleshWorkListEmpty()
825{
826 return FleshWorkList.next == NULL;
827}
828
829/**
830 * Check if pci pathname is parent of child path name
831 * @param data is child path name
832 * @return TRUE if is work item path is parent of given path
833 */
834
835BOOL IsParentOfChildPath(PLIST2 item, PVOID data)
836{
837 UINT c;
838 if (!((PFLESHWORKITEM)item)->pci->pszFileName) {
839 Runtime_Error(pszSrcFile, __LINE__, "IsParentOfChildPath called with pci %p pszFileName (null)", ((PFLESHWORKITEM)item)->pci);
840 return FALSE;
841 }
842 c = strlen(((PFLESHWORKITEM)item)->pci->pszFileName);
843 // 2015-08-23 SHL FIXME to not trap for Gregg
844 return strncmp(((PFLESHWORKITEM)item)->pci->pszFileName, (PCSZ)data, c) == 0;
845}
846
847/**
848 * Wait until work list empty or until dependent items removed from list
849 * Advisory only
850 * @parse pszFileName is dependent pathName
851 */
852
853#ifndef WaitFleshWorkListEmpty // 2015-08-03 SHL FIXME debug
854VOID WaitFleshWorkListEmpty(PCSZ pszDirName)
855#else
856VOID WaitFleshWorkListEmptyDbg(PCSZ pszDirName, PCSZ pszSrcFile_, UINT uSrcLineNo_)
857#endif
858{
859 APIRET rc;
860 PFLESHWORKITEM item;
861 INT tid = GetTidForThread();
862 BOOL pathSaved = FALSE;
863 BOOL waited;
864 PCSZ pszSavedFleshFocusPath;
865
866 if (tid == 1 || tid == tidFleshWorkListThread) {
867# ifdef WaitFleshWorkListEmpty
868 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist %sempty by tid %u at %s:%u", IsFleshWorkListEmpty() ? "" : "not ", tid, pszSrcFile_, uSrcLineNo_);
869# else
870 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called by tid %u", tid);
871# endif
872 return; // Avoid hang
873 }
874#if 0
875 else if (IsFleshWorkListEmpty()) {
876# ifdef WaitFleshWorkListEmpty
877 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist empty at %s:%u", pszSrcFile_, uSrcLineNo_);
878# else
879 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list empty");
880# endif
881 }
882#endif
883
884 // Can not wait if call from thread 1 or FleshWorkListThread
885 for (waited = FALSE; !IsFleshWorkListEmpty(); waited = TRUE) {
886
887#if 0 // 2015-08-19 SHL FIXME debug
888# ifdef WaitFleshWorkListEmpty
889 if (!fNoFleshDbgMsg)
890 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty by %s:%u", pszSrcFile_, uSrcLineNo_); // 2015-08-07 SHL FIXME debug
891# else
892 if (!fNoFleshDbgMsg)
893 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty"); // 2015-08-07 SHL FIXME debug
894# endif
895#endif // 2015-08-19 SHL FIXME debug
896
897 // 2015-08-13 SHL
898 if (fAmQuitting)
899 return;
900
901 // Just wait for dependents to be gone if path name given
902 if (pszDirName) {
903 rc = xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
904 if (rc)
905 continue; // Maybe should return ???
906
907 if (!pathSaved) {
908 // Give priority to work items for parents of this path
909 pathSaved = TRUE;
910 pszSavedFleshFocusPath = pszFleshFocusPath;
911 pszFleshFocusPath = pszDirName;
912 }
913
914 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszDirName);
915
916 xDosReleaseMutexSem(hmtxFleshWork);
917
918 if (!item) {
919 if (waited)
920 DosSleep(100); // Let PM do some work
921 break; // Dependents gone from work list
922 }
923 } // if pszDirName
924
925 DosSleep(250);
926 } // for
927
928 if (pathSaved) {
929 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
930 pszFleshFocusPath = pszSavedFleshFocusPath;
931 xDosReleaseMutexSem(hmtxFleshWork);
932 }
933
934}
935
936/**
937 * Set focus drive to optimize work list processing
938 * @param chDriveLetter is upper case drive letter (A-Z)
939 */
940
941VOID SetFleshFocusPath(PCSZ pszPath) {
942 PCSZ pszOld;
943 PCSZ pszNew = strdup(pszPath);
944 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
945 pszOld = pszFleshFocusPath;
946 pszFleshFocusPath = pszNew;
947 xDosReleaseMutexSem(hmtxFleshWork);
948 if (pszOld)
949 xfree((PVOID)pszOld, pszSrcFile, __LINE__);
950 //DbgMsg(pszSrcFile, __LINE__, "SetFleshFocusPath focus path set to %s", pszFleshFocusPath); // 2015-08-03 SHL FIXME debug
951
952}
953
954/**
955 * Run Flesh, UnFlesh, FleshEnv, Stubby for directory for items in work list
956 */
957
958VOID FleshWorkThread(PVOID arg)
959{
960 HAB thab;
961 HMQ hmq = (HMQ)0;
962
963 // 2015-08-07 SHL FIXME to be gone
964 static INT ProcessDirCount = 0;
965
966 DosError(FERR_DISABLEHARDERR);
967
968# ifdef FORTIFY
969 Fortify_EnterScope();
970# endif
971
972 thab = WinInitialize(0);
973 if (thab) {
974 hmq = WinCreateMsgQueue(thab, 0);
975 if (hmq) {
976 IncrThreadUsage();
977 priority_normal();
978
979 // process list entries until time to die
980 for (;!fAmQuitting;) {
981
982 PFLESHWORKITEM item;
983
984 // 2015-08-07 SHL FIXME to use SMPSafe...
985 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
986
987 // 2015-08-14 SHL
988 // Get next work list item and remove from list
989 // If focus path set, process parents of focus path first
990 if (pszFleshFocusPath) {
991 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszFleshFocusPath);
992 if (!item) {
993 xfree((PSZ)pszFleshFocusPath, pszSrcFile, __LINE__);
994 pszFleshFocusPath = NULL; // Revert to normal
995 }
996 else
997 List2Delete(&FleshWorkList, (PLIST2)item);
998 }
999 else
1000 item = NULL;
1001
1002 if (!item)
1003 item = (PFLESHWORKITEM)List2DeleteFirst(&FleshWorkList);
1004
1005 xDosReleaseMutexSem(hmtxFleshWork);
1006
1007 // Wait for new items to be added to list
1008 if (!item) {
1009 ULONG ul;
1010#if 0
1011 if (!fNoFleshDbgMsg)
1012 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work list empty - waiting"); // 2015-08-03 SHL FIXME debug
1013#endif
1014 xDosWaitEventSem(hevFleshWorkListChanged, SEM_INDEFINITE_WAIT);
1015 xDosResetEventSem(hevFleshWorkListChanged, &ul);
1016#if 0
1017 if (!fNoFleshDbgMsg)
1018 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work hev posted"); // 2015-08-03 SHL FIXME debug
1019#endif
1020 continue;
1021 }
1022
1023 if (WinIsWindow((HAB)0, item->hwndCnr)) {
1024#if 0 // 2015-08-07 SHL FIXME debug
1025 {
1026 static PSZ itemNames[] = {
1027 "eStubby", "eFlesh", "eFleshEnv", "eUnFlesh"
1028 };
1029
1030 PCNRITEM pci = item->pci;
1031 if (!fNoFleshDbgMsg) {
1032 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread action %s pci %p pszFileName %s",
1033 itemNames[item->action],
1034 pci,
1035 pci && (INT)pci != -1 ?
1036 (pci->pszFileName ? pci->pszFileName : "(nullname)") :
1037 "(nullpci)"); // 2015-08-03 SHL FIXME debug
1038 }
1039 }
1040#endif
1041
1042 switch (item->action) {
1043 case eUnFlesh:
1044 UnFlesh(item->hwndCnr, item->pci);
1045 break;
1046 case eFleshEnv:
1047 FleshEnv(item->hwndCnr, item->pci);
1048 break;
1049 case eStubby:
1050 // DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread pci %p pszFileName %s", stubbyArgs->pci, stubbyArgs->pci->pszFileName); // 2015-08-03 SHL FIXME debug
1051 priority_bumped();
1052 Stubby(item->hwndCnr, item->pci);
1053 priority_normal();
1054 break;
1055 case eFlesh:
1056 if (Flesh(item->hwndCnr, item->pci)) {
1057 // 2015-08-06 SHL FIXME to report?
1058 }
1059 break;
1060 default:
1061 Runtime_Error(pszSrcFile, __LINE__, "item %u unexpected", item->action);
1062 } // switch
1063
1064
1065 } // if window
1066
1067 xfree(item, pszSrcFile, __LINE__);
1068
1069 } // for
1070
1071 WinDestroyMsgQueue(hmq);
1072 }
1073 DecrThreadUsage();
1074 WinTerminate(thab);
1075 }
1076
1077 ProcessDirCount++;
1078 // DbgMsg(pszSrcFile, __LINE__, "ProcessDirCount %i FixedVolume %i", ProcessDirCount, FixedVolume);
1079 if (ProcessDirCount >= FixedVolume) {
1080 ProcessDirCount = 0;
1081 FixedVolume = 0;
1082 }
1083
1084# ifdef FORTIFY
1085 Fortify_LeaveScope();
1086# endif
1087
1088}
1089
1090/**
1091 * Allocate resources and start FleshWorkThread
1092 * @return TRUE if OK
1093 */
1094
1095BOOL StartFleshWorkThread()
1096{
1097 APIRET rc = DosCreateMutexSem(NULL, &hmtxFleshWork, 0L /* Not shared */, FALSE /* Not owned */);
1098 if (rc) {
1099 Dos_Error(MB_CANCEL, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1100 PCSZ_DOSCREATEMUTEXSEM);
1101 return FALSE;
1102 }
1103
1104 rc = xDosCreateEventSem(NULL, &hevFleshWorkListChanged, 0 /* Not shared */, FALSE /* Reset */);
1105 if (rc)
1106 return FALSE; // Give up
1107#if 0
1108 /*DbgMsg is time consuming
1109 define FM2_NO_FLESH_DBGMSG to suppress
1110 2015-08-09 SHL FIXME to be gone
1111 */
1112
1113 fNoFleshDbgMsg = getenv("FM2_NO_FLESH_DBGMSG") != NULL;
1114#endif
1115 tidFleshWorkListThread = xbeginthread(FleshWorkThread,
1116 65536,
1117 NULL,
1118 pszSrcFile, __LINE__);
1119 return tidFleshWorkListThread != -1;
1120
1121}
1122
1123#pragma alloc_text(FLESH,Flesh,FleshEnv,UnFlesh,Stubby,FleshWorkThread,StartFleshWorkThread,AddFleshWorkRequest)
Note: See TracBrowser for help on using the repository browser.