summaryrefslogtreecommitdiffstats
path: root/libc/sysdeps/linux/common/getdents.c
diff options
context:
space:
mode:
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
commit675d62ac876ffe4719580d45b8c9469934ccf6d7 (patch)
treee666bd4a1d816842c070e4928715d66b82655fc2 /libc/sysdeps/linux/common/getdents.c
parentfd666fca933f7241ff75d06ff36c9282fd443335 (diff)
downloaduClibc-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.c86
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