OSDN Git Service

Implement readdir_r. Audit for proper thread safety and locking.
authorEric Andersen <andersen@codepoet.org>
Sat, 11 May 2002 00:26:15 +0000 (00:26 -0000)
committerEric Andersen <andersen@codepoet.org>
Sat, 11 May 2002 00:26:15 +0000 (00:26 -0000)
 -Erik

libc/misc/dirent/Makefile
libc/misc/dirent/closedir.c
libc/misc/dirent/dirstream.h
libc/misc/dirent/opendir.c
libc/misc/dirent/readdir.c
libc/misc/dirent/readdir64.c
libc/misc/dirent/readdir_r.c [new file with mode: 0644]
libc/misc/dirent/rewinddir.c
libc/misc/dirent/seekdir.c
libc/misc/dirent/telldir.c

index 4b942db..d50cdb5 100644 (file)
@@ -25,7 +25,7 @@ TOPDIR=../../../
 include $(TOPDIR)Rules.mak
 
 CSRC=alphasort.c closedir.c dirfd.c opendir.c readdir.c rewinddir.c scandir.c \
-       seekdir.c telldir.c readdir64.c alphasort64.c scandir64.c
+       seekdir.c telldir.c readdir64.c alphasort64.c scandir64.c readdir_r.c
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 OBJS=$(COBJS)
 
index 3b6337b..c9486ac 100644 (file)
@@ -19,8 +19,14 @@ int closedir(DIR * dir)
                __set_errno(EBADF);
                return -1;
        }
+#ifdef _POSIX_THREADS
+       pthread_mutex_lock(dir->dd_lock);
+#endif
        fd = dir->dd_fd;
        dir->dd_fd = -1;
+#ifdef _POSIX_THREADS
+       pthread_mutex_unlock(dir->dd_lock);
+#endif
        free(dir->dd_buf);
        free(dir);
        return close(fd);
index dc5c573..268ed1c 100644 (file)
@@ -30,17 +30,6 @@ Cambridge, MA 02139, USA.  */
 #include <pthread.h>
 #endif
 
-
-#ifdef __UCLIBC_HAVE_LFS__
-#ifndef __USE_LARGEFILE64
-# define __USE_LARGEFILE64
-#endif
-# define stuff_t    __off64_t
-#else
-# define stuff_t    __off_t
-#endif
-
-
 /* For now, syscall readdir () only supports one entry at a time. It
  * will be changed in the future.
 #define NUMENT         3
@@ -59,22 +48,20 @@ struct __dirstream {
   int dd_fd;
 
   /* offset of the next dir entry in buffer */
-  stuff_t dd_nextloc;
+  size_t dd_nextloc;
 
   /* bytes of valid entries in buffer */
-  stuff_t dd_size;
+  size_t dd_size;
 
   /* -> directory buffer */
   void *dd_buf;
 
   /* offset of the next dir entry in directory. */
-  stuff_t dd_nextoff;
+  off_t dd_nextoff;
 
   /* total size of buffer */
-  stuff_t dd_max;
+  size_t dd_max;
  
-  enum {unknown, have_getdents, no_getdents} dd_getdents;
-
   /* lock */
 #ifdef _POSIX_THREADS
   pthread_mutex_t *dd_lock;
index e2a6000..48911ce 100644 (file)
@@ -39,7 +39,6 @@ DIR *opendir(const char *name)
 
        ptr->dd_fd = fd;
        ptr->dd_nextloc = ptr->dd_size = ptr->dd_nextoff = 0;
-       ptr->dd_getdents = unknown;
 
        ptr->dd_max = statbuf.st_blksize;
        if (ptr->dd_max < 512)
@@ -52,5 +51,8 @@ DIR *opendir(const char *name)
                return NULL;
        }
        ptr->dd_buf = buf;
+#ifdef _POSIX_THREADS
+       pthread_mutex_init(ptr->dd_lock, NULL);
+#endif
        return ptr;
 }
