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