Fossil SCM

upgrade to dirent-1.11

jan.nijtmans 2012-08-29 21:32 UTC trunk
Commit 10fec4b7ddd57a96bf0a874e0fec0886b650b8a1
1 file changed +213 -71
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -20,10 +20,28 @@
2020
* IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
2121
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2222
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2323
* OTHER DEALINGS IN THE SOFTWARE.
2424
*
25
+ * Mar 15, 2011, Toni Ronkko
26
+ * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
27
+ *
28
+ * Aug 11, 2010, Toni Ronkko
29
+ * Added d_type and d_namlen fields to dirent structure. The former is
30
+ * especially useful for determining whether directory entry represents a
31
+ * file or a directory. For more information, see
32
+ * http://www.delorie.com/gnu/docs/glibc/libc_270.html
33
+ *
34
+ * Aug 11, 2010, Toni Ronkko
35
+ * Improved conformance to the standards. For example, errno is now set
36
+ * properly on failure and assert() is never used. Thanks to Peter Brockam
37
+ * for suggestions.
38
+ *
39
+ * Aug 11, 2010, Toni Ronkko
40
+ * Fixed a bug in rewinddir(): when using relative directory names, change
41
+ * of working directory no longer causes rewinddir() to fail.
42
+ *
2543
* Dec 15, 2009, John Cunningham
2644
* Added rewinddir member function
2745
*
2846
* Jan 18, 2008, Toni Ronkko
2947
* Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
@@ -56,43 +74,122 @@
5674
* First version.
5775
*****************************************************************************/
5876
#ifndef DIRENT_H
5977
#define DIRENT_H
6078
79
+#define WIN32_LEAN_AND_MEAN
6180
#include <windows.h>
6281
#include <string.h>
63
-#include <assert.h>
82
+#include <stdlib.h>
83
+#include <sys/types.h>
84
+#include <sys/stat.h>
85
+#include <errno.h>
86
+
87
+/* Entries missing from MSVC 6.0 */
88
+#if !defined(FILE_ATTRIBUTE_DEVICE)
89
+# define FILE_ATTRIBUTE_DEVICE 0x40
90
+#endif
91
+
92
+/* File type and permission flags for stat() */
93
+#if defined(_MSC_VER) && !defined(S_IREAD)
94
+# define S_IFMT _S_IFMT /* file type mask */
95
+# define S_IFDIR _S_IFDIR /* directory */
96
+# define S_IFCHR _S_IFCHR /* character device */
97
+# define S_IFFIFO _S_IFFIFO /* pipe */
98
+# define S_IFREG _S_IFREG /* regular file */
99
+# define S_IREAD _S_IREAD /* read permission */
100
+# define S_IWRITE _S_IWRITE /* write permission */
101
+# define S_IEXEC _S_IEXEC /* execute permission */
102
+#endif
103
+#define S_IFBLK 0 /* block device */
104
+#define S_IFLNK 0 /* link */
105
+#define S_IFSOCK 0 /* socket */
106
+
107
+#if defined(_MSC_VER)
108
+# define S_IRUSR S_IREAD /* read, user */
109
+# define S_IWUSR S_IWRITE /* write, user */
110
+# define S_IXUSR 0 /* execute, user */
111
+# define S_IRGRP 0 /* read, group */
112
+# define S_IWGRP 0 /* write, group */
113
+# define S_IXGRP 0 /* execute, group */
114
+# define S_IROTH 0 /* read, others */
115
+# define S_IWOTH 0 /* write, others */
116
+# define S_IXOTH 0 /* execute, others */
117
+#endif
118
+
119
+/* Indicates that d_type field is available in dirent structure */
120
+#define _DIRENT_HAVE_D_TYPE
121
+
122
+/* File type flags for d_type */
123
+#define DT_UNKNOWN 0
124
+#define DT_REG S_IFREG
125
+#define DT_DIR S_IFDIR
126
+#define DT_FIFO S_IFFIFO
127
+#define DT_SOCK S_IFSOCK
128
+#define DT_CHR S_IFCHR
129
+#define DT_BLK S_IFBLK
130
+
131
+/* Macros for converting between st_mode and d_type */
132
+#define IFTODT(mode) ((mode) & S_IFMT)
133
+#define DTTOIF(type) (type)
134
+
135
+/*
136
+ * File type macros. Note that block devices, sockets and links cannot be
137
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
138
+ * only defined for compatibility. These macros should always return false
139
+ * on Windows.
140
+ */
141
+#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
142
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
143
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
144
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
145
+#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
146
+#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
147
+#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
148
+
149
+#ifdef __cplusplus
150
+extern "C" {
151
+#endif
64152
65153
66154
typedef struct dirent
67155
{
68
- char d_name[MAX_PATH + 1]; /* current dir entry (multi-byte char string) */
69
- WIN32_FIND_DATAA data; /* file attributes */
70
-} dirent;
156
+ char d_name[MAX_PATH + 1]; /* File name */
157
+ size_t d_namlen; /* Length of name without \0 */
158
+ int d_type; /* File type */
159
+} dirent;
71160
72161
73162
typedef struct DIR
74163
{
75
- dirent current; /* Current directory entry */
76
- int cached; /* Indicates un-processed entry in memory */
77
- HANDLE search_handle; /* File search handle */
78
- char patt[MAX_PATH + 3]; /* search pattern (3 = pattern + "\\*\0") */
164
+ dirent curentry; /* Current directory entry */
165
+ WIN32_FIND_DATAA find_data; /* Private file data */
166
+ int cached; /* True if data is valid */
167
+ HANDLE search_handle; /* Win32 search handle */
168
+ char patt[MAX_PATH + 3]; /* Initial directory name */
79169
} DIR;
80170
81171
82172
/* Forward declarations */
83
-static DIR *opendir (const char *dirname);
84
-static struct dirent *readdir (DIR *dirp);
85
-static int closedir (DIR *dirp);
173
+static DIR *opendir(const char *dirname);
174
+static struct dirent *readdir(DIR *dirp);
175
+static int closedir(DIR *dirp);
86176
static void rewinddir(DIR* dirp);
87177
88178
89179
/* Use the new safe string functions introduced in Visual Studio 2005 */
90180
#if defined(_MSC_VER) && _MSC_VER >= 1400
91
-# define STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
181
+# define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
182
+#else
183
+# define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size))
184
+#endif
185
+
186
+/* Set errno variable */
187
+#if defined(_MSC_VER)
188
+#define DIRENT_SET_ERRNO(x) _set_errno (x)
92189
#else
93
-# define STRNCPY(dest,src,size) strncpy((dest),(src),(size))
190
+#define DIRENT_SET_ERRNO(x) (errno = (x))
94191
#endif
95192
96193
97194
/*****************************************************************************
98195
* Open directory stream DIRNAME for read and return a pointer to the
@@ -100,40 +197,63 @@
100197
* entries.
101198
*/
102199
static DIR *opendir(const char *dirname)
103200
{
104201
DIR *dirp;
105
- assert (dirname != NULL);
106
- assert (strlen (dirname) < MAX_PATH);
202
+
203
+ /* ensure that the resulting search pattern will be a valid file name */
204
+ if (dirname == NULL) {
205
+ DIRENT_SET_ERRNO (ENOENT);
206
+ return NULL;
207
+ }
208
+ if (strlen (dirname) + 3 >= MAX_PATH) {
209
+ DIRENT_SET_ERRNO (ENAMETOOLONG);
210
+ return NULL;
211
+ }
107212
108213
/* construct new DIR structure */
109214
dirp = (DIR*) malloc (sizeof (struct DIR));
110215
if (dirp != NULL) {
111
- char *p;
112
-
113
- /* take directory name... */
114
- STRNCPY (dirp->patt, dirname, sizeof(dirp->patt));
115
- dirp->patt[MAX_PATH] = '\0';
116
-
117
- /* ... and append search pattern to it */
118
- p = strchr (dirp->patt, '\0');
119
- if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
120
- *p++ = '\\';
121
- }
122
- *p++ = '*';
123
- *p = '\0';
124
-
125
- /* open stream and retrieve first file */
126
- dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data);
127
- if (dirp->search_handle == INVALID_HANDLE_VALUE) {
128
- /* invalid search pattern? */
129
- free (dirp);
130
- return NULL;
131
- }
132
-
133
- /* there is an un-processed directory entry in memory now */
134
- dirp->cached = 1;
216
+ int error;
217
+
218
+ /*
219
+ * Convert relative directory name to an absolute one. This
220
+ * allows rewinddir() to function correctly when the current working
221
+ * directory is changed between opendir() and rewinddir().
222
+ */
223
+ if (GetFullPathNameA (dirname, MAX_PATH, dirp->patt, NULL)) {
224
+ char *p;
225
+
226
+ /* append the search pattern "\\*\0" to the directory name */
227
+ p = strchr (dirp->patt, '\0');
228
+ if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
229
+ *p++ = '\\';
230
+ }
231
+ *p++ = '*';
232
+ *p = '\0';
233
+
234
+ /* open directory stream and retrieve the first entry */
235
+ dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
236
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
237
+ /* a directory entry is now waiting in memory */
238
+ dirp->cached = 1;
239
+ error = 0;
240
+ } else {
241
+ /* search pattern is not a directory name? */
242
+ DIRENT_SET_ERRNO (ENOENT);
243
+ error = 1;
244
+ }
245
+ } else {
246
+ /* buffer too small */
247
+ DIRENT_SET_ERRNO (ENOMEM);
248
+ error = 1;
249
+ }
250
+
251
+ if (error) {
252
+ free (dirp);
253
+ dirp = NULL;
254
+ }
135255
}
136256
137257
return dirp;
138258
}
139259
@@ -145,38 +265,53 @@
145265
* sub-directories, pseudo-directories "." and "..", but also volume labels,
146266
* hidden files and system files may be returned.
147267
*/
148268
static struct dirent *readdir(DIR *dirp)
149269
{
150
- assert (dirp != NULL);
151
-
152
- if (dirp->search_handle == INVALID_HANDLE_VALUE) {
153
- /* directory stream was opened/rewound incorrectly or ended normally */
270
+ DWORD attr;
271
+ if (dirp == NULL) {
272
+ /* directory stream did not open */
273
+ DIRENT_SET_ERRNO (EBADF);
154274
return NULL;
155275
}
156276
157277
/* get next directory entry */
158278
if (dirp->cached != 0) {
159279
/* a valid directory entry already in memory */
160280
dirp->cached = 0;
161281
} else {
162
- /* read next directory entry from disk */
163
- if (FindNextFileA (dirp->search_handle, &dirp->current.data) == FALSE) {
164
- /* the very last file has been processed or an error occured */
282
+ /* get the next directory entry from stream */
283
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
284
+ return NULL;
285
+ }
286
+ if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) {
287
+ /* the very last entry has been processed or an error occured */
165288
FindClose (dirp->search_handle);
166289
dirp->search_handle = INVALID_HANDLE_VALUE;
167290
return NULL;
168291
}
169292
}
170293
171294
/* copy as a multibyte character string */
172
- STRNCPY ( dirp->current.d_name,
173
- dirp->current.data.cFileName,
174
- sizeof(dirp->current.d_name) );
175
- dirp->current.d_name[MAX_PATH] = '\0';
295
+ DIRENT_STRNCPY ( dirp->curentry.d_name,
296
+ dirp->find_data.cFileName,
297
+ sizeof(dirp->curentry.d_name) );
298
+ dirp->curentry.d_name[MAX_PATH] = '\0';
299
+
300
+ /* compute the length of name */
301
+ dirp->curentry.d_namlen = strlen (dirp->curentry.d_name);
176302
177
- return &dirp->current;
303
+ /* determine file type */
304
+ attr = dirp->find_data.dwFileAttributes;
305
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
306
+ dirp->curentry.d_type = DT_CHR;
307
+ } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
308
+ dirp->curentry.d_type = DT_DIR;
309
+ } else {
310
+ dirp->curentry.d_type = DT_REG;
311
+ }
312
+ return &dirp->curentry;
178313
}
179314
180315
181316
/*****************************************************************************
182317
* Close directory stream opened by opendir() function. Close of the
@@ -183,48 +318,55 @@
183318
* directory stream invalidates the DIR structure as well as any previously
184319
* read directory entry.
185320
*/
186321
static int closedir(DIR *dirp)
187322
{
188
- assert (dirp != NULL);
323
+ if (dirp == NULL) {
324
+ /* invalid directory stream */
325
+ DIRENT_SET_ERRNO (EBADF);
326
+ return -1;
327
+ }
189328
190329
/* release search handle */
191330
if (dirp->search_handle != INVALID_HANDLE_VALUE) {
192331
FindClose (dirp->search_handle);
193332
dirp->search_handle = INVALID_HANDLE_VALUE;
194333
}
195334
196
- /* release directory handle */
335
+ /* release directory structure */
197336
free (dirp);
198337
return 0;
199338
}
200339
201340
202341
/*****************************************************************************
203342
* Resets the position of the directory stream to which dirp refers to the
204
- * beginning of the directory. It also causes the directory stream to refer
343
+ * beginning of the directory. It also causes the directory stream to refer
205344
* to the current state of the corresponding directory, as a call to opendir()
206
- * would have done. If dirp does not refer to a directory stream, the effect
345
+ * would have done. If dirp does not refer to a directory stream, the effect
207346
* is undefined.
208347
*/
209348
static void rewinddir(DIR* dirp)
210349
{
211
- /* release search handle */
212
- if (dirp->search_handle != INVALID_HANDLE_VALUE) {
213
- FindClose (dirp->search_handle);
214
- dirp->search_handle = INVALID_HANDLE_VALUE;
215
- }
216
-
217
- /* open new search handle and retrieve first file */
218
- dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data);
219
- if (dirp->search_handle == INVALID_HANDLE_VALUE) {
220
- /* invalid search pattern? */
221
- free (dirp);
222
- return;
223
- }
224
-
225
- /* there is an un-processed directory entry in memory now */
226
- dirp->cached = 1;
350
+ if (dirp != NULL) {
351
+ /* release search handle */
352
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
353
+ FindClose (dirp->search_handle);
354
+ }
355
+
356
+ /* open new search handle and retrieve the first entry */
357
+ dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
358
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
359
+ /* a directory entry is now waiting in memory */
360
+ dirp->cached = 1;
361
+ } else {
362
+ /* failed to re-open directory: no directory entry in memory */
363
+ dirp->cached = 0;
364
+ }
365
+ }
227366
}
228367
229368
369
+#ifdef __cplusplus
370
+}
371
+#endif
230372
#endif /*DIRENT_H*/
231373
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -20,10 +20,28 @@
20 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25 * Dec 15, 2009, John Cunningham
26 * Added rewinddir member function
27 *
28 * Jan 18, 2008, Toni Ronkko
29 * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
@@ -56,43 +74,122 @@
56 * First version.
57 *****************************************************************************/
58 #ifndef DIRENT_H
59 #define DIRENT_H
60
 
