xref: /openbsd/lib/libc/gen/telldir.c (revision 898184e3)
1 /*	$OpenBSD: telldir.c,v 1.13 2008/05/01 19:49:18 otto Exp $ */
2 /*
3  * Copyright (c) 1983, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/queue.h>
33 #include <dirent.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 
37 #include "thread_private.h"
38 #include "telldir.h"
39 
40 int _readdir_unlocked(DIR *, struct dirent **, int);
41 
42 /*
43  * return a pointer into a directory
44  */
45 long
46 _telldir_unlocked(DIR *dirp)
47 {
48 	long i;
49 	struct ddloc *lp;
50 
51 	i = dirp->dd_td->td_last;
52 	lp = &dirp->dd_td->td_locs[i];
53 
54 	/* return previous telldir, if there */
55 	for (; i < dirp->dd_td->td_loccnt; i++, lp++) {
56 		if (lp->loc_seek == dirp->dd_seek &&
57 		    lp->loc_loc == dirp->dd_loc) {
58 			dirp->dd_td->td_last = i;
59 			return (i);
60 		}
61 	}
62 
63 	if (dirp->dd_td->td_loccnt == dirp->dd_td->td_sz) {
64 		size_t newsz = dirp->dd_td->td_sz * 2 + 1;
65 		struct ddloc *p;
66 		p = realloc(dirp->dd_td->td_locs, newsz * sizeof(*p));
67 		if (p == NULL)
68 			return (-1);
69 		dirp->dd_td->td_sz = newsz;
70 		dirp->dd_td->td_locs = p;
71 		lp = &dirp->dd_td->td_locs[i];
72 	}
73 	dirp->dd_td->td_loccnt++;
74 	lp->loc_seek = dirp->dd_seek;
75 	lp->loc_loc = dirp->dd_loc;
76 	dirp->dd_td->td_last = i;
77 	return (i);
78 }
79 
80 long
81 telldir(DIR *dirp)
82 {
83 	long i;
84 
85 	_MUTEX_LOCK(&dirp->dd_lock);
86 	i = _telldir_unlocked(dirp);
87 	_MUTEX_UNLOCK(&dirp->dd_lock);
88 
89 	return (i);
90 }
91 
92 /*
93  * seek to an entry in a directory.
94  * Only values returned by "telldir" should be passed to seekdir.
95  */
96 void
97 __seekdir(DIR *dirp, long loc)
98 {
99 	struct ddloc *lp;
100 	struct dirent *dp;
101 
102 	if (loc < 0 || loc >= dirp->dd_td->td_loccnt)
103 		return;
104 	lp = &dirp->dd_td->td_locs[loc];
105 	dirp->dd_td->td_last = loc;
106 	if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
107 		return;
108 	(void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET);
109 	dirp->dd_seek = lp->loc_seek;
110 	dirp->dd_loc = 0;
111 	while (dirp->dd_loc < lp->loc_loc) {
112 		_readdir_unlocked(dirp, &dp, 0);
113 		if (dp == NULL)
114 			break;
115 	}
116 }
117