]> 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 9ed3413c3d4798ec50707ab299bcb4ec89a2cbda..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,33 +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.
- */
-#define SINGLEUSE
-
 /*
  * return a pointer into a directory
  */
 long
-telldir(dirp)
-       DIR *dirp;
+telldir(DIR *dirp)
 {
        struct ddloc *lp;
+       long idx;
 
-       if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
-               return (-1);
        if (__isthreaded)
                _pthread_mutex_lock(&dirp->dd_lock);
-       lp->loc_index = dirp->dd_td->td_loccnt++;
-       lp->loc_seek = dirp->dd_seek;
-       lp->loc_loc = dirp->dd_loc;
-       LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
+       LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) {
+#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 */
+                   lp->loc_loc == dirp->dd_loc)
+                       break;
+       }
+       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;
+#else /* !__DARWIN_64_BIT_INO_T */
+               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);
+       }
+       idx = lp->loc_index;
        if (__isthreaded)
                _pthread_mutex_unlock(&dirp->dd_lock);
-       return (lp->loc_index);
+       return (idx);
 }
 
 /*
@@ -79,9 +92,7 @@ telldir(dirp)
  * 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;
@@ -92,29 +103,77 @@ _seekdir(dirp, loc)
        }
        if (lp == NULL)
                return;
+#if __DARWIN_64_BIT_INO_T
+       if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_td->seekoff)
+#else /* !__DARWIN_64_BIT_INO_T */
        if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
-               goto found;
+#endif /* __DARWIN_64_BIT_INO_T */
+               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;
+#else /* !__DARWIN_64_BIT_INO_T */
        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
 /*
  * 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;
@@ -127,3 +186,4 @@ _reclaim_telldir(dirp)
        }
        LIST_INIT(&dirp->dd_td->td_locq);
 }
+#endif