61 #include <windows.h>
62 #include <string.h>
63 #include <assert.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
65
66 typedef struct dirent
67 {
68 char d_name[MAX_PATH + 1]; /* current dir entry (multi-byte char string) */
69 WIN32_FIND_DATAA data; /* file attributes */
70 } dirent;
 
71
72
73 typedef struct DIR
74 {
75 dirent current; /* Current directory entry */
76 int cached; /* Indicates un-processed entry in memory */
77 HANDLE search_handle; /* File search handle */
78 char patt[MAX_PATH + 3]; /* search pattern (3 = pattern + "\\*\0") */
 
79 } DIR;
80
81
82 /* Forward declarations */
83 static DIR *opendir (const char *dirname);
84 static struct dirent *readdir (DIR *dirp);
85 static int closedir (DIR *dirp);
86 static void rewinddir(DIR* dirp);
87
88
89 /* Use the new safe string functions introduced in Visual Studio 2005 */
90 #if defined(_MSC_VER) && _MSC_VER >= 1400
91 # define STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
 
 
 
 
 
 
 
92 #else
93 # define STRNCPY(dest,src,size) strncpy((dest),(src),(size))
94 #endif
95
96
97 /*****************************************************************************
98 * Open directory stream DIRNAME for read and return a pointer to the
@@ -100,40 +197,63 @@
100 * entries.
101 */
102 static DIR *opendir(const char *dirname)
103 {
104 DIR *dirp;
105 assert (dirname != NULL);
106 assert (strlen (dirname) < MAX_PATH);
 
 
 
 
 
 
 
 
107
108 /* construct new DIR structure */
109 dirp = (DIR*) malloc (sizeof (struct DIR));
110 if (dirp != NULL) {
111 char *p;
112
113 /* take directory name... */
114 STRNCPY (dirp->patt, dirname, sizeof(dirp->patt));
115 dirp->patt[MAX_PATH] = '\0';
116
117 /* ... and append search pattern to it */
118 p = strchr (dirp->patt, '\0');
119 if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
120 *p++ = '\\';
121 }
122 *p++ = '*';
123 *p = '\0';
124
125 /* open stream and retrieve first file */
126 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data);
127 if (dirp->search_handle == INVALID_HANDLE_VALUE) {
128 /* invalid search pattern? */
129 free (dirp);
130 return NULL;
131 }
132
133 /* there is an un-processed directory entry in memory now */
134 dirp->cached = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135 }
136
137 return dirp;
138 }
139
@@ -145,38 +265,53 @@
145 * sub-directories, pseudo-directories "." and "..", but also volume labels,
146 * hidden files and system files may be returned.
147 */
148 static struct dirent *readdir(DIR *dirp)
149 {
150 assert (dirp != NULL);
151
152 if (dirp->search_handle == INVALID_HANDLE_VALUE) {
153 /* directory stream was opened/rewound incorrectly or ended normally */
154 return NULL;
155 }
156
157 /* get next directory entry */
158 if (dirp->cached != 0) {
159 /* a valid directory entry already in memory */
160 dirp->cached = 0;
161 } else {
162 /* read next directory entry from disk */
163 if (FindNextFileA (dirp->search_handle, &dirp->current.data) == FALSE) {
164 /* the very last file has been processed or an error occured */
 
 
 
165 FindClose (dirp->search_handle);
166 dirp->search_handle = INVALID_HANDLE_VALUE;
167 return NULL;
168 }
169 }
170
171 /* copy as a multibyte character string */
172 STRNCPY ( dirp->current.d_name,
173 dirp->current.data.cFileName,
174 sizeof(dirp->current.d_name) );
175 dirp->current.d_name[MAX_PATH] = '\0';
 
 
 
176
177 return &dirp->current;
 
 
 
 
 
 
 
 
 
178 }
179
180
181 /*****************************************************************************
182 * Close directory stream opened by opendir() function. Close of the
@@ -183,48 +318,55 @@
183 * directory stream invalidates the DIR structure as well as any previously
184 * read directory entry.
185 */
186 static int closedir(DIR *dirp)
187 {
188 assert (dirp != NULL);
 
 
 
 
189
190 /* release search handle */
191 if (dirp->search_handle != INVALID_HANDLE_VALUE) {
192 FindClose (dirp->search_handle);
193 dirp->search_handle = INVALID_HANDLE_VALUE;
194 }
195
196 /* release directory handle */
197 free (dirp);
198 return 0;
199 }
200
201
202 /*****************************************************************************
203 * Resets the position of the directory stream to which dirp refers to the
204 * beginning of the directory. It also causes the directory stream to refer
205 * to the current state of the corresponding directory, as a call to opendir()
206 * would have done. If dirp does not refer to a directory stream, the effect
207 * is undefined.
208 */
209 static void rewinddir(DIR* dirp)
210 {
211 /* release search handle */
212 if (dirp->search_handle != INVALID_HANDLE_VALUE) {
213 FindClose (dirp->search_handle);
214 dirp->search_handle = INVALID_HANDLE_VALUE;
215 }
216
217 /* open new search handle and retrieve first file */
218 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data);
219 if (dirp->search_handle == INVALID_HANDLE_VALUE) {
220 /* invalid search pattern? */
221 free (dirp);
222 return;
223 }
224
225 /* there is an un-processed directory entry in memory now */
226 dirp->cached = 1;
227 }
228
229
 
 
 
