readdir.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #include <malloc.h>
  2. #include <string.h>
  3. #include <errno.h>
  4. #include "php.h"
  5. #include "readdir.h"
  6. #include "win32/ioutil.h"
  7. /**********************************************************************
  8. * Implement dirent-style opendir/readdir/rewinddir/closedir on Win32
  9. *
  10. * Functions defined are opendir(), readdir(), rewinddir() and
  11. * closedir() with the same prototypes as the normal dirent.h
  12. * implementation.
  13. *
  14. * Does not implement telldir(), seekdir(), or scandir(). The dirent
  15. * struct is compatible with Unix, except that d_ino is always 1 and
  16. * d_off is made up as we go along.
  17. *
  18. * The DIR typedef is not compatible with Unix.
  19. **********************************************************************/
  20. #ifdef __cplusplus
  21. extern "C" {
  22. #endif
  23. DIR *opendir(const char *dir)
  24. {/*{{{*/
  25. DIR *dp;
  26. wchar_t *filespecw, *resolvedw;
  27. HANDLE handle;
  28. char resolved_path_buff[MAXPATHLEN];
  29. size_t resolvedw_len, filespecw_len, index;
  30. zend_bool might_need_prefix;
  31. if (!VCWD_REALPATH(dir, resolved_path_buff)) {
  32. return NULL;
  33. }
  34. resolvedw = php_win32_ioutil_conv_any_to_w(resolved_path_buff, PHP_WIN32_CP_IGNORE_LEN, &resolvedw_len);
  35. if (!resolvedw) {
  36. return NULL;
  37. }
  38. might_need_prefix = resolvedw_len >= 3 && PHP_WIN32_IOUTIL_IS_LETTERW(resolvedw[0]) && L':' == resolvedw[1] && PHP_WIN32_IOUTIL_IS_SLASHW(resolvedw[2]);
  39. filespecw_len = resolvedw_len + 2;
  40. if (filespecw_len >= _MAX_PATH && might_need_prefix) {
  41. filespecw_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
  42. }
  43. filespecw = (wchar_t *)malloc((filespecw_len + 1)*sizeof(wchar_t));
  44. if (filespecw == NULL) {
  45. free(resolvedw);
  46. return NULL;
  47. }
  48. if (filespecw_len >= _MAX_PATH && might_need_prefix) {
  49. wcscpy(filespecw, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW);
  50. wcscpy(filespecw + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, resolvedw);
  51. index = resolvedw_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW - 1;
  52. } else {
  53. wcscpy(filespecw, resolvedw);
  54. index = resolvedw_len - 1;
  55. }
  56. if (index >= 0 && filespecw[index] == L'/' || index == 0 && filespecw[index] == L'\\')
  57. filespecw[index] = L'\0';
  58. wcscat(filespecw, L"\\*");
  59. dp = (DIR *) calloc(1, sizeof(DIR) + (_MAX_FNAME*5+1)*sizeof(char));
  60. if (dp == NULL) {
  61. free(filespecw);
  62. free(resolvedw);
  63. return NULL;
  64. }
  65. if ((handle = FindFirstFileExW(filespecw, FindExInfoBasic, &(dp->fileinfo), FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH)) == INVALID_HANDLE_VALUE) {
  66. DWORD err = GetLastError();
  67. if (err == ERROR_NO_MORE_FILES || err == ERROR_FILE_NOT_FOUND) {
  68. dp->finished = 1;
  69. } else {
  70. free(dp);
  71. free(filespecw);
  72. free(resolvedw);
  73. return NULL;
  74. }
  75. }
  76. dp->dirw = _wcsdup(resolvedw);
  77. dp->handle = handle;
  78. dp->offset = 0;
  79. dp->finished = 0;
  80. free(filespecw);
  81. free(resolvedw);
  82. return dp;
  83. }/*}}}*/
  84. struct dirent *readdir(DIR *dp)
  85. {/*{{{*/
  86. char *_tmp;
  87. size_t reclen;
  88. if (!dp || dp->finished)
  89. return NULL;
  90. if (dp->offset != 0) {
  91. if (FindNextFileW(dp->handle, &(dp->fileinfo)) == 0) {
  92. dp->finished = 1;
  93. return NULL;
  94. }
  95. }
  96. _tmp = php_win32_cp_conv_w_to_any(dp->fileinfo.cFileName, PHP_WIN32_CP_IGNORE_LEN, &reclen);
  97. if (!_tmp) {
  98. /* wide to utf8 failed, should never happen. */
  99. return NULL;
  100. }
  101. memmove(dp->dent.d_name, _tmp, reclen + 1);
  102. free(_tmp);
  103. dp->dent.d_reclen = (unsigned short)reclen;
  104. dp->offset++;
  105. dp->dent.d_ino = 1;
  106. dp->dent.d_off = dp->offset;
  107. return &(dp->dent);
  108. }/*}}}*/
  109. int readdir_r(DIR *dp, struct dirent *entry, struct dirent **result)
  110. {/*{{{*/
  111. char *_tmp;
  112. size_t reclen;
  113. if (!dp || dp->finished) {
  114. *result = NULL;
  115. return 0;
  116. }
  117. if (dp->offset != 0) {
  118. if (FindNextFileW(dp->handle, &(dp->fileinfo)) == 0) {
  119. dp->finished = 1;
  120. *result = NULL;
  121. return 0;
  122. }
  123. }
  124. _tmp = php_win32_cp_conv_w_to_any(dp->fileinfo.cFileName, PHP_WIN32_CP_IGNORE_LEN, &reclen);
  125. if (!_tmp) {
  126. /* wide to utf8 failed, should never happen. */
  127. result = NULL;
  128. return 0;
  129. }
  130. memmove(dp->dent.d_name, _tmp, reclen + 1);
  131. free(_tmp);
  132. dp->dent.d_reclen = (unsigned short)reclen;
  133. dp->offset++;
  134. dp->dent.d_ino = 1;
  135. dp->dent.d_off = dp->offset;
  136. memcpy(entry, &dp->dent, sizeof(*entry));
  137. *result = &dp->dent;
  138. return 0;
  139. }/*}}}*/
  140. int closedir(DIR *dp)
  141. {/*{{{*/
  142. if (!dp)
  143. return 0;
  144. /* It is valid to scan an empty directory but we have an invalid
  145. handle in this case (no first file found). */
  146. if (dp->handle != INVALID_HANDLE_VALUE) {
  147. FindClose(dp->handle);
  148. }
  149. if (dp->dirw)
  150. free(dp->dirw);
  151. if (dp)
  152. free(dp);
  153. return 0;
  154. }/*}}}*/
  155. int rewinddir(DIR *dp)
  156. {/*{{{*/
  157. /* Re-set to the beginning */
  158. wchar_t *filespecw;
  159. HANDLE handle;
  160. size_t dirw_len, filespecw_len, index;
  161. zend_bool might_need_prefix;
  162. FindClose(dp->handle);
  163. dp->offset = 0;
  164. dp->finished = 0;
  165. /* XXX save the dir len into the struct. */
  166. dirw_len = wcslen((wchar_t *)dp->dirw);
  167. might_need_prefix = dirw_len >= 3 && PHP_WIN32_IOUTIL_IS_LETTERW(dp->dirw[0]) && L':' == dp->dirw[1] && PHP_WIN32_IOUTIL_IS_SLASHW(dp->dirw[2]);
  168. filespecw_len = dirw_len + 2;
  169. if (filespecw_len >= _MAX_PATH && might_need_prefix) {
  170. filespecw_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
  171. }
  172. filespecw = (wchar_t *)malloc((filespecw_len + 1)*sizeof(wchar_t));
  173. if (filespecw == NULL) {
  174. return -1;
  175. }
  176. if (filespecw_len >= _MAX_PATH && might_need_prefix) {
  177. wcscpy(filespecw, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW);
  178. wcscpy(filespecw + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, dp->dirw);
  179. index = dirw_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW - 1;
  180. } else {
  181. wcscpy(filespecw, dp->dirw);
  182. index = dirw_len - 1;
  183. }
  184. if (index >= 0 && (filespecw[index] == L'/' ||
  185. (filespecw[index] == L'\\' && index == 0)))
  186. filespecw[index] = L'\0';
  187. wcscat(filespecw, L"\\*");
  188. if ((handle = FindFirstFileExW(filespecw, FindExInfoBasic, &(dp->fileinfo), FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH)) == INVALID_HANDLE_VALUE) {
  189. dp->finished = 1;
  190. }
  191. free(filespecw);
  192. dp->handle = handle;
  193. return 0;
  194. }/*}}}*/
  195. #ifdef __cplusplus
  196. }
  197. #endif
  198. /*
  199. * Local variables:
  200. * tab-width: 4
  201. * c-basic-offset: 4
  202. * End:
  203. * vim600: sw=4 ts=4 fdm=marker
  204. * vim<600: sw=4 ts=4
  205. */