This source file includes following definitions.
- opendir
- readdir
- telldir
- seekdir
- rewinddir
- closedir
- dirfd
#include "replace.h"
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#define DIR_BUF_BITS 9
#define DIR_BUF_SIZE (1<<DIR_BUF_BITS)
struct dir_buf {
int fd;
int nbytes, ofs;
off_t seekpos;
char buf[DIR_BUF_SIZE];
};
DIR *opendir(const char *dname)
{
struct dir_buf *d;
struct stat sb;
d = malloc(sizeof(*d));
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
d->fd = open(dname, O_RDONLY);
if (d->fd == -1) {
free(d);
return NULL;
}
if (fstat(d->fd, &sb) < 0) {
close(d->fd);
free(d);
return NULL;
}
if (!S_ISDIR(sb.st_mode)) {
close(d->fd);
free(d);
errno = ENOTDIR;
return NULL;
}
d->ofs = 0;
d->seekpos = 0;
d->nbytes = 0;
return (DIR *)d;
}
struct dirent *readdir(DIR *dir)
{
struct dir_buf *d = (struct dir_buf *)dir;
struct dirent *de;
if (d->ofs >= d->nbytes) {
long pos;
d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos);
d->seekpos = pos;
d->ofs = 0;
}
if (d->ofs >= d->nbytes) {
return NULL;
}
de = (struct dirent *)&d->buf[d->ofs];
d->ofs += de->d_reclen;
return de;
}
#ifdef TELLDIR_TAKES_CONST_DIR
long telldir(const DIR *dir)
#else
long telldir(DIR *dir)
#endif
{
struct dir_buf *d = (struct dir_buf *)dir;
if (d->ofs >= d->nbytes) {
d->seekpos = lseek(d->fd, 0, SEEK_CUR);
d->ofs = 0;
d->nbytes = 0;
}
if (d->seekpos & (DIR_BUF_SIZE-1)) {
abort();
}
return d->seekpos + d->ofs;
}
#ifdef SEEKDIR_RETURNS_INT
int seekdir(DIR *dir, long ofs)
#else
void seekdir(DIR *dir, long ofs)
#endif
{
struct dir_buf *d = (struct dir_buf *)dir;
long pos;
d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET);
d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos);
d->ofs = 0;
while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) {
if (readdir(dir) == NULL) break;
}
#ifdef SEEKDIR_RETURNS_INT
return -1;
#endif
}
void rewinddir(DIR *dir)
{
seekdir(dir, 0);
}
int closedir(DIR *dir)
{
struct dir_buf *d = (struct dir_buf *)dir;
int r = close(d->fd);
if (r != 0) {
return r;
}
free(d);
return 0;
}
#ifndef dirfd
int dirfd(DIR *dir)
{
struct dir_buf *d = (struct dir_buf *)dir;
return d->fd;
}
#endif