]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/dirent.c
SourceFormat: enforcement
[thirdparty/squid.git] / lib / dirent.c
1 /*
2 * $Id$
3 *
4 * Implement dirent-style opendir(), readdir(), closedir(), rewinddir(),
5 * seekdir() and telldir on Windows - Based on mingw-runtime package sources.
6 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 * Original file info follow:
35 *
36 * dirent.c
37 * This file has no copyright assigned and is placed in the Public Domain.
38 * This file is a part of the mingw-runtime package.
39 * No warranty is given; refer to the file DISCLAIMER within the package.
40 *
41 * Derived from DIRLIB.C by Matt J. Weinstein
42 * This note appears in the DIRLIB.H
43 * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89
44 *
45 * Updated by Jeremy Bettis <jeremy@hksys.com>
46 * Significantly revised and rewinddir, seekdir and telldir added by Colin
47 * Peters <colin@fu.is.saga-u.ac.jp>
48 *
49 */
50
51 #include "util.h"
52
53 /* The following code section is part of the native Windows Squid port */
54 #if defined(_SQUID_MSWIN_)
55 #include <stdlib.h>
56 #include <errno.h>
57 #include <string.h>
58 #include <io.h>
59 #include <dirent.h>
60
61 #define WIN32_LEAN_AND_MEAN
62 #include <windows.h> /* for GetFileAttributes */
63
64 #define SUFFIX ("*")
65 #define SLASH ("\\")
66
67
68 /*
69 * opendir
70 *
71 * Returns a pointer to a DIR structure appropriately filled in to begin
72 * searching a directory.
73 */
74 DIR *
75 opendir(const CHAR * szPath)
76 {
77 DIR *nd;
78 unsigned int rc;
79 CHAR szFullPath[MAX_PATH];
80
81 errno = 0;
82
83 if (!szPath) {
84 errno = EFAULT;
85 return (DIR *) 0;
86 }
87 if (szPath[0] == '\0') {
88 errno = ENOTDIR;
89 return (DIR *) 0;
90 }
91 /* Attempt to determine if the given path really is a directory. */
92 rc = GetFileAttributes(szPath);
93 if (rc == (unsigned int) -1) {
94 /* call GetLastError for more error info */
95 errno = ENOENT;
96 return (DIR *) 0;
97 }
98 if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) {
99 /* Error, entry exists but not a directory. */
100 errno = ENOTDIR;
101 return (DIR *) 0;
102 }
103 /* Make an absolute pathname. */
104 _fullpath(szFullPath, szPath, MAX_PATH);
105
106 /* Allocate enough space to store DIR structure and the complete
107 * directory path given. */
108 nd = (DIR *) malloc(sizeof(DIR) + (strlen(szFullPath)
109 + strlen(SLASH)
110 + strlen(SUFFIX) + 1)
111 * sizeof(CHAR));
112
113 if (!nd) {
114 /* Error, out of memory. */
115 errno = ENOMEM;
116 return (DIR *) 0;
117 }
118 /* Create the search expression. */
119 strcpy(nd->dd_name, szFullPath);
120
121 /* Add on a slash if the path does not end with one. */
122 if (nd->dd_name[0] != '\0'
123 && strchr(nd->dd_name, '/') != nd->dd_name
124 + strlen(nd->dd_name) - 1
125 && strchr(nd->dd_name, '\\') != nd->dd_name
126 + strlen(nd->dd_name) - 1) {
127 strcat(nd->dd_name, SLASH);
128 }
129 /* Add on the search pattern */
130 strcat(nd->dd_name, SUFFIX);
131
132 /* Initialize handle to -1 so that a premature closedir doesn't try
133 * to call _findclose on it. */
134 nd->dd_handle = -1;
135
136 /* Initialize the status. */
137 nd->dd_stat = 0;
138
139 /* Initialize the dirent structure. ino and reclen are invalid under
140 * Win32, and name simply points at the appropriate part of the
141 * findfirst_t structure. */
142 nd->dd_dir.d_ino = 0;
143 nd->dd_dir.d_reclen = 0;
144 nd->dd_dir.d_namlen = 0;
145 memset(nd->dd_dir.d_name, 0, FILENAME_MAX);
146
147 return nd;
148 }
149
150
151 /*
152 * readdir
153 *
154 * Return a pointer to a dirent structure filled with the information on the
155 * next entry in the directory.
156 */
157 struct dirent *
158 readdir(DIR * dirp) {
159 errno = 0;
160
161 /* Check for valid DIR struct. */
162 if (!dirp) {
163 errno = EFAULT;
164 return (struct dirent *) 0;
165 }
166 if (dirp->dd_stat < 0) {
167 /* We have already returned all files in the directory
168 * (or the structure has an invalid dd_stat). */
169 return (struct dirent *) 0;
170 } else if (dirp->dd_stat == 0) {
171 /* We haven't started the search yet. */
172 /* Start the search */
173 dirp->dd_handle = _findfirst(dirp->dd_name, &(dirp->dd_dta));
174
175 if (dirp->dd_handle == -1) {
176 /* Whoops! Seems there are no files in that
177 * directory. */
178 dirp->dd_stat = -1;
179 } else {
180 dirp->dd_stat = 1;
181 }
182 } else {
183 /* Get the next search entry. */
184 if (_findnext(dirp->dd_handle, &(dirp->dd_dta))) {
185 /* We are off the end or otherwise error.
186 * _findnext sets errno to ENOENT if no more file
187 * Undo this. */
188 DWORD winerr = GetLastError();
189 if (winerr == ERROR_NO_MORE_FILES)
190 errno = 0;
191 _findclose(dirp->dd_handle);
192 dirp->dd_handle = -1;
193 dirp->dd_stat = -1;
194 } else {
195 /* Update the status to indicate the correct
196 * number. */
197 dirp->dd_stat++;
198 }
199 }
200
201 if (dirp->dd_stat > 0) {
202 /* Successfully got an entry. Everything about the file is
203 * already appropriately filled in except the length of the
204 * file name. */
205 dirp->dd_dir.d_namlen = strlen(dirp->dd_dta.name);
206 strcpy(dirp->dd_dir.d_name, dirp->dd_dta.name);
207 return &dirp->dd_dir;
208 }
209 return (struct dirent *) 0;
210 }
211
212
213 /*
214 * closedir
215 *
216 * Frees up resources allocated by opendir.
217 */
218 int
219 closedir(DIR * dirp)
220 {
221 int rc;
222
223 errno = 0;
224 rc = 0;
225
226 if (!dirp) {
227 errno = EFAULT;
228 return -1;
229 }
230 if (dirp->dd_handle != -1) {
231 rc = _findclose(dirp->dd_handle);
232 }
233 /* Delete the dir structure. */
234 free(dirp);
235
236 return rc;
237 }
238
239 /*
240 * rewinddir
241 *
242 * Return to the beginning of the directory "stream". We simply call findclose
243 * and then reset things like an opendir.
244 */
245 void
246 rewinddir(DIR * dirp)
247 {
248 errno = 0;
249
250 if (!dirp) {
251 errno = EFAULT;
252 return;
253 }
254 if (dirp->dd_handle != -1) {
255 _findclose(dirp->dd_handle);
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
268 telldir(DIR * dirp)
269 {
270 errno = 0;
271
272 if (!dirp) {
273 errno = EFAULT;
274 return -1;
275 }
276 return dirp->dd_stat;
277 }
278
279 /*
280 * seekdir
281 *
282 * Seek to an entry previously returned by telldir. We rewind the directory
283 * and call readdir repeatedly until either dd_stat is the position number
284 * or -1 (off the end). This is not perfect, in that the directory may
285 * have changed while we weren't looking. But that is probably the case with
286 * any such system.
287 */
288 void
289 seekdir(DIR * dirp, long lPos)
290 {
291 errno = 0;
292
293 if (!dirp) {
294 errno = EFAULT;
295 return;
296 }
297 if (lPos < -1) {
298 /* Seeking to an invalid position. */
299 errno = EINVAL;
300 return;
301 } else if (lPos == -1) {
302 /* Seek past end. */
303 if (dirp->dd_handle != -1) {
304 _findclose(dirp->dd_handle);
305 }
306 dirp->dd_handle = -1;
307 dirp->dd_stat = -1;
308 } else {
309 /* Rewind and read forward to the appropriate index. */
310 rewinddir(dirp);
311
312 while ((dirp->dd_stat < lPos) && readdir(dirp));
313 }
314 }
315 #endif /* _SQUID_MSWIN_ */