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