]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Update.
authorUlrich Drepper <drepper@redhat.com>
Mon, 14 Aug 2000 17:41:59 +0000 (17:41 +0000)
committerUlrich Drepper <drepper@redhat.com>
Mon, 14 Aug 2000 17:41:59 +0000 (17:41 +0000)
2000-08-14  Jakub Jelinek  <jakub@redhat.com>

* dirent/Versions (getdirentries64): Export at GLIBC_2.2.
* sysdeps/unix/sysv/linux/kernel-features.h
(__ASSUME_GETDENTS64_SYSCALL): Define.
* sysdeps/unix/sysv/linux/getdents.c (__getdents): Use getdents64
syscall if available to get d_type fields.
* sysdeps/unix/sysv/linux/alpha/getdents.c (DIRENT_TYPE): Define.
* sysdeps/unix/sysv/linux/arm/Versions (__xstat64, __fxstat64,
__lxstat64): Export at GLIBC_2.2.
(alphasort64, readdir64, readdir64_r, scandir64, versionsort64):
Likewise.
* sysdeps/unix/sysv/linux/i386/Versions (getdirentries64): Remove.
* sysdeps/unix/sysv/linux/i386/getdents64.c (kernel_dirent64): Define.
* sysdeps/unix/sysv/linux/powerpc/Versions (alphasort64,
getdirentries64, versionsort64): Remove.
* sysdeps/unix/sysv/linux/sparc/sparc32/Versions (alphasort64,
getdirentries64, versionsort64): Remove.

ChangeLog
sysdeps/unix/sysv/linux/alpha/getdents.c
sysdeps/unix/sysv/linux/arm/Versions
sysdeps/unix/sysv/linux/getdents.c
sysdeps/unix/sysv/linux/i386/Versions
sysdeps/unix/sysv/linux/i386/getdents64.c
sysdeps/unix/sysv/linux/kernel-features.h
sysdeps/unix/sysv/linux/powerpc/Versions
sysdeps/unix/sysv/linux/sparc/sparc32/Versions

index 6a4bf52c1c69db565d170dd1bce803e5a9bc3268..c552bc4c1a399ad9d31670b7fc2c2f46c9cdc65b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2000-08-14  Jakub Jelinek  <jakub@redhat.com>
+
+       * dirent/Versions (getdirentries64): Export at GLIBC_2.2.
+       * sysdeps/unix/sysv/linux/kernel-features.h
+       (__ASSUME_GETDENTS64_SYSCALL): Define.
+       * sysdeps/unix/sysv/linux/getdents.c (__getdents): Use getdents64
+       syscall if available to get d_type fields.
+       * sysdeps/unix/sysv/linux/alpha/getdents.c (DIRENT_TYPE): Define.
+       * sysdeps/unix/sysv/linux/arm/Versions (__xstat64, __fxstat64,
+       __lxstat64): Export at GLIBC_2.2.
+       (alphasort64, readdir64, readdir64_r, scandir64, versionsort64):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/Versions (getdirentries64): Remove.
+       * sysdeps/unix/sysv/linux/i386/getdents64.c (kernel_dirent64): Define.
+       * sysdeps/unix/sysv/linux/powerpc/Versions (alphasort64,
+       getdirentries64, versionsort64): Remove.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/Versions (alphasort64,
+       getdirentries64, versionsort64): Remove.
+
 2000-08-13  Ulrich Drepper  <drepper@redhat.com>
 
        * posix/Makefile: Remove rules to generate glob package.
index 6deb87e2e4e7aebfcc05ad0e0d2133089afb37f5..175be9df853d0061387d040d3ae5429a78575127 100644 (file)
@@ -1,3 +1,4 @@
+#define DIRENT_TYPE struct dirent64
 #define DIRENT_SET_DP_INO(dp, value) \
   do { (dp)->d_ino = (value); (dp)->__pad = 0; } while (0)
 #define __getdents64 __no___getdents64_decl
