root/maint/gnulib/lib/scandir.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cancel_handler
  2. SCANDIR

   1 /* Copyright (C) 1992-1998, 2000, 2002-2003, 2009-2021 Free Software
   2    Foundation, Inc.
   3    This file is part of the GNU C Library.
   4 
   5    This file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 3 of the
   8    License, or (at your option) any later version.
   9 
  10    This file is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 #include <config.h>
  19 
  20 #include <dirent.h>
  21 
  22 #include <stdlib.h>
  23 #include <string.h>
  24 #include <errno.h>
  25 #if _LIBC
  26 # include <bits/libc-lock.h>
  27 #endif
  28 
  29 #undef select
  30 
  31 #ifndef _D_EXACT_NAMLEN
  32 # define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
  33 #endif
  34 #ifndef _D_ALLOC_NAMLEN
  35 # ifndef __KLIBC__
  36 #  define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
  37 # else
  38 /* On OS/2 kLIBC, d_name is not the last field of struct dirent. See
  39    <https://trac.netlabs.org/libc/browser/branches/libc-0.6/src/emx/include/sys/dirent.h#L68>.  */
  40 #  include <stddef.h>
  41 #  define _D_ALLOC_NAMLEN(d) (sizeof (struct dirent) - \
  42                               offsetof (struct dirent, d_name))
  43 # endif
  44 #endif
  45 
  46 #if _LIBC
  47 # ifndef SCANDIR
  48 #  define SCANDIR scandir
  49 #  define READDIR __readdir
  50 #  define DIRENT_TYPE struct dirent
  51 # endif
  52 #else
  53 # define SCANDIR scandir
  54 # define READDIR readdir
  55 # define DIRENT_TYPE struct dirent
  56 # define __opendir opendir
  57 # define __closedir closedir
  58 # define __set_errno(val) errno = (val)
  59 
  60 /* The results of opendir() in this file are not used with dirfd and fchdir,
  61    and we do not leak fds to any single-threaded code that could use stdio,
  62    therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
  63    FIXME - if the kernel ever adds support for multi-thread safety for
  64    avoiding standard fds, then we should use opendir_safer.  */
  65 # undef opendir
  66 # undef closedir
  67 #endif
  68 
  69 #ifndef SCANDIR_CANCEL
  70 # define SCANDIR_CANCEL
  71 struct scandir_cancel_struct
  72 {
  73   DIR *dp;
  74   void *v;
  75   size_t cnt;
  76 };
  77 
  78 # if _LIBC
  79 static void
  80 cancel_handler (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82   struct scandir_cancel_struct *cp = arg;
  83   size_t i;
  84   void **v = cp->v;
  85 
  86   for (i = 0; i < cp->cnt; ++i)
  87     free (v[i]);
  88   free (v);
  89   (void) __closedir (cp->dp);
  90 }
  91 # endif
  92 #endif
  93 
  94 
  95 int
  96 #ifndef __KLIBC__
  97 SCANDIR (const char *dir,
     /* [previous][next][first][last][top][bottom][index][help] */
  98          DIRENT_TYPE ***namelist,
  99          int (*select) (const DIRENT_TYPE *),
 100          int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **))
 101 #else
 102 /* On OS/2 kLIBC, scandir() declaration is different from POSIX. See
 103    <https://trac.netlabs.org/libc/browser/branches/libc-0.6/src/emx/include/dirent.h#L141>.  */
 104 SCANDIR (const char *dir,
 105          DIRENT_TYPE ***namelist,
 106          int (*select) (DIRENT_TYPE *),
 107          int (*cmp) (const void *, const void *))
 108 #endif
 109 {
 110   DIR *dp = __opendir (dir);
 111   DIRENT_TYPE **v = NULL;
 112   size_t vsize = 0;
 113   struct scandir_cancel_struct c;
 114   DIRENT_TYPE *d;
 115   int save;
 116 
 117   if (dp == NULL)
 118     return -1;
 119 
 120   save = errno;
 121   __set_errno (0);
 122 
 123   c.dp = dp;
 124   c.v = NULL;
 125   c.cnt = 0;
 126 #if _LIBC
 127   __libc_cleanup_push (cancel_handler, &c);
 128 #endif
 129 
 130   while ((d = READDIR (dp)) != NULL)
 131     {
 132       int use_it = select == NULL;
 133 
 134       if (! use_it)
 135         {
 136           use_it = select (d);
 137           /* The select function might have changed errno.  It was
 138              zero before and it need to be again to make the latter
 139              tests work.  */
 140           __set_errno (0);
 141         }
 142 
 143       if (use_it)
 144         {
 145           DIRENT_TYPE *vnew;
 146           size_t dsize;
 147 
 148           /* Ignore errors from select or readdir */
 149           __set_errno (0);
 150 
 151           if (__builtin_expect (c.cnt == vsize, 0))
 152             {
 153               DIRENT_TYPE **new;
 154               if (vsize == 0)
 155                 vsize = 10;
 156               else
 157                 vsize *= 2;
 158               new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v));
 159               if (new == NULL)
 160                 break;
 161               v = new;
 162               c.v = (void *) v;
 163             }
 164 
 165           dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
 166           vnew = (DIRENT_TYPE *) malloc (dsize);
 167           if (vnew == NULL)
 168             break;
 169 
 170           v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize);
 171         }
 172     }
 173 
 174   if (__builtin_expect (errno, 0) != 0)
 175     {
 176       save = errno;
 177 
 178       while (c.cnt > 0)
 179         free (v[--c.cnt]);
 180       free (v);
 181       c.cnt = -1;
 182     }
 183   else
 184     {
 185       /* Sort the list if we have a comparison function to sort with.  */
 186       if (cmp != NULL)
 187         qsort (v, c.cnt, sizeof (*v), (int (*) (const void *, const void *)) cmp);
 188 
 189       *namelist = v;
 190     }
 191 
 192 #if _LIBC
 193   __libc_cleanup_pop (0);
 194 #endif
 195 
 196   (void) __closedir (dp);
 197   __set_errno (save);
 198 
 199   return c.cnt;
 200 }

/* [previous][next][first][last][top][bottom][index][help] */