source: trunk/dll/flesh.c@ 1873

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

Adjustments to ShowTreeRec to eliminate failures and reduce retries and container noise on tree switches. Remove fInitialDriveScan code. Changes to speed up ExpandAll. WaitFleshWorkListEmpty now gives error message and returns if semaphore request fails more than 5 consecutive times.

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