diff options
author | Eric Andersen <andersen@codepoet.org> | 2002-05-11 00:26:15 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2002-05-11 00:26:15 +0000 |
commit | a4f07581502ee212aa45e7b0049fdd126dd10b40 (patch) | |
tree | 935a2f668e5fb5306e0e12f380924d2311da5ee5 | |
parent | d2be3a1d010ea7e953d15a2e705373735723c06e (diff) |
Implement readdir_r. Audit for proper thread safety and locking.
-Erik
-rw-r--r-- | libc/misc/dirent/Makefile | 2 | ||||
-rw-r--r-- | libc/misc/dirent/closedir.c | 6 | ||||
-rw-r--r-- | libc/misc/dirent/dirstream.h | 21 | ||||
-rw-r--r-- | libc/misc/dirent/opendir.c | 4 | ||||
-rw-r--r-- | libc/misc/dirent/readdir.c | 54 | ||||
-rw-r--r-- | libc/misc/dirent/readdir64.c | 55 | ||||
-rw-r--r-- | libc/misc/dirent/readdir_r.c | 63 | ||||
-rw-r--r-- | libc/misc/dirent/rewinddir.c | 6 | ||||
-rw-r--r-- | libc/misc/dirent/seekdir.c | 6 | ||||
-rw-r--r-- | libc/misc/dirent/telldir.c | 24 |
10 files changed, 140 insertions, 101 deletions
diff --git a/libc/misc/dirent/Makefile b/libc/misc/dirent/Makefile index 4b942dbdd..d50cdb520 100644 --- a/libc/misc/dirent/Makefile +++ b/libc/misc/dirent/Makefile @@ -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) diff --git a/libc/misc/dirent/closedir.c b/libc/misc/dirent/closedir.c index 3b6337b5f..c9486ac56 100644 --- a/libc/misc/dirent/closedir.c +++ b/libc/misc/dirent/closedir.c @@ -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); diff --git a/libc/misc/dirent/dirstream.h b/libc/misc/dirent/dirstream.h index dc5c5732a..268ed1c91 100644 --- a/libc/misc/dirent/dirstream.h +++ b/libc/misc/dirent/dirstream.h @@ -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; diff --git a/libc/misc/dirent/opendir.c b/libc/misc/dirent/opendir.c index e2a6000ca..48911ce32 100644 --- a/libc/misc/dirent/opendir.c +++ b/libc/misc/dirent/opendir.c @@ -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; } diff --git a/libc/misc/dirent/readdir.c b/libc/misc/dirent/readdir.c index 81575283d..b9f5f55bd 100644 --- a/libc/misc/dirent/readdir.c +++ b/libc/misc/dirent/readdir.c @@ -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; } diff --git a/libc/misc/dirent/readdir64.c b/libc/misc/dirent/readdir64.c index 56481d234..1630172ea 100644 --- a/libc/misc/dirent/readdir64.c +++ b/libc/misc/dirent/readdir64.c @@ -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 index 000000000..9d9db0dee --- /dev/null +++ b/libc/misc/dirent/readdir_r.c @@ -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); +} diff --git a/libc/misc/dirent/rewinddir.c b/libc/misc/dirent/rewinddir.c index 495594089..a541f8963 100644 --- a/libc/misc/dirent/rewinddir.c +++ b/libc/misc/dirent/rewinddir.c @@ -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 } diff --git a/libc/misc/dirent/seekdir.c b/libc/misc/dirent/seekdir.c index a1649c9b3..c00171a28 100644 --- a/libc/misc/dirent/seekdir.c +++ b/libc/misc/dirent/seekdir.c @@ -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 } diff --git a/libc/misc/dirent/telldir.c b/libc/misc/dirent/telldir.c index 8c13a9c23..124030431 100644 --- a/libc/misc/dirent/telldir.c +++ b/libc/misc/dirent/telldir.c @@ -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; } |