uClibc, libstdc++, and readdir()
Jeff Warren
tiny.laser at comcast.net
Tue May 23 20:01:34 UTC 2006
Hi All,
I am having trouble with readdir and uClibc and thought I would see if
anyone here could help me. The basic problem is that readdir will
return a dirent with d_type always set to zero.
Vapier committed a change on 2/3/2006 (Revision 13824) to
libc/sysdeps/linux/common/getdents.c and getdents64.c which fixes this.
I am running uClibc 0.9.26 on my target system, so I had to apply the
changes slightly differently so I didn't have to use the Large file
system flag.
So I applied the fix and put the library in my root filesystem
for the
target and I see no change.
I then look at my process and see with the gdb command 'info
sharedlibrary' that libc.so.0 is not even loaded. And that sortof makes
sense to me as it is a C++ app and it has the libstdc++.so.5.0.6 and the
lduClibc.so loaded. Here is where I get confused: In a c++ app, does
it use the installed C library to run calls such as readdir()? On my
target it doesn't seem so as I can delete uClibc from the /lib dir and
restart my application without problems.
So if it doesn't get the functionality from the installed C
library,
where does it get it from, libstdc++? I looked in there and I can't
seem to find readdir (arm-linux-readelf --syms libstdc++.so.5.0.6 | grep
readdir)
By the way, I put a printk statement in both of sys_getdents and
sys_getdents64 in my kernel (2.6.12.1) and even with my changes, I see
that readdir() fires off the sys_getdents printk when it should fire off
the sys_getdents64 printk if the changes are correct.
I have made other changes to the uClibc, for instance specifically
setting the d_type, which still seems to have no effect. I am
definitely missing some knowledge on what is going on. Any guidance on
this would be appreciated.
Thanks in advance,
Regards,
Jeff Warren
P.S. I have included the diff that containse the changes I've made
against 0.9.26.
-------------- next part --------------
--- libc/sysdeps/linux/common/getdents.c.orig 2003-02-10 13:15:20.000000000 -0800
+++ libc/sysdeps/linux/common/getdents.c 2006-05-22 10:52:32.000000000 -0700
@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <sysdep.h>
#include <sys/syscall.h>
+#include <features.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
@@ -37,64 +38,36 @@
long d_ino;
__kernel_off_t d_off;
unsigned short d_reclen;
- char d_name[256];
+ char d_name[256];
};
#define __NR___syscall_getdents __NR_getdents
static inline _syscall3(int, __syscall_getdents, int, fd, unsigned char *, kdirp, size_t, count);
+extern ssize_t __getdents64 (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;
- ssize_t retval;
- size_t red_nbytes;
- struct kernel_dirent *skdp, *kdp;
- const size_t size_diff = (offsetof (struct dirent, d_name)
- - offsetof (struct kernel_dirent, d_name));
-
- red_nbytes = MIN (nbytes - ((nbytes /
- (offsetof (struct dirent, d_name) + 14)) * size_diff),
- nbytes - size_diff);
-
- dp = (struct dirent *) buf;
- skdp = kdp = alloca (red_nbytes);
-
- retval = __syscall_getdents(fd, (char *)kdp, red_nbytes);
- if (retval == -1)
- return -1;
-
- while ((char *) kdp < (char *) skdp + retval) {
- const size_t alignment = __alignof__ (struct dirent);
- /* Since kdp->d_reclen is already aligned for the kernel structure
- this may compute a value that is bigger than necessary. */
- size_t new_reclen = ((kdp->d_reclen + size_diff + alignment - 1)
- & ~(alignment - 1));
- if ((char *) dp + new_reclen > buf + nbytes) {
- /* Our heuristic failed. We read too many entries. Reset
- the stream. */
- assert (last_offset != -1);
- lseek(fd, last_offset, SEEK_SET);
-
- if ((char *) dp == buf) {
- /* The buffer the user passed in is too small to hold even
- one entry. */
- __set_errno (EINVAL);
- return -1;
- }
- break;
- }
-
- last_offset = kdp->d_off;
- dp->d_ino = kdp->d_ino;
- dp->d_off = kdp->d_off;
- dp->d_reclen = new_reclen;
- dp->d_type = DT_UNKNOWN;
- 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);
+ 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 (char *) dp - buf;
+
+ return ret;
}
+
--- libc/sysdeps/linux/common/getdents64.c.orig 2003-02-10 13:15:20.000000000 -0800
+++ libc/sysdeps/linux/common/getdents64.c 2006-05-23 11:53:31.000000000 -0700
@@ -30,7 +30,7 @@
#include <sys/types.h>
#include <sys/syscall.h>
-#if defined __UCLIBC_HAS_LFS__ && defined __NR_getdents64
+//#if defined __NR_getdents64
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
@@ -52,7 +52,7 @@
ssize_t __getdents64 (int fd, char *buf, size_t nbytes)
{
struct dirent64 *dp;
- off64_t last_offset = -1;
+ off_t last_offset = -1;
ssize_t retval;
size_t red_nbytes;
struct kernel_dirent64 *skdp, *kdp;
@@ -80,7 +80,7 @@
/* Our heuristic failed. We read too many entries. Reset
the stream. */
assert (last_offset != -1);
- lseek64(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
@@ -95,7 +95,7 @@
dp->d_ino = kdp->d_ino;
dp->d_off = kdp->d_off;
dp->d_reclen = new_reclen;
- dp->d_type = DT_UNKNOWN;
+ dp->d_type = kdp->d_type;
memcpy (dp->d_name, kdp->d_name,
kdp->d_reclen - offsetof (struct kernel_dirent64, d_name));
dp = (struct dirent64 *) ((char *) dp + new_reclen);
@@ -103,11 +103,11 @@
}
return (char *) dp - buf;
}
-#else
+/*#else
ssize_t __getdents (int fd, char *buf, size_t nbytes);
ssize_t __getdents64 (int fd, char *buf, size_t nbytes)
{
return(__getdents(fd, buf, nbytes));
}
-#endif /* __UCLIBC_HAS_LFS__ */
+#endif*/ /* __UCLIBC_HAS_LFS__ */
--- libc/sysdeps/linux/common/bits/dirent.h.orig 2006-05-23 12:38:55.000000000 -0700
+++ libc/sysdeps/linux/common/bits/dirent.h 2006-05-23 12:39:14.000000000 -0700
@@ -34,7 +34,7 @@
char d_name[256]; /* We must not include limits.h! */
};
-#ifdef __USE_LARGEFILE64
+//#ifdef __USE_LARGEFILE64
struct dirent64
{
__ino64_t d_ino;
@@ -43,7 +43,7 @@
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
-#endif
+//#endif
#define d_fileno d_ino /* Backwards compatibility. */
More information about the uClibc
mailing list