source: trunk/dll/flesh.c@ 1874

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

DosSleep times in WaitFleshWorkListEmpty set by caller; TOPDIR code calls WaitFleshWorkListEmpty before ShowCnrRecord and now actually exists for directory containers in tree view. These calls are made from the object windows.

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