summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOkan Demirmen <okan@cvs.openbsd.org>2008-04-04 21:26:08 +0000
committerOkan Demirmen <okan@cvs.openbsd.org>2008-04-04 21:26:08 +0000
commit77b01758cdd4f3d22af1ad0d6b43c6d9f86ef5c5 (patch)
treea94b57f618bc11d613fb35404fcedf9e86975320
parent2419060533a4e33e9985400be7adb6ab4ce3263b (diff)
alter internal _readdir_unlocked() api to be less confusing, so that
callers may respond accordingly and correctly. this fixes an issue where readdir_r() could not decipher the difference between an error or no more entires. feedback and ok kurt@, ok millert@
-rw-r--r--lib/libc/gen/readdir.c33
-rw-r--r--lib/libc/gen/telldir.c6
2 files changed, 21 insertions, 18 deletions
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
index 5f4c447e576..577a51a0995 100644
--- a/lib/libc/gen/readdir.c
+++ b/lib/libc/gen/readdir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readdir.c,v 1.12 2007/06/05 18:11:48 kurt Exp $ */
+/* $OpenBSD: readdir.c,v 1.13 2008/04/04 21:26:07 okan Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -37,31 +37,34 @@
/*
* get next entry in a directory.
*/
-struct dirent *
-_readdir_unlocked(DIR *dirp)
+int
+_readdir_unlocked(DIR *dirp, struct dirent **result)
{
struct dirent *dp;
+ *result = NULL;
for (;;) {
- if (dirp->dd_loc >= dirp->dd_size) {
+ if (dirp->dd_loc >= dirp->dd_size)
dirp->dd_loc = 0;
- }
if (dirp->dd_loc == 0) {
dirp->dd_size = getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size <= 0)
- return (NULL);
+ if (dirp->dd_size == 0)
+ return (0);
+ if (dirp->dd_size < 0)
+ return (-1);
}
dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
if ((long)dp & 03) /* bogus pointer check */
- return (NULL);
+ return (-1);
if (dp->d_reclen <= 0 ||
dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
- return (NULL);
+ return (-1);
dirp->dd_loc += dp->d_reclen;
if (dp->d_ino == 0)
continue;
- return (dp);
+ *result = dp;
+ return (0);
}
}
@@ -71,7 +74,7 @@ readdir(DIR *dirp)
struct dirent *dp;
_MUTEX_LOCK(&dirp->dd_lock);
- dp = _readdir_unlocked(dirp);
+ _readdir_unlocked(dirp, &dp);
_MUTEX_UNLOCK(&dirp->dd_lock);
return (dp);
@@ -83,13 +86,13 @@ readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
struct dirent *dp;
_MUTEX_LOCK(&dirp->dd_lock);
- dp = _readdir_unlocked(dirp);
- if (dp == NULL && errno != 0) {
+ if (_readdir_unlocked(dirp, &dp) != 0) {
_MUTEX_UNLOCK(&dirp->dd_lock);
return errno;
}
- if (dp != NULL)
- memcpy(entry, dp, sizeof (struct dirent) - MAXNAMLEN + dp->d_namlen);
+ if (dp != NULL)
+ memcpy(entry, dp,
+ sizeof (struct dirent) - MAXNAMLEN + dp->d_namlen);
_MUTEX_UNLOCK(&dirp->dd_lock);
if (dp != NULL)
*result = entry;
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index cc9761c92f8..57829a2af43 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: telldir.c,v 1.11 2007/10/02 16:14:58 kurt Exp $ */
+/* $OpenBSD: telldir.c,v 1.12 2008/04/04 21:26:07 okan Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -37,7 +37,7 @@
#include "thread_private.h"
#include "telldir.h"
-struct dirent *_readdir_unlocked(DIR *);
+int _readdir_unlocked(DIR *, struct dirent **);
/*
* return a pointer into a directory
@@ -109,7 +109,7 @@ __seekdir(DIR *dirp, long loc)
dirp->dd_seek = lp->loc_seek;
dirp->dd_loc = 0;
while (dirp->dd_loc < lp->loc_loc) {
- dp = _readdir_unlocked(dirp);
+ _readdir_unlocked(dirp, &dp);
if (dp == NULL)
break;
}