source: trunk/dll/flesh.c@ 1865

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

Correct WaitFleshWorkListEmpty typo that could corrupt heap
Protect some read-only strings from overwriting

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.0 KB
RevLine 
[145]1
2/***********************************************************************
3
4 $Id: flesh.c 1865 2015-08-23 20:36:02Z 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;
806 PCSZ pszSavedFleshFocusPath;
[1856]807
808 if (tid == 1 || tid == tidFleshWorkListThread) {
809# ifdef WaitFleshWorkListEmpty
810 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist %sempty by tid %u at %s:%u", IsFleshWorkListEmpty() ? "" : "not ", tid, pszSrcFile_, uSrcLineNo_);
811# else
812 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called by tid %u", tid);
813# endif
814 return; // Avoid hang
815 }
816 else if (IsFleshWorkListEmpty()) {
817# ifdef WaitFleshWorkListEmpty
[1858]818 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist empty at %s:%u", pszSrcFile_, uSrcLineNo_);
[1856]819# else
[1858]820 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list empty");
[1856]821# endif
822 }
823
824 // Can not wait if call from thread 1 or FleshWorkListThread
825 while (!IsFleshWorkListEmpty()) {
[1858]826
827#if 0 // 2015-08-19 SHL FIXME debug
[1856]828# ifdef WaitFleshWorkListEmpty
829 if (!fNoFleshDbgMsg)
[1858]830 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty by %s:%u", pszSrcFile_, uSrcLineNo_); // 2015-08-07 SHL FIXME debug
[1856]831# else
832 if (!fNoFleshDbgMsg)
[1858]833 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty"); // 2015-08-07 SHL FIXME debug
[1856]834# endif
[1858]835#endif // 2015-08-19 SHL FIXME debug
836
837 // 2015-08-13 SHL
838 if (fAmQuitting)
839 return;
840
[1860]841 // Just wait for dependents to be gone if path name given
842 if (pszDirName) {
843 rc = xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
844 if (rc)
845 continue; // Maybe should return ???
846
847 if (!pathSaved) {
848 // Give priority to work items for parents of this path
849 pathSaved = TRUE;
850 pszSavedFleshFocusPath = pszFleshFocusPath;
851 pszFleshFocusPath = pszDirName;
[1858]852 }
853
[1860]854 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszDirName);
[1858]855
[1860]856 xDosReleaseMutexSem(hmtxFleshWork);
[1858]857
858 if (!item)
859 break; // Dependents gone from work list
[1860]860 } // if pszDirName
861
[1856]862 DosSleep(250);
[1858]863 } // while
864
[1865]865 if (pathSaved) {
[1860]866 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
867 pszFleshFocusPath = pszSavedFleshFocusPath;
868 xDosReleaseMutexSem(hmtxFleshWork);
869 }
[1858]870
[1856]871}
872
873/**
874 * Set focus drive to optimize work list processing
875 * @param chDriveLetter is upper case drive letter (A-Z)
876 */
877
[1860]878VOID SetFleshFocusPath(PCSZ pszPath) {
879 PCSZ pszOld;
880 PCSZ pszNew = strdup(pszPath);
881 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
882 pszOld = pszFleshFocusPath;
883 pszFleshFocusPath = pszNew;
884 xDosReleaseMutexSem(hmtxFleshWork);
885 if (pszOld)
886 xfree((PVOID)pszOld, pszSrcFile, __LINE__);
887 DbgMsg(pszSrcFile, __LINE__, "SetFleshFocusPath focus path set to %s", pszFleshFocusPath); // 2015-08-03 SHL FIXME debug
[1856]888
889}
890
891/**
892 * Run Flesh, UnFlesh, FleshEnv, Stubby for directory for items in work list
893 */
894
895VOID FleshWorkThread(PVOID arg)
896{
897 HAB thab;
898 HMQ hmq = (HMQ)0;
899
900 // 2015-08-07 SHL FIXME to be gone
901 static INT ProcessDirCount = 0;
902
903 DosError(FERR_DISABLEHARDERR);
904
905# ifdef FORTIFY
906 Fortify_EnterScope();
907# endif
908
909 thab = WinInitialize(0);
910 if (thab) {
911 hmq = WinCreateMsgQueue(thab, 0);
912 if (hmq) {
913 IncrThreadUsage();
914 priority_normal();
915
[1858]916 // process list entries until time to die
917 for (;!fAmQuitting;) {
[1856]918
919 PFLESHWORKITEM item;
920
921 // 2015-08-07 SHL FIXME to use SMPSafe...
[1860]922 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
[1856]923
924 // 2015-08-14 SHL
925 // Get next work list item and remove from list
[1860]926 // If focus path set, process parents of focus path first
927 if (pszFleshFocusPath) {
928 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszFleshFocusPath);
929 if (!item) {
930 xfree((PSZ)pszFleshFocusPath, pszSrcFile, __LINE__);
931 pszFleshFocusPath = NULL; // Revert to normal
932 }
[1856]933 else
934 List2Delete(&FleshWorkList, (PLIST2)item);
935 }
936 else
937 item = NULL;
938
939 if (!item)
940 item = (PFLESHWORKITEM)List2DeleteFirst(&FleshWorkList);
941
[1860]942 xDosReleaseMutexSem(hmtxFleshWork);
[1856]943
[1858]944 // Wait for new items to be added to list
[1856]945 if (!item) {
946 ULONG ul;
947 if (!fNoFleshDbgMsg)
948 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work list empty - waiting"); // 2015-08-03 SHL FIXME debug
[1860]949 xDosWaitEventSem(hevFleshWorkListChanged, SEM_INDEFINITE_WAIT);
950 xDosResetEventSem(hevFleshWorkListChanged, &ul);
[1856]951 if (!fNoFleshDbgMsg)
952 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work hev posted"); // 2015-08-03 SHL FIXME debug
953 continue;
954 }
955
956 if (WinIsWindow((HAB)0, item->hwndCnr)) {
957#if 0 // 2015-08-07 SHL FIXME debug
958 // 2015-08-03 SHL FIXME debug
959 {
960 static PSZ itemNames[] = {
961 "eStubby", "eFlesh", "eFleshEnv", "eUnFlesh"
962 };
963
964 PCNRITEM pci = item->pci;
965 if (!fNoFleshDbgMsg) {
966 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread action %s pci %p pszFileName %s",
967 itemNames[item->action],
968 pci,
969 pci && (INT)pci != -1 ?
970 (pci->pszFileName ? pci->pszFileName : "(nullname)") :
971 "(nullpci)"); // 2015-08-03 SHL FIXME debug
972 }
973 }
974#endif
975
976 switch (item->action) {
977 case eUnFlesh:
978 UnFlesh(item->hwndCnr, item->pci);
979 break;
980 case eFleshEnv:
981 FleshEnv(item->hwndCnr, item->pci);
982 break;
983 case eStubby:
984 // DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread pci %p pszFileName %s", stubbyArgs->pci, stubbyArgs->pci->pszFileName); // 2015-08-03 SHL FIXME debug
[1865]985 Stubby(item->hwndCnr, item->pci);
986 break;
[1856]987 case eFlesh:
988 if (Flesh(item->hwndCnr, item->pci)) {
989 // 2015-08-06 SHL FIXME to report?
990 }
991 break;
992 default:
993 Runtime_Error(pszSrcFile, __LINE__, "item %u unexpected", item->action);
994 } // switch
995
996
997 } // if window
998
999 xfree(item, pszSrcFile, __LINE__);
1000
1001 } // for
1002
1003 WinDestroyMsgQueue(hmq);
1004 }
1005 DecrThreadUsage();
1006 WinTerminate(thab);
1007 }
1008
1009 ProcessDirCount++;
1010 // DbgMsg(pszSrcFile, __LINE__, "ProcessDirCount %i FixedVolume %i", ProcessDirCount, FixedVolume);
1011 if (ProcessDirCount >= FixedVolume) {
1012 ProcessDirCount = 0;
1013 FixedVolume = 0;
1014 }
1015
1016# ifdef FORTIFY
1017 Fortify_LeaveScope();
1018# endif
1019
1020}
1021
1022/**
1023 * Allocate resources and start FleshWorkThread
1024 * @return TRUE if OK
1025 */
1026
1027BOOL StartFleshWorkThread()
1028{
1029 APIRET rc = DosCreateMutexSem(NULL, &hmtxFleshWork, 0L /* Not shared */, FALSE /* Not owned */);
1030 if (rc) {
1031 Dos_Error(MB_CANCEL, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1032 PCSZ_DOSCREATEMUTEXSEM);
1033 return FALSE;
1034 }
1035
[1860]1036 rc = xDosCreateEventSem(NULL, &hevFleshWorkListChanged, 0 /* Not shared */, FALSE /* Reset */);
1037 if (rc)
1038 return FALSE; // Give up
[1856]1039
1040 /* DbgMsg is time consuming
1041 define FM2_NO_FLESH_DBGMSG to suppress
1042 2015-08-09 SHL FIXME to be gone
1043 */
1044
1045 fNoFleshDbgMsg = getenv("FM2_NO_FLESH_DBGMSG") != NULL;
1046
1047 tidFleshWorkListThread = xbeginthread(FleshWorkThread,
1048 65536,
1049 NULL,
1050 pszSrcFile, __LINE__);
1051 return tidFleshWorkListThread != -1;
1052
1053}
1054
1055#pragma alloc_text(FLESH,Flesh,FleshEnv,UnFlesh,Stubby,FleshWorkThread,StartFleshWorkThread,AddFleshWorkRequest)
Note: See TracBrowser for help on using the repository browser.