]>
Commit | Line | Data |
---|---|---|
63b81f13 GS |
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. | |
26ac0430 | 24 | * |
63b81f13 GS |
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. | |
26ac0430 | 29 | * |
63b81f13 GS |
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 | * | |
26ac0430 | 41 | * Derived from DIRLIB.C by Matt J. Weinstein |
63b81f13 GS |
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> | |
26ac0430 | 48 | * |
63b81f13 GS |
49 | */ |
50 | ||
f7f3304a | 51 | #include "squid.h" |
63b81f13 GS |
52 | |
53 | /* The following code section is part of the native Windows Squid port */ | |
8a09e810 | 54 | #if _SQUID_MSWIN_ |
75072239 AJ |
55 | |
56 | #include "util.h" | |
63b81f13 GS |
57 | #include <stdlib.h> |
58 | #include <errno.h> | |
59 | #include <string.h> | |
60 | #include <io.h> | |
61 | #include <dirent.h> | |
62 | ||
63 | #define WIN32_LEAN_AND_MEAN | |
64 | #include <windows.h> /* for GetFileAttributes */ | |
65 | ||
66 | #define SUFFIX ("*") | |
67 | #define SLASH ("\\") | |
68 | ||
63b81f13 GS |
69 | /* |
70 | * opendir | |
71 | * | |
72 | * Returns a pointer to a DIR structure appropriately filled in to begin | |
73 | * searching a directory. | |
74 | */ | |
75 | DIR * | |
76 | opendir(const CHAR * szPath) | |
77 | { | |
78 | DIR *nd; | |
79 | unsigned int rc; | |
80 | CHAR szFullPath[MAX_PATH]; | |
81 | ||
82 | errno = 0; | |
83 | ||
84 | if (!szPath) { | |
26ac0430 AJ |
85 | errno = EFAULT; |
86 | return (DIR *) 0; | |
63b81f13 GS |
87 | } |
88 | if (szPath[0] == '\0') { | |
26ac0430 AJ |
89 | errno = ENOTDIR; |
90 | return (DIR *) 0; | |
63b81f13 GS |
91 | } |
92 | /* Attempt to determine if the given path really is a directory. */ | |
93 | rc = GetFileAttributes(szPath); | |
94 | if (rc == (unsigned int) -1) { | |
26ac0430 AJ |
95 | /* call GetLastError for more error info */ |
96 | errno = ENOENT; | |
97 | return (DIR *) 0; | |
63b81f13 GS |
98 | } |
99 | if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) { | |
26ac0430 AJ |
100 | /* Error, entry exists but not a directory. */ |
101 | errno = ENOTDIR; | |
102 | return (DIR *) 0; | |
63b81f13 GS |
103 | } |
104 | /* Make an absolute pathname. */ | |
105 | _fullpath(szFullPath, szPath, MAX_PATH); | |
106 | ||
107 | /* Allocate enough space to store DIR structure and the complete | |
108 | * directory path given. */ | |
109 | nd = (DIR *) malloc(sizeof(DIR) + (strlen(szFullPath) | |
26ac0430 AJ |
110 | + strlen(SLASH) |
111 | + strlen(SUFFIX) + 1) | |
112 | * sizeof(CHAR)); | |
63b81f13 GS |
113 | |
114 | if (!nd) { | |
26ac0430 AJ |
115 | /* Error, out of memory. */ |
116 | errno = ENOMEM; | |
117 | return (DIR *) 0; | |
63b81f13 GS |
118 | } |
119 | /* Create the search expression. */ | |
120 | strcpy(nd->dd_name, szFullPath); | |
121 | ||
122 | /* Add on a slash if the path does not end with one. */ | |
123 | if (nd->dd_name[0] != '\0' | |
26ac0430 AJ |
124 | && strchr(nd->dd_name, '/') != nd->dd_name |
125 | + strlen(nd->dd_name) - 1 | |
126 | && strchr(nd->dd_name, '\\') != nd->dd_name | |
127 | + strlen(nd->dd_name) - 1) { | |
128 | strcat(nd->dd_name, SLASH); | |
63b81f13 GS |
129 | } |
130 | /* Add on the search pattern */ | |
131 | strcat(nd->dd_name, SUFFIX); | |
132 | ||
133 | /* Initialize handle to -1 so that a premature closedir doesn't try | |
134 | * to call _findclose on it. */ | |
135 | nd->dd_handle = -1; | |
136 | ||
137 | /* Initialize the status. */ | |
138 | nd->dd_stat = 0; | |
139 | ||
140 | /* Initialize the dirent structure. ino and reclen are invalid under | |
141 | * Win32, and name simply points at the appropriate part of the | |
142 | * findfirst_t structure. */ | |
143 | nd->dd_dir.d_ino = 0; | |
144 | nd->dd_dir.d_reclen = 0; | |
145 | nd->dd_dir.d_namlen = 0; | |
146 | memset(nd->dd_dir.d_name, 0, FILENAME_MAX); | |
147 | ||
148 | return nd; | |
149 | } | |
150 | ||
63b81f13 GS |
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 * | |
e1381638 | 158 | readdir(DIR * dirp) { |
63b81f13 GS |
159 | errno = 0; |
160 | ||
161 | /* Check for valid DIR struct. */ | |
162 | if (!dirp) { | |
26ac0430 AJ |
163 | errno = EFAULT; |
164 | return (struct dirent *) 0; | |
63b81f13 GS |
165 | } |
166 | if (dirp->dd_stat < 0) { | |
26ac0430 AJ |
167 | /* We have already returned all files in the directory |
168 | * (or the structure has an invalid dd_stat). */ | |
169 | return (struct dirent *) 0; | |
63b81f13 | 170 | } else if (dirp->dd_stat == 0) { |
26ac0430 AJ |
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 | } | |
63b81f13 | 182 | } else { |
26ac0430 AJ |
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 | } | |
63b81f13 GS |
199 | } |
200 | ||
201 | if (dirp->dd_stat > 0) { | |
26ac0430 AJ |
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; | |
63b81f13 GS |
208 | } |
209 | return (struct dirent *) 0; | |
210 | } | |
211 | ||
63b81f13 GS |
212 | /* |
213 | * closedir | |
214 | * | |
215 | * Frees up resources allocated by opendir. | |
216 | */ | |
217 | int | |
218 | closedir(DIR * dirp) | |
219 | { | |
220 | int rc; | |
221 | ||
222 | errno = 0; | |
223 | rc = 0; | |
224 | ||
225 | if (!dirp) { | |
26ac0430 AJ |
226 | errno = EFAULT; |
227 | return -1; | |
63b81f13 GS |
228 | } |
229 | if (dirp->dd_handle != -1) { | |
26ac0430 | 230 | rc = _findclose(dirp->dd_handle); |
63b81f13 GS |
231 | } |
232 | /* Delete the dir structure. */ | |
233 | free(dirp); | |
234 | ||
235 | return rc; | |
236 | } | |
237 | ||
238 | /* | |
239 | * rewinddir | |
240 | * | |
241 | * Return to the beginning of the directory "stream". We simply call findclose | |
242 | * and then reset things like an opendir. | |
243 | */ | |
244 | void | |
245 | rewinddir(DIR * dirp) | |
246 | { | |
247 | errno = 0; | |
248 | ||
249 | if (!dirp) { | |
26ac0430 AJ |
250 | errno = EFAULT; |
251 | return; | |
63b81f13 GS |
252 | } |
253 | if (dirp->dd_handle != -1) { | |
26ac0430 | 254 | _findclose(dirp->dd_handle); |
63b81f13 GS |
255 | } |
256 | dirp->dd_handle = -1; | |
257 | dirp->dd_stat = 0; | |
258 | } | |
259 | ||
260 | /* | |
261 | * telldir | |
262 | * | |
263 | * Returns the "position" in the "directory stream" which can be used with | |
264 | * seekdir to go back to an old entry. We simply return the value in stat. | |
265 | */ | |
266 | long | |
267 | telldir(DIR * dirp) | |
268 | { | |
269 | errno = 0; | |
270 | ||
271 | if (!dirp) { | |
26ac0430 AJ |
272 | errno = EFAULT; |
273 | return -1; | |
63b81f13 GS |
274 | } |
275 | return dirp->dd_stat; | |
276 | } | |
277 | ||
278 | /* | |
279 | * seekdir | |
280 | * | |
281 | * Seek to an entry previously returned by telldir. We rewind the directory | |
282 | * and call readdir repeatedly until either dd_stat is the position number | |
283 | * or -1 (off the end). This is not perfect, in that the directory may | |
284 | * have changed while we weren't looking. But that is probably the case with | |
285 | * any such system. | |
286 | */ | |
287 | void | |
288 | seekdir(DIR * dirp, long lPos) | |
289 | { | |
290 | errno = 0; | |
291 | ||
292 | if (!dirp) { | |
26ac0430 AJ |
293 | errno = EFAULT; |
294 | return; | |
63b81f13 GS |
295 | } |
296 | if (lPos < -1) { | |
26ac0430 AJ |
297 | /* Seeking to an invalid position. */ |
298 | errno = EINVAL; | |
299 | return; | |
63b81f13 | 300 | } else if (lPos == -1) { |
26ac0430 AJ |
301 | /* Seek past end. */ |
302 | if (dirp->dd_handle != -1) { | |
303 | _findclose(dirp->dd_handle); | |
304 | } | |
305 | dirp->dd_handle = -1; | |
306 | dirp->dd_stat = -1; | |
63b81f13 | 307 | } else { |
26ac0430 AJ |
308 | /* Rewind and read forward to the appropriate index. */ |
309 | rewinddir(dirp); | |
63b81f13 | 310 | |
26ac0430 | 311 | while ((dirp->dd_stat < lPos) && readdir(dirp)); |
63b81f13 GS |
312 | } |
313 | } | |
314 | #endif /* _SQUID_MSWIN_ */ |