dirent.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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
9/*
10 * Implement dirent-style opendir(), readdir(), closedir(), rewinddir(),
11 * seekdir() and telldir on Windows - Based on mingw-runtime package sources.
12 */
13
14/*
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 *
22 * Derived from DIRLIB.C by Matt J. Weinstein
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>
29 *
30 */
31
32#include "squid.h"
33
34/* The following code section is part of the native Windows Squid port */
35#if _SQUID_WINDOWS_
36
37#include "util.h"
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
45#include <windows.h> /* for GetFileAttributes */
46
47#define SUFFIX ("*")
48#define SLASH ("\\")
49
50/*
51 * opendir
52 *
53 * Returns a pointer to a DIR structure appropriately filled in to begin
54 * searching a directory.
55 */
56DIR *
57opendir(const CHAR * szPath)
58{
59 DIR *nd;
60 unsigned int rc;
61 CHAR szFullPath[MAX_PATH];
62
63 errno = 0;
64
65 if (!szPath) {
66 errno = EFAULT;
67 return (DIR *) 0;
68 }
69 if (szPath[0] == '\0') {
70 errno = ENOTDIR;
71 return (DIR *) 0;
72 }
73 /* Attempt to determine if the given path really is a directory. */
74 rc = GetFileAttributes(szPath);
75 if (rc == (unsigned int) -1) {
76 /* call GetLastError for more error info */
77 errno = ENOENT;
78 return (DIR *) 0;
79 }
80 if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) {
81 /* Error, entry exists but not a directory. */
82 errno = ENOTDIR;
83 return (DIR *) 0;
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)
91 + strlen(SLASH)
92 + strlen(SUFFIX) + 1)
93 * sizeof(CHAR));
94
95 if (!nd) {
96 /* Error, out of memory. */
97 errno = ENOMEM;
98 return (DIR *) 0;
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'
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);
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
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 */
138struct dirent *
139readdir(DIR * dirp) {
140 errno = 0;
141
142 /* Check for valid DIR struct. */
143 if (!dirp) {
144 errno = EFAULT;
145 return (struct dirent *) 0;
146 }
147 if (dirp->dd_stat < 0) {
148 /* We have already returned all files in the directory
149 * (or the structure has an invalid dd_stat). */
150 return (struct dirent *) 0;
151 } else if (dirp->dd_stat == 0) {
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 }
163 } else {
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 }
180 }
181
182 if (dirp->dd_stat > 0) {
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;
189 }
190 return (struct dirent *) 0;
191}
192
193/*
194 * closedir
195 *
196 * Frees up resources allocated by opendir.
197 */
198int
199closedir(DIR * dirp)
200{
201 int rc;
202
203 errno = 0;
204 rc = 0;
205
206 if (!dirp) {
207 errno = EFAULT;
208 return -1;
209 }
210 if (dirp->dd_handle != -1) {
211 rc = _findclose(dirp->dd_handle);
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 */
225void
226rewinddir(DIR * dirp)
227{
228 errno = 0;
229
230 if (!dirp) {
231 errno = EFAULT;
232 return;
233 }
234 if (dirp->dd_handle != -1) {
235 _findclose(dirp->dd_handle);
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 */
247long
248telldir(DIR * dirp)
249{
250 errno = 0;
251
252 if (!dirp) {
253 errno = EFAULT;
254 return -1;
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 */
268void
269seekdir(DIR * dirp, long lPos)
270{
271 errno = 0;
272
273 if (!dirp) {
274 errno = EFAULT;
275 return;
276 }
277 if (lPos < -1) {
278 /* Seeking to an invalid position. */
279 errno = EINVAL;
280 return;
281 } else if (lPos == -1) {
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;
288 } else {
289 /* Rewind and read forward to the appropriate index. */
290 rewinddir(dirp);
291
292 while ((dirp->dd_stat < lPos) && readdir(dirp));
293 }
294}
295#endif /* _SQUID_WINDOWS_ */
296

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors