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.
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
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>
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h> /* for GetFileAttributes */
31 #define _tdirent _wdirent
33 #define _topendir _wopendir
34 #define _tclosedir _wclosedir
35 #define _treaddir _wreaddir
36 #define _trewinddir _wrewinddir
37 #define _ttelldir _wtelldir
38 #define _tseekdir _wseekdir
40 #define _tdirent dirent
42 #define _topendir opendir
43 #define _tclosedir closedir
44 #define _treaddir readdir
45 #define _trewinddir rewinddir
46 #define _ttelldir telldir
47 #define _tseekdir seekdir
50 #define SUFFIX _T("*")
51 #define SLASH _T("\\")
57 * Returns a pointer to a DIR structure appropriately filled in to begin
58 * searching a directory.
61 _topendir (const _TCHAR
*szPath
)
65 _TCHAR szFullPath
[MAX_PATH
];
75 if (szPath
[0] == _T('\0'))
81 /* Attempt to determine if the given path really is a directory. */
82 rc
= GetFileAttributes (szPath
);
83 if (rc
== (unsigned int)-1)
85 /* call GetLastError for more error info */
89 if (!(rc
& FILE_ATTRIBUTE_DIRECTORY
))
91 /* Error, entry exists but not a directory. */
96 /* Make an absolute pathname. */
97 _tfullpath (szFullPath
, szPath
, MAX_PATH
);
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
));
106 /* Error, out of memory. */
111 /* Create the search expression. */
112 _tcscpy (nd
->dd_name
, szFullPath
);
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('\\'))
119 _tcscat (nd
->dd_name
, SLASH
);
122 /* Add on the search pattern */
123 _tcscat (nd
->dd_name
, SUFFIX
);
125 /* Initialize handle to -1 so that a premature closedir doesn't try
126 * to call _findclose on it. */
129 /* Initialize the status. */
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
);
147 * Return a pointer to a dirent structure filled with the information on the
148 * next entry in the directory.
151 _treaddir (_TDIR
* dirp
)
155 /* Check for valid DIR struct. */
159 return (struct _tdirent
*) 0;
162 if (dirp
->dd_stat
< 0)
164 /* We have already returned all files in the directory
165 * (or the structure has an invalid dd_stat). */
166 return (struct _tdirent
*) 0;
168 else if (dirp
->dd_stat
== 0)
170 /* We haven't started the search yet. */
171 /* Start the search */
172 dirp
->dd_handle
= _tfindfirst (dirp
->dd_name
, &(dirp
->dd_dta
));
174 if (dirp
->dd_handle
== -1)
176 /* Whoops! Seems there are no files in that
187 /* Get the next search entry. */
188 if (_tfindnext (dirp
->dd_handle
, &(dirp
->dd_dta
)))
190 /* We are off the end or otherwise error.
191 _findnext sets errno to ENOENT if no more file
193 DWORD winerr
= GetLastError();
194 if (winerr
== ERROR_NO_MORE_FILES
)
196 _findclose (dirp
->dd_handle
);
197 dirp
->dd_handle
= -1;
202 /* Update the status to indicate the correct
208 if (dirp
->dd_stat
> 0)
210 /* Successfully got an entry. Everything about the file is
211 * already appropriately filled in except the length of the
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
;
218 return (struct _tdirent
*) 0;
225 * Frees up resources allocated by opendir.
228 _tclosedir (_TDIR
* dirp
)
241 if (dirp
->dd_handle
!= -1)
243 rc
= _findclose (dirp
->dd_handle
);
246 /* Delete the dir structure. */
255 * Return to the beginning of the directory "stream". We simply call findclose
256 * and then reset things like an opendir.
259 _trewinddir (_TDIR
* dirp
)
269 if (dirp
->dd_handle
!= -1)
271 _findclose (dirp
->dd_handle
);
274 dirp
->dd_handle
= -1;
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.
285 _ttelldir (_TDIR
* dirp
)
294 return dirp
->dd_stat
;
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
307 _tseekdir (_TDIR
* dirp
, long lPos
)
319 /* Seeking to an invalid position. */
326 if (dirp
->dd_handle
!= -1)
328 _findclose (dirp
->dd_handle
);
330 dirp
->dd_handle
= -1;
335 /* Rewind and read forward to the appropriate index. */
338 while ((dirp
->dd_stat
< lPos
) && _treaddir (dirp
))