diff options
-rw-r--r-- | include/dirent.h | 6 | ||||
-rw-r--r-- | lib/libc/gen/closedir.c | 9 | ||||
-rw-r--r-- | lib/libc/gen/directory.3 | 8 | ||||
-rw-r--r-- | lib/libc/gen/opendir.c | 12 | ||||
-rw-r--r-- | lib/libc/gen/seekdir.c | 5 | ||||
-rw-r--r-- | lib/libc/gen/telldir.c | 82 | ||||
-rw-r--r-- | lib/libc/gen/telldir.h | 62 |
7 files changed, 112 insertions, 72 deletions
diff --git a/include/dirent.h b/include/dirent.h index 05e5c83cd61..6360ab89147 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dirent.h,v 1.15 2005/12/13 00:35:22 millert Exp $ */ +/* $OpenBSD: dirent.h,v 1.16 2006/04/01 18:06:59 otto Exp $ */ /* $NetBSD: dirent.h,v 1.9 1995/03/26 20:13:37 jtc Exp $ */ /*- @@ -59,6 +59,7 @@ /* definitions for library routines operating on directories. */ #define DIRBLKSIZ 1024 +struct _telldir; /* structure describing an open directory. */ typedef struct _dirdesc { int dd_fd; /* file descriptor associated with directory */ @@ -69,6 +70,7 @@ typedef struct _dirdesc { long dd_seek; /* magic cookie returned by getdirentries */ long dd_rewind; /* magic cookie for rewinding */ int dd_flags; /* flags for readdir */ + struct _telldir *dd_td; /* telldir position recording */ } DIR; #define dirfd(dirp) ((dirp)->dd_fd) @@ -106,7 +108,7 @@ int getdirentries(int, char *, int, long *) __attribute__ ((__bounded__(__string__,2,3))); #endif /* __BSD_VISIBLE */ #if __XPG_VISIBLE -long telldir(const DIR *); +long telldir(DIR *); void seekdir(DIR *, long); #endif #if __POSIX_VISIBLE >= 199506 || __XPG_VISIBLE >= 500 diff --git a/lib/libc/gen/closedir.c b/lib/libc/gen/closedir.c index f43d5adfbd8..7315bcc1e41 100644 --- a/lib/libc/gen/closedir.c +++ b/lib/libc/gen/closedir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: closedir.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */ +/* $OpenBSD: closedir.c,v 1.7 2006/04/01 18:06:59 otto Exp $ */ /* * Copyright (c) 1983, 1993 * Regents of the University of California. All rights reserved. @@ -33,6 +33,7 @@ #include <stdlib.h> #include <unistd.h> #include "thread_private.h" +#include "telldir.h" /* * close a directory. @@ -45,12 +46,12 @@ closedir(DIR *dirp) if ((ret = _FD_LOCK(dirp->dd_fd, FD_READ, NULL)) != 0) return (ret); - seekdir(dirp, dirp->dd_rewind); /* free seekdir storage */ fd = dirp->dd_fd; dirp->dd_fd = -1; dirp->dd_loc = 0; - free((void *)dirp->dd_buf); - free((void *)dirp); + free(dirp->dd_td->td_locs); + free(dirp->dd_buf); + free(dirp); ret = close(fd); _FD_UNLOCK(fd, FD_READ); return (ret); diff --git a/lib/libc/gen/directory.3 b/lib/libc/gen/directory.3 index 08883944cff..40ebc57e292 100644 --- a/lib/libc/gen/directory.3 +++ b/lib/libc/gen/directory.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: directory.3,v 1.16 2003/06/02 20:18:34 millert Exp $ +.\" $OpenBSD: directory.3,v 1.17 2006/04/01 18:06:59 otto Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -135,12 +135,6 @@ from which they are derived. If the directory is closed and then reopened, the .Fn telldir value may be invalidated due to undetected directory compaction. -It is safe to use a previous -.Fn telldir -value immediately after a call to -.Fn opendir -and before any calls to -.Fn readdir . .Pp The .Fn rewinddir diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index e407dd4b815..35c8f08346c 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: opendir.c,v 1.15 2005/10/10 17:37:43 espie Exp $ */ +/* $OpenBSD: opendir.c,v 1.16 2006/04/01 18:06:59 otto Exp $ */ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -40,6 +40,8 @@ #include <string.h> #include <unistd.h> +#include "telldir.h" + /* * Open a directory. */ @@ -67,11 +69,17 @@ __opendir2(const char *name, int flags) return (NULL); } if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 || - (dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { + (dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL) { close(fd); return (NULL); } + dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR)); + dirp->dd_td->td_locs = NULL; + dirp->dd_td->td_sz = 0; + dirp->dd_td->td_loccnt = 0; + + /* * If the machine's page size is an exact multiple of DIRBLKSIZ, * use a buffer that is cluster boundary aligned. diff --git a/lib/libc/gen/seekdir.c b/lib/libc/gen/seekdir.c index b339a2709ad..e472f62b789 100644 --- a/lib/libc/gen/seekdir.c +++ b/lib/libc/gen/seekdir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: seekdir.c,v 1.7 2005/08/08 08:05:34 espie Exp $ */ +/* $OpenBSD: seekdir.c,v 1.8 2006/04/01 18:06:59 otto Exp $ */ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -30,8 +30,7 @@ #include <sys/param.h> #include <dirent.h> - -void __seekdir(DIR *, long); +#include "telldir.h" /* * Seek to an entry in a directory. diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c index e215c847c25..e25bb53bca3 100644 --- a/lib/libc/gen/telldir.c +++ b/lib/libc/gen/telldir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: telldir.c,v 1.7 2005/08/08 08:05:34 espie Exp $ */ +/* $OpenBSD: telldir.c,v 1.8 2006/04/01 18:06:59 otto Exp $ */ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -29,56 +29,43 @@ */ #include <sys/param.h> +#include <sys/queue.h> #include <dirent.h> #include <stdlib.h> #include <unistd.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 */ - -void __seekdir(DIR *, long); +#include "telldir.h" /* * return a pointer into a directory */ long -telldir(const DIR *dirp) +telldir(DIR *dirp) { - int index; - struct ddloc *lp; + long i = 0; + struct ddloc *lp = dirp->dd_td->td_locs; + + /* return previous telldir, if there */ + for (; i < dirp->dd_td->td_loccnt; i++, lp++) { + if (lp->loc_seek == dirp->dd_seek && + lp->loc_loc == dirp->dd_loc) + return (i); + } - if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) - return (-1); - index = dd_loccnt++; - lp->loc_index = index; + if (dirp->dd_td->td_loccnt == dirp->dd_td->td_sz) { + size_t newsz = dirp->dd_td->td_sz * 2 + 1; + struct ddloc *p; + p = realloc(dirp->dd_td->td_locs, newsz * sizeof(*p)); + if (p == NULL) + return (-1); + dirp->dd_td->td_sz = newsz; + dirp->dd_td->td_locs = p; + lp = &dirp->dd_td->td_locs[i]; + } + dirp->dd_td->td_loccnt++; 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); + return (i); } /* @@ -89,21 +76,13 @@ void __seekdir(DIR *dirp, long loc) { struct ddloc *lp; - struct ddloc **prevlp; struct dirent *dp; - 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) + if (loc < 0 || loc >= dirp->dd_td->td_loccnt) return; + lp = &dirp->dd_td->td_locs[loc]; if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek) - goto found; + return; (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET); dirp->dd_seek = lp->loc_seek; dirp->dd_loc = 0; @@ -112,9 +91,4 @@ __seekdir(DIR *dirp, long loc) if (dp == NULL) break; } -found: -#ifdef SINGLEUSE - *prevlp = lp->loc_next; - free((caddr_t)lp); -#endif } diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h new file mode 100644 index 00000000000..7e10ed9e497 --- /dev/null +++ b/lib/libc/gen/telldir.h @@ -0,0 +1,62 @@ +/* $OpenBSD: telldir.h,v 1.1 2006/04/01 18:06:59 otto Exp $ */ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2000 + * Daniel Eischen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/gen/telldir.h,v 1.2 2001/01/24 12:59:24 deischen Exp $ + */ + +#ifndef _TELLDIR_H_ +#define _TELLDIR_H_ + +/* + * 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 { + long loc_seek; /* magic cookie returned by getdirentries */ + long loc_loc; /* offset of entry in buffer */ +}; + +/* + * One of these structures is malloced for each DIR to record telldir + * positions. + */ +struct _telldir { + struct ddloc *td_locs; /* locations */ + size_t td_sz; /* size of locations */ + long td_loccnt; /* index of entry for sequential readdir's */ +}; + +void __seekdir(DIR *, long); + +#endif |