Implemented buffering int readdir()

This commit is contained in:
2022-05-17 20:58:47 +01:00
parent f2bc7348e9
commit 7b5edf6e8d
2 changed files with 106 additions and 33 deletions

View File

@@ -30,66 +30,128 @@ DIR *opendir(const char *path)
int closedir(DIR *d) int closedir(DIR *d)
{ {
close(d->fd); close(d->fd);
for (int i = 0; i < d->cache_size; i++) {
if (d->dent_cache[i].d_namep) {
free(d->dent_cache[i].d_namep);
}
}
free(d); free(d);
return 0; return 0;
} }
struct dirent *readdir(DIR *d) static void clear_cache(DIR *d)
{ {
mio_dirent dent; for (int i = 0; i < d->cache_size; i++) {
int r = mio_getdents(d->fd, &dent, 1); if (d->dent_cache[i].d_namep) {
if (r < 1) { free(d->dent_cache[i].d_namep);
__set_errno(-r);
return NULL;
} }
size_t name_max = sizeof(d->current_dent.d_name); d->dent_cache[i].d_namep = NULL;
if (sizeof(dent.d_name) < name_max) {
name_max = sizeof(dent.d_name);
} }
d->current_dent.d_ino = dent.d_ino; d->cache_size = d->cache_idx = 0;
d->current_dent.d_type = dent.d_type;
memcpy(d->current_dent.d_name, dent.d_name, name_max);
return &d->current_dent;
} }
int readdir_r(DIR *d, struct dirent *entry, struct dirent **result) static int refill(DIR *d)
{ {
mio_dirent dent; clear_cache(d);
int r = mio_getdents(d->fd, &dent, 1);
if (r < 1) { for (int i = 0; i < d->cache_size; i++) {
*result = NULL; free(d->dent_cache[i].d_namep);
d->dent_cache[i].d_namep = NULL;
}
d->cache_size = d->cache_idx = 0;
mio_dirent dent[__SYS_DENT_CACHE_SZ];
int r = mio_getdents(d->fd, dent, __SYS_DENT_CACHE_SZ);
if (r < 0) {
__set_errno(-r); __set_errno(-r);
return -1; return -1;
} }
size_t name_max = sizeof(d->current_dent.d_name); for (int i = 0; i < r; i++) {
if (sizeof(dent.d_name) < name_max) { struct __dentcache *cache_ent = &d->dent_cache[i];
name_max = sizeof(dent.d_name); cache_ent->d_ino = dent[i].d_ino;
cache_ent->d_type = dent[i].d_type;
cache_ent->d_namep = strdup(dent[i].d_name);
} }
d->current_dent.d_ino = dent.d_ino; d->cache_idx = 0;
d->current_dent.d_type = dent.d_type; d->cache_size = r;
memcpy(d->current_dent.d_name, dent.d_name, name_max); return 0;
memcpy(entry, &d->current_dent, sizeof(*entry)); }
static void fill_dirent(DIR *d, struct dirent *out)
{
if (d->cache_idx >= d->cache_size) {
return;
}
struct __dentcache *cache_ent = &d->dent_cache[d->cache_idx];
out->d_ino = cache_ent->d_ino;
out->d_type = cache_ent->d_type;
if (cache_ent->d_namep) {
strncpy(out->d_name, cache_ent->d_namep, sizeof out->d_name - 1);
out->d_name[sizeof out->d_name - 1] = '\0';
}
}
struct dirent *readdir(DIR *d)
{
if (d->cache_idx == d->cache_size) {
if (refill(d) != 0 || !d->cache_size) {
return NULL;
}
}
fill_dirent(d, &d->cdent);
d->cache_idx++;
d->seek++;
return &d->cdent;
}
int readdir_r(DIR *d, struct dirent *entry, struct dirent **result)
{
if (d->cache_idx == d->cache_size) {
if (refill(d) != 0) {
return 1;
}
if (d->cache_size == 0) {
if (result) {
*result = NULL;
}
return 0;
}
}
fill_dirent(d, entry);
d->seek++;
if (result) {
*result = entry; *result = entry;
}
return 0; return 0;
} }
void rewinddir(DIR *d) void rewinddir(DIR *d)
{ {
mio_seek(d->fd, 0, SEEK_SET); d->seek = mio_seek(d->fd, 0, SEEK_SET);
clear_cache(d);
} }
void seekdir(DIR *d, long int off) void seekdir(DIR *d, long int off)
{ {
mio_seek(d->fd, off, SEEK_SET); d->seek = mio_seek(d->fd, off, SEEK_SET);
clear_cache(d);
} }
long int telldir(DIR *d) long int telldir(DIR *d)
{ {
return mio_seek(d->fd, 0, SEEK_CUR); return d->seek;
} }

View File

@@ -4,6 +4,14 @@
#include <sys/types.h> #include <sys/types.h>
#include <limits.h> #include <limits.h>
#define __SYS_DENT_CACHE_SZ 4
struct __dentcache {
ino_t d_ino;
unsigned char d_type;
char *d_namep;
};
struct dirent { struct dirent {
ino_t d_ino; ino_t d_ino;
unsigned char d_type; unsigned char d_type;
@@ -12,7 +20,10 @@ struct dirent {
typedef struct { typedef struct {
int fd; int fd;
struct dirent current_dent; long seek;
unsigned char cache_idx, cache_size;
struct __dentcache dent_cache[__SYS_DENT_CACHE_SZ];
struct dirent cdent;
} DIR; } DIR;
#endif #endif