[project @ 1996-01-11 14:06:51 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(char **entries, int count)
31 {
32     int i;
33
34     for (i = 0; i < count; i++)
35         free(entries[i]);
36     free(entries);
37 }
38
39 /* 
40  * Our caller expects a malloc'ed array of malloc'ed string pointers.
41  * To ensure consistency when mixing this with other directory
42  * operations, we collect the entire list in one atomic operation,
43  * rather than reading the directory lazily.
44  */
45
46 StgAddr
47 getDirectoryContents(path)
48 StgByteArray path;
49 {
50     struct stat sb;
51     DIR *dir;
52     struct dirent *d;
53     char **entries;
54     int alloc, count;
55
56     /* Check for an actual directory */
57     while (stat(path, &sb) != 0) {
58         if (errno != EINTR) {
59             cvtErrno();
60             stdErrno();
61             return NULL;
62         }
63     }
64     if (!S_ISDIR(sb.st_mode)) {
65         ghc_errtype = ERR_INAPPROPRIATETYPE;
66         ghc_errstr = "not a directory";
67         return NULL;
68     }
69
70     alloc = LINK_MAX;
71     if ((entries = (char **) malloc(alloc * sizeof(char *))) == NULL) {
72         ghc_errtype = ERR_RESOURCEEXHAUSTED;
73         ghc_errstr = "not enough virtual memory";
74         return NULL;
75     }
76     
77     while ((dir = opendir(path)) == NULL) {
78         if (errno != EINTR) {
79             cvtErrno();
80             stdErrno();
81             free(entries);
82             return NULL;
83         }
84     }
85
86     count = 0;
87     for (;;) {
88         errno = 0;  /* unchanged by readdir on EOF */
89         while ((d = readdir(dir)) == NULL) {
90             if (errno == 0) {
91                 entries[count] = NULL;
92                 (void) closedir(dir);
93                 return (StgAddr) entries;
94             } else if (errno != EINTR) {
95                 cvtErrno();
96                 stdErrno();
97                 freeEntries(entries, count);
98                 (void) closedir(dir);
99                 return NULL;
100             }
101             errno = 0;
102         }
103         if ((entries[count] = malloc(strlen(d->d_name))) == NULL) {
104             ghc_errtype = ERR_RESOURCEEXHAUSTED;
105             ghc_errstr = "not enough virtual memory";
106             freeEntries(entries, count);
107             (void) closedir(dir);
108             return NULL;
109         }
110         strcpy(entries[count], d->d_name);
111         if (++count == alloc) {
112             alloc += LINK_MAX;
113             if ((entries = (char **) realloc(entries, alloc * sizeof(char *))) == NULL) {
114                 ghc_errtype = ERR_RESOURCEEXHAUSTED;
115                 ghc_errstr = "not enough virtual memory";
116                 freeEntries(entries, count);
117                 (void) closedir(dir);
118                 return NULL;
119             }
120         }
121     }
122 }
123
124 \end{code}