[uClibc-cvs] uClibc/libc/sysdeps/linux/common getdents.c,1.4,1.5 getdents64.c,NONE,1.1 Makefile,1.73,1.74 syscalls.c,1.96,1.97

Erik Andersen andersen at codepoet.org
Tue Jan 28 11:06:06 UTC 2003


Update of /var/cvs/uClibc/libc/sysdeps/linux/common
In directory winder:/tmp/cvs-serv17535/libc/sysdeps/linux/common

Modified Files:
	Makefile syscalls.c 
Added Files:
	getdents.c getdents64.c 
Log Message:
Fix scandir64 to not free the wrong pieces of memory (which could
and did cause segfaults) by adjusting the working scandir.c to
the the 64 thing.  Fix up potential for mismatches between the
libc and kernel dirent structures, which could also cause ugly
problems.
 -Erik



--- NEW FILE: getdents64.c ---
/* 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.  */

#include <features.h>

#ifdef __UCLIBC_HAS_LFS__

#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <dirent.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sysdep.h>
#include <sys/syscall.h>


#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

struct kernel_dirent64
{
    uint64_t            d_ino;
    int64_t             d_off;
    unsigned short int  d_reclen;
    unsigned char       d_type;
    char                d_name[256];
};


#define __NR___syscall_getdents64 __NR_getdents64
static inline _syscall3(int, __syscall_getdents64, int, fd, unsigned char *, dirp, size_t, count);


ssize_t __getdents64 (int fd, char *buf, size_t nbytes)
{
    struct dirent64 *dp;
    off64_t last_offset = -1;
    ssize_t retval;
    size_t red_nbytes;
    struct kernel_dirent64 *skdp, *kdp;
    const size_t size_diff = (offsetof (struct dirent64, d_name)
	    - offsetof (struct kernel_dirent64, d_name));

    red_nbytes = MIN (nbytes - ((nbytes / 
		    (offsetof (struct dirent64, d_name) + 14)) * size_diff), 
	    nbytes - size_diff);

    dp = (struct dirent64 *) buf;
    skdp = kdp = alloca (red_nbytes);

    retval = __syscall_getdents64(fd, (char *)kdp, red_nbytes);
    if (retval == -1)
	return -1;

    while ((char *) kdp < (char *) skdp + retval) {
	const size_t alignment = __alignof__ (struct dirent64);
	/* 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);
	    lseek64(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_dirent64, d_name));
	dp = (struct dirent64 *) ((char *) dp + new_reclen);
	kdp = (struct kernel_dirent64 *) (((char *) kdp) + kdp->d_reclen);
    }
    return (char *) dp - buf;
}
#endif /* __UCLIBC_HAS_LFS__ */


Index: Makefile
===================================================================
RCS file: /var/cvs/uClibc/libc/sysdeps/linux/common/Makefile,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- Makefile	24 Jan 2003 11:52:51 -0000	1.73
+++ Makefile	28 Jan 2003 11:06:01 -0000	1.74
@@ -25,7 +25,7 @@
 	cmsg_nxthdr.c longjmp.c open64.c ftruncate64.c \
 	truncate64.c getrlimit64.c setrlimit64.c creat64.c mmap64.c \
 	llseek.c pread_write.c _exit.c setuid.c sync.c getdirname.c \
-	sendfile64.c xstatconv.c
+	sendfile64.c xstatconv.c getdents.c getdents64.c
 ifneq ($(strip $(EXCLUDE_BRK)),y)
 CSRC+=sbrk.c
 endif

Index: syscalls.c
===================================================================
RCS file: /var/cvs/uClibc/libc/sysdeps/linux/common/syscalls.c,v
retrieving revision 1.96
retrieving revision 1.97
diff -u -d -r1.96 -r1.97
--- syscalls.c	24 Jan 2003 11:52:51 -0000	1.96
+++ syscalls.c	28 Jan 2003 11:06:02 -0000	1.97
@@ -1226,11 +1226,7 @@
 //See llseek.c
 
 //#define __NR_getdents         141
-#ifdef L_getdents
-#include <unistd.h>
-#include <dirent.h>
-_syscall3(int, getdents, int, fd, char *, dirp, size_t, count);
-#endif
+// See getdents.c
 
 //#define __NR__newselect       142
 #ifdef L__newselect
@@ -1766,13 +1762,7 @@
 //#define __NR_madvise1		219	/* delete when C lib stub is removed */
 
 //#define __NR_getdents64		220
-#ifdef L_getdents64
-#ifdef __UCLIBC_HAS_LFS__
-#include <unistd.h>
-#include <dirent.h>
-_syscall3(int, getdents64, int, fd, char *, dirp, size_t, count);
-#endif /* __UCLIBC_HAS_LFS__ */
-#endif
+// See getdents64.c
 
 //#define __NR_fcntl64		221
 #ifdef L__fcntl64




More information about the uClibc-cvs mailing list