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 *
filespec_from_dir_path(const char * path,char * buffer,size_t cch_buffer)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
opendir(const char * path)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
closedir(DIR * dp)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
readdir(DIR * dp)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
rewinddir(DIR * dp)220 rewinddir(DIR * dp)
221 {
222 if (IS_DP(dp))
223 dp->cursor = 0;
224 }
225
226 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
seekdir(DIR * dp,long offset)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
telldir(DIR * dp)234 telldir(DIR * dp)
235 {
236 return dp->cursor;
237 }
238