summaryrefslogtreecommitdiff
path: root/lib/libc/gen
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2008-05-01 19:49:19 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2008-05-01 19:49:19 +0000
commita889b94e4da0d0640d5168711d6a48c3ce71085e (patch)
tree0bccdaeaee6eb855d6d969970a2ff0bf03456d94 /lib/libc/gen
parent6cc9e5d5f4b3fce118d0b0c004269fe7c9a9d12d (diff)
Be carefull not to read away the target entry when encountering
deleted files after a seekdir(); testcase produced by mbalmer@; fix with and ok mbalmer; ok millert@
Diffstat (limited to 'lib/libc/gen')
-rw-r--r--lib/libc/gen/readdir.c16
-rw-r--r--lib/libc/gen/telldir.c6
2 files changed, 14 insertions, 8 deletions
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
index 577a51a0995..cd6c046549c 100644
--- a/lib/libc/gen/readdir.c
+++ b/lib/libc/gen/readdir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readdir.c,v 1.13 2008/04/04 21:26:07 okan Exp $ */
+/* $OpenBSD: readdir.c,v 1.14 2008/05/01 19:49:18 otto Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -38,7 +38,7 @@
* get next entry in a directory.
*/
int
-_readdir_unlocked(DIR *dirp, struct dirent **result)
+_readdir_unlocked(DIR *dirp, struct dirent **result, int skipdeleted)
{
struct dirent *dp;
@@ -61,7 +61,13 @@ _readdir_unlocked(DIR *dirp, struct dirent **result)
dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
return (-1);
dirp->dd_loc += dp->d_reclen;
- if (dp->d_ino == 0)
+ /*
+ * When called from seekdir(), we let it decide on
+ * the end condition to avoid overshooting: the next
+ * readdir call should produce the next non-deleted entry,
+ * and we already advanced dd_loc.
+ */
+ if (dp->d_ino == 0 && skipdeleted)
continue;
*result = dp;
return (0);
@@ -74,7 +80,7 @@ readdir(DIR *dirp)
struct dirent *dp;
_MUTEX_LOCK(&dirp->dd_lock);
- _readdir_unlocked(dirp, &dp);
+ _readdir_unlocked(dirp, &dp, 1);
_MUTEX_UNLOCK(&dirp->dd_lock);
return (dp);
@@ -86,7 +92,7 @@ readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
struct dirent *dp;
_MUTEX_LOCK(&dirp->dd_lock);
- if (_readdir_unlocked(dirp, &dp) != 0) {
+ if (_readdir_unlocked(dirp, &dp, 1) != 0) {
_MUTEX_UNLOCK(&dirp->dd_lock);
return errno;
}
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index 57829a2af43..5ffdfc1a6a9 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: telldir.c,v 1.12 2008/04/04 21:26:07 okan Exp $ */
+/* $OpenBSD: telldir.c,v 1.13 2008/05/01 19:49:18 otto 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"
-int _readdir_unlocked(DIR *, struct dirent **);
+int _readdir_unlocked(DIR *, struct dirent **, int);
/*
* 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) {
- _readdir_unlocked(dirp, &dp);
+ _readdir_unlocked(dirp, &dp, 0);
if (dp == NULL)
break;
}