source: trunk/dll/flesh.c@ 1860

Last change on this file since 1860 was 1860, checked in by Steven Levine, 10 years ago

Rework FlesWaitForWorkListEmpty to support wait for parents of path
Add more wrappers for mutex and event semaphores
Clean up some obsolete code

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