1 /*
2  * Dirent interface for Microsoft Visual Studio
3  * Version 1.21
4  *
5  * Copyright (C) 2006-2012 Toni Ronkko
6  * This file is part of dirent.  Dirent may be freely distributed
7  * under the MIT license.  For all details and documentation, see
8  * https://github.com/tronkko/dirent
9  */
10 #ifndef DIRENT_H
11 #define DIRENT_H
12 
13 /*
14  * Define architecture flags so we don't need to include windows.h.
15  * Avoiding windows.h makes it simpler to use windows sockets in conjunction
16  * with dirent.h.
17  */
18 #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)
19 #   define _X86_
20 #endif
21 #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64)
22 #define _AMD64_
23 #endif
24 
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <windef.h>
28 #include <winbase.h>
29 #include <wchar.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <malloc.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <errno.h>
36 
37 /* Indicates that d_type field is available in dirent structure */
38 #define _DIRENT_HAVE_D_TYPE
39 
40 /* Indicates that d_namlen field is available in dirent structure */
41 #define _DIRENT_HAVE_D_NAMLEN
42 
43 /* Entries missing from MSVC 6.0 */
44 #if !defined(FILE_ATTRIBUTE_DEVICE)
45 #   define FILE_ATTRIBUTE_DEVICE 0x40
46 #endif
47 
48 /* File type and permission flags for stat(), general mask */
49 #if !defined(S_IFMT)
50 #   define S_IFMT _S_IFMT
51 #endif
52 
53 /* Directory bit */
54 #if !defined(S_IFDIR)
55 #   define S_IFDIR _S_IFDIR
56 #endif
57 
58 /* Character device bit */
59 #if !defined(S_IFCHR)
60 #   define S_IFCHR _S_IFCHR
61 #endif
62 
63 /* Pipe bit */
64 #if !defined(S_IFFIFO)
65 #   define S_IFFIFO _S_IFFIFO
66 #endif
67 
68 /* Regular file bit */
69 #if !defined(S_IFREG)
70 #   define S_IFREG _S_IFREG
71 #endif
72 
73 /* Read permission */
74 #if !defined(S_IREAD)
75 #   define S_IREAD _S_IREAD
76 #endif
77 
78 /* Write permission */
79 #if !defined(S_IWRITE)
80 #   define S_IWRITE _S_IWRITE
81 #endif
82 
83 /* Execute permission */
84 #if !defined(S_IEXEC)
85 #   define S_IEXEC _S_IEXEC
86 #endif
87 
88 /* Pipe */
89 #if !defined(S_IFIFO)
90 #   define S_IFIFO _S_IFIFO
91 #endif
92 
93 /* Block device */
94 #if !defined(S_IFBLK)
95 #   define S_IFBLK 0
96 #endif
97 
98 /* Link */
99 #if !defined(S_IFLNK)
100 #   define S_IFLNK 0
101 #endif
102 
103 /* Socket */
104 #if !defined(S_IFSOCK)
105 #   define S_IFSOCK 0
106 #endif
107 
108 /* Read user permission */
109 #if !defined(S_IRUSR)
110 #   define S_IRUSR S_IREAD
111 #endif
112 
113 /* Write user permission */
114 #if !defined(S_IWUSR)
115 #   define S_IWUSR S_IWRITE
116 #endif
117 
118 /* Execute user permission */
119 #if !defined(S_IXUSR)
120 #   define S_IXUSR 0
121 #endif
122 
123 /* Read group permission */
124 #if !defined(S_IRGRP)
125 #   define S_IRGRP 0
126 #endif
127 
128 /* Write group permission */
129 #if !defined(S_IWGRP)
130 #   define S_IWGRP 0
131 #endif
132 
133 /* Execute group permission */
134 #if !defined(S_IXGRP)
135 #   define S_IXGRP 0
136 #endif
137 
138 /* Read others permission */
139 #if !defined(S_IROTH)
140 #   define S_IROTH 0
141 #endif
142 
143 /* Write others permission */
144 #if !defined(S_IWOTH)
145 #   define S_IWOTH 0
146 #endif
147 
148 /* Execute others permission */
149 #if !defined(S_IXOTH)
150 #   define S_IXOTH 0
151 #endif
152 
153 /* Maximum length of file name */
154 #if !defined(PATH_MAX)
155 #   define PATH_MAX MAX_PATH
156 #endif
157 #if !defined(FILENAME_MAX)
158 #   define FILENAME_MAX MAX_PATH
159 #endif
160 #if !defined(NAME_MAX)
161 #   define NAME_MAX FILENAME_MAX
162 #endif
163 
164 /* File type flags for d_type */
165 #define DT_UNKNOWN 0
166 #define DT_REG S_IFREG
167 #define DT_DIR S_IFDIR
168 #define DT_FIFO S_IFIFO
169 #define DT_SOCK S_IFSOCK
170 #define DT_CHR S_IFCHR
171 #define DT_BLK S_IFBLK
172 #define DT_LNK S_IFLNK
173 
174 /* Macros for converting between st_mode and d_type */
175 #define IFTODT(mode) ((mode) & S_IFMT)
176 #define DTTOIF(type) (type)
177 
178 /*
179  * File type macros.  Note that block devices, sockets and links cannot be
180  * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
181  * only defined for compatibility.  These macros should always return false
182  * on Windows.
183  */
184 #if !defined(S_ISFIFO)
185 #   define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
186 #endif
187 #if !defined(S_ISDIR)
188 #   define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
189 #endif
190 #if !defined(S_ISREG)
191 #   define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
192 #endif
193 #if !defined(S_ISLNK)
194 #   define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
195 #endif
196 #if !defined(S_ISSOCK)
197 #   define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
198 #endif
199 #if !defined(S_ISCHR)
200 #   define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
201 #endif
202 #if !defined(S_ISBLK)
203 #   define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
204 #endif
205 
206 /* Return the exact length of d_namlen without zero terminator */
207 #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
208 
209 /* Return number of bytes needed to store d_namlen */
210 #define _D_ALLOC_NAMLEN(p) (PATH_MAX)
211 
212 
213 #ifdef __cplusplus
214 extern "C" {
215 #endif
216 
217 
218 /* Wide-character version */
219 struct _wdirent {
220     /* Always zero */
221     long d_ino;
222 
223     /* Structure size */
224     unsigned short d_reclen;
225 
226     /* Length of name without \0 */
227     size_t d_namlen;
228 
229     /* File type */
230     int d_type;
231 
232     /* File name */
233     wchar_t d_name[PATH_MAX];
234 };
235 typedef struct _wdirent _wdirent;
236 
237 struct _WDIR {
238     /* Current directory entry */
239     struct _wdirent ent;
240 
241     /* Private file data */
242     WIN32_FIND_DATAW data;
243 
244     /* True if data is valid */
245     int cached;
246 
247     /* Win32 search handle */
248     HANDLE handle;
249 
250     /* Initial directory name */
251     wchar_t *patt;
252 };
253 typedef struct _WDIR _WDIR;
254 
255 static _WDIR *_wopendir (const wchar_t *dirname);
256 static struct _wdirent *_wreaddir (_WDIR *dirp);
257 static int _wclosedir (_WDIR *dirp);
258 static void _wrewinddir (_WDIR* dirp);
259 
260 
261 /* For compatibility with Symbian */
262 #define wdirent _wdirent
263 #define WDIR _WDIR
264 #define wopendir _wopendir
265 #define wreaddir _wreaddir
266 #define wclosedir _wclosedir
267 #define wrewinddir _wrewinddir
268 
269 
270 /* Multi-byte character versions */
271 struct dirent {
272     /* Always zero */
273     long d_ino;
274 
275     /* Structure size */
276     unsigned short d_reclen;
277 
278     /* Length of name without \0 */
279     size_t d_namlen;
280 
281     /* File type */
282     int d_type;
283 
284     /* File name */
285     char d_name[PATH_MAX];
286 };
287 typedef struct dirent dirent;
288 
289 struct DIR {
290     struct dirent ent;
291     struct _WDIR *wdirp;
292 };
293 typedef struct DIR DIR;
294 
295 static DIR *opendir (const char *dirname);
296 static struct dirent *readdir (DIR *dirp);
297 static int closedir (DIR *dirp);
298 static void rewinddir (DIR* dirp);
299 
300 
301 /* Internal utility functions */
302 static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
303 static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
304 
305 static int dirent_mbstowcs_s(
306     size_t *pReturnValue,
307     wchar_t *wcstr,
308     size_t sizeInWords,
309     const char *mbstr,
310     size_t count);
311 
312 static int dirent_wcstombs_s(
313     size_t *pReturnValue,
314     char *mbstr,
315     size_t sizeInBytes,
316     const wchar_t *wcstr,
317     size_t count);
318 
319 static void dirent_set_errno (int error);
320 
321 /*
322  * Open directory stream DIRNAME for read and return a pointer to the
323  * internal working area that is used to retrieve individual directory
324  * entries.
325  */
326 static _WDIR*
_wopendir(const wchar_t * dirname)327 _wopendir(
328     const wchar_t *dirname)
329 {
330     _WDIR *dirp = NULL;
331     int error;
332 
333     /* Must have directory name */
334     if (dirname == NULL  ||  dirname[0] == '\0') {
335         dirent_set_errno (ENOENT);
336         return NULL;
337     }
338 
339     /* Allocate new _WDIR structure */
340     dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
341     if (dirp != NULL) {
342         DWORD n;
343 
344         /* Reset _WDIR structure */
345         dirp->handle = INVALID_HANDLE_VALUE;
346         dirp->patt = NULL;
347         dirp->cached = 0;
348 
349         /* Compute the length of full path plus zero terminator */
350         n = GetFullPathNameW (dirname, 0, NULL, NULL);
351 
352         /* Allocate room for absolute directory name and search pattern */
353         dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
354         if (dirp->patt) {
355 
356             /*
357              * Convert relative directory name to an absolute one.  This
358              * allows rewinddir() to function correctly even when current
359              * working directory is changed between opendir() and rewinddir().
360              */
361             n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
362             if (n > 0) {
363                 wchar_t *p;
364 
365                 /* Append search pattern \* to the directory name */
366                 p = dirp->patt + n;
367                 if (dirp->patt < p) {
368                     switch (p[-1]) {
369                     case '\\':
370                     case '/':
371                     case ':':
372                         /* Directory ends in path separator, e.g. c:\temp\ */
373                         /*NOP*/;
374                         break;
375 
376                     default:
377                         /* Directory name doesn't end in path separator */
378                         *p++ = '\\';
379                     }
380                 }
381                 *p++ = '*';
382                 *p = '\0';
383 
384                 /* Open directory stream and retrieve the first entry */
385                 if (dirent_first (dirp)) {
386                     /* Directory stream opened successfully */
387                     error = 0;
388                 } else {
389                     /* Cannot retrieve first entry */
390                     error = 1;
391                     dirent_set_errno (ENOENT);
392                 }
393 
394             } else {
395                 /* Cannot retrieve full path name */
396                 dirent_set_errno (ENOENT);
397                 error = 1;
398             }
399 
400         } else {
401             /* Cannot allocate memory for search pattern */
402             error = 1;
403         }
404 
405     } else {
406         /* Cannot allocate _WDIR structure */
407         error = 1;
408     }
409 
410     /* Clean up in case of error */
411     if (error  &&  dirp) {
412         _wclosedir (dirp);
413         dirp = NULL;
414     }
415 
416     return dirp;
417 }
418 
419 /*
420  * Read next directory entry.  The directory entry is returned in dirent
421  * structure in the d_name field.  Individual directory entries returned by
422  * this function include regular files, sub-directories, pseudo-directories
423  * "." and ".." as well as volume labels, hidden files and system files.
424  */
425 static struct _wdirent*
_wreaddir(_WDIR * dirp)426 _wreaddir(
427     _WDIR *dirp)
428 {
429     WIN32_FIND_DATAW *datap;
430     struct _wdirent *entp;
431 
432     /* Read next directory entry */
433     datap = dirent_next (dirp);
434     if (datap) {
435         size_t n;
436         DWORD attr;
437 
438         /* Pointer to directory entry to return */
439         entp = &dirp->ent;
440 
441         /*
442          * Copy file name as wide-character string.  If the file name is too
443          * long to fit in to the destination buffer, then truncate file name
444          * to PATH_MAX characters and zero-terminate the buffer.
445          */
446         n = 0;
447         while (n + 1 < PATH_MAX  &&  datap->cFileName[n] != 0) {
448             entp->d_name[n] = datap->cFileName[n];
449             n++;
450         }
451         dirp->ent.d_name[n] = 0;
452 
453         /* Length of file name excluding zero terminator */
454         entp->d_namlen = n;
455 
456         /* File type */
457         attr = datap->dwFileAttributes;
458         if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
459             entp->d_type = DT_CHR;
460         } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
461             entp->d_type = DT_DIR;
462         } else {
463             entp->d_type = DT_REG;
464         }
465 
466         /* Reset dummy fields */
467         entp->d_ino = 0;
468         entp->d_reclen = sizeof (struct _wdirent);
469 
470     } else {
471 
472         /* Last directory entry read */
473         entp = NULL;
474 
475     }
476 
477     return entp;
478 }
479 
480 /*
481  * Close directory stream opened by opendir() function.  This invalidates the
482  * DIR structure as well as any directory entry read previously by
483  * _wreaddir().
484  */
485 static int
_wclosedir(_WDIR * dirp)486 _wclosedir(
487     _WDIR *dirp)
488 {
489     int ok;
490     if (dirp) {
491 
492         /* Release search handle */
493         if (dirp->handle != INVALID_HANDLE_VALUE) {
494             FindClose (dirp->handle);
495             dirp->handle = INVALID_HANDLE_VALUE;
496         }
497 
498         /* Release search pattern */
499         if (dirp->patt) {
500             free (dirp->patt);
501             dirp->patt = NULL;
502         }
503 
504         /* Release directory structure */
505         free (dirp);
506         ok = /*success*/0;
507 
508     } else {
509         /* Invalid directory stream */
510         dirent_set_errno (EBADF);
511         ok = /*failure*/-1;
512     }
513     return ok;
514 }
515 
516 /*
517  * Rewind directory stream such that _wreaddir() returns the very first
518  * file name again.
519  */
520 static void
_wrewinddir(_WDIR * dirp)521 _wrewinddir(
522     _WDIR* dirp)
523 {
524     if (dirp) {
525         /* Release existing search handle */
526         if (dirp->handle != INVALID_HANDLE_VALUE) {
527             FindClose (dirp->handle);
528         }
529 
530         /* Open new search handle */
531         dirent_first (dirp);
532     }
533 }
534 
535 /* Get first directory entry (internal) */
536 static WIN32_FIND_DATAW*
dirent_first(_WDIR * dirp)537 dirent_first(
538     _WDIR *dirp)
539 {
540     WIN32_FIND_DATAW *datap;
541 
542     /* Open directory and retrieve the first entry */
543     dirp->handle = FindFirstFileW (dirp->patt, &dirp->data);
544     if (dirp->handle != INVALID_HANDLE_VALUE) {
545 
546         /* a directory entry is now waiting in memory */
547         datap = &dirp->data;
548         dirp->cached = 1;
549 
550     } else {
551 
552         /* Failed to re-open directory: no directory entry in memory */
553         dirp->cached = 0;
554         datap = NULL;
555 
556     }
557     return datap;
558 }
559 
560 /* Get next directory entry (internal) */
561 static WIN32_FIND_DATAW*
dirent_next(_WDIR * dirp)562 dirent_next(
563     _WDIR *dirp)
564 {
565     WIN32_FIND_DATAW *p;
566 
567     /* Get next directory entry */
568     if (dirp->cached != 0) {
569 
570         /* A valid directory entry already in memory */
571         p = &dirp->data;
572         dirp->cached = 0;
573 
574     } else if (dirp->handle != INVALID_HANDLE_VALUE) {
575 
576         /* Get the next directory entry from stream */
577         if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
578             /* Got a file */
579             p = &dirp->data;
580         } else {
581             /* The very last entry has been processed or an error occured */
582             FindClose (dirp->handle);
583             dirp->handle = INVALID_HANDLE_VALUE;
584             p = NULL;
585         }
586 
587     } else {
588 
589         /* End of directory stream reached */
590         p = NULL;
591 
592     }
593 
594     return p;
595 }
596 
597 /*
598  * Open directory stream using plain old C-string.
599  */
600 static DIR*
opendir(const char * dirname)601 opendir(
602     const char *dirname)
603 {
604     struct DIR *dirp;
605     int error;
606 
607     /* Must have directory name */
608     if (dirname == NULL  ||  dirname[0] == '\0') {
609         dirent_set_errno (ENOENT);
610         return NULL;
611     }
612 
613     /* Allocate memory for DIR structure */
614     dirp = (DIR*) malloc (sizeof (struct DIR));
615     if (dirp) {
616         wchar_t wname[PATH_MAX];
617         size_t n;
618 
619         /* Convert directory name to wide-character string */
620         error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX);
621         if (!error) {
622 
623             /* Open directory stream using wide-character name */
624             dirp->wdirp = _wopendir (wname);
625             if (dirp->wdirp) {
626                 /* Directory stream opened */
627                 error = 0;
628             } else {
629                 /* Failed to open directory stream */
630                 error = 1;
631             }
632 
633         } else {
634             /*
635              * Cannot convert file name to wide-character string.  This
636              * occurs if the string contains invalid multi-byte sequences or
637              * the output buffer is too small to contain the resulting
638              * string.
639              */
640             error = 1;
641         }
642 
643     } else {
644         /* Cannot allocate DIR structure */
645         error = 1;
646     }
647 
648     /* Clean up in case of error */
649     if (error  &&  dirp) {
650         free (dirp);
651         dirp = NULL;
652     }
653 
654     return dirp;
655 }
656 
657 /*
658  * Read next directory entry.
659  *
660  * When working with text consoles, please note that file names returned by
661  * readdir() are represented in the default ANSI code page while any output to
662  * console is typically formatted on another code page.  Thus, non-ASCII
663  * characters in file names will not usually display correctly on console.  The
664  * problem can be fixed in two ways: (1) change the character set of console
665  * to 1252 using chcp utility and use Lucida Console font, or (2) use
666  * _cprintf function when writing to console.  The _cprinf() will re-encode
667  * ANSI strings to the console code page so many non-ASCII characters will
668  * display correcly.
669  */
670 static struct dirent*
readdir(DIR * dirp)671 readdir(
672     DIR *dirp)
673 {
674     WIN32_FIND_DATAW *datap;
675     struct dirent *entp;
676 
677     /* Read next directory entry */
678     datap = dirent_next (dirp->wdirp);
679     if (datap) {
680         size_t n;
681         int error;
682 
683         /* Attempt to convert file name to multi-byte string */
684         error = dirent_wcstombs_s(
685             &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
686 
687         /*
688          * If the file name cannot be represented by a multi-byte string,
689          * then attempt to use old 8+3 file name.  This allows traditional
690          * Unix-code to access some file names despite of unicode
691          * characters, although file names may seem unfamiliar to the user.
692          *
693          * Be ware that the code below cannot come up with a short file
694          * name unless the file system provides one.  At least
695          * VirtualBox shared folders fail to do this.
696          */
697         if (error  &&  datap->cAlternateFileName[0] != '\0') {
698             error = dirent_wcstombs_s(
699                 &n, dirp->ent.d_name, PATH_MAX,
700                 datap->cAlternateFileName, PATH_MAX);
701         }
702 
703         if (!error) {
704             DWORD attr;
705 
706             /* Initialize directory entry for return */
707             entp = &dirp->ent;
708 
709             /* Length of file name excluding zero terminator */
710             entp->d_namlen = n - 1;
711 
712             /* File attributes */
713             attr = datap->dwFileAttributes;
714             if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
715                 entp->d_type = DT_CHR;
716             } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
717                 entp->d_type = DT_DIR;
718             } else {
719                 entp->d_type = DT_REG;
720             }
721 
722             /* Reset dummy fields */
723             entp->d_ino = 0;
724             entp->d_reclen = sizeof (struct dirent);
725 
726         } else {
727             /*
728              * Cannot convert file name to multi-byte string so construct
729              * an errornous directory entry and return that.  Note that
730              * we cannot return NULL as that would stop the processing
731              * of directory entries completely.
732              */
733             entp = &dirp->ent;
734             entp->d_name[0] = '?';
735             entp->d_name[1] = '\0';
736             entp->d_namlen = 1;
737             entp->d_type = DT_UNKNOWN;
738             entp->d_ino = 0;
739             entp->d_reclen = 0;
740         }
741 
742     } else {
743         /* No more directory entries */
744         entp = NULL;
745     }
746 
747     return entp;
748 }
749 
750 /*
751  * Close directory stream.
752  */
753 static int
closedir(DIR * dirp)754 closedir(
755     DIR *dirp)
756 {
757     int ok;
758     if (dirp) {
759 
760         /* Close wide-character directory stream */
761         ok = _wclosedir (dirp->wdirp);
762         dirp->wdirp = NULL;
763 
764         /* Release multi-byte character version */
765         free (dirp);
766 
767     } else {
768 
769         /* Invalid directory stream */
770         dirent_set_errno (EBADF);
771         ok = /*failure*/-1;
772 
773     }
774     return ok;
775 }
776 
777 /*
778  * Rewind directory stream to beginning.
779  */
780 static void
rewinddir(DIR * dirp)781 rewinddir(
782     DIR* dirp)
783 {
784     /* Rewind wide-character string directory stream */
785     _wrewinddir (dirp->wdirp);
786 }
787 
788 /* Convert multi-byte string to wide character string */
789 static int
dirent_mbstowcs_s(size_t * pReturnValue,wchar_t * wcstr,size_t sizeInWords,const char * mbstr,size_t count)790 dirent_mbstowcs_s(
791     size_t *pReturnValue,
792     wchar_t *wcstr,
793     size_t sizeInWords,
794     const char *mbstr,
795     size_t count)
796 {
797     int error;
798 
799 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
800 
801     /* Microsoft Visual Studio 2005 or later */
802     error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
803 
804 #else
805 
806     /* Older Visual Studio or non-Microsoft compiler */
807     size_t n;
808 
809     /* Convert to wide-character string (or count characters) */
810     n = mbstowcs (wcstr, mbstr, sizeInWords);
811     if (!wcstr  ||  n < count) {
812 
813         /* Zero-terminate output buffer */
814         if (wcstr  &&  sizeInWords) {
815             if (n >= sizeInWords) {
816                 n = sizeInWords - 1;
817             }
818             wcstr[n] = 0;
819         }
820 
821         /* Length of resuting multi-byte string WITH zero terminator */
822         if (pReturnValue) {
823             *pReturnValue = n + 1;
824         }
825 
826         /* Success */
827         error = 0;
828 
829     } else {
830 
831         /* Could not convert string */
832         error = 1;
833 
834     }
835 
836 #endif
837 
838     return error;
839 }
840 
841 /* Convert wide-character string to multi-byte string */
842 static int
dirent_wcstombs_s(size_t * pReturnValue,char * mbstr,size_t sizeInBytes,const wchar_t * wcstr,size_t count)843 dirent_wcstombs_s(
844     size_t *pReturnValue,
845     char *mbstr,
846     size_t sizeInBytes, /* max size of mbstr */
847     const wchar_t *wcstr,
848     size_t count)
849 {
850     int error;
851 
852 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
853 
854     /* Microsoft Visual Studio 2005 or later */
855     error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
856 
857 #else
858 
859     /* Older Visual Studio or non-Microsoft compiler */
860     size_t n;
861 
862     /* Convert to multi-byte string (or count the number of bytes needed) */
863     n = wcstombs (mbstr, wcstr, sizeInBytes);
864     if (!mbstr  ||  n < count) {
865 
866         /* Zero-terminate output buffer */
867         if (mbstr  &&  sizeInBytes) {
868             if (n >= sizeInBytes) {
869                 n = sizeInBytes - 1;
870             }
871             mbstr[n] = '\0';
872         }
873 
874         /* Lenght of resulting multi-bytes string WITH zero-terminator */
875         if (pReturnValue) {
876             *pReturnValue = n + 1;
877         }
878 
879         /* Success */
880         error = 0;
881 
882     } else {
883 
884         /* Cannot convert string */
885         error = 1;
886 
887     }
888 
889 #endif
890 
891     return error;
892 }
893 
894 /* Set errno variable */
895 static void
dirent_set_errno(int error)896 dirent_set_errno(
897     int error)
898 {
899 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
900 
901     /* Microsoft Visual Studio 2005 and later */
902     _set_errno (error);
903 
904 #else
905 
906     /* Non-Microsoft compiler or older Microsoft compiler */
907     errno = error;
908 
909 #endif
910 }
911 
912 
913 #ifdef __cplusplus
914 }
915 #endif
916 #endif /*DIRENT_H*/
917 
918