|
3DTK
|
00001 /***************************************************************************** 00002 * dirent.h - dirent API for Microsoft Visual Studio 00003 * 00004 * Copyright (C) 2006 Toni Ronkko 00005 * 00006 * Permission is hereby granted, free of charge, to any person obtaining 00007 * a copy of this software and associated documentation files (the 00008 * ``Software''), to deal in the Software without restriction, including 00009 * without limitation the rights to use, copy, modify, merge, publish, 00010 * distribute, sublicense, and/or sell copies of the Software, and to 00011 * permit persons to whom the Software is furnished to do so, subject to 00012 * the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included 00015 * in all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS 00018 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00020 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR 00021 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00022 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00023 * OTHER DEALINGS IN THE SOFTWARE. 00024 * 00025 * Aug 11, 2010, Toni Ronkko 00026 * Added d_type and d_namlen fields to dirent structure. The former is 00027 * especially useful for determining whether directory entry represents a 00028 * file or a directory. For more information, see 00029 * http://www.delorie.com/gnu/docs/glibc/libc_270.html 00030 * 00031 * Aug 11, 2010, Toni Ronkko 00032 * Improved conformance to the standards. For example, errno is now set 00033 * properly on failure and assert() is never used. Thanks to Peter Brockam 00034 * for suggestions. 00035 * 00036 * Aug 11, 2010, Toni Ronkko 00037 * Fixed a bug in rewinddir(): when using relative directory names, change 00038 * of working directory no longer causes rewinddir() to fail. 00039 * 00040 * Dec 15, 2009, John Cunningham 00041 * Added rewinddir member function 00042 * 00043 * Jan 18, 2008, Toni Ronkko 00044 * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string 00045 * between multi-byte and unicode representations. This makes the 00046 * code simpler and also allows the code to be compiled under MingW. Thanks 00047 * to Azriel Fasten for the suggestion. 00048 * 00049 * Mar 4, 2007, Toni Ronkko 00050 * Bug fix: due to the strncpy_s() function this file only compiled in 00051 * Visual Studio 2005. Using the new string functions only when the 00052 * compiler version allows. 00053 * 00054 * Nov 2, 2006, Toni Ronkko 00055 * Major update: removed support for Watcom C, MS-DOS and Turbo C to 00056 * simplify the file, updated the code to compile cleanly on Visual 00057 * Studio 2005 with both unicode and multi-byte character strings, 00058 * removed rewinddir() as it had a bug. 00059 * 00060 * Aug 20, 2006, Toni Ronkko 00061 * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified 00062 * comments by removing SGML tags. 00063 * 00064 * May 14 2002, Toni Ronkko 00065 * Embedded the function definitions directly to the header so that no 00066 * source modules need to be included in the Visual Studio project. Removed 00067 * all the dependencies to other projects so that this very header can be 00068 * used independently. 00069 * 00070 * May 28 1998, Toni Ronkko 00071 * First version. 00072 *****************************************************************************/ 00073 #ifndef DIRENT_H 00074 #define DIRENT_H 00075 00076 #define WIN32_LEAN_AND_MEAN 00077 #include <windows.h> 00078 #include <string.h> 00079 #include <stdlib.h> 00080 #include <sys/types.h> 00081 #include <sys/stat.h> 00082 #include <errno.h> 00083 00084 /* File type and permission flags for stat() */ 00085 #if defined(_MSC_VER) && !defined(S_IREAD) 00086 # define S_IFMT _S_IFMT /* file type mask */ 00087 # define S_IFDIR _S_IFDIR /* directory */ 00088 # define S_IFCHR _S_IFCHR /* character device */ 00089 # define S_IFFIFO _S_IFFIFO /* pipe */ 00090 # define S_IFREG _S_IFREG /* regular file */ 00091 # define S_IREAD _S_IREAD /* read permission */ 00092 # define S_IWRITE _S_IWRITE /* write permission */ 00093 # define S_IEXEC _S_IEXEC /* execute permission */ 00094 #endif 00095 #define S_IFBLK 0 /* block device */ 00096 #define S_IFLNK 0 /* link */ 00097 #define S_IFSOCK 0 /* socket */ 00098 00099 #if defined(_MSC_VER) 00100 # define S_IRUSR S_IREAD /* read, user */ 00101 # define S_IWUSR S_IWRITE /* write, user */ 00102 # define S_IXUSR 0 /* execute, user */ 00103 # define S_IRGRP 0 /* read, group */ 00104 # define S_IWGRP 0 /* write, group */ 00105 # define S_IXGRP 0 /* execute, group */ 00106 # define S_IROTH 0 /* read, others */ 00107 # define S_IWOTH 0 /* write, others */ 00108 # define S_IXOTH 0 /* execute, others */ 00109 #endif 00110 00111 /* Indicates that d_type field is available in dirent structure */ 00112 #define _DIRENT_HAVE_D_TYPE 00113 00114 /* File type flags for d_type */ 00115 #define DT_UNKNOWN 0 00116 #define DT_REG S_IFREG 00117 #define DT_DIR S_IFDIR 00118 #define DT_FIFO S_IFFIFO 00119 #define DT_SOCK S_IFSOCK 00120 #define DT_CHR S_IFCHR 00121 #define DT_BLK S_IFBLK 00122 00123 /* Macros for converting between st_mode and d_type */ 00124 #define IFTODT(mode) ((mode) & S_IFMT) 00125 #define DTTOIF(type) (type) 00126 00127 /* 00128 * File type macros. Note that block devices, sockets and links cannot be 00129 * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are 00130 * only defined for compatibility. These macros should always return false 00131 * on Windows. 00132 */ 00133 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO) 00134 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 00135 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 00136 #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) 00137 #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) 00138 #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) 00139 #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) 00140 00141 #ifdef __cplusplus 00142 extern "C" { 00143 #endif 00144 00145 00146 typedef struct dirent 00147 { 00148 char d_name[MAX_PATH + 1]; /* File name */ 00149 size_t d_namlen; /* Length of name without \0 */ 00150 int d_type; /* File type */ 00151 } dirent; 00152 00153 00154 typedef struct DIR 00155 { 00156 dirent curentry; /* Current directory entry */ 00157 WIN32_FIND_DATAA find_data; /* Private file data */ 00158 int cached; /* True if data is valid */ 00159 HANDLE search_handle; /* Win32 search handle */ 00160 char patt[MAX_PATH + 3]; /* Initial directory name */ 00161 } DIR; 00162 00163 00164 /* Forward declarations */ 00165 static DIR *opendir(const char *dirname); 00166 static struct dirent *readdir(DIR *dirp); 00167 static int closedir(DIR *dirp); 00168 static void rewinddir(DIR* dirp); 00169 00170 00171 /* Use the new safe string functions introduced in Visual Studio 2005 */ 00172 #if defined(_MSC_VER) && _MSC_VER >= 1400 00173 # define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE) 00174 #else 00175 # define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size)) 00176 #endif 00177 00178 /* Set errno variable */ 00179 #if defined(_MSC_VER) 00180 #define DIRENT_SET_ERRNO(x) _set_errno (x) 00181 #else 00182 #define DIRENT_SET_ERRNO(x) (errno = (x)) 00183 #endif 00184 00185 00186 /***************************************************************************** 00187 * Open directory stream DIRNAME for read and return a pointer to the 00188 * internal working area that is used to retrieve individual directory 00189 * entries. 00190 */ 00191 static DIR *opendir(const char *dirname) 00192 { 00193 DIR *dirp; 00194 00195 /* ensure that the resulting search pattern will be a valid file name */ 00196 if (dirname == NULL) { 00197 DIRENT_SET_ERRNO (ENOENT); 00198 return NULL; 00199 } 00200 if (strlen (dirname) + 3 >= MAX_PATH) { 00201 DIRENT_SET_ERRNO (ENAMETOOLONG); 00202 return NULL; 00203 } 00204 00205 /* construct new DIR structure */ 00206 dirp = (DIR*) malloc (sizeof (struct DIR)); 00207 if (dirp != NULL) { 00208 int error; 00209 00210 /* 00211 * Convert relative directory name to an absolute directory one. This 00212 * allows rewinddir() to function correctly when the current working 00213 * directory is changed between opendir() and rewinddir(). 00214 */ 00215 if (GetFullPathNameA (dirname, MAX_PATH, dirp->patt, NULL)) { 00216 char *p; 00217 00218 /* append the search pattern "\\*\0" to the directory name */ 00219 p = strchr (dirp->patt, '\0'); 00220 if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') { 00221 *p++ = '\\'; 00222 } 00223 *p++ = '*'; 00224 *p = '\0'; 00225 00226 /* open directory stream and retrieve the first entry */ 00227 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data); 00228 if (dirp->search_handle != INVALID_HANDLE_VALUE) { 00229 /* a directory entry is now waiting in memory */ 00230 dirp->cached = 1; 00231 error = 0; 00232 } else { 00233 /* search pattern is not a directory name? */ 00234 DIRENT_SET_ERRNO (ENOENT); 00235 error = 1; 00236 } 00237 } else { 00238 /* buffer too small */ 00239 DIRENT_SET_ERRNO (ENOMEM); 00240 error = 1; 00241 } 00242 00243 if (error) { 00244 free (dirp); 00245 dirp = NULL; 00246 } 00247 } 00248 00249 return dirp; 00250 } 00251 00252 00253 /***************************************************************************** 00254 * Read a directory entry, and return a pointer to a dirent structure 00255 * containing the name of the entry in d_name field. Individual directory 00256 * entries returned by this very function include regular files, 00257 * sub-directories, pseudo-directories "." and "..", but also volume labels, 00258 * hidden files and system files may be returned. 00259 */ 00260 static struct dirent *readdir(DIR *dirp) 00261 { 00262 DWORD attr; 00263 if (dirp == NULL) { 00264 /* directory stream did not open */ 00265 DIRENT_SET_ERRNO (EBADF); 00266 return NULL; 00267 } 00268 00269 /* get next directory entry */ 00270 if (dirp->cached != 0) { 00271 /* a valid directory entry already in memory */ 00272 dirp->cached = 0; 00273 } else { 00274 /* get the next directory entry from stream */ 00275 if (dirp->search_handle == INVALID_HANDLE_VALUE) { 00276 return NULL; 00277 } 00278 if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) { 00279 /* the very last entry has been processed or an error occured */ 00280 FindClose (dirp->search_handle); 00281 dirp->search_handle = INVALID_HANDLE_VALUE; 00282 return NULL; 00283 } 00284 } 00285 00286 /* copy as a multibyte character string */ 00287 DIRENT_STRNCPY ( dirp->curentry.d_name, 00288 dirp->find_data.cFileName, 00289 sizeof(dirp->curentry.d_name) ); 00290 dirp->curentry.d_name[MAX_PATH] = '\0'; 00291 00292 /* compute the length of name */ 00293 dirp->curentry.d_namlen = strlen (dirp->curentry.d_name); 00294 00295 /* determine file type */ 00296 attr = dirp->find_data.dwFileAttributes; 00297 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 00298 dirp->curentry.d_type = DT_CHR; 00299 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 00300 dirp->curentry.d_type = DT_DIR; 00301 } else { 00302 dirp->curentry.d_type = DT_REG; 00303 } 00304 return &dirp->curentry; 00305 } 00306 00307 00308 /***************************************************************************** 00309 * Close directory stream opened by opendir() function. Close of the 00310 * directory stream invalidates the DIR structure as well as any previously 00311 * read directory entry. 00312 */ 00313 static int closedir(DIR *dirp) 00314 { 00315 if (dirp == NULL) { 00316 /* invalid directory stream */ 00317 DIRENT_SET_ERRNO (EBADF); 00318 return -1; 00319 } 00320 00321 /* release search handle */ 00322 if (dirp->search_handle != INVALID_HANDLE_VALUE) { 00323 FindClose (dirp->search_handle); 00324 dirp->search_handle = INVALID_HANDLE_VALUE; 00325 } 00326 00327 /* release directory structure */ 00328 free (dirp); 00329 return 0; 00330 } 00331 00332 00333 /***************************************************************************** 00334 * Resets the position of the directory stream to which dirp refers to the 00335 * beginning of the directory. It also causes the directory stream to refer 00336 * to the current state of the corresponding directory, as a call to opendir() 00337 * would have done. If dirp does not refer to a directory stream, the effect 00338 * is undefined. 00339 */ 00340 static void rewinddir(DIR* dirp) 00341 { 00342 if (dirp != NULL) { 00343 /* release search handle */ 00344 if (dirp->search_handle != INVALID_HANDLE_VALUE) { 00345 FindClose (dirp->search_handle); 00346 } 00347 00348 /* open new search handle and retrieve the first entry */ 00349 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data); 00350 if (dirp->search_handle != INVALID_HANDLE_VALUE) { 00351 /* a directory entry is now waiting in memory */ 00352 dirp->cached = 1; 00353 } else { 00354 /* failed to re-open directory: no directory entry in memory */ 00355 dirp->cached = 0; 00356 } 00357 } 00358 } 00359 00360 00361 #ifdef __cplusplus 00362 } 00363 #endif 00364 #endif /*DIRENT_H*/
1.7.4