]> git.saurik.com Git - apple/libc.git/blobdiff - gen/FreeBSD/telldir.c
Libc-1439.100.3.tar.gz
[apple/libc.git] / gen / FreeBSD / telldir.c
index 355ed50e4fc2615fab9646f8b7ccd4717ec16468..8351dc17908720c598ac2e920a83749a04252b31 100644 (file)
@@ -31,7 +31,7 @@
 static char sccsid[] = "@(#)telldir.c  8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/telldir.c,v 1.11 2008/05/05 14:05:23 kib Exp $");
+__FBSDID("$FreeBSD$");
 
 #include "namespace.h"
 #include <sys/param.h>
@@ -45,62 +45,46 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/telldir.c,v 1.11 2008/05/05 14:05:23 kib Ex
 #include "libc_private.h"
 #include "telldir.h"
 
-/*
- * The option SINGLEUSE may be defined to say that a telldir
- * cookie may be used only once before it is freed. This option
- * is used to avoid having memory usage grow without bound.
- */
-#if !__DARWIN_UNIX03
-#define SINGLEUSE
-#endif /* !__DARWIN_UNIX03 */
-
 /*
  * return a pointer into a directory
  */
 long
-telldir(dirp)
-       DIR *dirp;
+telldir(DIR *dirp)
 {
        struct ddloc *lp;
+       long idx;
 
-#if __DARWIN_UNIX03
        if (__isthreaded)
                _pthread_mutex_lock(&dirp->dd_lock);
        LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) {
-               if (
 #if __DARWIN_64_BIT_INO_T
-                   (lp->loc_seek == dirp->dd_td->seekoff)
+               if (lp->loc_seek == dirp->dd_td->seekoff &&
 #else /* !__DARWIN_64_BIT_INO_T */
-                   (lp->loc_seek == dirp->dd_seek)
+               if (lp->loc_seek == dirp->dd_seek &&
 #endif /* __DARWIN_64_BIT_INO_T */
-                   && (lp->loc_loc == dirp->dd_loc))
-                       goto found;
-       }
-       if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) {
-               if (__isthreaded)
-                       _pthread_mutex_unlock(&dirp->dd_lock);
-               return (-1);
+                   lp->loc_loc == dirp->dd_loc)
+                       break;
        }
-#else /* !__DARWIN_UNIX03 */
-       if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
-               return (-1);
-       if (__isthreaded)
-               _pthread_mutex_lock(&dirp->dd_lock);
-#endif /* __DARWIN_UNIX03 */
-       lp->loc_index = dirp->dd_td->td_loccnt++;
+       if (lp == NULL) {
+               lp = malloc(sizeof(struct ddloc));
+               if (lp == NULL) {
+                       if (__isthreaded)
+                               _pthread_mutex_unlock(&dirp->dd_lock);
+                       return (-1);
+               }
+               lp->loc_index = dirp->dd_td->td_loccnt++;
 #if __DARWIN_64_BIT_INO_T
-       lp->loc_seek = dirp->dd_td->seekoff;
+               lp->loc_seek = dirp->dd_td->seekoff;
 #else /* !__DARWIN_64_BIT_INO_T */
-       lp->loc_seek = dirp->dd_seek;
+               lp->loc_seek = dirp->dd_seek;
 #endif /* __DARWIN_64_BIT_INO_T */
-       lp->loc_loc = dirp->dd_loc;
-       LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
-#if __DARWIN_UNIX03
-found:
-#endif /* __DARWIN_UNIX03 */
+               lp->loc_loc = dirp->dd_loc;
+               LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
+       }
+       idx = lp->loc_index;
        if (__isthreaded)
                _pthread_mutex_unlock(&dirp->dd_lock);
-       return (lp->loc_index);
+       return (idx);
 }
 
 /*
@@ -108,9 +92,7 @@ found:
  * Only values returned by "telldir" should be passed to seekdir.
  */
 void
