3 * This file has no copyright assigned and is placed in the Public Domain.
\r
4 * This file is a part of the mingw-runtime package.
\r
5 * No warranty is given; refer to the file DISCLAIMER within the package.
\r
7 * Derived from DIRLIB.C by Matt J. Weinstein
\r
8 * This note appears in the DIRLIB.H
\r
9 * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89
\r
11 * Updated by Jeremy Bettis <jeremy@hksys.com>
\r
12 * Significantly revised and rewinddir, seekdir and telldir added by Colin
\r
13 * Peters <colin@fu.is.saga-u.ac.jp>
\r
25 #define WIN32_LEAN_AND_MEAN
\r
26 #include <windows.h> /* for GetFileAttributes */
\r
31 #define _tdirent _wdirent
\r
33 #define _topendir _wopendir
\r
34 #define _tclosedir _wclosedir
\r
35 #define _treaddir _wreaddir
\r
36 #define _trewinddir _wrewinddir
\r
37 #define _ttelldir _wtelldir
\r
38 #define _tseekdir _wseekdir
\r
40 #define _tdirent dirent
\r
42 #define _topendir opendir
\r
43 #define _tclosedir closedir
\r
44 #define _treaddir readdir
\r
45 #define _trewinddir rewinddir
\r
46 #define _ttelldir telldir
\r
47 #define _tseekdir seekdir
\r
50 #define SUFFIX _T("*")
\r
51 #define SLASH _T("\\")
\r
57 * Returns a pointer to a DIR structure appropriately filled in to begin
\r
58 * searching a directory.
\r
61 _topendir (const _TCHAR *szPath)
\r
65 _TCHAR szFullPath[MAX_PATH];
\r
75 if (szPath[0] == _T('\0'))
\r
81 /* Attempt to determine if the given path really is a directory. */
\r
82 rc = GetFileAttributes (szPath);
\r
83 if (rc == (unsigned int)-1)
\r
85 /* call GetLastError for more error info */
\r
89 if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
\r
91 /* Error, entry exists but not a directory. */
\r
96 /* Make an absolute pathname. */
\r
97 _tfullpath (szFullPath, szPath, MAX_PATH);
\r
99 /* Allocate enough space to store DIR structure and the complete
\r
100 * directory path given. */
\r
101 nd = (_TDIR *) malloc (sizeof (_TDIR) + (_tcslen(szFullPath) + _tcslen (SLASH) +
\r
102 _tcslen(SUFFIX) + 1) * sizeof(_TCHAR));
\r
106 /* Error, out of memory. */
\r
108 return (_TDIR *) 0;
\r
111 /* Create the search expression. */
\r
112 _tcscpy (nd->dd_name, szFullPath);
\r
114 /* Add on a slash if the path does not end with one. */
\r
115 if (nd->dd_name[0] != _T('\0') &&
\r
116 nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('/') &&
\r
117 nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('\\'))
\r
119 _tcscat (nd->dd_name, SLASH);
\r
122 /* Add on the search pattern */
\r
123 _tcscat (nd->dd_name, SUFFIX);
\r
125 /* Initialize handle to -1 so that a premature closedir doesn't try
\r
126 * to call _findclose on it. */
\r
127 nd->dd_handle = -1;
\r
129 /* Initialize the status. */
\r
132 /* Initialize the dirent structure. ino and reclen are invalid under
\r
133 * Win32, and name simply points at the appropriate part of the
\r
134 * findfirst_t structure. */
\r
135 nd->dd_dir.d_ino = 0;
\r
136 nd->dd_dir.d_reclen = 0;
\r
137 nd->dd_dir.d_namlen = 0;
\r
138 memset (nd->dd_dir.d_name, 0, FILENAME_MAX);
\r
147 * Return a pointer to a dirent structure filled with the information on the
\r
148 * next entry in the directory.
\r
151 _treaddir (_TDIR * dirp)
\r
155 /* Check for valid DIR struct. */
\r
159 return (struct _tdirent *) 0;
\r
162 if (dirp->dd_stat < 0)
\r
164 /* We have already returned all files in the directory
\r
165 * (or the structure has an invalid dd_stat). */
\r
166 return (struct _tdirent *) 0;
\r
168 else if (dirp->dd_stat == 0)
\r
170 /* We haven't started the search yet. */
\r
171 /* Start the search */
\r
172 dirp->dd_handle = _tfindfirst (dirp->dd_name, &(dirp->dd_dta));
\r
174 if (dirp->dd_handle == -1)
\r
176 /* Whoops! Seems there are no files in that
\r
178 dirp->dd_stat = -1;
\r
187 /* Get the next search entry. */
\r
188 if (_tfindnext (dirp->dd_handle, &(dirp->dd_dta)))
\r
190 /* We are off the end or otherwise error.
\r
191 _findnext sets errno to ENOENT if no more file
\r
193 DWORD winerr = GetLastError();
\r
194 if (winerr == ERROR_NO_MORE_FILES)
\r
196 _findclose (dirp->dd_handle);
\r
197 dirp->dd_handle = -1;
\r
198 dirp->dd_stat = -1;
\r
202 /* Update the status to indicate the correct
\r
208 if (dirp->dd_stat > 0)
\r
210 /* Successfully got an entry. Everything about the file is
\r
211 * already appropriately filled in except the length of the
\r
213 dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dta.name);
\r
214 _tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
\r
215 return &dirp->dd_dir;
\r
218 return (struct _tdirent *) 0;
\r
225 * Frees up resources allocated by opendir.
\r
228 _tclosedir (_TDIR * dirp)
\r
241 if (dirp->dd_handle != -1)
\r
243 rc = _findclose (dirp->dd_handle);
\r
246 /* Delete the dir structure. */
\r
255 * Return to the beginning of the directory "stream". We simply call findclose
\r
256 * and then reset things like an opendir.
\r
259 _trewinddir (_TDIR * dirp)
\r
269 if (dirp->dd_handle != -1)
\r
271 _findclose (dirp->dd_handle);
\r
274 dirp->dd_handle = -1;
\r
281 * Returns the "position" in the "directory stream" which can be used with
\r
282 * seekdir to go back to an old entry. We simply return the value in stat.
\r
285 _ttelldir (_TDIR * dirp)
\r
294 return dirp->dd_stat;
\r
300 * Seek to an entry previously returned by telldir. We rewind the directory
\r
301 * and call readdir repeatedly until either dd_stat is the position number
\r
302 * or -1 (off the end). This is not perfect, in that the directory may
\r
303 * have changed while we weren't looking. But that is probably the case with
\r
307 _tseekdir (_TDIR * dirp, long lPos)
\r
319 /* Seeking to an invalid position. */
\r
323 else if (lPos == -1)
\r
325 /* Seek past end. */
\r
326 if (dirp->dd_handle != -1)
\r
328 _findclose (dirp->dd_handle);
\r
330 dirp->dd_handle = -1;
\r
331 dirp->dd_stat = -1;
\r
335 /* Rewind and read forward to the appropriate index. */
\r
336 _trewinddir (dirp);
\r
338 while ((dirp->dd_stat < lPos) && _treaddir (dirp))
\r