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.
This commit is contained in:
Ulrich Drepper 2000-08-14 17:41:59 +00:00
parent 8c2f6130c3
commit 14860991fc
9 changed files with 204 additions and 65 deletions

View File

@ -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.

View 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

View 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;
}
}

View File

@ -32,6 +32,19 @@
#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));
off_t last_offset = -1;
ssize_t retval;
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)
#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);
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 ((char *) dp == buf)
/* 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));
#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));
dp = (DIRENT_TYPE *) ((char *) dp + new_reclen);
kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
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;

View File

@ -19,8 +19,6 @@ libc {
# a*
alphasort64;
# g*
getdirentries64;
# New rlimit interface
getrlimit; setrlimit; getrlimit64;

View 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>

View File

@ -136,3 +136,9 @@
#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

View 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;
}
}

View 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;
}
}