/* File name:	LONGPATH.C	*/
/*
 * dirread.c dated 08/22/95
 *
 * Author:
 * Thomas Binder
 * (binder@rbg.informatik.th-darmstadt.de)
 *
 * Purpose:
 * Example program for correct use of alternative
 * file systems, independent of the operating
 * system currently used (it should be TOS-
 * compatible, of course). DirRead reads the
 * directory given in the commandline and displays
 * the filenames to stdout, one per line (without
 * attributes, as the file would get too long,
 * then).
 *
 * History:
 * (Omitted in the English translation)
 */

/*
 * If your compiler does not provide its own
 * mintbind.h for the new GEMDOS functions, you
 * have to build this file yourself, e.g. containing
 * #defines for the new calls
 */
#include <mintbind.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
 * Some mintbind.h (not the one that comes with
 * the MiNTLib) already define the error codes.
 * In that case, you'll have to remove the
 * following #include. If you don't have such a
 * file at all, build it yourself using the
 * constants found e.g. in the compendium (or in
 * table 2 of the article ;)
 */
#include <atarierr.h>
/*
 * portab.h is a file that comes with Pure C. It
 * defines WORD, LONG, UWORD, ULONG, etc. to be
 * independent of the sizeof(int) a compiler
 * uses.
 */
#include <portab.h>

/*
 * The following two constants determine how
 * long a filename (DFLT_MAXFLEN) and how long
 * a path (DFLT_MAXPLEN) may be at max if
 * Dpathconf() is not available or returns
 " "unlimited".
 */
#define DFLT_MAXFLEN    64
#define DFLT_MAXPLEN    512

#define VERSION         "V1.05 dated 08/22/95"

/* Prototypes */
WORD rel2abs(char *path, char **destpath);
WORD d_getcwd(char *buf, WORD drive, WORD len);
void usage(void);

