Git fork
at reftables-rust 92 lines 2.2 kB view raw
1#include "../../git-compat-util.h" 2 3struct DIR { 4 struct dirent dd_dir; /* includes d_type */ 5 HANDLE dd_handle; /* FindFirstFile handle */ 6 int dd_stat; /* 0-based index */ 7}; 8 9static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata) 10{ 11 /* convert UTF-16 name to UTF-8 */ 12 xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name)); 13 14 /* Set file type, based on WIN32_FIND_DATA */ 15 if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 16 ent->d_type = DT_DIR; 17 else 18 ent->d_type = DT_REG; 19} 20 21DIR *opendir(const char *name) 22{ 23 wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */ 24 WIN32_FIND_DATAW fdata; 25 HANDLE h; 26 int len; 27 DIR *dir; 28 29 /* convert name to UTF-16 and check length < MAX_PATH */ 30 if ((len = xutftowcs_path(pattern, name)) < 0) 31 return NULL; 32 33 /* append optional '/' and wildcard '*' */ 34 if (len && !is_dir_sep(pattern[len - 1])) 35 pattern[len++] = '/'; 36 pattern[len++] = '*'; 37 pattern[len] = 0; 38 39 /* open find handle */ 40 h = FindFirstFileW(pattern, &fdata); 41 if (h == INVALID_HANDLE_VALUE) { 42 DWORD err = GetLastError(); 43 errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); 44 return NULL; 45 } 46 47 /* initialize DIR structure and copy first dir entry */ 48 dir = xmalloc(sizeof(DIR)); 49 dir->dd_handle = h; 50 dir->dd_stat = 0; 51 finddata2dirent(&dir->dd_dir, &fdata); 52 return dir; 53} 54 55struct dirent *readdir(DIR *dir) 56{ 57 if (!dir) { 58 errno = EBADF; /* No set_errno for mingw */ 59 return NULL; 60 } 61 62 /* if first entry, dirent has already been set up by opendir */ 63 if (dir->dd_stat) { 64 /* get next entry and convert from WIN32_FIND_DATA to dirent */ 65 WIN32_FIND_DATAW fdata; 66 if (FindNextFileW(dir->dd_handle, &fdata)) { 67 finddata2dirent(&dir->dd_dir, &fdata); 68 } else { 69 DWORD lasterr = GetLastError(); 70 /* POSIX says you shouldn't set errno when readdir can't 71 find any more files; so, if another error we leave it set. */ 72 if (lasterr != ERROR_NO_MORE_FILES) 73 errno = err_win_to_posix(lasterr); 74 return NULL; 75 } 76 } 77 78 ++dir->dd_stat; 79 return &dir->dd_dir; 80} 81 82int closedir(DIR *dir) 83{ 84 if (!dir) { 85 errno = EBADF; 86 return -1; 87 } 88 89 FindClose(dir->dd_handle); 90 free(dir); 91 return 0; 92}