This is the mail archive of the libc-alpha@cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: libc/1068: [glibc] Possible erroneous return code from Linux __getdirentries



Hi Jamie,

Ulrich made the following patch which should address most of your
reported problems (ignore Hurd, it's handled separatly).

If you see any problems with this patch, please send your comments to
libc-alpha.  I'm off line the next two weeks and will not answer your
emails.

Andreas

1999-04-27  Ulrich Drepper  <drepper@cygnus.com>

	* include/dirent.h: Remove __getdirentries declaration, add __getdents
	and __getdents64.
	* sysdeps/unix/readdir.c: Use __getdents, not __getdirentries.
	* sysdeps/unix/readdir_r.c: Likewise.
	* sysdeps/unix/sysv/linux/readdir64.c: Likewise.
	* sysdeps/unix/sysv/linux/readdir64_r.c: Likewise.
	* sysdeps/unix/sysv/linux/getdents.c: Define __getdents, not
	__getdirentries.  Remove fourth argument.
	* sysdeps/unix/sysv/linux/getdirentries.c: New file.
	* sysdeps/unix/sysv/linux/getdirentries64.c: New file.
	* sysdeps/unix/sysv/linux/Makefile [subdir=dirent] (sysdep_routines):
	Add getdirentries and getdirentries64.
	* sysdeps/unix/sysv/linux/Dist: Add getdirentries and getdirentries64.

Index: include/dirent.h
===================================================================
--- dirent.h	1998/08/10 15:51:17	1.3
+++ dirent.h	1999/04/27 13:01:43	1.4
@@ -8,6 +8,8 @@
 extern struct dirent64 *__readdir64 __P ((DIR *__dirp));
 extern int __readdir_r __P ((DIR *__dirp, struct dirent *__entry,
 			     struct dirent **__result));
-extern __ssize_t __getdirentries __P ((int __fd, char *__buf,
-				       size_t __nbytes, __off_t *__basep));
+extern __ssize_t __getdents __P ((int __fd, char *__buf, size_t __nbytes))
+     internal_function;
+extern __ssize_t __getdents64 __P ((int __fd, char *__buf, size_t __nbytes))
+     internal_function;
 #endif
Index: sysdeps/unix/readdir.c
===================================================================
--- readdir.c	1997/01/23 04:23:47	1.16
+++ readdir.c	1999/04/27 13:02:36	1.17
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,94,95,96,97,99 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -45,7 +45,6 @@
 	  /* We've emptied out our buffer.  Refill it.  */
 
 	  size_t maxread;
-	  off_t base;
 	  ssize_t bytes;
 
 #ifndef _DIRENT_HAVE_D_RECLEN
@@ -55,8 +54,7 @@
 	  maxread = dirp->allocation;
 #endif
 
-	  base = dirp->filepos;
-	  bytes = __getdirentries (dirp->fd, dirp->data, maxread, &base);
+	  bytes = __getdents (dirp->fd, dirp->data, maxread);
 	  if (bytes <= 0)
 	    {
 	      dp = NULL;
Index: sysdeps/unix/readdir_r.c
===================================================================
--- readdir_r.c	1998/03/10 11:10:00	1.6
+++ readdir_r.c	1999/04/27 13:02:46	1.7
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -44,7 +44,6 @@
 	  /* We've emptied out our buffer.  Refill it.  */
 
 	  size_t maxread;
-	  off_t base;
 	  ssize_t bytes;
 
 #ifndef _DIRENT_HAVE_D_RECLEN
@@ -54,8 +53,7 @@
 	  maxread = dirp->allocation;
 #endif
 
-	  base = dirp->filepos;
-	  bytes = __getdirentries (dirp->fd, dirp->data, maxread, &base);
+	  bytes = __getdents (dirp->fd, dirp->data, maxread);
 	  if (bytes <= 0)
 	    {
 	      dp = NULL;
Index: sysdeps/unix/sysv/linux/Dist
===================================================================
--- Dist	1999/01/25 09:33:42	1.67
+++ Dist	1999/04/27 13:06:18	1.68
@@ -1,6 +1,8 @@
 bits/pthreadtypes.h
 cmsg_nxthdr.c
 errlist.h
+getdirentries.c
+getdirentries64.c
 init-first.h
 kernel_sigaction.h
 kernel_stat.h
Index: sysdeps/unix/sysv/linux/Makefile
===================================================================
--- Makefile	1999/01/24 10:40:24	1.102
+++ Makefile	1999/04/27 13:05:45	1.103
@@ -97,7 +97,7 @@
 inhibit-glue = yes
 
 ifeq ($(subdir),dirent)
-sysdep_routines += getdents64
+sysdep_routines += getdents64 getdirentries getdirentries64
 endif
 
 ifeq ($(subdir),nis)
Index: sysdeps/unix/sysv/linux/getdents.c
===================================================================
--- getdents.c	1999/04/07 05:07:38	1.7
+++ getdents.c	1999/04/27 13:04:33	1.8
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -51,22 +51,23 @@
   };
 
 #ifdef GETDENTS64
-#define __getdirentries __getdirentries64
-#define dirent dirent64
+# define __getdents __getdents64
+# define dirent dirent64
 #endif
 
 /* The problem here is that we cannot simply read the next NBYTES
    bytes.  We need to take the additional field into account.  We use
    some heuristic.  Assuming the directory contains names with 14
-   characters on average we can compute an estimate number of entries
+   characters on average we can compute an estimated number of entries
    which fit in the buffer.  Taking this number allows us to specify a
-   correct number of bytes to read.  If we should be wrong, we can reset
-   the file descriptor.  */
+   reasonable number of bytes to read.  If we should be wrong, we can
+   reset the file descriptor.  In practice the kernel is limiting the
+   amount of data returned much more then the reduced buffer size.  */
 ssize_t
-__getdirentries (int fd, char *buf, size_t nbytes, off_t *basep)
+internal_function
+__getdents (int fd, char *buf, size_t nbytes)
 {
-  off_t base = __lseek (fd, (off_t) 0, SEEK_CUR);
-  off_t last_offset = base;
+  off_t last_offset = 0;
   size_t red_nbytes;
   struct kernel_dirent *skdp, *kdp;
   struct dirent *dp;
@@ -84,7 +85,7 @@
 
   if (retval == -1)
     return -1;
-  
+
   while ((char *) kdp < (char *) skdp + retval)
     {
       const size_t alignment = __alignof__ (struct dirent);
@@ -95,8 +96,13 @@
       if ((char *) dp + new_reclen > buf + nbytes)
 	{
 	  /* Our heuristic failed.  We read too many entries.  Reset
-	     the stream.  */
-	  __lseek (fd, last_offset, SEEK_SET);
+	     the stream.  `last_offset' contains the last known
+	     position.  If it is zero this is the first record we are
+	     reading.  In this case do a relative search.  */
+	  if (last_offset == 0)
+	    __lseek (fd, -retval, SEEK_CUR);
+	  else
+	    __lseek (fd, last_offset, SEEK_SET);
 	  break;
 	}
 
@@ -112,12 +118,5 @@
       kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
     }
 
-  if (basep)
-    *basep = base;
-
   return (char *) dp - buf;
 }
-
-#ifndef GETDENTS64
-weak_alias (__getdirentries, getdirentries)
-#endif
Index: sysdeps/unix/sysv/linux/readdir64.c
===================================================================
--- readdir64.c	1998/03/20 12:05:02	1.2
+++ readdir64.c	1999/04/27 13:03:12	1.3
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -27,9 +27,6 @@
 
 #include <dirstream.h>
 
-extern ssize_t __getdirentries64 (int, char *, size_t, off_t *);
-
-
 /* Read a directory entry from DIRP.  */
 struct dirent64 *
 __readdir64 (DIR *dirp)
@@ -47,7 +44,6 @@
 	  /* We've emptied out our buffer.  Refill it.  */
 
 	  size_t maxread;
-	  off_t base;
 	  ssize_t bytes;
 
 #ifndef _DIRENT_HAVE_D_RECLEN
@@ -57,8 +53,7 @@
 	  maxread = dirp->allocation;
 #endif
 
-	  base = dirp->filepos;
-	  bytes = __getdirentries64 (dirp->fd, dirp->data, maxread, &base);
+	  bytes = __getdents64 (dirp->fd, dirp->data, maxread);
 	  if (bytes <= 0)
 	    {
 	      dp = NULL;
Index: sysdeps/unix/sysv/linux/readdir64_r.c
===================================================================
--- readdir64_r.c	1998/03/10 11:09:48	1.2
+++ readdir64_r.c	1999/04/27 13:03:13	1.3
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -27,9 +27,6 @@
 
 #include <dirstream.h>
 
-extern ssize_t __getdirentries64 (int, char *, size_t, off_t *);
-
-
 /* Read a directory entry from DIRP, store result in ENTRY and return
    pointer to result in *RESULT.  */
 int
@@ -47,7 +44,6 @@
 	  /* We've emptied out our buffer.  Refill it.  */
 
 	  size_t maxread;
-	  off_t base;
 	  ssize_t bytes;
 
 #ifndef _DIRENT_HAVE_D_RECLEN
@@ -57,8 +53,7 @@
 	  maxread = dirp->allocation;
 #endif
 
-	  base = dirp->filepos;
-	  bytes = __getdirentries64 (dirp->fd, dirp->data, maxread, &base);
+	  bytes = __getdents64 (dirp->fd, dirp->data, maxread);
 	  if (bytes <= 0)
 	    {
 	      dp = NULL;
--- /dev/null	Sun May 24 15:02:15 1998
+++ sysdeps/unix/sysv/linux/getdirentries.c	Tue Apr 27 15:04:46 1999
@@ -0,0 +1,39 @@
+/* Copyright (C) 1993, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dirent.h>
+#include <unistd.h>
+
+#ifdef GETDENTS64
+# define getdirentries getdirentries64
+# define __getdents __getdents64
+#endif
+
+ssize_t
+getdirentries (int fd, char *buf, size_t nbytes, off_t *basep)
+{
+  off_t base = __lseek (fd, (off_t) 0, SEEK_CUR);
+  ssize_t result;
+
+  result = __getdents (fd, buf, nbytes);
+
+  if (result != -1)
+    *basep = base;
+
+  return result;
+}
--- /dev/null	Sun May 24 15:02:15 1998
+++ sysdeps/unix/sysv/linux/getdirentries64.c	Tue Apr 27 15:04:51 1999
@@ -0,0 +1,2 @@
+#define GETDENTS64 1
+#include "getdirentries.c"


-- 
 Andreas Jaeger   aj@arthur.rhein-neckar.de    jaeger@informatik.uni-kl.de
  for pgp-key finger ajaeger@aixd1.rhrk.uni-kl.de


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]