1 /* $NetBSD: dirent.c,v 1.1.1.2 2014/04/24 12:45:52 pettai Exp $ */ 2 3 /*********************************************************************** 4 * Copyright (c) 2009, Secure Endpoints Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * - Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 * OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 **********************************************************************/ 33 34 #include<config.h> 35 36 #include <stdlib.h> 37 #include <io.h> 38 #include <string.h> 39 #include <errno.h> 40 #include "dirent.h" 41 42 #ifndef _WIN32 43 #error Only implemented for Win32 44 #endif 45 46 struct _dirent_dirinfo { 47 int magic; 48 long n_entries; 49 long nc_entries; 50 long cursor; 51 struct dirent **entries; 52 }; 53 #define DIRINFO_MAGIC 0xf8c0639d 54 #define IS_DP(p) ((p) && ((DIR *)(p))->magic == DIRINFO_MAGIC) 55 56 #define INITIAL_ENTRIES 16 57 58 /** 59 * Create a filespec for use with _findfirst() using a path spec 60 * 61 * If the last component of the path spec contains wildcards, we let 62 * it be. If the last component doesn't end with a slash, we add one. 63 */ 64 static const char * 65 filespec_from_dir_path(const char * path, char * buffer, size_t cch_buffer) 66 { 67 char *comp, *t; 68 size_t pos; 69 int found_sep = 0; 70 71 if (strcpy_s(buffer, cch_buffer, path) != 0) 72 return NULL; 73 74 comp = strrchr(buffer, '\\'); 75 if (comp == NULL) 76 comp = buffer; 77 else 78 found_sep = 1; 79 80 t = strrchr(comp, '/'); 81 if (t != NULL) { 82 comp = t; 83 found_sep = 1; 84 } 85 86 if (found_sep) 87 comp++; 88 89 pos = strcspn(comp, "*?"); 90 if (comp[pos] != '\0') 91 return buffer; 92 93 /* We don't append a slash if pos == 0 because that changes the 94 * meaning: 95 * 96 * "*.*" is all files in the current directory. 97 * "\*.*" is all files in the root directory of the current drive. 98 */ 99 if (pos > 0 && comp[pos - 1] != '\\' && 100 comp[pos - 1] != '/') { 101 strcat_s(comp, cch_buffer - (comp - buffer), "\\"); 102 } 103 104 strcat_s(comp, cch_buffer - (comp - buffer), "*.*"); 105 106 return buffer; 107 } 108 109 ROKEN_LIB_FUNCTION DIR * ROKEN_LIB_CALL 110 opendir(const char * path) 111 { 112 DIR * dp; 113 struct _finddata_t fd; 114 intptr_t fd_handle; 115 const char *filespec; 116 char path_buffer[1024]; 117 118 memset(&fd, 0, sizeof(fd)); 119 120 filespec = filespec_from_dir_path(path, path_buffer, sizeof(path_buffer)/sizeof(char)); 121 if (filespec == NULL) 122 return NULL; 123 124 fd_handle = _findfirst(filespec, &fd); 125 126 if (fd_handle == -1) 127 return NULL; 128 129 dp = malloc(sizeof(*dp)); 130 if (dp == NULL) 131 goto done; 132 133 memset(dp, 0, sizeof(*dp)); 134 dp->magic = DIRINFO_MAGIC; 135 dp->cursor = 0; 136 dp->n_entries = 0; 137 dp->nc_entries = INITIAL_ENTRIES; 138 dp->entries = calloc(dp->nc_entries, sizeof(dp->entries[0])); 139 140 if (dp->entries == NULL) { 141 closedir(dp); 142 dp = NULL; 143 goto done; 144 } 145 146 do { 147 size_t len = strlen(fd.name); 148 struct dirent * e; 149 150 if (dp->n_entries == dp->nc_entries) { 151 struct dirent ** ne; 152 153 dp->nc_entries *= 2; 154 ne = realloc(dp->entries, sizeof(dp->entries[0]) * dp->nc_entries); 155 156 if (ne == NULL) { 157 closedir(dp); 158 dp = NULL; 159 goto done; 160 } 161 162 dp->entries = ne; 163 } 164 165 e = malloc(sizeof(*e) + len * sizeof(char)); 166 if (e == NULL) { 167 closedir(dp); 168 dp = NULL; 169 goto done; 170 } 171 172 e->d_ino = 0; /* no inodes :( */ 173 strcpy_s(e->d_name, len + 1, fd.name); 174 175 dp->entries[dp->n_entries++] = e; 176 177 } while (_findnext(fd_handle, &fd) == 0); 178 179 done: 180 if (fd_handle != -1) 181 _findclose(fd_handle); 182 183 return dp; 184 } 185 186 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 187 closedir(DIR * dp) 188 { 189 if (!IS_DP(dp)) 190 return EINVAL; 191 192 if (dp->entries) { 193 long i; 194 195 for (i=0; i < dp->n_entries; i++) { 196 free(dp->entries[i]); 197 } 198 199 free(dp->entries); 200 } 201 202 free(dp); 203 204 return 0; 205 } 206 207 ROKEN_LIB_FUNCTION struct dirent * ROKEN_LIB_CALL 208 readdir(DIR * dp) 209 { 210 if (!IS_DP(dp) || 211 dp->cursor < 0 || 212 dp->cursor >= dp->n_entries) 213 214 return NULL; 215 216 return dp->entries[dp->cursor++]; 217 } 218 219 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 220 rewinddir(DIR * dp) 221 { 222 if (IS_DP(dp)) 223 dp->cursor = 0; 224 } 225 226 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 227 seekdir(DIR * dp, long offset) 228 { 229 if (IS_DP(dp) && offset >= 0 && offset < dp->n_entries) 230 dp->cursor = offset; 231 } 232 233 ROKEN_LIB_FUNCTION long ROKEN_LIB_CALL 234 telldir(DIR * dp) 235 { 236 return dp->cursor; 237 } 238