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