dirent_win.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <util/system/defaults.h>
  2. #ifdef _win_
  3. #include <stdio.h>
  4. #include "dirent_win.h"
  5. #if defined(_MSC_VER) && (_MSC_VER < 1900)
  6. void __cdecl _dosmaperr(unsigned long);
  7. static void SetErrno() {
  8. _dosmaperr(GetLastError());
  9. }
  10. #else
  11. void __cdecl __acrt_errno_map_os_error(unsigned long const oserrno);
  12. static void SetErrno() {
  13. __acrt_errno_map_os_error(GetLastError());
  14. }
  15. #endif
  16. struct DIR* opendir(const char* dirname) {
  17. struct DIR* dir = (struct DIR*)malloc(sizeof(struct DIR));
  18. if (!dir) {
  19. return NULL;
  20. }
  21. dir->sh = INVALID_HANDLE_VALUE;
  22. dir->fff_templ = NULL;
  23. dir->file_no = 0;
  24. dir->readdir_buf = NULL;
  25. int len = strlen(dirname);
  26. // Remove trailing slashes
  27. while (len && (dirname[len - 1] == '\\' || dirname[len - 1] == '/')) {
  28. --len;
  29. }
  30. int len_converted = MultiByteToWideChar(CP_UTF8, 0, dirname, len, 0, 0);
  31. if (len_converted == 0) {
  32. closedir(dir);
  33. return NULL;
  34. }
  35. dir->fff_templ = (WCHAR*)malloc((len_converted + 5) * sizeof(WCHAR));
  36. if (!dir->fff_templ) {
  37. closedir(dir);
  38. return NULL;
  39. }
  40. MultiByteToWideChar(CP_UTF8, 0, dirname, len, dir->fff_templ, len_converted);
  41. WCHAR append[] = {'\\', '*', '.', '*', 0};
  42. memcpy(dir->fff_templ + len_converted, append, sizeof(append));
  43. dir->sh = FindFirstFileW(dir->fff_templ, &dir->wfd);
  44. if (dir->sh == INVALID_HANDLE_VALUE) {
  45. SetErrno();
  46. closedir(dir);
  47. return NULL;
  48. }
  49. return dir;
  50. }
  51. int closedir(struct DIR* dir) {
  52. if (dir->sh != INVALID_HANDLE_VALUE) {
  53. FindClose(dir->sh);
  54. }
  55. free(dir->fff_templ);
  56. free(dir->readdir_buf);
  57. free(dir);
  58. return 0;
  59. }
  60. int readdir_r(struct DIR* dir, struct dirent* entry, struct dirent** result) {
  61. if (!FindNextFileW(dir->sh, &dir->wfd)) {
  62. int err = GetLastError();
  63. *result = 0;
  64. if (err == ERROR_NO_MORE_FILES) {
  65. SetLastError(0);
  66. return 0;
  67. } else {
  68. return err;
  69. }
  70. }
  71. entry->d_fileno = dir->file_no++;
  72. entry->d_reclen = sizeof(struct dirent);
  73. if (dir->wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
  74. (dir->wfd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT || dir->wfd.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
  75. {
  76. entry->d_type = DT_LNK;
  77. } else if (dir->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  78. entry->d_type = DT_DIR;
  79. } else {
  80. entry->d_type = DT_REG;
  81. }
  82. int len = lstrlenW(dir->wfd.cFileName);
  83. int conv_len = WideCharToMultiByte(CP_UTF8, 0, dir->wfd.cFileName, len, 0, 0, 0, 0);
  84. if (conv_len == 0) {
  85. return -1;
  86. }
  87. if (conv_len > sizeof(entry->d_name) - 1) {
  88. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  89. return ERROR_INSUFFICIENT_BUFFER;
  90. }
  91. entry->d_namlen = conv_len;
  92. WideCharToMultiByte(CP_UTF8, 0, dir->wfd.cFileName, len, entry->d_name, conv_len, 0, 0);
  93. entry->d_name[conv_len] = 0;
  94. *result = entry;
  95. return 0;
  96. }
  97. struct dirent* readdir(struct DIR* dir) {
  98. struct dirent* res;
  99. if (!dir->readdir_buf) {
  100. dir->readdir_buf = (struct dirent*)malloc(sizeof(struct dirent));
  101. if (dir->readdir_buf == 0) {
  102. return 0;
  103. }
  104. }
  105. readdir_r(dir, dir->readdir_buf, &res);
  106. return res;
  107. }
  108. void rewinddir(struct DIR* dir) {
  109. FindClose(dir->sh);
  110. dir->sh = FindFirstFileW(dir->fff_templ, &dir->wfd);
  111. dir->file_no = 0;
  112. }
  113. #endif // _win_