source: trunk/dll/flesh.c@ 1861

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

IsParentOfChildPath: correct Runtime_Error copy/paste typo

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 KB
RevLine 
[145]1
2/***********************************************************************
3
4 $Id: flesh.c 1861 2015-08-22 23:33:45Z 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
[145]38
39***********************************************************************/
40
[907]41#include <stdlib.h>
42#include <string.h>
43#include <ctype.h>
[1831]44//#include <malloc.h>
[907]45
[2]46#define INCL_DOS
47#define INCL_DOSERRORS
48#define INCL_WIN
[907]49#define INCL_LONGLONG // dircnrs.h
[2]50
[1177]51#include "fm3dll.h"
[1207]52#include "draglist.h" // Data declaration(s)
53#include "notebook.h" // Data declaration(s)
54#include "info.h" // Data declaration(s)
55#include "init.h" // Data declaration(s)
56#include "mainwnd.h" // Data declaration(s)
[907]57#include "fm3str.h"
58#include "filldir.h" // FileAttrToString...
59#include "errutil.h" // Dos_Error...
60#include "strutil.h" // GetPString
[1155]61#include "flesh.h"
62#include "valid.h" // IsValidDir
[1856]63#include "misc.h" // LoadLibPath GetTidForThread
[1177]64#include "findrec.h" // FindCnrRecord
65#include "notify.h" // Notify
66#include "wrappers.h" // xfree
[1354]67#include "excputil.h" // xbeginthread
[1856]68#include "listutil.h" // List...
69#include "common.h" // IncrThreadUsage DecrThreadUsage
70
[1831]71#if 0
72#define __PMPRINTF__
73#include "PMPRINTF.H"
74#endif
[2]75
[1207]76// Data definitions
[2]77#pragma data_seg(DATA1)
[340]78
79static PSZ pszSrcFile = __FILE__;
80
[1856]81
82static INT tidFleshWorkListThread = -1; // 2015-08-08 SHL
83
[1860]84static PCSZ pszFleshFocusPath; // 2015-08-20 SHL
[1856]85
86BOOL fNoFleshDbgMsg; // 2015-08-09 SHL FIXME to be gone
87
[1207]88#pragma data_seg(GLOBAL1)
89ULONG NoBrokenNotify;
90BOOL fFilesInTree;
91
[1856]92BOOL Flesh(HWND hwndCnr, PCNRITEM pciParent);
93
94BOOL Stubby(HWND hwndCnr, PCNRITEM pciParent);
95BOOL FleshEnv(HWND hwndCnr, PCNRITEM pciParent);
[1858]96VOID UnFlesh(HWND hwndCnr, PCNRITEM pciParent);
[1856]97
98/**
99 * Insert CNRITEMs for members of PATH-like environment variable
100 * @param hwndCnr is the container to be populated
101 * @param pciParent is CNRITEM defining PATH-like environment variable
102 * @return TRUE if OK, FALSE is error detected
103 */
104
[551]105BOOL FleshEnv(HWND hwndCnr, PCNRITEM pciParent)
[175]106{
[551]107 PCNRITEM pciL;
[2]108 DIRCNRDATA *dcd;
[551]109 CHAR path[CCHMAXPATH + 12],
110 fullpath[CCHMAXPATH + 12], *env, *p, *pp, *var = NULL;
[2]111
[1858]112 if (!pciParent || (INT)pciParent == -1 || !hwndCnr)
[2]113 return FALSE;
[1856]114
[574]115 dcd = (DIRCNRDATA *) WinQueryWindowPtr(hwndCnr, QWL_USER);
[551]116 if (!dcd)
[2]117 return FALSE;
118
[730]119 strcpy(path, pciParent->pszFileName + 1);
[551]120 if (stricmp(path, GetPString(IDS_ENVVARSTEXT) + 1))
121 UnFlesh(hwndCnr, pciParent);
122 if (*path) {
[2]123 path[strlen(path) - 1] = 0;
[1400]124 if (!stricmp(path, PCSZ_LIBPATH)) {
[551]125 var = xmalloc(65536, pszSrcFile, __LINE__);
126 if (var)
127 LoadLibPath(var, 65536);
[2]128 env = var;
129 }
130 else
131 env = getenv(path);
[551]132 if (env && *env) {
[2]133 p = env;
[551]134 while (*p) {
135 pp = path;
136 while (*p == ';')
137 p++;
138 while (*p && *p != ';') {
139 *pp = *p;
140 p++;
141 pp++;
142 }
143 *pp = 0;
144 if (*path &&
145 strcmp(path, ".") &&
146 strcmp(path, ".\\") &&
147 strcmp(path, "..") &&
148 strcmp(path, "..\\") &&
149 strncmp(path, ".\\", 2) && strncmp(path, "..\\", 3)) {
150 if (!DosQueryPathInfo(path,
151 FIL_QUERYFULLNAME,
152 fullpath,
153 sizeof(fullpath)) && IsValidDir(fullpath)) {
154 pciL = FindCnrRecord(hwndCnr,
155 fullpath, pciParent, FALSE, FALSE, FALSE);
156 if (pciL) {
[1858]157 while (pciL && pciL != (PCNRITEM)-1 && pciL != pciParent)
[551]158 pciL = WinSendMsg(hwndCnr,
159 CM_QUERYRECORD,
160 MPFROMP(pciL),
161 MPFROM2SHORT(CMA_PARENT, CMA_ITEMORDER));
162 }
163 if (!pciL) {
[2]164
[551]165 RECORDINSERT ri;
[2]166
[551]167 pciL = WinSendMsg(hwndCnr,
168 CM_ALLOCRECORD,
[751]169 MPFROMLONG(EXTRA_RECORD_BYTES),
[551]170 MPFROMLONG(1));
171 if (pciL) {
[730]172 pciL->pszFileName = xstrdup(fullpath, pszSrcFile, __LINE__);
[751]173 pciL->rc.pszIcon = pciL->pszFileName;
[551]174 if (!fNoIconsDirs &&
175 (!isalpha(*fullpath) ||
176 !(driveflags[toupper(*fullpath) - 'A'] &
177 DRIVE_NOLOADICONS)))
178 pciL->rc.hptrIcon = WinLoadFileIcon(fullpath, FALSE);
179 if (!pciL->rc.hptrIcon)
180 pciL->rc.hptrIcon = hptrDir;
181 pciL->attrFile = FILE_DIRECTORY;
[751]182 pciL->pszDispAttr = FileAttrToString(pciL->attrFile);
[551]183 memset(&ri, 0, sizeof(ri));
184 ri.cb = sizeof(ri);
[1858]185 ri.pRecordOrder = (PRECORDCORE)CMA_END;
186 ri.pRecordParent = (PRECORDCORE)pciParent;
187 ri.zOrder = (ULONG)CMA_TOP;
[551]188 ri.cRecordsInsert = 1;
189 ri.fInvalidateRecord = FALSE;
[1858]190 // 2015-08-03 SHL FIXME debug
191 if (pciL->pszFileName == NullStr)
192 DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD pci %p pszFileName \"%s\"", pciL, pciL->pszFileName); // 2015-08-03 SHL FIXME debug
[551]193 if (!WinSendMsg(hwndCnr,
194 CM_INSERTRECORD, MPFROMP(pciL), MPFROMP(&ri)))
[751]195 FreeCnrItem(hwndCnr, pciL);
[551]196 }
197 }
198 }
199 }
[2]200 }
201 }
[1009]202 xfree(var, pszSrcFile, __LINE__);
[1858]203 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
204 CM_QUERYRECORD,
205 MPFROMP(pciParent),
206 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
207 while (pciL && (INT)pciL != -1) {
[2]208 pciL->flags |= (RECFLAGS_NODRAG | RECFLAGS_UNDERENV);
209 WinSendMsg(hwndCnr,
[551]210 CM_INVALIDATERECORD, MPFROMP(&pciL), MPFROM2SHORT(1, 0));
[2]211 pciL = WinSendMsg(hwndCnr,
[551]212 CM_QUERYRECORD,
213 MPFROMP(pciL), MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
[2]214 }
215 }
216 return TRUE;
217}
218
[1856]219/**
220 * Insert CNRITEMs for all children of pciParent
221 * @param hwnCnr is container to receive CNRITEMs
222 * @param pciParent is CNRITEM to have children inserted
223 * @return TRUE if OK, FALSE is error detected
224 */
225
[551]226BOOL Flesh(HWND hwndCnr, PCNRITEM pciParent)
[166]227{
[551]228 PCNRITEM pciL;
[2]229 DIRCNRDATA *dcd;
[1856]230 BOOL includefiles;
[2]231
[1856]232 if (!pciParent || (INT)pciParent == -1 || !hwndCnr)
[2]233 return FALSE;
[1856]234
[1858]235 // 2015-08-13 SHL
236 if (fAmQuitting)
237 return FALSE;
[1856]238
239 // 2015-08-03 SHL FIXME debug
240 if (!fNoFleshDbgMsg) {
241 DbgMsg(pszSrcFile, __LINE__, "Flesh %s pciParent %p pszFileName %p",
242 pciParent && (INT)pciParent != -1 && pciParent->pszFileName ?
243 pciParent->pszFileName : "(null)",
244 pciParent,
245 pciParent && (INT)pciParent != -1 ? pciParent->pszFileName : (PVOID)-1); // 2015-08-03 SHL FIXME debug
246 }
247
248 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
249 CM_QUERYRECORD,
250 MPFROMP(pciParent),
251 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
252
253 // 2015-08-06 SHL allow pciL -1
[1858]254 // 2015-08-06 SHL FIXME to not need pszFileName check
[1856]255 if (!pciL || (INT)pciL == -1 || !*pciL->pszFileName) {
256
257 // No children or filename null
258 if (pciL && (INT)pciL != -1) {
[1858]259 // 2015-08-06 SHL FIXME to ensure this an not happen
260 // if (!*pciL->pszFileName)
261 // Runtime_Error(pszSrcFile, __LINE__, "Flesh called with pci %p pszFileName (null)", pciL);
262
[1856]263 if (!fNoFleshDbgMsg)
[1858]264 DbgMsg(pszSrcFile, __LINE__, "Flesh RemoveCnrItems() pciL %p \"%s\"",
265 pciL,
266 pciL->pszFileName ? pciL->pszFileName : "(null)"); // 2015-08-04 SHL FIXME debug
267 // Assume refernces to pciL already removed from work list
[1651]268 RemoveCnrItems(hwndCnr, pciL, 1, CMA_FREE);
[1856]269 }
270
[1651]271 dcd = INSTDATA(hwndCnr);
272 if (dcd && dcd->size != sizeof(DIRCNRDATA))
273 dcd = NULL;
[1856]274
275 includefiles =
276 driveflags[toupper(*pciParent->pszFileName) - 'A'] & DRIVE_INCLUDEFILES ?
277 TRUE : fFilesInTree;
278
[1662]279 ProcessDirectory(hwndCnr,
[1856]280 pciParent,
281 pciParent->pszFileName,
282 includefiles, // filestoo
283 TRUE, // recurse
284 TRUE, // partial
285 NULL, // stop flag
286 dcd,
287 NULL, // total files
288 NULL); // total bytes
[1662]289 if (pciParent && pciParent->pszFileName && !(driveflags[toupper(*pciParent->pszFileName) - 'A'] & DRIVE_RSCANNED))
290 driveflags[toupper(*pciParent->pszFileName) - 'A'] |= DRIVE_RSCANNED;
[1655]291 return TRUE;
[1651]292 }
[1856]293
[1655]294 return FALSE;
[2]295}
296
[1858]297/**
298 * Remove children from container
299 * @parame pciParent is parent of children to be removed
300 */
[1856]301
[1858]302VOID UnFlesh(HWND hwndCnr, PCNRITEM pciParent)
[175]303{
[1856]304 BOOL removed = FALSE;
[2]305 PCNRITEM pciL;
306
[175]307 if (!pciParent || !hwndCnr)
[1858]308 return;
[1856]309
310 if (!fNoFleshDbgMsg)
311 DbgMsg(pszSrcFile, __LINE__, "UnFlesh pciParent %p pszFileName %s", pciParent, pciParent->pszFileName ? pciParent->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
312
[551]313 for (;;) {
[1858]314 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
315 CM_QUERYRECORD,
316 MPFROMP(pciParent),
317 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
[1856]318 if (!pciL || (INT)pciL == -1)
319 break; // Done
320
321 if (!fNoFleshDbgMsg)
322 DbgMsg(pszSrcFile, __LINE__, "UnFlesh RemoveCnrItems() pciL %p %s", pciL, pciL->pszFileName ? pciL->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
323 RemoveCnrItems(hwndCnr, pciL, 1, CMA_FREE);
324 removed = TRUE;
325 } // for
326
327 if (removed) {
[2]328 WinSendMsg(hwndCnr,
[551]329 CM_INVALIDATERECORD,
330 MPFROMP(&pciParent),
331 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
[175]332 }
[1858]333 return;
[2]334}
335
[1482]336#define DDEPTH 64
[2]337
[1471]338/**
[1856]339 * Insert CNRITEM for 1st subdirectory [or file] of pciParent
340 * @param hwdCnr is container to be filled
341 * @param pciParent is CNRITEM to receive child record
342 * @return TRUE if record inserted, else FALSE
343 * Ensures that expand/collapse button displays if directory has children
344 * Secondary purpose is to detect broken LANs and inaccesible mapped drives
[1471]345 */
346
[551]347BOOL Stubby(HWND hwndCnr, PCNRITEM pciParent)
[175]348{
[1409]349 /**
[2]350 * this code is full of workarounds for screwed up LANs.
351 * let's hope all the current LAN programmers fall into
352 * a black hole and make way for people who can get it right...
353 */
354
[1471]355 BOOL ok = FALSE;
[847]356 FILEFINDBUF3 ffb[DDEPTH];
357 PFILEFINDBUF3 pffb;
[551]358 HDIR hDir = HDIR_CREATE;
[1856]359 ULONG nm, ulM = 1, total = 0, fl;
[1858]360 CHAR wildcard[CCHMAXPATH];
[551]361 register INT len;
362 APIRET rc, prc;
[1858]363 BOOL isadir = FALSE;
364 BOOL isremote;
365 BOOL includefiles;
[1482]366 ULONG ddepth = DDEPTH;
[1299]367 ULONG drvNum;
368 ULONG flags;
[551]369 static BOOL brokenlan = FALSE, isbroken = FALSE;
[2]370
[1858]371 if (!pciParent || (INT)pciParent == -1 || !*pciParent->pszFileName
[1832]372 || pciParent->pszFileName == NullStr || !hwndCnr)
[2]373 return FALSE;
[1856]374
375 if (!fNoFleshDbgMsg)
376 DbgMsg(pszSrcFile, __LINE__, "Stubby pciParent %p pszFileName %s", pciParent, pciParent->pszFileName); // 2015-08-03 SHL FIXME debug
377
378 // Build wildcard
[730]379 len = strlen(pciParent->pszFileName);
[1858]380 memcpy(wildcard, pciParent->pszFileName, len + 1);
381 if (wildcard[len - 1] != '\\')
382 wildcard[len++] = '\\';
383 wildcard[len++] = '*';
384 wildcard[len] = 0;
[2]385
[1858]386 // 2015-08-19 SHL FIXME to know how this can happen
387 if (!isalpha(*wildcard) || wildcard[1] != ':' || wildcard[2] != '\\') {
388 MakeFullName(wildcard);
389 DbgMsg(pszSrcFile, __LINE__, "Stubby MakeFullName returned %s", wildcard); // 2015-08-19 SHL FIXME debug
390 }
[2]391
[1299]392 drvNum = toupper(*pciParent->pszFileName) - 'A';
393 flags = driveflags[drvNum];
[1858]394 if (!isalpha(*wildcard) ||
395 wildcard[1] != ':' ||
396 wildcard[2] != '\\' || ((flags & DRIVE_IGNORE)))
[1856]397 return FALSE; // Not a directory or ignore requested
[2]398
[1856]399 includefiles = flags & DRIVE_INCLUDEFILES ? TRUE : fFilesInTree;
[2]400
[1856]401 isremote = flags & DRIVE_REMOTE ? TRUE : FALSE;
[2]402
[551]403 if (isremote) {
404 if (fRemoteBug) {
405 if (brokenlan) {
[1858]406 ddepth = (ULONG)-1;
[551]407 ddepth--;
[2]408 }
[761]409 ulM = 1;
[2]410 }
411 }
[551]412 else if (isbroken)
[2]413 ddepth = 14;
414
[1482]415 if (!fRemoteBug)
[1856]416 ulM = ddepth <= DDEPTH ? ddepth : 1;
[2]417
418 nm = ulM;
419
420 DosError(FERR_DISABLEHARDERR);
[1856]421
422 fl = includefiles ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY;
423
[1858]424 DbgMsg(pszSrcFile, __LINE__, "Stubby DosFindFirst(%s)", wildcard); // 2015-08-19 SHL FIXME debug
425
426 rc = DosFindFirst(wildcard,
[847]427 &hDir,
428 FILE_NORMAL | fl |
429 FILE_READONLY | FILE_ARCHIVED |
430 FILE_SYSTEM | FILE_HIDDEN,
431 &ffb, ulM * sizeof(FILEFINDBUF3), &nm, FIL_STANDARD);
[761]432 if (ulM == 1 && !rc) {
[1856]433 // Loop looking for 1st directory (or file)
[2]434 do {
435 pffb = &ffb[0];
[551]436 if (!includefiles && !(pffb->attrFile & FILE_DIRECTORY) && !brokenlan) {
[1856]437 // Find returned file when only directories requested
[551]438 brokenlan = TRUE;
[1858]439 ddepth = (ULONG)-1;
[551]440 ddepth--;
441 if (!NoBrokenNotify) {
442 prc = saymsg(MB_YESNO | MB_ICONEXCLAMATION,
443 HWND_DESKTOP,
444 GetPString(IDS_LANERRORTITLETEXT),
445 GetPString(IDS_LANERRORTEXT));
446 if (prc == MBID_NO) {
447 saymsg(MB_ENTER,
448 HWND_DESKTOP,
449 GetPString(IDS_LANERROR2TITLETEXT),
450 GetPString(IDS_LANERROR2TEXT));
[847]451 NoBrokenNotify = 255;
[1505]452 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
[551]453 &NoBrokenNotify, sizeof(ULONG));
454 }
455 }
456 else {
457 NoBrokenNotify--;
[1505]458 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
[551]459 &NoBrokenNotify, sizeof(ULONG));
460 }
[2]461 }
[1856]462
[515]463 if (*pffb->achName &&
[551]464 (includefiles || (pffb->attrFile & FILE_DIRECTORY)) &&
465 (pffb->achName[0] != '.' ||
[515]466 (pffb->achName[1] &&
[551]467 (pffb->achName[1] != '.' || pffb->achName[2])))) {
[1856]468 // Got directory other than . or .. (or a file)
[551]469 DosFindClose(hDir);
470 isadir = TRUE;
471 goto Interruptus;
[2]472 }
[761]473 nm = 1;
[2]474 DosError(FERR_DISABLEHARDERR);
[1856]475 } while (++total < ddepth && !(rc = (DosFindNext(hDir,
476 &ffb,
477 sizeof(FILEFINDBUF3),
478 &nm))));
479 DosFindClose(hDir);
480
[730]481 if (toupper(*pciParent->pszFileName) > 'B' &&
[751]482 (*(pciParent->pszFileName + 1)) == ':' &&
[730]483 (*(pciParent->pszFileName + 2)) == '\\' && !(*(pciParent->pszFileName + 3))) {
[2]484
[1856]485 // Searching root of hard or remote drive and find reported error
[2]486 CHAR s[132];
487 sprintf(s,
[551]488 GetPString(IDS_NOSUBDIRSTEXT),
[730]489 total, toupper(*pciParent->pszFileName));
[551]490 if (rc && rc != ERROR_NO_MORE_FILES)
[1858]491 sprintf(&s[strlen(s)], GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
[847]492 else if (ddepth < 16)
[551]493 brokenlan = TRUE;
[2]494 Notify(s);
495 }
[1856]496 goto None; // Done
[2]497 }
[1856]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
[1858]605 else if (toupper(*wildcard) > 'B' && wildcard[1] == ':' && wildcard[2] == '\\' &&
606 !wildcard[3]) {
[2]607
[1858]608 // 2015-08-19 SHL FIXME to know how this can happen since wildcard ends with *
[1856]609 // Is root and no subdirectories
[551]610 CHAR s[162];
[1858]611 DbgMsg(pszSrcFile, __LINE__, "Stubby !isadir for %s", wildcard); // 2015-08-19 SHL FIXME debug
[551]612 sprintf(s,
613 GetPString(IDS_NOSUBDIRS2TEXT),
614 nm,
[730]615 toupper(*pciParent->pszFileName),
[1856]616 isremote ? GetPString(IDS_NOSUBDIRS3TEXT) : NullStr);
[551]617 Notify(s);
[2]618 }
619 }
620 }
[1858]621 else if (toupper(*wildcard) > 'B' && rc != ERROR_NO_MORE_FILES) {
[1856]622 // Find for remote or hard drive failed with error
[2]623 CHAR s[CCHMAXPATH + 80];
[1858]624 sprintf(s, GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
[2]625 Notify(s);
626 }
627
628None:
629
630 DosError(FERR_DISABLEHARDERR);
[1471]631 return ok;
[1856]632} // Stubby
633
634// Stubby/Flesh/Unflesh work list item
635
636typedef struct {
637 LIST2 list;
638 HWND hwndCnr;
639 PCNRITEM pci;
640 FLESHWORKACTION action;
641} FLESHWORKITEM;
642typedef FLESHWORKITEM *PFLESHWORKITEM;
643
644// Stubby/Flesh/Unflesh work list
645LIST2 FleshWorkList;
646
647HMTX hmtxFleshWork;
648HEV hevFleshWorkListChanged;
649
650/**
[1858]651 * Check work list item pci matches passed pci
[1856]652 */
653
654BOOL WorkListItemMatches(PLIST2 item, PVOID data)
655{
656 return ((PFLESHWORKITEM)data)->pci == ((PFLESHWORKITEM)item)->pci;
[2]657}
[793]658
[1856]659/**
660 * Delete stale items from flesh queue
661 */
662
663VOID DeleteStaleFleshWorkListItems(PCNRITEM pci)
664{
665 FLESHWORKITEM match;
666 PLIST2 item;
667
668 match.pci = pci;
669
670 for (;;) {
671 item = List2Search(&FleshWorkList, WorkListItemMatches, &match);
672 if (!item)
673 break;
674 DbgMsg(pszSrcFile, __LINE__, "DeleteStaleFleshWorkListItems deleting %p %s", pci, pci->pszFileName ? pci->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
675 List2Delete(&FleshWorkList, item);
676 xfree(item, pszSrcFile, __LINE__);
677 }
678}
679
680/**
681 * Add item to flesh work list
682 * eUnFlesh requests get special handling
683 * eFlesh etc. items for the same CNRITEM are considered stale and are
684 * deleted because eUnFlesh will free the CNRITEM associated with the item
685 * before the work list item is processed
686 */
687
688#if 0 // 2015-08-03 SHL FIXME debug
689BOOL AddFleshWorkRequest(HWND hwndCnr, PCNRITEM pci, FLESHWORKACTION action)
690#else
691BOOL AddFleshWorkRequestDbg(HWND hwndCnr, PCNRITEM pci, FLESHWORKACTION action, PCSZ pszSrcFile_, UINT uSrcLineNo)
692#endif
693{
694 PFLESHWORKITEM item = xmallocz(sizeof(FLESHWORKITEM), pszSrcFile, __LINE__);
695 item->hwndCnr = hwndCnr;
696 item->pci = pci;
697 item->action= action;
698
[1858]699 if (fAmQuitting)
700 return FALSE;
[1856]701
702 // 2015-08-03 SHL FIXME debug
[1858]703#if 0 // 2015-08-13 SHL FIXME to be gone
[1856]704 {
705 static PSZ itemNames[] = {
706 "eStubby", "eFlesh", "eFleshEnv", "eUnFlesh"
707 };
708
709# ifdef AddFleshWorkRequest
710 if (!pci || (INT)pci == -1) {
711 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p by %s:%u",
712 itemNames[item->action],
713 pci,
[1858]714 pszSrcFile_, uSrcLineNo);
[1856]715 }
716 else if (!pci->pszFileName) {
717 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest call with action %s pci %p pszFileName (null) by %s:%u",
718 itemNames[item->action],
719 pci,
[1858]720 pszSrcFile_, uSrcLineNo);
[1856]721 }
722 else if (!fNoFleshDbgMsg) {
723 DbgMsg(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p pszFileName %s by %s:%u",
724 itemNames[item->action],
725 pci,
726 pci->pszFileName,
727 pszSrcFile_, uSrcLineNo); // 2015-08-03 SHL FIXME debug
728 }
729#else
730 if (!pci || (INT)pci == -1) {
731 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest call with action %s pci %p",
732 itemNames[item->action],
[1858]733 pci);
[1856]734 }
735 else if (!pci->pszFileName) {
736 Runtime_Error(pszSrcFile, __LINE__, "AddFleshWorkRequest called with action %s pci %p pszFileName (null)",
737 itemNames[item->action],
[1858]738 pci);
[1856]739 }
740 else if (!fNoFleshDbgMsg) {
741 DbgMsg(pszSrcFile, __LINE__, "AddFleshWorkRequest action %s pci %p pszFileName %s",
742 itemNames[item->action],
743 pci,
744 pci->pszFileName); // 2015-08-03 SHL FIXME debug
745 }
746#endif
[1858]747 }
[1856]748#endif
749
[1860]750 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
[1856]751
752 // Delete stale requests
[1858]753 if (item->action == eUnFlesh)
[1856]754 DeleteStaleFleshWorkListItems(pci);
755
756 List2Append(&FleshWorkList, (PLIST2)item);
757
[1860]758 xDosReleaseMutexSem(hmtxFleshWork);
759 xDosPostEventSem(hevFleshWorkListChanged);
[1856]760
761 return TRUE;
762}
763
764/**
765 * Return TRUE if work list empty
766 * Advisory only
767 */
768
769BOOL IsFleshWorkListEmpty()
770{
771 return FleshWorkList.next == NULL;
772}
773
774/**
[1858]775 * Check if pci pathname is parent of child path name
776 * @param data is child path name
[1860]777 * @return TRUE if is work item path is parent of given path
[1858]778 */
779
780BOOL IsParentOfChildPath(PLIST2 item, PVOID data)
781{
782 UINT c;
783 if (!((PFLESHWORKITEM)item)->pci->pszFileName) {
[1861]784 Runtime_Error(pszSrcFile, __LINE__, "IsParentOfChildPath called with pci %p pszFileName (null)", ((PFLESHWORKITEM)item)->pci);
[1858]785 return FALSE;
786 }
787 c = strlen(((PFLESHWORKITEM)item)->pci->pszFileName);
788 return strncmp(((PFLESHWORKITEM)item)->pci->pszFileName, (PCSZ)data, c) == 0;
789}
790
791/**
792 * Wait until work list empty or until dependent items removed from list
[1856]793 * Advisory only
[1858]794 * @parse pszFileName is dependent pathName
[1856]795 */
796
797#if 0 // 2015-08-03 SHL FIXME debug
[1860]798VOID WaitFleshWorkListEmpty(PCSZ pszDirName)
[1856]799#else
[1860]800VOID WaitFleshWorkListEmptyDbg(PCSZ pszDirName, PCSZ pszSrcFile_, UINT uSrcLineNo_)
[1856]801#endif
802{
[1858]803 APIRET rc;
804 PFLESHWORKITEM item;
[1856]805 INT tid = GetTidForThread();
[1860]806 BOOL pathSaved = FALSE;
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
826 while (!IsFleshWorkListEmpty()) {
[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
859 if (!item)
860 break; // Dependents gone from work list
[1860]861 } // if pszDirName
862
[1856]863 DosSleep(250);
[1858]864 } // while
865
[1860]866 if (!pathSaved) {
867 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
868 pszFleshFocusPath = pszSavedFleshFocusPath;
869 xDosReleaseMutexSem(hmtxFleshWork);
870 }
[1858]871
[1856]872}
873
874/**
875 * Set focus drive to optimize work list processing
876 * @param chDriveLetter is upper case drive letter (A-Z)
877 */
878
[1860]879VOID SetFleshFocusPath(PCSZ pszPath) {
880 PCSZ pszOld;
881 PCSZ pszNew = strdup(pszPath);
882 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
883 pszOld = pszFleshFocusPath;
884 pszFleshFocusPath = pszNew;
885 xDosReleaseMutexSem(hmtxFleshWork);
886 if (pszOld)
887 xfree((PVOID)pszOld, pszSrcFile, __LINE__);
888 DbgMsg(pszSrcFile, __LINE__, "SetFleshFocusPath focus path set to %s", pszFleshFocusPath); // 2015-08-03 SHL FIXME debug
[1856]889
890}
891
892/**
893 * Run Flesh, UnFlesh, FleshEnv, Stubby for directory for items in work list
894 */
895
896VOID FleshWorkThread(PVOID arg)
897{
898 HAB thab;
899 HMQ hmq = (HMQ)0;
900
901 // 2015-08-07 SHL FIXME to be gone
902 static INT ProcessDirCount = 0;
903
904 DosError(FERR_DISABLEHARDERR);
905
906# ifdef FORTIFY
907 Fortify_EnterScope();
908# endif
909
910 thab = WinInitialize(0);
911 if (thab) {
912 hmq = WinCreateMsgQueue(thab, 0);
913 if (hmq) {
914 IncrThreadUsage();
915 priority_normal();
916
[1858]917 // process list entries until time to die
918 for (;!fAmQuitting;) {
[1856]919
920 PFLESHWORKITEM item;
921
922 // 2015-08-07 SHL FIXME to use SMPSafe...
[1860]923 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
[1856]924
925 // 2015-08-14 SHL
926 // Get next work list item and remove from list
[1860]927 // If focus path set, process parents of focus path first
928 if (pszFleshFocusPath) {
929 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszFleshFocusPath);
930 if (!item) {
931 xfree((PSZ)pszFleshFocusPath, pszSrcFile, __LINE__);
932 pszFleshFocusPath = NULL; // Revert to normal
933 }
[1856]934 else
935 List2Delete(&FleshWorkList, (PLIST2)item);
936 }
937 else
938 item = NULL;
939
940 if (!item)
941 item = (PFLESHWORKITEM)List2DeleteFirst(&FleshWorkList);
942
[1860]943 xDosReleaseMutexSem(hmtxFleshWork);
[1856]944
[1858]945 // Wait for new items to be added to list
[1856]946 if (!item) {
947 ULONG ul;
948 if (!fNoFleshDbgMsg)
949 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work list empty - waiting"); // 2015-08-03 SHL FIXME debug
[1860]950 xDosWaitEventSem(hevFleshWorkListChanged, SEM_INDEFINITE_WAIT);
951 xDosResetEventSem(hevFleshWorkListChanged, &ul);
[1856]952 if (!fNoFleshDbgMsg)
953 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work hev posted"); // 2015-08-03 SHL FIXME debug
954 continue;
955 }
956
957 if (WinIsWindow((HAB)0, item->hwndCnr)) {
958
959 ULONG flags;
960
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 eFillDir:
988 case eStubby:
989 // DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread pci %p pszFileName %s", stubbyArgs->pci, stubbyArgs->pci->pszFileName); // 2015-08-03 SHL FIXME debug
990 flags = driveflags[toupper(*item->pci->pszFileName) - 'A'];
991
992#if 1
993 if (item->action == eFillDir) {
994 // eFillDir maps to eFlesh or eStubby depending on fRScan.. settings
995 if (((fRScanLocal && flags & DRIVE_LOCALHD) ||
996 (fRScanRemote && flags & DRIVE_REMOTE) ||
997 (fRScanVirtual && flags & DRIVE_VIRTUAL)) &&
998 (!(flags & ((fRScanNoWrite ? 0 : DRIVE_NOTWRITEABLE) |
999 (fRScanSlow ? 0 : DRIVE_SLOW)))))
1000 {
1001 item->action = eFlesh;
1002 }
1003 else
1004 item->action = eStubby;
1005 }
1006#else
1007 wantFlesh = ((fRScanLocal && flags & DRIVE_LOCALHD ) ||
1008 (fRScanRemote && flags & DRIVE_REMOTE) ||
1009 (fRScanVirtual && flags & DRIVE_VIRTUAL)) &&
1010 // 2015-08-11 SHL typo - should not be local or
1011 (!(flags & ((fRScanNoWrite ? 0 : DRIVE_NOTWRITEABLE) ||
1012 (fRScanSlow ? 0 : DRIVE_SLOW))));
1013#endif
1014 if (item->action == eStubby) {
1015 Stubby(item->hwndCnr, item->pci);
1016 break;
1017 }
1018 // Drop through to eFlesh
1019
1020 case eFlesh:
1021 if (Flesh(item->hwndCnr, item->pci)) {
1022 // 2015-08-06 SHL FIXME to report?
1023 }
1024 break;
1025 default:
1026 Runtime_Error(pszSrcFile, __LINE__, "item %u unexpected", item->action);
1027 } // switch
1028
1029
1030 } // if window
1031
1032 xfree(item, pszSrcFile, __LINE__);
1033
1034 } // for
1035
1036 WinDestroyMsgQueue(hmq);
1037 }
1038 DecrThreadUsage();
1039 WinTerminate(thab);
1040 }
1041
1042 ProcessDirCount++;
1043 // DbgMsg(pszSrcFile, __LINE__, "ProcessDirCount %i FixedVolume %i", ProcessDirCount, FixedVolume);
1044 if (ProcessDirCount >= FixedVolume) {
1045 ProcessDirCount = 0;
1046 FixedVolume = 0;
1047 }
1048
1049# ifdef FORTIFY
1050 Fortify_LeaveScope();
1051# endif
1052
1053}
1054
1055/**
1056 * Allocate resources and start FleshWorkThread
1057 * @return TRUE if OK
1058 */
1059
1060BOOL StartFleshWorkThread()
1061{
1062 APIRET rc = DosCreateMutexSem(NULL, &hmtxFleshWork, 0L /* Not shared */, FALSE /* Not owned */);
1063 if (rc) {
1064 Dos_Error(MB_CANCEL, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1065 PCSZ_DOSCREATEMUTEXSEM);
1066 return FALSE;
1067 }
1068
[1860]1069 rc = xDosCreateEventSem(NULL, &hevFleshWorkListChanged, 0 /* Not shared */, FALSE /* Reset */);
1070 if (rc)
1071 return FALSE; // Give up
[1856]1072
1073 /* DbgMsg is time consuming
1074 define FM2_NO_FLESH_DBGMSG to suppress
1075 2015-08-09 SHL FIXME to be gone
1076 */
1077
1078 fNoFleshDbgMsg = getenv("FM2_NO_FLESH_DBGMSG") != NULL;
1079
1080 tidFleshWorkListThread = xbeginthread(FleshWorkThread,
1081 65536,
1082 NULL,
1083 pszSrcFile, __LINE__);
1084 return tidFleshWorkListThread != -1;
1085
1086}
1087
1088#pragma alloc_text(FLESH,Flesh,FleshEnv,UnFlesh,Stubby,FleshWorkThread,StartFleshWorkThread,AddFleshWorkRequest)
Note: See TracBrowser for help on using the repository browser.