230 #endif /*DIRENT_H*/
231
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -20,10 +20,28 @@
20 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Mar 15, 2011, Toni Ronkko
26 * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
27 *
28 * Aug 11, 2010, Toni Ronkko
29 * Added d_type and d_namlen fields to dirent structure. The former is
30 * especially useful for determining whether directory entry represents a
31 * file or a directory. For more information, see
32 * http://www.delorie.com/gnu/docs/glibc/libc_270.html
33 *
34 * Aug 11, 2010, Toni Ronkko
35 * Improved conformance to the standards. For example, errno is now set
36 * properly on failure and assert() is never used. Thanks to Peter Brockam
37 * for suggestions.
38 *
39 * Aug 11, 2010, Toni Ronkko
40 * Fixed a bug in rewinddir(): when using relative directory names, change
41 * of working directory no longer causes rewinddir() to fail.
42 *
43 * Dec 15, 2009, John Cunningham
44 * Added rewinddir member function
45 *
46 * Jan 18, 2008, Toni Ronkko
47 * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
@@ -56,43 +74,122 @@
74 * First version.
75 *****************************************************************************/
76 #ifndef DIRENT_H
77 #define DIRENT_H
78
79 #define WIN32_LEAN_AND_MEAN
80 #include <windows.h>
81 #include <string.h>
82 #include <stdlib.h>
83 #include <sys/types.h>
84 #include <sys/stat.h>
85 #include <errno.h>
86
87 /* Entries missing from MSVC 6.0 */
88 #if !defined(FILE_ATTRIBUTE_DEVICE)
89 # define FILE_ATTRIBUTE_DEVICE 0x40
90 #endif
91
92 /* File type and permission flags for stat() */
93 #if defined(_MSC_VER) && !defined(S_IREAD)
94 # define S_IFMT _S_IFMT /* file type mask */
95 # define S_IFDIR _S_IFDIR /* directory */
96 # define S_IFCHR _S_IFCHR /* character device */
97 # define S_IFFIFO _S_IFFIFO /* pipe */
98 # define S_IFREG _S_IFREG /* regular file */
99 # define S_IREAD _S_IREAD /* read permission */
100 # define S_IWRITE _S_IWRITE /* write permission */
101 # define S_IEXEC _S_IEXEC /* execute permission */
102 #endif
103 #define S_IFBLK 0 /* block device */
104 #define S_IFLNK 0 /* link */
105 #define S_IFSOCK 0 /* socket */
106
107 #if defined(_MSC_VER)
108 # define S_IRUSR S_IREAD /* read, user */
109 # define S_IWUSR S_IWRITE /* write, user */
110 # define S_IXUSR 0 /* execute, user */
111 # define S_IRGRP 0 /* read, group */
112 # define S_IWGRP 0 /* write, group */
113 # define S_IXGRP 0 /* execute, group */
114 # define S_IROTH 0 /* read, others */
115 # define S_IWOTH 0 /* write, others */
116 # define S_IXOTH 0 /* execute, others */
117 #endif
118
119 /* Indicates that d_type field is available in dirent structure */
120 #define _DIRENT_HAVE_D_TYPE
121
122 /* File type flags for d_type */
123 #define DT_UNKNOWN 0
124 #define DT_REG S_IFREG
125 #define DT_DIR S_IFDIR
126 #define DT_FIFO S_IFFIFO
127 #define DT_SOCK S_IFSOCK
128 #define DT_CHR S_IFCHR
129 #define DT_BLK S_IFBLK
130
131 /* Macros for converting between st_mode and d_type */
132 #define IFTODT(mode) ((mode) & S_IFMT)
133 #define DTTOIF(type) (type)
134
135 /*
136 * File type macros. Note that block devices, sockets and links cannot be
137 * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
138 * only defined for compatibility. These macros should always return false
139 * on Windows.
140 */
141 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
142 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
143 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
144 #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
145 #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
146 #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
147 #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
148
149 #ifdef __cplusplus
150 extern "C" {
151 #endif
152
153
154 typedef struct dirent
155 {
156 char d_name[MAX_PATH + 1]; /* File name */
157 size_t d_namlen; /* Length of name without \0 */
158 int d_type; /* File type */
159 } dirent;
160
161
162 typedef struct DIR
163 {
164 dirent curentry; /* Current directory entry */
165 WIN32_FIND_DATAA find_data; /* Private file data */
166 int cached; /* True if data is valid */
167 HANDLE search_handle; /* Win32 search handle */
168 char patt[MAX_PATH + 3]; /* Initial directory name */
169 } DIR;
170
171
172 /* Forward declarations */
173 static DIR *opendir(const char *dirname);
174 static struct dirent *readdir(DIR *dirp);
175 static int closedir(DIR *dirp);
176 static void rewinddir(DIR* dirp);
177
178
179 /* Use the new safe string functions introduced in Visual Studio 2005 */
180 #if defined(_MSC_VER) && _MSC_VER >= 1400
181 # define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
182 #else
183 # define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size))
184 #endif
185
186 /* Set errno variable */
187 #if defined(_MSC_VER)
188 #define DIRENT_SET_ERRNO(x) _set_errno (x)
189 #else
190 #define DIRENT_SET_ERRNO(x) (errno = (x))
191 #endif
192
193
194 /*****************************************************************************
195 * Open directory stream DIRNAME for read and return a pointer to the
@@ -100,40 +197,63 @@
197 * entries.
198 */
199 static DIR *opendir(const char *dirname)
200 {
201 DIR *dirp;
202
203 /* ensure that the resulting search pattern will be a valid file name */
204 if (dirname == NULL) {
205 DIRENT_SET_ERRNO (ENOENT);
206 return NULL;
207 }
208 if (strlen (dirname) + 3 >= MAX_PATH) {
209 DIRENT_SET_ERRNO (ENAMETOOLONG);
210 return NULL;
211 }
212
213 /* construct new DIR structure */
214 dirp = (DIR*) malloc (sizeof (struct DIR));
215 if (dirp != NULL) {
216 int error;
217
218 /*
219 * Convert relative directory name to an absolute one. This
220 * allows rewinddir() to function correctly when the current working
221 * directory is changed between opendir() and rewinddir().
222 */
223 if (GetFullPathNameA (dirname, MAX_PATH, dirp->patt, NULL)) {
224 char *p;
225
226 /* append the search pattern "\\*\0" to the directory name */
227 p = strchr (dirp->patt, '\0');
228 if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
229 *p++ = '\\';
230 }
231 *p++ = '*';
232 *p = '\0';
233
234 /* open directory stream and retrieve the first entry */
235 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
236 if (dirp->search_handle != INVALID_HANDLE_VALUE) {
237 /* a directory entry is now waiting in memory */
238 dirp->cached = 1;
239 error = 0;
240 } else {
241 /* search pattern is not a directory name? */
242 DIRENT_SET_ERRNO (ENOENT);
243 error = 1;
244 }
245 } else {
246 /* buffer too small */
247 DIRENT_SET_ERRNO (ENOMEM);
248 error = 1;
249 }
250
251 if (error) {
252 free (dirp);
253 dirp = NULL;
254 }
255 }
256
257 return dirp;
258 }
259
@@ -145,38 +265,53 @@
265 * sub-directories, pseudo-directories "." and "..", but also volume labels,
266 * hidden files and system files may be returned.
267 */
268 static struct dirent *readdir(DIR *dirp)
269 {
270 DWORD attr;
271 if (dirp == NULL) {
272 /* directory stream did not open */
273 DIRENT_SET_ERRNO (EBADF);
274 return NULL;
275 }
276
277 /* get next directory entry */
278 if (dirp->cached != 0) {
279 /* a valid directory entry already in memory */
280 dirp->cached = 0;
281 } else {
282 /* get the next directory entry from stream */
283 if (dirp->search_handle == INVALID_HANDLE_VALUE) {
284 return NULL;
285 }
286 if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) {
287 /* the very last entry has been processed or an error occured */
288 FindClose (dirp->search_handle);
289 dirp->search_handle = INVALID_HANDLE_VALUE;
290 return NULL;
291 }
292 }
293
294 /* copy as a multibyte character string */
295 DIRENT_STRNCPY ( dirp->curentry.d_name,
296 dirp->find_data.cFileName,
297 sizeof(dirp->curentry.d_name) );
298 dirp->curentry.d_name[MAX_PATH] = '\0';
299
300 /* compute the length of name */
301 dirp->curentry.d_namlen = strlen (dirp->curentry.d_name);
302
303 /* determine file type */
304 attr = dirp->find_data.dwFileAttributes;
305 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
306 dirp->curentry.d_type = DT_CHR;
307 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
308 dirp->curentry.d_type = DT_DIR;
309 } else {
310 dirp->curentry.d_type = DT_REG;
311 }
312 return &dirp->curentry;
313 }
314
315
316 /*****************************************************************************
317 * Close directory stream opened by opendir() function. Close of the
@@ -183,48 +318,55 @@
318 * directory stream invalidates the DIR structure as well as any previously
319 * read directory entry.
320 */
321 static int closedir(DIR *dirp)
322 {
323 if (dirp == NULL) {
324 /* invalid directory stream */
325 DIRENT_SET_ERRNO (EBADF);
326 return -1;
327 }
328
329 /* release search handle */
330 if (dirp->search_handle != INVALID_HANDLE_VALUE) {
331 FindClose (dirp->search_handle);
332 dirp->search_handle = INVALID_HANDLE_VALUE;
333 }
334
335 /* release directory structure */
336 free (dirp);
337 return 0;
338 }
339
340
341 /*****************************************************************************
342 * Resets the position of the directory stream to which dirp refers to the
343 * beginning of the directory. It also causes the directory stream to refer
344 * to the current state of the corresponding directory, as a call to opendir()
345 * would have done. If dirp does not refer to a directory stream, the effect
346 * is undefined.
347 */
348 static void rewinddir(DIR* dirp)
349 {
350 if (dirp != NULL) {
351 /* release search handle */
352 if (dirp->search_handle != INVALID_HANDLE_VALUE) {
353 FindClose (dirp->search_handle);
354 }
355
356 /* open new search handle and retrieve the first entry */
357 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
358 if (dirp->search_handle != INVALID_HANDLE_VALUE) {
359 /* a directory entry is now waiting in memory */
360 dirp->cached = 1;
361 } else {
362 /* failed to re-open directory: no directory entry in memory */
363 dirp->cached = 0;
364 }
365 }
366 }
367
368
369 #ifdef __cplusplus
370 }
371 #endif
372 #endif /*DIRENT_H*/
373

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button