:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / 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$
13  * $Author$
14  * $Date$
15  *
16  */
17
18 #include <crtdll/stdlib.h>
19 /* #include <crtdll/ctype.h> */
20 #include <crtdll/errno.h>
21 #include <crtdll/string.h>
22 #include <crtdll/dir.h>
23 #include <crtdll/direct.h>
24 #include <crtdll/sys/stat.h>
25
26 #include <crtdll/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