Cygwin: access: Fix X_OK behaviour for backup operators and admins
[newlib-cygwin.git] / newlib / libc / sys / sysvi386 / telldir.c
blobe8749503f8d779884b2c4761fdb41d67199c460f
1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
30 #if defined(LIBC_SCCS) && !defined(lint)
31 static char sccsid[] = "@(#)telldir.c 5.9 (Berkeley) 2/23/91";
32 #endif /* LIBC_SCCS and not lint */
34 #include <sys/param.h>
35 #include <dirent.h>
36 #include <stdlib.h>
37 #include <unistd.h>
40 * The option SINGLEUSE may be defined to say that a telldir
41 * cookie may be used only once before it is freed. This option
42 * is used to avoid having memory usage grow without bound.
44 #define SINGLEUSE
47 * One of these structures is malloced to describe the current directory
48 * position each time telldir is called. It records the current magic
49 * cookie returned by getdirentries and the offset within the buffer
50 * associated with that return value.
52 struct ddloc {
53 struct ddloc *loc_next;/* next structure in list */
54 long loc_index; /* key associated with structure */
55 long loc_seek; /* magic cookie returned by getdirentries */
56 long loc_loc; /* offset of entry in buffer */
59 #define NDIRHASH 32 /* Num of hash lists, must be a power of 2 */
60 #define LOCHASH(i) ((i)&(NDIRHASH-1))
62 static long dd_loccnt; /* Index of entry for sequential readdir's */
63 static struct ddloc *dd_hash[NDIRHASH]; /* Hash list heads for ddlocs */
66 * return a pointer into a directory
68 long
69 telldir(dirp)
70 const DIR *dirp;
72 register int index;
73 register struct ddloc *lp;
75 if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
76 return (-1);
77 index = dd_loccnt++;
78 lp->loc_index = index;
79 lp->loc_seek = dirp->dd_seek;
80 lp->loc_loc = dirp->dd_loc;
81 lp->loc_next = dd_hash[LOCHASH(index)];
82 dd_hash[LOCHASH(index)] = lp;
83 return (index);
87 * seek to an entry in a directory.
88 * Only values returned by "telldir" should be passed to seekdir.
90 void
91 _seekdir(dirp, loc)
92 register DIR *dirp;
93 long loc;
95 register struct ddloc *lp;
96 register struct ddloc **prevlp;
97 struct dirent *dp;
98 extern long lseek();
100 prevlp = &dd_hash[LOCHASH(loc)];
101 lp = *prevlp;
102 while (lp != NULL) {
103 if (lp->loc_index == loc)
104 break;
105 prevlp = &lp->loc_next;
106 lp = lp->loc_next;
108 if (lp == NULL)
109 return;
110 if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
111 goto found;
112 (void) lseek(dirp->dd_fd, lp->loc_seek, 0);
113 dirp->dd_seek = lp->loc_seek;
114 dirp->dd_loc = 0;
115 while (dirp->dd_loc < lp->loc_loc) {
116 dp = readdir(dirp);
117 if (dp == NULL)
118 break;
120 found:
121 #ifdef SINGLEUSE
122 *prevlp = lp->loc_next;
123 free((caddr_t)lp);
124 #endif