source: trunk/dll/flesh.c@ 1880

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

Remove dead code and comments from remaining c files. #if 0 and #if NEVER were not addressed

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