% % (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 #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_DIRENT_H #include #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}