summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/common/getdents.c
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2012-10-11 11:30:59 +0100
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2013-02-20 13:45:12 +0100
commit92b784d6a58d8baa52289bea6a286752c3e6200e (patch)
treee6d23fd7c9aed5003bf6419df742ea0fd8a6a4ef /libc/sysdeps/linux/common/getdents.c
parent524744db1f05b57dc254419009370a8577a49894 (diff)
getdents: Use getdents64 if arch does not have the getdents syscall
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Diffstat (limited to 'libc/sysdeps/linux/common/getdents.c')
-rw-r--r--libc/sysdeps/linux/common/getdents.c50
1 files changed, 36 insertions, 14 deletions
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 <assert.h>
-# include <stddef.h>
-# include <errno.h>
-# include <unistd.h>
-# include <sys/param.h>
-# include <bits/uClibc_alloc.h>
+# include <assert.h>
+# include <stddef.h>
+# include <errno.h>
+# include <unistd.h>
+# include <sys/param.h>
+# include <bits/uClibc_alloc.h>
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 <stddef.h>
+# include <stddef.h>
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