dirent.h 21 KB

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