source: trunk/dll/flesh.c@ 1892

Last change on this file since 1892 was 1891, checked in by Steven Levine, 6 years ago

Rework FreeCnrItem to ensure all CNRITEMs deleted.
Use WinSendMsg CMA_NEXT.
Was using preccNextRecord which is not recommended because control does
not maintain linkage after inserts and deletes.
Note: arccnrs.c still needs to be reworked to use common functions from filldir.c.

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