WORD main(WORD argc, char *argv[])
{
    LONG    maxflen,
            dirh;
    WORD    rootdrive = -1,
            count = 0,
            err;
    char    *unixmode,
            *argument,
            *setpath,
            *namebuf,
            newdrive,
            *r;
#ifdef __MINT__
    _DTA
#else
    DTA
#endif
            my_dta,
            *olddta;

/* Display usage if number of parameters if wrong */
    if (argc != 2)
    {
        usage();
        return(2);
    }
/* Switch to MiNT-domain */
    Pdomain(1);
/*
 * Take the given path and transform it into an
 * absolute one, i.e. of the form X:\...\
 */
    if ((err = rel2abs(argv[1], &argument)) != 0)
    {
    puts("DirRead: Error calling rel2abs!");
        return(err);
    }
/*
 * Now, evaluate $UNIXMODE. If it contains rX, X
 * will be the default drive (if it's known to
 * GEMDOS)
 */
    if ((unixmode = getenv("UNIXMODE")) != NULL)
    {
        if ((r = strchr(unixmode, 'r')) != NULL)
        {
            newdrive = r[1];
            if ((newdrive >= 'A') &&
                (newdrive <= 'Z'))
            {
                newdrive -= 'A';
                if (Dsetdrv(Dgetdrv()) &
                    (1L << (LONG)newdrive))
                {
                    rootdrive = (WORD)newdrive;
                    Dsetdrv(rootdrive);
                }
            }
        }
    }
/*
 * Start reading the directory. First, try it with
 * Dopendir(). If that's available, Dreaddir() and
 * Dclosdir() must be available, too, as it wouldn't
 * make any sense if not. If Dopendir() is not
 * supported, though, Fsfirst()/next() have to be
 * used instead.
 */
    if ((dirh = Dopendir(".", 0)) == EINVFN)
    {
        olddta = Fgetdta();
        Fsetdta(&my_dta);
        strcat(argument, "*.*");
        err = Fsfirst(argument, 0x17);
        while (!err)
        {
            count++;
#ifdef __MINT__
            puts(my_dta.dta_name);
#else
            puts(my_dta.d_fname);
#endif
            err = Fsnext();
        }
        if (err == EPTHNF)
        {
            printf("DirRead: Directory %s is not "
                "reachable!\n", argument);
            free(argument);
            return(err);
        }
        Fsetdta(olddta);
    }
    else
    {
        if ((dirh & 0xff000000L) != 0xff000000L)
            Dclosedir(dirh);
/*
 * In case Dopendir() & Co. are available, first
 * try to determine the maximum filename length
 * in the directory. Therefore, change to this
 * directory and call Dpathconf() on ".". If
 * there was a root drive supplied by $UNIXMODE,
 * change the path: X:\foo gets \X\foo, so that
 * the actual drive is accessed as a subdirectory
 * of the root drive. Of course, the transformation
 * must not take place if X is already the root
 * drive ...
 */
        if ((rootdrive >= 0) && (argument[0] !=
            ((char)rootdrive + 65)))
        {
            argument[1] = argument[0] | 32;
            argument[0] = '\\';
            setpath = argument;
        }
        else
        {
            Dsetdrv((WORD)argument[0] - 65);
            setpath = &argument[2];
        }
        if ((err = Dsetpath(setpath)) < 0)
        {
            printf("DirRead: Directory %s is not "
                "reachable!\n", argument);
            free(argument);
            return(err);
        }
        if (Dpathconf(".", -1) >= 3L)
        {
            maxflen = Dpathconf(".", 3);
            if (maxflen == 0x7fffffffL)
                maxflen = DFLT_MAXFLEN;
        }
/*
 * Increase maxflen by 5 due to the file index
 * and \0
 */
        maxflen += 5;
/* Allocate memory for the filename buffer */
        if ((namebuf = malloc(maxflen)) == NULL)
        {
            puts("DirRead: Not enough memory!");
            free(argument);
            return(ENSMEM);
        }
/* Open the directory */
        dirh = Dopendir(argument, 0);
        if ((dirh & 0xff000000L) == 0xff000000L)
        {
            printf("DirRead: Directory %s is not "
                "reachable!\n", argument);
            free(namebuf);
            free(argument);
            return((WORD)dirh);
        }
/*
 * After successfully opening the directory, read
 * filenames with Dreaddir() until it returns an
 * error. If the error is ERANGE, the filename
 * buffer is too small for the current name (this
 * should only happen if we had to use
 * DFLT_MAXFLEN) and we can safely continue reading.
 * In all other error situations, stop reading.
 */
        for (;;)
        {
            if ((err = (WORD)Dreaddir((WORD)
                maxflen, dirh, namebuf)) != 0L)
            {
                if (err == ERANGE)
                {
                    puts("*** Filename too long ***");
                    continue;
                }
                else
                    break;
            }
            count++;
            puts(&namebuf[4]);
        }
/* Important: Don't forget Dclosedir()! */
        Dclosedir(dirh);
        free(namebuf);
    }
    if (count)
        printf("%u files\n", count);
    else
        puts("No files!");
    free(argument);
    return(0);
}

/*
 * rel2abs
 *
 * Transforms a possibly relative path in to an
 * absoute one (X:\...\), without paying attention
 * if the given path exists or is really a
 * directory. Memory for the absolute path is
 * automatically allocated, the caller is then
 * responsible to free it. rel2abs tries to
 * remove as many path errors (like multiple
 * backslashes) as possible, but of course it's
 * helpless on totally senseless input.
 *
 * Input:
 * path: Pointer to the original path, which may
 *       be relative and may contain "." and ".."
 *       components
 * destpath: Pointer to a pointer for the new
 *           path. On successful transformation,
 *           the pointer to the malloc()ed
 *           memory block is stored here. In
 *           case an error occured, destpath will
 *           be set to NULL.
 *
 * Return:
 * 0: Everything OK, destpath contains pointer to
 *    the transformed path
 * otherwise: GEMDOS error code, destpath points
 *            to NULL
 */
