source: trunk/dll/flesh.c@ 1863

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

Remove recurse scan code; fix A:\ drive not ready error caused by not moving the cursor from drive A:\ fast enough. Have Flesh remove pcis that have NullStr FileNames.

  • 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 1863 2015-08-23 00:13:48Z gyoung $
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),
[1863]251 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
[1856]252
253 // 2015-08-06 SHL allow pciL -1
[1858]254 // 2015-08-06 SHL FIXME to not need pszFileName check
[1863]255 if (!pciL || (INT)pciL == -1 || !*pciL->pszFileName || !strcmp(pciL->pszFileName, NullStr)) {
[1856]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
[1655]289 return TRUE;
[1651]290 }
[1856]291
[1655]292 return FALSE;
[2]293}
294
[1858]295/**
296 * Remove children from container
297 * @parame pciParent is parent of children to be removed
298 */
[1856]299
[1858]300VOID UnFlesh(HWND hwndCnr, PCNRITEM pciParent)
[175]301{
[1856]302 BOOL removed = FALSE;
[2]303 PCNRITEM pciL;
304
[175]305 if (!pciParent || !hwndCnr)
[1858]306 return;
[1856]307
308 if (!fNoFleshDbgMsg)
309 DbgMsg(pszSrcFile, __LINE__, "UnFlesh pciParent %p pszFileName %s", pciParent, pciParent->pszFileName ? pciParent->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
310
[551]311 for (;;) {
[1858]312 pciL = (PCNRITEM)WinSendMsg(hwndCnr,
313 CM_QUERYRECORD,
314 MPFROMP(pciParent),
315 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
[1856]316 if (!pciL || (INT)pciL == -1)
317 break; // Done
318
319 if (!fNoFleshDbgMsg)
320 DbgMsg(pszSrcFile, __LINE__, "UnFlesh RemoveCnrItems() pciL %p %s", pciL, pciL->pszFileName ? pciL->pszFileName : "(null)"); // 2015-08-03 SHL FIXME debug
321 RemoveCnrItems(hwndCnr, pciL, 1, CMA_FREE);
322 removed = TRUE;
323 } // for
324
325 if (removed) {
[2]326 WinSendMsg(hwndCnr,
[551]327 CM_INVALIDATERECORD,
328 MPFROMP(&pciParent),
329 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
[175]330 }
[1858]331 return;
[2]332}
333
[1482]334#define DDEPTH 64
[2]335
[1471]336/**
[1856]337 * Insert CNRITEM for 1st subdirectory [or file] of pciParent
338 * @param hwdCnr is container to be filled
339 * @param pciParent is CNRITEM to receive child record
340 * @return TRUE if record inserted, else FALSE
341 * Ensures that expand/collapse button displays if directory has children
342 * Secondary purpose is to detect broken LANs and inaccesible mapped drives
[1471]343 */
344
[551]345BOOL Stubby(HWND hwndCnr, PCNRITEM pciParent)
[175]346{
[1409]347 /**
[2]348 * this code is full of workarounds for screwed up LANs.
349 * let's hope all the current LAN programmers fall into
350 * a black hole and make way for people who can get it right...
351 */
352
[1471]353 BOOL ok = FALSE;
[847]354 FILEFINDBUF3 ffb[DDEPTH];
355 PFILEFINDBUF3 pffb;
[551]356 HDIR hDir = HDIR_CREATE;
[1856]357 ULONG nm, ulM = 1, total = 0, fl;
[1858]358 CHAR wildcard[CCHMAXPATH];
[551]359 register INT len;
360 APIRET rc, prc;
[1858]361 BOOL isadir = FALSE;
362 BOOL isremote;
363 BOOL includefiles;
[1482]364 ULONG ddepth = DDEPTH;
[1299]365 ULONG drvNum;
366 ULONG flags;
[551]367 static BOOL brokenlan = FALSE, isbroken = FALSE;
[2]368
[1858]369 if (!pciParent || (INT)pciParent == -1 || !*pciParent->pszFileName
[1832]370 || pciParent->pszFileName == NullStr || !hwndCnr)
[2]371 return FALSE;
[1856]372
373 if (!fNoFleshDbgMsg)
374 DbgMsg(pszSrcFile, __LINE__, "Stubby pciParent %p pszFileName %s", pciParent, pciParent->pszFileName); // 2015-08-03 SHL FIXME debug
375
376 // Build wildcard
[730]377 len = strlen(pciParent->pszFileName);
[1858]378 memcpy(wildcard, pciParent->pszFileName, len + 1);
379 if (wildcard[len - 1] != '\\')
380 wildcard[len++] = '\\';
381 wildcard[len++] = '*';
382 wildcard[len] = 0;
[2]383
[1858]384 // 2015-08-19 SHL FIXME to know how this can happen
385 if (!isalpha(*wildcard) || wildcard[1] != ':' || wildcard[2] != '\\') {
386 MakeFullName(wildcard);
387 DbgMsg(pszSrcFile, __LINE__, "Stubby MakeFullName returned %s", wildcard); // 2015-08-19 SHL FIXME debug
388 }
[2]389
[1299]390 drvNum = toupper(*pciParent->pszFileName) - 'A';
391 flags = driveflags[drvNum];
[1858]392 if (!isalpha(*wildcard) ||
393 wildcard[1] != ':' ||
394 wildcard[2] != '\\' || ((flags & DRIVE_IGNORE)))
[1856]395 return FALSE; // Not a directory or ignore requested
[2]396
[1856]397 includefiles = flags & DRIVE_INCLUDEFILES ? TRUE : fFilesInTree;
[2]398
[1856]399 isremote = flags & DRIVE_REMOTE ? TRUE : FALSE;
[2]400
[551]401 if (isremote) {
402 if (fRemoteBug) {
403 if (brokenlan) {
[1858]404 ddepth = (ULONG)-1;
[551]405 ddepth--;
[2]406 }
[761]407 ulM = 1;
[2]408 }
409 }
[551]410 else if (isbroken)
[2]411 ddepth = 14;
412
[1482]413 if (!fRemoteBug)
[1856]414 ulM = ddepth <= DDEPTH ? ddepth : 1;
[2]415
416 nm = ulM;
417
418 DosError(FERR_DISABLEHARDERR);
[1856]419
420 fl = includefiles ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY;
421
[1858]422 DbgMsg(pszSrcFile, __LINE__, "Stubby DosFindFirst(%s)", wildcard); // 2015-08-19 SHL FIXME debug
423
424 rc = DosFindFirst(wildcard,
[847]425 &hDir,
426 FILE_NORMAL | fl |
427 FILE_READONLY | FILE_ARCHIVED |
428 FILE_SYSTEM | FILE_HIDDEN,
429 &ffb, ulM * sizeof(FILEFINDBUF3), &nm, FIL_STANDARD);
[761]430 if (ulM == 1 && !rc) {
[1856]431 // Loop looking for 1st directory (or file)
[2]432 do {
433 pffb = &ffb[0];
[551]434 if (!includefiles && !(pffb->attrFile & FILE_DIRECTORY) && !brokenlan) {
[1856]435 // Find returned file when only directories requested
[551]436 brokenlan = TRUE;
[1858]437 ddepth = (ULONG)-1;
[551]438 ddepth--;
439 if (!NoBrokenNotify) {
440 prc = saymsg(MB_YESNO | MB_ICONEXCLAMATION,
441 HWND_DESKTOP,
442 GetPString(IDS_LANERRORTITLETEXT),
443 GetPString(IDS_LANERRORTEXT));
444 if (prc == MBID_NO) {
445 saymsg(MB_ENTER,
446 HWND_DESKTOP,
447 GetPString(IDS_LANERROR2TITLETEXT),
448 GetPString(IDS_LANERROR2TEXT));
[847]449 NoBrokenNotify = 255;
[1505]450 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
[551]451 &NoBrokenNotify, sizeof(ULONG));
452 }
453 }
454 else {
455 NoBrokenNotify--;
[1505]456 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
[551]457 &NoBrokenNotify, sizeof(ULONG));
458 }
[2]459 }
[1856]460
[515]461 if (*pffb->achName &&
[551]462 (includefiles || (pffb->attrFile & FILE_DIRECTORY)) &&
463 (pffb->achName[0] != '.' ||
[515]464 (pffb->achName[1] &&
[551]465 (pffb->achName[1] != '.' || pffb->achName[2])))) {
[1856]466 // Got directory other than . or .. (or a file)
[551]467 DosFindClose(hDir);
468 isadir = TRUE;
469 goto Interruptus;
[2]470 }
[761]471 nm = 1;
[2]472 DosError(FERR_DISABLEHARDERR);
[1856]473 } while (++total < ddepth && !(rc = (DosFindNext(hDir,
474 &ffb,
475 sizeof(FILEFINDBUF3),
476 &nm))));
477 DosFindClose(hDir);
478
[730]479 if (toupper(*pciParent->pszFileName) > 'B' &&
[751]480 (*(pciParent->pszFileName + 1)) == ':' &&
[730]481 (*(pciParent->pszFileName + 2)) == '\\' && !(*(pciParent->pszFileName + 3))) {
[2]482
[1856]483 // Searching root of hard or remote drive and find reported error
[2]484 CHAR s[132];
485 sprintf(s,
[551]486 GetPString(IDS_NOSUBDIRSTEXT),
[730]487 total, toupper(*pciParent->pszFileName));
[551]488 if (rc && rc != ERROR_NO_MORE_FILES)
[1858]489 sprintf(&s[strlen(s)], GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
[847]490 else if (ddepth < 16)
[551]491 brokenlan = TRUE;
[2]492 Notify(s);
493 }
[1856]494 goto None; // Done
[2]495 }
[1856]496
[551]497 if (!rc) {
[2]498 DosFindClose(hDir);
[551]499 if (nm) {
[1353]500 PBYTE fb = (PBYTE)&ffb[0];
[551]501 for (len = 0; len < nm; len++) {
[847]502 pffb = (PFILEFINDBUF3) fb;
[551]503 if (!includefiles && !(pffb->attrFile & FILE_DIRECTORY)) {
[1856]504 // Got file(s), but did not ask for files
[551]505 if (!isbroken) {
506 isbroken = TRUE;
507 if (!NoBrokenNotify) {
508 prc = saymsg(MB_YESNO | MB_ICONEXCLAMATION,
509 HWND_DESKTOP,
510 GetPString(IDS_FSDERRORTITLETEXT),
511 GetPString(IDS_FSDERRORTEXT),
[1471]512 isremote ? GetPString(IDS_REMOTETEXT) :
513 GetPString(IDS_LOCALTEXT),
[1858]514 *wildcard);
[551]515 if (prc == MBID_NO) {
516 saymsg(MB_ENTER,
517 HWND_DESKTOP,
518 GetPString(IDS_FSDERROR2TITLETEXT),
519 GetPString(IDS_FSDERROR2TEXT));
[847]520 NoBrokenNotify = 255;
[1505]521 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
[551]522 &NoBrokenNotify, sizeof(ULONG));
523 }
524 }
525 else {
526 NoBrokenNotify--;
[1505]527 PrfWriteProfileData(fmprof, FM3Str, "NoBrokenNotify",
[551]528 &NoBrokenNotify, sizeof(ULONG));
529 }
[1856]530 } // if !broken
531 } // if !directory
532
[551]533 if (*pffb->achName &&
534 (includefiles || (pffb->attrFile & FILE_DIRECTORY)) &&
[1856]535 ((pffb->achName[0] && pffb->achName[0] != '.') ||
536 (pffb->achName[1] &&
537 (pffb->achName[1] != '.' || pffb->achName[2]))))
538 {
539 // Got directory other than . or .. (or a file)
[551]540 isadir = TRUE;
541 break;
542 }
543 fb += pffb->oNextEntryOffset;
[1353]544 } // for
[2]545
[551]546 Interruptus:
[2]547
[551]548 if (isadir) {
[2]549
[1856]550 // Insert CNRITEM for selected directory (or file)
[1471]551 PCNRITEM pci;
[2]552
[1471]553 if (WinIsWindow((HAB)0, hwndCnr)) {
554 pci = WinSendMsg(hwndCnr,
555 CM_ALLOCRECORD,
556 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(1));
557 if (!pci) {
558 Win_Error(hwndCnr, HWND_DESKTOP, __FILE__, __LINE__,
559 GetPString(IDS_RECORDALLOCFAILEDTEXT));
560 }
561 else {
562 RECORDINSERT ri;
[1858]563 // 2015-08-19 SHL FIXME to use BldFullPathName(wildcard, ...)
564 pci->pszFileName = NullStr; // 2015-08-19 SHL FIXME to doc why
565 pci->pszDisplayName = NullStr;
[1471]566 pci->rc.pszIcon = pci->pszDisplayName;
567 memset(&ri, 0, sizeof(RECORDINSERT));
568 ri.cb = sizeof(RECORDINSERT);
[1858]569 ri.pRecordOrder = (PRECORDCORE)CMA_END;
570 ri.pRecordParent = (PRECORDCORE)pciParent;
571 ri.zOrder = (ULONG)CMA_TOP;
[1471]572 ri.cRecordsInsert = 1;
[1856]573 ri.fInvalidateRecord = TRUE;
[1858]574 // 2015-08-03 SHL FIXME debug
575 if (pci->pszFileName == NullStr)
576 DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD %p \"%s\" %.255s", pci, pci->pszFileName, pffb->achName);
[1471]577 if (!WinSendMsg(hwndCnr,
578 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
[1856]579 // Assume busy and try again
[1471]580 DosSleep(50); //05 Aug 07 GKY 100
[1856]581 WinSetFocus(HWND_DESKTOP, hwndCnr);
582 if (WinIsWindow((HAB)0, hwndCnr)) {
[1858]583 if (!fNoFleshDbgMsg) {
584 // 2015-08-03 SHL FIXME debug
585 if (pci->pszFileName == NullStr)
586 DbgMsg(pszSrcFile, __LINE__, "Stubby CM_INSERTRECORD pci %p pszFileName \"%s\"", pci, pci->pszFileName); // 2015-08-03 SHL FIXME debug
587 }
[1471]588 if (!WinSendMsg(hwndCnr,
589 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
590 Win_Error(hwndCnr, HWND_DESKTOP, __FILE__, __LINE__,
591 GetPString(IDS_RECORDINSERTFAILEDTEXT));
592 FreeCnrItem(hwndCnr, pci);
593 }
594 else
595 ok = TRUE;
596 }
597 }
598 else
[1856]599 ok = TRUE;
[1471]600 }
601 }
[1856]602 } // if isadir
[1858]603 else if (toupper(*wildcard) > 'B' && wildcard[1] == ':' && wildcard[2] == '\\' &&
604 !wildcard[3]) {
[2]605
[1858]606 // 2015-08-19 SHL FIXME to know how this can happen since wildcard ends with *
[1856]607 // Is root and no subdirectories
[551]608 CHAR s[162];
[1858]609 DbgMsg(pszSrcFile, __LINE__, "Stubby !isadir for %s", wildcard); // 2015-08-19 SHL FIXME debug
[551]610 sprintf(s,
611 GetPString(IDS_NOSUBDIRS2TEXT),
612 nm,
[730]613 toupper(*pciParent->pszFileName),
[1856]614 isremote ? GetPString(IDS_NOSUBDIRS3TEXT) : NullStr);
[551]615 Notify(s);
[2]616 }
617 }
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
686#if 0 // 2015-08-03 SHL FIXME debug
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);
[1863]786 return strncmp(((PFLESHWORKITEM)item)->pci->pszFileName, (PCSZ)data, c) == 0;
[1858]787}
788
789/**
790 * Wait until work list empty or until dependent items removed from list
[1856]791 * Advisory only
[1858]792 * @parse pszFileName is dependent pathName
[1856]793 */
794
795#if 0 // 2015-08-03 SHL FIXME debug
[1860]796VOID WaitFleshWorkListEmpty(PCSZ pszDirName)
[1856]797#else
[1860]798VOID WaitFleshWorkListEmptyDbg(PCSZ pszDirName, PCSZ pszSrcFile_, UINT uSrcLineNo_)
[1856]799#endif
800{
[1858]801 APIRET rc;
802 PFLESHWORKITEM item;
[1856]803 INT tid = GetTidForThread();
[1860]804 BOOL pathSaved = FALSE;
805 PCSZ pszSavedFleshFocusPath;
[1856]806
807 if (tid == 1 || tid == tidFleshWorkListThread) {
808# ifdef WaitFleshWorkListEmpty
809 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist %sempty by tid %u at %s:%u", IsFleshWorkListEmpty() ? "" : "not ", tid, pszSrcFile_, uSrcLineNo_);
810# else
811 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called by tid %u", tid);
812# endif
813 return; // Avoid hang
814 }
815 else if (IsFleshWorkListEmpty()) {
816# ifdef WaitFleshWorkListEmpty
[1858]817 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with worklist empty at %s:%u", pszSrcFile_, uSrcLineNo_);
[1856]818# else
[1858]819 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list empty");
[1856]820# endif
821 }
822
823 // Can not wait if call from thread 1 or FleshWorkListThread
824 while (!IsFleshWorkListEmpty()) {
[1858]825
826#if 0 // 2015-08-19 SHL FIXME debug
[1856]827# ifdef WaitFleshWorkListEmpty
828 if (!fNoFleshDbgMsg)
[1858]829 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty by %s:%u", pszSrcFile_, uSrcLineNo_); // 2015-08-07 SHL FIXME debug
[1856]830# else
831 if (!fNoFleshDbgMsg)
[1858]832 DbgMsg(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called with work list not empty"); // 2015-08-07 SHL FIXME debug
[1856]833# endif
[1858]834#endif // 2015-08-19 SHL FIXME debug
835
836 // 2015-08-13 SHL
837 if (fAmQuitting)
838 return;
839
[1860]840 // Just wait for dependents to be gone if path name given
841 if (pszDirName) {
842 rc = xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
843 if (rc)
844 continue; // Maybe should return ???
845
846 if (!pathSaved) {
847 // Give priority to work items for parents of this path
848 pathSaved = TRUE;
849 pszSavedFleshFocusPath = pszFleshFocusPath;
850 pszFleshFocusPath = pszDirName;
[1858]851 }
852
[1860]853 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszDirName);
[1858]854
[1860]855 xDosReleaseMutexSem(hmtxFleshWork);
[1858]856
857 if (!item)
858 break; // Dependents gone from work list
[1860]859 } // if pszDirName
860
[1856]861 DosSleep(250);
[1858]862 } // while
863
[1860]864 if (!pathSaved) {
865 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
866 pszFleshFocusPath = pszSavedFleshFocusPath;
867 xDosReleaseMutexSem(hmtxFleshWork);
868 }
[1858]869
[1856]870}
871
872/**
873 * Set focus drive to optimize work list processing
874 * @param chDriveLetter is upper case drive letter (A-Z)
875 */
876
[1860]877VOID SetFleshFocusPath(PCSZ pszPath) {
878 PCSZ pszOld;
879 PCSZ pszNew = strdup(pszPath);
880 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
881 pszOld = pszFleshFocusPath;
882 pszFleshFocusPath = pszNew;
883 xDosReleaseMutexSem(hmtxFleshWork);
884 if (pszOld)
885 xfree((PVOID)pszOld, pszSrcFile, __LINE__);
886 DbgMsg(pszSrcFile, __LINE__, "SetFleshFocusPath focus path set to %s", pszFleshFocusPath); // 2015-08-03 SHL FIXME debug
[1856]887
888}
889
890/**
891 * Run Flesh, UnFlesh, FleshEnv, Stubby for directory for items in work list
892 */
893
894VOID FleshWorkThread(PVOID arg)
895{
896 HAB thab;
897 HMQ hmq = (HMQ)0;
898
899 // 2015-08-07 SHL FIXME to be gone
900 static INT ProcessDirCount = 0;
901
902 DosError(FERR_DISABLEHARDERR);
903
904# ifdef FORTIFY
905 Fortify_EnterScope();
906# endif
907
908 thab = WinInitialize(0);
909 if (thab) {
910 hmq = WinCreateMsgQueue(thab, 0);
911 if (hmq) {
912 IncrThreadUsage();
913 priority_normal();
914
[1858]915 // process list entries until time to die
916 for (;!fAmQuitting;) {
[1856]917
918 PFLESHWORKITEM item;
919
920 // 2015-08-07 SHL FIXME to use SMPSafe...
[1860]921 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
[1856]922
923 // 2015-08-14 SHL
924 // Get next work list item and remove from list
[1860]925 // If focus path set, process parents of focus path first
926 if (pszFleshFocusPath) {
927 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszFleshFocusPath);
928 if (!item) {
929 xfree((PSZ)pszFleshFocusPath, pszSrcFile, __LINE__);
930 pszFleshFocusPath = NULL; // Revert to normal
931 }
[1856]932 else
933 List2Delete(&FleshWorkList, (PLIST2)item);
934 }
935 else
936 item = NULL;
937
938 if (!item)
939 item = (PFLESHWORKITEM)List2DeleteFirst(&FleshWorkList);
940
[1860]941 xDosReleaseMutexSem(hmtxFleshWork);
[1856]942
[1858]943 // Wait for new items to be added to list
[1856]944 if (!item) {
945 ULONG ul;
946 if (!fNoFleshDbgMsg)
947 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work list empty - waiting"); // 2015-08-03 SHL FIXME debug
[1860]948 xDosWaitEventSem(hevFleshWorkListChanged, SEM_INDEFINITE_WAIT);
949 xDosResetEventSem(hevFleshWorkListChanged, &ul);
[1856]950 if (!fNoFleshDbgMsg)
951 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread work hev posted"); // 2015-08-03 SHL FIXME debug
952 continue;
953 }
954
955 if (WinIsWindow((HAB)0, item->hwndCnr)) {
956#if 0 // 2015-08-07 SHL FIXME debug
957 // 2015-08-03 SHL FIXME debug
958 {
959 static PSZ itemNames[] = {
960 "eStubby", "eFlesh", "eFleshEnv", "eUnFlesh"
961 };
962
963 PCNRITEM pci = item->pci;
964 if (!fNoFleshDbgMsg) {
965 DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread action %s pci %p pszFileName %s",
966 itemNames[item->action],
967 pci,
968 pci && (INT)pci != -1 ?
969 (pci->pszFileName ? pci->pszFileName : "(nullname)") :
970 "(nullpci)"); // 2015-08-03 SHL FIXME debug
971 }
972 }
973#endif
974
975 switch (item->action) {
976 case eUnFlesh:
977 UnFlesh(item->hwndCnr, item->pci);
978 break;
979 case eFleshEnv:
980 FleshEnv(item->hwndCnr, item->pci);
981 break;
982 case eStubby:
983 // DbgMsg(pszSrcFile, __LINE__, "FleshWorkThread pci %p pszFileName %s", stubbyArgs->pci, stubbyArgs->pci->pszFileName); // 2015-08-03 SHL FIXME debug
[1863]984 Stubby(item->hwndCnr, item->pci);
985 break;
[1856]986 case eFlesh:
987 if (Flesh(item->hwndCnr, item->pci)) {
988 // 2015-08-06 SHL FIXME to report?
989 }
990 break;
991 default:
992 Runtime_Error(pszSrcFile, __LINE__, "item %u unexpected", item->action);
993 } // switch
994
995
996 } // if window
997
998 xfree(item, pszSrcFile, __LINE__);
999
1000 } // for
1001
1002 WinDestroyMsgQueue(hmq);
1003 }
1004 DecrThreadUsage();
1005 WinTerminate(thab);
1006 }
1007
1008 ProcessDirCount++;
1009 // DbgMsg(pszSrcFile, __LINE__, "ProcessDirCount %i FixedVolume %i", ProcessDirCount, FixedVolume);
1010 if (ProcessDirCount >= FixedVolume) {
1011 ProcessDirCount = 0;
1012 FixedVolume = 0;
1013 }
1014
1015# ifdef FORTIFY
1016 Fortify_LeaveScope();
1017# endif
1018
1019}
1020
1021/**
1022 * Allocate resources and start FleshWorkThread
1023 * @return TRUE if OK
1024 */
1025
1026BOOL StartFleshWorkThread()
1027{
1028 APIRET rc = DosCreateMutexSem(NULL, &hmtxFleshWork, 0L /* Not shared */, FALSE /* Not owned */);
1029 if (rc) {
1030 Dos_Error(MB_CANCEL, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1031 PCSZ_DOSCREATEMUTEXSEM);
1032 return FALSE;
1033 }
1034
[1860]1035 rc = xDosCreateEventSem(NULL, &hevFleshWorkListChanged, 0 /* Not shared */, FALSE /* Reset */);
1036 if (rc)
1037 return FALSE; // Give up
[1856]1038
1039 /* DbgMsg is time consuming
1040 define FM2_NO_FLESH_DBGMSG to suppress
1041 2015-08-09 SHL FIXME to be gone
1042 */
1043
1044 fNoFleshDbgMsg = getenv("FM2_NO_FLESH_DBGMSG") != NULL;
1045
1046 tidFleshWorkListThread = xbeginthread(FleshWorkThread,
1047 65536,
1048 NULL,
1049 pszSrcFile, __LINE__);
1050 return tidFleshWorkListThread != -1;
1051
1052}
1053
1054#pragma alloc_text(FLESH,Flesh,FleshEnv,UnFlesh,Stubby,FleshWorkThread,StartFleshWorkThread,AddFleshWorkRequest)
Note: See TracBrowser for help on using the repository browser.