DragonFly bugs List (threaded) for 2008-05
DragonFly BSD
DragonFly bugs List (threaded) for 2008-05
[Date Prev][Date Next]  [Thread Prev][Thread Next]  [Date Index][Thread Index]

Seekdir Bug


From: Marc Balmer <mbalmer@xxxxxxxxxxx>
Date: Fri, 02 May 2008 10:32:53 +0200

There is a bug in all seekdir()/readdir() implementations in all BSDs:

Under some circumstance, a seekdir() will no take you to the expected
position, but one further.  This happens when the first entry in a
block has been unlinked and you seekdir to the second.  In this case
seekdir() overshoots by one entry.

_readdir_unlocked() must not skip deleted entries when being called
from _seekdir().

A diff is attached.

- Marc Balmer
--- readdir.c.orig	Fri May  2 10:25:47 2008
+++ readdir.c	Fri May  2 10:27:18 2008
@@ -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,7 +73,7 @@
 		if (_DIRENT_DIRSIZ(dp) > dirp->dd_len + 1 - dirp->dd_loc)
 			return (NULL);
 		dirp->dd_loc += _DIRENT_DIRSIZ(dp);
-		if (dp->d_ino == 0)
+		if (dp->d_ino == 0 && skipdeleted)
 			continue;
 		if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
 			continue;
@@ -88,7 +88,7 @@
 
 	if (__isthreaded)
 		_pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
-	dp = _readdir_unlocked(dirp);
+	dp = _readdir_unlocked(dirp, 0);
 	if (__isthreaded)
 		_pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
 
@@ -105,10 +105,10 @@
 	errno = 0;
 	if (__isthreaded)
 		_pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
-	if ((dp = _readdir_unlocked(dirp)) != NULL)
+	if ((dp = _readdir_unlocked(dirp, 0)) != NULL)
 		memcpy(entry, dp, _DIRENT_MINSIZ(dp));
 	if (__isthreaded)
-		_pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
+		_pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock, 0);
 
 	if (errno != 0) {
 		if (dp == NULL) {
--- telldir.c.orig	Fri May  2 10:25:58 2008
+++ telldir.c	Fri May  2 10:26:02 2008
@@ -148,7 +148,7 @@
 	 * 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, 1);
 		if (dp == NULL)
 			break;
 	}


[Date Prev][Date Next]  [Thread Prev][Thread Next]  [Date Index][Thread Index]