source: trunk/dll/flesh.c@ 1856

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

Rework Flesh/Stubby etc. to avoid running on thread 1
Should be ready for release after spurious traps resolved
DbgMsg calls retained - delete/disable before release

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