source: trunk/dll/flesh.c@ 1882

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

ExpandAll on a CDROM drive caused directory not found errors. Changed waits so they are longer on removable drives errors are gone performance on hard drives is unchanged.

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