WORD rel2abs(char *path, char **destpath)
{
    char    *act_path,
            *temp,
            *pos,
            *next,
            rootdir[4] = "x:\\";
    WORD    drive,
            err;
    LONG    maxplen;

/*
 * If path contains a drive letter, extract it,
 * otherwise determine the current drive
 */
    if (path[1] == ':')
    {
        drive = (path[0] & ~32) - 65;
        pos = &path[2];
    }
    else
    {
        if ((drive = Dgetdrv()) < 0)
            return(drive);
        pos = path;
    }
/*
 * Try to get the maximum path length for
 * the root directory of the affected drive.
 */
    rootdir[0] = (drive + 65);
    if (Dpathconf(rootdir, -1) >= 2)
    {
        maxplen = Dpathconf(rootdir, 2);
        if (maxplen == 0x7fffffffL)
            maxplen = DFLT_MAXPLEN;
    }
    else
        maxplen = DFLT_MAXPLEN;
/*
 * Add two bytes for the trailing backslash
 * and \0 for EOS
 */
    maxplen += 2;
/*
 * Allocated memory for two path buffers, this
 * also yields the address which is stored in
 * destpath
 */
    if ((*destpath = temp = malloc(maxplen * 2L))
        == NULL)
    {
        return(ENSMEM);
    }
/* Get the current path of the drive */
    act_path = (char *)((LONG)temp + maxplen);
    if ((err = d_getcwd(act_path, drive + 1,
        (WORD)maxplen)) < 0)
    {
        free(temp);
        *destpath = NULL;
        return(err);
    }
/* Remove traling backslash, if necessary */
    if (*act_path && (act_path[strlen(act_path) - 1] ==
        '\\'))
    {
        act_path[strlen(act_path) - 1] = 0;
    }
/*
 * Create beginning of the absolute path. If path
 * wasn't absolute, use the current path.
 * Otherwise, skip additional leading backslashes.
 */
    sprintf(temp, "%c:", drive + 65);
    if (*pos != '\\')
        strcat(temp, act_path);
    else
        for (; *pos && (*pos == '\\'); pos++);
/*
 * The rest of the path is now split into
 * components (from the current position up
 * to the next backslash). Is the current
 * component ".", it'll be ignored as it
 * stands for the same directory. ".." will
 * remove the last added component (only
 * if there are components to be removed
 * at all). Again, multiple backslashes will
 * be skipped.
 */
    next = pos;
    while ((next != NULL) && *pos)
    {
        if ((next = strchr(pos, '\\')) != NULL)
            for(; *next && (*next == '\\'); *next++ = 0);
        if (!strcmp(pos, ".."))
        {
            if (strlen(temp) > 2)
                *strrchr(temp, '\\') = 0;
        }
        else
        {
            if (strcmp(pos, "."))
            {
                strcat(temp, "\\");
                strcat(temp, pos);
            }
        }
        if (next != NULL)
            pos = next;
    }
/*
 * After the transformation, terminate the new
 * path with a backslash, to signal it's a
 * directory. There's no check if that's
 * really true, i.e. the created path may
 * be a file or may even not exist at all.
 * If you want to add the backslash only if
 * the new path is an existing directory,
 * use Fxattr() (or Fsfirst(), if the other
 * function is not available) and check the
 * return code and the attributes.
 */
    strcat(temp, "\\");
    return(0);
}

/*
 * d_getcwd
 *
 * Just like Dgetcwd(), but uses Dgetpath()
 * automatically when Dgetcwd() isn't available
 * (of course, in this case you can only pray
 * that buf is large enough as len will be
 * ignored). Dgetpath() is also used if
 * Dgetcwd() returned EDRIVE. This is due to a
 * problem in connection with MetaDOS, which
 * does not offer Dgetcwd(), so that this call
 * is directly passed to the underlying GEMDOS
 * which of course does not know about this
 * drive at all.
 *
 * Input:
 * buf: Pointer to buffer to which the current
 *      path should be copied
 * drive: The drive for which the current path
 *        should be determined (0 = current,
 *        (1 = A, 2 = B, etc.)
 * len: Maximum number of characters which can
 *      be copied into buf
 *
 * Return:
 * Return value of Dgetcwd() or Dgetpath()
 */
