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