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