diff options
author | Carmelo Amoroso <carmelo.amoroso@st.com> | 2008-09-09 12:01:37 +0000 |
---|---|---|
committer | Carmelo Amoroso <carmelo.amoroso@st.com> | 2008-09-09 12:01:37 +0000 |
commit | 33bcf733559a1108049c1d33ea8fafce0150e5f8 (patch) | |
tree | 571fd5ac0719f1a2fa010427085b1582df25e764 /libc/sysdeps/linux | |
parent | 1cf466022bd863dd8f529d6da52480f445fceb96 (diff) |
Use getdents syscall if kernel provide supports for this
instead of relying upon getdents64.
Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Diffstat (limited to 'libc/sysdeps/linux')
-rw-r--r-- | libc/sysdeps/linux/common/getdents.c | 39 |
1 files changed, 33 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; |