summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/dirent.h6
-rw-r--r--lib/libc/gen/closedir.c9
-rw-r--r--lib/libc/gen/directory.38
-rw-r--r--lib/libc/gen/opendir.c12
-rw-r--r--lib/libc/gen/seekdir.c5
-rw-r--r--lib/libc/gen/telldir.c82
-rw-r--r--lib/libc/gen/telldir.h62
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