diff options
| -rw-r--r-- | libc/sysdeps/linux/common/getdents.c | 39 | ||||
| -rw-r--r-- | libpthread/linuxthreads/sysdeps/pthread/kernel-features.h | 8 | 
2 files changed, 41 insertions, 6 deletions
| diff --git a/libc/sysdeps/linux/common/getdents.c b/libc/sysdeps/linux/common/getdents.c index d858eab91..97c6d8b06 100644 --- a/libc/sysdeps/linux/common/getdents.c +++ b/libc/sysdeps/linux/common/getdents.c @@ -18,8 +18,7 @@  #include <bits/kernel_types.h>  /* With newer versions of linux, the getdents syscall returns d_type - * information after the name field.  Someday, we should add support for - * that instead of always calling getdents64 ... + * information after the name field.   *   * See __ASSUME_GETDENTS32_D_TYPE in glibc's kernel-features.h for specific   * version / arch details. @@ -39,14 +38,42 @@ struct kernel_dirent  ssize_t __getdents (int fd, char *buf, size_t nbytes) attribute_hidden; -#if ! defined __UCLIBC_HAS_LFS__ || ! defined __NR_getdents64 +#define __NR___syscall_getdents __NR_getdents +static inline _syscall3(int, __syscall_getdents, int, fd, unsigned char *, kdirp, size_t, count); + +#ifdef __ASSUME_GETDENTS32_D_TYPE +ssize_t __getdents (int fd, char *buf, size_t nbytes) +{ +	ssize_t retval; + +	retval = __syscall_getdents(fd, (unsigned char *)buf, nbytes); + +	/* The kernel added the d_type value after the name.  Change +	this now.  */ +	if (retval != -1) { +		union { +			struct kernel_dirent k; +			struct dirent u; +		} *kbuf = (void *) buf; + +		while ((char *) kbuf < buf + retval) { +			char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1); +			memmove (kbuf->u.d_name, kbuf->k.d_name, +			strlen (kbuf->k.d_name) + 1); +			kbuf->u.d_type = d_type; + +			kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen); +		} +	} + +	return retval; +} + +#elif ! defined __UCLIBC_HAS_LFS__ || ! defined __NR_getdents64  /* Experimentally off - libc_hidden_proto(memcpy) */  libc_hidden_proto(lseek) -#define __NR___syscall_getdents __NR_getdents -static __inline__ _syscall3(int, __syscall_getdents, int, fd, unsigned char *, kdirp, size_t, count); -  ssize_t __getdents (int fd, char *buf, size_t nbytes)  {      struct dirent *dp; diff --git a/libpthread/linuxthreads/sysdeps/pthread/kernel-features.h b/libpthread/linuxthreads/sysdeps/pthread/kernel-features.h index 424922ec0..88a71828b 100644 --- a/libpthread/linuxthreads/sysdeps/pthread/kernel-features.h +++ b/libpthread/linuxthreads/sysdeps/pthread/kernel-features.h @@ -62,6 +62,14 @@  # define __ASSUME_VFORK_SYSCALL		1  #endif +/* Starting with version 2.6.4-rc1 the getdents syscall returns d_type + *    information as well and in between 2.6.5 and 2.6.8 most compat wrappers + *       were fixed too.  Except s390{,x} which was fixed in 2.6.11.  */ +#if (__LINUX_KERNEL_VERSION >= 0x020608 && !defined __s390__) \ +    || (__LINUX_KERNEL_VERSION >= 0x02060b && defined __s390__) +# define __ASSUME_GETDENTS32_D_TYPE 1 +#endif +  /* These features were surely available with 2.4.12.  */  #if __LINUX_KERNEL_VERSION >= 132108 && defined __mc68000__  # define __ASSUME_MMAP2_SYSCALL		1 | 
