From 92b784d6a58d8baa52289bea6a286752c3e6200e Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 11 Oct 2012 11:30:59 +0100 Subject: getdents: Use getdents64 if arch does not have the getdents syscall Signed-off-by: Markos Chandras Signed-off-by: Bernhard Reutner-Fischer --- libc/sysdeps/linux/common/getdents.c | 50 ++++++++++++++++++++++++---------- libc/sysdeps/linux/common/getdents64.c | 2 +- 2 files changed, 37 insertions(+), 15 deletions(-) (limited to 'libc/sysdeps') diff --git a/libc/sysdeps/linux/common/getdents.c b/libc/sysdeps/linux/common/getdents.c index f4fb7476e..b65524eee 100644 --- a/libc/sysdeps/linux/common/getdents.c +++ b/libc/sysdeps/linux/common/getdents.c @@ -26,6 +26,7 @@ * version / arch details. */ +# ifdef __ARCH_HAS_DEPRECATED_SYSCALLS__ struct kernel_dirent { long int d_ino; @@ -33,11 +34,16 @@ struct kernel_dirent unsigned short int d_reclen; char d_name[256]; }; +# else +# define kernel_dirent dirent +# endif -#define __NR___syscall_getdents __NR_getdents +# if defined __NR_getdents +# define __NR___syscall_getdents __NR_getdents static __always_inline _syscall3(int, __syscall_getdents, int, fd, unsigned char *, kdirp, size_t, count) +# endif -#if defined __ASSUME_GETDENTS32_D_TYPE +# if defined __ASSUME_GETDENTS32_D_TYPE && defined __NR_getdents ssize_t __getdents (int fd, char *buf, size_t nbytes) { @@ -66,14 +72,14 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes) return retval; } -#elif ! defined __UCLIBC_HAS_LFS__ || ! defined __NR_getdents64 +# elif ! defined __UCLIBC_HAS_LFS__ || !defined __NR_getdents64 -# include -# include -# include -# include -# include -# include +# include +# include +# include +# include +# include +# include ssize_t __getdents (int fd, char *buf, size_t nbytes) { @@ -85,6 +91,7 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes) const size_t size_diff = (offsetof (struct dirent, d_name) - offsetof (struct kernel_dirent, d_name)); +# ifdef __ARCH_HAS_DEPRECATED_SYSCALLS__ red_nbytes = MIN (nbytes - ((nbytes / (offsetof (struct dirent, d_name) + 14)) * size_diff), nbytes - size_diff); @@ -93,6 +100,21 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes) skdp = kdp = stack_heap_alloc(red_nbytes); retval = __syscall_getdents(fd, (unsigned char *)kdp, red_nbytes); +# else + + dp = (struct dirent *) buf; + skdp = kdp = stack_heap_alloc(nbytes); + + retval = INLINE_SYSCALL(getdents64, 3, fd, (unsigned char *)kdp, nbytes); + if (retval > 0) { + /* Did we overflow? */ + if (kdp->__pad1 || kdp->__pad2) { + __set_errno(EINVAL); + return -1; + } + } +# endif + if (retval == -1) { stack_heap_free(skdp); return -1; @@ -134,9 +156,9 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes) return (char *) dp - buf; } -#elif __WORDSIZE == 32 +# elif __WORDSIZE == 32 && !defined __NR_getdents64 -# include +# include ssize_t __getdents (int fd, char *buf, size_t nbytes) { @@ -163,10 +185,10 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes) return ret; } -#endif +# endif -#if defined __UCLIBC_HAS_LFS__ && ! defined __NR_getdents64 +# if defined __UCLIBC_HAS_LFS__ && ! defined __NR_getdents64 strong_alias(__getdents,__getdents64) -#endif +# endif #endif diff --git a/libc/sysdeps/linux/common/getdents64.c b/libc/sysdeps/linux/common/getdents64.c index aacbe97cc..017fa63c1 100644 --- a/libc/sysdeps/linux/common/getdents64.c +++ b/libc/sysdeps/linux/common/getdents64.c @@ -91,7 +91,7 @@ ssize_t __getdents64 (int fd, char *buf, size_t nbytes) return (char *) dp - buf; } -#if __WORDSIZE == 64 +#if __WORDSIZE == 64 || (defined __UCLIBC_HAS_LFS__ && !defined __NR_getdents) /* since getdents doesnt give us d_type but getdents64 does, try and * use getdents64 as much as possible */ strong_alias(__getdents64,__getdents) -- cgit v1.2.3