diff options
author | "Steven J. Hill" <sjhill@realitydiluted.com> | 2006-02-28 03:18:23 +0000 |
---|---|---|
committer | "Steven J. Hill" <sjhill@realitydiluted.com> | 2006-02-28 03:18:23 +0000 |
commit | 675d62ac876ffe4719580d45b8c9469934ccf6d7 (patch) | |
tree | e666bd4a1d816842c070e4928715d66b82655fc2 /libc/sysdeps/linux/common/getdents.c | |
parent | fd666fca933f7241ff75d06ff36c9282fd443335 (diff) | |
download | uClibc-alpine-675d62ac876ffe4719580d45b8c9469934ccf6d7.tar.bz2 uClibc-alpine-675d62ac876ffe4719580d45b8c9469934ccf6d7.tar.xz |
Merge from trunk.
Diffstat (limited to 'libc/sysdeps/linux/common/getdents.c')
-rw-r--r-- | libc/sysdeps/linux/common/getdents.c | 86 |
1 files changed, 60 insertions, 26 deletions
diff --git a/libc/sysdeps/linux/common/getdents.c b/libc/sysdeps/linux/common/getdents.c index f7f3a2f12..7fe191d77 100644 --- a/libc/sysdeps/linux/common/getdents.c +++ b/libc/sysdeps/linux/common/getdents.c @@ -1,20 +1,8 @@ -/* Copyright (C) 1993, 1995-2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ +/* + * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ #include <alloca.h> #include <assert.h> @@ -28,23 +16,37 @@ #include <sys/types.h> #include <sys/syscall.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 ... + * + * See __ASSUME_GETDENTS32_D_TYPE in glibc's kernel-features.h for specific + * version / arch details. + */ + #ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif struct kernel_dirent { - long d_ino; - __kernel_off_t d_off; - unsigned short d_reclen; - char d_name[256]; + long int d_ino; + __kernel_off_t d_off; + unsigned short int d_reclen; + char d_name[256]; }; +ssize_t __getdents (int fd, char *buf, size_t nbytes) attribute_hidden; + +#if ! defined __UCLIBC_HAS_LFS__ || ! defined __NR_getdents64 + +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 attribute_hidden __getdents (int fd, char *buf, size_t nbytes) +ssize_t __getdents (int fd, char *buf, size_t nbytes) { struct dirent *dp; off_t last_offset = -1; @@ -75,7 +77,7 @@ ssize_t attribute_hidden __getdents (int fd, char *buf, size_t nbytes) /* Our heuristic failed. We read too many entries. Reset the stream. */ assert (last_offset != -1); - __lseek(fd, last_offset, SEEK_SET); + lseek(fd, last_offset, SEEK_SET); if ((char *) dp == buf) { /* The buffer the user passed in is too small to hold even @@ -91,10 +93,42 @@ ssize_t attribute_hidden __getdents (int fd, char *buf, size_t nbytes) dp->d_off = kdp->d_off; dp->d_reclen = new_reclen; dp->d_type = DT_UNKNOWN; - __memcpy (dp->d_name, kdp->d_name, + memcpy (dp->d_name, kdp->d_name, kdp->d_reclen - offsetof (struct kernel_dirent, d_name)); dp = (struct dirent *) ((char *) dp + new_reclen); kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen); } return (char *) dp - buf; } + +#elif __WORDSIZE == 32 + +libc_hidden_proto(memmove) + +extern __typeof(__getdents) __getdents64 attribute_hidden; +ssize_t __getdents (int fd, char *buf, size_t nbytes) +{ + struct dirent *dp; + struct dirent64 *dp64; + ssize_t ret = __getdents64 (fd, buf, nbytes); + + if (ret <= 0) + return ret; + + dp64 = (struct dirent64 *) buf; + buf += ret; + while ((void *) dp64 < (void *) buf) { + dp = (struct dirent *) dp64; + dp->d_ino = dp64->d_ino; + dp->d_off = dp64->d_off; + dp->d_reclen = dp64->d_reclen; + dp->d_type = dp64->d_type; + memmove (dp->d_name, dp64->d_name, dp->d_reclen - offsetof (struct dirent64, d_name)); + memmove (dp64, dp, dp->d_reclen); + dp64 = ((void *) dp64) + dp->d_reclen; + } + + return ret; +} + +#endif |