This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / lib / libc / gen / directory.c
CommitLineData
9b07ac93
NW
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, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)closedir.c 5.9 (Berkeley) 2/23/91";
36#endif /* LIBC_SCCS and not lint */
37
38/*
39 * One of these structures is malloced to describe the current directory
40 * position each time telldir is called. It records the current magic
41 * cookie returned by getdirentries and the offset within the buffer
42 * associated with that return value.
43 */
44struct ddloc {
45 struct ddloc *loc_next;/* next structure in list */
46 long loc_index; /* key associated with structure */
47 long loc_seek; /* magic cookie returned by getdirentries */
48 long loc_loc; /* offset of entry in buffer */
49};
50
51static long dd_loccnt = 0; /* Index of entry for sequential telldir's */
52
53#include <sys/types.h>
54#include <sys/param.h>
55#include <dirent.h>
56#include <stdlib.h>
57#include <unistd.h>
58#include <fcntl.h>
59
60/*
61 * close a directory.
62 */
63int
64closedir(dirp)
65 register DIR *dirp;
66{
67 struct ddloc *ptr, *nextptr;
68 int fd;
69
70 fd = dirp->dd_fd;
71 dirp->dd_fd = -1;
72 dirp->dd_loc = 0;
73 for (ptr = (struct ddloc*)dirp->dd_ddloc; ptr; ptr = nextptr) {
74 nextptr = ptr->loc_next;
75 free((void *)ptr);
76 }
77 free((void *)dirp->dd_buf);
78 free((void *)dirp);
79 return(close(fd));
80}
81
82/*
83 * open a directory.
84 */
85DIR *
86opendir(name)
87 const char *name;
88{
89 register DIR *dirp;
90 register int fd;
91
92 if ((fd = open(name, 0)) == -1)
93 return NULL;
94 if (fcntl(fd, F_SETFD, 1) == -1 ||
95 (dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
96 close (fd);
97 return NULL;
98 }
99 /*
100 * If CLSIZE is an exact multiple of DIRBLKSIZ, use a CLSIZE
101 * buffer that it cluster boundary aligned.
102 * Hopefully this can be a big win someday by allowing page trades
103 * to user space to be done by getdirentries()
104 */
105 if ((CLSIZE % DIRBLKSIZ) == 0) {
106 dirp->dd_buf = malloc(CLSIZE);
107 dirp->dd_len = CLSIZE;
108 } else {
109 dirp->dd_buf = malloc(DIRBLKSIZ);
110 dirp->dd_len = DIRBLKSIZ;
111 }
112 if (dirp->dd_buf == NULL) {
113 close (fd);
114 free(dirp);
115 return NULL;
116 }
117 dirp->dd_fd = fd;
118 dirp->dd_loc = 0;
119 dirp->dd_seek = 0;
120 dirp->dd_ddloc = NULL;
121
122 return dirp;
123}
124
125/*
126 * get next entry in a directory.
127 */
128struct dirent *
129readdir(dirp)
130 register DIR *dirp;
131{
132 register struct dirent *dp;
133
134 for (;;) {
135 if (dirp->dd_loc == 0) {
136 dirp->dd_size = getdirentries(dirp->dd_fd,
137 dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
138 if (dirp->dd_size <= 0)
139 return NULL;
140 }
141 if (dirp->dd_loc >= dirp->dd_size) {
142 dirp->dd_loc = 0;
143 continue;
144 }
145 dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
146 if ((int)dp & 03) /* bogus pointer check */
147 return NULL;
148 if (dp->d_reclen <= 0 ||
149 dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
150 return NULL;
151 dirp->dd_loc += dp->d_reclen;
152 if (dp->d_ino == 0)
153 continue;
154 return (dp);
155 }
156}
157
158void
159rewinddir(dirp)
160 DIR *dirp;
161{
162 (void)lseek(dirp->dd_fd, 0, 0);
163 dirp->dd_seek = 0;
164 dirp->dd_loc = 0;
165}
166
167/*
168 * Seek to an entry in a directory.
169 * _seekdir is in telldir.c so that it can share opaque data structures.
170 */
171void
172seekdir(dirp, loc)
173 DIR *dirp;
174 long loc;
175{
176 register struct ddloc **prevlp;
177 register struct ddloc *lp;
178 struct dirent *dp;
179 extern long lseek();
180
181 prevlp = (struct ddloc **)&(dirp->dd_ddloc);
182 lp = *prevlp;
183 while (lp != NULL) {
184 if (lp->loc_index == loc)
185 break;
186 prevlp = &lp->loc_next;
187 lp = lp->loc_next;
188 }
189 if (lp) {
190 if (lp->loc_seek != dirp->dd_seek) {
191 if (lseek(dirp->dd_fd, lp->loc_seek, 0) == -1) {
192 *prevlp = lp->loc_next;
193 free(lp);
194 return;
195 }
196 dirp->dd_seek = lp->loc_seek;
197 dirp->dd_loc = 0;
198 while (dirp->dd_loc < lp->loc_loc) {
199 if (!(dp = readdir(dirp))) {
200 *prevlp = lp->loc_next;
201 free(lp);
202 return;
203 }
204 }
205 }
206 }
207}
208
209/*
210 * return a pointer into a directory
211 */
212long
213telldir(dirp)
214 const DIR *dirp;
215{
216 register struct ddloc *lp, **fakeout;
217
218 if (lp = (struct ddloc *)malloc(sizeof(struct ddloc))) {
219 lp->loc_index = dd_loccnt++;
220 lp->loc_seek = dirp->dd_seek;
221 lp->loc_loc = dirp->dd_loc;
222 lp->loc_next = dirp->dd_ddloc;
223
224 /* Compiler won't let us change anything pointed to by db directly */
225 /* So we fake to the left and do it anyway */
226 /* Wonder if the compile optomizes it to the correct solution */
227 fakeout = (struct ddloc **)&(dirp->dd_ddloc);
228 *fakeout = lp;
229
230 return (lp->loc_index);
231 }
232 return (-1);
233}
234