]>
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 | ||
75072239 | 51 | #include "config.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 | ||
69 | ||
70 | /* | |
71 | * opendir | |
72 | * | |
73 | * Returns a pointer to a DIR structure appropriately filled in to begin | |
74 | * searching a directory. | |
75 | */ | |
76 | DIR * | |
77 | opendir(const CHAR * szPath) | |
78 | { | |
79 | DIR *nd; | |
80 | unsigned int rc; | |
81 | CHAR szFullPath[MAX_PATH]; | |
82 | ||
83 | errno = 0; | |
84 | ||
85 | if (!szPath) { | |
26ac0430 AJ |
86 | errno = EFAULT; |
87 | return (DIR *) 0; | |
63b81f13 GS |
88 | } |
89 | if (szPath[0] == '\0') { | |
26ac0430 AJ |
90 | errno = ENOTDIR; |
91 | return (DIR *) 0; | |
63b81f13 GS |
92 | } |
93 | /* Attempt to determine if the given path really is a directory. */ | |
94 | rc = GetFileAttributes(szPath); | |
95 | if (rc == (unsigned int) -1) { | |
26ac0430 AJ |
96 | /* call GetLastError for more error info */ |
97 | errno = ENOENT; | |
98 | return (DIR *) 0; | |
63b81f13 GS |
99 | } |
100 | if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) { | |
26ac0430 AJ |
101 | /* Error, entry exists but not a directory. */ |
102 | errno = ENOTDIR; | |
103 | return (DIR *) 0; | |
63b81f13 GS |
104 | } |
105 | /* Make an absolute pathname. */ | |
106 | _fullpath(szFullPath, szPath, MAX_PATH); | |
107 | ||
108 | /* Allocate enough space to store DIR structure and the complete | |
109 | * directory path given. */ | |
110 | nd = (DIR *) malloc(sizeof(DIR) + (strlen(szFullPath) | |
26ac0430 AJ |
111 | + strlen(SLASH) |
112 | + strlen(SUFFIX) + 1) | |
113 | * sizeof(CHAR)); | |
63b81f13 GS |
114 | |
115 | if (!nd) { | |
26ac0430 AJ |
116 | /* Error, out of memory. */ |
117 | errno = ENOMEM; | |
118 | return (DIR *) 0; | |
63b81f13 GS |
119 | } |
120 | /* Create the search expression. */ | |
121 | strcpy(nd->dd_name, szFullPath); | |
122 | ||
123 | /* Add on a slash if the path does not end with one. */ | |
124 | if (nd->dd_name[0] != '\0' | |
26ac0430 AJ |
125 | && strchr(nd->dd_name, '/') != nd->dd_name |
126 | + strlen(nd->dd_name) - 1 | |
127 | && strchr(nd->dd_name, '\\') != nd->dd_name | |
128 | + strlen(nd->dd_name) - 1) { | |
129 | strcat(nd->dd_name, SLASH); | |
63b81f13 GS |
130 | } |
131 | /* Add on the search pattern */ | |
132 | strcat(nd->dd_name, SUFFIX); | |
133 | ||
134 | /* Initialize handle to -1 so that a premature closedir doesn't try | |
135 | * to call _findclose on it. */ | |
136 | nd->dd_handle = -1; | |
137 | ||
138 | /* Initialize the status. */ | |
139 | nd->dd_stat = 0; | |
140 | ||
141 | /* Initialize the dirent structure. ino and reclen are invalid under | |
142 | * Win32, and name simply points at the appropriate part of the | |
143 | * findfirst_t structure. */ | |
144 | nd->dd_dir.d_ino = 0; | |
145 | nd->dd_dir.d_reclen = 0; | |
146 | nd->dd_dir.d_namlen = 0; | |
147 | memset(nd->dd_dir.d_name, 0, FILENAME_MAX); | |
148 | ||
149 | return nd; | |
150 | } | |
151 | ||
152 | ||
153 | /* | |
154 | * readdir | |
155 | * | |
156 | * Return a pointer to a dirent structure filled with the information on the | |
157 | * next entry in the directory. | |
158 | */ | |
159 | struct dirent * | |
e1381638 | 160 | readdir(DIR * dirp) { |
63b81f13 GS |
161 | errno = 0; |
162 | ||
163 | /* Check for valid DIR struct. */ | |
164 | if (!dirp) { | |
26ac0430 AJ |
165 | errno = EFAULT; |
166 | return (struct dirent *) 0; | |
63b81f13 GS |
167 | } |
168 | if (dirp->dd_stat < 0) { | |
26ac0430 AJ |
169 | /* We have already returned all files in the directory |
170 | * (or the structure has an invalid dd_stat). */ | |
171 | return (struct dirent *) 0; | |
63b81f13 | 172 | } else if (dirp->dd_stat == 0) { |
26ac0430 AJ |
173 | /* We haven't started the search yet. */ |
174 | /* Start the search */ | |
175 | dirp->dd_handle = _findfirst(dirp->dd_name, &(dirp->dd_dta)); | |
176 | ||
177 | if (dirp->dd_handle == -1) { | |
178 | /* Whoops! Seems there are no files in that | |
179 | * directory. */ | |
180 | dirp->dd_stat = -1; | |
181 | } else { | |
182 | dirp->dd_stat = 1; | |
183 | } | |
63b81f13 | 184 | } else { |
26ac0430 AJ |
185 | /* Get the next search entry. */ |
186 | if (_findnext(dirp->dd_handle, &(dirp->dd_dta))) { | |
187 | /* We are off the end or otherwise error. | |
188 | * _findnext sets errno to ENOENT if no more file | |
189 | * Undo this. */ | |
190 | DWORD winerr = GetLastError(); | |
191 | if (winerr == ERROR_NO_MORE_FILES) | |
192 | errno = 0; | |
193 | _findclose(dirp->dd_handle); | |
194 | dirp->dd_handle = -1; | |
195 | dirp->dd_stat = -1; | |
196 | } else { | |
197 | /* Update the status to indicate the correct | |
198 | * number. */ | |
199 | dirp->dd_stat++; | |
200 | } | |
63b81f13 GS |
201 | } |
202 | ||
203 | if (dirp->dd_stat > 0) { | |
26ac0430 AJ |
204 | /* Successfully got an entry. Everything about the file is |
205 | * already appropriately filled in except the length of the | |
206 | * file name. */ | |
207 | dirp->dd_dir.d_namlen = strlen(dirp->dd_dta.name); | |
208 | strcpy(dirp->dd_dir.d_name, dirp->dd_dta.name); | |
209 | return &dirp->dd_dir; | |
63b81f13 GS |
210 | } |
211 | return (struct dirent *) 0; | |
212 | } | |
213 | ||
214 | ||
215 | /* | |
216 | * closedir | |
217 | * | |
218 | * Frees up resources allocated by opendir. | |
219 | */ | |
220 | int | |
221 | closedir(DIR * dirp) | |
222 | { | |
223 | int rc; | |
224 | ||
225 | errno = 0; | |
226 | rc = 0; | |
227 | ||
228 | if (!dirp) { | |
26ac0430 AJ |
229 | errno = EFAULT; |
230 | return -1; | |
63b81f13 GS |
231 | } |
232 | if (dirp->dd_handle != -1) { | |
26ac0430 | 233 | rc = _findclose(dirp->dd_handle); |
63b81f13 GS |
234 | } |
235 | /* Delete the dir structure. */ | |
236 | free(dirp); | |
237 | ||
238 | return rc; | |
239 | } | |
240 | ||
241 | /* | |
242 | * rewinddir | |
243 | * | |
244 | * Return to the beginning of the directory "stream". We simply call findclose | |
245 | * and then reset things like an opendir. | |
246 | */ | |
247 | void | |
248 | rewinddir(DIR * dirp) | |
249 | { | |
250 | errno = 0; | |
251 | ||
252 | if (!dirp) { | |
26ac0430 AJ |
253 | errno = EFAULT; |
254 | return; | |
63b81f13 GS |
255 | } |
256 | if (dirp->dd_handle != -1) { | |
26ac0430 | 257 | _findclose(dirp->dd_handle); |
63b81f13 GS |
258 | } |
259 | dirp->dd_handle = -1; | |
260 | dirp->dd_stat = 0; | |
261 | } | |
262 | ||
263 | /* | |
264 | * telldir | |
265 | * | |
266 | * Returns the "position" in the "directory stream" which can be used with | |
267 | * seekdir to go back to an old entry. We simply return the value in stat. | |
268 | */ | |
269 | long | |
270 | telldir(DIR * dirp) | |
271 | { | |
272 | errno = 0; | |
273 | ||
274 | if (!dirp) { | |
26ac0430 AJ |
275 | errno = EFAULT; |
276 | return -1; | |
63b81f13 GS |
277 | } |
278 | return dirp->dd_stat; | |
279 | } | |
280 | ||
281 | /* | |
282 | * seekdir | |
283 | * | |
284 | * Seek to an entry previously returned by telldir. We rewind the directory | |
285 | * and call readdir repeatedly until either dd_stat is the position number | |
286 | * or -1 (off the end). This is not perfect, in that the directory may | |
287 | * have changed while we weren't looking. But that is probably the case with | |
288 | * any such system. | |
289 | */ | |
290 | void | |
291 | seekdir(DIR * dirp, long lPos) | |
292 | { | |
293 | errno = 0; | |
294 | ||
295 | if (!dirp) { | |
26ac0430 AJ |
296 | errno = EFAULT; |
297 | return; | |
63b81f13 GS |
298 | } |
299 | if (lPos < -1) { | |
26ac0430 AJ |
300 | /* Seeking to an invalid position. */ |
301 | errno = EINVAL; | |
302 | return; | |
63b81f13 | 303 | } else if (lPos == -1) { |
26ac0430 AJ |
304 | /* Seek past end. */ |
305 | if (dirp->dd_handle != -1) { | |
306 | _findclose(dirp->dd_handle); | |
307 | } | |
308 | dirp->dd_handle = -1; | |
309 | dirp->dd_stat = -1; | |
63b81f13 | 310 | } else { |
26ac0430 AJ |
311 | /* Rewind and read forward to the appropriate index. */ |
312 | rewinddir(dirp); | |
63b81f13 | 313 | |
26ac0430 | 314 | while ((dirp->dd_stat < lPos) && readdir(dirp)); |
63b81f13 GS |
315 | } |
316 | } | |
317 | #endif /* _SQUID_MSWIN_ */ |