blob: bb425648b4918b72650b47df2039146b04bbc99a [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
3 *
4 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
5 */
6
7#include <dirent.h>
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <errno.h>
12#include <sys/types.h>
13#include "dirstream.h"
14
15int scandir(const char *dir, struct dirent ***namelist,
16 int (*selector) (const struct dirent *),
17 int (*compar) (const struct dirent **, const struct dirent **))
18{
19 DIR *dp = opendir (dir);
20 struct dirent *current;
21 struct dirent **names = NULL;
22 size_t names_size = 0, pos;
23 int save;
24
25 if (dp == NULL)
26 return -1;
27
28 save = errno;
29 __set_errno (0);
30
31 pos = 0;
32 while ((current = readdir (dp)) != NULL) {
33 int use_it = selector == NULL;
34
35 if (! use_it)
36 {
37 use_it = (*selector) (current);
38 /* The selector function might have changed errno.
39 * It was zero before and it need to be again to make
40 * the latter tests work. */
41 if (! use_it)
42 __set_errno (0);
43 }
44 if (use_it)
45 {
46 struct dirent *vnew;
47 size_t dsize;
48
49 /* Ignore errors from selector or readdir */
50 __set_errno (0);
51
52 if (unlikely(pos == names_size))
53 {
54 struct dirent **new;
55 if (names_size == 0)
56 names_size = 10;
57 else
58 names_size *= 2;
59 new = (struct dirent **) realloc (names,
60 names_size * sizeof (struct dirent *));
61 if (new == NULL)
62 break;
63 names = new;
64 }
65
66 dsize = &current->d_name[_D_ALLOC_NAMLEN(current)] - (char*)current;
67 vnew = (struct dirent *) malloc (dsize);
68 if (vnew == NULL)
69 break;
70
71 names[pos++] = (struct dirent *) memcpy (vnew, current, dsize);
72 }
73 }
74
75 if (unlikely(errno != 0))
76 {
77 save = errno;
78 closedir (dp);
79 while (pos > 0)
80 free (names[--pos]);
81 free (names);
82 __set_errno (save);
83 return -1;
84 }
85
86 closedir (dp);
87 __set_errno (save);
88
89 /* Sort the list if we have a comparison function to sort with. */
90 if (compar != NULL)
91 qsort (names, pos, sizeof (struct dirent *), (comparison_fn_t) compar);
92 *namelist = names;
93 return pos;
94}