dirent.h 29 KB

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