home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl502b.zip / OS2 / lib / dirent.c next >
C/C++ Source or Header  |  1995-04-29  |  9KB  |  390 lines

  1. /*****************************************************************************
  2.  * $Id: dirent2.c,v 1.10 1995/04/28 22:40:36 ak Exp $
  3.  *****************************************************************************
  4.  * $Log: dirent2.c,v $
  5.  * Revision 1.10  1995/04/28  22:40:36  ak
  6.  * Cleanup. Make dirent2 layout compatible to EMX to avoid trouble
  7.  * with include-files. Moved struct defs to implementation.
  8.  *
  9.  * Revision 1.9  1994/11/18  22:39:48  ak
  10.  * Use a request count of 100 to avoid LS20 bug.
  11.  *
  12.  * Revision 1.8  1994/02/17  11:57:06  ak
  13.  * Bugfix upper/lowercase conversion.
  14.  *
  15.  * Revision 1.7  1994/02/14  14:07:26  edvkai
  16.  * Added abs_path (like dirent.c), it's needed in some places.
  17.  *
  18.  * Revision 1.6  1994/02/08  14:59:51  edvkai
  19.  * fstype caching.
  20.  * different buffer sizes.
  21.  * no double slashes
  22.  *
  23.  * Revision 1.5  1994/01/05  13:46:36  edvkai
  24.  * Old openxdir included directories by default, so dirent2 should do as well.
  25.  *
  26.  * Revision 1.4  1994/01/03  12:30:46  edvkai
  27.  * *** empty log message ***
  28.  *
  29.  * Revision 1.3  1994/01/03  12:30:21  edvkai
  30.  * *** empty log message ***
  31.  *
  32.  * Revision 1.2  1993/12/30  18:11:37  edvkai
  33.  * opendir omitted directories.
  34.  *
  35.  * Revision 1.1  1993/12/30  17:58:15  edvkai
  36.  * Initial revision
  37.  *
  38.  *****************************************************************************/
  39.  
  40. #ifdef OS2
  41.  
  42. static char *rcsid = "$Id: dirent2.c,v 1.10 1995/04/28 22:40:36 ak Exp $";
  43.  
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48.  
  49. #include <dirent.h>
  50. #include <errno.h>
  51.  
  52. #ifndef __EMX__
  53. #include <libx.h>
  54. #endif
  55.  
  56. #define INCL_DOSFILEMGR
  57. #define INCL_DOSERRORS
  58. #include <os2.h>
  59.  
  60. #if OS2 >= 2
  61. # define FFBUF    FILEFINDBUF3
  62. # define Word    ULONG
  63.   /*
  64.    * LS20 recommends a request count of 100, but according to the
  65.    * APAR text it does not lead to missing files, just to funny
  66.    * numbers of returned entries.
  67.    *
  68.    * LS30 HPFS386 requires a count greater than 2, or some files
  69.    * are missing (those starting with a character less that '.').
  70.    *
  71.    * Novell looses entries which overflow the buffer. In previous
  72.    * versions of dirent2, this could have lead to missing files
  73.    * when the average length of 100 directory entries was 40 bytes
  74.    * or more (quite unlikely for files on a Novell server).
  75.    *
  76.    * Conclusion: Make sure that the entries all fit into the buffer
  77.    * and that the buffer is large enough for more than 2 entries
  78.    * (each entry is at most 300 bytes long). And ignore the LS20
  79.    * effect.
  80.    */
  81. # define Count    25
  82. # define BufSz    (25 * (sizeof(FILEFINDBUF3)+1))
  83. #else
  84. # define FFBUF    FILEFINDBUF
  85. # define Word    USHORT
  86. # define BufSz    1024
  87. # define Count    3
  88. #endif
  89.  
  90. #if defined(__IBMC__)
  91.   #define error(rc) _doserrno = rc, errno = EOS2ERR
  92. #elif defined(MICROSOFT)
  93.   #define error(rc) _doserrno = rc, errno = 255
  94. #else
  95.   #define error(rc) errno = 255
  96. #endif
  97.  
  98. struct _dirdescr {
  99.     HDIR        handle;        /* DosFindFirst handle */
  100.     char        fstype;        /* filesystem type */
  101.     Word        count;        /* valid entries in <ffbuf> */
  102.     long        number;        /* absolute number of next entry */
  103.     int        index;        /* relative number of next entry */
  104.     FFBUF *        next;        /* pointer to next entry */
  105.     char        name[MAXPATHLEN+3]; /* directory name */
  106.     unsigned    attrmask;    /* attribute mask for seekdir */
  107.     struct dirent    entry;        /* buffer for directory entry */
  108.     BYTE        ffbuf[BufSz];
  109. };
  110.  
  111. /*
  112.  * Return first char of filesystem type, or 0 if unknown.
  113.  */
  114. static char
  115. getFSType(const char *path)
  116. {
  117.     static char cache[1+26];
  118.     char drive[3], info[512];
  119.     Word unit, infolen;
  120.     char r;
  121.  
  122.     if (isalpha(path[0]) && path[1] == ':') {
  123.         unit = toupper(path[0]) - '@';
  124.         path += 2;
  125.     } else {
  126.         ULONG driveMap;
  127. #if OS2 >= 2
  128.         if (DosQueryCurrentDisk(&unit, &driveMap))
  129. #else
  130.         if (DosQCurDisk(&unit, &driveMap))
  131. #endif
  132.             return 0;
  133.     }
  134.  
  135.     if ((path[0] == '\\' || path[0] == '/')
  136.      && (path[1] == '\\' || path[1] == '/'))
  137.         return 0;
  138.  
  139.     if (cache [unit])
  140.         return cache [unit];
  141.  
  142.     drive[0] = '@' + unit;
  143.     drive[1] = ':';
  144.     drive[2] = '\0';
  145.     infolen = sizeof info;
  146. #if OS2 >= 2
  147.     if (DosQueryFSAttach(drive, 0, FSAIL_QUERYNAME, (PVOID)info, &infolen))
  148.         return 0;
  149.     if (infolen >= sizeof(FSQBUFFER2)) {
  150.         FSQBUFFER2 *p = (FSQBUFFER2 *)info;
  151.         r = p->szFSDName[p->cbName];
  152.     } else
  153. #else
  154.     if (DosQFSAttach((PSZ)drive, 0, FSAIL_QUERYNAME, (PVOID)info, &infolen, 0))
  155.         return 0;
  156.     if (infolen >= 9) {
  157.         char *p = info + sizeof(USHORT);
  158.         p += sizeof(USHORT) + *(USHORT *)p + 1 + sizeof(USHORT);
  159.         r = *p;
  160.     } else
  161. #endif
  162.         r = 0;
  163.     return cache [unit] = r;
  164. }
  165.  
  166. char *
  167. abs_path(const char *name, char *buffer, int len)
  168. {
  169.     char buf[4];
  170.     if (isalpha(name[0]) && name[1] == ':' && name[2] == '\0') {
  171.         buf[0] = name[0];
  172.         buf[1] = name[1];
  173.         buf[2] = '.';
  174.         buf[3] = '\0';
  175.         name = buf;
  176.     }
  177. #if OS2 >= 2
  178.     if (DosQueryPathInfo(name, FIL_QUERYFULLNAME, buffer, len))
  179. #else
  180.     if (DosQPathInfo((PSZ)name, FIL_QUERYFULLNAME, (PBYTE)buffer, len, 0L))
  181. #endif
  182.         return NULL;
  183.     return buffer;
  184. }
  185.  
  186. DIR *
  187. openxdir(const char *path, unsigned att_mask)
  188. {
  189.     DIR *dir;
  190.     char name[MAXPATHLEN+3];
  191.     Word rc;
  192.  
  193.     dir = malloc(sizeof(DIR));
  194.     if (dir == NULL) {
  195.         errno = ENOMEM;
  196.         return NULL;
  197.     }
  198.  
  199.     strncpy(name, path, MAXPATHLEN);
  200.     name[MAXPATHLEN] = '\0';
  201.     switch (name[strlen(name)-1]) {
  202.     default:
  203.         strcat(name, "\\");
  204.     case '\\':
  205.     case '/':
  206.     case ':':
  207.         ;
  208.     }
  209.     strcat(name, ".");
  210.     if (!abs_path(name, dir->name, MAXPATHLEN+1))
  211.         strcpy(dir->name, name);
  212.     if (dir->name[strlen(dir->name)-1] == '\\')
  213.         strcat(dir->name, "*");
  214.     else
  215.         strcat(dir->name, "\\*");
  216.  
  217.     dir->fstype = getFSType(dir->name);
  218.     dir->attrmask = att_mask | A_DIR;
  219.  
  220.     dir->handle = HDIR_CREATE;
  221.     dir->count = 100;
  222. #if OS2 >= 2
  223.     rc = DosFindFirst(dir->name, &dir->handle, dir->attrmask,
  224.         dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
  225. #else
  226.     rc = DosFindFirst((PSZ)dir->name, &dir->handle, dir->attrmask,
  227.         (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0);
  228. #endif
  229.     switch (rc) {
  230.     default:
  231.         free(dir);
  232.         error(rc);
  233.         return NULL;
  234.     case NO_ERROR:
  235.     case ERROR_NO_MORE_FILES:
  236.         ;
  237.     }
  238.  
  239.     dir->number = 0;
  240.     dir->index = 0;
  241.     dir->next = (FFBUF *)dir->ffbuf;
  242.  
  243.     return (DIR *)dir;
  244. }
  245.  
  246. DIR *
  247. opendir(const char *pathname)
  248. {
  249.     return openxdir(pathname, 0);
  250. }
  251.  
  252. struct dirent *
  253. readdir(DIR *dir)
  254. {
  255.     static int dummy_ino = 2;
  256.  
  257.     if (dir->index == dir->count) {
  258.         Word rc;
  259.         dir->count = 100;
  260. #if OS2 >= 2
  261.         rc = DosFindNext(dir->handle, dir->ffbuf,
  262.             sizeof dir->ffbuf, &dir->count);
  263. #else
  264.         rc = DosFindNext(dir->handle, (PFILEFINDBUF)dir->ffbuf,
  265.             sizeof dir->ffbuf, &dir->count);
  266. #endif
  267.         if (rc) {
  268.             error(rc);
  269.             return NULL;
  270.         }
  271.  
  272.         dir->index = 0;
  273.         dir->next = (FFBUF *)dir->ffbuf;
  274.     }
  275.  
  276.     if (dir->index == dir->count)
  277.         return NULL;
  278.  
  279.     memcpy(dir->entry.d_name, dir->next->achName, dir->next->cchName);
  280.     dir->entry.d_name[dir->next->cchName] = '\0';
  281.     dir->entry.d_ino = dummy_ino++;
  282.     dir->entry.d_reclen = dir->next->cchName;
  283.     dir->entry.d_namlen = dir->next->cchName;
  284.     dir->entry.d_size = dir->next->cbFile;
  285.     dir->entry.d_attribute = dir->next->attrFile;
  286.     dir->entry.d_time = *(USHORT *)&dir->next->ftimeLastWrite;
  287.     dir->entry.d_date = *(USHORT *)&dir->next->fdateLastWrite;
  288.  
  289.     switch (dir->fstype) {
  290.     case 'F': /* FAT */
  291.     case 'C': /* CDFS */
  292.         if (dir->next->attrFile & FILE_DIRECTORY)
  293.             strupr(dir->entry.d_name);
  294.         else
  295.             strlwr(dir->entry.d_name);
  296.     }
  297.  
  298. #if OS2 >= 2
  299.     dir->next = (FFBUF *)((BYTE *)dir->next + dir->next->oNextEntryOffset);
  300. #else
  301.     dir->next = (FFBUF *)((BYTE *)dir->next->achName + dir->next->cchName + 1);
  302. #endif
  303.     ++dir->number;
  304.     ++dir->index;
  305.  
  306.     return &dir->entry;
  307. }
  308.  
  309. long
  310. telldir(DIR *dir)
  311. {
  312.     return dir->number;
  313. }
  314.  
  315. void
  316. seekdir(DIR *dir, long off)
  317. {
  318.     if (dir->number > off) {
  319.         char name[MAXPATHLEN+2];
  320.         Word rc;
  321.  
  322.         DosFindClose(dir->handle);
  323.  
  324.         strcpy(name, dir->name);
  325.         strcat(name, "*");
  326.  
  327.         dir->handle = HDIR_CREATE;
  328.         dir->count = 32767;
  329. #if OS2 >= 2
  330.         rc = DosFindFirst(name, &dir->handle, dir->attrmask,
  331.             dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
  332. #else
  333.         rc = DosFindFirst((PSZ)name, &dir->handle, dir->attrmask,
  334.             (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0);
  335. #endif
  336.         switch (rc) {
  337.         default:
  338.             error(rc);
  339.             return;
  340.         case NO_ERROR:
  341.         case ERROR_NO_MORE_FILES:
  342.             ;
  343.         }
  344.  
  345.         dir->number = 0;
  346.         dir->index = 0;
  347.         dir->next = (FFBUF *)dir->ffbuf;
  348.     }
  349.  
  350.     while (dir->number < off && readdir(dir))
  351.         ;
  352. }
  353.  
  354. void
  355. closedir(DIR *dir)
  356. {
  357.     DosFindClose(dir->handle);
  358.     free(dir);
  359. }
  360.  
  361. /*****************************************************************************/
  362.  
  363. #ifdef TEST
  364.  
  365. main(int argc, char **argv)
  366. {
  367.     int i;
  368.     DIR *dir;
  369.     struct dirent *ep;
  370.  
  371.     for (i = 1; i < argc; ++i) {
  372.         dir = opendir(argv[i]);
  373.         if (!dir)
  374.             continue;
  375.         while (ep = readdir(dir))
  376.             if (strchr("\\/:", argv[i] [strlen(argv[i]) - 1]))
  377.                 printf("%s%s\n", argv[i], ep->d_name);
  378.             else
  379.                 printf("%s/%s\n", argv[i], ep->d_name);
  380.         closedir(dir);
  381.     }
  382.  
  383.     return 0;
  384. }
  385.  
  386. #endif
  387.  
  388. #endif /* OS2 */
  389.  
  390.