source: trunk/dll/flesh.c@ 1863

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

Remove recurse scan code; fix A:\ drive not ready error caused by not moving the cursor from drive A:\ fast enough. Have Flesh remove pcis that have NullStr FileNames.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.0 KB
Line 
1
2/***********************************************************************
3
4 $Id: flesh.c 1863 2015-08-23 00:13:48Z 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
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 || !strcmp(pciL->pszFileName, NullStr)) {
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 return TRUE;
290 }
291
292 return FALSE;
293}
294
295/**
296 * Remove children from container
297 * @parame pciParent is parent of children to be removed
298 */
299
300VOID UnFlesh(HWND hwndCnr, PCNRITEM pciParent)
301{
302 BOOL removed = FALSE;
303 PCNRITEM pciL;
304
305 if (!pciParent || !hwndCnr)
306 return;
307
308 if (!fNoFleshDbgMsg)
309 DbgMsg(pszSrcFile, __LINE__, "UnFlesh pciParent %p pszFileName %s", pciParent, pciParent->pszFileName ? pciParent->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
310
311 for (;;) {
312 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
313 CM_QUERYRECORD,
314 MPFROMP(pciParent),
315 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
316 if (!pciL || (INT)pciL == -1)
317 break; // Done
318
319 if (!fNoFleshDbgMsg)
320 DbgMsg(pszSrcFile, __LINE__, "UnFlesh RemoveCnrItems() pciL %p %s", pciL, pciL->pszFileName ? pciL->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
321 RemoveCnrItems(hwndCnr, pciL, 1, CMA_FREE);
322 removed = TRUE;
323 } // for
324
325 if (removed) {
326 WinSendMsg(hwndCnr,
327 CM_INVALIDATERECORD,
328 MPFROMP(&pciParent),
329 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
330 }
331 return;
332}
333
334#define DDEPTH 64
335
336/**
337 * Insert CNRITEM for 1st subdirectory [or file] of pciParent
338 * @param hwdCnr is container to be filled
339 * @param pciParent is CNRITEM to receive child record
340 * @return TRUE if record inserted, else FALSE
341 * Ensures that expand/collapse button displays if directory has children
342 * Secondary purpose is to detect broken LANs and inaccesible mapped drives
343 */
344
345BOOL Stubby(HWND hwndCnr, PCNRITEM pciParent)
346{
347 /**
348 * this code is full of workarounds for screwed up LANs.
349 * let's hope all the current LAN programmers fall into
350 * a black hole and make way for people who can get it right...
351 */
352
353 BOOL ok = FALSE;
354 FILEFINDBUF3 ffb[DDEPTH];
355 PFILEFINDBUF3 pffb;
356 HDIR hDir = HDIR_CREATE;
357 ULONG nm, ulM = 1, total = 0, fl;
358 CHAR wildcard[CCHMAXPATH];
359 register INT len;
360 APIRET rc, prc;
361 BOOL isadir = FALSE;
362 BOOL isremote;
363 BOOL includefiles;
364 ULONG ddepth = DDEPTH;
365 ULONG drvNum;
366 ULONG flags;
367 static BOOL brokenlan = FALSE, isbroken = FALSE;
368
369 if (!pciParent || (INT)pciParent == -1 || !*pciParent->pszFileName
370 || pciParent->pszFileName == NullStr || !hwndCnr)
371 return FALSE;
372
373 if (!fNoFleshDbgMsg)
374 DbgMsg(pszSrcFile, __LINE__, "Stubby pciParent %p pszFileName %s", pciParent, pciParent->pszFileName); // 2015-08-03 SHL FIXME debug
375
376 // Build wildcard
377 len = strlen(pciParent->pszFileName);
378 memcpy(wildcard, pciParent->pszFileName, len + 1);
379 if (wildcard[len - 1] != '\\')
380 wildcard[len++] = '\\';
381 wildcard[len++] = '*';
382 wildcard[len] = 0;
383
384 // 2015-08-19 SHL FIXME to know how this can happen
385 if (!isalpha(*wildcard) || wildcard[1] != ':' || wildcard[2] != '\\') {
386 MakeFullName(wildcard);
387 DbgMsg(pszSrcFile, __LINE__, "Stubby MakeFullName returned %s", wildcard); // 2015-08-19 SHL FIXME debug
388 }
389
390 drvNum = toupper(*pciParent->pszFileName) - 'A';
391 flags = driveflags[drvNum];
392 if (!isalpha(*wildcard) ||
393 wildcard[1] != ':' ||
394 wildcard[2] != '\\' || ((flags & DRIVE_IGNORE)))
395 return FALSE; // Not a directory or ignore requested
396
397 includefiles = flags & DRIVE_INCLUDEFILES ? TRUE : fFilesInTree;
398
399 isremote = flags & DRIVE_REMOTE ? TRUE : FALSE;
400
401 if (isremote) {
402 if (fRemoteBug) {
403 if (brokenlan) {
404 ddepth = (ULONG)-1;
405 ddepth--;
406 }
407 ulM = 1;
408 }
409 }
410 else if (isbroken)
411 ddepth = 14;
412
413 if (!fRemoteBug)
414 ulM = ddepth <= DDEPTH ? ddepth : 1;
415
416 nm = ulM;
417
418 DosError(FERR_DISABLEHARDERR);
419
420 fl = includefiles ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY;
421
422 DbgMsg(pszSrcFile, __LINE__, "Stubby DosFindFirst(%s)", wildcard); // 2015-08-19 SHL FIXME debug
423
424 rc = DosFindFirst(wildcard,
425 &hDir,
426 FILE_NORMAL | fl |
427 FILE_READONLY | FILE_ARCHIVED |
428 FILE_SYSTEM | FILE_HIDDEN,
429 &ffb, ulM * sizeof(FILEFINDBUF3), &nm, FIL_STANDARD);
430 if (ulM == 1 && !rc) {
431 // Loop looking for 1st directory (or file)
432 do {
433 pffb = &ffb[0];
434 if (!includefiles && !(pffb->attrFile & FILE_DIRECTORY) && !brokenlan) {
435 // Find returned file when only directories requested
436 brokenlan = TRUE;
437 ddepth = (ULONG)-1;
438 ddepth--;
439 if (!NoBrokenNotify) {
440 prc = saymsg(MB_YESNO | MB_ICONEXCLAMATION,
441 HWND_DESKTOP,
442 GetPString(IDS_LANERRORTITLETEXT),
443 GetPString(IDS_LANERRORTEXT));
444 if (prc == MBID_NO) {
445 saymsg(MB_ENTER,
446 HWND_DESKTOP,
447 GetPString(IDS_LANERROR2TITLETEXT),
448 GetPString(IDS_LANERROR2TEXT));
449 NoBrokenNotify = 255;
450 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
451 &NoBrokenNotify, sizeof(ULONG));
452 }
453 }
454 else {
455 NoBrokenNotify--;
456 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
457 &NoBrokenNotify, sizeof(ULONG));
458 }
459 }
460
461 if (*pffb->achName &&
462 (includefiles || (pffb->attrFile & FILE_DIRECTORY)) &&
463 (pffb->achName[0] != '.' ||
464 (pffb->achName[1] &&
465 (pffb->achName[1] != '.' || pffb->achName[2])))) {
466 // Got directory other than . or .. (or a file)
467 DosFindClose(hDir);
468 isadir = TRUE;
469 goto Interruptus;
470 }
471 nm = 1;
472 DosError(FERR_DISABLEHARDERR);
473 } while (++total < ddepth && !(rc = (DosFindNext(hDir,
474 &ffb,
475 sizeof(FILEFINDBUF3),
476 &nm))));
477 DosFindClose(hDir);
478
479 if (toupper(*pciParent->pszFileName) > 'B' &&
480 (*(pciParent->pszFileName + 1)) == ':' &&
481 (*(pciParent->pszFileName + 2)) == '\\' && !(*(pciParent->pszFileName + 3))) {
482
483 // Searching root of hard or remote drive and find reported error
484 CHAR s[132];
485 sprintf(s,
486 GetPString(IDS_NOSUBDIRSTEXT),
487 total, toupper(*pciParent->pszFileName));
488 if (rc && rc != ERROR_NO_MORE_FILES)
489 sprintf(&s[strlen(s)], GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
490 else if (ddepth < 16)
491 brokenlan = TRUE;
492 Notify(s);
493 }
494 goto None; // Done
495 }
496
497 if (!rc) {
498 DosFindClose(hDir);
499 if (nm) {
500 PBYTE fb = (PBYTE)&ffb[0];
501 for (len = 0; len < nm; len++) {
502 pffb = (PFILEFINDBUF3) fb;
503 if (!includefiles && !(pffb->attrFile & FILE_DIRECTORY)) {
504 // Got file(s), but did not ask for files
505 if (!isbroken) {
506 isbroken = TRUE;
507 if (!NoBrokenNotify) {
508 prc = saymsg(MB_YESNO | MB_ICONEXCLAMATION,
509 HWND_DESKTOP,
510 GetPString(IDS_FSDERRORTITLETEXT),
511 GetPString(IDS_FSDERRORTEXT),
512 isremote ? GetPString(IDS_REMOTETEXT) :
513 GetPString(IDS_LOCALTEXT),
514 *wildcard);
515 if (prc == MBID_NO) {
516 saymsg(MB_ENTER,
517 HWND_DESKTOP,
518 GetPString(IDS_FSDERROR2TITLETEXT),
519 GetPString(IDS_FSDERROR2TEXT));
520 NoBrokenNotify = 255;
521 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
522 &NoBrokenNotify, sizeof(ULONG));
523 }
524 }
525 else {
526 NoBrokenNotify--;
527 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
528 &NoBrokenNotify, sizeof(ULONG));
529 }
530 } // if !broken
531 } // if !directory
532
533 if (*pffb->achName &&
534 (includefiles || (pffb->attrFile & FILE_DIRECTORY)) &&
535 ((pffb->achName[0] && pffb->achName[0] != '.') ||
536 (pffb->achName[1] &&
537 (pffb->achName[1] != '.' || pffb->achName[2]))))
538 {
539 // Got directory other than . or .. (or a file)
540 isadir = TRUE;
541 break;
542 }
543 fb += pffb->oNextEntryOffset;
544 } // for
545
546 Interruptus:
547
548 if (isadir) {
549
550 // Insert CNRITEM for selected directory (or file)
551 PCNRITEM pci;
552
553 if (WinIsWindow((HAB)0, hwndCnr)) {
554 pci = WinSendMsg(hwndCnr,
555 CM_ALLOCRECORD,
556 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(1));
557 if (!pci) {
558 Win_Error(hwndCnr, HWND_DESKTOP, __FILE__, __LINE__,
559 GetPString(IDS_RECORDALLOCFAILEDTEXT));
560 }
561 else {
562 RECORDINSERT ri;
563 // 2015-08-19 SHL FIXME to use BldFullPathName(wildcard, ...)
564 pci->pszFileName = NullStr; // 2015-08-19 SHL FIXME to doc why
565 pci->pszDisplayName = NullStr;
566 pci->rc.pszIcon = pci->pszDisplayName;
567 memset(&ri, 0, sizeof(RECORDINSERT));
568 ri.cb = sizeof(RECORDINSERT);
569 ri.pRecordOrder = (PRECORDCORE)CMA_END;
570 ri.pRecordParent = (PRECORDCORE)pciParent;
571 ri.zOrder = (ULONG)CMA_TOP;
572 ri.cRecordsInsert = 1;
573 ri.fInvalidateRecord = TRUE;
574 // 2015-08-03 SHL FIXME debug
575 if (pci->pszFileName == NullStr)
576 DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD %p \"%s\" %.255s", pci, pci->pszFileName, pffb->achName);
577 if (!WinSendMsg(hwndCnr,
578 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
579 // Assume busy and try again
580 DosSleep(50); //05 Aug 07 GKY 100
581 WinSetFocus(HWND_DESKTOP, hwndCnr);
582 if (WinIsWindow((HAB)0, hwndCnr)) {
583 if (!fNoFleshDbgMsg) {
584 // 2015-08-03 SHL FIXME debug
585 if (pci->pszFileName == NullStr)
586 DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD pci %p pszFileName \"%s\"", pci, pci->pszFileName); // 2015-08-03 SHL FIXME debug
587 }
588 if (!WinSendMsg(hwndCnr,
589 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
590 Win_Error(hwndCnr, HWND_DESKTOP, __FILE__, __LINE__,
591 GetPString(IDS_RECORDINSERTFAILEDTEXT));
592 FreeCnrItem(hwndCnr, pci);
593 }
594 else
595 ok = TRUE;
596 }
597 }
598 else
599 ok = TRUE;
600 }
601 }
602 } // if isadir
603 else if (toupper(*wildcard) > 'B' && wildcard[1] == ':' && wildcard[2] == '\\' &&
604 !wildcard[3]) {
605
606 // 2015-08-19 SHL FIXME to know how this can happen since wildcard ends with *
607 // Is root and no subdirectories
608 CHAR s[162];
609 DbgMsg(pszSrcFile, __LINE__, "Stubby !isadir for %s", wildcard); // 2015-08-19 SHL FIXME debug
610 sprintf(s,
611 GetPString(IDS_NOSUBDIRS2TEXT),
612 nm,
613 toupper(*pciParent->pszFileName),
614 isremote ? GetPString(IDS_NOSUBDIRS3TEXT) : NullStr);
615 Notify(s);
616 }
617 }
618 }
619 else if (toupper(*wildcard) > 'B' && rc != ERROR_NO_MORE_FILES) {
620 // Find for remote or hard drive failed with error
621 CHAR s[CCHMAXPATH + 80];
622 sprintf(s, GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
623 Notify(s);
624 }
625
626None:
627
628 DosError(FERR_DISABLEHARDERR);
629 return ok;
630} // Stubby
631
632// Stubby/Flesh/Unflesh work list item
633
634typedef struct {
635 LIST2 list;
636 HWND hwndCnr;
637 PCNRITEM pci;
638 FLESHWORKACTION action;
639} FLESHWORKITEM;
640typedef FLESHWORKITEM *PFLESHWORKITEM;
641
642// Stubby/Flesh/Unflesh work list
643LIST2 FleshWorkList;
644
645HMTX hmtxFleshWork;
646HEV hevFleshWorkListChanged;
647
648/**
649 * Check work list item pci matches passed pci
650 */
651
652BOOL WorkListItemMatches(PLIST2 item, PVOID data)
653{
654 return ((PFLESHWORKITEM)data)->pci == ((PFLESHWORKITEM)item)->pci;
655}
656
657/**
658 * Delete stale items from flesh queue
659 */
660
661VOID DeleteStaleFleshWorkListItems(PCNRITEM pci)
662{
663 FLESHWORKITEM match;
664 PLIST2 item;
665
666 match.pci = pci;
667
668 for (;;) {
669 item = List2Search(&FleshWorkList, WorkListItemMatches, &match);
670 if (!item)
671 break;
672 DbgMsg(pszSrcFile, __LINE__, "DeleteStaleFleshWorkListItems deleting %p %s", pci, pci->pszFileName ? pci->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
673 List2Delete(&FleshWorkList, item);
674 xfree(item, pszSrcFile, __LINE__);
675 }
676}
677
678/**
679 * Add item to flesh work list
680 * eUnFlesh requests get special handling
681 * eFlesh etc. items for the same CNRITEM are considered stale and are
682 * deleted because eUnFlesh will free the CNRITEM associated with the item
683 * before the work list item is processed
684 */
685
686#if 0 // 2015-08-03 SHL FIXME debug
687BOOL AddFleshWorkRequest(HWND hwndCnr, PCNRITEM pci, FLESHWORKACTION action)
688#else
689BOOL AddFleshWorkRequestDbg(HWND hwndCnr, PCNRITEM pci, FLESHWORKACTION action, PCSZ pszSrcFile_, UINT uSrcLineNo)
690#endif
691{
692 PFLESHWORKITEM item = xmallocz(sizeof(FLESHWORKITEM), pszSrcFile, __LINE__);
693 item->hwndCnr = hwndCnr;
694 item->pci = pci;
695 item->action= action;
696
697 if (fAmQuitting)
698 return FALSE;
699
700 // 2015-08-03 SHL FIXME debug
701#if 0 // 2015-08-13 SHL FIXME to be gone
702 {
703 static PSZ itemNames[] = {
704 "eStubby", "eFlesh", "eFleshEnv", "eUnFlesh"
705 };
706
707# ifdef AddFleshWorkRequest
708 if (!pci || (INT)pci == -1) {
709 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p by %s:%u",
710 itemNames[item->action],
711 pci,
712 pszSrcFile_, uSrcLineNo);
713 }
714 else if (!pci->pszFileName) {
715 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest call with action %s pci %p pszFileName (null) by %s:%u",
716 itemNames[item->action],
717 pci,
718 pszSrcFile_, uSrcLineNo);
719 }
720 else if (!fNoFleshDbgMsg) {
721 DbgMsg(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p pszFileName %s by %s:%u",
722 itemNames[item->action],
723 pci,
724 pci->pszFileName,
725 pszSrcFile_, uSrcLineNo); // 2015-08-03 SHL FIXME debug
726 }
727#else
728 if (!pci || (INT)pci == -1) {
729 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest call with action %s pci %p",
730 itemNames[item->action],
731 pci);
732 }
733 else if (!pci->pszFileName) {
734 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p pszFileName (null)",
735 itemNames[item->action],
736 pci);
737 }
738 else if (!fNoFleshDbgMsg) {
739 DbgMsg(pszSrcFile, __LINE__, "AddFleshWorkRequest action %s pci %p pszFileName %s",
740 itemNames[item->action],
741 pci,
742 pci->pszFileName); // 2015-08-03 SHL FIXME debug
743 }
744#endif
745 }
746#endif
747
748 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
749
750 // Delete stale requests
751 if (item->action == eUnFlesh)
752 DeleteStaleFleshWorkListItems(pci);
753
754 List2Append(&FleshWorkList, (PLIST2)item);
755
756 xDosReleaseMutexSem(hmtxFleshWork);
757 xDosPostEventSem(hevFleshWorkListChanged);
758
759 return TRUE;
760}
761
762/**
763 * Return TRUE if work list empty
764 * Advisory only
765 */
766
767BOOL IsFleshWorkListEmpty()
768{
769 return FleshWorkList.next == NULL;
770}
771
772/**
773 * Check if pci pathname is parent of child path name
774 * @param data is child path name
775 * @return TRUE if is work item path is parent of given path
776 */
777
778BOOL IsParentOfChildPath(PLIST2 item, PVOID data)
779{
780 UINT c;
781 if (!((PFLESHWORKITEM)item)->pci->pszFileName) {
782 Runtime_Error(pszSrcFile, __LINE__, "IsParentOfChildPath called with pci %p pszFileName (null)", ((PFLESHWORKITEM)item)->pci);
783 return FALSE;
784 }
785 c = strlen(((PFLESHWORKITEM)item)->pci->pszFileName);
786 return strncmp(((PFLESHWORKITEM)item)->pci->pszFileName, (PCSZ)data, c) == 0;
787}
788
789/**
790 * Wait until work list empty or until dependent items removed from list
791 * Advisory only
792 * @parse pszFileName is dependent pathName
793 */
794
795#if 0 // 2015-08-03 SHL FIXME debug
796VOID WaitFleshWorkListEmpty(PCSZ pszDirName)
797#else
798VOID WaitFleshWorkListEmptyDbg(PCSZ pszDirName, PCSZ pszSrcFile_, UINT uSrcLineNo_)
799#endif
800{
801 APIRET rc;
802 PFLESHWORKITEM item;
803 INT tid = GetTidForThread();
804 BOOL pathSaved = FALSE;
805 PCSZ pszSavedFleshFocusPath;
806
807 if (tid == 1 || tid == tidFleshWorkListThread) {
808# ifdef WaitFleshWorkListEmpty
809 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist %sempty by tid %u at %s:%u", IsFleshWorkListEmpty() ? "" : "not ", tid, pszSrcFile_, uSrcLineNo_);
810# else
811 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called by tid %u", tid);
812# endif
813 return; // Avoid hang
814 }
815 else if (IsFleshWorkListEmpty()) {
816# ifdef WaitFleshWorkListEmpty
817 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist empty at %s:%u", pszSrcFile_, uSrcLineNo_);
818# else
819 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list empty");
820# endif
821 }
822
823 // Can not wait if call from thread 1 or FleshWorkListThread
824 while (!IsFleshWorkListEmpty()) {
825
826#if 0 // 2015-08-19 SHL FIXME debug
827# ifdef WaitFleshWorkListEmpty
828 if (!fNoFleshDbgMsg)
829 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty by %s:%u", pszSrcFile_, uSrcLineNo_); // 2015-08-07 SHL FIXME debug
830# else
831 if (!fNoFleshDbgMsg)
832 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty"); // 2015-08-07 SHL FIXME debug
833# endif
834#endif // 2015-08-19 SHL FIXME debug
835
836 // 2015-08-13 SHL
837 if (fAmQuitting)
838 return;
839
840 // Just wait for dependents to be gone if path name given
841 if (pszDirName) {
842 rc = xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
843 if (rc)
844 continue; // Maybe should return ???
845
846 if (!pathSaved) {
847 // Give priority to work items for parents of this path
848 pathSaved = TRUE;
849 pszSavedFleshFocusPath = pszFleshFocusPath;
850 pszFleshFocusPath = pszDirName;
851 }
852
853 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszDirName);
854
855 xDosReleaseMutexSem(hmtxFleshWork);
856
857 if (!item)
858 break; // Dependents gone from work list
859 } // if pszDirName
860
861 DosSleep(250);
862 } // while
863
864 if (!pathSaved) {
865 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
866 pszFleshFocusPath = pszSavedFleshFocusPath;
867 xDosReleaseMutexSem(hmtxFleshWork);
868 }
869
870}
871
872/**
873 * Set focus drive to optimize work list processing
874 * @param chDriveLetter is upper case drive letter (A-Z)
875 */
876
877VOID SetFleshFocusPath(PCSZ pszPath) {
878 PCSZ pszOld;
879 PCSZ pszNew = strdup(pszPath);
880 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
881 pszOld = pszFleshFocusPath;
882 pszFleshFocusPath = pszNew;
883 xDosReleaseMutexSem(hmtxFleshWork);
884 if (pszOld)
885 xfree((PVOID)pszOld, pszSrcFile, __LINE__);
886 DbgMsg(pszSrcFile, __LINE__, "SetFleshFocusPath focus path set to %s", pszFleshFocusPath); // 2015-08-03 SHL FIXME debug
887
888}
889
890/**
891 * Run Flesh, UnFlesh, FleshEnv, Stubby for directory for items in work list
892 */
893
894VOID FleshWorkThread(PVOID arg)
895{
896 HAB thab;
897 HMQ hmq = (HMQ)0;
898
899 // 2015-08-07 SHL FIXME to be gone
900 static INT ProcessDirCount = 0;
901
902 DosError(FERR_DISABLEHARDERR);
903
904# ifdef FORTIFY
905 Fortify_EnterScope();
906# endif
907
908 thab = WinInitialize(0);
909 if (thab) {
910 hmq = WinCreateMsgQueue(thab, 0);
911 if (hmq) {
912 IncrThreadUsage();
913 priority_normal();
914
915 // process list entries until time to die
916 for (;!fAmQuitting;) {
917
918 PFLESHWORKITEM item;
919
920 // 2015-08-07 SHL FIXME to use SMPSafe...
921 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
922
923 // 2015-08-14 SHL
924 // Get next work list item and remove from list
925 // If focus path set, process parents of focus path first
926 if (pszFleshFocusPath) {
927 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszFleshFocusPath);
928 if (!item) {
929 xfree((PSZ)pszFleshFocusPath, pszSrcFile, __LINE__);
930 pszFleshFocusPath = NULL; // Revert to normal
931 }
932 else
933 List2Delete(&FleshWorkList, (PLIST2)item);
934 }
935 else
936 item = NULL;
937
938 if (!item)
939 item = (PFLESHWORKITEM)List2DeleteFirst(&FleshWorkList);
940
941 xDosReleaseMutexSem(hmtxFleshWork);
942
943 // Wait for new items to be added to list
944 if (!item) {
945 ULONG ul;
946 if (!fNoFleshDbgMsg)
947 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work list empty - waiting"); // 2015-08-03 SHL FIXME debug
948 xDosWaitEventSem(hevFleshWorkListChanged, SEM_INDEFINITE_WAIT);
949 xDosResetEventSem(hevFleshWorkListChanged, &ul);
950 if (!fNoFleshDbgMsg)
951 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work hev posted"); // 2015-08-03 SHL FIXME debug
952 continue;
953 }
954
955 if (WinIsWindow((HAB)0, item->hwndCnr)) {
956#if 0 // 2015-08-07 SHL FIXME debug
957 // 2015-08-03 SHL FIXME debug
958 {
959 static PSZ itemNames[] = {
960 "eStubby", "eFlesh", "eFleshEnv", "eUnFlesh"
961 };
962
963 PCNRITEM pci = item->pci;
964 if (!fNoFleshDbgMsg) {
965 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread action %s pci %p pszFileName %s",
966 itemNames[item->action],
967 pci,
968 pci && (INT)pci != -1 ?
969 (pci->pszFileName ? pci->pszFileName : "(nullname)") :
970 "(nullpci)"); // 2015-08-03 SHL FIXME debug
971 }
972 }
973#endif
974
975 switch (item->action) {
976 case eUnFlesh:
977 UnFlesh(item->hwndCnr, item->pci);
978 break;
979 case eFleshEnv:
980 FleshEnv(item->hwndCnr, item->pci);
981 break;
982 case eStubby:
983 // DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread pci %p pszFileName %s", stubbyArgs->pci, stubbyArgs->pci->pszFileName); // 2015-08-03 SHL FIXME debug
984 Stubby(item->hwndCnr, item->pci);
985 break;
986 case eFlesh:
987 if (Flesh(item->hwndCnr, item->pci)) {
988 // 2015-08-06 SHL FIXME to report?
989 }
990 break;
991 default:
992 Runtime_Error(pszSrcFile, __LINE__, "item %u unexpected", item->action);
993 } // switch
994
995
996 } // if window
997
998 xfree(item, pszSrcFile, __LINE__);
999
1000 } // for
1001
1002 WinDestroyMsgQueue(hmq);
1003 }
1004 DecrThreadUsage();
1005 WinTerminate(thab);
1006 }
1007
1008 ProcessDirCount++;
1009 // DbgMsg(pszSrcFile, __LINE__, "ProcessDirCount %i FixedVolume %i", ProcessDirCount, FixedVolume);
1010 if (ProcessDirCount >= FixedVolume) {
1011 ProcessDirCount = 0;
1012 FixedVolume = 0;
1013 }
1014
1015# ifdef FORTIFY
1016 Fortify_LeaveScope();
1017# endif
1018
1019}
1020
1021/**
1022 * Allocate resources and start FleshWorkThread
1023 * @return TRUE if OK
1024 */
1025
1026BOOL StartFleshWorkThread()
1027{
1028 APIRET rc = DosCreateMutexSem(NULL, &hmtxFleshWork, 0L /* Not shared */, FALSE /* Not owned */);
1029 if (rc) {
1030 Dos_Error(MB_CANCEL, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1031 PCSZ_DOSCREATEMUTEXSEM);
1032 return FALSE;
1033 }
1034
1035 rc = xDosCreateEventSem(NULL, &hevFleshWorkListChanged, 0 /* Not shared */, FALSE /* Reset */);
1036 if (rc)
1037 return FALSE; // Give up
1038
1039 /* DbgMsg is time consuming
1040 define FM2_NO_FLESH_DBGMSG to suppress
1041 2015-08-09 SHL FIXME to be gone
1042 */
1043
1044 fNoFleshDbgMsg = getenv("FM2_NO_FLESH_DBGMSG") != NULL;
1045
1046 tidFleshWorkListThread = xbeginthread(FleshWorkThread,
1047 65536,
1048 NULL,
1049 pszSrcFile, __LINE__);
1050 return tidFleshWorkListThread != -1;
1051
1052}
1053
1054#pragma alloc_text(FLESH,Flesh,FleshEnv,UnFlesh,Stubby,FleshWorkThread,StartFleshWorkThread,AddFleshWorkRequest)
Note: See TracBrowser for help on using the repository browser.