Correct a bug in seekdir/readdir which could cause the directory entry
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 3 May 2008 22:07:37 +0000 (22:07 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 3 May 2008 22:07:37 +0000 (22:07 +0000)
after a deleted entry to be skipped when seeking past the deleted entry.

NOTE: DragonFly has a specific issue even after this fix which currently
causes seekdirs to be unreliable if any files are deleted.  DragonFly
translates directory entries into a filesystem-independant form and if
the real filesystem collapses the entry, the offsets will not be maintained
in the machine-independant form.

Submitted-by: Marc Balmer <marc@msys.ch>
include/dirent.h
lib/libc/gen/readdir.c
lib/libc/gen/telldir.c

index c992d30..850fd78 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)dirent.h    8.2 (Berkeley) 7/28/94
  * $FreeBSD: src/include/dirent.h,v 1.7 1999/12/29 05:01:20 peter Exp $
- * $DragonFly: src/include/dirent.h,v 1.8 2008/04/22 21:29:41 dillon Exp $
+ * $DragonFly: src/include/dirent.h,v 1.9 2008/05/03 22:07:36 dillon Exp $
  */
 
 #ifndef _DIRENT_H_
@@ -92,7 +92,7 @@ int closedir (DIR *);
 #ifndef _POSIX_SOURCE
 DIR *__opendir2 (const char *, int);
 long telldir (const DIR *);
-struct dirent *_readdir_unlocked(DIR *);
+struct dirent *_readdir_unlocked(DIR *, int);
 void seekdir(DIR *, long);
 void _reclaim_telldir(DIR *);
 void _seekdir (DIR *, long);
index f8e6cb0..abf5e12 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc/gen/readdir.c,v 1.5.2.4 2002/02/26 22:53:57 alfred Exp $
- * $DragonFly: src/lib/libc/gen/readdir.c,v 1.9 2007/11/21 05:48:31 dillon Exp $
+ * $DragonFly: src/lib/libc/gen/readdir.c,v 1.10 2008/05/03 22:07:37 dillon Exp $
  *
  * @(#)readdir.c       8.3 (Berkeley) 9/29/94
  */
@@ -51,7 +51,7 @@
  * get next entry in a directory.
  */
 struct dirent *
-_readdir_unlocked(DIR *dirp)
+_readdir_unlocked(DIR *dirp, int skipdeleted)
 {
        struct dirent *dp;
        long dummy;
@@ -73,10 +73,13 @@ _readdir_unlocked(DIR *dirp)
                if (_DIRENT_DIRSIZ(dp) > dirp->dd_len + 1 - dirp->dd_loc)
                        return (NULL);
                dirp->dd_loc += _DIRENT_DIRSIZ(dp);
-               if (dp->d_ino == 0)
-                       continue;
-               if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
-                       continue;
+
+               if (skipdeleted) {
+                       if (dp->d_ino == 0)
+                               continue;
+                       if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
+                               continue;
+               }
                return (dp);
        }
 }
@@ -88,7 +91,7 @@ readdir(DIR *dirp)
 
        if (__isthreaded)
                _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
-       dp = _readdir_unlocked(dirp);
+       dp = _readdir_unlocked(dirp, 1);
        if (__isthreaded)
                _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
 
@@ -105,7 +108,7 @@ readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
        errno = 0;
        if (__isthreaded)
                _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
-       if ((dp = _readdir_unlocked(dirp)) != NULL)
+       if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
                memcpy(entry, dp, _DIRENT_MINSIZ(dp));
        if (__isthreaded)
                _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
index 384e04e..39cebc2 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc/gen/telldir.c,v 1.4.12.1 2001/03/05 09:39:59 obrien Exp $
- * $DragonFly: src/lib/libc/gen/telldir.c,v 1.6 2008/04/22 21:29:42 dillon Exp $
+ * $DragonFly: src/lib/libc/gen/telldir.c,v 1.7 2008/05/03 22:07:37 dillon Exp $
  *
  * @(#)telldir.c       8.1 (Berkeley) 6/4/93
  */
@@ -128,7 +128,7 @@ _seekdir(DIR *dirp, long loc)
         if (__isthreaded)
                _pthread_mutex_lock(&dd_hash_lock);
        for (lp = dd_hash[LOCHASH(loc)]; lp; lp = lp->loc_next) {
-               if (lp->loc_index == loc)
+               if (lp->loc_dirp == dirp && lp->loc_index == loc)
                        break;
        }
         if (__isthreaded)
@@ -148,7 +148,7 @@ _seekdir(DIR *dirp, long loc)
         * load a new buffer or for dd_loc to not match directly.
         */
        while (dirp->dd_loc < lp->loc_loc && dirp->dd_seek == lp->loc_seek) {
-               dp = _readdir_unlocked(dirp);
+               dp = _readdir_unlocked(dirp, 0);
                if (dp == NULL)
                        break;
        }