BSD 4_3_Reno release
[unix-history] / usr / src / lib / libc / gen / telldir.c
index e96bc38..0eef315 100644 (file)
@@ -3,25 +3,53 @@
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
  * from this software without specific prior written permission.
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * from this software without specific prior written permission.
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)telldir.c  5.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)telldir.c  5.8 (Berkeley) 6/1/90";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #include <dirent.h>
 
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #include <dirent.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
+
+/*
+ * One of these structures is malloced to describe the current directory
+ * position each time telldir is called. It records the current magic 
+ * cookie returned by getdirentries and the offset within the buffer
+ * associated with that return value.
+ */
+struct ddloc {
+       struct  ddloc *loc_next;/* next structure in list */
+       long    loc_index;      /* key associated with structure */
+       long    loc_seek;       /* magic cookie returned by getdirentries */
+       long    loc_loc;        /* offset of entry in buffer */
+};
+
+#define        NDIRHASH        32      /* Num of hash lists, must be a power of 2 */
+#define        LOCHASH(i)      ((i)&(NDIRHASH-1))
+
+static long    dd_loccnt;      /* Index of entry for sequential readdir's */
+static struct  ddloc *dd_hash[NDIRHASH];   /* Hash list heads for ddlocs */
+
 /*
  * return a pointer into a directory
  */
 /*
  * return a pointer into a directory
  */
@@ -29,7 +57,57 @@ long
 telldir(dirp)
        DIR *dirp;
 {
 telldir(dirp)
        DIR *dirp;
 {
+       register int index;
+       register struct ddloc *lp;
+
+       if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
+               return (-1);
+       index = dd_loccnt++;
+       lp->loc_index = index;
+       lp->loc_seek = dirp->dd_seek;
+       lp->loc_loc = dirp->dd_loc;
+       lp->loc_next = dd_hash[LOCHASH(index)];
+       dd_hash[LOCHASH(index)] = lp;
+       return (index);
+}
+
+/*
+ * seek to an entry in a directory.
+ * Only values returned by "telldir" should be passed to seekdir.
+ */
+void
+_seekdir(dirp, loc)
+       register DIR *dirp;
+       long loc;
+{
+       register struct ddloc *lp;
+       register struct ddloc **prevlp;
+       struct dirent *dp;
        extern long lseek();
 
        extern long lseek();
 
-       return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
+       prevlp = &dd_hash[LOCHASH(loc)];
+       lp = *prevlp;
+       while (lp != NULL) {
+               if (lp->loc_index == loc)
+                       break;
+               prevlp = &lp->loc_next;
+               lp = lp->loc_next;
+       }
+       if (lp == NULL)
+               return;
+       if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
+               goto found;
+       (void) lseek(dirp->dd_fd, lp->loc_seek, 0);
+       dirp->dd_seek = lp->loc_seek;
+       dirp->dd_loc = 0;
+       while (dirp->dd_loc < lp->loc_loc) {
+               dp = readdir(dirp);
+               if (dp == NULL)
+                       break;
+       }
+found:
+#ifdef SINGLEUSE
+       *prevlp = lp->loc_next;
+       free((caddr_t)lp);
+#endif
 }
 }