index 4ac5b58a9b8f478db5bef1088090a9ef939bb7e4..549808625326eefebf744ea000424edaaf31f6c6 100644 (file)
@@ -11,7 +11,22 @@ libc {
     outb; outw; outl;
   }
   GLIBC_2.2 {
+    # functions used in other libraries
+    __xstat64; __fxstat64; __lxstat64;
+
+    # a*
+    alphasort64;
+
     # New rlimit interface
     getrlimit; setrlimit; getrlimit64;
+
+    # r*
+    readdir64; readdir64_r;
+
+    # s*
+    scandir64;
+
+    # v*
+    versionsort64;
   }
 }
index 474bf1989b2e0832c69c385422fdd22195814cf9..19ab9238fea423d7f8b8437d1a6a8cffc02ffd68 100644 (file)
 
 #include <linux/posix_types.h>
 
+#include "kernel-features.h"
+
+#ifdef __NR_getdents64
+#ifndef __ASSUME_GETDENTS64_SYSCALL
+#ifndef __GETDENTS
+/* The variable is shared between all *getdents* calls.  */
+int __have_no_getdents64;
+#else
+extern int __have_no_getdents64;
+#endif
+#endif
+#endif
+
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 
 extern int __syscall_getdents (int fd, char *__unbounded buf, size_t nbytes);
@@ -51,8 +64,19 @@ struct kernel_dirent
     char d_name[256];
   };
 
+struct kernel_dirent64
+  {
+    u_int64_t          d_ino;
+    int64_t            d_off;
+    unsigned short int d_reclen;
+    unsigned char      d_type;
+    char               d_name[256];
+  };
+
 #ifndef __GETDENTS
 # define __GETDENTS __getdents
+#endif
+#ifndef DIRENT_TYPE
 # define DIRENT_TYPE struct dirent
 #endif
 #ifndef DIRENT_SET_DP_INO
