Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch dirent-1.11 Excluding Merge-Ins
This is equivalent to a diff from 41577fd3ef to 10fec4b7dd
2012-08-29
| ||
21:32 | upgrade to dirent-1.11 Closed-Leaf check-in: 10fec4b7dd user: jan.nijtmans tags: dirent-1.11, broken-msvc-2 | |
20:57 | undo [bf079432fb]: It's crucial for the Tcl fossil repository to be able to do a no-op merge-mark. This change would make that impossible. Closed-Leaf check-in: 41577fd3ef user: jan.nijtmans tags: broken-msvc-2 | |
20:48 | working part of [ticket-01a2f3a346] (still don't understand, but somehow it doesn't work with msvc) check-in: 517309406a user: jan.nijtmans tags: broken-msvc-2 | |
Changes to win/include/dirent.h.
18 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 20 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 23 * OTHER DEALINGS IN THE SOFTWARE. 24 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 + * 25 43 * Dec 15, 2009, John Cunningham 26 44 * Added rewinddir member function 27 45 * 28 46 * Jan 18, 2008, Toni Ronkko 29 47 * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string 30 48 * between multi-byte and unicode representations. This makes the 31 49 * code simpler and also allows the code to be compiled under MingW. Thanks ................................................................................ 54 72 * 55 73 * May 28 1998, Toni Ronkko 56 74 * First version. 57 75 *****************************************************************************/ 58 76 #ifndef DIRENT_H 59 77 #define DIRENT_H 60 78 79 +#define WIN32_LEAN_AND_MEAN 61 80 #include <windows.h> 62 81 #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 64 152 65 153 66 154 typedef struct dirent 67 155 { 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; 71 160 72 161 73 162 typedef struct DIR 74 163 { 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 */ 79 169 } DIR; 80 170 81 171 82 172 /* 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); 86 176 static void rewinddir(DIR* dirp); 87 177 88 178 89 179 /* Use the new safe string functions introduced in Visual Studio 2005 */ 90 180 #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) 92 189 #else 93 -# define STRNCPY(dest,src,size) strncpy((dest),(src),(size)) 190 +#define DIRENT_SET_ERRNO(x) (errno = (x)) 94 191 #endif 95 192 96 193 97 194 /***************************************************************************** 98 195 * Open directory stream DIRNAME for read and return a pointer to the 99 196 * internal working area that is used to retrieve individual directory 100 197 * entries. 101 198 */ 102 199 static DIR *opendir(const char *dirname) 103 200 { 104 201 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 + } 107 212 108 213 /* construct new DIR structure */ 109 214 dirp = (DIR*) malloc (sizeof (struct DIR)); 110 215 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; 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; 131 249 } 132 250 133 - /* there is an un-processed directory entry in memory now */ 134 - dirp->cached = 1; 251 + if (error) { 252 + free (dirp); 253 + dirp = NULL; 254 + } 135 255 } 136 256 137 257 return dirp; 138 258 } 139 259 140 260 141 261 /***************************************************************************** ................................................................................ 143 263 * containing the name of the entry in d_name field. Individual directory 144 264 * entries returned by this very function include regular files, 145 265 * sub-directories, pseudo-directories "." and "..", but also volume labels, 146 266 * hidden files and system files may be returned. 147 267 */ 148 268 static struct dirent *readdir(DIR *dirp) 149 269 { 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); 154 274 return NULL; 155 275 } 156 276 157 277 /* get next directory entry */ 158 278 if (dirp->cached != 0) { 159 279 /* a valid directory entry already in memory */ 160 280 dirp->cached = 0; 161 281 } 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 */ 165 288 FindClose (dirp->search_handle); 166 289 dirp->search_handle = INVALID_HANDLE_VALUE; 167 290 return NULL; 168 291 } 169 292 } 170 293 171 294 /* 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); 176 302 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; 178 313 } 179 314 180 315 181 316 /***************************************************************************** 182 317 * Close directory stream opened by opendir() function. Close of the 183 318 * directory stream invalidates the DIR structure as well as any previously 184 319 * read directory entry. 185 320 */ 186 321 static int closedir(DIR *dirp) 187 322 { 188 - assert (dirp != NULL); 323 + if (dirp == NULL) { 324 + /* invalid directory stream */ 325 + DIRENT_SET_ERRNO (EBADF); 326 + return -1; 327 + } 189 328 190 329 /* release search handle */ 191 330 if (dirp->search_handle != INVALID_HANDLE_VALUE) { 192 331 FindClose (dirp->search_handle); 193 332 dirp->search_handle = INVALID_HANDLE_VALUE; 194 333 } 195 334 196 - /* release directory handle */ 335 + /* release directory structure */ 197 336 free (dirp); 198 337 return 0; 199 338 } 200 339 201 340 202 341 /***************************************************************************** 203 342 * 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 205 344 * 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 207 346 * is undefined. 208 347 */ 209 348 static void rewinddir(DIR* dirp) 210 349 { 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 - } 350 + if (dirp != NULL) { 351 + /* release search handle */ 352 + if (dirp->search_handle != INVALID_HANDLE_VALUE) { 353 + FindClose (dirp->search_handle); 354 + } 216 355 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; 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 + } 223 365 } 224 - 225 - /* there is an un-processed directory entry in memory now */ 226 - dirp->cached = 1; 227 366 } 228 367 229 368 369 +#ifdef __cplusplus 370 +} 371 +#endif 230 372 #endif /*DIRENT_H*/