opendir/readdir/closedir: partial rewrite, fix errors, block cache
authorAlan Cox <alan@linux.intel.com>
Tue, 26 May 2015 23:06:58 +0000 (00:06 +0100)
committerAlan Cox <alan@linux.intel.com>
Tue, 26 May 2015 23:06:58 +0000 (00:06 +0100)
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

Library/include/dirent.h
Library/libs/closedir.c
Library/libs/opendir.c
Library/libs/readdir.c

index 707a5c2..bfb9e7e 100644 (file)
@@ -4,8 +4,6 @@
 #include <types.h>
 #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));
index 98ae649..efcf377 100644 (file)
@@ -1,4 +1,4 @@
-/* close.c      closedir implementation
+/* closedir.c      closedir implementation
  *
  */
 #include <unistd.h>
@@ -9,16 +9,15 @@
 #include <fcntl.h>
 #include <string.h>
 
-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;
 }
index 3c9f8c5..30e06ff 100644 (file)
@@ -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;
 }
index 44f0afe..a25c273 100644 (file)
@@ -9,31 +9,42 @@
 #include <fcntl.h>
 #include <string.h>
 
-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;
 }