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  */
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) {
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  */
138 struct dirent *
139 readdir(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  */
198 int
199 closedir(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  */
225 void
226 rewinddir(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  */
247 long
248 telldir(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  */
268 void
269 seekdir(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