summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-05-11 00:26:15 +0000
committerEric Andersen <andersen@codepoet.org>2002-05-11 00:26:15 +0000
commita4f07581502ee212aa45e7b0049fdd126dd10b40 (patch)
tree935a2f668e5fb5306e0e12f380924d2311da5ee5 /libc
parentd2be3a1d010ea7e953d15a2e705373735723c06e (diff)
Implement readdir_r. Audit for proper thread safety and locking.
-Erik
Diffstat (limited to 'libc')
-rw-r--r--libc/misc/dirent/Makefile2
-rw-r--r--libc/misc/dirent/closedir.c6
-rw-r--r--libc/misc/dirent/dirstream.h21
-rw-r--r--libc/misc/dirent/opendir.c4
-rw-r--r--libc/misc/dirent/readdir.c54
-rw-r--r--libc/misc/dirent/readdir64.c55
-rw-r--r--libc/misc/dirent/readdir_r.c63
-rw-r--r--libc/misc/dirent/rewinddir.c6
-rw-r--r--libc/misc/dirent/seekdir.c6
-rw-r--r--libc/misc/dirent/telldir.c24
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;
}