source: trunk/dll/flesh.c@ 1901

Last change on this file since 1901 was 1901, checked in by Gregg Young, 17 months ago

Fix ticket #583 tree corruption on startup or rescan and ticket #584 spurious "no drop" on first subdirectory in tree.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.6 KB
RevLine 
[145]1
2/***********************************************************************
3
4 $Id: flesh.c 1901 2024-05-29 20:05:35Z gyoung $
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
[1901]284 (pciL && (INT)pciL != -1) && pciL->pszDisplayName ? 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 }
[1901]602 pci->rc.hptrIcon = hptr;
603 pci->attrFile = pffb->attrFile;
[1471]604 memset(&ri, 0, sizeof(RECORDINSERT));
605 ri.cb = sizeof(RECORDINSERT);
[1858]606 ri.pRecordOrder = (PRECORDCORE)CMA_END;
607 ri.pRecordParent = (PRECORDCORE)pciParent;
608 ri.zOrder = (ULONG)CMA_TOP;
[1471]609 ri.cRecordsInsert = 1;
[1856]610 ri.fInvalidateRecord = TRUE;
[1891]611 if (!WinSendMsg(hwndCnr,
[1471]612 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
[1856]613 // Assume busy and try again
[1891]614 DosSleep(50);
[1856]615 WinSetFocus(HWND_DESKTOP, hwndCnr);
[1891]616 if (WinIsWindow((HAB)0, hwndCnr)) {
[1471]617 if (!WinSendMsg(hwndCnr,
618 CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri))) {
619 Win_Error(hwndCnr, HWND_DESKTOP, __FILE__, __LINE__,
620 GetPString(IDS_RECORDINSERTFAILEDTEXT));
621 FreeCnrItem(hwndCnr, pci);
622 }
[1891]623 else
624 ok = TRUE;
[1471]625 }
626 }
627 else
[1856]628 ok = TRUE;
[1471]629 }
630 }
[1856]631 } // if isadir
[2]632 }
[1864]633 } // if !rc
634 else if (toupper(*wildcard) > 'B' && wildcard[1] == ':' && wildcard[2] == '\\' &&
[1865]635 wildcard[3] == '*' && !wildcard[4]) {
[1864]636 // Is root and no subdirectories
637 CHAR s[162];
[1865]638
[1864]639 sprintf(s,
[1865]640 GetPString(IDS_NOSUBDIRS2TEXT),
641 nm,
642 toupper(*pciParent->pszFileName),
643 isremote ? GetPString(IDS_NOSUBDIRS3TEXT) : NullStr);
[1864]644 Notify(s);
[2]645 }
[1858]646 else if (toupper(*wildcard) > 'B' && rc != ERROR_NO_MORE_FILES) {
[1856]647 // Find for remote or hard drive failed with error
[2]648 CHAR s[CCHMAXPATH + 80];
[1858]649 sprintf(s, GetPString(IDS_SEARCHERRORTEXT), rc, wildcard);
[2]650 Notify(s);
651 }
652
653None:
654
655 DosError(FERR_DISABLEHARDERR);
[1471]656 return ok;
[1856]657} // Stubby
658
659// Stubby/Flesh/Unflesh work list item
660
661typedef struct {
662 LIST2 list;
663 HWND hwndCnr;
664 PCNRITEM pci;
665 FLESHWORKACTION action;
666} FLESHWORKITEM;
667typedef FLESHWORKITEM *PFLESHWORKITEM;
668
669// Stubby/Flesh/Unflesh work list
670LIST2 FleshWorkList;
671
672HMTX hmtxFleshWork;
[1891]673HEV hevFleshWorkListChanged;
[1856]674
675/**
[1858]676 * Check work list item pci matches passed pci
[1856]677 */
678
679BOOL WorkListItemMatches(PLIST2 item, PVOID data)
680{
681 return ((PFLESHWORKITEM)data)->pci == ((PFLESHWORKITEM)item)->pci;
[2]682}
[793]683
[1856]684/**
685 * Delete stale items from flesh queue
686 */
687
688VOID DeleteStaleFleshWorkListItems(PCNRITEM pci)
689{
690 FLESHWORKITEM match;
691 PLIST2 item;
692
693 match.pci = pci;
694
695 for (;;) {
696 item = List2Search(&FleshWorkList, WorkListItemMatches, &match);
697 if (!item)
698 break;
699 List2Delete(&FleshWorkList, item);
700 xfree(item, pszSrcFile, __LINE__);
701 }
702}
703
704/**
705 * Add item to flesh work list
706 * eUnFlesh requests get special handling
707 * eFlesh etc. items for the same CNRITEM are considered stale and are
708 * deleted because eUnFlesh will free the CNRITEM associated with the item
709 * before the work list item is processed
710 */
711
712BOOL AddFleshWorkRequest(HWND hwndCnr, PCNRITEM pci, FLESHWORKACTION action)
713{
714 PFLESHWORKITEM item = xmallocz(sizeof(FLESHWORKITEM), pszSrcFile, __LINE__);
715 item->hwndCnr = hwndCnr;
716 item->pci = pci;
717 item->action= action;
718
[1858]719 if (fAmQuitting)
720 return FALSE;
[1856]721
[1860]722 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
[1856]723
724 // Delete stale requests
[1858]725 if (item->action == eUnFlesh)
[1856]726 DeleteStaleFleshWorkListItems(pci);
727
728 List2Append(&FleshWorkList, (PLIST2)item);
729
[1860]730 xDosReleaseMutexSem(hmtxFleshWork);
731 xDosPostEventSem(hevFleshWorkListChanged);
[1856]732
733 return TRUE;
734}
735
736/**
737 * Return TRUE if work list empty
738 * Advisory only
739 */
740
[1879]741BOOL IsFleshWorkListEmpty(VOID)
[1856]742{
743 return FleshWorkList.next == NULL;
744}
745
746/**
[1858]747 * Check if pci pathname is parent of child path name
748 * @param data is child path name
[1860]749 * @return TRUE if is work item path is parent of given path
[1858]750 */
751
752BOOL IsParentOfChildPath(PLIST2 item, PVOID data)
753{
754 UINT c;
755 if (!((PFLESHWORKITEM)item)->pci->pszFileName) {
[1861]756 Runtime_Error(pszSrcFile, __LINE__, "IsParentOfChildPath called with pci %p pszFileName (null)", ((PFLESHWORKITEM)item)->pci);
[1858]757 return FALSE;
758 }
759 c = strlen(((PFLESHWORKITEM)item)->pci->pszFileName);
[1865]760 return strncmp(((PFLESHWORKITEM)item)->pci->pszFileName, (PCSZ)data, c) == 0;
[1858]761}
762
763/**
764 * Wait until work list empty or until dependent items removed from list
[1856]765 * Advisory only
[1858]766 * @parse pszFileName is dependent pathName
[1856]767 */
768
[1874]769VOID WaitFleshWorkListEmpty(PCSZ pszDirName, ULONG ulSleep)
[1856]770{
[1858]771 APIRET rc;
772 PFLESHWORKITEM item;
[1856]773 INT tid = GetTidForThread();
[1860]774 BOOL pathSaved = FALSE;
[1867]775 BOOL waited;
[1860]776 PCSZ pszSavedFleshFocusPath;
[1873]777 INT rcCount = 0;
[1856]778
[1891]779 // 11 Oct 15 GKY FIXME did we intend to keep this
780 if (tid == 1 || tid == tidFleshWorkListThread) {
[1856]781 Runtime_Error(pszSrcFile, __LINE__, "WaitFleshWorkListEmpty called by tid %u", tid);
[1891]782 return; // Avoid hang
[1856]783 }
784 // Can not wait if call from thread 1 or FleshWorkListThread
[1867]785 for (waited = FALSE; !IsFleshWorkListEmpty(); waited = TRUE) {
[1858]786 // 2015-08-13 SHL
787 if (fAmQuitting)
788 return;
789
[1860]790 // Just wait for dependents to be gone if path name given
791 if (pszDirName) {
792 rc = xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
[1873]793 if (rc) {
[1891]794 rcCount++;
795 if (rcCount < 6)
796 continue; // Maybe should return ???
797 else {
798 Dos_Error(MB_CANCEL, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
799 PCSZ_DOSREQUESTMUTEXSEM);
800 return;
801 }
[1860]802
[1873]803 }
804
[1860]805 if (!pathSaved) {
806 // Give priority to work items for parents of this path
807 pathSaved = TRUE;
808 pszSavedFleshFocusPath = pszFleshFocusPath;
809 pszFleshFocusPath = pszDirName;
[1858]810 }
811
[1860]812 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszDirName);
[1858]813
[1860]814 xDosReleaseMutexSem(hmtxFleshWork);
[1873]815 rcCount = 0;
[1858]816
[1867]817 if (!item) {
818 if (waited)
[1891]819 DosSleep(ulSleep); // Let PM do some work
[1858]820 break; // Dependents gone from work list
[1867]821 }
[1860]822 } // if pszDirName
[1874]823 DosSleep(ulSleep);
[1867]824 } // for
[1858]825
[1865]826 if (pathSaved) {
[1860]827 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
828 pszFleshFocusPath = pszSavedFleshFocusPath;
829 xDosReleaseMutexSem(hmtxFleshWork);
830 }
[1858]831
[1856]832}
833
834/**
835 * Set focus drive to optimize work list processing
836 * @param chDriveLetter is upper case drive letter (A-Z)
837 */
838
[1860]839VOID SetFleshFocusPath(PCSZ pszPath) {
840 PCSZ pszOld;
841 PCSZ pszNew = strdup(pszPath);
842 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
843 pszOld = pszFleshFocusPath;
844 pszFleshFocusPath = pszNew;
845 xDosReleaseMutexSem(hmtxFleshWork);
846 if (pszOld)
847 xfree((PVOID)pszOld, pszSrcFile, __LINE__);
[1856]848}
849
850/**
851 * Run Flesh, UnFlesh, FleshEnv, Stubby for directory for items in work list
852 */
853
854VOID FleshWorkThread(PVOID arg)
855{
856 HAB thab;
857 HMQ hmq = (HMQ)0;
858
859 // 2015-08-07 SHL FIXME to be gone
860 static INT ProcessDirCount = 0;
861
862 DosError(FERR_DISABLEHARDERR);
863
864# ifdef FORTIFY
865 Fortify_EnterScope();
866# endif
867
868 thab = WinInitialize(0);
869 if (thab) {
870 hmq = WinCreateMsgQueue(thab, 0);
871 if (hmq) {
872 IncrThreadUsage();
873 priority_normal();
874
[1858]875 // process list entries until time to die
876 for (;!fAmQuitting;) {
[1856]877
878 PFLESHWORKITEM item;
879
880 // 2015-08-07 SHL FIXME to use SMPSafe...
[1860]881 xDosRequestMutexSem(hmtxFleshWork, SEM_INDEFINITE_WAIT);
[1856]882
883 // 2015-08-14 SHL
884 // Get next work list item and remove from list
[1860]885 // If focus path set, process parents of focus path first
886 if (pszFleshFocusPath) {
887 item = (PFLESHWORKITEM)List2Search(&FleshWorkList, IsParentOfChildPath, (PVOID)pszFleshFocusPath);
888 if (!item) {
889 xfree((PSZ)pszFleshFocusPath, pszSrcFile, __LINE__);
[1891]890 pszFleshFocusPath = NULL; // Revert to normal
[1860]891 }
[1856]892 else
893 List2Delete(&FleshWorkList, (PLIST2)item);
894 }
895 else
896 item = NULL;
897
898 if (!item)
899 item = (PFLESHWORKITEM)List2DeleteFirst(&FleshWorkList);
900
[1860]901 xDosReleaseMutexSem(hmtxFleshWork);
[1856]902
[1858]903 // Wait for new items to be added to list
[1856]904 if (!item) {
[1891]905 ULONG ul;
906 xDosWaitEventSem(hevFleshWorkListChanged, SEM_INDEFINITE_WAIT);
907 xDosResetEventSem(hevFleshWorkListChanged, &ul);
908 continue;
[1856]909 }
910
[1891]911 if (WinIsWindow((HAB)0, item->hwndCnr)) {
[1856]912
913 switch (item->action) {
[1891]914 case eUnFlesh:
915 UnFlesh(item->hwndCnr, item->pci);
[1856]916 break;
917 case eFleshEnv:
918 FleshEnv(item->hwndCnr, item->pci);
919 break;
920 case eStubby:
[1891]921 priority_bumped();
922 Stubby(item->hwndCnr, item->pci);
923 priority_normal();
[1865]924 break;
[1856]925 case eFlesh:
926 if (Flesh(item->hwndCnr, item->pci)) {
927 // 2015-08-06 SHL FIXME to report?
928 }
929 break;
930 default:
931 Runtime_Error(pszSrcFile, __LINE__, "item %u unexpected", item->action);
932 } // switch
933
934 } // if window
935
936 xfree(item, pszSrcFile, __LINE__);
937
938 } // for
939
940 WinDestroyMsgQueue(hmq);
941 }
942 DecrThreadUsage();
943 WinTerminate(thab);
944 }
945
946 ProcessDirCount++;
947 if (ProcessDirCount >= FixedVolume) {
948 ProcessDirCount = 0;
949 FixedVolume = 0;
950 }
951
952# ifdef FORTIFY
953 Fortify_LeaveScope();
954# endif
955
956}
957
958/**
959 * Allocate resources and start FleshWorkThread
960 * @return TRUE if OK
961 */
962
[1879]963BOOL StartFleshWorkThread(VOID)
[1856]964{
965 APIRET rc = DosCreateMutexSem(NULL, &hmtxFleshWork, 0L /* Not shared */, FALSE /* Not owned */);
966 if (rc) {
967 Dos_Error(MB_CANCEL, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
968 PCSZ_DOSCREATEMUTEXSEM);
969 return FALSE;
970 }
971
[1860]972 rc = xDosCreateEventSem(NULL, &hevFleshWorkListChanged, 0 /* Not shared */, FALSE /* Reset */);
973 if (rc)
974 return FALSE; // Give up
[1856]975 tidFleshWorkListThread = xbeginthread(FleshWorkThread,
976 65536,
977 NULL,
978 pszSrcFile, __LINE__);
979 return tidFleshWorkListThread != -1;
980
981}
982
983#pragma alloc_text(FLESH,Flesh,FleshEnv,UnFlesh,Stubby,FleshWorkThread,StartFleshWorkThread,AddFleshWorkRequest)
Note: See TracBrowser for help on using the repository browser.