Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src fix rewinddir on nfs. fix PR/42879 (and probably PR/40229.)
details: https://anonhg.NetBSD.org/src/rev/bbcdabd7db19
branches: trunk
changeset: 757838:bbcdabd7db19
user: yamt <yamt%NetBSD.org@localhost>
date: Sun Sep 26 02:26:59 2010 +0000
description:
fix rewinddir on nfs. fix PR/42879 (and probably PR/40229.)
diffstat:
include/dirent.h | 4 +-
lib/libc/gen/Makefile.inc | 4 +-
lib/libc/gen/closedir.c | 15 +-
lib/libc/gen/dirent_private.h | 4 +-
lib/libc/gen/initdir.c | 274 ++++++++++++++++++++++++++++++++++++++++++
lib/libc/gen/opendir.c | 262 ++++++----------------------------------
lib/libc/gen/rewinddir.c | 23 +-
7 files changed, 338 insertions(+), 248 deletions(-)
diffs (truncated from 739 to 300 lines):
diff -r b1c8750a7a2f -r bbcdabd7db19 include/dirent.h
--- a/include/dirent.h Sat Sep 25 22:14:07 2010 +0000
+++ b/include/dirent.h Sun Sep 26 02:26:59 2010 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dirent.h,v 1.33 2009/02/24 18:41:40 christos Exp $ */
+/* $NetBSD: dirent.h,v 1.34 2010/09/26 02:26:59 yamt Exp $ */
/*-
* Copyright (c) 1989, 1993
@@ -74,6 +74,8 @@
#define DTF_NODUP 0x0002 /* don't return duplicate names */
#define DTF_REWIND 0x0004 /* rewind after reading union stack */
#define __DTF_READALL 0x0008 /* everything has been read */
+#define __DTF_RETRY_ON_BADCOOKIE 0x0001 /* retry on EINVAL
+ (only valid with __DTF_READALL) */
#include <sys/null.h>
diff -r b1c8750a7a2f -r bbcdabd7db19 lib/libc/gen/Makefile.inc
--- a/lib/libc/gen/Makefile.inc Sat Sep 25 22:14:07 2010 +0000
+++ b/lib/libc/gen/Makefile.inc Sun Sep 26 02:26:59 2010 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.inc,v 1.171 2010/08/27 08:38:41 christos Exp $
+# $NetBSD: Makefile.inc,v 1.172 2010/09/26 02:26:59 yamt Exp $
# from: @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
# gen sources
@@ -15,7 +15,7 @@
getloadavg.c getlogin.c getmntinfo.c \
getnetgrent.c getpagesize.c \
getpass.c getprogname.c getpwent.c getttyent.c \
- getusershell.c glob.c humanize_number.c initgroups.c \
+ getusershell.c glob.c humanize_number.c initdir.c initgroups.c \
isascii.c isatty.c isctype.c lockf.c nftw.c \
nice.c nlist.c nlist_aout.c \
nlist_coff.c nlist_ecoff.c nlist_elf32.c nlist_elf64.c opendir.c \
diff -r b1c8750a7a2f -r bbcdabd7db19 lib/libc/gen/closedir.c
--- a/lib/libc/gen/closedir.c Sat Sep 25 22:14:07 2010 +0000
+++ b/lib/libc/gen/closedir.c Sun Sep 26 02:26:59 2010 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: closedir.c,v 1.15 2006/05/17 20:36:50 christos Exp $ */
+/* $NetBSD: closedir.c,v 1.16 2010/09/26 02:26:59 yamt Exp $ */
/*
* Copyright (c) 1983, 1993
@@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "@(#)closedir.c 8.1 (Berkeley) 6/10/93";
#else
-__RCSID("$NetBSD: closedir.c,v 1.15 2006/05/17 20:36:50 christos Exp $");
+__RCSID("$NetBSD: closedir.c,v 1.16 2010/09/26 02:26:59 yamt Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@@ -62,7 +62,6 @@
closedir(DIR *dirp)
{
int fd;
- struct dirpos *poslist;
_DIAGASSERT(dirp != NULL);
@@ -72,15 +71,7 @@
#endif
fd = dirp->dd_fd;
dirp->dd_fd = -1;
- dirp->dd_loc = 0;
- free(dirp->dd_buf);
-
- /* free seekdir/telldir storage */
- for (poslist = dirp->dd_internal; poslist; ) {
- struct dirpos *nextpos = poslist->dp_next;
- free(poslist);
- poslist = nextpos;
- }
+ _finidir(dirp);
#ifdef _REENTRANT
if (__isthreaded) {
diff -r b1c8750a7a2f -r bbcdabd7db19 lib/libc/gen/dirent_private.h
--- a/lib/libc/gen/dirent_private.h Sat Sep 25 22:14:07 2010 +0000
+++ b/lib/libc/gen/dirent_private.h Sun Sep 26 02:26:59 2010 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dirent_private.h,v 1.3 2010/09/16 02:38:50 yamt Exp $ */
+/* $NetBSD: dirent_private.h,v 1.4 2010/09/26 02:26:59 yamt Exp $ */
/*
* One struct _dirpos is malloced to describe the current directory
@@ -15,6 +15,8 @@
struct _dirdesc;
void _seekdir_unlocked(struct _dirdesc *, long);
long _telldir_unlocked(struct _dirdesc *);
+int _initdir(DIR *, int, const char *);
+void _finidir(DIR *);
#ifndef __LIBC12_SOURCE__
struct dirent;
struct dirent *_readdir_unlocked(struct _dirdesc *, int)
diff -r b1c8750a7a2f -r bbcdabd7db19 lib/libc/gen/initdir.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libc/gen/initdir.c Sun Sep 26 02:26:59 2010 +0000
@@ -0,0 +1,274 @@
+/* $NetBSD: initdir.c,v 1.1 2010/09/26 02:26:59 yamt Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: initdir.c,v 1.1 2010/09/26 02:26:59 yamt Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include "extern.h"
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dirent_private.h"
+
+#define MAXITERATIONS 100
+
+int
+_initdir(DIR *dirp, int fd, const char *name)
+{
+ int flags = dirp->dd_flags;
+ int pagesz;
+ int incr;
+
+ /*
+ * If the machine's page size is an exact multiple of DIRBLKSIZ,
+ * use a buffer that is cluster boundary aligned.
+ * Hopefully this can be a big win someday by allowing page trades
+ * to user space to be done by getdents()
+ */
+ if (((pagesz = getpagesize()) % DIRBLKSIZ) == 0)
+ incr = pagesz;
+ else
+ incr = DIRBLKSIZ;
+
+ if ((flags & DTF_REWIND) && name == NULL) {
+ return EINVAL;
+ }
+ if ((flags & __DTF_READALL) != 0) {
+ size_t len;
+ size_t space;
+ char *buf, *nbuf;
+ char *ddptr;
+ char *ddeptr;
+ int n;
+ struct dirent **dpv;
+ int i;
+
+ /*
+ * The strategy here for directories on top of a union stack
+ * is to read all the directory entries into a buffer, sort
+ * the buffer, and remove duplicate entries by setting the
+ * inode number to zero.
+ *
+ * For directories on an NFS mounted filesystem, we try
+ * to get a consistent snapshot by trying until we have
+ * successfully read all of the directory without errors
+ * (i.e. 'bad cookie' errors from the server because
+ * the directory was modified). These errors should not
+ * happen often, but need to be dealt with.
+ */
+ i = 0;
+retry:
+ len = 0;
+ space = 0;
+ buf = 0;
+ ddptr = 0;
+
+ do {
+ /*
+ * Always make at least DIRBLKSIZ bytes
+ * available to getdents
+ */
+ if (space < DIRBLKSIZ) {
+ space += incr;
+ len += incr;
+ nbuf = realloc(buf, len);
+ if (nbuf == NULL) {
+ dirp->dd_buf = buf;
+ return errno;
+ }
+ buf = nbuf;
+ ddptr = buf + (len - space);
+ }
+
+ dirp->dd_seek = lseek(fd, (off_t)0, SEEK_CUR);
+ n = getdents(fd, ddptr, space);
+ /*
+ * For NFS: EINVAL means a bad cookie error
+ * from the server. Keep trying to get a
+ * consistent view, in this case this means
+ * starting all over again.
+ */
+ if (n == -1 && errno == EINVAL &&
+ (flags & __DTF_RETRY_ON_BADCOOKIE) != 0) {
+ free(buf);
+ lseek(fd, (off_t)0, SEEK_SET);
+ if (++i > MAXITERATIONS)
+ return EINVAL;
+ goto retry;
+ }
+ if (n > 0) {
+ ddptr += n;
+ space -= n;
+ }
+ } while (n > 0);
+
+ ddeptr = ddptr;
+
+ /*
+ * Re-open the directory.
+ * This has the effect of rewinding back to the
+ * top of the union stack and is needed by
+ * programs which plan to fchdir to a descriptor
+ * which has also been read -- see fts.c.
+ */
+ if (flags & DTF_REWIND) {
+ (void) close(fd);
+ if ((fd = open(name, O_RDONLY)) == -1 ||
+ fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ dirp->dd_buf = buf;
+ return errno;
+ }
+ }
+
+ /*
+ * There is now a buffer full of (possibly) duplicate
+ * names.
+ */
+ dirp->dd_buf = buf;
+
+ /*
+ * Go round this loop twice...
+ *
+ * Scan through the buffer, counting entries.
+ * On the second pass, save pointers to each one.
+ * Then sort the pointers and remove duplicate names.
+ */
+ if ((flags & DTF_NODUP) != 0) {
+ for (dpv = 0;;) {
+ for (n = 0, ddptr = buf; ddptr < ddeptr;) {
+ struct dirent *dp;
+
+ dp = (struct dirent *)(void *)ddptr;
+ if ((long)dp & _DIRENT_ALIGN(dp))
+ break;
+ /*
+ * d_reclen is unsigned,
+ * so no need to compare <= 0
+ */
+ if (dp->d_reclen > (ddeptr + 1 - ddptr))
+ break;
+ ddptr += dp->d_reclen;
+ if (dp->d_fileno) {
+ if (dpv)
+ dpv[n] = dp;
+ n++;
+ }
+ }
+
+ if (dpv) {
+ struct dirent *xp;
Home |
Main Index |
Thread Index |
Old Index