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