]>
Commit | Line | Data |
---|---|---|
0545caaa | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors |
0545caaa AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
63b81f13 | 9 | /* |
63b81f13 GS |
10 | * Implement dirent-style opendir(), readdir(), closedir(), rewinddir(), |
11 | * seekdir() and telldir on Windows - Based on mingw-runtime package sources. | |
0545caaa AJ |
12 | */ |
13 | ||
14 | /* | |
63b81f13 GS |
15 | * Original file info follow: |
16 | * | |
17 | * dirent.c | |
18 | * This file has no copyright assigned and is placed in the Public Domain. | |
19 | * This file is a part of the mingw-runtime package. | |
20 | * No warranty is given; refer to the file DISCLAIMER within the package. | |
21 | * | |
26ac0430 | 22 | * Derived from DIRLIB.C by Matt J. Weinstein |
63b81f13 GS |
23 | * This note appears in the DIRLIB.H |
24 | * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 | |
25 | * | |
26 | * Updated by Jeremy Bettis <jeremy@hksys.com> | |
27 | * Significantly revised and rewinddir, seekdir and telldir added by Colin | |
28 | * Peters <colin@fu.is.saga-u.ac.jp> | |
26ac0430 | 29 | * |
63b81f13 GS |
30 | */ |
31 | ||
f7f3304a | 32 | #include "squid.h" |
63b81f13 GS |
33 | |
34 | /* The following code section is part of the native Windows Squid port */ | |
7aa9bb3e | 35 | #if _SQUID_WINDOWS_ |
75072239 AJ |
36 | |
37 | #include "util.h" | |
63b81f13 GS |
38 | #include <stdlib.h> |
39 | #include <errno.h> | |
40 | #include <string.h> | |
41 | #include <io.h> | |
42 | #include <dirent.h> | |
43 | ||
44 | #define WIN32_LEAN_AND_MEAN | |
f53969cc | 45 | #include <windows.h> /* for GetFileAttributes */ |
63b81f13 | 46 | |
f53969cc SM |
47 | #define SUFFIX ("*") |
48 | #define SLASH ("\\") | |
63b81f13 | 49 | |
63b81f13 GS |
50 | /* |
51 | * opendir | |
52 | * | |
53 | * Returns a pointer to a DIR structure appropriately filled in to begin | |
54 | * searching a directory. | |
55 | */ | |
56 | DIR * | |
57 | opendir(const CHAR * szPath) | |
58 | { | |
59 | DIR *nd; | |
60 | unsigned int rc; | |
61 | CHAR szFullPath[MAX_PATH]; | |
62 | ||
63 | errno = 0; | |
64 | ||
65 | if (!szPath) { | |
26ac0430 AJ |
66 | errno = EFAULT; |
67 | return (DIR *) 0; | |
63b81f13 GS |
68 | } |
69 | if (szPath[0] == '\0') { | |
26ac0430 AJ |
70 | errno = ENOTDIR; |
71 | return (DIR *) 0; | |
63b81f13 GS |
72 | } |
73 | /* Attempt to determine if the given path really is a directory. */ | |
74 | rc = GetFileAttributes(szPath); | |
75 | if (rc == (unsigned int) -1) { | |
26ac0430 AJ |
76 | /* call GetLastError for more error info */ |
77 | errno = ENOENT; | |
78 | return (DIR *) 0; | |
63b81f13 GS |
79 | } |
80 | if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) { | |
26ac0430 AJ |
81 | /* Error, entry exists but not a directory. */ |
82 | errno = ENOTDIR; | |
83 | return (DIR *) 0; | |
63b81f13 GS |
84 | } |
85 | /* Make an absolute pathname. */ | |
86 | _fullpath(szFullPath, szPath, MAX_PATH); | |
87 | ||
88 | /* Allocate enough space to store DIR structure and the complete | |
89 | * directory path given. */ | |
90 | nd = (DIR *) malloc(sizeof(DIR) + (strlen(szFullPath) | |
26ac0430 AJ |
91 | + strlen(SLASH) |
92 | + strlen(SUFFIX) + 1) | |
93 | * sizeof(CHAR)); | |
63b81f13 GS |
94 | |
95 | if (!nd) { | |
26ac0430 AJ |
96 | /* Error, out of memory. */ |
97 | errno = ENOMEM; | |
98 | return (DIR *) 0; | |
63b81f13 GS |
99 | } |
100 | /* Create the search expression. */ | |
101 | strcpy(nd->dd_name, szFullPath); | |
102 | ||
103 | /* Add on a slash if the path does not end with one. */ | |
104 | if (nd->dd_name[0] != '\0' | |
26ac0430 AJ |
105 | && strchr(nd->dd_name, '/') != nd->dd_name |
106 | + strlen(nd->dd_name) - 1 | |
107 | && strchr(nd->dd_name, '\\') != nd->dd_name | |
108 | + strlen(nd->dd_name) - 1) { | |
109 | strcat(nd->dd_name, SLASH); | |
63b81f13 GS |
110 | } |
111 | /* Add on the search pattern */ | |
112 | strcat(nd->dd_name, SUFFIX); | |
113 | ||
114 | /* Initialize handle to -1 so that a premature closedir doesn't try | |
115 | * to call _findclose on it. */ | |
116 | nd->dd_handle = -1; | |
117 | ||
118 | /* Initialize the status. */ | |
119 | nd->dd_stat = 0; | |
120 | ||
121 | /* Initialize the dirent structure. ino and reclen are invalid under | |
122 | * Win32, and name simply points at the appropriate part of the | |
123 | * findfirst_t structure. */ | |
124 | nd->dd_dir.d_ino = 0; | |
125 | nd->dd_dir.d_reclen = 0; | |
126 | nd->dd_dir.d_namlen = 0; | |
127 | memset(nd->dd_dir.d_name, 0, FILENAME_MAX); | |
128 | ||
129 | return nd; | |
130 | } | |
131 | ||
63b81f13 GS |
132 | /* |
133 | * readdir | |
134 | * | |
135 | * Return a pointer to a dirent structure filled with the information on the | |
136 | * next entry in the directory. | |
137 | */ | |
138 | struct dirent * | |
e1381638 | 139 | readdir(DIR * dirp) { |
63b81f13 GS |
140 | errno = 0; |
141 | ||
142 | /* Check for valid DIR struct. */ | |
143 | if (!dirp) { | |
26ac0430 AJ |
144 | errno = EFAULT; |
145 | return (struct dirent *) 0; | |
63b81f13 GS |
146 | } |
147 | if (dirp->dd_stat < 0) { | |
26ac0430 AJ |
148 | /* We have already returned all files in the directory |
149 | * (or the structure has an invalid dd_stat). */ | |
150 | return (struct dirent *) 0; | |
63b81f13 | 151 | } else if (dirp->dd_stat == 0) { |
26ac0430 AJ |
152 | /* We haven't started the search yet. */ |
153 | /* Start the search */ | |
154 | dirp->dd_handle = _findfirst(dirp->dd_name, &(dirp->dd_dta)); | |
155 | ||
156 | if (dirp->dd_handle == -1) { | |
157 | /* Whoops! Seems there are no files in that | |
158 | * directory. */ | |
159 | dirp->dd_stat = -1; | |
160 | } else { | |
161 | dirp->dd_stat = 1; | |
162 | } | |
63b81f13 | 163 | } else { |
26ac0430 AJ |
164 | /* Get the next search entry. */ |
165 | if (_findnext(dirp->dd_handle, &(dirp->dd_dta))) { | |
166 | /* We are off the end or otherwise error. | |
167 | * _findnext sets errno to ENOENT if no more file | |
168 | * Undo this. */ | |
169 | DWORD winerr = GetLastError(); | |
170 | if (winerr == ERROR_NO_MORE_FILES) | |
171 | errno = 0; | |
172 | _findclose(dirp->dd_handle); | |
173 | dirp->dd_handle = -1; | |
174 | dirp->dd_stat = -1; | |
175 | } else { | |
176 | /* Update the status to indicate the correct | |
177 | * number. */ | |
178 | dirp->dd_stat++; | |
179 | } | |
63b81f13 GS |
180 | } |
181 | ||
182 | if (dirp->dd_stat > 0) { | |
26ac0430 AJ |
183 | /* Successfully got an entry. Everything about the file is |
184 | * already appropriately filled in except the length of the | |
185 | * file name. */ | |
186 | dirp->dd_dir.d_namlen = strlen(dirp->dd_dta.name); | |
187 | strcpy(dirp->dd_dir.d_name, dirp->dd_dta.name); | |
188 | return &dirp->dd_dir; | |
63b81f13 GS |
189 | } |
190 | return (struct dirent *) 0; | |
191 | } | |
192 | ||
63b81f13 GS |
193 | /* |
194 | * closedir | |
195 | * | |
196 | * Frees up resources allocated by opendir. | |
197 | */ | |
198 | int | |
199 | closedir(DIR * dirp) | |
200 | { | |
201 | int rc; | |
202 | ||
203 | errno = 0; | |
204 | rc = 0; | |
205 | ||
206 | if (!dirp) { | |
26ac0430 AJ |
207 | errno = EFAULT; |
208 | return -1; | |
63b81f13 GS |
209 | } |
210 | if (dirp->dd_handle != -1) { | |
26ac0430 | 211 | rc = _findclose(dirp->dd_handle); |
63b81f13 GS |
212 | } |
213 | /* Delete the dir structure. */ | |
214 | free(dirp); | |
215 | ||
216 | return rc; | |
217 | } | |
218 | ||
219 | /* | |
220 | * rewinddir | |
221 | * | |
222 | * Return to the beginning of the directory "stream". We simply call findclose | |
223 | * and then reset things like an opendir. | |
224 | */ | |
225 | void | |
226 | rewinddir(DIR * dirp) | |
227 | { | |
228 | errno = 0; | |
229 | ||
230 | if (!dirp) { | |
26ac0430 AJ |
231 | errno = EFAULT; |
232 | return; | |
63b81f13 GS |
233 | } |
234 | if (dirp->dd_handle != -1) { | |
26ac0430 | 235 | _findclose(dirp->dd_handle); |
63b81f13 GS |
236 | } |
237 | dirp->dd_handle = -1; | |
238 | dirp->dd_stat = 0; | |
239 | } | |
240 | ||
241 | /* | |
242 | * telldir | |
243 | * | |
244 | * Returns the "position" in the "directory stream" which can be used with | |
245 | * seekdir to go back to an old entry. We simply return the value in stat. | |
246 | */ | |
247 | long | |
248 | telldir(DIR * dirp) | |
249 | { | |
250 | errno = 0; | |
251 | ||
252 | if (!dirp) { | |
26ac0430 AJ |
253 | errno = EFAULT; |
254 | return -1; | |
63b81f13 GS |
255 | } |
256 | return dirp->dd_stat; | |
257 | } | |
258 | ||
259 | /* | |
260 | * seekdir | |
261 | * | |
262 | * Seek to an entry previously returned by telldir. We rewind the directory | |
263 | * and call readdir repeatedly until either dd_stat is the position number | |
264 | * or -1 (off the end). This is not perfect, in that the directory may | |
265 | * have changed while we weren't looking. But that is probably the case with | |
266 | * any such system. | |
267 | */ | |
268 | void | |
269 | seekdir(DIR * dirp, long lPos) | |
270 | { | |
271 | errno = 0; | |
272 | ||
273 | if (!dirp) { | |
26ac0430 AJ |
274 | errno = EFAULT; |
275 | return; | |
63b81f13 GS |
276 | } |
277 | if (lPos < -1) { | |
26ac0430 AJ |
278 | /* Seeking to an invalid position. */ |
279 | errno = EINVAL; | |
280 | return; | |
63b81f13 | 281 | } else if (lPos == -1) { |
26ac0430 AJ |
282 | /* Seek past end. */ |
283 | if (dirp->dd_handle != -1) { | |
284 | _findclose(dirp->dd_handle); | |
285 | } | |
286 | dirp->dd_handle = -1; | |
287 | dirp->dd_stat = -1; | |
63b81f13 | 288 | } else { |
26ac0430 AJ |
289 | /* Rewind and read forward to the appropriate index. */ |
290 | rewinddir(dirp); | |
63b81f13 | 291 | |
26ac0430 | 292 | while ((dirp->dd_stat < lPos) && readdir(dirp)); |
63b81f13 GS |
293 | } |
294 | } | |
7aa9bb3e | 295 | #endif /* _SQUID_WINDOWS_ */ |
f53969cc | 296 |