#include #include #include #include #include #include #include #include #include DIR *opendir(const char *path) { int fd = open(path, O_DIRECTORY); if (fd < 0) { return NULL; } DIR *out = malloc(sizeof(*out)); if (!out) { __set_errno(ENOMEM); return NULL; } memset(out, 0x0, sizeof(*out)); out->fd = fd; return out; } int closedir(DIR *d) { 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); return 0; } static void clear_cache(DIR *d) { for (int i = 0; i < d->cache_size; i++) { if (d->dent_cache[i].d_namep) { free(d->dent_cache[i].d_namep); } d->dent_cache[i].d_namep = NULL; } d->cache_size = d->cache_idx = 0; } static int refill(DIR *d) { clear_cache(d); for (int i = 0; i < d->cache_size; i++) { 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); return -1; } for (int i = 0; i < r; i++) { struct __dentcache *cache_ent = &d->dent_cache[i]; 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->cache_idx = 0; d->cache_size = r; return 0; } 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; } return 0; } void rewinddir(DIR *d) { d->seek = mio_seek(d->fd, 0, SEEK_SET); clear_cache(d); } void seekdir(DIR *d, long int off) { d->seek = mio_seek(d->fd, off, SEEK_SET); clear_cache(d); } long int telldir(DIR *d) { return d->seek; }