WORD d_getcwd(char *buf, WORD drive, WORD len)
{
    LONG    err;

    err = Dgetcwd(buf, drive, len);
    if ((err != EINVFN) && (err != EDRIVE))
    {
        return((WORD)err);
    }
    return(Dgetpath(buf, drive));
}

/*
 * usage
 *
 * Displays usage of DirRead.
 */
void usage(void)
{
    puts("DirRead "VERSION);
    puts("Geschrieben in Pure C von "
        "Thomas Binder");
    puts("\nAufruf: dirread Verzeichnis");
}


--=-=-=__xYJLtEXCTLRxeXREcsWURTDZ9__=-=-=

Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: attachment; filename="dirtest.c"

#include <stdio.h>
#include <stdlib.h>
#ifdef __MINT__
#include <unistd.h>
#include <fcntl.h>
typedef struct xattr
{
    unsigned int    mode;
    long            index;
    unsigned int    dev;
    unsigned int    rdev;
    unsigned int    nlink;
    unsigned int    uid;
    unsigned int    gid;
    long            size;
    long            blksize, nblocks;
    int             mtime, mdate;
    int             atime, adate;
    int             ctime, cdate;
    int             attr;
    int             reserved2;
    long            reserved3[2];
} XATTR;
#endif
#include <mintbind.h>
#include <portab.h>

#define MAX_CONF    8
#define MAX_TRUNC    2
#define MAX_CASE    2

typedef struct
{
    ULONG    bitmask;
    char    *identifier;
} COMPARE;

void print_date(UWORD gemdos_date);
void print_time(UWORD gemdos_time);

