source: trunk/dll/flesh.c@ 1882

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

ExpandAll on a CDROM drive caused directory not found errors. Changed waits so they are longer on removable drives errors are gone performance on hard drives is unchanged.

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