Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / posix / scandir.c
blob7fd008910eff410150cf65639ef91decad93a83d
1 #ifndef HAVE_OPENDIR
3 /*-
4 * SPDX-License-Identifier: BSD-3-Clause
6 * Copyright (c) 1983, 1993
7 * The Regents of the University of California. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __SCCSID("@(#)scandir.c 8.3 (Berkeley) 1/2/94");
36 __FBSDID("$FreeBSD: head/lib/libc/gen/scandir.c 335898 2018-07-03 17:31:45Z jhb $");
39 * Scan the directory dirname calling select to make a list of selected
40 * directory entries then sort using qsort and compare routine dcomp.
41 * Returns the number of entries and a pointer to a list of pointers to
42 * struct dirent (through namelist). Returns -1 if there were any errors.
45 #include <stddef.h>
46 #include <dirent.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/lock.h>
52 * The DIRSIZ macro gives the minimum record length which will hold
53 * the directory entry. This requires the amount of space in struct dirent
54 * without the d_name field, plus enough space for the name with a terminating
55 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
57 #undef DIRSIZ
58 #ifdef _DIRENT_HAVE_D_NAMLEN
59 #define DIRSIZ(dp) \
60 (offsetof (struct dirent, d_name) + (((dp)->d_namlen+1 + 3) &~ 3))
61 #else
62 #define DIRSIZ(dp) \
63 (offsetof (struct dirent, d_name) + ((strlen((dp)->d_name)+1 + 3) &~ 3))
64 #endif
67 int
68 scandir(const char *dirname, struct dirent ***namelist,
69 int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
70 const struct dirent **))
72 register struct dirent *d, *p, **names = NULL;
73 register size_t arraysz, numitems;
74 DIR *dirp;
76 if ((dirp = opendir(dirname)) == NULL)
77 return(-1);
78 #ifdef HAVE_DD_LOCK
79 __lock_acquire_recursive(dirp->dd_lock);
80 #endif
82 numitems = 0;
83 arraysz = 32; /* initial estimate of the array size */
84 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
85 if (names == NULL)
86 goto fail;
88 while ((d = readdir(dirp)) != NULL) {
89 if (select != NULL && !(*select)(d))
90 continue; /* just selected names */
92 * Make a minimum size copy of the data
94 p = (struct dirent *)malloc(DIRSIZ(d));
95 if (p == NULL)
96 goto fail;
97 p->d_ino = d->d_ino;
98 #ifdef DT_UNKNOWN
99 p->d_type = d->d_type;
100 #endif
101 p->d_reclen = d->d_reclen;
102 #ifdef _DIRENT_HAVE_D_NAMLEN
103 p->d_namlen = d->d_namlen;
104 bcopy(d->d_name, p->d_name, p->d_namlen + 1);
105 #else
106 strcpy(p->d_name, d->d_name);
107 #endif
109 * Check to make sure the array has space left and
110 * realloc the maximum size.
112 if (numitems >= arraysz) {
113 struct dirent **names2;
115 names2 = reallocarray(names, arraysz,
116 2 * sizeof(struct dirent *));
117 if (names2 == NULL) {
118 free(p);
119 goto fail;
121 names = names2;
122 arraysz *= 2;
124 names[numitems++] = p;
126 closedir(dirp);
127 if (numitems && dcomp != NULL)
128 qsort(names, numitems, sizeof(struct dirent *), (void *)dcomp);
129 *namelist = names;
130 #ifdef HAVE_DD_LOCK
131 __lock_release_recursive(dirp->dd_lock);
132 #endif
133 return (numitems);
135 fail:
136 while (numitems > 0)
137 free(names[--numitems]);
138 free(names);
139 closedir(dirp);
140 #ifdef HAVE_DD_LOCK
141 __lock_release_recursive(dirp->dd_lock);
142 #endif
143 return (-1);
147 * Alphabetic order comparison routine for those who want it.
148 * POSIX 2008 requires that alphasort() uses strcoll().
151 alphasort(const struct dirent **d1, const struct dirent **d2)
154 return (strcoll((*d1)->d_name, (*d2)->d_name));
157 #endif /* ! HAVE_OPENDIR */