]>
Commit | Line | Data |
---|---|---|
a8248f4a | 1 | #include "../../git-compat-util.h" |
d1b6e6e0 EFL |
2 | |
3 | struct DIR { | |
4 | struct dirent dd_dir; /* includes d_type */ | |
5 | HANDLE dd_handle; /* FindFirstFile handle */ | |
6 | int dd_stat; /* 0-based index */ | |
d1b6e6e0 EFL |
7 | }; |
8 | ||
0217569b | 9 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata) |
d8890ce7 | 10 | { |
0217569b KB |
11 | /* convert UTF-16 name to UTF-8 */ |
12 | xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name)); | |
d8890ce7 KB |
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 | ||
d1b6e6e0 EFL |
21 | DIR *opendir(const char *name) |
22 | { | |
0217569b KB |
23 | wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */ |
24 | WIN32_FIND_DATAW fdata; | |
d8890ce7 | 25 | HANDLE h; |
d1b6e6e0 | 26 | int len; |
d8890ce7 | 27 | DIR *dir; |
d1b6e6e0 | 28 | |
0217569b KB |
29 | /* convert name to UTF-16 and check length < MAX_PATH */ |
30 | if ((len = xutftowcs_path(pattern, name)) < 0) | |
d1b6e6e0 | 31 | return NULL; |
d8890ce7 KB |
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 */ | |
0217569b | 40 | h = FindFirstFileW(pattern, &fdata); |
d8890ce7 KB |
41 | if (h == INVALID_HANDLE_VALUE) { |
42 | DWORD err = GetLastError(); | |
43 | errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); | |
d1b6e6e0 | 44 | return NULL; |
d8890ce7 | 45 | } |
d1b6e6e0 | 46 | |
d8890ce7 KB |
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; | |
d1b6e6e0 EFL |
53 | } |
54 | ||
55 | struct dirent *readdir(DIR *dir) | |
56 | { | |
d8890ce7 | 57 | if (!dir) { |
d1b6e6e0 EFL |
58 | errno = EBADF; /* No set_errno for mingw */ |
59 | return NULL; | |
60 | } | |
61 | ||
d8890ce7 KB |
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 */ | |
0217569b KB |
65 | WIN32_FIND_DATAW fdata; |
66 | if (FindNextFileW(dir->dd_handle, &fdata)) { | |
d8890ce7 KB |
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); | |
d1b6e6e0 EFL |
74 | return NULL; |
75 | } | |
d1b6e6e0 EFL |
76 | } |
77 | ||
d1b6e6e0 | 78 | ++dir->dd_stat; |
d1b6e6e0 EFL |
79 | return &dir->dd_dir; |
80 | } | |
81 | ||
82 | int closedir(DIR *dir) | |
83 | { | |
84 | if (!dir) { | |
85 | errno = EBADF; | |
86 | return -1; | |
87 | } | |
88 | ||
d8890ce7 | 89 | FindClose(dir->dd_handle); |
d1b6e6e0 EFL |
90 | free(dir); |
91 | return 0; | |
92 | } |