Open /etc/resolv.conf with FD_CLOEXEC
[glibc.git] / dirent / scandirat.c
blob3eda9702e8e0a9a222916c6bb21affe294ffe7da
1 /* Copyright (C) 1992-1998,2000,2002,2003,2009,2011
2 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <dirent.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <bits/libc-lock.h>
26 #ifndef SCANDIRAT
27 # define SCANDIRAT scandirat
28 # define READDIR __readdir
29 # define DIRENT_TYPE struct dirent
30 #endif
32 #ifndef SKIP_SCANDIR_CANCEL
33 void
34 __scandir_cancel_handler (void *arg)
36 struct scandir_cancel_struct *cp = arg;
37 size_t i;
38 void **v = cp->v;
40 for (i = 0; i < cp->cnt; ++i)
41 free (v[i]);
42 free (v);
43 (void) __closedir (cp->dp);
45 #endif
48 int
49 SCANDIRAT (dfd, dir, namelist, select, cmp)
50 int dfd;
51 const char *dir;
52 DIRENT_TYPE ***namelist;
53 int (*select) (const DIRENT_TYPE *);
54 int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **);
56 DIR *dp = __opendirat (dfd, dir);
57 DIRENT_TYPE **v = NULL;
58 size_t vsize = 0;
59 struct scandir_cancel_struct c;
60 DIRENT_TYPE *d;
61 int save;
63 if (dp == NULL)
64 return -1;
66 save = errno;
67 __set_errno (0);
69 c.dp = dp;
70 c.v = NULL;
71 c.cnt = 0;
72 __libc_cleanup_push (__scandir_cancel_handler, &c);
74 while ((d = READDIR (dp)) != NULL)
76 int use_it = select == NULL;
78 if (! use_it)
80 use_it = select (d);
81 /* The select function might have changed errno. It was
82 zero before and it need to be again to make the latter
83 tests work. */
84 __set_errno (0);
87 if (use_it)
89 DIRENT_TYPE *vnew;
90 size_t dsize;
92 /* Ignore errors from select or readdir */
93 __set_errno (0);
95 if (__builtin_expect (c.cnt == vsize, 0))
97 DIRENT_TYPE **new;
98 if (vsize == 0)
99 vsize = 10;
100 else
101 vsize *= 2;
102 new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v));
103 if (new == NULL)
104 break;
105 v = new;
106 c.v = (void *) v;
109 dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
110 vnew = (DIRENT_TYPE *) malloc (dsize);
111 if (vnew == NULL)
112 break;
114 v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize);
118 if (__builtin_expect (errno, 0) != 0)
120 save = errno;
122 while (c.cnt > 0)
123 free (v[--c.cnt]);
124 free (v);
125 c.cnt = -1;
127 else
129 /* Sort the list if we have a comparison function to sort with. */
130 if (cmp != NULL)
131 qsort (v, c.cnt, sizeof (*v),
132 (int (*) (const void *, const void *)) cmp);
134 *namelist = v;
137 __libc_cleanup_pop (0);
139 (void) __closedir (dp);
140 __set_errno (save);
142 return c.cnt;
144 libc_hidden_def (SCANDIRAT)