WORD main(WORD argc, char *argv[])
{
#ifdef __MINT__
    _CCONLINE    input;
#else
    LINE        input;
#endif
    LONG        value;
    char        *conf_name[] = {
                    "Maximum number of open files: ",
                    "Maximum number of links to a file: ",
                    "Maximum path length: ",
                    "Maximum filename length: ",
                    "Size of an atomic write: ",
                    "Filename truncation: ",
                    "Case sensitivity: ",
                    "Allowed attributes and filetypes: ",
                    "Supported XATTR-fields: "},
                *trunc_name[] = {
                    "No truncation\n",
                    "Truncation to maximum length\n",
                    "8+3-truncation\n"},
                *case_name[] = {
                    "Fully case sensitive\n",
                    "Case insensitive, case is preserved\n",
                    "Case insensitive, case is altered\n"},
                linkdest[256];
    COMPARE        tosattr[] = {
                    1,        "Readonly",
                    2,        "Hidden",
                    4,        "System",
                    8,        "Label",
                    16,        "Directory",
                    32,        "Changed",
                    64,        "(Bit 6)",
                    128,    "(Bit 7)",
                    0,                NULL},
                unixattr[] = {
                    04000L << 8L,    "SetUID",
                    02000L << 8L,    "SetGID",
                    01000L << 8L,    "Sticky",
                    0400L << 8L,    "RUSR",
                    0200L << 8L,    "WUSR",
                    0100L << 8L,    "XUSR",
                    040L << 8L,        "RGRP",
                    020L << 8L,        "WGRP",
                    010L << 8L,        "XGRP",
                    04L << 8L,        "ROTH",
                    02L << 8L,        "WOTH",
                    01L << 8L,        "XOTH",
                    0,                NULL},
                filetypes[] = {
                    0x00100000L,    "Dir",
                    0x00200000L,    "Char",
                    0x00400000L,    "Block",
                    0x00800000L,    "Regular",
                    0x01000000L,    "Symlink",
                    0x02000000L,    "Socket",
                    0x04000000L,    "FIFO",
                    0x08000000L,    "Memory",
                    0x10000000L,    "(Bit 28)",
                    0x20000000L,    "(Bit 29)",
                    0x40000000L,    "(Bit 30)",
                    0x80000000L,    "(Bit 31)",
                    0,                NULL},
                xattrfields[] = {
                    0x0001L,    "index",
                    0x0002L,    "dev",
                    0x0004L,    "rdev",
                    0x0008L,    "nlink",
                    0x0010L,    "uid",
                    0x0020L,    "gid",
                    0x0040L,    "blksize",
                    0x0080L,    "size",
                    0x0200L,    "nblocks",
                    0x0400L,    "atime",
                    0x0400L,    "ctime",
                    0x0800L,    "mtime",
                    0x1000L,    "(Bit 12)",
                    0x2000L,    "(Bit 13)",
                    0x4000L,    "(Bit 14)",
                    0x8000L,    "(Bit 15)",
                    0,                NULL};
    WORD        i,
                j,
                k,
                des,
                mode,
                one;
    LONG        max_mode;
    XATTR        attribs;

    if (Dpathconf("U:\\", -1) == -32L)
    {
        puts("Dpathconf() not available!");
        return(1);
    }
    if (argc <= 1)
    {
        Cconws("Enter test directory: ");
        input.maxlen = 254;
        Cconrs(&input);
        input.buffer[input.actuallen] = 0;
        argc = 2;
        argv[1] = input.buffer;
    }
    for (i = 1; i < argc; i++)
    {
        printf("\nInformation for: %s\n", argv[i]);
        if ((max_mode = Dpathconf(argv[i], -1)) < 0)
        {
            puts("None available! (Error)");
            goto get_xattr;
        }
        printf("Highest supported Dpathconf()modes: %ld\n", max_mode);
        for (j = 0; j <= (WORD)max_mode; j++)
        {
            if (j <= MAX_CONF)
                printf(conf_name[j]);
            else
                printf("Mode %d: ", j);
            value = Dpathconf(argv[i], j);
            if (value < 0)
                puts("Couldn't be determined! (Error)");
            else
            {
                switch (j)
                {
                    case 5:
                        if (value > MAX_TRUNC)
                            printf("%ld (0x%lx)\n", value, value);
                        else
                            printf(trunc_name[value]);
                        break;
                    case 6:
                        if (value > MAX_CASE)
                            printf("%ld (0x%lx)\n", value, value);
                        else
                            printf(case_name[value]);
                        break;
                    case 7:
                        one = 0;
                        printf("  GEMDOS-attributes: ");
                        for (k = 0; tosattr[k].identifier; k++)
                        {
                            if (value & tosattr[k].bitmask)
                            {
                                if (one)
                                    printf(", ");
                                printf(tosattr[k].identifier);
                                one = 1;
                            }
                        }
                        if (!one)
                            printf("None!");
                        puts("");
                        one = 0;
                        printf("  UNIX-attributes: ");
                        for (k = 0; unixattr[k].identifier; k++)
                        {
                            if (value & unixattr[k].bitmask)
                            {
                                if (one)
                                    printf(", ");
                                printf(unixattr[k].identifier);
                                one = 1;
                            }
                        }
                        if (!one)
                            printf("None!");
                        puts("");
                        one = 0;
                        printf("  Filetypes: ");
                        for (k = 0; filetypes[k].identifier; k++)
                        {
                            if (value & filetypes[k].bitmask)
                            {
                                if (one)
                                    printf(", ");
                                printf(filetypes[k].identifier);
                                one = 1;
                            }
                        }
                        if (!one)
                            printf("None!");
                        puts("");
                        break;
                    case 8:    
                        one = 0;
                        for (k = 0; xattrfields[k].identifier; k++)
                        {
                            if (value & xattrfields[k].bitmask)
                            {
                                if (one)
                                    printf(", ");
                                printf(xattrfields[k].identifier);
                                one = 1;
                            }
                        }
                        if (!one)
                            printf("None!");
                        puts("");
                        break;
                    default:
                        if (value == 0x7fffffffL)
                            puts("Unlimited");
                        else
                        {
                            printf("%ld (0x%lx, %#lo)\n", value,
                                value, value);
                        }
                        break;
                }
            }
        }
get_xattr:
        printf("\nFxattr()-result for %s:\n", argv[i]);
        if (Fxattr(1, argv[i], &attribs) != 0)
        {
            puts("Failed!");
            continue;
        }
        switch ((mode = (attribs.mode & 0170000)))
        {
            case 020000:
                puts("BIOS-special");
                break;
            case 040000:
                puts("Directory");
                break;
            case 0100000:
                puts("Regular File");
                break;
            case 0120000:
                puts("FIFO");
                break;
            case 0140000:
                puts("Memory block or process file");
                break;
            case 0160000:
                printf("Symbolic link ");
                if (Freadlink(256, linkdest, argv[i]) != 0)
                 puts ("- destination couldn't be determined!");
                else
                 printf("to %s\n", linkdest);
                break;
            default:
                printf("Unknown type %d (0x%x, %#o)\n",
                    mode, mode, mode);
                break;
        }
        printf("Access rights: %#04o\n", attribs.mode & ~0170000);
        printf("Device: %d\n", attribs.dev);
        printf("(BIOS-Device: %d)\n", attribs.rdev);
        printf("Number of hardlinks: %d\n", attribs.nlink);
        printf("Last inode modification: ");
        print_date(attribs.cdate);
        printf(", ");
        print_time(attribs.ctime);
        puts("");
        printf("Last modification: ");
        print_date(attribs.mdate);
        printf(", ");
        print_time(attribs.mtime);
        puts("");
        printf("Last access: ");
        print_date(attribs.adate);
        printf(", ");
        print_time(attribs.atime);
        puts("");
        if ((des = open(argv[i], O_WRONLY)) < 0)
            puts("Can't be opened as a file!");
        else
        {
            if (isatty(des))
                puts("File represents a terminal.");
            close(des);
        }
    }
    return(0);
}