@@ -71,63 +95,155 @@ ssize_t
 internal_function
 __GETDENTS (int fd, char *buf, size_t nbytes)
 {
-  off_t last_offset = -1;
-  size_t red_nbytes;
-  struct kernel_dirent *skdp, *kdp;
   DIRENT_TYPE *dp;
-  int retval;
-  const size_t size_diff = (offsetof (DIRENT_TYPE, d_name)
-                           - offsetof (struct kernel_dirent, d_name));
-
-  red_nbytes = MIN (nbytes
-                   - ((nbytes / (offsetof (DIRENT_TYPE, d_name) + 14))
-                      * size_diff),
-                   nbytes - size_diff);
-
-  dp = (DIRENT_TYPE *) buf;
-  skdp = kdp = __alloca (red_nbytes);
-
-  retval = INLINE_SYSCALL (getdents, 3, fd,
-                          CHECK_N ((char *) kdp, red_nbytes), red_nbytes);
-
-  if (retval == -1)
-    return -1;
+  off_t last_offset = -1;
+  ssize_t retval;
 
-  while ((char *) kdp < (char *) skdp + retval)
+#ifdef __NR_getdents64
+#ifndef __ASSUME_GETDENTS64_SYSCALL
+  if (!__have_no_getdents64)
+#endif
     {
-      const size_t alignment = __alignof__ (DIRENT_TYPE);
-      /* Since kdp->d_reclen is already aligned for the kernel structure
-        this may compute a value that is bigger than necessary.  */
-      size_t new_reclen = ((kdp->d_reclen + size_diff + alignment - 1)
-                          & ~(alignment - 1));
-      if ((char *) dp + new_reclen > buf + nbytes)
+#ifndef __ASSUME_GETDENTS64_SYSCALL
+      int saved_errno = errno;
+#endif
+      char *kbuf = buf;
+      size_t kbytes = nbytes;
+      if (offsetof (DIRENT_TYPE, d_name)
+         < offsetof (struct kernel_dirent64, d_name)
+         && nbytes <= sizeof (DIRENT_TYPE))
        {
-         /* Our heuristic failed.  We read too many entries.  Reset
-            the stream.  */
-         assert (last_offset != -1);
-         __lseek (fd, last_offset, SEEK_SET);
-
-         if ((char *) dp == buf)
+         kbytes = nbytes + offsetof (struct kernel_dirent64, d_name)
+                  - offsetof (DIRENT_TYPE, d_name);
+         kbuf = __alloca(kbytes);
+       }
+      retval = INLINE_SYSCALL (getdents64, 3, fd, CHECK_N(kbuf, kbytes),
+                              kbytes);
+#ifndef __ASSUME_GETDENTS64_SYSCALL
+      if (retval != -1 && errno != -EINVAL)
+#endif
+       {
+         struct kernel_dirent64 *kdp;
+         const size_t size_diff = (offsetof (struct kernel_dirent64, d_name)
+                                  - offsetof (DIRENT_TYPE, d_name));
+
+         /* If the structure returned by the kernel is identical to what we
+            need, don't do any conversions.  */
+         if (offsetof (DIRENT_TYPE, d_name)
+             == offsetof (struct kernel_dirent64, d_name)
+             && sizeof (dp->d_ino) == sizeof (kdp->d_ino)
+             && sizeof (dp->d_off) == sizeof (kdp->d_off))
+           return retval;
+
+         dp = (DIRENT_TYPE *)buf;
+         kdp = (struct kernel_dirent64 *)kbuf;
+         while ((char *) kdp < kbuf + retval)
            {
-             /* The buffer the user passed in is too small to hold even
-                one entry.  */
-             __set_errno (EINVAL);
-             return -1;
+             const size_t alignment = __alignof__ (DIRENT_TYPE);
+             /* Since kdp->d_reclen is already aligned for the kernel
+                structure this may compute a value that is bigger
+                than necessary.  */
+             size_t old_reclen = kdp->d_reclen;
+             size_t new_reclen = ((old_reclen - size_diff + alignment - 1)
+                                 & ~(alignment - 1));
+             u_int64_t d_ino = kdp->d_ino;
+             int64_t d_off = kdp->d_off;
+             unsigned char d_type = kdp->d_type;
+
+             DIRENT_SET_DP_INO(dp, d_ino);
+             dp->d_off = d_off;
+             if ((sizeof (dp->d_ino) != sizeof (kdp->d_ino)
+                  && dp->d_ino != d_ino)
+                 || (sizeof (dp->d_off) != sizeof (kdp->d_off)
+                     && dp->d_off != d_off))
+               {
+                 /* Overflow.  If there was at least one entry
+                    before this one, return them without error,
+                    otherwise signal overflow.  */
+                 if (last_offset != -1)
+                   {
+                     __lseek (fd, last_offset, SEEK_SET);
+                     return (char *) dp - buf;
+                   }
+                 __set_errno (EOVERFLOW);
+                 return -1;
+               }
+
+             last_offset = d_off;
+             dp->d_reclen = new_reclen;
+             dp->d_type = d_type;
+             memmove (dp->d_name, kdp->d_name,
+                      old_reclen - offsetof (struct kernel_dirent64, d_name));
+
+             dp = (DIRENT_TYPE *) ((char *) dp + new_reclen);
+             kdp = (struct kernel_dirent64 *) ((char *) kdp + old_reclen);
            }
 
-         break;
+         return (char *) dp - buf;
        }
 
-      last_offset = kdp->d_off;
-      DIRENT_SET_DP_INO(dp, kdp->d_ino);
-      dp->d_off = kdp->d_off;
-      dp->d_reclen = new_reclen;
-      dp->d_type = DT_UNKNOWN;
-      memcpy (dp->d_name, kdp->d_name,
-             kdp->d_reclen - offsetof (struct kernel_dirent, d_name));
-
-      dp = (DIRENT_TYPE *) ((char *) dp + new_reclen);
-      kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
+#ifndef __ASSUME_GETDENTS64_SYSCALL
+      __set_errno (saved_errno);
+      __have_no_getdents64 = 1;
+#endif
+    }
+#endif
+  {
+    size_t red_nbytes;
+    struct kernel_dirent *skdp, *kdp;
+    const size_t size_diff = (offsetof (DIRENT_TYPE, d_name)
+                             - offsetof (struct kernel_dirent, d_name));
+
+    red_nbytes = MIN (nbytes
+                     - ((nbytes / (offsetof (DIRENT_TYPE, d_name) + 14))
+                        * size_diff),
+                     nbytes - size_diff);
+
+    dp = (DIRENT_TYPE *) buf;
+    skdp = kdp = __alloca (red_nbytes);
+
+    retval = INLINE_SYSCALL (getdents, 3, fd,
+                            CHECK_N ((char *) kdp, red_nbytes), red_nbytes);
+
+    if (retval == -1)
+      return -1;
+
+    while ((char *) kdp < (char *) skdp + retval)
+      {
+       const size_t alignment = __alignof__ (DIRENT_TYPE);
+       /* Since kdp->d_reclen is already aligned for the kernel structure
+          this may compute a value that is bigger than necessary.  */
+       size_t new_reclen = ((kdp->d_reclen + size_diff + alignment - 1)
+                            & ~(alignment - 1));
+       if ((char *) dp + new_reclen > buf + nbytes)
+         {
+           /* Our heuristic failed.  We read too many entries.  Reset
+              the stream.  */
+           assert (last_offset != -1);
+           __lseek (fd, last_offset, SEEK_SET);
+
+           if ((char *) dp == buf)
+             {
+               /* The buffer the user passed in is too small to hold even
+                  one entry.  */
+               __set_errno (EINVAL);
+               return -1;
+             }
+
+           break;
+         }
+
+       last_offset = kdp->d_off;
+       DIRENT_SET_DP_INO(dp, kdp->d_ino);
+       dp->d_off = kdp->d_off;
+       dp->d_reclen = new_reclen;
+       dp->d_type = DT_UNKNOWN;
+       memcpy (dp->d_name, kdp->d_name,
+               kdp->d_reclen - offsetof (struct kernel_dirent, d_name));
+
+       dp = (DIRENT_TYPE *) ((char *) dp + new_reclen);
+       kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
+      }
     }
 
   return (char *) dp - buf;
index 58c7b3d9b1dee24fa170b68ca760f2b1b02121ab..b7af24b1b3e58abcc46928c67564eaacc13524cb 100644 (file)
@@ -19,8 +19,6 @@ libc {
     # a*
     alphasort64;
 
-    # g*
-    getdirentries64;
     # New rlimit interface
     getrlimit; setrlimit; getrlimit64;
 
index dac046fa0c021bc3a94670685c720071d93d8af0..bbfff20cf06449d2a7dbb6d598ebdf31fc18630a 100644 (file)
@@ -36,6 +36,7 @@ versioned_symbol (libc, __getdents64, getdents64, GLIBC_2_2);
 #define __GETDENTS __old_getdents64
 #define DIRENT_TYPE struct __old_dirent64
 #define kernel_dirent old_kernel_dirent
+#define kernel_dirent64 old_kernel_dirent64
 
 #include <sysdeps/unix/sysv/linux/getdents.c>
 
index e7699a62f8f4810bf3391c338a8b422c7b066c16..2f9d12bb28e0d9110bc4fac00b84e2a3e3cf0cc4 100644 (file)
 #if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __sparc__)
 # define __ASSUME_FCNTL64              1
 #endif
+
+/* The getdents64 syscall was introduced in 2.4.0-test7.  We test for
+   2.4.1 for the earliest version we know the syscall is available.  */
+#if __LINUX_KERNEL_VERSION >= 132097
+# define __ASSUME_GETDENTS64_SYSCALL   1
+#endif
index 6466be2cc519e8f1515461b8a961aeecf6a65037..1ea93d74f320a9573027605c800c1aa7ea738316 100644 (file)
@@ -9,11 +9,6 @@ libc {
     # functions used in other libraries
     __xstat64; __fxstat64; __lxstat64;
 
-    # a*
-    alphasort64;
-
-    # g*
-    getdirentries64;
     # New rlimit interface
     getrlimit; setrlimit; getrlimit64; setrlimit64;
 
@@ -22,8 +17,5 @@ libc {
 
     # s*
     scandir64;
-
-    # v*
-    versionsort64;
   }
 }
index fcb9df31ec9242f4a60c80e5667f98843f3af670..2448fa2d375ef531e24f4ef106d3f4b4a7a20f84 100644 (file)
@@ -9,19 +9,10 @@ libc {
     # functions used in other libraries
     __xstat64; __fxstat64; __lxstat64;
 
-    # a*
-    alphasort64;
-
-    # g*
-    getdirentries64;
-
     # r*
     readdir64; readdir64_r;
 
     # s*
     scandir64;
-
-    # v*
-    versionsort64;
   }
 }