浏览代码

Fix a segfault in scandir for empty directories. After looking over
our version, I'm adopting the scandir from glibc (with minor changes)
instead as it seems simpler and already correct.

Eric Andersen 23 年之前
父节点
当前提交
0eccd99fb0
共有 2 个文件被更改,包括 82 次插入67 次删除
  1. 5 2
      include/features.h
  2. 77 65
      libc/misc/dirent/scandir.c

+ 5 - 2
include/features.h

@@ -411,9 +411,12 @@ uClibc was built without large file support enabled.
 #endif
 #endif
 
 
 /* Prepare for the case that `__builtin_expect' is not available.  */
 /* Prepare for the case that `__builtin_expect' is not available.  */
-#ifndef HAVE_BUILTIN_EXPECT
+#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
-# define __builtin_expect(expr, val) (expr)
+#define __builtin_expect(x, expected_value) (x)
 #endif
 #endif
 
 
+#define likely(x)       __builtin_expect((x),1)
+#define unlikely(x)     __builtin_expect((x),0)
+
 
 
 #endif	/* features.h  */
 #endif	/* features.h  */

+ 77 - 65
libc/misc/dirent/scandir.c

@@ -1,85 +1,97 @@
-/* -*- Mode: C; c-file-style: "gnu" -*- */
+/* Copyright (C) 1992-1998, 2000 Free Software Foundation, Inc.
-/*
+   This file is part of the GNU C Library.
-   Copyright (c) 2000 Petter Reinholdtsen
+
-
+   The GNU C Library is free software; you can redistribute it and/or
-   Permission is hereby granted, free of charge, to any person
+   modify it under the terms of the GNU Lesser General Public
-   obtaining a copy of this software and associated documentation
+   License as published by the Free Software Foundation; either
-   files (the "Software"), to deal in the Software without
+   version 2.1 of the License, or (at your option) any later version.
-   restriction, including without limitation the rights to use, copy,
+
-   modify, merge, publish, distribute, sublicense, and/or sell copies
+   The GNU C Library is distributed in the hope that it will be useful,
-   of the Software, and to permit persons to whom the Software is
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   furnished to do so, subject to the following conditions:
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-
+   Lesser General Public License for more details.
-   The above copyright notice and this permission notice shall be
+
-   included in all copies or substantial portions of the Software.
+   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
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   02111-1307 USA.  
-   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   */
-   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+
-   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+/* Modified for uClibc by Erik Andersen
-   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   */
-   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-   SOFTWARE.
-*/
 
 
 #include <dirent.h>
 #include <dirent.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/types.h>
 #include "dirstream.h"
 #include "dirstream.h"
 
 
-int scandir(const char *dir, struct dirent ***namelist,
+int scandir(const char *dir, struct dirent ***namelist, 
-			 int (*selector) (const struct dirent *),
+	int (*selector) (const struct dirent *),
-			 int (*compar) (const __ptr_t, const __ptr_t))
+	int (*compar) (const void *, const void *))
 {
 {
-    DIR *d = opendir(dir);
+    DIR *dp = opendir (dir);
     struct dirent *current;
     struct dirent *current;
-    struct dirent **names;
+    struct dirent **names = NULL;
-    int count = 0;
+    size_t names_size = 0, pos;
-    int pos = 0;
+    int save;
-    int result = -1;
 
 
-    if (NULL == d)
+    if (dp == NULL)
-        return -1;
-
-    while (NULL != readdir(d))
-        count++;
-
-    if (!(names = malloc(sizeof (struct dirent *) * count))) {
-	closedir(d);
 	return -1;
 	return -1;
-    }
-
-    rewinddir(d);
 
 
-    while (NULL != (current = readdir(d))) {
+    save = errno;
-        if (NULL == selector || selector(current)) {
+    __set_errno (0);
-            struct dirent *copyentry = malloc(current->d_reclen);
+
-
+    pos = 0;
-            memcpy(copyentry, current, current->d_reclen);
+    while ((current = readdir (dp)) != NULL)
-
+	if (selector == NULL || (*selector) (current))
-            names[pos] = copyentry;
+	{
-            pos++;
+	    struct dirent *vnew;
-        }
+	    size_t dsize;
-    }
+
-    result = closedir(d);
+	    /* Ignore errors from selector or readdir */
-
+	    __set_errno (0);
-    if (pos != count) {
+
-	struct dirent **tmp;
+	    if (unlikely(pos == names_size))
-	if (!(tmp = realloc(names, sizeof (struct dirent *) * pos))) {
+	    {
-	    free(names);
+		struct dirent **new;
-	    return -1;
+		if (names_size == 0)
+		    names_size = 10;
+		else
+		    names_size *= 2;
+		new = (struct dirent **) realloc (names, names_size * sizeof (struct dirent *));
+		if (new == NULL)
+		    break;
+		names = new;
+	    }
+
+	    dsize = &current->d_name[_D_ALLOC_NAMLEN (current)] - (char *) current;
+	    vnew = (struct dirent *) malloc (dsize);
+	    if (vnew == NULL)
+		break;
+
+	    names[pos++] = (struct dirent *) memcpy (vnew, current, dsize);
 	}
 	}
-	names = tmp;
-    }
 
 
-    if (compar != NULL) {
+    if (unlikely(errno != 0))
-	qsort(names, pos, sizeof (struct dirent *), compar);
+    {
+	save = errno;
+	closedir (dp);
+	while (pos > 0)
+	    free (names[--pos]);
+	free (names);
+	__set_errno (save);
+	return -1;
     }
     }
 
 
-    *namelist = names;
+    closedir (dp);
+    __set_errno (save);
 
 
+    /* Sort the list if we have a comparison function to sort with.  */
+    if (compar != NULL)
+	qsort (names, pos, sizeof (struct dirent *), compar);
+    *namelist = names;
     return pos;
     return pos;
 }
 }