-_seekdir(dirp, loc)
-       DIR *dirp;
-       long loc;
+_seekdir(DIR *dirp, long loc)
 {
        struct ddloc *lp;
        struct dirent *dp;
@@ -121,14 +103,28 @@ _seekdir(dirp, loc)
        }
        if (lp == NULL)
                return;
-       if (lp->loc_loc == dirp->dd_loc && 
 #if __DARWIN_64_BIT_INO_T
-           lp->loc_seek == dirp->dd_td->seekoff
+       if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_td->seekoff)
 #else /* !__DARWIN_64_BIT_INO_T */
-           lp->loc_seek == dirp->dd_seek
+       if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
 #endif /* __DARWIN_64_BIT_INO_T */
-       )
-               goto found;
+               return;
+
+       /* If it's within the same chunk of data, don't bother reloading. */
+#if __DARWIN_64_BIT_INO_T
+       if (lp->loc_seek == dirp->dd_td->seekoff) {
+#else /* !__DARWIN_64_BIT_INO_T */
+       if (lp->loc_seek == dirp->dd_seek) {
+#endif /* __DARWIN_64_BIT_INO_T */
+               /*
+                * If we go back to 0 don't make the next readdir
+                * trigger a call to getdirentries().
+                */
+               if (lp->loc_loc == 0)
+                       dirp->dd_flags |= __DTF_SKIPREAD;
+               dirp->dd_loc = lp->loc_loc;
+               return;
+       }
        (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET);
 #if __DARWIN_64_BIT_INO_T
        dirp->dd_td->seekoff = lp->loc_seek;
@@ -136,16 +132,40 @@ _seekdir(dirp, loc)
        dirp->dd_seek = lp->loc_seek;
 #endif /* __DARWIN_64_BIT_INO_T */
        dirp->dd_loc = 0;
+       dirp->dd_flags &= ~(__DTF_SKIPREAD | __DTF_ATEND); /* current contents are invalid */
        while (dirp->dd_loc < lp->loc_loc) {
                dp = _readdir_unlocked(dirp, 0);
                if (dp == NULL)
                        break;
        }
-found:;
-#ifdef SINGLEUSE
-       LIST_REMOVE(lp, loc_lqe);
-       free((caddr_t)lp);
-#endif
+}
+
+/*
+ * After readdir returns the last entry in a block, a call to telldir
+ * returns a location that is after the end of that last entry.
+ * However, that location doesn't refer to a valid directory entry.
+ * Ideally, the call to telldir would return a location that refers to
+ * the first entry in the next block.  That location is not known
+ * until the next block is read, so readdir calls this function after
+ * fetching a new block to fix any such telldir locations.
+ */
+void
+_fixtelldir(DIR *dirp, long oldseek, long oldloc)
+{
+       struct ddloc *lp;
+
+       lp = LIST_FIRST(&dirp->dd_td->td_locq);
+       if (lp != NULL) {
+               if (lp->loc_loc == oldloc &&
+                   lp->loc_seek == oldseek) {
+#if __DARWIN_64_BIT_INO_T
+                       lp->loc_seek = dirp->dd_td->seekoff;
+#else /* !__DARWIN_64_BIT_INO_T */
+                       lp->loc_seek = dirp->dd_seek;
+#endif /* __DARWIN_64_BIT_INO_T */
+                       lp->loc_loc = dirp->dd_loc;
+               }
+       }
 }
 
 #ifndef BUILDING_VARIANT
@@ -153,8 +173,7 @@ found:;
  * Reclaim memory for telldir cookies which weren't used.
  */
 void
-_reclaim_telldir(dirp)
-       DIR *dirp;
+_reclaim_telldir(DIR *dirp)
 {
        struct ddloc *lp;
        struct ddloc *templp;
@@ -167,4 +186,4 @@ _reclaim_telldir(dirp)
        }
        LIST_INIT(&dirp->dd_td->td_locq);
 }
-#endif /* !BUILDING_VARIANT */
+#endif