source: trunk/dll/flesh.c@ 1867

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

Rework ShowTreeRec to avoid retry failures
Rework WaitFleshWorkListEmpty to let PM do some work before returning to caller

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