source: trunk/dll/flesh.c@ 1891

Last change on this file since 1891 was 1891, checked in by Steven Levine, 6 years ago

Rework FreeCnrItem to ensure all CNRITEMs deleted.
Use WinSendMsg CMA_NEXT.
Was using preccNextRecord which is not recommended because control does
not maintain linkage after inserts and deletes.
Note: arccnrs.c still needs to be reworked to use common functions from filldir.c.

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