From: Alan Cox Date: Tue, 26 May 2015 23:06:58 +0000 (+0100) Subject: opendir/readdir/closedir: partial rewrite, fix errors, block cache X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=337be789e3bdce8c8c028031a1a31eccd9f5248d;p=FUZIX.git opendir/readdir/closedir: partial rewrite, fix errors, block cache We now pull a sector at a time and hand it out an entry at a time. This makes life a lot quicker. In addition we now use one allocation not two and the code correctly handles the corner case of the directory being fd 0 --- diff --git a/Library/include/dirent.h b/Library/include/dirent.h index 707a5c28..bfb9e7ea 100644 --- a/Library/include/dirent.h +++ b/Library/include/dirent.h @@ -4,8 +4,6 @@ #include #endif -/* It's 14 for the kernel as it stands but may move to 30 so build - that into userspace */ #define MAXNAMLEN 30 @@ -17,6 +15,7 @@ typedef struct { struct dirent *dd_buf; /* -> directory buffer */ } DIR; /* stream data from opendir() */ + typedef int (*__dir_select_fn_t) __P ((struct dirent *)); typedef int (*__dir_compar_fn_t) __P ((struct dirent **, struct dirent **)); @@ -28,12 +27,21 @@ struct dirent { char d_name[31]; }; -/* Internal version */ +/* Kernel directory format off disk */ struct __dirent { - int d_ino; + ino_t d_ino; char d_name[30]; }; +/* Internal directory structure */ +struct _dir { + DIR d; + struct dirent de; + uint8_t buf[512]; + uint8_t next; + uint8_t last; +}; + extern DIR *opendir __P ((char *__name)); extern int closedir __P ((DIR * __dirp)); extern struct dirent *readdir __P ((DIR * __dirp)); diff --git a/Library/libs/closedir.c b/Library/libs/closedir.c index 98ae649a..efcf3777 100644 --- a/Library/libs/closedir.c +++ b/Library/libs/closedir.c @@ -1,4 +1,4 @@ -/* close.c closedir implementation +/* closedir.c closedir implementation * */ #include @@ -9,16 +9,15 @@ #include #include -int closedir(DIR * dir) +int closedir(DIR * dirp) { - if (dir == NULL || dir->dd_buf == NULL || dir->dd_fd == 0) { + struct _dir *dir = (struct _dir *)dirp; + if (dir == NULL || dir->d.dd_fd == -1) { errno = EFAULT; return -1; } - close(dir->dd_fd); - free(dir->dd_buf); - dir->dd_fd = 0; - dir->dd_buf = NULL; + close(dir->d.dd_fd); + dir->d.dd_fd = -1; free(dir); return 0; } diff --git a/Library/libs/opendir.c b/Library/libs/opendir.c index 3c9f8c57..30e06ff7 100644 --- a/Library/libs/opendir.c +++ b/Library/libs/opendir.c @@ -9,27 +9,22 @@ DIR *opendir(char *path) { struct stat statbuf; - register DIR *dir; + struct _dir *dir; if (stat(path, &statbuf) != 0) - goto Err; + return NULL; + if ((statbuf.st_mode & S_IFDIR) == 0) { errno = ENOTDIR; - goto Err; - } - if ((dir = (DIR *) calloc(1, sizeof(DIR))) == NULL) { - errno = ENOMEM; - goto Err; + return NULL; } - if ((dir->dd_buf = calloc(1, sizeof(struct dirent))) == NULL) { - free(dir); + if ((dir = calloc(1, sizeof(struct _dir))) == NULL) { errno = ENOMEM; - goto Err; + return NULL; } - if ((dir->dd_fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) { - free(dir->dd_buf); + if ((dir->d.dd_fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) { free(dir); - Err:return NULL; + return NULL; } - return dir; + return (DIR *)dir; } diff --git a/Library/libs/readdir.c b/Library/libs/readdir.c index 44f0afe2..a25c2737 100644 --- a/Library/libs/readdir.c +++ b/Library/libs/readdir.c @@ -9,31 +9,42 @@ #include #include -struct dirent *readdir(DIR * dir) +static struct __dirent *dnext(struct _dir *dir) { - struct __dirent direntry; + if (dir->next == dir->last) { + int l = read(dir->d.dd_fd, dir->buf, sizeof(dir->buf)); + if (l == 0) + return NULL; + l /= 32; + dir->last = l; + dir->next = 0; + } + return (struct __dirent *)(dir->buf + 32 * dir->next++); +} + +struct dirent *readdir(DIR * dirp) +{ + struct _dir *dir = (struct _dir *)dirp; + struct __dirent *direntry; register struct dirent *buf; int len; - if (dir == NULL || dir->dd_buf == NULL || dir->dd_fd == 0) { + if (dir == NULL || dir->d.dd_fd == -1) { errno = EFAULT; return NULL; - } - direntry.d_name[0] = 0; - while (direntry.d_name[0] == 0) { - len = _getdirent(dir->dd_fd, &direntry, sizeof(direntry)); - if (len > sizeof(direntry)) { - errno = ERANGE; - return NULL; - } - if (len == 0) + } + + do { + direntry = dnext(dir); + if (direntry == NULL) return NULL; - } - buf = dir->dd_buf; - buf->d_ino = direntry.d_ino; + } while (direntry->d_name[0] == 0); + + buf = &dir->de; + buf->d_ino = direntry->d_ino; buf->d_off = -1; /* FIXME */ - buf->d_reclen = len + 1; - strncpy(buf->d_name, (char *) direntry.d_name, len - 2); - buf->d_name[len - 2] = 0; + buf->d_reclen = 33; + strncpy(buf->d_name, (char *) direntry->d_name, 31); + buf->d_name[30] = 0; return buf; }