root/trunk/txlib/txtree.c

Revision 1, 55.4 kB (checked in by jvw, 3 years ago)

Initial check-in for TxWin? version 1.02 sources

Line 
1//
2//                     TxWin, Textmode Windowing Library
3//
4//   Original code Copyright (c) 1995-2005 Fsys Software and Jan van Wijk
5//
6// ==========================================================================
7//
8// This file contains Original Code and/or Modifications of Original Code as
9// defined in and that are subject to the GNU Lesser General Public License.
10// You may not use this file except in compliance with the License.
11// BY USING THIS FILE YOU AGREE TO ALL TERMS AND CONDITIONS OF THE LICENSE.
12// A copy of the License is provided with the Original Code and Modifications,
13// and is also available at http://www.dfsee.com/txwin/lgpl.htm
14//
15// This library is free software; you can redistribute it and/or modify
16// it under the terms of the GNU Lesser General Public License as published
17// by the Free Software Foundation; either version 2.1 of the License,
18// or (at your option) any later version.
19//
20// This library is distributed in the hope that it will be useful,
21// but WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23// See the GNU Lesser General Public License for more details.
24//
25// You should have received a copy of the GNU Lesser General Public License
26// along with this library; (lgpl.htm) if not, write to the Free Software
27// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28//
29// Questions on TxWin licensing can be directed to: txwin@fsys.nl
30//
31// ==========================================================================
32//
33// Recursive findfile with call-back function to operate on found files
34//
35// Author: J. van Wijk
36//
37// Developed for LPT file transfer utility, updated for TxWin File dialog
38//
39// Modelled after SysFileTree implementation from REXXUTIL
40// Major functional changes made:
41//
42//   - REXX interfaces (stem, variablepool) changed to normal 'C'
43//   - Action on each matching file implemented as a call-back function
44//     with the full "true-filename" and a FILEFINDBUF4 structure as parameters
45//   - Source and Destination mask use different syntax (+,-,* and ARSHD)
46//
47//     options  - Any combo of the following:
48//                 'B' - Search for files and directories. (default)
49//                 'D' - Search for directories only.
50//                 'F' - Search for files only.
51//                 'S' - Recursively scan subdirectories.
52//
53// Includes the lower-level TxFindFirstFile() and TxFindNextFile() APIs too
54// with an associated TX specific (OS-neutral) TXFILEFIND structure
55//
56// Also includes a wrapper to deliver a result-set in a TXSELIST structure
57
58#include <txlib.h>
59
60#if defined (LINUX)
61   #include <dirent.h>
62   #include <sys/stat.h>
63
64typedef struct txlin_ffinfo
65{
66   DIR             *dir;                        // opendir/readdir handle
67   TXLN             dirname;                    // original directory path
68   TXLN             wildcard;                   // filename part of fspec
69} TXLIN_FFINFO;                                 // end of struct "txlin_ffinfo"
70
71
72// Find next file matching the specified (wildcard) name
73static ULONG TxLinuxNextFile                    // RET   result
74(
75   TXLIN_FFINFO       *ffi,                     // IN    TX filefind handle
76   TXFILEFIND         *found                    // OUT   found file details
77);
78
79
80#endif
81
82/*********************************************************************/
83/* Defines uses by TxTree                                            */
84/*********************************************************************/
85
86#define  FIRST_TIME     0x0001
87#define  RECURSE        0x0002
88#define  DO_DIRS        0x0004
89#define  DO_FILES       0x0008
90#define  INCLUDESPEC    0x0010
91#define  INCL_DOTDOT    0x0020                  // keep the .. directory
92
93#define  TX_ALL_ATTRS   FATTR_READONLY  | FATTR_HIDDEN    | \
94                        FATTR_SYSTEM    | FATTR_DIRECTORY | FATTR_ARCHIVED
95
96typedef struct TxTreeData                       // Tree data structure
97{
98   TXLN                TargetSpec;              // Filespec FlTree searches
99   TXLN                truefile;                // actual file name
100   TXLN                tempfile;                // temp file name
101   TXLN                Temp;                    // Used when building data
102   char              **filter;                  // Include/Exclude file-specs
103   ULONG               nattrib;                 // New attrib, diff for each
104} TXTREEDATA;
105
106
107// Split path and filename part of a full-filespec
108static void txGetPath
109(
110   char               *string,                  // IN    full filespec
111   char               *path,                    // OUT   path component, incl SEP
112   char               *filename                 // OUT   filename component
113);                                              //       or NULL if not wanted
114
115
116// Compare two sets of file-attributes in REXXXUtil format
117static BOOL txSameAttr                          // RET   attrs are  same
118(
119   char               *mask,                    // IN    1st set, as string
120   ULONG               attr                     // IN    2nd set as bitmask
121);
122
123
124// Combine two sets of file-attributes in REXXXUtil format
125static ULONG txNewAttr
126(
127   char               *mask,
128   ULONG               attr
129);
130
131
132// Change file attribute bits
133static ULONG  txSetFileMode
134(
135   char               *file,                    // file name
136   ULONG               attr                     // new file attributes
137);
138
139static ULONG txRecursiveFindFile                // RET   result error code
140(
141   char               *FileSpec,                // IN    Filespecs to search
142   TXTREEDATA         *ldp,                     // INOUT local data
143   char               *smask,                   // IN    select attributes
144   char               *dmask,                   // IN    modify attributes
145   ULONG               options,                 // IN    search options
146   TXTREE_CALLBACK     callback,                // IN    function to call back
147   void               *calldata                 // IN    callback data
148);
149
150
151#if defined (USEWINDOWING)
152// Add file/directory instance to the Selist being built
153static ULONG txFileDirAdd2List
154(
155   char               *fname,                   // IN    full filename
156   TXFILEFIND         *finfo,                   // IN    file information
157   void               *cdata                    // IN    Callback data
158);
159
160/*****************************************************************************/
161// Build selection-list with File/Directory/Tree information
162/*****************************************************************************/
163TXSELIST *TxFileDirSelist                       // RET   selection list or NULL
164(                                               //       Tree RC is in userinfo
165   char               *fspec,                   // IN    Filespec to match
166   char               *fopts,                   // IN    Find options
167   char               *fattr,                   // IN    Select attributes
168   char              **filter,                  // IN    Excl/Incl file-specs
169   ULONG               flags                    // IN    flags - 'descriptions'
170)
171{
172   TXSELIST           *list  = NULL;            // total list
173   ULONG               size  = 500;             // initial allocated size
174
175   ENTER();
176
177   TRACES(( "fspec:'%s' fopts:'%s' fattr:'%s' filter:%8.8lx flags:%8.8lx\n",
178             fspec,     fopts,     fattr,     filter,       flags));
179
180   TxCancelAbort();                             // possible previous ESC ...
181                                                // FileTree would abort on it
182   if (TxSelCreate( size, size, size,
183                    TXS_AS_NOSTATIC, FALSE, NULL, &list) == NO_ERROR)
184   {
185      list->astatus  = TXS_AS_NOSTATIC;         // all dynamic allocated
186      list->userinfo = flags;                   // input for FileDirAdd2List
187
188      TxFileTree( fspec, fopts, fattr, "", filter, txFileDirAdd2List, list);
189
190      list->flags    = TXSL_MULTI_QUICK;        // multi-char quick select
191      list->userinfo = 0;
192      list->tsize    = list->asize;
193   }
194   RETURN( list);
195}                                               // end 'TxFileDirSelist'
196/*---------------------------------------------------------------------------*/
197
198
199/*****************************************************************************/
200// Add file/directory instance to the Selist being built
201/*****************************************************************************/
202static ULONG txFileDirAdd2List
203(
204   char               *fname,                   // IN    full filename
205   TXFILEFIND         *finfo,                   // IN    file information
206   void               *cdata                    // IN    Callback data
207)
208{
209   ULONG               rc  = NO_ERROR;
210   TXSELIST         *list = (TXSELIST *) cdata; // list being built
211   TXS_ITEM         *item;                      // single item
212
213   ENTER();
214   TRARGS(("fname: '%s'\n",  fname));           // full filename
215
216   if (list != NULL)                            // do we have a list ?
217   {
218      if (list->count >= list->asize)           // reached maximum array size
219      {
220         ULONG         newsize = 2 * list->asize + 100;
221
222         TRACES(("realloc items to %lu items\n",  newsize));
223         if ((list->items = realloc( list->items, newsize *
224                                     sizeof(TXS_ITEM *))) != NULL)
225         {
226            list->asize = newsize;              // size has doubled now
227         }
228         else
229         {
230            rc = TX_ALLOC_ERROR;
231         }
232      }
233      if (rc == NO_ERROR)
234      {
235         if ((item = TxAlloc( 1, sizeof(TXS_ITEM))) != NULL)
236         {
237            TRACES(("Alloc: %lu, adding item %lu: '%s' for '%s'\n",
238                     list->asize, list->count, finfo->fName, fname));
239
240            list->items[list->count++] = item;  // attach item to list
241
242            if ((item->text = TxAlloc( 1, strlen(finfo->fName)+1)) != NULL)
243            {
244               strcpy( item->text, finfo->fName); // basename as item-text
245            }
246            item->helpid = TXWH_USE_WIN_HELP;   // from list-window itself
247            item->index  = 1;                   // quick select on 1st char
248                                                // (unless multi-quick flag)
249
250            if (list->userinfo & TXFDS_ADD_DESCRIPTION)
251            {
252               int    fnlength = max( strlen(finfo->fName) +1, TXMAXTT -4);
253               TRACES(( "fnlength: %d\n", fnlength));
254
255               if ((item->desc = TxAlloc(1, fnlength + 40)) != NULL)
256               {
257                  TXTT   date;
258                  TXLN   name;                  // fnlength may be TXMAXLN!
259
260                  strftime( date, TXMAXTT, " %d-%m-%Y %H:%M:%S ", gmtime( &(finfo->wTime)));
261                  sprintf(  name, " %-*.*s", fnlength, fnlength,  finfo->fName);
262                  txFileAttr2String( finfo->fAttr, item->desc);
263                  if (finfo->fAttr & FATTR_DIRECTORY)
264                  {
265                     strcat( item->desc, date);
266                     strcat( item->desc, "<directory>");
267                     strcat( item->desc, name);
268                  }
269                  else
270                  {
271                     txStrSize64( item->desc, date, finfo->fSize, name);
272                  }
273               }
274            }
275         }
276      }
277   }
278   else
279   {
280      TRACES(("supplied listpointer is NULL!\n"));
281   }
282   RETURN (rc);
283}                                               // end 'txFileDirAdd2List'
284/*---------------------------------------------------------------------------*/
285
286
287/*****************************************************************************/
288// Split multiple wildcard in BASE and INCLUDE array
289/*****************************************************************************/
290char **txWildcard2Filter
291(
292   char               *base,                    // INOUT base specification
293   char               *spec,                    // IN    wildcard (multi)
294   char              **fa,                      // IN    filter array
295   int                 size                     // IN    size of filter array
296)
297{
298   char              **rc = NULL;               // function return
299   char               *we;                      // wildcard end
300   char               *wb;                      // wildcard begin
301   int                 i;
302   TXLN                wildcard;                // modifiable copy
303
304   ENTER();
305
306   TRACES(( "base: '%s'  wildcard: '%s'\n", base, spec));
307
308   strcpy( wildcard, spec);                     // use local copy to modify
309   if ((we = strchr( wildcard, ';')) != NULL)   // multiple wildcards, use
310   {                                            // include mechanism
311      for ( i = 0,           wb  = wildcard;
312           (i < size -1) && (wb != NULL);
313            i++)
314      {
315         if (we != NULL)
316         {
317            *we = '\0';                         // terminate this wildcard
318         }
319         if ((fa[i] = TxAlloc( 1, strlen( wb) + 1)) != NULL)
320         {
321            strcpy( fa[i], wb);
322            TRACES(( "Added filter %u: '%s'\n", i, fa[i]));
323         }
324         if ((wb = we) != NULL)                 // more to come
325         {
326            wb++;                               // advance beyond the ';'
327            we = strchr( wb, ';');              // find new end
328         }
329      }
330      fa[i] = NULL;                             // terminate the array
331      strcat( base, FS_WILDCARD);               // standard wildcard as base
332
333      rc = fa;                                  // return array
334   }
335   else
336   {
337      strcat( base, wildcard);                  // use supplied wildcard
338   }
339   RETURN (rc);
340}                                               // end 'txWildcard2Filter'
341/*---------------------------------------------------------------------------*/
342
343
344/*****************************************************************************/
345// Free filter array memory
346/*****************************************************************************/
347char **txFreeFilter                             // RET   NULL
348(
349   char              **filter,                  // IN    filter array
350   int                 size                     // IN    max number of entries
351)
352{
353   int                 i;
354
355   ENTER();
356
357   if (filter != NULL)
358   {
359      for (i = 0; (i < size) && (filter[i] != NULL); i++)
360      {
361         TRACES(( "Freeing wildcard %u at %8.8lx\n", i, filter[i]));
362         TxFreeMem( filter[i]);
363      }
364   }
365   RETURN (NULL);
366}                                               // end 'txFreeFilter'
367/*---------------------------------------------------------------------------*/
368#endif                                          // USEWINDOWING
369
370
371/*****************************************************************************/
372// Find first file matching the specified (wildcard) name
373/*****************************************************************************/
374ULONG TxFindFirstFile                           // RET   result
375(
376   char               *fspec,                   // IN    file specification
377   TXHANDLE           *handle,                  // OUT   filefind handle
378   TXFILEFIND         *found                    // OUT   found file details
379)
380{
381   ULONG               rc = NO_ERROR;           // function return
382   #if   defined (WIN32)
383      WIN32_FIND_DATA     ffb;                  // filefind buffer
384   #elif defined (DOS32)
385      struct _finddata_t  ffb;                  // filefind buffer
386   #elif defined (LINUX)
387      TXLIN_FFINFO       *ffi = NULL;
388   #else
389      ULONG               fnum = 1;             // number of files
390      FILEFINDBUF4        ffs;                  // OS/2 kernel 4.0 or older
391      FILEFINDBUF4L       ffl;                  // OS/2 kernel 4.5 or newer
392   #endif
393
394   ENTER();
395   TRARGS(("fspec: '%s'\n", fspec));
396
397   memset( found, 0, sizeof(TXFILEFIND));       // initialize all fields
398
399   #if defined (WIN32)
400      if ((*handle = (TXHANDLE) FindFirstFile( fspec, &ffb)) != -1)
401      {
402         found->fAttr = ffb.dwFileAttributes;
403         found->fSize = (((LLONG) ffb.nFileSizeHigh) << 32) + ffb.nFileSizeLow;
404
405         found->cTime = txWinFileTime2t( (NTIME *) &ffb.ftCreationTime,   0);
406         found->aTime = txWinFileTime2t( (NTIME *) &ffb.ftLastAccessTime, 0);
407         found->wTime = txWinFileTime2t( (NTIME *) &ffb.ftLastWriteTime,  0);
408
409         strcpy( found->fName, ffb.cFileName);
410      }
411      else
412      {
413         rc = ERROR_NO_MORE_FILES;
414      }
415   #elif defined (DOS32)
416      if ((*handle = (TXHANDLE) _findfirst( fspec, &ffb)) != -1)
417      {
418         found->fAttr = (ULONG) ffb.attrib;
419         found->fSize = ffb.size;
420
421         found->cTime = ffb.time_create  - 18000; // WATCOM seems 5 hours off
422         found->aTime = ffb.time_access  - 18000;
423         found->wTime = ffb.time_write   - 18000;
424
425         strcpy( found->fName, ffb.name);
426      }
427      else
428      {
429         rc = ERROR_NO_MORE_FILES;
430      }
431   #elif defined (LINUX)
432      if ((ffi = TxAlloc(1, sizeof( TXLIN_FFINFO))) != NULL)
433      {
434         txGetPath( fspec, ffi->dirname, ffi->wildcard);
435
436         TRACES(( "Linux opendir for: '%s'\n", ffi->dirname));
437         if ((ffi->dir = opendir( ffi->dirname)) != NULL)
438         {
439            if ((rc = TxLinuxNextFile( ffi, found)) != NO_ERROR)
440            {
441               closedir(  ffi->dir);
442               TxFreeMem( ffi);
443            }
444         }
445         else                                   // invalid, perhaps wildcard ...
446         {
447            TxFreeMem( ffi);
448         }
449      }
450      *handle = (TXHANDLE) ffi;                 // assign handle
451   #else
452      *handle = (TXHANDLE) HDIR_CREATE;
453      if (TxLargeFileApiOS2( NULL))
454      {
455         rc = DosFindFirst( fspec, (HDIR *) handle, TX_ALL_ATTRS,
456                            &ffl, sizeof( FILEFINDBUF4L),
457                            &fnum, FIL_QUERYEASIZEL);
458         if (rc == NO_ERROR)
459         {
460            found->fAttr = ffl.attrFile;
461            found->fSize = ffl.cbFile;
462
463            found->cTime = txOS2FileTime2t( (USHORT *) &ffl.fdateCreation,
464                                            (USHORT *) &ffl.ftimeCreation);
465            found->aTime = txOS2FileTime2t( (USHORT *) &ffl.fdateLastAccess,
466                                            (USHORT *) &ffl.ftimeLastAccess);
467            found->wTime = txOS2FileTime2t( (USHORT *) &ffl.fdateLastWrite,
468                                            (USHORT *) &ffl.ftimeLastWrite);
469
470            strcpy( found->fName, ffl.achName);
471         }
472      }
473      else
474      {
475         rc = DosFindFirst( fspec, (HDIR *) handle, TX_ALL_ATTRS,
476                            &ffs, sizeof( FILEFINDBUF4),
477                            &fnum, FIL_QUERYEASIZE);
478         if (rc == NO_ERROR)
479         {
480            found->fAttr = ffs.attrFile;
481            found->fSize = ffs.cbFile;
482
483            found->cTime = txOS2FileTime2t( (USHORT *) &ffs.fdateCreation,
484                                            (USHORT *) &ffs.ftimeCreation);
485            found->aTime = txOS2FileTime2t( (USHORT *) &ffs.fdateLastAccess,
486                                            (USHORT *) &ffs.ftimeLastAccess);
487            found->wTime = txOS2FileTime2t( (USHORT *) &ffs.fdateLastWrite,
488                                            (USHORT *) &ffs.ftimeLastWrite);
489
490            strcpy( found->fName, ffs.achName);
491         }
492      }
493   #endif
494   TRARGS(("handle OUT: %8.8lx, fName: '%s'\n", *handle, found->fName));
495   RETURN (rc);
496}                                               // end 'TxFindFirstFile'
497/*---------------------------------------------------------------------------*/
498
499/*****************************************************************************/
500// Find next file matching the specified (wildcard) name
501/*****************************************************************************/
502ULONG TxFindNextFile                            // RET   result
503(
504   TXHANDLE            handle,                  // IN    filefind handle
505   TXFILEFIND         *found                    // OUT   found file details
506)
507{
508   ULONG               rc = NO_ERROR;           // function return
509   #if   defined (WIN32)
510      WIN32_FIND_DATA     ffb;                  // filefind buffer
511   #elif defined (DOS32)
512      struct _finddata_t  ffb;
513   #elif defined (LINUX)
514      TXLIN_FFINFO       *ffi = NULL;
515   #else
516      ULONG               fnum = 1;             // number of files
517      FILEFINDBUF4        ffs;                  // OS/2 4.xx or older
518      FILEFINDBUF4L       ffl;                  // OS/2 4.5x or newer
519   #endif
520
521   ENTER();
522
523   memset( found, 0, sizeof(TXFILEFIND));       // initialize all fields
524
525   #if defined (WIN32)
526      if (FindNextFile( (HANDLE) handle, &ffb))
527      {
528         found->fAttr = ffb.dwFileAttributes;
529         found->fSize = (((LLONG) ffb.nFileSizeHigh) << 32) + ffb.nFileSizeLow;
530
531         found->cTime = txWinFileTime2t( (NTIME *) &ffb.ftCreationTime,   0);
532         found->aTime = txWinFileTime2t( (NTIME *) &ffb.ftLastAccessTime, 0);
533         found->wTime = txWinFileTime2t( (NTIME *) &ffb.ftLastWriteTime,  0);
534
535         strcpy( found->fName, ffb.cFileName);
536      }
537      else
538      {
539         rc = ERROR_NO_MORE_FILES;
540      }
541   #elif defined (DOS32)
542      if (_findnext( (long) handle, &ffb) != -1)
543      {
544         found->fAttr = (ULONG) ffb.attrib;
545         found->fSize = ffb.size;
546
547         found->cTime = ffb.time_create  - 18000; // WATCOM seems 5 hours off
548         found->aTime = ffb.time_access  - 18000;
549         found->wTime = ffb.time_write   - 18000;
550
551         strcpy( found->fName, ffb.name);
552      }
553      else
554      {
555         rc = ERROR_NO_MORE_FILES;
556      }
557   #elif defined (LINUX)
558      if ((ffi = (TXLIN_FFINFO *) handle) != NULL) // handle open ?
559      {
560         rc = TxLinuxNextFile( ffi, found);
561      }
562      else
563      {
564         rc = TX_INVALID_HANDLE;
565      }
566   #else
567      if (TxLargeFileApiOS2( NULL))
568      {
569         rc = DosFindNext( (HDIR) handle, &ffl, sizeof( FILEFINDBUF4L), &fnum);
570         if (rc == NO_ERROR)
571         {
572            found->fAttr = ffl.attrFile;
573            found->fSize = ffl.cbFile;
574
575            found->cTime = txOS2FileTime2t( (USHORT *) &ffl.fdateCreation,
576                                            (USHORT *) &ffl.ftimeCreation);
577            found->aTime = txOS2FileTime2t( (USHORT *) &ffl.fdateLastAccess,
578                                            (USHORT *) &ffl.ftimeLastAccess);
579            found->wTime = txOS2FileTime2t( (USHORT *) &ffl.fdateLastWrite,
580                                            (USHORT *) &ffl.ftimeLastWrite);
581
582            strcpy( found->fName, ffl.achName);
583         }
584      }
585      else
586      {
587         rc = DosFindNext( (HDIR) handle, &ffs, sizeof( FILEFINDBUF4), &fnum);
588         if (rc == NO_ERROR)
589         {
590            found->fAttr = ffs.attrFile;
591            found->fSize = ffs.cbFile;
592
593            found->cTime = txOS2FileTime2t( (USHORT *) &ffs.fdateCreation,
594                                            (USHORT *) &ffs.ftimeCreation);
595            found->aTime = txOS2FileTime2t( (USHORT *) &ffs.fdateLastAccess,
596                                            (USHORT *) &ffs.ftimeLastAccess);
597            found->wTime = txOS2FileTime2t( (USHORT *) &ffs.fdateLastWrite,
598                                            (USHORT *) &ffs.ftimeLastWrite);
599
600            strcpy( found->fName, ffs.achName);
601         }
602      }
603   #endif
604   TRARGS(("handle  IN: %8.8lx, fName: '%s'\n", handle, found->fName));
605   RETURN (rc);
606}                                               // end 'TxFindNextFile'
607/*---------------------------------------------------------------------------*/
608
609#if defined (LINUX)
610/*****************************************************************************/
611// Find next file matching the specified (wildcard) name
612/*****************************************************************************/
613static ULONG TxLinuxNextFile                    // RET   result
614(
615   TXLIN_FFINFO       *ffi,                     // IN    TX filefind handle
616   TXFILEFIND         *found                    // OUT   found file details
617)
618{
619   ULONG               rc = NO_ERROR;           // function return
620   struct stat         f;
621   struct dirent      *dent;                    // one directory entry
622   TXLN                filename;                // full filename
623
624   ENTER();
625   TRACES(( "Linux NextFile handle: 0x%lx  path: '%s' wildcard: '%s'\n",
626             ffi->dir, ffi->dirname, ffi->wildcard));
627   do
628   {
629      memset( found, 0, sizeof(TXFILEFIND));    // reset before EVERY file!
630      memset( &f,    0, sizeof(struct stat));   // just in case ...
631
632      TRACES(( "read next dir entry using DIR handle: %8.8lx\n", ffi->dir));
633      if ((ffi->dir != 0) && ((dent = readdir( ffi->dir)) != NULL))
634      {
635         strcpy( found->fName, dent->d_name);
636         strcpy( filename, ffi->dirname);
637         strcat( filename, found->fName);
638
639         if (stat( filename, &f) == NO_ERROR)
640         {
641            if (S_ISDIR(f.st_mode))             // is it a directory ?
642            {
643               found->fAttr |= FATTR_DIRECTORY;
644            }
645            if ((f.st_mode & S_IWRITE) == 0)
646            {
647               found->fAttr |= FATTR_READONLY;
648            }
649            found->fSize  = (ULONG) f.st_size;
650         }
651         else if ((errno == EFBIG) ||            // must be a large-file
652                  (errno == EOVERFLOW))
653         {
654            TRACES(( "stat errno %d on large-file '%s'\n", errno, filename));
655            TxFileSize( filename, &(found->fSize)); // get real size
656         }
657         else                                   // DIR-entry invalid ??
658         {
659            TRACES(( "stat errno %d on '%s'\n", errno, filename));
660            rc = ERROR_NO_MORE_FILES;
661         }
662         found->aTime = f.st_atime;
663         found->wTime = f.st_mtime;
664         found->cTime = f.st_ctime;
665      }
666      else
667      {
668         TRACES(( "readdir error %d on '%s'\n", errno, ffi->dirname));
669         rc = ERROR_NO_MORE_FILES;
670      }
671   } while ((rc == NO_ERROR) && (TxStrWcmp(found->fName, ffi->wildcard) < 0));
672
673   TRARGS(("ffi IN: %8.8lx, fName OUT: '%s'\n", ffi, found->fName));
674   RETURN (rc);
675}                                               // end 'TxLinuxNextFile'
676/*---------------------------------------------------------------------------*/
677
678#endif
679
680/*****************************************************************************/
681// Close FindFirst/FindNext session for specified handle
682/*****************************************************************************/
683ULONG TxFindClose                               // RET   result
684(
685   TXHANDLE            handle                   // IN    filefind handle
686)
687{
688   ULONG               rc = NO_ERROR;           // function return
689
690   ENTER();
691   TRARGS(("handle: %8.8lx\n", handle));
692
693   if (handle != 0)
694   {
695      #if defined (WIN32)
696         rc = (ULONG) FindClose( (HANDLE) handle);
697      #elif defined (DOS32)
698         _findclose( (long) handle);
699      #elif defined (LINUX)
700         TXLIN_FFINFO  *ffi = (TXLIN_FFINFO *) handle;
701         rc = (ULONG) closedir( ffi->dir);
702         TxFreeMem( ffi);
703      #else
704         rc = (ULONG) DosFindClose( handle);
705      #endif
706   }
707   else
708   {
709      rc = TX_INVALID_HANDLE;
710   }
711   RETURN (rc);
712}                                               // end 'TxFindClose'
713/*---------------------------------------------------------------------------*/
714
715
716/*****************************************************************************/
717// Simple (example) callback for FileTree, listing files date/attr/full-name
718/*****************************************************************************/
719ULONG txFileTreeOneFile
720(
721   char               *fname,                   // IN    full filename
722   TXFILEFIND         *finfo,                   // IN    file information
723   v