[PATCH v3 29/48] getdents: Use getdents64 if arch does not have the getdents syscall
Markos Chandras
markos.chandras at gmail.com
Wed Jan 23 11:41:53 UTC 2013
From: Markos Chandras <markos.chandras at imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras at imgtec.com>
---
libc/sysdeps/linux/common/getdents.c | 26 +++++++++++++++++++++++---
libc/sysdeps/linux/common/getdents64.c | 2 +-
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/libc/sysdeps/linux/common/getdents.c b/libc/sysdeps/linux/common/getdents.c
index f4fb747..dd95396 100644
--- a/libc/sysdeps/linux/common/getdents.c
+++ b/libc/sysdeps/linux/common/getdents.c
@@ -26,6 +26,7 @@
* version / arch details.
*/
+#ifndef kernel_dirent
struct kernel_dirent
{
long int d_ino;
@@ -33,11 +34,14 @@ struct kernel_dirent
unsigned short int d_reclen;
char d_name[256];
};
+#endif
+#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,7 +70,7 @@ 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 <assert.h>
# include <stddef.h>
@@ -85,6 +89,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 +98,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,7 +154,7 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes)
return (char *) dp - buf;
}
-#elif __WORDSIZE == 32
+#elif __WORDSIZE == 32 && !defined(__NR_getdents64)
# include <stddef.h>
diff --git a/libc/sysdeps/linux/common/getdents64.c b/libc/sysdeps/linux/common/getdents64.c
index aacbe97..b4e8973 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)
--
1.8.1.1
More information about the uClibc
mailing list