• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * dirent.c
3  * This file has no copyright assigned and is placed in the Public Domain.
4  * This file is a part of the mingw-runtime package.
5  * No warranty is given; refer to the file DISCLAIMER within the package.
6  *
7  * Derived from DIRLIB.C by Matt J. Weinstein
8  * This note appears in the DIRLIB.H
9  * DIRLIB.H by M. J. Weinstein   Released to public domain 1-Jan-89
10  *
11  * Updated by Jeremy Bettis <jeremy@hksys.com>
12  * Significantly revised and rewinddir, seekdir and telldir added by Colin
13  * Peters <colin@fu.is.saga-u.ac.jp>
14  *
15  */
16 
17 #include <stdlib.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <io.h>
21 #include <direct.h>
22 
23 #include "dirent.h"
24 
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h> /* for GetFileAttributes */
27 
28 #include <tchar.h>
29 
30 #ifdef _UNICODE
31 #define _tdirent	_wdirent
32 #define _TDIR 		_WDIR
33 #define _topendir	_wopendir
34 #define _tclosedir	_wclosedir
35 #define _treaddir	_wreaddir
36 #define _trewinddir	_wrewinddir
37 #define _ttelldir	_wtelldir
38 #define _tseekdir	_wseekdir
39 #else
40 #define _tdirent	dirent
41 #define _TDIR 		DIR
42 #define _topendir	opendir
43 #define _tclosedir	closedir
44 #define _treaddir	readdir
45 #define _trewinddir	rewinddir
46 #define _ttelldir	telldir
47 #define _tseekdir	seekdir
48 #endif
49 
50 #define SUFFIX	_T("*")
51 #define	SLASH	_T("\\")
52 
53 
54 /*
55  * opendir
56  *
57  * Returns a pointer to a DIR structure appropriately filled in to begin
58  * searching a directory.
59  */
60 _TDIR *
_topendir(const _TCHAR * szPath)61 _topendir (const _TCHAR *szPath)
62 {
63   _TDIR *nd;
64   unsigned int rc;
65   _TCHAR szFullPath[MAX_PATH];
66 
67   errno = 0;
68 
69   if (!szPath)
70     {
71       errno = EFAULT;
72       return (_TDIR *) 0;
73     }
74 
75   if (szPath[0] == _T('\0'))
76     {
77       errno = ENOTDIR;
78       return (_TDIR *) 0;
79     }
80 
81   /* Attempt to determine if the given path really is a directory. */
82   rc = GetFileAttributes (szPath);
83   if (rc == (unsigned int)-1)
84     {
85       /* call GetLastError for more error info */
86       errno = ENOENT;
87       return (_TDIR *) 0;
88     }
89   if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
90     {
91       /* Error, entry exists but not a directory. */
92       errno = ENOTDIR;
93       return (_TDIR *) 0;
94     }
95 
96   /* Make an absolute pathname.  */
97   _tfullpath (szFullPath, szPath, MAX_PATH);
98 
99   /* Allocate enough space to store DIR structure and the complete
100    * directory path given. */
101   nd = (_TDIR *) malloc (sizeof (_TDIR) + (_tcslen(szFullPath) + _tcslen (SLASH) +
102 			 _tcslen(SUFFIX) + 1) * sizeof(_TCHAR));
103 
104   if (!nd)
105     {
106       /* Error, out of memory. */
107       errno = ENOMEM;
108       return (_TDIR *) 0;
109     }
110 
111   /* Create the search expression. */
112   _tcscpy (nd->dd_name, szFullPath);
113 
114   /* Add on a slash if the path does not end with one. */
115   if (nd->dd_name[0] != _T('\0') &&
116       nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('/') &&
117       nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('\\'))
118     {
119       _tcscat (nd->dd_name, SLASH);
120     }
121 
122   /* Add on the search pattern */
123   _tcscat (nd->dd_name, SUFFIX);
124 
125   /* Initialize handle to -1 so that a premature closedir doesn't try
126    * to call _findclose on it. */
127   nd->dd_handle = -1;
128 
129   /* Initialize the status. */
130   nd->dd_stat = 0;
131 
132   /* Initialize the dirent structure. ino and reclen are invalid under
133    * Win32, and name simply points at the appropriate part of the
134    * findfirst_t structure. */
135   nd->dd_dir.d_ino = 0;
136   nd->dd_dir.d_reclen = 0;
137   nd->dd_dir.d_namlen = 0;
138   memset (nd->dd_dir.d_name, 0, FILENAME_MAX);
139 
140   return nd;
141 }
142 
143 
144 /*
145  * readdir
146  *
147  * Return a pointer to a dirent structure filled with the information on the
148  * next entry in the directory.
149  */
150 struct _tdirent *
_treaddir(_TDIR * dirp)151 _treaddir (_TDIR * dirp)
152 {
153   errno = 0;
154 
155   /* Check for valid DIR struct. */
156   if (!dirp)
157     {
158       errno = EFAULT;
159       return (struct _tdirent *) 0;
160     }
161 
162   if (dirp->dd_stat < 0)
163     {
164       /* We have already returned all files in the directory
165        * (or the structure has an invalid dd_stat). */
166       return (struct _tdirent *) 0;
167     }
168   else if (dirp->dd_stat == 0)
169     {
170       /* We haven't started the search yet. */
171       /* Start the search */
172       dirp->dd_handle = _tfindfirst (dirp->dd_name, &(dirp->dd_dta));
173 
174   	  if (dirp->dd_handle == -1)
175 	{
176 	  /* Whoops! Seems there are no files in that
177 	   * directory. */
178 	  dirp->dd_stat = -1;
179 	}
180       else
181 	{
182 	  dirp->dd_stat = 1;
183 	}
184     }
185   else
186     {
187       /* Get the next search entry. */
188       if (_tfindnext (dirp->dd_handle, &(dirp->dd_dta)))
189 	{
190 	  /* We are off the end or otherwise error.
191 	     _findnext sets errno to ENOENT if no more file
192 	     Undo this. */
193 	  DWORD winerr = GetLastError();
194 	  if (winerr == ERROR_NO_MORE_FILES)
195 	    errno = 0;
196 	  _findclose (dirp->dd_handle);
197 	  dirp->dd_handle = -1;
198 	  dirp->dd_stat = -1;
199 	}
200       else
201 	{
202 	  /* Update the status to indicate the correct
203 	   * number. */
204 	  dirp->dd_stat++;
205 	}
206     }
207 
208   if (dirp->dd_stat > 0)
209     {
210       /* Successfully got an entry. Everything about the file is
211        * already appropriately filled in except the length of the
212        * file name. */
213       dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dta.name);
214       _tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
215       return &dirp->dd_dir;
216     }
217 
218   return (struct _tdirent *) 0;
219 }
220 
221 
222 /*
223  * closedir
224  *
225  * Frees up resources allocated by opendir.
226  */
227 int
_tclosedir(_TDIR * dirp)228 _tclosedir (_TDIR * dirp)
229 {
230   int rc;
231 
232   errno = 0;
233   rc = 0;
234 
235   if (!dirp)
236     {
237       errno = EFAULT;
238       return -1;
239     }
240 
241   if (dirp->dd_handle != -1)
242     {
243       rc = _findclose (dirp->dd_handle);
244     }
245 
246   /* Delete the dir structure. */
247   free (dirp);
248 
249   return rc;
250 }
251 
252 /*
253  * rewinddir
254  *
255  * Return to the beginning of the directory "stream". We simply call findclose
256  * and then reset things like an opendir.
257  */
258 void
_trewinddir(_TDIR * dirp)259 _trewinddir (_TDIR * dirp)
260 {
261   errno = 0;
262 
263   if (!dirp)
264     {
265       errno = EFAULT;
266       return;
267     }
268 
269   if (dirp->dd_handle != -1)
270     {
271       _findclose (dirp->dd_handle);
272     }
273 
274   dirp->dd_handle = -1;
275   dirp->dd_stat = 0;
276 }
277 
278 /*
279  * telldir
280  *
281  * Returns the "position" in the "directory stream" which can be used with
282  * seekdir to go back to an old entry. We simply return the value in stat.
283  */
284 long
_ttelldir(_TDIR * dirp)285 _ttelldir (_TDIR * dirp)
286 {
287   errno = 0;
288 
289   if (!dirp)
290     {
291       errno = EFAULT;
292       return -1;
293     }
294   return dirp->dd_stat;
295 }
296 
297 /*
298  * seekdir
299  *
300  * Seek to an entry previously returned by telldir. We rewind the directory
301  * and call readdir repeatedly until either dd_stat is the position number
302  * or -1 (off the end). This is not perfect, in that the directory may
303  * have changed while we weren't looking. But that is probably the case with
304  * any such system.
305  */
306 void
_tseekdir(_TDIR * dirp,long lPos)307 _tseekdir (_TDIR * dirp, long lPos)
308 {
309   errno = 0;
310 
311   if (!dirp)
312     {
313       errno = EFAULT;
314       return;
315     }
316 
317   if (lPos < -1)
318     {
319       /* Seeking to an invalid position. */
320       errno = EINVAL;
321       return;
322     }
323   else if (lPos == -1)
324     {
325       /* Seek past end. */
326       if (dirp->dd_handle != -1)
327 	{
328 	  _findclose (dirp->dd_handle);
329 	}
330       dirp->dd_handle = -1;
331       dirp->dd_stat = -1;
332     }
333   else
334     {
335       /* Rewind and read forward to the appropriate index. */
336       _trewinddir (dirp);
337 
338       while ((dirp->dd_stat < lPos) && _treaddir (dirp))
339 	;
340     }
341 }
342