source: trunk/dll/flesh.c@ 1876

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

Eliminate some unnecessary Flesh and UnFlesh calls.Update icon and display name on CD/DVD eject in all cases.
Don't use Flesh thread for floppy drive scans fix them getting mistakenly identified as directories and add nonexistent subdirectories.

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