xref: /original-bsd/lib/libc/gen/telldir.c (revision c73c5200)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static char sccsid[] = "@(#)telldir.c	5.6 (Berkeley) 07/11/89";
20 #endif /* LIBC_SCCS and not lint */
21 
22 #include <sys/param.h>
23 #include <dirent.h>
24 
25 /*
26  * The option SINGLEUSE may be defined to say that a telldir
27  * cookie may be used only once before it is freed. This option
28  * is used to avoid having memory usage grow without bound.
29  */
30 #define SINGLEUSE
31 
32 /*
33  * One of these structures is malloced to describe the current directory
34  * position each time telldir is called. It records the current magic
35  * cookie returned by getdirentries and the offset within the buffer
36  * associated with that return value.
37  */
38 struct ddloc {
39 	struct	ddloc *loc_next;/* next structure in list */
40 	long	loc_index;	/* key associated with structure */
41 	long	loc_seek;	/* magic cookie returned by getdirentries */
42 	long	loc_loc;	/* offset of entry in buffer */
43 };
44 
45 #define	NDIRHASH	32	/* Num of hash lists, must be a power of 2 */
46 #define	LOCHASH(i)	((i)&(NDIRHASH-1))
47 
48 static long	dd_loccnt;	/* Index of entry for sequential readdir's */
49 static struct	ddloc *dd_hash[NDIRHASH];   /* Hash list heads for ddlocs */
50 
51 /*
52  * return a pointer into a directory
53  */
54 long
55 telldir(dirp)
56 	DIR *dirp;
57 {
58 	register int index;
59 	register struct ddloc *lp;
60 
61 	if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
62 		return (-1);
63 	index = dd_loccnt++;
64 	lp->loc_index = index;
65 	lp->loc_seek = dirp->dd_seek;
66 	lp->loc_loc = dirp->dd_loc;
67 	lp->loc_next = dd_hash[LOCHASH(index)];
68 	dd_hash[LOCHASH(index)] = lp;
69 	return (index);
70 }
71 
72 /*
73  * seek to an entry in a directory.
74  * Only values returned by "telldir" should be passed to seekdir.
75  */
76 void
77 _seekdir(dirp, loc)
78 	register DIR *dirp;
79 	long loc;
80 {
81 	register struct ddloc *lp;
82 	register struct ddloc **prevlp;
83 	struct dirent *dp;
84 	extern long lseek();
85 
86 	prevlp = &dd_hash[LOCHASH(loc)];
87 	lp = *prevlp;
88 	while (lp != NULL) {
89 		if (lp->loc_index == loc)
90 			break;
91 		prevlp = &lp->loc_next;
92 		lp = lp->loc_next;
93 	}
94 	if (lp == NULL)
95 		return;
96 	if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
97 		goto found;
98 	(void) lseek(dirp->dd_fd, lp->loc_seek, 0);
99 	dirp->dd_loc = 0;
100 	while (dirp->dd_loc < lp->loc_loc) {
101 		dp = readdir(dirp);
102 		if (dp == NULL)
103 			break;
104 	}
105 found:
106 #ifdef SINGLEUSE
107 	*prevlp = lp->loc_next;
108 	free((caddr_t)lp);
109 #endif
110 }
111