• dirent.h文件


     dirent.h头文件

       1 /*
       2  * Dirent interface for Microsoft Visual Studio
       3  *
       4  * Copyright (C) 1998-2019 Toni Ronkko
       5  * This file is part of dirent.  Dirent may be freely distributed
       6  * under the MIT license.  For all details and documentation, see
       7  * https://github.com/tronkko/dirent
       8  */
       9 #ifndef DIRENT_H
      10 #define DIRENT_H
      11 
      12 /* Hide warnings about unreferenced local functions */
      13 #if defined(__clang__)
      14 #   pragma clang diagnostic ignored "-Wunused-function"
      15 #elif defined(_MSC_VER)
      16 #   pragma warning(disable:4505)
      17 #elif defined(__GNUC__)
      18 #   pragma GCC diagnostic ignored "-Wunused-function"
      19 #endif
      20 
      21 /*
      22  * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
      23  * Windows Sockets 2.0.
      24  */
      25 #ifndef WIN32_LEAN_AND_MEAN
      26 #   define WIN32_LEAN_AND_MEAN
      27 #endif
      28 #include <windows.h>
      29 
      30 #include <stdio.h>
      31 #include <stdarg.h>
      32 #include <wchar.h>
      33 #include <string.h>
      34 #include <stdlib.h>
      35 #include <malloc.h>
      36 #include <sys/types.h>
      37 #include <sys/stat.h>
      38 #include <errno.h>
      39 
      40 /* Indicates that d_type field is available in dirent structure */
      41 #define _DIRENT_HAVE_D_TYPE
      42 
      43 /* Indicates that d_namlen field is available in dirent structure */
      44 #define _DIRENT_HAVE_D_NAMLEN
      45 
      46 /* Entries missing from MSVC 6.0 */
      47 #if !defined(FILE_ATTRIBUTE_DEVICE)
      48 #   define FILE_ATTRIBUTE_DEVICE 0x40
      49 #endif
      50 
      51 /* File type and permission flags for stat(), general mask */
      52 #if !defined(S_IFMT)
      53 #   define S_IFMT _S_IFMT
      54 #endif
      55 
      56 /* Directory bit */
      57 #if !defined(S_IFDIR)
      58 #   define S_IFDIR _S_IFDIR
      59 #endif
      60 
      61 /* Character device bit */
      62 #if !defined(S_IFCHR)
      63 #   define S_IFCHR _S_IFCHR
      64 #endif
      65 
      66 /* Pipe bit */
      67 #if !defined(S_IFFIFO)
      68 #   define S_IFFIFO _S_IFFIFO
      69 #endif
      70 
      71 /* Regular file bit */
      72 #if !defined(S_IFREG)
      73 #   define S_IFREG _S_IFREG
      74 #endif
      75 
      76 /* Read permission */
      77 #if !defined(S_IREAD)
      78 #   define S_IREAD _S_IREAD
      79 #endif
      80 
      81 /* Write permission */
      82 #if !defined(S_IWRITE)
      83 #   define S_IWRITE _S_IWRITE
      84 #endif
      85 
      86 /* Execute permission */
      87 #if !defined(S_IEXEC)
      88 #   define S_IEXEC _S_IEXEC
      89 #endif
      90 
      91 /* Pipe */
      92 #if !defined(S_IFIFO)
      93 #   define S_IFIFO _S_IFIFO
      94 #endif
      95 
      96 /* Block device */
      97 #if !defined(S_IFBLK)
      98 #   define S_IFBLK 0
      99 #endif
     100 
     101 /* Link */
     102 #if !defined(S_IFLNK)
     103 #   define S_IFLNK 0
     104 #endif
     105 
     106 /* Socket */
     107 #if !defined(S_IFSOCK)
     108 #   define S_IFSOCK 0
     109 #endif
     110 
     111 /* Read user permission */
     112 #if !defined(S_IRUSR)
     113 #   define S_IRUSR S_IREAD
     114 #endif
     115 
     116 /* Write user permission */
     117 #if !defined(S_IWUSR)
     118 #   define S_IWUSR S_IWRITE
     119 #endif
     120 
     121 /* Execute user permission */
     122 #if !defined(S_IXUSR)
     123 #   define S_IXUSR 0
     124 #endif
     125 
     126 /* Read group permission */
     127 #if !defined(S_IRGRP)
     128 #   define S_IRGRP 0
     129 #endif
     130 
     131 /* Write group permission */
     132 #if !defined(S_IWGRP)
     133 #   define S_IWGRP 0
     134 #endif
     135 
     136 /* Execute group permission */
     137 #if !defined(S_IXGRP)
     138 #   define S_IXGRP 0
     139 #endif
     140 
     141 /* Read others permission */
     142 #if !defined(S_IROTH)
     143 #   define S_IROTH 0
     144 #endif
     145 
     146 /* Write others permission */
     147 #if !defined(S_IWOTH)
     148 #   define S_IWOTH 0
     149 #endif
     150 
     151 /* Execute others permission */
     152 #if !defined(S_IXOTH)
     153 #   define S_IXOTH 0
     154 #endif
     155 
     156 /* Maximum length of file name */
     157 #if !defined(PATH_MAX)
     158 #   define PATH_MAX MAX_PATH
     159 #endif
     160 #if !defined(FILENAME_MAX)
     161 #   define FILENAME_MAX MAX_PATH
     162 #endif
     163 #if !defined(NAME_MAX)
     164 #   define NAME_MAX FILENAME_MAX
     165 #endif
     166 
     167 /* File type flags for d_type */
     168 #define DT_UNKNOWN 0
     169 #define DT_REG S_IFREG
     170 #define DT_DIR S_IFDIR
     171 #define DT_FIFO S_IFIFO
     172 #define DT_SOCK S_IFSOCK
     173 #define DT_CHR S_IFCHR
     174 #define DT_BLK S_IFBLK
     175 #define DT_LNK S_IFLNK
     176 
     177 /* Macros for converting between st_mode and d_type */
     178 #define IFTODT(mode) ((mode) & S_IFMT)
     179 #define DTTOIF(type) (type)
     180 
     181 /*
     182  * File type macros.  Note that block devices, sockets and links cannot be
     183  * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
     184  * only defined for compatibility.  These macros should always return false
     185  * on Windows.
     186  */
     187 #if !defined(S_ISFIFO)
     188 #   define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
     189 #endif
     190 #if !defined(S_ISDIR)
     191 #   define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
     192 #endif
     193 #if !defined(S_ISREG)
     194 #   define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
     195 #endif
     196 #if !defined(S_ISLNK)
     197 #   define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
     198 #endif
     199 #if !defined(S_ISSOCK)
     200 #   define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
     201 #endif
     202 #if !defined(S_ISCHR)
     203 #   define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
     204 #endif
     205 #if !defined(S_ISBLK)
     206 #   define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
     207 #endif
     208 
     209 /* Return the exact length of the file name without zero terminator */
     210 #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
     211 
     212 /* Return the maximum size of a file name */
     213 #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
     214 
     215 
     216 #ifdef __cplusplus
     217 extern "C" {
     218 #endif
     219 
     220 
     221 /* Wide-character version */
     222 struct _wdirent {
     223     /* Always zero */
     224     long d_ino;
     225 
     226     /* File position within stream */
     227     long d_off;
     228 
     229     /* Structure size */
     230     unsigned short d_reclen;
     231 
     232     /* Length of name without  */
     233     size_t d_namlen;
     234 
     235     /* File type */
     236     int d_type;
     237 
     238     /* File name */
     239     wchar_t d_name[PATH_MAX+1];
     240 };
     241 typedef struct _wdirent _wdirent;
     242 
     243 struct _WDIR {
     244     /* Current directory entry */
     245     struct _wdirent ent;
     246 
     247     /* Private file data */
     248     WIN32_FIND_DATAW data;
     249 
     250     /* True if data is valid */
     251     int cached;
     252 
     253     /* Win32 search handle */
     254     HANDLE handle;
     255 
     256     /* Initial directory name */
     257     wchar_t *patt;
     258 };
     259 typedef struct _WDIR _WDIR;
     260 
     261 /* Multi-byte character version */
     262 struct dirent {
     263     /* Always zero */
     264     long d_ino;
     265 
     266     /* File position within stream */
     267     long d_off;
     268 
     269     /* Structure size */
     270     unsigned short d_reclen;
     271 
     272     /* Length of name without  */
     273     size_t d_namlen;
     274 
     275     /* File type */
     276     int d_type;
     277 
     278     /* File name */
     279     char d_name[PATH_MAX+1];
     280 };
     281 typedef struct dirent dirent;
     282 
     283 struct DIR {
     284     struct dirent ent;
     285     struct _WDIR *wdirp;
     286 };
     287 typedef struct DIR DIR;
     288 
     289 
     290 /* Dirent functions */
     291 static DIR *opendir (const char *dirname);
     292 static _WDIR *_wopendir (const wchar_t *dirname);
     293 
     294 static struct dirent *readdir (DIR *dirp);
     295 static struct _wdirent *_wreaddir (_WDIR *dirp);
     296 
     297 static int readdir_r(
     298     DIR *dirp, struct dirent *entry, struct dirent **result);
     299 static int _wreaddir_r(
     300     _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
     301 
     302 static int closedir (DIR *dirp);
     303 static int _wclosedir (_WDIR *dirp);
     304 
     305 static void rewinddir (DIR* dirp);
     306 static void _wrewinddir (_WDIR* dirp);
     307 
     308 static int scandir (const char *dirname, struct dirent ***namelist,
     309     int (*filter)(const struct dirent*),
     310     int (*compare)(const struct dirent**, const struct dirent**));
     311 
     312 static int alphasort (const struct dirent **a, const struct dirent **b);
     313 
     314 static int versionsort (const struct dirent **a, const struct dirent **b);
     315 
     316 
     317 /* For compatibility with Symbian */
     318 #define wdirent _wdirent
     319 #define WDIR _WDIR
     320 #define wopendir _wopendir
     321 #define wreaddir _wreaddir
     322 #define wclosedir _wclosedir
     323 #define wrewinddir _wrewinddir
     324 
     325 
     326 /* Internal utility functions */
     327 static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
     328 static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
     329 
     330 static int dirent_mbstowcs_s(
     331     size_t *pReturnValue,
     332     wchar_t *wcstr,
     333     size_t sizeInWords,
     334     const char *mbstr,
     335     size_t count);
     336 
     337 static int dirent_wcstombs_s(
     338     size_t *pReturnValue,
     339     char *mbstr,
     340     size_t sizeInBytes,
     341     const wchar_t *wcstr,
     342     size_t count);
     343 
     344 static void dirent_set_errno (int error);
     345 
     346 
     347 /*
     348  * Open directory stream DIRNAME for read and return a pointer to the
     349  * internal working area that is used to retrieve individual directory
     350  * entries.
     351  */
     352 static _WDIR*
     353 _wopendir(
     354     const wchar_t *dirname)
     355 {
     356     _WDIR *dirp;
     357     DWORD n;
     358     wchar_t *p;
     359 
     360     /* Must have directory name */
     361     if (dirname == NULL  ||  dirname[0] == '') {
     362         dirent_set_errno (ENOENT);
     363         return NULL;
     364     }
     365 
     366     /* Allocate new _WDIR structure */
     367     dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
     368     if (!dirp) {
     369         return NULL;
     370     }
     371 
     372     /* Reset _WDIR structure */
     373     dirp->handle = INVALID_HANDLE_VALUE;
     374     dirp->patt = NULL;
     375     dirp->cached = 0;
     376 
     377     /*
     378      * Compute the length of full path plus zero terminator
     379      *
     380      * Note that on WinRT there's no way to convert relative paths
     381      * into absolute paths, so just assume it is an absolute path.
     382      */
     383 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
     384     /* Desktop */
     385     n = GetFullPathNameW (dirname, 0, NULL, NULL);
     386 #else
     387     /* WinRT */
     388     n = wcslen (dirname);
     389 #endif
     390 
     391     /* Allocate room for absolute directory name and search pattern */
     392     dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
     393     if (dirp->patt == NULL) {
     394         goto exit_closedir;
     395     }
     396 
     397     /*
     398      * Convert relative directory name to an absolute one.  This
     399      * allows rewinddir() to function correctly even when current
     400      * working directory is changed between opendir() and rewinddir().
     401      *
     402      * Note that on WinRT there's no way to convert relative paths
     403      * into absolute paths, so just assume it is an absolute path.
     404      */
     405 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
     406     /* Desktop */
     407     n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
     408     if (n <= 0) {
     409         goto exit_closedir;
     410     }
     411 #else
     412     /* WinRT */
     413     wcsncpy_s (dirp->patt, n+1, dirname, n);
     414 #endif
     415 
     416     /* Append search pattern * to the directory name */
     417     p = dirp->patt + n;
     418     switch (p[-1]) {
     419     case '\':
     420     case '/':
     421     case ':':
     422         /* Directory ends in path separator, e.g. c:	emp */
     423         /*NOP*/;
     424         break;
     425 
     426     default:
     427         /* Directory name doesn't end in path separator */
     428         *p++ = '\';
     429     }
     430     *p++ = '*';
     431     *p = '';
     432 
     433     /* Open directory stream and retrieve the first entry */
     434     if (!dirent_first (dirp)) {
     435         goto exit_closedir;
     436     }
     437 
     438     /* Success */
     439     return dirp;
     440 
     441     /* Failure */
     442 exit_closedir:
     443     _wclosedir (dirp);
     444     return NULL;
     445 }
     446 
     447 /*
     448  * Read next directory entry.
     449  *
     450  * Returns pointer to static directory entry which may be overwritten by
     451  * subsequent calls to _wreaddir().
     452  */
     453 static struct _wdirent*
     454 _wreaddir(
     455     _WDIR *dirp)
     456 {
     457     struct _wdirent *entry;
     458 
     459     /*
     460      * Read directory entry to buffer.  We can safely ignore the return value
     461      * as entry will be set to NULL in case of error.
     462      */
     463     (void) _wreaddir_r (dirp, &dirp->ent, &entry);
     464 
     465     /* Return pointer to statically allocated directory entry */
     466     return entry;
     467 }
     468 
     469 /*
     470  * Read next directory entry.
     471  *
     472  * Returns zero on success.  If end of directory stream is reached, then sets
     473  * result to NULL and returns zero.
     474  */
     475 static int
     476 _wreaddir_r(
     477     _WDIR *dirp,
     478     struct _wdirent *entry,
     479     struct _wdirent **result)
     480 {
     481     WIN32_FIND_DATAW *datap;
     482 
     483     /* Read next directory entry */
     484     datap = dirent_next (dirp);
     485     if (datap) {
     486         size_t n;
     487         DWORD attr;
     488 
     489         /*
     490          * Copy file name as wide-character string.  If the file name is too
     491          * long to fit in to the destination buffer, then truncate file name
     492          * to PATH_MAX characters and zero-terminate the buffer.
     493          */
     494         n = 0;
     495         while (n < PATH_MAX  &&  datap->cFileName[n] != 0) {
     496             entry->d_name[n] = datap->cFileName[n];
     497             n++;
     498         }
     499         entry->d_name[n] = 0;
     500 
     501         /* Length of file name excluding zero terminator */
     502         entry->d_namlen = n;
     503 
     504         /* File type */
     505         attr = datap->dwFileAttributes;
     506         if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
     507             entry->d_type = DT_CHR;
     508         } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
     509             entry->d_type = DT_DIR;
     510         } else {
     511             entry->d_type = DT_REG;
     512         }
     513 
     514         /* Reset dummy fields */
     515         entry->d_ino = 0;
     516         entry->d_off = 0;
     517         entry->d_reclen = sizeof (struct _wdirent);
     518 
     519         /* Set result address */
     520         *result = entry;
     521 
     522     } else {
     523 
     524         /* Return NULL to indicate end of directory */
     525         *result = NULL;
     526 
     527     }
     528 
     529     return /*OK*/0;
     530 }
     531 
     532 /*
     533  * Close directory stream opened by opendir() function.  This invalidates the
     534  * DIR structure as well as any directory entry read previously by
     535  * _wreaddir().
     536  */
     537 static int
     538 _wclosedir(
     539     _WDIR *dirp)
     540 {
     541     int ok;
     542     if (dirp) {
     543 
     544         /* Release search handle */
     545         if (dirp->handle != INVALID_HANDLE_VALUE) {
     546             FindClose (dirp->handle);
     547         }
     548 
     549         /* Release search pattern */
     550         free (dirp->patt);
     551 
     552         /* Release directory structure */
     553         free (dirp);
     554         ok = /*success*/0;
     555 
     556     } else {
     557 
     558         /* Invalid directory stream */
     559         dirent_set_errno (EBADF);
     560         ok = /*failure*/-1;
     561 
     562     }
     563     return ok;
     564 }
     565 
     566 /*
     567  * Rewind directory stream such that _wreaddir() returns the very first
     568  * file name again.
     569  */
     570 static void
     571 _wrewinddir(
     572     _WDIR* dirp)
     573 {
     574     if (dirp) {
     575         /* Release existing search handle */
     576         if (dirp->handle != INVALID_HANDLE_VALUE) {
     577             FindClose (dirp->handle);
     578         }
     579 
     580         /* Open new search handle */
     581         dirent_first (dirp);
     582     }
     583 }
     584 
     585 /* Get first directory entry (internal) */
     586 static WIN32_FIND_DATAW*
     587 dirent_first(
     588     _WDIR *dirp)
     589 {
     590     WIN32_FIND_DATAW *datap;
     591     DWORD error;
     592 
     593     /* Open directory and retrieve the first entry */
     594     dirp->handle = FindFirstFileExW(
     595         dirp->patt, FindExInfoStandard, &dirp->data,
     596         FindExSearchNameMatch, NULL, 0);
     597     if (dirp->handle != INVALID_HANDLE_VALUE) {
     598 
     599         /* a directory entry is now waiting in memory */
     600         datap = &dirp->data;
     601         dirp->cached = 1;
     602 
     603     } else {
     604 
     605         /* Failed to open directory: no directory entry in memory */
     606         dirp->cached = 0;
     607         datap = NULL;
     608 
     609         /* Set error code */
     610         error = GetLastError ();
     611         switch (error) {
     612         case ERROR_ACCESS_DENIED:
     613             /* No read access to directory */
     614             dirent_set_errno (EACCES);
     615             break;
     616 
     617         case ERROR_DIRECTORY:
     618             /* Directory name is invalid */
     619             dirent_set_errno (ENOTDIR);
     620             break;
     621 
     622         case ERROR_PATH_NOT_FOUND:
     623         default:
     624             /* Cannot find the file */
     625             dirent_set_errno (ENOENT);
     626         }
     627 
     628     }
     629     return datap;
     630 }
     631 
     632 /*
     633  * Get next directory entry (internal).
     634  *
     635  * Returns
     636  */
     637 static WIN32_FIND_DATAW*
     638 dirent_next(
     639     _WDIR *dirp)
     640 {
     641     WIN32_FIND_DATAW *p;
     642 
     643     /* Get next directory entry */
     644     if (dirp->cached != 0) {
     645 
     646         /* A valid directory entry already in memory */
     647         p = &dirp->data;
     648         dirp->cached = 0;
     649 
     650     } else if (dirp->handle != INVALID_HANDLE_VALUE) {
     651 
     652         /* Get the next directory entry from stream */
     653         if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
     654             /* Got a file */
     655             p = &dirp->data;
     656         } else {
     657             /* The very last entry has been processed or an error occurred */
     658             FindClose (dirp->handle);
     659             dirp->handle = INVALID_HANDLE_VALUE;
     660             p = NULL;
     661         }
     662 
     663     } else {
     664 
     665         /* End of directory stream reached */
     666         p = NULL;
     667 
     668     }
     669 
     670     return p;
     671 }
     672 
     673 /*
     674  * Open directory stream using plain old C-string.
     675  */
     676 static DIR*
     677 opendir(
     678     const char *dirname)
     679 {
     680     struct DIR *dirp;
     681 
     682     /* Must have directory name */
     683     if (dirname == NULL  ||  dirname[0] == '') {
     684         dirent_set_errno (ENOENT);
     685         return NULL;
     686     }
     687 
     688     /* Allocate memory for DIR structure */
     689     dirp = (DIR*) malloc (sizeof (struct DIR));
     690     if (!dirp) {
     691         return NULL;
     692     }
     693     {
     694         int error;
     695         wchar_t wname[PATH_MAX + 1];
     696         size_t n;
     697 
     698         /* Convert directory name to wide-character string */
     699         error = dirent_mbstowcs_s(
     700             &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
     701         if (error) {
     702             /*
     703              * Cannot convert file name to wide-character string.  This
     704              * occurs if the string contains invalid multi-byte sequences or
     705              * the output buffer is too small to contain the resulting
     706              * string.
     707              */
     708             goto exit_free;
     709         }
     710 
     711 
     712         /* Open directory stream using wide-character name */
     713         dirp->wdirp = _wopendir (wname);
     714         if (!dirp->wdirp) {
     715             goto exit_free;
     716         }
     717 
     718     }
     719 
     720     /* Success */
     721     return dirp;
     722 
     723     /* Failure */
     724 exit_free:
     725     free (dirp);
     726     return NULL;
     727 }
     728 
     729 /*
     730  * Read next directory entry.
     731  */
     732 static struct dirent*
     733 readdir(
     734     DIR *dirp)
     735 {
     736     struct dirent *entry;
     737 
     738     /*
     739      * Read directory entry to buffer.  We can safely ignore the return value
     740      * as entry will be set to NULL in case of error.
     741      */
     742     (void) readdir_r (dirp, &dirp->ent, &entry);
     743 
     744     /* Return pointer to statically allocated directory entry */
     745     return entry;
     746 }
     747 
     748 /*
     749  * Read next directory entry into called-allocated buffer.
     750  *
     751  * Returns zero on success.  If the end of directory stream is reached, then
     752  * sets result to NULL and returns zero.
     753  */
     754 static int
     755 readdir_r(
     756     DIR *dirp,
     757     struct dirent *entry,
     758     struct dirent **result)
     759 {
     760     WIN32_FIND_DATAW *datap;
     761 
     762     /* Read next directory entry */
     763     datap = dirent_next (dirp->wdirp);
     764     if (datap) {
     765         size_t n;
     766         int error;
     767 
     768         /* Attempt to convert file name to multi-byte string */
     769         error = dirent_wcstombs_s(
     770             &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
     771 
     772         /*
     773          * If the file name cannot be represented by a multi-byte string,
     774          * then attempt to use old 8+3 file name.  This allows traditional
     775          * Unix-code to access some file names despite of unicode
     776          * characters, although file names may seem unfamiliar to the user.
     777          *
     778          * Be ware that the code below cannot come up with a short file
     779          * name unless the file system provides one.  At least
     780          * VirtualBox shared folders fail to do this.
     781          */
     782         if (error  &&  datap->cAlternateFileName[0] != '') {
     783             error = dirent_wcstombs_s(
     784                 &n, entry->d_name, PATH_MAX + 1,
     785                 datap->cAlternateFileName, PATH_MAX + 1);
     786         }
     787 
     788         if (!error) {
     789             DWORD attr;
     790 
     791             /* Length of file name excluding zero terminator */
     792             entry->d_namlen = n - 1;
     793 
     794             /* File attributes */
     795             attr = datap->dwFileAttributes;
     796             if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
     797                 entry->d_type = DT_CHR;
     798             } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
     799                 entry->d_type = DT_DIR;
     800             } else {
     801                 entry->d_type = DT_REG;
     802             }
     803 
     804             /* Reset dummy fields */
     805             entry->d_ino = 0;
     806             entry->d_off = 0;
     807             entry->d_reclen = sizeof (struct dirent);
     808 
     809         } else {
     810 
     811             /*
     812              * Cannot convert file name to multi-byte string so construct
     813              * an erroneous directory entry and return that.  Note that
     814              * we cannot return NULL as that would stop the processing
     815              * of directory entries completely.
     816              */
     817             entry->d_name[0] = '?';
     818             entry->d_name[1] = '';
     819             entry->d_namlen = 1;
     820             entry->d_type = DT_UNKNOWN;
     821             entry->d_ino = 0;
     822             entry->d_off = -1;
     823             entry->d_reclen = 0;
     824 
     825         }
     826 
     827         /* Return pointer to directory entry */
     828         *result = entry;
     829 
     830     } else {
     831 
     832         /* No more directory entries */
     833         *result = NULL;
     834 
     835     }
     836 
     837     return /*OK*/0;
     838 }
     839 
     840 /*
     841  * Close directory stream.
     842  */
     843 static int
     844 closedir(
     845     DIR *dirp)
     846 {
     847     int ok;
     848     if (dirp) {
     849 
     850         /* Close wide-character directory stream */
     851         ok = _wclosedir (dirp->wdirp);
     852         dirp->wdirp = NULL;
     853 
     854         /* Release multi-byte character version */
     855         free (dirp);
     856 
     857     } else {
     858 
     859         /* Invalid directory stream */
     860         dirent_set_errno (EBADF);
     861         ok = /*failure*/-1;
     862 
     863     }
     864     return ok;
     865 }
     866 
     867 /*
     868  * Rewind directory stream to beginning.
     869  */
     870 static void
     871 rewinddir(
     872     DIR* dirp)
     873 {
     874     /* Rewind wide-character string directory stream */
     875     _wrewinddir (dirp->wdirp);
     876 }
     877 
     878 /*
     879  * Scan directory for entries.
     880  */
     881 static int
     882 scandir(
     883     const char *dirname,
     884     struct dirent ***namelist,
     885     int (*filter)(const struct dirent*),
     886     int (*compare)(const struct dirent**, const struct dirent**))
     887 {
     888     struct dirent **files = NULL;
     889     size_t size = 0;
     890     size_t allocated = 0;
     891     const size_t init_size = 1;
     892     DIR *dir = NULL;
     893     struct dirent *entry;
     894     struct dirent *tmp = NULL;
     895     size_t i;
     896     int result = 0;
     897 
     898     /* Open directory stream */
     899     dir = opendir (dirname);
     900     if (dir) {
     901 
     902         /* Read directory entries to memory */
     903         while (1) {
     904 
     905             /* Enlarge pointer table to make room for another pointer */
     906             if (size >= allocated) {
     907                 void *p;
     908                 size_t num_entries;
     909 
     910                 /* Compute number of entries in the enlarged pointer table */
     911                 if (size < init_size) {
     912                     /* Allocate initial pointer table */
     913                     num_entries = init_size;
     914                 } else {
     915                     /* Double the size */
     916                     num_entries = size * 2;
     917                 }
     918 
     919                 /* Allocate first pointer table or enlarge existing table */
     920                 p = realloc (files, sizeof (void*) * num_entries);
     921                 if (p != NULL) {
     922                     /* Got the memory */
     923                     files = (dirent**) p;
     924                     allocated = num_entries;
     925                 } else {
     926                     /* Out of memory */
     927                     result = -1;
     928                     break;
     929                 }
     930 
     931             }
     932 
     933             /* Allocate room for temporary directory entry */
     934             if (tmp == NULL) {
     935                 tmp = (struct dirent*) malloc (sizeof (struct dirent));
     936                 if (tmp == NULL) {
     937                     /* Cannot allocate temporary directory entry */
     938                     result = -1;
     939                     break;
     940                 }
     941             }
     942 
     943             /* Read directory entry to temporary area */
     944             if (readdir_r (dir, tmp, &entry) == /*OK*/0) {
     945 
     946                 /* Did we get an entry? */
     947                 if (entry != NULL) {
     948                     int pass;
     949 
     950                     /* Determine whether to include the entry in result */
     951                     if (filter) {
     952                         /* Let the filter function decide */
     953                         pass = filter (tmp);
     954                     } else {
     955                         /* No filter function, include everything */
     956                         pass = 1;
     957                     }
     958 
     959                     if (pass) {
     960                         /* Store the temporary entry to pointer table */
     961                         files[size++] = tmp;
     962                         tmp = NULL;
     963 
     964                         /* Keep up with the number of files */
     965                         result++;
     966                     }
     967 
     968                 } else {
     969 
     970                     /*
     971                      * End of directory stream reached => sort entries and
     972                      * exit.
     973                      */
     974                     qsort (files, size, sizeof (void*),
     975                         (int (*) (const void*, const void*)) compare);
     976                     break;
     977 
     978                 }
     979 
     980             } else {
     981                 /* Error reading directory entry */
     982                 result = /*Error*/ -1;
     983                 break;
     984             }
     985 
     986         }
     987 
     988     } else {
     989         /* Cannot open directory */
     990         result = /*Error*/ -1;
     991     }
     992 
     993     /* Release temporary directory entry */
     994     free (tmp);
     995 
     996     /* Release allocated memory on error */
     997     if (result < 0) {
     998         for (i = 0; i < size; i++) {
     999             free (files[i]);
    1000         }
    1001         free (files);
    1002         files = NULL;
    1003     }
    1004 
    1005     /* Close directory stream */
    1006     if (dir) {
    1007         closedir (dir);
    1008     }
    1009 
    1010     /* Pass pointer table to caller */
    1011     if (namelist) {
    1012         *namelist = files;
    1013     }
    1014     return result;
    1015 }
    1016 
    1017 /* Alphabetical sorting */
    1018 static int
    1019 alphasort(
    1020     const struct dirent **a, const struct dirent **b)
    1021 {
    1022     return strcoll ((*a)->d_name, (*b)->d_name);
    1023 }
    1024 
    1025 /* Sort versions */
    1026 static int
    1027 versionsort(
    1028     const struct dirent **a, const struct dirent **b)
    1029 {
    1030     /* FIXME: implement strverscmp and use that */
    1031     return alphasort (a, b);
    1032 }
    1033 
    1034 /* Convert multi-byte string to wide character string */
    1035 static int
    1036 dirent_mbstowcs_s(
    1037     size_t *pReturnValue,
    1038     wchar_t *wcstr,
    1039     size_t sizeInWords,
    1040     const char *mbstr,
    1041     size_t count)
    1042 {
    1043     int error;
    1044 
    1045 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
    1046 
    1047     /* Microsoft Visual Studio 2005 or later */
    1048     error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
    1049 
    1050 #else
    1051 
    1052     /* Older Visual Studio or non-Microsoft compiler */
    1053     size_t n;
    1054 
    1055     /* Convert to wide-character string (or count characters) */
    1056     n = mbstowcs (wcstr, mbstr, sizeInWords);
    1057     if (!wcstr  ||  n < count) {
    1058 
    1059         /* Zero-terminate output buffer */
    1060         if (wcstr  &&  sizeInWords) {
    1061             if (n >= sizeInWords) {
    1062                 n = sizeInWords - 1;
    1063             }
    1064             wcstr[n] = 0;
    1065         }
    1066 
    1067         /* Length of resulting multi-byte string WITH zero terminator */
    1068         if (pReturnValue) {
    1069             *pReturnValue = n + 1;
    1070         }
    1071 
    1072         /* Success */
    1073         error = 0;
    1074 
    1075     } else {
    1076 
    1077         /* Could not convert string */
    1078         error = 1;
    1079 
    1080     }
    1081 
    1082 #endif
    1083     return error;
    1084 }
    1085 
    1086 /* Convert wide-character string to multi-byte string */
    1087 static int
    1088 dirent_wcstombs_s(
    1089     size_t *pReturnValue,
    1090     char *mbstr,
    1091     size_t sizeInBytes, /* max size of mbstr */
    1092     const wchar_t *wcstr,
    1093     size_t count)
    1094 {
    1095     int error;
    1096 
    1097 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
    1098 
    1099     /* Microsoft Visual Studio 2005 or later */
    1100     error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
    1101 
    1102 #else
    1103 
    1104     /* Older Visual Studio or non-Microsoft compiler */
    1105     size_t n;
    1106 
    1107     /* Convert to multi-byte string (or count the number of bytes needed) */
    1108     n = wcstombs (mbstr, wcstr, sizeInBytes);
    1109     if (!mbstr  ||  n < count) {
    1110 
    1111         /* Zero-terminate output buffer */
    1112         if (mbstr  &&  sizeInBytes) {
    1113             if (n >= sizeInBytes) {
    1114                 n = sizeInBytes - 1;
    1115             }
    1116             mbstr[n] = '';
    1117         }
    1118 
    1119         /* Length of resulting multi-bytes string WITH zero-terminator */
    1120         if (pReturnValue) {
    1121             *pReturnValue = n + 1;
    1122         }
    1123 
    1124         /* Success */
    1125         error = 0;
    1126 
    1127     } else {
    1128 
    1129         /* Cannot convert string */
    1130         error = 1;
    1131 
    1132     }
    1133 
    1134 #endif
    1135     return error;
    1136 }
    1137 
    1138 /* Set errno variable */
    1139 static void
    1140 dirent_set_errno(
    1141     int error)
    1142 {
    1143 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
    1144 
    1145     /* Microsoft Visual Studio 2005 and later */
    1146     _set_errno (error);
    1147 
    1148 #else
    1149 
    1150     /* Non-Microsoft compiler or older Microsoft compiler */
    1151     errno = error;
    1152 
    1153 #endif
    1154 }
    1155 
    1156 
    1157 #ifdef __cplusplus
    1158 }
    1159 #endif
    1160 #endif /*DIRENT_H*/
  • 相关阅读:
    大道至简第六章-从编程到工程
    Java动手动脑-接口继承
    随机数生成数组元素求和
    大道至简第五章-失败的过程也是过程
    课堂-字符串加密
    字符串加密
    课堂动手动脑-3及字符串加密
    java课堂回答
    读后感
    从编辑懂工程
  • 原文地址:https://www.cnblogs.com/hsy1941/p/11711452.html
Copyright © 2020-2023  润新知