#include <dirent.h>
#include "fcntl.h"
#include "unistd.h"
#include <stdlib.h>
#include <errno.h>
struct __DIR {
int fd;
off_t offset;
struct dirent entry;
};
static void init_dir(DIR *dirp, int fd)
{
dirp->fd = fd;
dirp->offset = 0;
}
DIR __attribute__ ((weak, visibility ("default"))) *opendir(const char *dirname)
{
int fd;
struct stat statbuf;
int errnum;
int flags;
DIR *dirp;
if ((fd = __open(dirname, O_RDONLY)) == -1)
return NULL;
if (__fstat(fd, &statbuf) == -1) {
errnum = errno;
goto error_close;
}
if (!S_ISDIR(statbuf.st_mode)) {
errnum = ENOTDIR;
goto error_close;
}
if ((flags = __fcntl(fd, F_GETFD)) == -1) {
errnum = errno;
goto error_close;
}
flags |= FD_CLOEXEC;
if (__fcntl(fd, F_SETFD, flags) == -1) {
errnum = errno;
goto error_close;
}
if (!(dirp = malloc(sizeof (struct __DIR)))) {
errnum = errno;
goto error_close;
}
init_dir(dirp, fd);
return dirp;
error_close:
__close(fd);
errno = errnum;
return NULL;
}
DIR __attribute__ ((weak, visibility ("default"))) *fdopendir(int fd)
{
struct stat statbuf;
DIR *dirp;
if (__fstat(fd, &statbuf) == -1)
return NULL;
if (!S_ISDIR(statbuf.st_mode)) {
errno = ENOTDIR;
return NULL;
}
if (!(dirp = malloc(sizeof (struct __DIR))))
return NULL;
init_dir(dirp, fd);
return dirp;
}
int __attribute__ ((weak, visibility ("default"))) closedir(DIR *dirp)
{
int fd;
fd = dirp->fd;
free(dirp);
if (__close(fd) == -1)
return -1;
return 0;
}
struct dirent __attribute__ ((weak, visibility ("default"))) *readdir(DIR *dirp)
{
ssize_t n;
if ((n = __read(dirp->fd, dirp->entry.d_name, NAME_MAX + 1)) <= 0)
return NULL;
dirp->offset += n;
return &dirp->entry;
}
void __attribute__ ((weak, visibility ("default"))) seekdir(DIR *dirp, long loc)
{
__lseek(dirp->fd, loc, SEEK_SET);
dirp->offset = loc;
}
long __attribute__ ((weak, visibility ("default"))) telldir(DIR *dirp)
{
return dirp->offset;
}
void __attribute__ ((weak, visibility ("default"))) rewinddir(DIR *dirp)
{
__lseek(dirp->fd, 0, SEEK_SET);
dirp->offset = 0;
}
int __attribute__ ((weak, visibility ("default"))) dirfd(DIR *dirp)
{
return dirp->fd;
}