1  /* Copyright (C) 2000-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #define scandir __no_scandir_decl
      19  #include <dirent.h>
      20  #undef scandir
      21  
      22  int
      23  __scandir64 (const char *dir, struct dirent64 ***namelist,
      24  	   int (*select) (const struct dirent64 *),
      25  	   int (*cmp) (const struct dirent64 **, const struct dirent64 **))
      26  {
      27    return __scandir64_tail (__opendir (dir), namelist, select, cmp);
      28  }
      29  
      30  #if _DIRENT_MATCHES_DIRENT64
      31  weak_alias (__scandir64, scandir64)
      32  weak_alias (__scandir64, scandir)
      33  #else
      34  # include <shlib-compat.h>
      35  versioned_symbol (libc, __scandir64, scandir64, GLIBC_2_2);
      36  # if SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)
      37  #  include <string.h>
      38  #  include <errno.h>
      39  #  include "olddirent.h"
      40  
      41  int
      42  __old_scandir64 (const char *dir, struct __old_dirent64 ***namelist,
      43  		 int (*select) (const struct __old_dirent64 *),
      44  		 int (*cmp) (const struct __old_dirent64 **,
      45  			     const struct __old_dirent64 **))
      46  {
      47    DIR *dp = __opendir (dir);
      48    struct __old_dirent64 **v = NULL;
      49    size_t vsize = 0;
      50    struct scandir_cancel_struct c;
      51    struct __old_dirent64 *d;
      52    int save;
      53  
      54    if (dp == NULL)
      55      return -1;
      56  
      57    save = errno;
      58    __set_errno (0);
      59  
      60    c.dp = dp;
      61    c.v = NULL;
      62    c.cnt = 0;
      63    __libc_cleanup_push (__scandir_cancel_handler, &c);
      64  
      65    while ((d = __old_readdir64 (dp)) != NULL)
      66      {
      67        int use_it = select == NULL;
      68  
      69        if (! use_it)
      70  	{
      71  	  use_it = select (d);
      72  	  /* The select function might have changed errno.  It was
      73  	     zero before and it need to be again to make the latter
      74  	     tests work.  */
      75  	  __set_errno (0);
      76  	}
      77  
      78        if (use_it)
      79  	{
      80  	  struct __old_dirent64 *vnew;
      81  	  size_t dsize;
      82  
      83  	  /* Ignore errors from select or readdir */
      84  	  __set_errno (0);
      85  
      86  	  if (__glibc_unlikely (c.cnt == vsize))
      87  	    {
      88  	      struct __old_dirent64 **new;
      89  	      if (vsize == 0)
      90  		vsize = 10;
      91  	      else
      92  		vsize *= 2;
      93  	      new = (struct __old_dirent64 **) realloc (v,
      94  							vsize * sizeof (*v));
      95  	      if (new == NULL)
      96  		break;
      97  	      v = new;
      98  	      c.v = (void *) v;
      99  	    }
     100  
     101  	  dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
     102  	  vnew = (struct __old_dirent64 *) malloc (dsize);
     103  	  if (vnew == NULL)
     104  	    break;
     105  
     106  	  v[c.cnt++] = (struct __old_dirent64 *) memcpy (vnew, d, dsize);
     107  	}
     108      }
     109  
     110    if (__builtin_expect (errno, 0) != 0)
     111      {
     112        save = errno;
     113  
     114        while (c.cnt > 0)
     115  	free (v[--c.cnt]);
     116        free (v);
     117        c.cnt = -1;
     118      }
     119    else
     120      {
     121        /* Sort the list if we have a comparison function to sort with.  */
     122        if (cmp != NULL)
     123  	qsort (v, c.cnt, sizeof (*v),
     124  	       (int (*) (const void *, const void *)) cmp);
     125  
     126        *namelist = v;
     127      }
     128  
     129    __libc_cleanup_pop (0);
     130  
     131    (void) __closedir (dp);
     132    __set_errno (save);
     133  
     134    return c.cnt;
     135  }
     136  compat_symbol (libc, __old_scandir64, scandir64, GLIBC_2_1);
     137  
     138  # endif /* SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)  */
     139  #endif /* _DIRENT_MATCHES_DIRENT64  */