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