Update aarch64 bits/hwcap.h, dl-procinfo.c for Linux 4.16 HWCAP_ASIMDFHM.
[glibc.git] / dirent / scandir-tail.c
blob67c9c92d656905987a26e9337bfe8514266c972e
1 /* Logic guts of scandir*.
2 Copyright (C) 1992-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <dirent.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <libc-lock.h>
25 #ifndef SCANDIR_TAIL
26 # define SCANDIR_TAIL __scandir_tail
27 # define READDIR __readdir
28 # define DIRENT_TYPE struct dirent
29 #endif
31 int
32 SCANDIR_TAIL (DIR *dp,
33 DIRENT_TYPE ***namelist,
34 int (*select) (const DIRENT_TYPE *),
35 int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **))
37 if (dp == NULL)
38 return -1;
40 int save = errno;
41 __set_errno (0);
43 int result;
44 struct scandir_cancel_struct c = { .dp = dp };
45 __libc_cleanup_push (&__scandir_cancel_handler, &c);
47 DIRENT_TYPE **v = NULL;
48 size_t vsize = 0;
49 DIRENT_TYPE *d;
50 while ((d = READDIR (dp)) != NULL)
52 if (select != NULL)
54 int selected = (*select) (d);
56 /* The SELECT function might have set errno to non-zero on
57 success. It was zero before and it needs to be again to
58 make the later tests work. */
59 __set_errno (0);
61 if (!selected)
62 continue;
65 if (__glibc_unlikely (c.cnt == vsize))
67 if (vsize == 0)
68 vsize = 10;
69 else
70 vsize *= 2;
71 DIRENT_TYPE **new = realloc (v, vsize * sizeof *v);
72 if (new == NULL)
73 break;
74 c.v = v = new;
77 size_t dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
78 DIRENT_TYPE *vnew = malloc (dsize);
79 if (vnew == NULL)
80 break;
81 v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize);
83 /* Ignore errors from readdir, malloc or realloc. These functions
84 might have set errno to non-zero on success. It was zero before
85 and it needs to be again to make the latter tests work. */
86 __set_errno (0);
89 if (__glibc_likely (errno == 0))
91 __closedir (dp);
93 /* Sort the list if we have a comparison function to sort with. */
94 if (cmp != NULL)
95 qsort (v, c.cnt, sizeof *v, (__compar_fn_t) cmp);
97 *namelist = v;
98 result = c.cnt;
100 else
102 /* This frees everything and calls closedir. */
103 __scandir_cancel_handler (&c);
104 result = -1;
107 __libc_cleanup_pop (0);
109 if (result >= 0)
110 __set_errno (save);
111 return result;