From patchwork Tue May 12 22:53:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roland McGrath X-Patchwork-Id: 471607 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 1FE0414078C for ; Wed, 13 May 2015 08:54:09 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=sourceware.org header.i=@sourceware.org header.b=NFfMeE/t; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:mime-version:content-type :content-transfer-encoding:from:to:subject:in-reply-to :references:message-id:date; q=dns; s=default; b=mDU7b/IIIsPDyDy Im9/YePOjzUmJOgZQ0vXrvSlOa8g4I+/YQrnebbOQDwqnp8CtIVOaG+bLuMOMS9t 7hYoSbUUCUqkf7ZqOoWJk7kyzj2uVSVfCP1cljNOQai3A7GJuQ1E4w2RO2qNifKL 8sVjMnfxubbJBeExkWVNfAJez5Vk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:mime-version:content-type :content-transfer-encoding:from:to:subject:in-reply-to :references:message-id:date; s=default; bh=erJ+CqbPR7emW8x18X+j3 l1fA8w=; b=NFfMeE/tySPq13fCiTWlXYG2s/m6RPgZ5Ps+c00aMEUsdGnWPwH4b x4EXPfCgMmScLpTfSCUqNQmc2SKd8ZxUjpp7dQ5RYe8lXt0YkHF35qZXvfKU43MM b5/bpmaNYct5u+MzZF6KYh1YCMWZKKHQqmAuUUd0fPHCQekwaAQ79o= Received: (qmail 43790 invoked by alias); 12 May 2015 22:54:03 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 43777 invoked by uid 89); 12 May 2015 22:54:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.7 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY autolearn=no version=3.3.2 X-HELO: topped-with-meat.com MIME-Version: 1.0 From: Roland McGrath To: "GNU C. Library" Subject: [PATCH 3/3 roland/scandir] Refactor scandir/scandirat to use common tail. In-Reply-To: Roland McGrath's message of Tuesday, 12 May 2015 15:50:45 -0700 <20150512225045.45B202C3AB9@topped-with-meat.com> References: <20150512225045.45B202C3AB9@topped-with-meat.com> Message-Id: <20150512225358.F32922C3AB9@topped-with-meat.com> Date: Tue, 12 May 2015 15:53:58 -0700 (PDT) X-CMAE-Score: 0 X-CMAE-Analysis: v=2.1 cv=SvUDtp+0 c=1 sm=1 tr=0 a=WkljmVdYkabdwxfqvArNOQ==:117 a=14OXPxybAAAA:8 a=kj9zAlcOel0A:10 a=hOe2yjtxAAAA:8 a=mDV3o1hIAAAA:8 a=GKrRBGeyzCcHmnFyw2UA:9 a=CjuIK1q_8ugA:10 This refactors things so that scandir uses only opendir and only scandirat uses opendirat, so a configuration with a working opendir but no working opendirat gets a working scandir and just no working scandirat. If there are no objections, I'll commit this shortly. Tested x86_64-linux-gnu and i686-linux-gnu. Thanks, Roland 2015-05-12 Roland McGrath * dirent/scandir64-tail.c: New file. * dirent/Makefile (routines): Add them. * include/dirent.h (__scandir_tail, __scandir64_tail): Declare them. * dirent/scandir.c [!SCANDIR] (SCANDIRAT): Macro removed. [!SCANDIR] (SCANDIR_TAIL): New macro. (SCANDIR): Call __opendir and __scandir_tail, not __scandirat. * dirent/scandir64.c [!_DIRENT_MATCHES_DIRENT64] (SCANDIRAT): Macro removed. (SCANDIR_TAIL): New macro. * dirent/scandirat.c [!SCANDIRAT] (READDIR): Macro removed. [!SCANDIRAT] (SCANDIR_TAIL): New macro. (SCANDIRAT): Just call __opendirat and __scandir_tail. * dirent/scandirat64.c [!_DIRENT_MATCHES_DIRENT64] (READDIR): Macro removed. (SCANDIR_TAIL): New macro. * sysdeps/unix/sysv/linux/i386/scandir64.c (READDIR): Macro removed. (SCANDIR_TAIL): New macro. diff --git a/dirent/Makefile b/dirent/Makefile index 2a97649..551372e 100644 --- a/dirent/Makefile +++ b/dirent/Makefile @@ -27,7 +27,8 @@ routines := opendir closedir readdir readdir_r rewinddir \ seekdir telldir scandir alphasort versionsort \ getdents getdents64 dirfd readdir64 readdir64_r scandir64 \ alphasort64 versionsort64 fdopendir \ - scandirat scandirat64 scandir-cancel + scandirat scandirat64 \ + scandir-cancel scandir-tail scandir64-tail tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \ tst-fdopendir2 tst-scandir tst-scandir64 diff --git a/dirent/scandir-tail.c b/dirent/scandir-tail.c new file mode 100644 index 0000000..4560834 --- /dev/null +++ b/dirent/scandir-tail.c @@ -0,0 +1,110 @@ +/* Logic guts of scandir*. + Copyright (C) 1992-2015 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, see + . */ + +#include +#include +#include +#include +#include + +#ifndef SCANDIR_TAIL +# define SCANDIR_TAIL __scandir_tail +# define READDIR __readdir +# define DIRENT_TYPE struct dirent +#endif + +internal_function +int +SCANDIR_TAIL (DIR *dp, + DIRENT_TYPE ***namelist, + int (*select) (const DIRENT_TYPE *), + int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **)) +{ + if (dp == NULL) + return -1; + + int save = errno; + __set_errno (0); + + int result; + struct scandir_cancel_struct c = { .dp = dp }; + __libc_cleanup_push (&__scandir_cancel_handler, &c); + + DIRENT_TYPE **v = NULL; + size_t vsize = 0; + DIRENT_TYPE *d; + while ((d = READDIR (dp)) != NULL) + { + if (select != NULL) + { + int selected = (*select) (d); + + /* The SELECT function might have changed errno. It was + zero before and it need to be again to make the later + tests work. */ + __set_errno (0); + + if (!selected) + continue; + } + else + __set_errno (0); + + if (__glibc_unlikely (c.cnt == vsize)) + { + if (vsize == 0) + vsize = 10; + else + vsize *= 2; + DIRENT_TYPE **new = realloc (v, vsize * sizeof *v); + if (new == NULL) + break; + c.v = v = new; + } + + size_t dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d; + DIRENT_TYPE *vnew = malloc (dsize); + if (vnew == NULL) + break; + v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize); + } + + if (__glibc_likely (errno == 0)) + { + __closedir (dp); + + /* Sort the list if we have a comparison function to sort with. */ + if (cmp != NULL) + qsort (v, c.cnt, sizeof *v, (__compar_fn_t) cmp); + + *namelist = v; + result = c.cnt; + } + else + { + /* This frees everything and calls closedir. */ + __scandir_cancel_handler (&c); + result = -1; + } + + __libc_cleanup_pop (0); + + if (result >= 0) + __set_errno (save); + return result; +} diff --git a/dirent/scandir.c b/dirent/scandir.c index 99c9681..c0c3f7a 100644 --- a/dirent/scandir.c +++ b/dirent/scandir.c @@ -24,23 +24,20 @@ #undef scandir64 -#include - #ifndef SCANDIR -# define SCANDIR scandir -# define SCANDIRAT __scandirat -# define DIRENT_TYPE struct dirent +# define SCANDIR scandir +# define SCANDIR_TAIL __scandir_tail +# define DIRENT_TYPE struct dirent #endif int -SCANDIR (dir, namelist, select, cmp) - const char *dir; - DIRENT_TYPE ***namelist; - int (*select) (const DIRENT_TYPE *); - int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **); +SCANDIR (const char *dir, + DIRENT_TYPE ***namelist, + int (*select) (const DIRENT_TYPE *), + int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **)) { - return SCANDIRAT (AT_FDCWD, dir, namelist, select, cmp); + return SCANDIR_TAIL (__opendir (dir), namelist, select, cmp); } #ifdef _DIRENT_MATCHES_DIRENT64 diff --git a/dirent/scandir64-tail.c b/dirent/scandir64-tail.c new file mode 100644 index 0000000..b10dd0a --- /dev/null +++ b/dirent/scandir64-tail.c @@ -0,0 +1,26 @@ +/* Logic guts of scandir*64. + Copyright (C) 2015 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, see + . */ + +#include + +#ifndef _DIRENT_MATCHES_DIRENT64 +# define SCANDIR_TAIL __scandir64_tail +# define READDIR __readdir64 +# define DIRENT_TYPE struct dirent64 +# include +#endif diff --git a/dirent/scandir64.c b/dirent/scandir64.c index d9f780f..fbb1866 100644 --- a/dirent/scandir64.c +++ b/dirent/scandir64.c @@ -20,10 +20,10 @@ /* scandir.c defines scandir64 as an alias if _DIRENT_MATCHES_DIRENT64. */ #ifndef _DIRENT_MATCHES_DIRENT64 -#define SCANDIR scandir64 -#define SCANDIRAT scandirat64 -#define DIRENT_TYPE struct dirent64 +# define SCANDIR scandir64 +# define SCANDIR_TAIL __scandir64_tail +# define DIRENT_TYPE struct dirent64 -#include +# include #endif diff --git a/dirent/scandirat.c b/dirent/scandirat.c index d7ae5e5..41725af 100644 --- a/dirent/scandirat.c +++ b/dirent/scandirat.c @@ -24,114 +24,20 @@ #undef scandirat64 -#include -#include -#include -#include - #ifndef SCANDIRAT -# define SCANDIRAT __scandirat -# define READDIR __readdir -# define DIRENT_TYPE struct dirent +# define SCANDIRAT __scandirat +# define SCANDIR_TAIL __scandir_tail +# define DIRENT_TYPE struct dirent # define SCANDIRAT_WEAK_ALIAS #endif - int -SCANDIRAT (dfd, dir, namelist, select, cmp) - int dfd; - const char *dir; - DIRENT_TYPE ***namelist; - int (*select) (const DIRENT_TYPE *); - int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **); +SCANDIRAT (int dfd, const char *dir, + DIRENT_TYPE ***namelist, + int (*select) (const DIRENT_TYPE *), + int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **)) { - DIR *dp = __opendirat (dfd, dir); - DIRENT_TYPE **v = NULL; - size_t vsize = 0; - struct scandir_cancel_struct c; - DIRENT_TYPE *d; - int save; - - if (dp == NULL) - return -1; - - save = errno; - __set_errno (0); - - c.dp = dp; - c.v = NULL; - c.cnt = 0; - __libc_cleanup_push (__scandir_cancel_handler, &c); - - while ((d = READDIR (dp)) != NULL) - { - int use_it = select == NULL; - - if (! use_it) - { - use_it = select (d); - /* The select function might have changed errno. It was - zero before and it need to be again to make the latter - tests work. */ - __set_errno (0); - } - - if (use_it) - { - DIRENT_TYPE *vnew; - size_t dsize; - - /* Ignore errors from select or readdir */ - __set_errno (0); - - if (__glibc_unlikely (c.cnt == vsize)) - { - DIRENT_TYPE **new; - if (vsize == 0) - vsize = 10; - else - vsize *= 2; - new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v)); - if (new == NULL) - break; - v = new; - c.v = (void *) v; - } - - dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d; - vnew = (DIRENT_TYPE *) malloc (dsize); - if (vnew == NULL) - break; - - v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize); - } - } - - if (__builtin_expect (errno, 0) != 0) - { - save = errno; - - while (c.cnt > 0) - free (v[--c.cnt]); - free (v); - c.cnt = -1; - } - else - { - /* Sort the list if we have a comparison function to sort with. */ - if (cmp != NULL) - qsort (v, c.cnt, sizeof (*v), - (int (*) (const void *, const void *)) cmp); - - *namelist = v; - } - - __libc_cleanup_pop (0); - - (void) __closedir (dp); - __set_errno (save); - - return c.cnt; + return SCANDIR_TAIL (__opendirat (dfd, dir), namelist, select, cmp); } libc_hidden_def (SCANDIRAT) #ifdef SCANDIRAT_WEAK_ALIAS diff --git a/dirent/scandirat64.c b/dirent/scandirat64.c index fcdd1a9..e330a7b 100644 --- a/dirent/scandirat64.c +++ b/dirent/scandirat64.c @@ -20,10 +20,10 @@ /* scandirat.c defines scandirat64 as an alias if _DIRENT_MATCHES_DIRENT64. */ #ifndef _DIRENT_MATCHES_DIRENT64 -#define SCANDIRAT scandirat64 -#define READDIR __readdir64 -#define DIRENT_TYPE struct dirent64 +# define SCANDIRAT scandirat64 +# define SCANDIR_TAIL __scandir64_tail +# define DIRENT_TYPE struct dirent64 -#include "scandirat.c" +# include #endif diff --git a/include/dirent.h b/include/dirent.h index c50bd23..258f2d0 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -49,6 +49,26 @@ extern DIR *__alloc_dir (int fd, bool close_fd, int flags, extern __typeof (rewinddir) __rewinddir; extern void __scandir_cancel_handler (void *arg) attribute_hidden; +extern int __scandir_tail (DIR *dp, + struct dirent ***namelist, + int (*select) (const struct dirent *), + int (*cmp) (const struct dirent **, + const struct dirent **)) + internal_function attribute_hidden; +# ifdef _DIRENT_MATCHES_DIRENT64 +# define __scandir64_tail (dp, namelist, select, cmp) \ + __scandir_tail (dp, (struct dirent ***) (namelist), \ + (int (*) (const struct dirent *)) (select), \ + (int (*) (const struct dirent **, \ + const struct dirent **)) (cmp)) +# else +extern int __scandir64_tail (DIR *dp, + struct dirent64 ***namelist, + int (*select) (const struct dirent64 *), + int (*cmp) (const struct dirent64 **, + const struct dirent64 **)) + internal_function attribute_hidden; +# endif libc_hidden_proto (__rewinddir) extern __typeof (scandirat) __scandirat; diff --git a/sysdeps/unix/sysv/linux/i386/scandir64.c b/sysdeps/unix/sysv/linux/i386/scandir64.c index 824bf84..8629078 100644 --- a/sysdeps/unix/sysv/linux/i386/scandir64.c +++ b/sysdeps/unix/sysv/linux/i386/scandir64.c @@ -17,22 +17,21 @@ #include -#define SCANDIR __scandir64 -#define SCANDIRAT scandirat64 -#define READDIR __readdir64 -#define DIRENT_TYPE struct dirent64 +#define SCANDIR __scandir64 +#define SCANDIR_TAIL __scandir64_tail +#define DIRENT_TYPE struct dirent64 #include -#undef SCANDIR -#undef READDIR -#undef DIRENT_TYPE +#undef SCANDIR +#undef SCANDIR_TAIL +#undef DIRENT_TYPE #include versioned_symbol (libc, __scandir64, scandir64, GLIBC_2_2); -#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) +#if SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) # include # include # include "olddirent.h"