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