source: trunk/dll/flesh.c@ 1879

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

Code cleanup fix declares

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