[project @ 1998-04-22 00:08:32 by sof]
[ghc-hetmet.git] / ghc / lib / std / cbits / 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 StgAddr
46 getDirectoryContents(path)
47 StgByteArray path;
48 {
49     struct stat sb;
50     DIR *dir;
51     struct dirent *d;
52     char **entries;
53     int alloc, count, len;
54
55     /* Check for an actual directory */
56     while (stat(path, &sb) != 0) {
57         if (errno != EINTR) {
58             cvtErrno();
59             stdErrno();
60             return NULL;
61         }
62     }
63     if (!S_ISDIR(sb.st_mode)) {
64         ghc_errtype = ERR_INAPPROPRIATETYPE;
65         ghc_errstr = "not a directory";
66         return NULL;
67     }
68
69     alloc = LINK_MAX;
70     if ((entries = (char **) malloc(alloc * sizeof(char *))) == NULL) {
71         ghc_errtype = ERR_RESOURCEEXHAUSTED;
72         ghc_errstr = "not enough virtual memory";
73         return NULL;
74     }
75     
76     while ((dir = opendir(path)) == NULL) {
77         if (errno != EINTR) {
78             cvtErrno();
79             stdErrno();
80             free(entries);
81             return NULL;
82         }
83     }
84
85     count = 0;
86     for (;;) {
87         errno = 0;  /* unchanged by readdir on EOF */
88         while ((d = readdir(dir)) == NULL) {
89             if (errno == 0) {
90                 entries[count] = NULL;
91                 (void) closedir(dir);
92                 return (StgAddr) entries;
93             } else if (errno != EINTR) {
94                 cvtErrno();
95                 stdErrno();
96                 freeEntries(entries, count);
97                 (void) closedir(dir);
98                 return NULL;
99             }
100             errno = 0;
101         }
102         len = strlen(d->d_name);
103         if ((entries[count] = malloc(len+1)) == 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         /* Terminate the sucker */
112         *(entries[count] + len) = 0;
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}