1 /* /////////////////////////////////////////////////////////////////////////
2 * File: dirent.c
3 *
4 * Purpose: Definition of the opendir() API functions for the Win32 platform.
5 *
6 * Created: 19th October 2002
7 * Updated: 12th August 2010
8 *
9 * Home: http://synesis.com.au/software/
10 *
11 * Copyright (c) 2002-2010, Matthew Wilson and Synesis Software
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met:
17 *
18 * - Redistributions of source code must retain the above copyright notice,
19 * this list of conditions and the following disclaimer.
20 * - Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * - Neither the name(s) of Matthew Wilson and Synesis Software nor the
24 * names of any contributors may be used to endorse or promote products
25 * derived from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
28 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
29 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 * ////////////////////////////////////////////////////////////////////// */
40
41
42 #ifndef UNIXEM_DOCUMENTATION_SKIP_SECTION
43 # define _SYNSOFT_VER_C_DIRENT_MAJOR 3
44 # define _SYNSOFT_VER_C_DIRENT_MINOR 0
45 # define _SYNSOFT_VER_C_DIRENT_REVISION 3
46 # define _SYNSOFT_VER_C_DIRENT_EDIT 38
47 #endif /* !UNIXEM_DOCUMENTATION_SKIP_SECTION */
48
49 /* /////////////////////////////////////////////////////////////////////////
50 * Includes
51 */
52
53 #include <unixem/dirent.h>
54
55 #include <errno.h>
56 #include <stdlib.h>
57 #include <windows.h>
58
59 /* /////////////////////////////////////////////////////////////////////////
60 * Compiler differences
61 */
62
63 #if defined(__BORLANDC__)
64 #elif defined(__DMC__)
65 #elif defined(__GNUC__)
66 #elif defined(__INTEL_COMPILER)
67 #elif defined(_MSC_VER)
68 #elif defined(__MWERKS__)
69 #elif defined(__WATCOMC__)
70 #else
71 # error Compiler not discriminated
72 #endif /* compiler */
73
74
75 #if defined(UNIXEM_opendir_PROVIDED_BY_COMPILER) && \
76 !defined(UNIXEM_FORCE_ANY_COMPILER)
77 # error The opendir() API is provided by this compiler, so should not be built here
78 #endif /* !UNIXEM_opendir_PROVIDED_BY_COMPILER */
79
80 /* /////////////////////////////////////////////////////////////////////////
81 * Constants and definitions
82 */
83
84 #ifndef FILE_ATTRIBUTE_ERROR
85 # define FILE_ATTRIBUTE_ERROR (0xFFFFFFFF)
86 #endif /* FILE_ATTRIBUTE_ERROR */
87
88 /* /////////////////////////////////////////////////////////////////////////
89 * Typedefs
90 */
91
92 struct dirent_dir
93 {
94 char directory[_MAX_DIR + 1]; /* . */
95 WIN32_FIND_DATAA find_data; /* The Win32 FindFile data. */
96 HANDLE hFind; /* The Win32 FindFile handle. */
97 struct unixem_dirent dirent; /* The handle's entry. */
98 };
99
100 struct wdirent_dir
101 {
102 wchar_t directory[_MAX_DIR + 1]; /* . */
103 WIN32_FIND_DATAW find_data; /* The Win32 FindFile data. */
104 HANDLE hFind; /* The Win32 FindFile handle. */
105 struct unixem_wdirent dirent; /* The handle's entry. */
106 };
107
108 /* /////////////////////////////////////////////////////////////////////////
109 * Helper functions
110 */
111
unixem__dirent__findfile_directory(char const * name,LPWIN32_FIND_DATAA data)112 static HANDLE unixem__dirent__findfile_directory(
113 char const* name
114 , LPWIN32_FIND_DATAA data
115 )
116 {
117 char search_spec[_MAX_PATH +1];
118
119 /* Simply add the *.*, ensuring the path separator is
120 * included.
121 */
122 (void)lstrcpyA(search_spec, name);
123 if( '\\' != search_spec[lstrlenA(search_spec) - 1] &&
124 '/' != search_spec[lstrlenA(search_spec) - 1])
125 {
126 (void)lstrcatA(search_spec, "\\*.*");
127 }
128 else
129 {
130 (void)lstrcatA(search_spec, "*.*");
131 }
132
133 return FindFirstFileA(search_spec, data);
134 }
135
136 #if 0
137 static HANDLE unixem__dirent__wfindfile_directory(
138 wchar_t const* name
139 , LPWIN32_FIND_DATAW data
140 )
141 {
142 wchar_t search_spec[_MAX_PATH +1];
143
144 /* Simply add the *.*, ensuring the path separator is
145 * included.
146 */
147 lstrcpyW(search_spec, name);
148 if( L'\\' != search_spec[lstrlenW(search_spec) - 1] &&
149 L'/' != search_spec[lstrlenW(search_spec) - 1])
150 {
151 lstrcatW(search_spec, L"\\*.*");
152 }
153 else
154 {
155 lstrcatW(search_spec, L"*.*");
156 }
157
158 return FindFirstFileW(search_spec, data);
159 }
160 #endif /* 0 */
161
162 /* /////////////////////////////////////////////////////////////////////////
163 * API functions
164 */
165
unixem_opendir(char const * name)166 unixem_DIR* unixem_opendir(char const* name)
167 {
168 unixem_DIR* result = NULL;
169 DWORD dwAttr;
170
171 /* Must be a valid name */
172 if( !name ||
173 !*name ||
174 (dwAttr = GetFileAttributes(name)) == FILE_ATTRIBUTE_ERROR)
175 {
176 errno = ENOENT;
177 }
178 /* Must be a directory */
179 else if(!(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
180 {
181 errno = ENOTDIR;
182 }
183 else
184 {
185 result = (unixem_DIR*)malloc(sizeof(unixem_DIR));
186
187 if(result == NULL)
188 {
189 errno = ENOMEM;
190 }
191 else
192 {
193 result->hFind = unixem__dirent__findfile_directory(name, &result->find_data);
194
195 if(result->hFind == INVALID_HANDLE_VALUE)
196 {
197 free(result);
198
199 result = NULL;
200 }
201 else
202 {
203 /* Save the directory, in case of rewind. */
204 (void)lstrcpyA(result->directory, name);
205 (void)lstrcpyA(result->dirent.d_name, result->find_data.cFileName);
206 result->dirent.d_mode = (int)result->find_data.dwFileAttributes;
207 }
208 }
209 }
210
211 #if 0
212 if(NULL != dir)
213 {
214 struct dirent* readdir(DIR* dir)
215
216 }
217 #endif /* 0 */
218
219
220
221 return result;
222 }
223
unixem_closedir(unixem_DIR * dir)224 int unixem_closedir(unixem_DIR* dir)
225 {
226 int ret;
227
228 if(dir == NULL)
229 {
230 errno = EBADF;
231
232 ret = -1;
233 }
234 else
235 {
236 /* Close the search handle, if not already done. */
237 if(dir->hFind != INVALID_HANDLE_VALUE)
238 {
239 (void)FindClose(dir->hFind);
240 }
241
242 free(dir);
243
244 ret = 0;
245 }
246
247 return ret;
248 }
249
unixem_rewinddir(unixem_DIR * dir)250 void unixem_rewinddir(unixem_DIR* dir)
251 {
252 /* Close the search handle, if not already done. */
253 if(dir->hFind != INVALID_HANDLE_VALUE)
254 {
255 (void)FindClose(dir->hFind);
256 }
257
258 dir->hFind = unixem__dirent__findfile_directory(dir->directory, &dir->find_data);
259
260 if(dir->hFind != INVALID_HANDLE_VALUE)
261 {
262 (void)lstrcpyA(dir->dirent.d_name, dir->find_data.cFileName);
263 }
264 }
265
unixem_readdir(unixem_DIR * dir)266 struct unixem_dirent* unixem_readdir(unixem_DIR* dir)
267 {
268 /* The last find exhausted the matches, so return NULL. */
269 if(dir->hFind == INVALID_HANDLE_VALUE)
270 {
271 if(FILE_ATTRIBUTE_ERROR == dir->find_data.dwFileAttributes)
272 {
273 errno = EBADF;
274 }
275 else
276 {
277 dir->find_data.dwFileAttributes = FILE_ATTRIBUTE_ERROR;
278 }
279
280 return NULL;
281 }
282 else
283 {
284 /* Copy the result of the last successful match to
285 * dirent.
286 */
287 (void)lstrcpyA(dir->dirent.d_name, dir->find_data.cFileName);
288
289 /* Attempt the next match. */
290 if(!FindNextFileA(dir->hFind, &dir->find_data))
291 {
292 /* Exhausted all matches, so close and null the
293 * handle.
294 */
295 (void)FindClose(dir->hFind);
296 dir->hFind = INVALID_HANDLE_VALUE;
297 }
298
299 return &dir->dirent;
300 }
301 }
302
303 /* ///////////////////////////// end of file //////////////////////////// */
304