1 #include "general.h"
2 /*
3  * Taken from https://github.com/ClusterLabs/pacemaker/blob/master/replace/scandir.c
4  */
5 
6 /* scandir: Scan a directory, collecting all (selected) items into a an array.
7  *
8  * This code borrowed from 'libit', which can be found here:
9  *
10  * http://www.iro.umontreal.ca/~pinard/libit/dist/scandir/
11  *
12  * The original author put this code in the public domain.
13  * It has been modified slightly to get rid of warnings, etc.
14  *
15  * Below is the email I received from pinard@iro.umontreal.ca (François Pinard)
16  * when I sent him an email asking him about the license, etc. of this
17  * code which I obtained from his site.
18  *
19  * I think the correct spelling of his name is Rich Salz.  I think he's now
20  * rsalz@datapower.com...
21  * --
22  * Rich Salz, Chief Security Architect
23  * DataPower Technology                           http://www.datapower.com
24  * XS40 XML Security Gateway   http://www.datapower.com/products/xs40.html
25  *
26  *	Copyright(C):	none (public domain)
27  *	License:	none (public domain)
28  *	Author:		Rich Salz <rsalz@datapower.com>
29  *
30  *
31  *
32  *	-- Alan Robertson
33  *	   alanr@unix.sh
34  *
35  **************************************************************************
36  *
37  * Subject:	Re: Scandir replacement function
38  * Date:	18 May 2001 12:00:48 -0400
39  * From:	pinard@iro.umontreal.ca (François Pinard)
40  * To:		Alan Robertson <alanr@unix.sh>
41  * References:	1
42  *
43  *
44  * [Alan Robertson]
45  *
46  * > Hi, I'd like to use your scandir replacement function found here:
47  * > http://www.iro.umontreal.ca/~pinard/libit/dist/scandir/ But, it does
48  * > not indicate authorship or licensing terms in it.  Could you tell me
49  * > who wrote this code, under what license you distribute it, and whether
50  * > and under what terms I may further distribute it?
51  *
52  * Hello, Alan.  These are (somewhat) explained in UNSHAR.HDR found in the
53  * same directory.  The routines have been written by Rick Saltz (I'm not
54  * completely sure of the spelling) a long while ago.  I think that nowadays,
55  * Rick is better known as the main author of the nice INN package.
56  *
57  **************************************************************************
58  *
59  * I spent a little time verifying this with Rick Salz.
60  * The results are below:
61  *
62  **************************************************************************
63  *
64  * Date: Tue, 20 Sep 2005 21:52:09 -0400 (EDT)
65  * From: Rich Salz <rsalz@datapower.com>
66  * To: Alan Robertson <alanr@unix.sh>
67  * Subject: Re: Verifying permissions/licenses/etc on some old code of yours -
68  *  scandir.c
69  * In-Reply-To: <433071CA.8000107@unix.sh>
70  * Message-ID: <Pine.LNX.4.44L0.0509202151270.9198-100000@smtp.datapower.com>
71  * Content-Type: TEXT/PLAIN; charset=US-ASCII
72  *
73  * yes, it's most definitely in the public domain.
74  *
75  * I'm glad you find it useful.  I'm surprised it hasn't been replaced by,
76  * e.g,. something in GLibC.  Ii'm impressed you tracked me down.
77  *
78  *	/r$
79  *
80  * --
81  * Rich Salz                  Chief Security Architect
82  * DataPower Technology       http://www.datapower.com
83  * XS40 XML Security Gateway  http://www.datapower.com/products/xs40.html
84  * ---------------------------------------------------------------------->
85  * Subject:	scandir, ftw REDUX
86  * Date: 	1 Jan 88 00:47:01 GMT
87  * From: 	rsalz@pebbles.bbn.com
88  * Newsgroups:  comp.sources.misc
89  *
90  *
91  * Forget my previous message -- I just decided for completeness's sake to
92  * implement the SysV ftw(3) routine, too.
93  *
94  * To repeat, these are public-domain implementations of the SystemV ftw()
95  * routine, the BSD scandir() and alphasort() routines, and documentation for
96  * same.  The FTW manpage could be more readable, but so it goes.
97  *
98  * Anyhow, feel free to post these, and incorporate them into your existing
99  * packages.  I have readdir() routiens for MSDOS and the Amiga if anyone
100  *  wants them, and should have them for VMS by the end of January; let me
101  *  know if you want copies.
102  *
103  *                        Yours in filesystems,
104  *                                /r$
105  *
106  *                                Anyhow, feel free to post
107  * ----------------------------------------------------------------------<
108  *
109  */
110 
111 #include "routines.h"
112 #include "routines_p.h"
113 
114 #if defined (HAVE_SCANDIR) && defined (HAVE_DIRENT_H)
115 #include <dirent.h>
116 #elif defined (HAVE_DIRENT_H) || defined (_MSC_VER)
117 # ifdef HAVE_DIRENT_H
118 # include <dirent.h>
119 # endif
120 #define USE_SCANDIR_COMPARE_STRUCT_DIRENT
121 
122 #include <sys/types.h>
123 
124 #include <stdlib.h>
125 #include <stddef.h>
126 #include <string.h>
127 
128 #ifndef NULL
129 #  define NULL ((void *) 0)
130 #endif
131 
132 /* Initial guess at directory allocated.  */
133 #define INITIAL_ALLOCATION 20
134 
135 int
scandir(const char * directory_name,struct dirent *** array_pointer,int (* select_function)(const struct dirent *),int (* compare_function)(const struct dirent **,const struct dirent **))136 scandir(const char *directory_name,
137         struct dirent ***array_pointer, int (*select_function) (const struct dirent *),
138 #ifdef USE_SCANDIR_COMPARE_STRUCT_DIRENT
139         /* This is what the linux man page says */
140         int (*compare_function) (const struct dirent **, const struct dirent **)
141 #else
142         /* This is what the linux header file says ... */
143         int (*compare_function) (const void *, const void *)
144 #endif
145     )
146 {
147     DIR *directory;
148     struct dirent **array;
149     struct dirent *entry;
150     struct dirent *copy;
151     int allocated = INITIAL_ALLOCATION;
152     int counter = 0;
153 
154     /* Get initial list space and open directory.  */
155 
156     if (directory = opendir(directory_name), directory == NULL)
157         return -1;
158 
159     if (array = (struct dirent **)eMalloc(allocated * sizeof(struct dirent *)), array == NULL)
160         return -1;
161 
162     /* Read entries in the directory.  */
163 
164     while (entry = readdir(directory), entry)
165         if (select_function == NULL || (*select_function) (entry)) {
166             /* User wants them all, or he wants this one.  Copy the entry.  */
167 
168             /*
169              * On some OSes the declaration of "entry->d_name" is a minimal-length
170              * placeholder.  Example: Solaris:
171              *      /usr/include/sys/dirent.h:
172              *              "char d_name[1];"
173              *      man page "dirent(3)":
174              *              The field d_name is the beginning of the character array
175              *              giving the name of the directory entry. This name is
176              *              null terminated and may have at most MAXNAMLEN chars.
177              * So our malloc length may need to be increased accordingly.
178              *      sizeof(entry->d_name): space (possibly minimal) in struct.
179              *      strlen(entry->d_name): actual length of the entry.
180              *
181              *                      John Kavadias <john_kavadias@hotmail.com>
182              *                      David Lee <t.d.lee@durham.ac.uk>
183              */
184             int namelength = strlen(entry->d_name) + 1; /* length with NULL */
185             int extra = 0;
186 
187             if (sizeof(entry->d_name) <= namelength) {
188                 /* allocated space <= required space */
189                 extra += namelength - sizeof(entry->d_name);
190             }
191 
192             if (copy = (struct dirent *)eMalloc(sizeof(struct dirent) + extra), copy == NULL) {
193                 closedir(directory);
194                 eFree(array);
195                 return -1;
196             }
197             copy->d_ino = entry->d_ino;
198             copy->d_reclen = entry->d_reclen;
199             strcpy(copy->d_name, entry->d_name);
200 
201             /* Save the copy.  */
202 
203             if (counter + 1 == allocated) {
204                 allocated <<= 1;
205                 array = (struct dirent **)
206                     eRealloc((char *)array, allocated * sizeof(struct dirent *));
207                 if (array == NULL) {
208                     closedir(directory);
209                     eFree(array);
210                     eFree(copy);
211                     return -1;
212                 }
213             }
214             array[counter++] = copy;
215         }
216 
217     /* Close things off.  */
218 
219     array[counter] = NULL;
220     *array_pointer = array;
221     closedir(directory);
222 
223     /* Sort?  */
224 
225     if (counter > 1 && compare_function)
226         qsort((char *)array, counter, sizeof(struct dirent *)
227               , (int (*)(const void *, const void *))(compare_function));
228 
229     return counter;
230 }
231 #endif
232 
233 #if defined (HAVE_DIRENT_H) || defined (_MSC_VER)
scanDirectory(const char * directory_name,struct dirent *** array_pointer,int (* select_function)(const struct dirent *),int (* compare_function)(const struct dirent **,const struct dirent **))234 int scanDirectory (const char *directory_name,
235 				   struct dirent ***array_pointer, int (*select_function) (const struct dirent *),
236 				   int (*compare_function) (const struct dirent **, const struct dirent **))
237 {
238 	return scandir (directory_name, array_pointer, select_function, compare_function);
239 }
240 #endif
241