source: trunk/dll/filldir.c@ 1355

Last change on this file since 1355 was 1355, checked in by Gregg Young, 17 years ago

Minor update to write verify fix for USB removables

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.6 KB
RevLine 
[31]1
2/***********************************************************************
3
4 $Id: filldir.c 1355 2008-12-26 02:01:35Z gyoung $
5
6 Fill Directory Tree Containers
7
8 Copyright (c) 1993-98 M. Kimes
[907]9 Copyright (c) 2001, 2008 Steven H. Levine
[31]10
[145]11 10 Jan 04 SHL ProcessDirectory: avoid most large drive failures
12 24 May 05 SHL Rework Win_Error usage
[167]13 24 May 05 SHL Rework for CNRITEM.szSubject
14 25 May 05 SHL Rework for ULONGLONG
15 25 May 05 SHL Rework FillInRecordFromFFB
16 25 May 05 SHL Rework FillTreeCnr
[174]17 28 May 05 SHL Drop stale debug code
[188]18 05 Jun 05 SHL Comments
[214]19 09 Jun 05 SHL Rework WinLoadFileIcon enables
20 09 Jun 05 SHL Rework IDFile
[246]21 13 Aug 05 SHL Renames
[282]22 24 Oct 05 SHL FillInRecordFromFFB: correct longname display enable
23 24 Oct 05 SHL FillInRecordFromFSA: correct longname display enable
24 24 Oct 05 SHL Drop obsolete code
[359]25 22 Jul 06 SHL Check more run time errors
[534]26 20 Oct 06 SHL Sync . .. check code
27 22 Oct 06 GKY Add NDFS32 support
[552]28 17 Feb 07 GKY Additional archive and image file tyoes identifed by extension
29 17 Feb 07 GKY Add more drive types
[557]30 09 Mar 07 GKY Use SelectDriveIcon
[572]31 20 Mar 07 GKY Increase extention check to 4 letters for icon selections
[705]32 23 Jun 07 GKY Fixed ram disk without a directory not appearing on states drive list
[737]33 23 Jul 07 SHL Sync with CNRITEM updates (ticket#24)
[744]34 29 Jul 07 SHL Add CNRITEM free and remove support (ticket#24)
[751]35 02 Aug 07 SHL Add FileAttrToString
[756]36 03 Aug 07 GKY Enlarged and made setable everywhere Findbuf (speed file loading)
[760]37 04 Aug 07 SHL Update #pragma alloc_test for new functions
[775]38 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
[783]39 13 Aug 07 SHL Sync code with other FilesToGet usage and optimize
40 13 Aug 07 SHL Move #pragma alloc_text to end for OpenWatcom compat
[856]41 04 Nov 07 GKY Use commaFmtULL to display large file sizes
[985]42 29 Feb 08 GKY Use xfree where appropriate
[1063]43 07 Jul 08 SHL Use NULL rather than NullStr in FreeCnrItemData
[1075]44 16 JUL 08 GKY Use TMP directory for temp files
[1083]45 20 Jul 08 JBS Ticket 114: Support user-selectable env. strings in Tree container.
[1090]46 21 Jul 08 JBS Ticket 114: Change env var separator from blank to semicolon
[1104]47 02 Aug 08 GKY Remove redundant strcpys from inner loop
[1114]48 23 Aug 08 GKY Free pszDisplayName when appropriate
[1154]49 01 Sep 08 GKY Updated FreeCnrItemData to prevent trap in strrchr if pci->pszFileName is NULL.
50 05 Sep 08 SHL Correct FreeCnrItemData pszDisplayName pointer overlap check
[1174]51 08 Sep 08 SHL Remove extra pszLongName logic in FreeCnrItemData
[1250]52 18 Oct 08 GKY Scan drives in 4 passes (local, virtual, remote, flagged slow) to speed tree scans
[1284]53 19 Nov 08 SHL Correct and sanitize 4 pass scan logic
[1290]54 21 Nov 08 SHL FillTreeCnr: ensure any unchecked drives checked in pass 4
[1299]55 24 Nov 08 GKY Add StubyScanThread to treecnr scan/rescan drives all on separate threads
56 24 Nov 08 GKY Replace 4 pass drive scan code with StubyScanThread multithread scan
[1308]57 28 Nov 08 SHL FreeCnrItemData: optimize and always NULL pointers
58 28 Nov 08 SHL StubbyScanThread: add else lost in translation
59 30 Nov 08 SHL StubbyScanThread: restore else - we want all drives listed
60 30 Nov 08 SHL FreeCnrItemData: report double free with Runtime_Error
[1319]61 04 Dec 08 GKY Use event semaphore to prevent scan of "last" directory container prior to
[1335]62 tree scan completion; prevents duplicate directory names in tree.
63 10 Dec 08 SHL Integrate exception handler support
[31]64
65***********************************************************************/
66
[2]67#include <stdlib.h>
68#include <string.h>
[1154]69#include <malloc.h> // _msize _heapchk
[2]70#include <ctype.h>
[1335]71// #include <process.h> // _beginthread
[763]72
[907]73#define INCL_DOS
74#define INCL_WIN
75#define INCL_DOSERRORS
76#define INCL_LONGLONG
77
[1182]78#include "fm3dll.h"
[1223]79#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
[1207]80#include "draglist.h" // Data declaration(s)
81#include "treecnr.h" // Data declaration(s)
82#include "info.h" // Data declaration(s)
83#include "newview.h" // Data declaration(s)
[907]84#include "fm3str.h"
85#include "filldir.h"
86#include "errutil.h" // Dos_Error...
87#include "strutil.h" // GetPString
[1078]88#include "misc.h" // GetTidForWindow
89#include "fortify.h" // 06 May 08 SHL
[1083]90#include "notebook.h" // INI file fields
[1159]91#include "flesh.h" // FleshEnv, Stubby
92#include "update.h" // SelectDriveIcon
[1182]93#include "valid.h" // CheckDrive
94#include "filter.h" // Filter
95#include "subj.h" // Subject
96#include "copyf.h" // unlinkf
97#include "literal.h" // wildcard
98#include "commafmt.h" // CommaFmtULL
99#include "wrappers.h" // xDosFindNext
[1207]100#include "init.h" // GetTidForWindow
[1308]101#include "common.h" // IncrThreadUsage
[1335]102#include "excputil.h" // xbeginthread
[2]103
[1299]104VOID StubbyScanThread(VOID * arg);
105
[1207]106// Data definitions
[359]107static PSZ pszSrcFile = __FILE__;
[1207]108static BOOL fFirstTime;
[359]109
[1207]110#pragma data_seg(GLOBAL1)
111HPOINTER hptrEnv;
112HPOINTER hptrHidden;
113HPOINTER hptrReadonly;
114HPOINTER hptrSystem;
115
116#pragma data_seg(GLOBAL2)
117CHAR *FM3Tools;
118CHAR *WPProgram;
[1308]119volatile INT StubbyScanCount;
[1354]120volatile INT ProcessDirCount;
[1207]121
[1299]122typedef struct {
123 PCNRITEM pci;
[1308]124 HWND hwndCnr; // hwnd you want the message posted to
[1299]125 HWND hwndDrivesList;
126 BOOL RamDrive;
127}
128STUBBYSCAN;
129
[751]130/**
131 * Return display string given standard file attribute mask
132 * @param fileAttr attribute mask in FILEFINDBUF format
133 * @return fixed length string for display
134 */
135
136const PSZ FileAttrToString(ULONG fileAttr)
137{
138 // From os2win.h
139 // FILE_ATTRIBUTE_READONLY 0x00000001
140 // FILE_ATTRIBUTE_HIDDEN 0x00000002
141 // FILE_ATTRIBUTE_SYSTEM 0x00000004
142 // 0x00000008
143 // FILE_ATTRIBUTE_DIRECTORY 0x00000010
144 // FILE_ATTRIBUTE_ARCHIVE 0x00000020
145
146 static CHAR *apszAttrString[] = {
147 // RHSDA
148 "-----",
149 "R----",
150 "-H---",
151 "RH---",
152 "--S--",
153 "R-S--",
154 "-HS--",
155 "RHS--",
156 "---D-",
157 "R--D-",
158 "-H-D-",
159 "RH-D-",
160 "--SD-",
161 "R-SD-",
162 "-HSD-",
163 "RHSD-",
164 "----A",
165 "R---A",
166 "-H--A",
167 "RH--A",
168 "--S-A",
169 "R-S-A",
170 "-HS-A",
171 "RHS-A",
172 "---DA",
173 "R--DA",
174 "-H-DA",
175 "RH-DA",
176 "--SDA",
177 "R-SDA",
178 "-HSDA",
179 "RHSDA"
180 };
181
182 fileAttr = ((fileAttr & 0x30) >> 1) | (fileAttr & 7); // Drop don't care bit from index
183
184 return apszAttrString[fileAttr];
185
186}
187
[1299]188VOID StubbyScanThread(VOID * arg)
189{
190 STUBBYSCAN *StubbyScan;
191 HAB thab;
192 HMQ hmq = (HMQ) 0;
193 BOOL ret;
194
195 DosError(FERR_DISABLEHARDERR);
196
197# ifdef FORTIFY
198 Fortify_EnterScope();
199# endif
200
[1308]201 StubbyScan = (STUBBYSCAN *)arg;
202 if (StubbyScan && StubbyScan->pci && StubbyScan->pci->pszFileName && StubbyScan->hwndCnr) {
[1299]203 thab = WinInitialize(0);
204 if (thab) {
205 hmq = WinCreateMsgQueue(thab, 0);
206 if (hmq) {
[1354]207 StubbyScanCount++;
[1308]208 IncrThreadUsage();
209 priority_normal();
[1354]210 ret = Stubby(StubbyScan->hwndCnr, StubbyScan->pci);
211 //DbgMsg(pszSrcFile, __LINE__, "Stubby %i ", ret);
212 if (ret == 1) {
213 if (WinIsWindow((HAB)0, StubbyScan->hwndCnr)) {
[1308]214 WinSendMsg(StubbyScan->hwndCnr,
215 CM_INVALIDATERECORD,
216 MPFROMP(&StubbyScan->pci),
[1347]217 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
[1354]218 if (fRScanLocal) {
219 if (!(driveflags[toupper(*StubbyScan->pci->pszFileName) - 'A'] &
220 ((fRScanNoWrite ? 0 : DRIVE_NOTWRITEABLE) |
221 (fRScanRemote ? 0 : DRIVE_REMOTE) |
222 (fRScanSlow ? 0 : DRIVE_SLOW) |
223 (fRScanVirtual ? 0 : DRIVE_VIRTUAL)))
224 && fInitialDriveScan) {
225 WinSendMsg(StubbyScan->hwndCnr, CM_EXPANDTREE, MPFROMP(StubbyScan->pci), MPVOID);
226 //DbgMsg(pszSrcFile, __LINE__, "expanded %x %s", StubbyScan->hwndCnr, StubbyScan->pci->pszFileName);
227 WinSendMsg(StubbyScan->hwndCnr, CM_COLLAPSETREE, MPFROMP(StubbyScan->pci), MPVOID);
228 }
229 }
230 else if ((fRScanRemote && (driveflags[toupper(*StubbyScan->pci->pszFileName) - 'A'] &
231 DRIVE_REMOTE)) ||
232 (fRScanVirtual && (driveflags[toupper(*StubbyScan->pci->pszFileName) - 'A'] &
233 DRIVE_VIRTUAL)) && fInitialDriveScan) {
234 if (!(driveflags[toupper(*StubbyScan->pci->pszFileName) - 'A'] &
235 ((fRScanNoWrite ? NULL : DRIVE_NOTWRITEABLE) |
236 (fRScanSlow ? NULL : DRIVE_SLOW)))) {
237 WinSendMsg(StubbyScan->hwndCnr, CM_EXPANDTREE, MPFROMP(StubbyScan->pci), MPVOID);
238 //DbgMsg(pszSrcFile, __LINE__, "expanded %x %s", StubbyScan->hwndCnr, StubbyScan->pci->pszFileName);
239 WinSendMsg(StubbyScan->hwndCnr, CM_COLLAPSETREE, MPFROMP(StubbyScan->pci), MPVOID);
240 }
241 }
[1347]242 }
[1354]243 }
[1308]244 if (WinIsWindow((HAB)0, StubbyScan->hwndDrivesList)) {
245 WinSendMsg(StubbyScan->hwndDrivesList,
246 LM_INSERTITEM,
247 MPFROM2SHORT(LIT_SORTASCENDING, 0),
248 MPFROMP(StubbyScan->pci->pszFileName));
[1335]249 }
250 StubbyScanCount--;
[1354]251 /* if (StubbyScanCount == 0) {
252 if (fInitialDriveScan) {
253 WinShowWindow(StubbyScan->hwndCnr, TRUE);
254 WinShowWindow(StubbyScan->hwndDrivesList, TRUE);
255 }
256 fInitialDriveScan = FALSE;
257 }*/
[1308]258 WinDestroyMsgQueue(hmq);
[1299]259 }
260 DecrThreadUsage();
261 WinTerminate(thab);
262 }
263 free(StubbyScan);
264 } // if StubbyScan
265# ifdef FORTIFY
266 Fortify_LeaveScope();
267# endif
268
[1335]269 // _endthread(); // 10 Dec 08 SHL
[1299]270}
271
[1354]272VOID ProcessDirectoryThread(VOID * arg)
273{
274 PROCESSDIR *ProcessDir;
275 HAB thab;
276 HMQ hmq = (HMQ) 0;
277 //BOOL ret;
278
279 DosError(FERR_DISABLEHARDERR);
280
281# ifdef FORTIFY
282 Fortify_EnterScope();
283# endif
284
285 ProcessDir = (PROCESSDIR *)arg;
286 if (ProcessDir && ProcessDir->pciParent && ProcessDir->pciParent->pszFileName && ProcessDir->hwndCnr) {
287 thab = WinInitialize(0);
288 if (thab) {
289 hmq = WinCreateMsgQueue(thab, 0);
290 if (hmq) {
291 ProcessDirCount ++;
292 IncrThreadUsage();
293 priority_normal();
294 ProcessDirectory(ProcessDir->hwndCnr,
295 ProcessDir->pciParent,
296 ProcessDir->szDirBase,
297 ProcessDir->filestoo,
298 ProcessDir->recurse,
299 ProcessDir->partial,
300 ProcessDir->stopflag,
301 ProcessDir->dcd, // Optional
302 ProcessDir->pulTotalFiles, // Optional
303 ProcessDir->pullTotalBytes); // Optional
304 ProcessDirCount --;
305 WinDestroyMsgQueue(hmq);
306 }
307 DecrThreadUsage();
308 WinTerminate(thab);
309 }
310 free(ProcessDir);
311 } // if ProcessDir
312# ifdef FORTIFY
313 Fortify_LeaveScope();
314# endif
315
316 // _endthread(); // 10 Dec 08 SHL
317}
318
[214]319static HPOINTER IDFile(PSZ p)
[90]320{
[2]321 HPOINTER hptr;
[551]322 ULONG cmp;
[572]323 CHAR cmps[5];
[2]324
[551]325 p = strrchr(p, '.');
[572]326 if (p && !p[5]) {
[214]327 cmps[0] = '.';
328 cmps[1] = toupper(p[1]);
329 cmps[2] = toupper(p[2]);
330 cmps[3] = toupper(p[3]);
[572]331 cmps[4] = toupper(p[4]);
[214]332
[551]333 cmp = *(ULONG *) cmps;
[214]334
[551]335 if (cmp == *(ULONG *) ".EXE" || cmp == *(ULONG *) ".CMD" ||
336 cmp == *(ULONG *) ".BAT" || cmp == *(ULONG *) ".COM")
[214]337 hptr = hptrApp;
[551]338 else if (cmp == *(ULONG *) ".ZIP" || cmp == *(ULONG *) ".LZH" ||
339 cmp == *(ULONG *) ".ARJ" || cmp == *(ULONG *) ".ARC" ||
[552]340 cmp == *(ULONG *) ".ZOO" || cmp == *(ULONG *) ".RAR" ||
341 cmp == *(ULONG *) ".TAR" || cmp == *(ULONG *) ".TGZ" ||
342 cmp == *(ULONG *) ".GZ" || cmp == *(ULONG *) ".Z" ||
343 cmp == *(ULONG *) ".CAB" || cmp == *(ULONG *) ".BZ2")
[214]344 hptr = hptrArc;
[551]345 else if (cmp == *(ULONG *) ".BMP" || cmp == *(ULONG *) ".ICO" ||
346 cmp == *(ULONG *) ".PTR" || cmp == *(ULONG *) ".GIF" ||
347 cmp == *(ULONG *) ".TIF" || cmp == *(ULONG *) ".PCX" ||
[552]348 cmp == *(ULONG *) ".TGA" || cmp == *(ULONG *) ".XBM" ||
349 cmp == *(ULONG *) ".JPEG" || cmp == *(ULONG *) ".JPG" ||
350 cmp == *(ULONG *) ".PNG" || cmp == *(ULONG *) ".PSD" ||
351 cmp == *(ULONG *) ".LGO" || cmp == *(ULONG *) ".EPS" ||
352 cmp == *(ULONG *) ".RLE" || cmp == *(ULONG *) ".RAS" ||
353 cmp == *(ULONG *) ".PLC" || cmp == *(ULONG *) ".MSP" ||
354 cmp == *(ULONG *) ".IFF" || cmp == *(ULONG *) ".FIT" ||
355 cmp == *(ULONG *) ".DCX" || cmp == *(ULONG *) ".MAC" ||
356 cmp == *(ULONG *) ".SFF" || cmp == *(ULONG *) ".SGI" ||
357 cmp == *(ULONG *) ".XWD" || cmp == *(ULONG *) ".XPM" ||
358 cmp == *(ULONG *) ".WPG" || cmp == *(ULONG *) ".CUR" ||
359 cmp == *(ULONG *) ".PNM" || cmp == *(ULONG *) ".PPM" ||
360 cmp == *(ULONG *) ".PGM" || cmp == *(ULONG *) ".PBM")
[214]361 hptr = hptrArt;
362 else
[551]363 hptr = (HPOINTER) 0;
[214]364 }
365 else
[551]366 hptr = (HPOINTER) 0;
[214]367
[2]368 return hptr;
369}
370
[214]371static BOOL IsDefaultIcon(HPOINTER hptr)
372{
373 HPOINTER hptr2;
374 HPOINTER hptr3;
375 UINT u;
376
377 static HPOINTER hptrPMFile;
378 static HPOINTER hptrWPSFile;
379
[551]380 if (!hptrPMFile) {
381 hptrPMFile = WinQuerySysPointer(HWND_DESKTOP, SPTR_FILE, FALSE);
[214]382 }
383
384 // try to guess WPS default file icon
[551]385 hptr2 = (HPOINTER) 0;
386 for (u = 0; !hptrWPSFile && u < 10; u++) {
[214]387 char szFileName[CCHMAXPATH];
388 char *psz;
389
[1076]390 if (pTmpDir) {
[1069]391 psz = pTmpDir;
[214]392 strcpy(szFileName, psz);
393 psz = szFileName + strlen(szFileName) - 1;
[551]394 if (*psz != '\\') {
[214]395 psz++;
396 *psz++ = '\\';
397 }
398 }
399 else
400 psz = szFileName;
401
[551]402 sprintf(psz, "%08x.%03x", rand() & 0xffffffff, rand() & 0xfff);
403 if (IsFile(szFileName) != 1) {
404 FILE *fp = fopen(szFileName, "w");
405
406 if (fp) {
[214]407 fclose(fp);
408 hptr3 = WinLoadFileIcon(szFileName, FALSE);
409 unlinkf("%s", szFileName);
410 if (!hptr2)
411 hptr2 = hptr3;
[551]412 else if (hptr3 == hptr3) {
[214]413 hptrWPSFile = hptr3; // Got same icon twice
414 break;
415 }
416 }
417 }
418 DosSleep(rand() % 100);
419
[731]420 } // for
[214]421
422 return hptr == hptrPMFile || hptr == hptrWPSFile;
423
[731]424} // IsDefaultIcon
[214]425
[731]426ULONGLONG FillInRecordFromFFB(HWND hwndCnr,
427 PCNRITEM pci,
[551]428 const PSZ pszDirectory,
[841]429 const PFILEFINDBUF4L pffb,
[731]430 const BOOL partial,
[737]431 DIRCNRDATA *dcd)
[31]432{
[841]433 // fill in a container record from a FILEFINDBUF4L structure
[2]434
[551]435 CHAR *p;
436 HPOINTER hptr;
[1326]437 ULONG flags;
[2]438
439 pci->hwndCnr = hwndCnr;
[731]440
441 /* note that we cheat below, and accept the full pathname in pszDirectory
442 if !*pffb->achName. This speeds up and simplifies processing elsewhere
[167]443 (like in update.c)
[551]444 */
[763]445 if (!*pffb->achName) {
[773]446 pci->pszFileName = xstrdup(pszDirectory, pszSrcFile, __LINE__);
[1018]447 //strcpy(pci->pszFileName, pszDirectory);
[763]448 }
[731]449 else {
450 INT c = strlen(pszDirectory);
451 INT c2 = pffb->cchName + 1;
452 if (pszDirectory[c - 1] != '\\')
453 c2++;
[773]454 pci->pszFileName = xmalloc(c + c2, pszSrcFile, __LINE__);
[1078]455# ifdef FORTIFY
456 {
[1154]457 if (dcd->type != TREE_FRAME)
[1078]458 Fortify_ChangeScope(pci->pszFileName, -1);
[1154]459 else {
[1078]460 Fortify_SetOwner(pci->pszFileName, 1);
[1154]461 Fortify_SetScope(pci->pszFileName, 2);
462 }
[1078]463 }
464# endif
[731]465 memcpy(pci->pszFileName, pszDirectory, c + 1);
466 p = pci->pszFileName + c - 1;
[167]467 if (*p != '\\') {
[2]468 p++;
469 *p = '\\';
470 }
471 p++;
[551]472 memcpy(p, pffb->achName, pffb->cchName + 1);
[2]473 }
[1326]474 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
[783]475 // load the object's Subject, if required
[1326]476 // pci->pszSubject = NullStr; dubplicate see below 12-05-08 GKY
[167]477 if (pffb->cbList > 4L &&
478 dcd && fLoadSubject &&
[730]479 (isalpha(*pci->pszFileName) &&
[1326]480 !(flags & DRIVE_NOLOADSUBJS)))
[731]481 {
[551]482 APIRET rc;
483 EAOP2 eaop;
[2]484 PGEA2LIST pgealist;
485 PFEA2LIST pfealist;
[551]486 PGEA2 pgea;
487 PFEA2 pfea;
488 CHAR *value;
[2]489
[551]490 pgealist = xmallocz(sizeof(GEA2LIST) + 32, pszSrcFile, __LINE__);
[359]491 if (pgealist) {
[2]492 pgea = &pgealist->list[0];
[551]493 strcpy(pgea->szName, SUBJECT);
[2]494 pgea->cbName = strlen(pgea->szName);
[188]495 pgea->oNextEntryOffset = 0;
[2]496 pgealist->cbList = (sizeof(GEA2LIST) + pgea->cbName);
[551]497 pfealist = xmallocz(1532, pszSrcFile, __LINE__);
[359]498 if (pfealist) {
[214]499 pfealist->cbList = 1024;
500 eaop.fpGEA2List = pgealist;
501 eaop.fpFEA2List = pfealist;
502 eaop.oError = 0;
[730]503 rc = DosQueryPathInfo(pci->pszFileName, FIL_QUERYEASFROMLIST,
[551]504 (PVOID) & eaop, (ULONG) sizeof(EAOP2));
[214]505 if (!rc) {
506 pfea = &eaop.fpFEA2List->list[0];
507 value = pfea->szName + pfea->cbName + 1;
508 value[pfea->cbValue] = 0;
[551]509 if (*(USHORT *) value == EAT_ASCII)
[730]510 pci->pszSubject = xstrdup(value + (sizeof(USHORT) * 2), pszSrcFile, __LINE__);
[214]511 }
[1039]512 free(pfealist);
[2]513 }
[1039]514 free(pgealist);
[2]515 }
516 }
[731]517 if (!pci->pszSubject)
[751]518 pci->pszSubject = NullStr;
[731]519
[783]520 // load the object's longname
[1063]521 pci->pszLongName = NULL;
[282]522 if (fLoadLongnames &&
523 dcd &&
524 pffb->cbList > 4L &&
[730]525 isalpha(*pci->pszFileName) &&
[1326]526 ~flags & DRIVE_NOLONGNAMES &&
527 ~flags & DRIVE_NOLOADLONGS)
[731]528 {
[551]529 APIRET rc;
530 EAOP2 eaop;
[2]531 PGEA2LIST pgealist;
532 PFEA2LIST pfealist;
[551]533 PGEA2 pgea;
534 PFEA2 pfea;
535 CHAR *value;
[2]536
[551]537 pgealist = xmallocz(sizeof(GEA2LIST) + 32, pszSrcFile, __LINE__);
[359]538 if (pgealist) {
[2]539 pgea = &pgealist->list[0];
[551]540 strcpy(pgea->szName, LONGNAME);
[2]541 pgea->cbName = strlen(pgea->szName);
[188]542 pgea->oNextEntryOffset = 0;
[2]543 pgealist->cbList = (sizeof(GEA2LIST) + pgea->cbName);
[551]544 pfealist = xmallocz(1532, pszSrcFile, __LINE__);
[167]545 if (pfealist) {
[214]546 pfealist->cbList = 1024;
547 eaop.fpGEA2List = pgealist;
548 eaop.fpFEA2List = pfealist;
549 eaop.oError = 0;
[730]550 rc = DosQueryPathInfo(pci->pszFileName, FIL_QUERYEASFROMLIST,
[551]551 (PVOID) & eaop, (ULONG) sizeof(EAOP2));
552 if (!rc) {
[214]553 pfea = &eaop.fpFEA2List->list[0];
554 value = pfea->szName + pfea->cbName + 1;
555 value[pfea->cbValue] = 0;
[1078]556 if (*(USHORT *) value == EAT_ASCII) {
[762]557 pci->pszLongName = xstrdup(value + (sizeof(USHORT) * 2), pszSrcFile, __LINE__);
[1078]558# ifdef FORTIFY
[1154]559 {
560 unsigned tid = GetTidForWindow(hwndCnr);
561 if (tid == 1)
562 Fortify_ChangeScope(pci->pszLongName, -1);
563 else
564 Fortify_SetOwner(pci->pszLongName, 1);
565 }
[1078]566# endif
567 }
[214]568 }
[1039]569 free(pfealist);
[2]570 }
[1039]571 free(pgealist);
[2]572 }
573 }
[762]574 if (!pci->pszLongName)
575 pci->pszLongName = NullStr;
[731]576
[783]577 // do anything required to case of filename
[167]578 if (fForceUpper)
[730]579 strupr(pci->pszFileName);
[167]580 else if (fForceLower)
[730]581 strlwr(pci->pszFileName);
[2]582
[783]583 // get an icon to use with it
[551]584 if (pffb->attrFile & FILE_DIRECTORY) {
[214]585 // is directory
586 if (fNoIconsDirs ||
[1326]587 (flags & DRIVE_NOLOADICONS) ||
[730]588 !isalpha(*pci->pszFileName)) {
[551]589 hptr = (HPOINTER) 0;
[214]590 }
591 else
[730]592 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
[2]593 }
[551]594 else {
[214]595 // is file
596 if (fNoIconsFiles ||
[1326]597 (flags & DRIVE_NOLOADICONS) ||
[730]598 !isalpha(*pci->pszFileName)) {
[551]599 hptr = (HPOINTER) 0;
[167]600 }
[42]601 else
[730]602 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
[167]603
[214]604 if (!hptr || IsDefaultIcon(hptr))
[730]605 hptr = IDFile(pci->pszFileName);
[2]606 }
[214]607
[551]608 if (!hptr) {
[214]609 hptr = pffb->attrFile & FILE_DIRECTORY ?
[1335]610 hptrDir : pffb->attrFile & FILE_SYSTEM ?
611 hptrSystem : pffb->attrFile & FILE_HIDDEN ?
612 hptrHidden : pffb->attrFile & FILE_READONLY ?
[1326]613 hptrReadonly : hptrFile;
[167]614 }
[2]615
[737]616 // Tell container what part of pathname to display
[551]617 if (partial) {
[730]618 p = strrchr(pci->pszFileName, '\\');
[551]619 if (!p) {
[730]620 p = strrchr(pci->pszFileName, ':');
[167]621 if (!p)
[730]622 p = pci->pszFileName;
[2]623 else
[214]624 p++;
[2]625 }
[167]626 else if ((dcd && dcd->type == TREE_FRAME) ||
[551]627 (!(pffb->attrFile & FILE_DIRECTORY) || !*(p + 1))) {
[2]628 p++;
[167]629 }
630 if (!*p)
[730]631 p = pci->pszFileName;
[2]632 }
633 else
[730]634 p = pci->pszFileName;
[737]635 pci->pszDisplayName = p;
636
[856]637 //comma format the file size for large file support
[859]638 {
[1078]639 CHAR szBuf[30];
[856]640 CommaFmtULL(szBuf, sizeof(szBuf), pffb->cbFile, ' ');
641 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
[1078]642# ifdef FORTIFY
643 {
644 unsigned tid = GetTidForWindow(hwndCnr);
645 if (tid == 1)
646 Fortify_ChangeScope(pci->pszFmtFileSize, -1);
647 else
648 Fortify_SetOwner(pci->pszFmtFileSize, 1);
649 }
650# endif
[856]651 }
652
[783]653 // now fill the darned thing in...
[551]654 pci->date.day = pffb->fdateLastWrite.day;
655 pci->date.month = pffb->fdateLastWrite.month;
656 pci->date.year = pffb->fdateLastWrite.year + 1980;
657 pci->time.seconds = pffb->ftimeLastWrite.twosecs * 2;
658 pci->time.minutes = pffb->ftimeLastWrite.minutes;
659 pci->time.hours = pffb->ftimeLastWrite.hours;
660 pci->ladate.day = pffb->fdateLastAccess.day;
661 pci->ladate.month = pffb->fdateLastAccess.month;
662 pci->ladate.year = pffb->fdateLastAccess.year + 1980;
[2]663 pci->latime.seconds = pffb->ftimeLastAccess.twosecs * 2;
664 pci->latime.minutes = pffb->ftimeLastAccess.minutes;
[551]665 pci->latime.hours = pffb->ftimeLastAccess.hours;
666 pci->crdate.day = pffb->fdateCreation.day;
667 pci->crdate.month = pffb->fdateCreation.month;
668 pci->crdate.year = pffb->fdateCreation.year + 1980;
[2]669 pci->crtime.seconds = pffb->ftimeCreation.twosecs * 2;
670 pci->crtime.minutes = pffb->ftimeCreation.minutes;
[551]671 pci->crtime.hours = pffb->ftimeCreation.hours;
672 pci->easize = CBLIST_TO_EASIZE(pffb->cbList);
673 pci->cbFile = pffb->cbFile;
674 pci->attrFile = pffb->attrFile;
[751]675 pci->pszDispAttr = FileAttrToString(pci->attrFile);
[739]676 pci->rc.pszIcon = pci->pszDisplayName;
[551]677 pci->rc.hptrIcon = hptr;
[2]678
[783]679 // check to see if record should be visible
[167]680 if (dcd && (*dcd->mask.szMask || dcd->mask.antiattr ||
[551]681 ((dcd->mask.attrFile &
682 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED))
683 !=
684 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED))))
[167]685 {
[551]686 if (*dcd->mask.szMask || dcd->mask.antiattr) {
687 if (!Filter((PMINIRECORDCORE) pci, (PVOID) & dcd->mask))
[214]688 pci->rc.flRecordAttr |= CRA_FILTERED;
[2]689 }
[551]690 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
691 (pci->attrFile & FILE_HIDDEN)) ||
692 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
693 (pci->attrFile & FILE_SYSTEM)) ||
694 (!(dcd->mask.attrFile & FILE_READONLY) &&
695 (pci->attrFile & FILE_READONLY)) ||
696 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
697 (pci->attrFile & FILE_ARCHIVED))) {
[2]698 pci->rc.flRecordAttr |= CRA_FILTERED;
[167]699 }
[2]700 }
701
702 return pffb->cbFile + pci->easize;
703
[731]704} // FillInRecordFromFFB
[2]705
[1154]706ULONGLONG FillInRecordFromFSA(HWND hwndCnr,
707 PCNRITEM pci,
[907]708 const PSZ pszFileName,
709 const PFILESTATUS4L pfsa4,
[1154]710 const BOOL partial,
711 DIRCNRDATA *dcd) // Optional
[31]712{
[551]713 HPOINTER hptr;
[731]714 CHAR *p;
[1326]715 ULONG flags;
[2]716
[841]717 // fill in a container record from a FILESTATUS4L structure
[2]718
719 pci->hwndCnr = hwndCnr;
[773]720 pci->pszFileName = xstrdup(pszFileName, pszSrcFile, __LINE__);
[1099]721 //strcpy(pci->pszFileName, pszFileName);
[1326]722 flags = driveflags[toupper(*pci->pszFileName) - 'A'];
[783]723 // load the object's Subject, if required
[1326]724 //pci->pszSubject = NullStr;
[841]725 if (pfsa4->cbList > 4 &&
[167]726 dcd &&
727 fLoadSubject &&
[730]728 (!isalpha(*pci->pszFileName) ||
[1326]729 !(flags & DRIVE_NOLOADSUBJS)))
[731]730 {
[551]731 APIRET rc;
732 EAOP2 eaop;
[2]733 PGEA2LIST pgealist;
734 PFEA2LIST pfealist;
[551]735 PGEA2 pgea;
736 PFEA2 pfea;
737 CHAR *value;
[2]738
[551]739 pgealist = xmallocz(sizeof(GEA2LIST) + 32, pszSrcFile, __LINE__);
[167]740 if (pgealist) {
[2]741 pgea = &pgealist->list[0];
[551]742 strcpy(pgea->szName, SUBJECT);
[2]743 pgea->cbName = strlen(pgea->szName);
[188]744 pgea->oNextEntryOffset = 0;
[2]745 pgealist->cbList = (sizeof(GEA2LIST) + pgea->cbName);
[551]746 pfealist = xmallocz(1532, pszSrcFile, __LINE__);
[167]747 if (pfealist) {
[214]748 pfealist->cbList = 1024;
749 eaop.fpGEA2List = pgealist;
750 eaop.fpFEA2List = pfealist;
751 eaop.oError = 0;
[730]752 rc = DosQueryPathInfo(pci->pszFileName, FIL_QUERYEASFROMLIST,
[551]753 (PVOID) & eaop, (ULONG) sizeof(EAOP2));
[214]754 if (!rc) {
755 pfea = &eaop.fpFEA2List->list[0];
756 value = pfea->szName + pfea->cbName + 1;
757 value[pfea->cbValue] = 0;
[551]758 if (*(USHORT *) value == EAT_ASCII)
[731]759 pci->pszSubject = xstrdup(value + (sizeof(USHORT) * 2), pszSrcFile, __LINE__);
[214]760 }
[1039]761 free(pfealist);
[2]762 }
[1039]763 free(pgealist);
[2]764 }
765 }
[731]766 if (!pci->pszSubject)
[751]767 pci->pszSubject = NullStr;
[731]768
[1063]769 pci->pszLongName = NULL;
[282]770 if (fLoadLongnames &&
[167]771 dcd &&
[282]772 pfsa4->cbList > 4L &&
[730]773 isalpha(*pci->pszFileName) &&
[1326]774 ~flags & DRIVE_NOLONGNAMES &&
775 ~flags & DRIVE_NOLOADLONGS)
[731]776 {
[551]777 APIRET rc;
778 EAOP2 eaop;
[2]779 PGEA2LIST pgealist;
780 PFEA2LIST pfealist;
[551]781 PGEA2 pgea;
782 PFEA2 pfea;
783 CHAR *value;
[2]784
[551]785 pgealist = xmallocz(sizeof(GEA2LIST) + 32, pszSrcFile, __LINE__);
[167]786 if (pgealist) {
[2]787 pgea = &pgealist->list[0];
[551]788 strcpy(pgea->szName, LONGNAME);
[2]789 pgea->cbName = strlen(pgea->szName);
[188]790 pgea->oNextEntryOffset = 0;
[2]791 pgealist->cbList = (sizeof(GEA2LIST) + pgea->cbName);
[551]792 pfealist = xmallocz(1532, pszSrcFile, __LINE__);
[167]793 if (pfealist) {
[214]794 pfealist->cbList = 1024;
795 eaop.fpGEA2List = pgealist;
796 eaop.fpFEA2List = pfealist;
797 eaop.oError = 0;
[730]798 rc = DosQueryPathInfo(pci->pszFileName, FIL_QUERYEASFROMLIST,
[551]799 (PVOID) & eaop, (ULONG) sizeof(EAOP2));
[214]800 if (!rc) {
801 pfea = &eaop.fpFEA2List->list[0];
[731]802 value = pfea->szName + pfea->cbName + 1; // Point at EA value
[1174]803 value[pfea->cbValue] = 0; // Terminate
[731]804 if (*(USHORT *) value == EAT_ASCII) {
[1174]805 p = value + sizeof(USHORT) * 2; // Point at value string
[762]806 pci->pszLongName = xstrdup(p, pszSrcFile, __LINE__);
[731]807 }
[214]808 }
[1039]809 free(pfealist);
[2]810 }
[1039]811 free(pgealist);
[2]812 }
813 }
[762]814 if (!pci->pszLongName)
815 pci->pszLongName = NullStr;
[731]816
[167]817 if (fForceUpper)
[730]818 strupr(pci->pszFileName);
[167]819 else if (fForceLower)
[730]820 strlwr(pci->pszFileName);
[2]821
[551]822 if (pfsa4->attrFile & FILE_DIRECTORY) {
[214]823 if (fNoIconsDirs ||
[1326]824 (flags & DRIVE_NOLOADICONS) ||
[730]825 !isalpha(*pci->pszFileName)) {
[551]826 hptr = (HPOINTER) 0;
[214]827 }
828 else
[730]829 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
[2]830 }
[551]831 else {
[214]832 if (fNoIconsFiles ||
[1326]833 (flags & DRIVE_NOLOADICONS) ||
[730]834 !isalpha(*pci->pszFileName)) {
835 hptr = IDFile(pci->pszFileName);
[2]836 }
[214]837 else
[730]838 hptr = WinLoadFileIcon(pci->pszFileName, FALSE);
[2]839 }
[551]840 if (!hptr) {
[214]841 hptr = pfsa4->attrFile & FILE_DIRECTORY ?
[551]842 hptrDir :
843 pfsa4->attrFile & FILE_SYSTEM ?
844 hptrSystem :
845 pfsa4->attrFile & FILE_HIDDEN ?
846 hptrHidden : pfsa4->attrFile & FILE_READONLY ? hptrReadonly : hptrFile;
[214]847 }
[2]848
[737]849 // Tell container what part of pathname to display
[551]850 if (partial) {
[730]851 p = strrchr(pci->pszFileName, '\\');
[167]852 if (!p) {
[730]853 p = strrchr(pci->pszFileName, ':');
[167]854 if (!p)
[730]855 p = pci->pszFileName;
[2]856 else
[214]857 p++;
[2]858 }
[167]859 else if ((dcd && dcd->type == TREE_FRAME) ||
[551]860 !(pfsa4->attrFile & FILE_DIRECTORY) || !*(p + 1))
[2]861 p++;
[167]862 if (!*p)
[730]863 p = pci->pszFileName;
[2]864 }
865 else
[730]866 p = pci->pszFileName;
[737]867 pci->pszDisplayName = p;
868
[856]869 //comma format the file size for large file support
[859]870 {
[1154]871 CHAR szBuf[30];
[856]872 CommaFmtULL(szBuf, sizeof(szBuf), pfsa4->cbFile, ' ');
873 pci->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
[1154]874# ifdef FORTIFY
875 {
876 if (dcd && dcd->type == TREE_FRAME) {
877 // Will be freed in TreeCnrWndProc WM_DESTROY
878 // Fortify_SetOwner(pci->pszFmtFileSize, 1);
879 Fortify_SetScope(pci->pszFmtFileSize, 2);
880 }
881 }
882# endif
[856]883 }
[551]884 pci->date.day = pfsa4->fdateLastWrite.day;
885 pci->date.month = pfsa4->fdateLastWrite.month;
886 pci->date.year = pfsa4->fdateLastWrite.year + 1980;
887 pci->time.seconds = pfsa4->ftimeLastWrite.twosecs * 2;
888 pci->time.minutes = pfsa4->ftimeLastWrite.minutes;
889 pci->time.hours = pfsa4->ftimeLastWrite.hours;
890 pci->ladate.day = pfsa4->fdateLastAccess.day;
891 pci->ladate.month = pfsa4->fdateLastAccess.month;
892 pci->ladate.year = pfsa4->fdateLastAccess.year + 1980;
[2]893 pci->latime.seconds = pfsa4->ftimeLastAccess.twosecs * 2;
894 pci->latime.minutes = pfsa4->ftimeLastAccess.minutes;
[551]895 pci->latime.hours = pfsa4->ftimeLastAccess.hours;
896 pci->crdate.day = pfsa4->fdateCreation.day;
897 pci->crdate.month = pfsa4->fdateCreation.month;
898 pci->crdate.year = pfsa4->fdateCreation.year + 1980;
[2]899 pci->crtime.seconds = pfsa4->ftimeCreation.twosecs * 2;
900 pci->crtime.minutes = pfsa4->ftimeCreation.minutes;
[551]901 pci->crtime.hours = pfsa4->ftimeCreation.hours;
902 pci->easize = CBLIST_TO_EASIZE(pfsa4->cbList);
903 pci->cbFile = pfsa4->cbFile;
904 pci->attrFile = pfsa4->attrFile;
[751]905 pci->pszDispAttr = FileAttrToString(pci->attrFile);
[739]906 pci->rc.pszIcon = pci->pszDisplayName;
[551]907 pci->rc.hptrIcon = hptr;
[2]908
[167]909 if (dcd &&
910 (*dcd->mask.szMask || dcd->mask.antiattr ||
911 ((dcd->mask.attrFile &
[551]912 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)) !=
913 (FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_ARCHIVED)))) {
914 if (*dcd->mask.szMask || dcd->mask.antiattr) {
915 if (!Filter((PMINIRECORDCORE) pci, (PVOID) & dcd->mask))
[214]916 pci->rc.flRecordAttr |= CRA_FILTERED;
[2]917 }
[167]918 else if ((!(dcd->mask.attrFile & FILE_HIDDEN) &&
[214]919 (pci->attrFile & FILE_HIDDEN)) ||
920 (!(dcd->mask.attrFile & FILE_SYSTEM) &&
921 (pci->attrFile & FILE_SYSTEM)) ||
922 (!(dcd->mask.attrFile & FILE_READONLY) &&
923 (pci->attrFile & FILE_READONLY)) ||
924 (!(dcd->mask.attrFile & FILE_ARCHIVED) &&
925 (pci->attrFile & FILE_ARCHIVED)))
[2]926 pci->rc.flRecordAttr |= CRA_FILTERED;
927 }
928
929 return pfsa4->cbFile + pci->easize;
930
[731]931} // FillInRecordFromFSA
[2]932
[737]933VOID ProcessDirectory(const HWND hwndCnr,
934 const PCNRITEM pciParent,
935 const CHAR *szDirBase,
936 const BOOL filestoo,
937 const BOOL recurse,
938 const BOOL partial,
939 CHAR *stopflag,
940 DIRCNRDATA *dcd, // Optional
941 ULONG *pulTotalFiles, // Optional
[167]942 PULONGLONG pullTotalBytes) // Optional
[31]943{
[2]944 /* put all the directories (and files if filestoo is TRUE) from a
945 * directory into the container. recurse through subdirectories if
946 * recurse is TRUE.
947 */
948
[551]949 PSZ pszFileSpec;
950 INT t;
[841]951 PFILEFINDBUF4L paffbFound;
952 PFILEFINDBUF4L *papffbSelected;
953 PFILEFINDBUF4L pffbFile;
954 PFILEFINDBUF4L paffbTotal = NULL;
955 PFILEFINDBUF4L paffbTemp;
[551]956 HDIR hdir = HDIR_CREATE;
[783]957 ULONG ulFindCnt;
958 ULONG ulFindMax;
959 ULONG ulSelCnt;
[551]960 ULONG ulTotal = 0;
961 ULONGLONG ullBytes;
962 ULONGLONG ullTotalBytes;
963 ULONG ulReturnFiles = 0;
964 ULONGLONG ullReturnBytes = 0;
965 PCH pchEndPath;
966 APIRET rc;
967 PCNRITEM pci;
968 PCNRITEM pciFirst;
969 RECORDINSERT ri;
970 BOOL ok = TRUE;
[783]971 ULONG ulBufBytes;
972 ULONG x;
[2]973
[551]974 if (isalpha(*szDirBase) && szDirBase[1] == ':' && szDirBase[2] == '\\') {
[167]975 if ((driveflags[toupper(*szDirBase) - 'A'] & DRIVE_REMOTE) && fRemoteBug)
[1174]976 ulFindMax = 1; // file system gets confused
[167]977 else if (driveflags[toupper(*szDirBase) - 'A'] & DRIVE_ZIPSTREAM)
[783]978 ulFindMax = min(FilesToGet, 225); // anything more is wasted
[2]979 else
[783]980 ulFindMax = FilesToGet; // full-out
[2]981 }
[924]982 else
[783]983 ulFindMax = FilesToGet;
[924]984
[167]985 if (OS2ver[0] == 20 && OS2ver[1] < 30)
[841]986 ulFindMax = min(ulFindMax, (65535 / sizeof(FILEFINDBUF4L)));
[2]987
[841]988 ulBufBytes = ulFindMax * sizeof(FILEFINDBUF4L);
[783]989
[551]990 pszFileSpec = xmalloc(CCHMAXPATH + 2, pszSrcFile, __LINE__);
[783]991 paffbFound = xmalloc(ulBufBytes, pszSrcFile, __LINE__);
[841]992 papffbSelected = xmalloc(sizeof(PFILEFINDBUF4L) * ulFindMax, pszSrcFile, __LINE__);
[783]993
[167]994 if (paffbFound && papffbSelected && pszFileSpec) {
[2]995 t = strlen(szDirBase);
[551]996 memcpy(pszFileSpec, szDirBase, t + 1);
[42]997 pchEndPath = pszFileSpec + t;
[167]998 if (*(pchEndPath - 1) != '\\') {
[551]999 memcpy(pchEndPath, "\\", 2);
[2]1000 pchEndPath++;
1001 }
[551]1002 memcpy(pchEndPath, "*", 2);
[2]1003 DosError(FERR_DISABLEHARDERR);
[783]1004 ulFindCnt = ulFindMax;
[838]1005 rc = xDosFindFirst(pszFileSpec,
1006 &hdir,
1007 FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
1008 FILE_SYSTEM | FILE_HIDDEN |
1009 (filestoo ? FILE_DIRECTORY : MUST_HAVE_DIRECTORY),
1010 paffbFound,
1011 ulBufBytes,
1012 &ulFindCnt,
[841]1013 FIL_QUERYEASIZEL);
[2]1014 priority_normal();
[924]1015 *pchEndPath = 0; // Chop off wildcard
[551]1016 if (!rc) {
[783]1017 do {
[214]1018 /*
1019 * remove . and .. from list if present
1020 * also counter file system bugs that sometimes
1021 * allows normal files to slip through when
1022 * only directories should appear (only a few
1023 * network file systems exhibit such a problem).
1024 */
[2]1025
[214]1026 if (stopflag && *stopflag)
1027 goto Abort;
[783]1028 pffbFile = paffbFound;
1029 ulSelCnt = 0;
1030 for (;;) {
[214]1031 if (!*pffbFile->achName ||
[783]1032 (!filestoo && ~pffbFile->attrFile & FILE_DIRECTORY) ||
1033 (pffbFile->attrFile & FILE_DIRECTORY &&
[534]1034 pffbFile->achName[0] == '.' &&
1035 (!pffbFile->achName[1] ||
[551]1036 (pffbFile->achName[1] == '.' && !pffbFile->achName[2])))) {
[783]1037 // ulFindCnt--; // Got . or .. or file to be skipped
[174]1038 }
[214]1039 else
[783]1040 papffbSelected[ulSelCnt++] = pffbFile; // Remember selected file
[551]1041 if (!pffbFile->oNextEntryOffset) {
[783]1042 // ulFindCnt = ulSelCnt; // Remember number selected
[214]1043 break;
1044 }
[841]1045 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + pffbFile->oNextEntryOffset);
[763]1046 } // for
[783]1047 if (ulSelCnt) {
1048 // One or more entries selected
[214]1049 if (stopflag && *stopflag)
1050 goto Abort;
[1335]1051 if (fSyncUpdates) {
[214]1052 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
[783]1053 MPFROMLONG(EXTRA_RECORD_BYTES),
1054 MPFROMLONG(ulSelCnt));
[359]1055 if (!pciFirst) {
[551]1056 Win_Error2(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1057 IDS_CMALLOCRECERRTEXT);
[359]1058 ok = FALSE;
1059 ullTotalBytes = 0;
1060 }
1061 else {
[907]1062 // 04 Jan 08 SHL fixme like comp.c to handle less than ulSelCnt records
[214]1063 pci = pciFirst;
1064 ullTotalBytes = 0;
[783]1065 // Insert selected in container
1066 for (x = 0; x < ulSelCnt; x++) {
1067 pffbFile = papffbSelected[x];
[551]1068 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1069 pffbFile, partial, dcd);
1070 pci = (PCNRITEM) pci->rc.preccNextRecord;
[214]1071 ullTotalBytes += ullBytes;
[731]1072 } // for
[783]1073 memset(&ri, 0, sizeof(RECORDINSERT));
1074 ri.cb = sizeof(RECORDINSERT);
1075 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1076 ri.pRecordParent = (PRECORDCORE) pciParent;
1077 ri.zOrder = (ULONG) CMA_TOP;
1078 ri.cRecordsInsert = ulSelCnt;
[1316]1079 ri.fInvalidateRecord = TRUE;
1080 // !fSyncUpdates && dcd && dcd->type == DIR_FRAME ? FALSE : TRUE; //fSyncUpdates always TRUE 12-1-08 GKY
[783]1081 if (!WinSendMsg(hwndCnr,
1082 CM_INSERTRECORD,
1083 MPFROMP(pciFirst), MPFROMP(&ri))) {
1084 DosSleep(10); // Give GUI time to work
1085 WinSetFocus(HWND_DESKTOP, hwndCnr);
[214]1086 if (!WinSendMsg(hwndCnr,
1087 CM_INSERTRECORD,
[551]1088 MPFROMP(pciFirst), MPFROMP(&ri))) {
[783]1089 Win_Error2(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1090 IDS_CMINSERTERRTEXT);
1091 ok = FALSE;
1092 ullTotalBytes = 0;
1093 if (WinIsWindow((HAB) 0, hwndCnr))
[1335]1094 FreeCnrItemList(hwndCnr, pciFirst);
[214]1095 }
[783]1096 // }
[214]1097 }
1098 }
[551]1099 if (ok) {
[214]1100 ullReturnBytes += ullTotalBytes;
[783]1101 ulReturnFiles += ulSelCnt;
[1335]1102 }
[783]1103 } // if sync updates
[551]1104 else {
[783]1105 // Append newly selected entries to aggregate list
[359]1106 paffbTemp = xrealloc(paffbTotal,
[841]1107 sizeof(FILEFINDBUF4L) * (ulSelCnt + ulTotal),
[551]1108 pszSrcFile, __LINE__);
1109 if (paffbTemp) {
[783]1110 // 13 Aug 07 SHL fixme to optimize copy
[214]1111 paffbTotal = paffbTemp;
[783]1112 for (x = 0; x < ulSelCnt; x++)
[214]1113 paffbTotal[x + ulTotal] = *papffbSelected[x];
[783]1114 ulTotal += ulSelCnt;
[214]1115 }
[551]1116 else {
[214]1117 saymsg(MB_ENTER,
1118 HWND_DESKTOP,
[551]1119 GetPString(IDS_ERRORTEXT), GetPString(IDS_OUTOFMEMORY));
[214]1120 break;
1121 }
1122 }
[783]1123 } // if entries selected
[214]1124 if (stopflag && *stopflag)
[551]1125 goto Abort;
[214]1126 DosError(FERR_DISABLEHARDERR);
[783]1127 ulFindCnt = ulFindMax;
[850]1128 rc = xDosFindNext(hdir, paffbFound, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
[214]1129 priority_normal();
1130 if (rc)
1131 DosError(FERR_DISABLEHARDERR);
[783]1132 } while (!rc);
1133
[2]1134 DosFindClose(hdir);
[1009]1135 xfree(paffbFound, pszSrcFile, __LINE__);
[985]1136 paffbFound = NULL;
[1009]1137 xfree(papffbSelected, pszSrcFile, __LINE__);
[985]1138 papffbSelected = NULL;
[2]1139
[551]1140 if (ulTotal && paffbTotal) {
[167]1141
[214]1142 if (stopflag && *stopflag)
1143 goto Abort;
[167]1144
[214]1145 pciFirst = WinSendMsg(hwndCnr, CM_ALLOCRECORD,
[783]1146 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(ulTotal));
[359]1147 if (!pciFirst) {
[551]1148 Win_Error2(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1149 IDS_CMALLOCRECERRTEXT);
[359]1150 ok = FALSE;
1151 ullTotalBytes = 0;
1152 }
1153 else {
[907]1154 // 04 Jan 08 SHL fixme like comp.c to handle less than ulSelCnt records
[214]1155 pci = pciFirst;
1156 ullTotalBytes = 0;
[783]1157 pffbFile = paffbTotal;
1158 for (x = 0; x < ulTotal; x++) {
[551]1159 ullBytes = FillInRecordFromFFB(hwndCnr, pci, pszFileSpec,
1160 pffbFile, partial, dcd);
1161 pci = (PCNRITEM) pci->rc.preccNextRecord;
[214]1162 ullTotalBytes += ullBytes;
[783]1163 // Can not use offset since we have merged lists - this should be equivalent
[841]1164 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + sizeof(FILEFINDBUF4L));
[214]1165 }
[551]1166 if (ulTotal) {
1167 memset(&ri, 0, sizeof(RECORDINSERT));
1168 ri.cb = sizeof(RECORDINSERT);
1169 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1170 ri.pRecordParent = (PRECORDCORE) pciParent;
1171 ri.zOrder = (ULONG) CMA_TOP;
1172 ri.cRecordsInsert = ulTotal;
1173 ri.fInvalidateRecord = (!fSyncUpdates && dcd &&
1174 dcd->type == DIR_FRAME) ? FALSE : TRUE;
1175 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1176 MPFROMP(pciFirst), MPFROMP(&ri))) {
[783]1177 DosSleep(10); // Give GUI time to work
[551]1178 WinSetFocus(HWND_DESKTOP, hwndCnr);
1179 if (!WinSendMsg(hwndCnr, CM_INSERTRECORD,
1180 MPFROMP(pciFirst), MPFROMP(&ri))) {
1181 Win_Error2(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
1182 IDS_CMINSERTERRTEXT);
[214]1183 ok = FALSE;
1184 ullTotalBytes = 0;
[751]1185 if (WinIsWindow((HAB) 0, hwndCnr))
[1335]1186 FreeCnrItemList(hwndCnr, pciFirst);
[214]1187 }
1188 }
1189 }
1190 }
[551]1191 if (ok) {
[214]1192 ullReturnBytes += ullTotalBytes;
[783]1193 ulReturnFiles += ulFindCnt;
[214]1194 }
[2]1195 }
1196 }
1197
[924]1198 /**
1199 * DosFind for subdirectories of a read-only directory on a FAT volume
1200 * returns path not found if there are no subdirectories
1201 * FAT FS seems to ignore . and .. in this case
1202 * Map to no more files
1203 * We could verify that directory is marked read-only, it's probably not
1204 * worth the extra code since we do verify 2 out of 3 prerequisites
1205 * 15 Jan 08 SHL
1206 */
1207 if (rc == ERROR_PATH_NOT_FOUND && !filestoo) {
1208 ULONG ulDriveType = 0;
1209 CHAR szFSType[CCHMAXPATH];
1210 INT removable = CheckDrive(*pszFileSpec, szFSType, &ulDriveType);
1211 if (removable != -1 && strcmp(szFSType, "FAT") == 0)
1212 rc = ERROR_NO_MORE_FILES;
1213 }
1214
[783]1215 if (rc && rc != ERROR_NO_MORE_FILES) {
1216 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1217 GetPString(IDS_CANTFINDDIRTEXT), pszFileSpec);
1218 }
1219
[167]1220 if (!fSyncUpdates && dcd && dcd->type == DIR_FRAME)
[551]1221 WinSendMsg(hwndCnr, CM_INVALIDATERECORD, MPVOID,
1222 MPFROM2SHORT(0, CMA_ERASE));
[2]1223 }
1224Abort:
[1009]1225 xfree(paffbTotal, pszSrcFile, __LINE__);
1226 xfree(pszFileSpec, pszSrcFile, __LINE__);
1227 xfree(paffbFound, pszSrcFile, __LINE__);
1228 xfree(papffbSelected, pszSrcFile, __LINE__);
[783]1229
[551]1230 if (recurse) {
[2]1231 pci = WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMP(pciParent),
[214]1232 MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
[762]1233 while (pci && (INT)pci != -1) {
[1354]1234 if ((pci->attrFile & FILE_DIRECTORY))
1235 if (fInitialDriveScan)
1236 Stubby(hwndCnr, pci);
1237 else {
1238 while (StubbyScanCount != 0)
1239 DosSleep(50);
1240 Stubby(hwndCnr, pci);
1241 }
1242 //Stubby(hwndCnr, pci);
[2]1243 pci = WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMP(pci),
[214]1244 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
[2]1245 }
1246 }
1247
[167]1248 if (pulTotalFiles)
1249 *pulTotalFiles = ulReturnFiles;
[2]1250
[167]1251 if (pullTotalBytes)
1252 *pullTotalBytes = ullReturnBytes;
[2]1253
[731]1254} // ProcessDirectory
[167]1255
1256VOID FillDirCnr(HWND hwndCnr,
[551]1257 CHAR * pszDirectory,
[924]1258 DIRCNRDATA * dcd,
1259 PULONGLONG pullTotalBytes)
[90]1260{
[167]1261 ProcessDirectory(hwndCnr,
[924]1262 (PCNRITEM)NULL,
[167]1263 pszDirectory,
[737]1264 TRUE, // filestoo
1265 FALSE, // recurse
1266 TRUE, // partial
1267 dcd ? &dcd->stopflag : NULL,
1268 dcd,
[924]1269 NULL, // total files
[737]1270 pullTotalBytes);
[2]1271 DosPostEventSem(CompactSem);
1272
[762]1273#if 0 // fixme to be gone or to be configurable
[751]1274 {
1275 int state = _heapchk();
1276 if (state != _HEAPOK)
1277 Runtime_Error(pszSrcFile, __LINE__, "heap corrupted %d", state);
[763]1278 else
1279 DbgMsg(pszSrcFile, __LINE__, "_memavl %u", _memavl());
[751]1280 }
1281#endif
1282
[731]1283} // FillDirCnr
[2]1284
[551]1285VOID FillTreeCnr(HWND hwndCnr, HWND hwndParent)
[90]1286{
[924]1287 ULONG ulCurDriveNum, ulDriveMap, numtoinsert = 0;
1288 ULONG ulDriveType;
[551]1289 PCNRITEM pci, pciFirst = NULL, pciNext, pciParent = NULL;
1290 INT x, removable;
[731]1291 CHAR suggest[32];
[739]1292 CHAR szDrive[] = " :\\";
[924]1293 CHAR szFSType[CCHMAXPATH];
[841]1294 FILESTATUS4L fsa4;
[551]1295 APIRET rc;
1296 BOOL drivesbuilt = FALSE;
[739]1297 ULONG startdrive = 3;
[2]1298 static BOOL didonce = FALSE;
1299
1300 fDummy = TRUE;
1301 *suggest = 0;
[689]1302 for (x = 0; x < 26; x++) {
[2]1303 driveflags[x] &= (DRIVE_IGNORE | DRIVE_NOPRESCAN | DRIVE_NOLOADICONS |
[214]1304 DRIVE_NOLOADSUBJS | DRIVE_NOLOADLONGS |
[1354]1305 DRIVE_INCLUDEFILES | DRIVE_SLOW | DRIVE_NOSTATS |
1306 DRIVE_WRITEVERIFYOFF);
[689]1307 }
[551]1308 memset(driveserial, -1, sizeof(driveserial));
[739]1309
1310 DosError(FERR_DISABLEHARDERR);
1311 if (!DosQuerySysInfo(QSV_BOOT_DRIVE,
1312 QSV_BOOT_DRIVE,
1313 (PVOID) &startdrive,
1314 (ULONG) sizeof(ULONG)) &&
1315 startdrive)
[2]1316 {
[739]1317 driveflags[startdrive - 1] |= DRIVE_BOOT;
1318 }
[2]1319
1320 DosError(FERR_DISABLEHARDERR);
[731]1321 rc = DosQCurDisk(&ulCurDriveNum, &ulDriveMap);
[551]1322 if (rc) {
[2]1323 Dos_Error(MB_CANCEL,
[214]1324 rc,
1325 HWND_DESKTOP,
[551]1326 pszSrcFile, __LINE__, GetPString(IDS_FILLDIRQCURERRTEXT));
[2]1327 exit(0);
1328 }
[739]1329
[731]1330 // Calc number of drive items to create
[689]1331 for (x = 0; x < 26; x++) {
[167]1332 if ((ulDriveMap & (1L << x)) && !(driveflags[x] & DRIVE_IGNORE))
[2]1333 numtoinsert++;
[689]1334 }
[739]1335
[689]1336 if (numtoinsert) {
[2]1337 pciFirst = WinSendMsg(hwndCnr,
[214]1338 CM_ALLOCRECORD,
[751]1339 MPFROMLONG(EXTRA_RECORD_BYTES),
[551]1340 MPFROMLONG((ULONG) numtoinsert));
[689]1341 }
[739]1342
[359]1343 if (!pciFirst) {
[744]1344 Win_Error2(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__, IDS_CMALLOCRECERRTEXT);
[907]1345 // 04 Jan 08 SHL fixme not just up and die
[359]1346 exit(0);
1347 }
[689]1348
[907]1349 // 04 Jan 08 SHL fixme like comp.c to handle less than ulSelCnt records
[739]1350 pci = pciFirst;
1351 for (x = 0; x < 26; x++) {
1352 if ((ulDriveMap & (1L << x)) && !(driveflags[x] & DRIVE_IGNORE)) {
[2]1353
[739]1354 CHAR s[80];
1355 ULONG flags = 0;
[1328]1356 ULONG size = sizeof(ULONG);
[2]1357
[739]1358 *szDrive = (CHAR)x + 'A'; // Build path spec
[731]1359
[739]1360 sprintf(s, "%c.DriveFlags", toupper(*szDrive));
[1328]1361 if (PrfQueryProfileData(fmprof, appname, s, &flags, &size)) {
[739]1362 driveflags[toupper(*szDrive) - 'A'] |= flags;
1363 }
[2]1364
[739]1365 if (x > 1) {
1366 // Hard drive (2..N)
1367 if (!(driveflags[x] & DRIVE_NOPRESCAN)) {
[924]1368 *szFSType = 0;
1369 ulDriveType = 0;
1370 removable = CheckDrive(*szDrive, szFSType, &ulDriveType);
[739]1371 driveserial[x] = -1;
1372 if (removable != -1) {
1373 struct {
1374 ULONG serial;
1375 CHAR volumelength;
1376 CHAR volumelabel[CCHMAXPATH];
1377 } volser;
[2]1378
[739]1379 DosError(FERR_DISABLEHARDERR);
1380 if (!DosQueryFSInfo((ULONG) x,
1381 FSIL_VOLSER, &volser, sizeof(volser))) {
1382 driveserial[x] = volser.serial;
[731]1383 }
[739]1384 }
1385 else
1386 driveflags[x] |= DRIVE_INVALID;
[731]1387
[841]1388 memset(&fsa4, 0, sizeof(FILESTATUS4L));
[739]1389 driveflags[x] |= removable == -1 || removable == 1 ?
1390 DRIVE_REMOVABLE : 0;
[924]1391 if (ulDriveType & DRIVE_REMOTE)
[739]1392 driveflags[x] |= DRIVE_REMOTE;
[924]1393 if (!stricmp(szFSType,RAMFS)) {
[739]1394 driveflags[x] |= DRIVE_RAMDISK;
1395 driveflags[x] &= ~DRIVE_REMOTE;
1396 }
[924]1397 if (!stricmp(szFSType,NDFS32)) {
[739]1398 driveflags[x] |= DRIVE_VIRTUAL;
1399 driveflags[x] &= ~DRIVE_REMOTE;
1400 }
[924]1401 if (!stricmp(szFSType,NTFS))
[739]1402 driveflags[x] |= DRIVE_NOTWRITEABLE;
[924]1403 if (strcmp(szFSType, HPFS) &&
1404 strcmp(szFSType, JFS) &&
1405 strcmp(szFSType, ISOFS) &&
1406 strcmp(szFSType, CDFS) &&
1407 strcmp(szFSType, FAT32) &&
1408 strcmp(szFSType, NDFS32) &&
1409 strcmp(szFSType, RAMFS) &&
[1347]1410 strcmp(szFSType, NTFS) &&
[924]1411 strcmp(szFSType, HPFS386)) {
[739]1412 driveflags[x] |= DRIVE_NOLONGNAMES;
1413 }
[534]1414
[924]1415 if (!strcmp(szFSType, CDFS) || !strcmp(szFSType,ISOFS)) {
[739]1416 removable = 1;
[1347]1417 driveflags[x] |= DRIVE_REMOVABLE | DRIVE_NOTWRITEABLE | DRIVE_CDROM;
[739]1418 }
[1347]1419 if (!stricmp(szFSType, CBSIFS)) {
[739]1420 driveflags[x] |= DRIVE_ZIPSTREAM;
1421 driveflags[x] &= ~DRIVE_REMOTE;
[924]1422 if (ulDriveType & DRIVE_REMOVABLE)
[739]1423 driveflags[x] |= DRIVE_REMOVABLE;
[924]1424 if (!(ulDriveType & DRIVE_NOLONGNAMES))
[739]1425 driveflags[x] &= ~DRIVE_NOLONGNAMES;
[1347]1426 }
[1354]1427 if (!fVerifyOffChecked[x]) {
1428 if (driveflags[x] & DRIVE_REMOVABLE)
1429 driveflags[x] |= DRIVE_WRITEVERIFYOFF;
[1355]1430 if (!(driveflags[x] & DRIVE_INVALID)) {
[1354]1431 CHAR Key[80];
[2]1432
[1354]1433 sprintf(Key, "%c.VerifyOffChecked", (CHAR) (x + 'A'));
1434 fVerifyOffChecked[x] = TRUE;
1435 PrfWriteProfileData(fmprof, appname, Key, &fVerifyOffChecked[x], sizeof(BOOL));
1436 }
1437 }
[739]1438 pci->rc.flRecordAttr |= CRA_RECORDREADONLY;
1439 if ((ULONG)(toupper(*szDrive) - '@') == ulCurDriveNum)
1440 pci->rc.flRecordAttr |= (CRA_CURSORED | CRA_SELECTED);
[2]1441
[739]1442 if (removable == 0) {
1443 // Fixed volume
1444 pci->attrFile |= FILE_DIRECTORY;
1445 DosError(FERR_DISABLEHARDERR);
1446 rc = DosQueryPathInfo(szDrive,
[841]1447 FIL_QUERYEASIZEL,
1448 &fsa4, (ULONG) sizeof(FILESTATUS4L));
[739]1449 // ERROR_BAD_NET_RSP = 58
1450 if (rc == 58) {
[214]1451 DosError(FERR_DISABLEHARDERR);
1452 rc = DosQueryPathInfo(szDrive,
[841]1453 FIL_STANDARDL,
[847]1454 &fsa4, (ULONG) sizeof(FILESTATUS4L));
[739]1455 fsa4.cbList = 0;
1456 }
1457 if (rc && !didonce) {
1458 // Guess drive letter
1459 if (!*suggest) {
1460 *suggest = '/';
1461 suggest[1] = 0;
[214]1462 }
[739]1463 sprintf(suggest + strlen(suggest), "%c" , toupper(*szDrive));
[773]1464 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
[739]1465 pci->pszDisplayName = pci->pszFileName;
1466 pci->rc.pszIcon = pci->pszDisplayName;
[214]1467 pci->attrFile = FILE_DIRECTORY;
[751]1468 pci->pszDispAttr = FileAttrToString(pci->attrFile);
[739]1469 driveserial[x] = -1;
[731]1470 }
[739]1471 else
1472 FillInRecordFromFSA(hwndCnr, pci, szDrive, &fsa4, TRUE, NULL);
[214]1473 }
[551]1474 else {
[739]1475 // Removable volume
[773]1476 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
[739]1477 pci->pszDisplayName = pci->pszFileName;
1478 pci->rc.pszIcon = pci->pszDisplayName;
[214]1479 pci->attrFile = FILE_DIRECTORY;
[751]1480 pci->pszDispAttr = FileAttrToString(pci->attrFile);
[214]1481 }
[1284]1482 SelectDriveIcon(pci);
[1250]1483# ifdef FORTIFY
1484 // Will be freed by TreeCnrWndProc WM_DESTROY
1485 Fortify_SetScope(pci->pszFileName, 2);
1486# endif
[214]1487 }
[1284]1488 else {
[739]1489 pci->rc.hptrIcon = hptrDunno;
[773]1490 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
[1154]1491# ifdef FORTIFY
1492 // Will be freed by TreeCnrWndProc WM_DESTROY
1493 Fortify_SetScope(pci->pszFileName, 2);
1494# endif
[739]1495 pci->pszDisplayName = pci->pszFileName;
[214]1496 pci->rc.pszIcon = pci->pszFileName;
1497 pci->attrFile = FILE_DIRECTORY;
[751]1498 pci->pszDispAttr = FileAttrToString(pci->attrFile);
[214]1499 driveserial[x] = -1;
1500 }
[2]1501 }
[739]1502 else {
1503 // diskette drive (A or B)
1504 pci->rc.hptrIcon = hptrFloppy;
[773]1505 pci->pszFileName = xstrdup(szDrive, pszSrcFile, __LINE__);
[739]1506 pci->pszDisplayName = pci->pszFileName;
1507 pci->rc.pszIcon = pci->pszDisplayName;
1508 pci->attrFile = FILE_DIRECTORY;
[751]1509 pci->pszDispAttr = FileAttrToString(pci->attrFile);
[739]1510 driveflags[x] |= (DRIVE_REMOVABLE | DRIVE_NOLONGNAMES);
1511 driveserial[x] = -1;
1512 }
1513 pci->rc.flRecordAttr |= CRA_RECORDREADONLY;
[783]1514 pci = (PCNRITEM) pci->rc.preccNextRecord; // next rec
[739]1515 }
1516 else if (!(ulDriveMap & (1L << x)))
1517 driveflags[x] |= DRIVE_INVALID;
1518 } // for drives
[689]1519
[739]1520 PostMsg(hwndMain, UM_BUILDDRIVEBAR, MPVOID, MPVOID);
1521 drivesbuilt = TRUE;
[2]1522
[783]1523 // insert the drives
[739]1524 if (numtoinsert && pciFirst) {
1525 RECORDINSERT ri;
1526
1527 memset(&ri, 0, sizeof(RECORDINSERT));
1528 ri.cb = sizeof(RECORDINSERT);
1529 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1530 ri.pRecordParent = (PRECORDCORE) NULL;
1531 ri.zOrder = (ULONG) CMA_TOP;
1532 ri.cRecordsInsert = numtoinsert;
1533 ri.fInvalidateRecord = FALSE;
1534 if (!WinSendMsg(hwndCnr,
1535 CM_INSERTRECORD, MPFROMP(pciFirst), MPFROMP(&ri)))
1536 {
[744]1537 Win_Error2(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
[739]1538 IDS_CMINSERTERRTEXT);
[2]1539 }
[739]1540 }
[689]1541
[783]1542 // move cursor onto the default drive rather than the first drive
[739]1543 if (!fSwitchTree) {
1544 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1545 CM_QUERYRECORD,
1546 MPVOID,
1547 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
[762]1548 while (pci && (INT)pci != -1) {
[739]1549 if ((ULONG) (toupper(*pci->pszFileName) - '@') == ulCurDriveNum) {
1550 WinSendMsg(hwndCnr,
1551 CM_SETRECORDEMPHASIS,
1552 MPFROMP(pci), MPFROM2SHORT(TRUE, CRA_CURSORED));
1553 break;
1554 }
[551]1555 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1556 CM_QUERYRECORD,
[739]1557 MPFROMP(pci),
1558 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
[2]1559 }
[739]1560 }
[2]1561
[739]1562 if (hwndParent) {
1563 WinSendMsg(WinWindowFromID(WinQueryWindow(hwndParent, QW_PARENT),
1564 MAIN_DRIVELIST),
1565 LM_DELETEALL, MPVOID, MPVOID);
1566 }
[2]1567
[739]1568 if (fShowEnv) {
1569 RECORDINSERT ri;
[2]1570
[739]1571 pciParent = WinSendMsg(hwndCnr,
1572 CM_ALLOCRECORD,
[751]1573 MPFROMLONG(EXTRA_RECORD_BYTES), MPFROMLONG(1));
[739]1574 if (pciParent) {
1575 pciParent->flags |= RECFLAGS_ENV;
[773]1576 pciParent->pszFileName = xstrdup(GetPString(IDS_ENVVARSTEXT), pszSrcFile, __LINE__);
[763]1577 pciParent->pszDisplayName = pciParent->pszFileName; // 03 Aug 07 SHL
[739]1578 pciParent->rc.hptrIcon = hptrEnv;
1579 pciParent->rc.pszIcon = pciParent->pszFileName;
[751]1580 pciParent->pszDispAttr = FileAttrToString(0);
[739]1581 memset(&ri, 0, sizeof(RECORDINSERT));
1582 ri.cb = sizeof(RECORDINSERT);
1583 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1584 ri.pRecordParent = (PRECORDCORE) NULL;
1585 ri.zOrder = (ULONG) CMA_TOP;
1586 ri.cRecordsInsert = 1;
1587 ri.fInvalidateRecord = FALSE;
1588 if (WinSendMsg(hwndCnr,
1589 CM_INSERTRECORD, MPFROMP(pciParent), MPFROMP(&ri))) {
[2]1590
[739]1591 char *p, *pp;
[2]1592
[1154]1593 p = pszTreeEnvVarList;
[1090]1594 while (*p == ';')
[739]1595 p++;
1596 while (*p) {
[924]1597 *szFSType = 0;
1598 pp = szFSType;
[1090]1599 while (*p && *p != ';')
[739]1600 *pp++ = *p++;
1601 *pp = 0;
[1090]1602 while (*p == ';')
[214]1603 p++;
[924]1604 if (*szFSType &&
1605 (!stricmp(szFSType, "LIBPATH") || getenv(szFSType))) {
[739]1606 pci = WinSendMsg(hwndCnr,
1607 CM_ALLOCRECORD,
[751]1608 MPFROMLONG(EXTRA_RECORD_BYTES),
[739]1609 MPFROMLONG(1));
1610 if (pci) {
1611 CHAR fname[CCHMAXPATH];
1612 pci->flags |= RECFLAGS_ENV;
[924]1613 sprintf(fname, "%%%s%%", szFSType);
[739]1614 pci->pszFileName = xstrdup(fname, pszSrcFile, __LINE__);
1615 pci->rc.hptrIcon = hptrEnv;
1616 pci->rc.pszIcon = pci->pszFileName;
[751]1617 pci->pszDispAttr = FileAttrToString(0);
[739]1618 memset(&ri, 0, sizeof(RECORDINSERT));
1619 ri.cb = sizeof(RECORDINSERT);
1620 ri.pRecordOrder = (PRECORDCORE) CMA_END;
1621 ri.pRecordParent = (PRECORDCORE) pciParent;
1622 ri.zOrder = (ULONG) CMA_TOP;
1623 ri.cRecordsInsert = 1;
1624 ri.fInvalidateRecord = FALSE;
1625 if (!WinSendMsg(hwndCnr,
1626 CM_INSERTRECORD,
1627 MPFROMP(pci), MPFROMP(&ri))) {
[744]1628 Win_Error2(hwndCnr, HWND_DESKTOP, pszSrcFile, __LINE__,
[739]1629 IDS_CMINSERTERRTEXT);
[751]1630 FreeCnrItem(hwndCnr, pci);
[214]1631 }
1632 }
1633 }
1634 }
[739]1635 WinSendMsg(hwndCnr,
1636 CM_INVALIDATERECORD,
1637 MPFROMP(&pciParent),
1638 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
[2]1639 }
[739]1640 else
[751]1641 FreeCnrItem(hwndCnr, pciParent);
[739]1642 }
1643 } // if show env
[1299]1644 {
[1335]1645 STUBBYSCAN *stubbyScan;
[1299]1646 HWND hwndDrivesList = WinWindowFromID(WinQueryWindow(hwndParent, QW_PARENT),
[1335]1647 MAIN_DRIVELIST);
[1299]1648
[1250]1649 pci = (PCNRITEM) WinSendMsg(hwndCnr,
[1308]1650 CM_QUERYRECORD,
1651 MPVOID,
[1335]1652 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
[1317]1653 StubbyScanCount ++;
[1250]1654 while (pci && (INT)pci != -1) {
[1335]1655 stubbyScan = xmallocz(sizeof(STUBBYSCAN), pszSrcFile, __LINE__);
1656 if (!stubbyScan)
[1308]1657 break;
[1335]1658 stubbyScan->pci = pci;
1659 stubbyScan->hwndCnr = hwndCnr;
1660 stubbyScan->hwndDrivesList = hwndDrivesList;
1661 stubbyScan->RamDrive = FALSE;
[1250]1662 pciNext = (PCNRITEM) WinSendMsg(hwndCnr,
[1308]1663 CM_QUERYRECORD,
1664 MPFROMP(pci),
1665 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
[1284]1666 if (~pci->flags & RECFLAGS_ENV) {
[1308]1667 ULONG drvNum = toupper(*pci->pszFileName) - 'A'; // 0..25
1668 if (drvNum == ulCurDriveNum || drvNum >= 2) {
1669 ULONG flags = driveflags[drvNum]; // Speed up
1670 if (~flags & DRIVE_INVALID &&
1671 ~flags & DRIVE_NOPRESCAN &&
[1326]1672 (!fNoRemovableScan || ~flags & DRIVE_REMOVABLE) && !fDrivetoSkip[drvNum])
[1308]1673 {
1674 if (DRIVE_RAMDISK)
[1335]1675 stubbyScan->RamDrive = TRUE;
1676 if (xbeginthread(StubbyScanThread,
1677 65536,
1678 stubbyScan,
1679 pszSrcFile,
1680 __LINE__) == -1)
1681 {
1682 xfree(stubbyScan, pszSrcFile, __LINE__);
1683 }
[1308]1684 } // if drive for scanning
1685 else
1686 WinSendMsg(hwndDrivesList,
1687 LM_INSERTITEM,
1688 MPFROM2SHORT(LIT_SORTASCENDING, 0),
1689 MPFROMP(pci->pszFileName));
1690 }
1691 else {
1692 WinSendMsg(hwndCnr,
1693 CM_INVALIDATERECORD,
1694 MPFROMP(&pci),
1695 MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION));
1696 WinSendMsg(hwndDrivesList,
1697 LM_INSERTITEM,
1698 MPFROM2SHORT(LIT_SORTASCENDING, 0),
1699 MPFROMP(pci->pszFileName));
[1335]1700 }
1701 fDrivetoSkip[drvNum] = FALSE;
[739]1702 }
[1250]1703 pci = pciNext;
1704 } // while
[1326]1705 StubbyScanCount--;
[1299]1706 }
[739]1707 if (hwndParent)
1708 WinSendMsg(WinWindowFromID(WinQueryWindow(hwndParent, QW_PARENT),
1709 MAIN_DRIVELIST), LM_SELECTITEM,
1710 MPFROM2SHORT(0, 0), MPFROMLONG(TRUE));
[2]1711
[739]1712 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1713 CM_QUERYRECORD,
1714 MPVOID,
1715 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
[762]1716 while (pci && (INT)pci != -1) {
[739]1717 pciNext = (PCNRITEM) WinSendMsg(hwndCnr,
[551]1718 CM_QUERYRECORD,
1719 MPFROMP(pci),
[739]1720 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1721 if (pci->flags & RECFLAGS_ENV) {
[551]1722 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1723 CM_QUERYRECORD,
1724 MPFROMP(pci),
[739]1725 MPFROM2SHORT(CMA_FIRSTCHILD,
1726 CMA_ITEMORDER));
[762]1727 while (pci && (INT)pci != -1) {
[739]1728 if (pci->flags & RECFLAGS_ENV)
1729 FleshEnv(hwndCnr, pci);
1730 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1731 CM_QUERYRECORD,
1732 MPFROMP(pci),
1733 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1734 }
1735 break;
[2]1736 }
[739]1737 pci = (PCNRITEM) WinSendMsg(hwndCnr,
1738 CM_QUERYRECORD,
1739 MPFROMP(pci),
1740 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1741 }
[2]1742
[167]1743 if (!drivesbuilt && hwndMain)
[551]1744 PostMsg(hwndMain, UM_BUILDDRIVEBAR, MPVOID, MPVOID);
[783]1745 DosSleep(16); // 05 Aug 07 GKY 33
[2]1746 fDummy = FALSE;
1747 DosPostEventSem(CompactSem);
[739]1748
[2]1749 {
1750 BYTE info;
1751 BOOL includesyours = FALSE;
1752
[917]1753 // 10 Jan 08 SHL fixme to understand fFirstTime
[551]1754 if (*suggest || (!(driveflags[1] & DRIVE_IGNORE) && fFirstTime)) {
1755 if (!DosDevConfig(&info, DEVINFO_FLOPPY) && info == 1) {
1756 if (!*suggest) {
[214]1757 *suggest = '/';
1758 suggest[1] = 0;
1759 }
1760 else
[551]1761 memmove(suggest + 2, suggest + 1, strlen(suggest));
[214]1762 suggest[1] = 'B';
[2]1763 }
1764 }
[551]1765 if (*suggest) {
1766 for (x = 2; x < 26; x++) {
1767 if (driveflags[x] & DRIVE_IGNORE) {
[214]1768 includesyours = TRUE;
[551]1769 sprintf(suggest + strlen(suggest), "%c", (char)(x + 'A'));
[214]1770 }
[2]1771 }
[551]1772 strcat(suggest, " %*");
[167]1773 if (saymsg(MB_YESNO | MB_ICONEXCLAMATION,
[214]1774 (hwndParent) ? hwndParent : hwndCnr,
1775 GetPString(IDS_SUGGESTTITLETEXT),
1776 GetPString(IDS_SUGGEST1TEXT),
1777 (includesyours) ? GetPString(IDS_SUGGEST2TEXT) : NullStr,
[551]1778 suggest) == MBID_YES) {
[214]1779 char s[64];
[2]1780
[214]1781 sprintf(s, "PARAMETERS=%s", suggest);
[551]1782 WinCreateObject(WPProgram, "FM/2", s, FM3Folder, CO_UPDATEIFEXISTS);
[214]1783 WinCreateObject(WPProgram,
[551]1784 "FM/2 Lite", s, FM3Folder, CO_UPDATEIFEXISTS);
[214]1785 WinCreateObject(WPProgram,
[551]1786 "Archive Viewer/2", s, FM3Tools, CO_UPDATEIFEXISTS);
[214]1787 WinCreateObject(WPProgram,
[551]1788 "Dir Sizes", s, FM3Tools, CO_UPDATEIFEXISTS);
[214]1789 WinCreateObject(WPProgram,
[551]1790 "Visual Tree", s, FM3Tools, CO_UPDATEIFEXISTS);
[214]1791 WinCreateObject(WPProgram,
[551]1792 "Visual Directory", s, FM3Tools, CO_UPDATEIFEXISTS);
[214]1793 WinCreateObject(WPProgram,
[551]1794 "Global File Viewer", s, FM3Tools, CO_UPDATEIFEXISTS);
1795 WinCreateObject(WPProgram, "Databar", s, FM3Tools, CO_UPDATEIFEXISTS);
[2]1796 }
1797 }
1798 }
1799 didonce = TRUE;
[1354]1800 if (fInitialDriveScan) {
1801 HWND hwndDrivesList = WinWindowFromID(WinQueryWindow(hwndParent, QW_PARENT),
1802 MAIN_DRIVELIST);
1803 while (StubbyScanCount != 0 || ProcessDirCount != 0)
1804 DosSleep(50);
1805 WinShowWindow(hwndCnr, TRUE);
1806 WinShowWindow(hwndDrivesList, TRUE);
1807 fInitialDriveScan = FALSE;
1808 }
[731]1809} // FillTreeCnr
[743]1810
1811
1812/**
1813 * Empty all records from a container and free associated storage and
1814 * Free up field infos
1815 */
1816
1817VOID EmptyCnr(HWND hwnd)
1818{
1819 PFIELDINFO pfi;
1820
[762]1821#if 0 // fixme to be gone or to be configurable
[751]1822 {
1823 int state = _heapchk();
1824 if (state != _HEAPOK)
1825 Runtime_Error(pszSrcFile, __LINE__, "heap corrupted %d", state);
1826 }
1827#endif
1828
[743]1829 // Remove all records
1830 RemoveCnrItems(hwnd, NULL, 0, CMA_FREE);
1831
1832 // Remove field info descriptors
1833 pfi = (PFIELDINFO) WinSendMsg(hwnd, CM_QUERYDETAILFIELDINFO, MPVOID,
1834 MPFROMSHORT(CMA_FIRST));
[745]1835 if (pfi &&
1836 (INT)WinSendMsg(hwnd, CM_REMOVEDETAILFIELDINFO, MPVOID,
1837 MPFROM2SHORT(0, CMA_FREE)) == -1) {
1838 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVEDETAILFIELDINFO hwnd %x", hwnd);
1839 }
[743]1840}
1841
1842/**
1843 * Free storage associated with container item
1844 */
1845
[751]1846VOID FreeCnrItemData(PCNRITEM pci)
[743]1847{
[1308]1848 if (pci->pszSubject) {
1849 if (pci->pszSubject != NullStr)
1850 free(pci->pszSubject);
[1174]1851 pci->pszSubject = NULL; // Catch illegal references
[762]1852 }
[743]1853
[1174]1854 // 08 Sep 08 SHL Remove excess logic
[1308]1855 if (pci->pszLongName) {
1856 if (pci->pszLongName != NullStr)
1857 free(pci->pszLongName);
[1174]1858 pci->pszLongName = NULL; // Catch illegal references
[762]1859 }
[1154]1860
1861 // Bypass free if pszDisplayName points into pszFileName buffer
1862 // 05 Sep 08 SHL Correct pointer overlap compare logic
[1308]1863 if (pci->pszDisplayName) {
1864 if (pci->pszDisplayName != NullStr) {
1865 if (!pci->pszFileName ||
1866 pci->pszDisplayName < pci->pszFileName ||
1867 pci->pszDisplayName >= pci->pszFileName + _msize(pci->pszFileName))
1868 {
1869 free(pci->pszDisplayName);
1870 }
[1154]1871 }
[1308]1872 pci->pszDisplayName = NULL; // Catch illegal references
[1154]1873 }
[1113]1874
[1308]1875 if (!pci->pszFileName)
1876 Runtime_Error(pszSrcFile, __LINE__, "FreeCnrItemData attempting free %p data twice", pci);
1877 else {
1878 if (pci->pszFileName != NullStr)
1879 free(pci->pszFileName);
1880 pci->pszFileName = NULL; // Catch illegal references
1881 }
1882
[1299]1883 // 08 Sep 08 SHL Remove excess logic
[1308]1884 if (pci->pszLongName) {
1885 if (pci->pszLongName != NullStr)
1886 free(pci->pszLongName);
[1299]1887 pci->pszLongName = NULL; // Catch illegal references
1888 }
[1174]1889
[1308]1890 if (pci->pszFmtFileSize) {
1891 if (pci->pszFmtFileSize != NullStr)
1892 free(pci->pszFmtFileSize);
[1174]1893 pci->pszFmtFileSize = NULL; // Catch illegal references
[857]1894 }
[743]1895}
1896
1897/**
[762]1898 * Free single container item and associated storage
[743]1899 */
1900
[762]1901VOID FreeCnrItem(HWND hwnd, PCNRITEM pci)
[743]1902{
[745]1903 // DbgMsg(pszSrcFile, __LINE__, "FreeCnrItem hwnd %x pci %p", hwnd, pci);
1904
[743]1905 FreeCnrItemData(pci);
1906
[762]1907 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(1))) {
[744]1908 // Win_Error2(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,IDS_CMFREEERRTEXT);
[773]1909 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,
1910 "CM_FREERECORD hwnd %x pci %p file %s",
[783]1911 hwnd, pci,
[773]1912 pci && pci->pszFileName ? pci->pszFileName : "n/a");
[743]1913 }
1914}
1915
1916/**
[751]1917 * Free container item list and associated storage
[743]1918 */
1919
[751]1920VOID FreeCnrItemList(HWND hwnd, PCNRITEM pciFirst)
[743]1921{
[751]1922 PCNRITEM pci = pciFirst;
1923 PCNRITEM pciNext;
[762]1924 USHORT usCount;
[751]1925
[762]1926 for (usCount = 0; pci; usCount++) {
[751]1927 pciNext = (PCNRITEM) pci->rc.preccNextRecord;
[762]1928 FreeCnrItemData(pci);
[751]1929 pci = pciNext;
1930 }
[762]1931
1932 if (usCount) {
1933 if (!WinSendMsg(hwnd, CM_FREERECORD, MPFROMP(&pci), MPFROMSHORT(usCount))) {
1934 // Win_Error2(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,IDS_CMFREEERRTEXT);
1935 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_FREERECORD hwnd %x pci %p cnt %u", hwnd, pci, usCount);
1936 }
1937 }
[751]1938}
1939
1940/**
1941 * Remove item(s) from container and free associated storage if requested
[762]1942 * @param pciFirst points to first item to remove or NULL to remove all
1943 * @param usCnt is remove count or 0 to remove all
[751]1944 * @returns count of items remaining in container or -1 if error
1945 */
1946
[762]1947INT RemoveCnrItems(HWND hwnd, PCNRITEM pciFirst, USHORT usCnt, USHORT usFlags)
[751]1948{
[762]1949 INT remaining = usCnt;
1950 PCNRITEM pci;
[751]1951
[762]1952 if ((usCnt && !pciFirst) || (!usCnt && pciFirst)) {
1953 Runtime_Error(pszSrcFile, __LINE__, "pciFirst %p usCnt %u mismatch", pciFirst, usCnt);
[751]1954 remaining = -1;
[762]1955 }
1956 else {
1957 // Free our buffers if free requested
1958 if (usFlags & CMA_FREE) {
1959 if (pciFirst)
1960 pci = pciFirst;
1961 else {
[743]1962 pci = (PCNRITEM)WinSendMsg(hwnd, CM_QUERYRECORD, MPVOID,
[744]1963 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
[762]1964 if ((INT)pci == -1) {
[744]1965 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_QUERYRECORD");
[751]1966 remaining = -1;
[762]1967 pci = NULL;
1968 }
1969 }
1970 while (pci) {
[850]1971 // 12 Sep 07 SHL dwg drivebar crash testing - ticket# ???
[1174]1972 static PCNRITEM pciLast; // 12 Sep 07 SHL
[907]1973 ULONG ulSize = sizeof(*pci);
1974 ULONG ulAttr;
[850]1975 APIRET apiret = DosQueryMem((PVOID)pci, &ulSize, &ulAttr);
1976 if (apiret)
[907]1977 Dos_Error(MB_ENTER, apiret, HWND_DESKTOP, pszSrcFile, __LINE__,
[850]1978 "DosQueryMem failed pci %p pciLast %p", pci, pciLast);
[1308]1979 FreeCnrItemData(pci);
[850]1980 pciLast = pci;
[762]1981 pci = (PCNRITEM)pci->rc.preccNextRecord;
1982 if (remaining && --remaining == 0)
[744]1983 break;
[762]1984 }
[743]1985 }
1986 }
[745]1987
[762]1988 // DbgMsg(pszSrcFile, __LINE__, "RemoveCnrItems %p %u %s", pci, usCnt, pci->pszFileName);
[743]1989
[762]1990 if (remaining != - 1) {
1991 remaining = (INT)WinSendMsg(hwnd, CM_REMOVERECORD, MPFROMP(&pciFirst), MPFROM2SHORT(usCnt, usFlags));
[751]1992 if (remaining == -1) {
[744]1993 // Win_Error2(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,IDS_CMREMOVEERRTEXT);
[762]1994 Win_Error(hwnd, HWND_DESKTOP, pszSrcFile, __LINE__,"CM_REMOVERECORD hwnd %x pci %p cnt %u", hwnd, pciFirst, usCnt);
[743]1995 }
1996 }
[762]1997
[751]1998 return remaining;
[743]1999}
2000
[783]2001#pragma alloc_text(FILLDIR,FillInRecordFromFFB,FillInRecordFromFSA,IDFile)
[1299]2002#pragma alloc_text(FILLDIR1,ProcessDirectory,FillDirCnr,FillTreeCnr,FileAttrToString,StubbyScanThread)
[783]2003#pragma alloc_text(EMPTYCNR,EmptyCnr,FreeCnrItemData,FreeCnrItem,FreeCnrItemList,RemoveCnrItems)
2004
Note: See TracBrowser for help on using the repository browser.