[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / runtime / io / getDirectoryContents.lc
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995
3 %
4 \subsection[getDirectoryContents.lc]{getDirectoryContents Runtime Support}
5
6 \begin{code}
7
8 #include "rtsdefs.h"
9 #include "stgio.h"
10
11 #ifdef HAVE_SYS_TYPES_H
12 #include <sys/types.h>
13 #endif
14
15 #ifdef HAVE_SYS_STAT_H
16 #include <sys/stat.h>
17 #endif
18
19 #ifdef HAVE_DIRENT_H
20 #include <dirent.h>
21 #endif
22
23 #ifndef LINK_MAX
24 #define LINK_MAX 1024
25 #endif
26
27 /* For cleanup of partial answer on error */
28
29 static void
30 freeEntries(entries, count)
31   char **entries;
32   int count;
33 {
34     int i;
35
36     for (i = 0; i < count; i++)
37         free(entries[i]);
38     free(entries);
39 }
40
41 /* 
42  * Our caller expects a malloc'ed array of malloc'ed string pointers.
43  * To ensure consistency when mixing this with other directory
44  * operations, we collect the entire list in one atomic operation,
45  * rather than reading the directory lazily.
46  */
47
48 StgAddr
49 getDirectoryContents(path)
50 StgByteArray path;
51 {
52     struct stat sb;
53     DIR *dir;
54     struct dirent *d;
55     char **entries;
56     int alloc, count;
57
58     /* Check for an actual directory */
59     while (stat(path, &sb) != 0) {
60         if (errno != EINTR) {
61             cvtErrno();
62             stdErrno();
63             return NULL;
64         }
65     }
66     if (!S_ISDIR(sb.st_mode)) {
67         ghc_errtype = ERR_INAPPROPRIATETYPE;
68         ghc_errstr = "not a directory";
69         return NULL;
70     }
71
72     alloc = LINK_MAX;
73     if ((entries = (char **) malloc(alloc * sizeof(char *))) == NULL) {
74         ghc_errtype = ERR_RESOURCEEXHAUSTED;
75         ghc_errstr = "not enough virtual memory";
76         return NULL;
77     }
78     
79     while ((dir = opendir(path)) == NULL) {
80         if (errno != EINTR) {
81             cvtErrno();
82             stdErrno();
83             free(entries);
84             return NULL;
85         }
86     }
87
88     count = 0;
89     for (;;) {
90         errno = 0;  /* unchanged by readdir on EOF */
91         while ((d = readdir(dir)) == NULL) {
92             if (errno == 0) {
93                 entries[count] = NULL;
94                 (void) closedir(dir);
95                 return (StgAddr) entries;
96             } else if (errno != EINTR) {
97                 cvtErrno();
98                 stdErrno();
99                 freeEntries(entries, count);
100                 (void) closedir(dir);
101                 return NULL;
102             }
103             errno = 0;
104         }
105         if ((entries[count] = malloc(strlen(d->d_name))) == NULL) {
106             ghc_errtype = ERR_RESOURCEEXHAUSTED;
107             ghc_errstr = "not enough virtual memory";
108             freeEntries(entries, count);
109             (void) closedir(dir);
110             return NULL;
111         }
112         strcpy(entries[count], d->d_name);
113         if (++count == alloc) {
114             alloc += LINK_MAX;
115             if ((entries = (char **) realloc(entries, alloc * sizeof(char *))) == NULL) {
116                 ghc_errtype = ERR_RESOURCEEXHAUSTED;
117                 ghc_errstr = "not enough virtual memory";
118                 freeEntries(entries, count);
119                 (void) closedir(dir);
120                 return NULL;
121             }
122         }
123     }
124 }
125
126 \end{code}