index 8157528..b9f5f55 100644 (file)
@@ -10,7 +10,7 @@ extern int getdents __P ((unsigned int fd, struct dirent *dirp, unsigned int cou
 
 struct dirent *readdir(DIR * dir)
 {
-       int result;
+       ssize_t bytes;
        struct dirent *de;
 
        if (!dir) {
@@ -18,42 +18,36 @@ struct dirent *readdir(DIR * dir)
                return NULL;
        }
 
-       /* Are we running an old kernel? */
-       if (dir->dd_getdents == no_getdents) {
-               abort();
-       }
+#ifdef _POSIX_THREADS
+       pthread_mutex_lock(dir->dd_lock);
+#endif
 
-       if (dir->dd_size <= dir->dd_nextloc) {
+       do {
+           if (dir->dd_size <= dir->dd_nextloc) {
                /* read dir->dd_max bytes of directory entries. */
-               result = getdents(dir->dd_fd, dir->dd_buf, dir->dd_max);
-
-               /* We assume we have getdents (). */
-               dir->dd_getdents = have_getdents;
-               if (result <= 0) {
-                       result = -result;
-                       if (result > 0) {
-                               /* Are we right? */
-                               if (result == ENOSYS) {
-                                       dir->dd_getdents = no_getdents;
-                                       abort();
-                               }
-                               __set_errno(result);
-                       }
-
-                       return NULL;
+               bytes = getdents(dir->dd_fd, dir->dd_buf, dir->dd_max);
+               if (bytes <= 0) {
+                   de = NULL;
+                   goto all_done;
                }
-
-               dir->dd_size = result;
+               dir->dd_size = bytes;
                dir->dd_nextloc = 0;
-       }
+           }
+
+           de = (struct dirent *) (((char *) dir->dd_buf) + dir->dd_nextloc);
 
-       de = (struct dirent *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+           /* Am I right? H.J. */
+           dir->dd_nextloc += de->d_reclen;
 
-       /* Am I right? H.J. */
-       dir->dd_nextloc += de->d_reclen;
+           /* We have to save the next offset here. */
+           dir->dd_nextoff = de->d_off;
 
-       /* We have to save the next offset here. */
-       dir->dd_nextoff = de->d_off;
+           /* Skip deleted files.  */
+       } while (de->d_ino == 0);
 
+all_done:
+#ifdef _POSIX_THREADS
+       pthread_mutex_unlock(dir->dd_lock);
+#endif
        return de;
 }
index 56481d2..1630172 100644 (file)
@@ -25,7 +25,7 @@ extern int getdents64 __P ((unsigned int fd, struct dirent64 *dirp, unsigned int
 
 struct dirent64 *readdir64(DIR * dir)
 {
-       int result;
+       ssize_t bytes;
        struct dirent64 *de;
 
        if (!dir) {
@@ -33,42 +33,37 @@ struct dirent64 *readdir64(DIR * dir)
                return NULL;
        }
 
-       /* Are we running an old kernel? */
-       if (dir->dd_getdents == no_getdents) {
-               abort();
-       }
+#ifdef _POSIX_THREADS
+       pthread_mutex_lock(dir->dd_lock);
+#endif
 
-       if (dir->dd_size <= dir->dd_nextloc) {
+       do {
+           if (dir->dd_size <= dir->dd_nextloc) {
                /* read dir->dd_max bytes of directory entries. */
-               result = getdents64(dir->dd_fd, dir->dd_buf, dir->dd_max);
-
-               /* We assume we have getdents64 (). */
-               dir->dd_getdents = have_getdents;
-               if (result <= 0) {
-                       result = -result;
-                       if (result > 0) {
-                               /* Are we right? */
-                               if (result == ENOSYS) {
-                                       dir->dd_getdents = no_getdents;
-                                       abort();
-                               }
-                               __set_errno(result);
-                       }
-
-                       return NULL;
+               bytes = getdents64(dir->dd_fd, dir->dd_buf, dir->dd_max);
+               if (bytes <= 0) {
+                   de = NULL;
+                   goto all_done;
                }
-
-               dir->dd_size = result;
+               dir->dd_size = bytes;
                dir->dd_nextloc = 0;
-       }
+           }
+
+           de = (struct dirent64 *) (((char *) dir->dd_buf) + dir->dd_nextloc);
 
-       de = (struct dirent64 *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+           /* Am I right? H.J. */
+           dir->dd_nextloc += de->d_reclen;
 
-       /* Am I right? H.J. */
-       dir->dd_nextloc += de->d_reclen;
+           /* We have to save the next offset here. */
+           dir->dd_nextoff = de->d_off;
 
-       /* We have to save the next offset here. */
-       dir->dd_nextoff = de->d_off;
+           /* Skip deleted files.  */
+       } while (dir->d_ino == 0);
+
+all_done:
+#ifdef _POSIX_THREADS
+       pthread_mutex_unlock(dir->dd_lock);
+#endif
 
        return de;
 }
diff --git a/libc/misc/dirent/readdir_r.c b/libc/misc/dirent/readdir_r.c
new file mode 100644 (file)
index 0000000..9d9db0d
--- /dev/null
@@ -0,0 +1,63 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "dirstream.h"
+
+extern int getdents __P ((unsigned int fd, struct dirent *dirp, unsigned int count));
+
+
+int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)
+{
+       int ret;
+       ssize_t bytes;
+       struct dirent *de;
+
+       if (!dir) {
+           __set_errno(EBADF);
+           return(EBADF);
+       }
+       de = NULL;
+
+#ifdef _POSIX_THREADS
+       pthread_mutex_lock(dir->dd_lock);
+#endif
+
+       do {
+           if (dir->dd_size <= dir->dd_nextloc) {
+               /* read dir->dd_max bytes of directory entries. */
+               bytes = getdents(dir->dd_fd, dir->dd_buf, dir->dd_max);
+               if (bytes <= 0) {
+                   *result = NULL;
+                   ret = errno;
+                   goto all_done;
+               }
+               dir->dd_size = bytes;
+               dir->dd_nextloc = 0;
+           }
+
+           de = (struct dirent *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+
+           /* Am I right? H.J. */
+           dir->dd_nextloc += de->d_reclen;
+
+           /* We have to save the next offset here. */
+           dir->dd_nextoff = de->d_off;
+           /* Skip deleted files.  */
+       } while (de->d_ino == 0);
+
+       if (de == NULL) {
+           *result = NULL;
+       } else {
+           *result = memcpy (entry, de, de->d_reclen);
+       }
+       ret = 0;
+
+all_done:
+
+#ifdef _POSIX_THREADS
+       pthread_mutex_unlock(dir->dd_lock);
+#endif
+        return((de != NULL)? 0 : ret);
+}
index 4955940..a541f89 100644 (file)
@@ -11,6 +11,12 @@ void rewinddir(DIR * dir)
                __set_errno(EBADF);
                return;
        }
+#ifdef _POSIX_THREADS
+       pthread_mutex_lock(dir->dd_lock);
+#endif
        lseek(dir->dd_fd, 0, SEEK_SET);
        dir->dd_nextoff = dir->dd_nextloc = dir->dd_size = 0;
+#ifdef _POSIX_THREADS
+       pthread_mutex_unlock(dir->dd_lock);
+#endif
 }
index a1649c9..c00171a 100644 (file)
@@ -10,6 +10,12 @@ void seekdir(DIR * dir, long int offset)
                __set_errno(EBADF);
                return;
        }
+#ifdef _POSIX_THREADS
+       pthread_mutex_lock(dir->dd_lock);
+#endif
        dir->dd_nextoff = lseek(dir->dd_fd, offset, SEEK_SET);
        dir->dd_size = dir->dd_nextloc = 0;
+#ifdef _POSIX_THREADS
+       pthread_mutex_unlock(dir->dd_lock);
+#endif
 }
index 8c13a9c..1240304 100644 (file)
@@ -6,31 +6,11 @@
 
 long int telldir(DIR * dir)
 {
-       off_t offset;
-
        if (!dir) {
                __set_errno(EBADF);
                return -1;
        }
 
-       switch (dir->dd_getdents) {
-       case no_getdents:
-               /* We are running the old kernel. This is the starting offset
-                  of the next readdir(). */
-               offset = lseek(dir->dd_fd, 0, SEEK_CUR);
-               break;
-
-       case unknown:
-               /* readdir () is not called yet. but seekdir () may be called. */
-       case have_getdents:
-               /* The next entry. */
-               offset = dir->dd_nextoff;
-               break;
-
-       default:
-               __set_errno(EBADF);
-               offset = -1;
-       }
-
-       return offset;
+       /* The next entry. */
+       return dir->dd_nextoff;
 }