home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / gcc / config / winnt / dirent.c < prev    next >
C/C++ Source or Header  |  1995-12-11  |  6KB  |  361 lines

  1. /*
  2.  * @(#)msd_dir.c 1.4 87/11/06    Public Domain.
  3.  *
  4.  *  A public domain implementation of BSD directory routines for
  5.  *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  6.  *  August 1897
  7.  *
  8.  *  Modified by Ian Stewartson, Data Logic (istewart@datlog.co.uk).
  9.  *
  10.  *  Updates:  1.  To support OS/2 1.x
  11.  *          2.  To support HPFS long filenames
  12.  *          3.  To support OS/2 2.x
  13.  *          4.  To support TurboC
  14.  *          5.  To support Windows NT
  15.  */
  16.  
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21.  
  22. #include <malloc.h>
  23.  
  24. #include <string.h>
  25. #include <limits.h>
  26. #include <ctype.h>
  27. #include <errno.h>
  28. #include <dirent.h>
  29.  
  30.  
  31. #define WIN32_LEAN_AND_MEAN
  32. #include <windows.h>
  33.  
  34. #define FILE_NAME_E        cFileName
  35. #define OS_CloseFH(a)        FindClose (a)
  36. #define FIND_BUFFER        WIN32_FIND_DATA
  37. #define DISABLE_HARD_ERRORS    SetErrorMode (0)
  38. #define ENABLE_HARD_ERRORS    SetErrorMode (SEM_FAILCRITICALERRORS | \
  39.                           SEM_NOOPENFILEERRORBOX);
  40.  
  41. #  define ERROR_EMPTY_DIR    ERROR_FILE_NOT_FOUND
  42.  
  43. #  define ATTRIBUTES        (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
  44.                  _A_NORMAL | _A_RDONLY | _A_ARCH)
  45.  
  46. /*
  47.  * missing ??
  48.  */
  49.  
  50. #ifndef ENOTDIR
  51. #  define ENOTDIR    120    /* Not a directory            */
  52. #endif
  53.  
  54. #ifndef S_IFMT
  55. #  define    S_IFMT    0xf000    /* type of file                */
  56. #endif
  57.  
  58. #ifndef S_ISDIR
  59. #  define S_ISDIR(m)    ((((m) & S_IFMT) == S_IFDIR))
  60. #endif
  61.  
  62. /*
  63.  * Internals
  64.  */
  65.  
  66. typedef struct _dircontents    DIRCONT;
  67. static void            free_dircontents (DIRCONT *);
  68.  
  69. /*
  70.  * Open the directory stream
  71.  */
  72.  
  73. DIR *
  74. opendir (name)
  75.     const char    *name;
  76. {
  77.     struct stat        statb;
  78.     DIR            *dirp;
  79.     char        *last;
  80.     DIRCONT        *dp;
  81.     char        *nbuf;
  82.     int            len = strlen (name);
  83.     unsigned long    rc;
  84.     FIND_BUFFER        dtabuf;
  85.     HANDLE        d_handle;
  86.     bool        HPFS = FALSE;
  87.  
  88.     if (!len)
  89.     {
  90.     errno = ENOTDIR;
  91.     return (DIR *)NULL;
  92.     }
  93.  
  94.     if ((nbuf = malloc (len + 5)) == (char *)NULL)
  95.     return (DIR *) NULL;
  96.  
  97.     strcpy (nbuf, name);
  98.     last = &nbuf[len - 1];
  99.  
  100. /* Ok, DOS is very picky about its directory names.  The following are
  101.  * valid.
  102.  *
  103.  *  c:/
  104.  *  c:.
  105.  *  c:name/name1
  106.  *
  107.  *  c:name/ is not valid
  108.  */
  109.  
  110.     if (((*last == '\\') || (*last == '/')) && (len > 1) &&
  111.     (!((len == 3) && (name[1] == ':'))))
  112.     *(last--) = 0;
  113.  
  114. /* Check its a directory */
  115.  
  116.     DISABLE_HARD_ERRORS;
  117.     rc = stat (nbuf, &statb);
  118.     ENABLE_HARD_ERRORS;
  119.  
  120.     if (rc)
  121.     {
  122.     free (nbuf);
  123.     return (DIR *) NULL;
  124.     }
  125.  
  126.     if (!S_ISDIR (statb.st_mode))
  127.     {
  128.     free (nbuf);
  129.     errno = ENOTDIR;
  130.     return (DIR *)NULL;
  131.     }
  132.  
  133.     if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
  134.     {
  135.     free (nbuf);
  136.     return (DIR *) NULL;
  137.     }
  138.  
  139. /* Set up to find everything */
  140.  
  141.     if ((*last != '\\') && (*last != '/'))
  142.     strcat (last, "/");
  143.  
  144.     strcat (last, "*.*");
  145.  
  146. /* Find the file system type */
  147.  
  148.     HPFS = IsHPFSFileSystem (nbuf);
  149.  
  150.     dirp->dd_loc      = 0;
  151.     dirp->dd_cp       = (DIRCONT *) NULL;
  152.     dirp->dd_contents = (DIRCONT *) NULL;
  153.  
  154.     DISABLE_HARD_ERRORS;
  155.  
  156.     d_handle = FindFirstFile (nbuf, &dtabuf);
  157.     rc = (d_handle == INVALID_HANDLE_VALUE) ? GetLastError () : 0;
  158.  
  159.     ENABLE_HARD_ERRORS;
  160.  
  161. /* Check for errors */
  162.  
  163.     if (rc)
  164.     {
  165.     free (nbuf);
  166.  
  167. /* Empty directory */
  168.  
  169. #if defined (ERROR_EMPTY_DIR)
  170.     if (rc == ERROR_EMPTY_DIR)
  171.         return dirp;
  172. #endif
  173.  
  174.     free (dirp);
  175.     return (DIR *) NULL;
  176.     }
  177.  
  178. /* Process the directory */
  179.  
  180.     do
  181.     {
  182.     if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
  183.         ((dp->_d_entry = strdup (dtabuf.FILE_NAME_E)) == (char *) NULL))
  184.     {
  185.         if (dp->_d_entry != (char *)NULL)
  186.         free ((char *)dp);
  187.  
  188.         free (nbuf);
  189.         free_dircontents (dirp->dd_contents);
  190.  
  191.         OS_CloseFH (d_handle);
  192.         return (DIR *) NULL;
  193.     }
  194.  
  195.     if (!HPFS)
  196.         strlwr (dp->_d_entry);
  197.  
  198.     if (dirp->dd_contents != (DIRCONT *) NULL)
  199.         dirp->dd_cp = dirp->dd_cp->_d_next = dp;
  200.  
  201.     else
  202.         dirp->dd_contents = dirp->dd_cp = dp;
  203.  
  204.     dp->_d_next = (DIRCONT *) NULL;
  205.  
  206.     } while (FindNextFile (d_handle, &dtabuf));
  207.  
  208.     dirp->dd_cp = dirp->dd_contents;
  209.     free (nbuf);
  210.  
  211.     OS_CloseFH (d_handle);
  212.     return dirp;
  213. }
  214.  
  215.  
  216. /*
  217.  * Close the directory stream
  218.  */
  219.  
  220. int
  221. closedir (dirp)
  222.     DIR *dirp;
  223. {
  224.     if (dirp != (DIR *)NULL)
  225.     {
  226.     free_dircontents (dirp->dd_contents);
  227.     free ((char *)dirp);
  228.     }
  229.  
  230.     return 0;
  231. }
  232.  
  233. /*
  234.  * Read the next record from the stream
  235.  */
  236.  
  237. struct dirent *
  238. readdir (dirp)
  239.     DIR    *dirp;
  240. {
  241.     static struct dirent    dp;
  242.  
  243.     if ((dirp == (DIR *)NULL) || (dirp->dd_cp == (DIRCONT *) NULL))
  244.     return (struct dirent *) NULL;
  245.  
  246.     dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
  247.     dp.d_off    = dirp->dd_loc * 32;
  248.     dp.d_ino    = (ino_t)++dirp->dd_loc;
  249.     dirp->dd_cp = dirp->dd_cp->_d_next;
  250.  
  251.     return &dp;
  252. }
  253.  
  254. /*
  255.  * Restart the directory stream
  256.  */
  257.  
  258. void
  259. rewinddir (dirp)
  260.     DIR *dirp;
  261. {
  262.     seekdir (dirp, (off_t)0);
  263. }
  264.  
  265. /*
  266.  * Move to a know position in the stream
  267.  */
  268.  
  269. void
  270. seekdir (dirp, off)
  271.     DIR *dirp;
  272.     off_t off;
  273. {
  274.     long    i = off;
  275.     DIRCONT    *dp;
  276.  
  277.     if ((dirp == (DIR *)NULL) || (off < 0L))
  278.     return;
  279.  
  280.     for (dp = dirp->dd_contents; (--i >= 0) && (dp != (DIRCONT *)NULL);
  281.      dp = dp->_d_next)
  282.     ;
  283.  
  284.     dirp->dd_loc = off - (i + 1);
  285.     dirp->dd_cp = dp;
  286. }
  287.  
  288. /*
  289.  * Get the current position
  290.  */
  291.  
  292. off_t
  293. telldir(dirp)
  294.     DIR *dirp;
  295. {
  296.     return (dirp == (DIR *)NULL) ? (off_t) -1 : dirp->dd_loc;
  297. }
  298.  
  299. /*
  300.  * Release the internal structure
  301.  */
  302.  
  303. static void
  304. free_dircontents (dp)
  305.     DIRCONT *dp;
  306. {
  307.     DIRCONT    *odp;
  308.  
  309.     while ((odp = dp) != (DIRCONT *)NULL)
  310.     {
  311.     if (dp->_d_entry != (char *)NULL)
  312.         free (dp->_d_entry);
  313.  
  314.     dp = dp->_d_next;
  315.     free ((char *)odp);
  316.     }
  317. }
  318.  
  319.  
  320. /*
  321.  * Windows NT version
  322.  */
  323.  
  324. bool
  325. IsHPFSFileSystem (directory)
  326.     char *directory;
  327. {
  328.     char        bName[4];
  329.     DWORD        flags;
  330.     DWORD        maxname;
  331.     BOOL        rc;
  332.     unsigned int    nDrive;
  333.     char        szCurDir [MAX_PATH];
  334.  
  335.     if (isalpha (directory[0]) && (directory[1] == ':'))
  336.     nDrive = toupper (directory[0]) - '@';
  337.  
  338.     else
  339.     {
  340.     GetCurrentDirectory (MAX_PATH, szCurDir);
  341.     nDrive = szCurDir[0] - 'A' + 1;
  342.     }
  343.  
  344. /* Set up the drive name */
  345.  
  346.     strcpy (bName, "x:\\");
  347.     bName[0] = (char) (nDrive + '@');
  348.  
  349. /* Read the volume info, if we fail - assume non-HPFS */
  350.  
  351.     DISABLE_HARD_ERRORS;
  352.  
  353.     rc = GetVolumeInformation (bName, (LPTSTR)NULL, 0, (LPDWORD)NULL,
  354.                    &maxname, &flags, (LPTSTR)NULL, 0);
  355.     ENABLE_HARD_ERRORS;
  356.  
  357.     return ((rc) && (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED)))
  358.             ? TRUE : FALSE;
  359. }
  360.  
  361.