[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / lib / std / cbits / getDirectoryContents.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: getDirectoryContents.c,v 1.3 1998/12/02 13:27:40 simonm Exp $
5  *
6  * getDirectoryContents Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15
16 #ifdef HAVE_SYS_STAT_H
17 #include <sys/stat.h>
18 #endif
19
20 #ifdef HAVE_DIRENT_H
21 #include <dirent.h>
22 #endif
23
24 #ifndef LINK_MAX
25 #define LINK_MAX 1024
26 #endif
27
28 /* For cleanup of partial answer on error */
29
30 static void
31 freeEntries(char **entries, int count)
32 {
33     int i;
34
35     for (i = 0; i < count; i++)
36         free(entries[i]);
37     free(entries);
38 }
39
40 /* 
41  * Our caller expects a malloc'ed array of malloc'ed string pointers.
42  * To ensure consistency when mixing this with other directory
43  * operations, we collect the entire list in one atomic operation,
44  * rather than reading the directory lazily.
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, len;
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         len = strlen(d->d_name);
104         if ((entries[count] = malloc(len+1)) == NULL) {
105             ghc_errtype = ERR_RESOURCEEXHAUSTED;
106             ghc_errstr = "not enough virtual memory";
107             freeEntries(entries, count);
108             (void) closedir(dir);
109             return NULL;
110         }
111         strcpy(entries[count], d->d_name);
112         /* Terminate the sucker */
113         *(entries[count] + len) = 0;
114         if (++count == alloc) {
115             alloc += LINK_MAX;
116             if ((entries = (char **) realloc(entries, alloc * sizeof(char *))) == NULL) {
117                 ghc_errtype = ERR_RESOURCEEXHAUSTED;
118                 ghc_errstr = "not enough virtual memory";
119                 freeEntries(entries, count);
120                 (void) closedir(dir);
121                 return NULL;
122             }
123         }
124     }
125 }