void print_date(UWORD gemdos_date)
{
    UWORD    day, month, year;

    day = gemdos_date & 31;
    month = (gemdos_date >> 5) & 15;
    year = (gemdos_date >> 9) + 1980;
    printf("%02d/%02d/%04d", month, day, year);
}

void print_time(UWORD gemdos_time)
{
    UWORD    h, m, s;

    s = (gemdos_time & 31) * 2;
    m = (gemdos_time >> 5) & 63;
    h = gemdos_time >> 11;
    printf("%02d:%02d:%02d", h, m, s);
}


--=-=-=__xYJLtEXCTLRxeXREcsWURTDZ9__=-=-=

Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: attachment; filename="system.c"

/*
 * This is part of Thing. dir_check descends a given directory and counts
 * all files, links and directories it encounters. No comments here, as I'm
 * already tired after translating the comments in dirread.c ...
 */

static int build_filename(char *dst, char *a, char *b);

static int build_filename(char *dst, char *a, char *b)
{
 if ((strlen(a) + strlen(b)) < (long)MAX_PLEN)
 {
  strcpy(dst, a);
  strcat(dst, b);
  return(0);
 }
 else
 {
  frm_alert(1,rs_frstr[ALRECURS],altitle,conf.wdial,0L);
  return(1);
 }
}

int dir_check(char *path,int *nfiles,int *nfolders,long *size,
 int *nlinks,int follow,int sub)
{
 int fret,
  xread,
  len;
 static XATTR xattr;
 DTA *old_dta,
  mydta;
 long dirh,
  xfret;
 char fpath[MAX_PLEN];
 static char fname[MAX_FLEN + 4];
 char xname[MAX_PLEN];
 char *p;

 if (sub > 16)
 {
  frm_alert(1,rs_frstr[ALRECURS],altitle,conf.wdial,0L);
  return(1);
 }
 strcpy(fpath, path);
 len = (int)strlen(fpath);
 if (!len)
  return(1);
 if ((fpath[len - 1] == '\\') && (len > 3))
  fpath[len - 1] = 0;
 if (len > 3)
 {
  fret = file_exists(fpath, follow, &xattr);
  if (fret)
  {
   err_file(rs_frstr[ALPREAD], (long)fret, fpath);
   return(fret);
  }
  xattr.mode &= S_IFMT;
  if (xattr.mode != S_IFDIR)
  {
   *size += xattr.size;
   (*nfiles)++;
   if (xattr.mode == S_IFLNK)
    (*nlinks)++;
   return(0);
  }
  (*nfolders)++;
 }
 if (sub == -1)
  return(0);
 dirh = Dopendir(fpath, 0);
 strcat(fpath, "\\");
 if (dirh != -32L)
 {
  if ((dirh & 0xff000000L) == 0xff000000L)
  {
   err_file(rs_frstr[ALPREAD], dirh, fpath);
   return((int)dirh);
  }
 }
 fret = 0;
 if (dirh != -32L)
 {
  xread = 1;
  while (fret == 0)
  {
   if (xread)
    fret = (int)Dxreaddir(MAX_FLEN + 4, dirh, fname, &xattr, &xfret);
   if (follow || !xread || (fret == -32L))
   {
    if (!xread || (fret == -32L))
    {
     xread = 0;
     fret = (int)Dreaddir(MAX_FLEN + 4, dirh, fname);
     if (fret)
      break;
    }
    else
    {
     if (fret)
      break;
    }
    if ((fret = build_filename(xname, fpath, &fname[4])) != 0)
     break;
    xfret = Fxattr(!follow, xname, &xattr);
   }
   if (fret)
    break;
   if (xfret)
   {
    fret = (int)xfret;
    break;
   }
   xattr.mode &= S_IFMT;
   if (xattr.mode == S_IFDIR)
   {
    if (!strcmp(&fname[4], ".") || !strcmp(&fname[4], ".."))
     continue;
    if ((fret = build_filename(xname, fpath, &fname[4])) != 0)
     break;
    fret = dir_check(xname, nfiles, nfolders, size, nlinks, follow,
     sub + 1);
    if (fret)
    {
     fret = 1;
     break;
    }
   }
   else
   {
    (*nfiles)++;
    if (xattr.mode == S_IFLNK)
     (*nlinks)++;
    *size += xattr.size;
   }
  }
  Dclosedir(dirh);
 }
 else
 {
  len = (int)strlen(fpath);
  strcat(fpath, "*.*");
  old_dta = Fgetdta();
  Fsetdta(&mydta);
  for (fret = Fsfirst(fpath, 0x17); fret == 0; fret = Fsnext())
  {
   if (mydta.d_attrib & FA_SUBDIR)
   {
    if (!strcmp(mydta.d_fname, ".") || !strcmp(mydta.d_fname, ".."))
     continue;
    fpath[len] = 0;
    if ((fret = build_filename(xname, fpath, mydta.d_fname)) != 0)
     break;
    fpath[len] = '*';
    fret = dir_check(xname, nfiles, nfolders, size, nlinks, follow,
     sub + 1);
    if (fret)
    {
     fret = 1;
     break;
    }
   }
   else
   {
    (*nfiles)++;
    *size += mydta.d_length;
   }
  }
  fpath[len] = 0;
  Fsetdta(old_dta);
 }
 if(fret && (fret != -49) && (fret != -33))
 {
  if(fret != 1)
  {
   p = strrchr(fname, '\\');
   if (p)
    *p = 0;
   err_file(rs_frstr[ALPREAD],(long)fret,fname);
   if (p)
    *p = '\\';
  }
 }
 else fret=0;
 return(fret);
}
/* End of file:	LONGPATH.C	*/
