diff options
Diffstat (limited to 'win32/dirent.c')
-rw-r--r-- | win32/dirent.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/win32/dirent.c b/win32/dirent.c new file mode 100644 index 000000000..b7de19391 --- /dev/null +++ b/win32/dirent.c | |||
@@ -0,0 +1,96 @@ | |||
1 | #include "libbb.h" | ||
2 | |||
3 | struct DIR { | ||
4 | struct dirent dd_dir; | ||
5 | HANDLE dd_handle; /* FindFirstFile handle */ | ||
6 | int dd_stat; /* 0-based index */ | ||
7 | }; | ||
8 | |||
9 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) | ||
10 | { | ||
11 | /* copy file name from WIN32_FIND_DATA to dirent */ | ||
12 | strcpy(ent->d_name, fdata->cFileName); | ||
13 | } | ||
14 | |||
15 | DIR *opendir(const char *name) | ||
16 | { | ||
17 | char pattern[MAX_PATH]; | ||
18 | WIN32_FIND_DATAA fdata; | ||
19 | HANDLE h; | ||
20 | int len; | ||
21 | DIR *dir; | ||
22 | |||
23 | /* check that name is not NULL */ | ||
24 | if (!name) { | ||
25 | errno = EINVAL; | ||
26 | return NULL; | ||
27 | } | ||
28 | /* check that the pattern won't be too long for FindFirstFileA */ | ||
29 | len = strlen(name); | ||
30 | if (len + 2 >= MAX_PATH) { | ||
31 | errno = ENAMETOOLONG; | ||
32 | return NULL; | ||
33 | } | ||
34 | /* copy name to temp buffer */ | ||
35 | strcpy(pattern, name); | ||
36 | |||
37 | /* append optional '/' and wildcard '*' */ | ||
38 | if (len && !is_dir_sep(pattern[len - 1])) | ||
39 | pattern[len++] = '/'; | ||
40 | pattern[len++] = '*'; | ||
41 | pattern[len] = 0; | ||
42 | |||
43 | /* open find handle */ | ||
44 | h = FindFirstFileA(pattern, &fdata); | ||
45 | if (h == INVALID_HANDLE_VALUE) { | ||
46 | DWORD err = GetLastError(); | ||
47 | errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(); | ||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | /* initialize DIR structure and copy first dir entry */ | ||
52 | dir = xmalloc(sizeof(DIR)); | ||
53 | dir->dd_handle = h; | ||
54 | dir->dd_stat = 0; | ||
55 | finddata2dirent(&dir->dd_dir, &fdata); | ||
56 | return dir; | ||
57 | } | ||
58 | |||
59 | struct dirent *readdir(DIR *dir) | ||
60 | { | ||
61 | if (!dir) { | ||
62 | errno = EBADF; /* No set_errno for mingw */ | ||
63 | return NULL; | ||
64 | } | ||
65 | |||
66 | /* if first entry, dirent has already been set up by opendir */ | ||
67 | if (dir->dd_stat) { | ||
68 | /* get next entry and convert from WIN32_FIND_DATA to dirent */ | ||
69 | WIN32_FIND_DATAA fdata; | ||
70 | if (FindNextFileA(dir->dd_handle, &fdata)) { | ||
71 | finddata2dirent(&dir->dd_dir, &fdata); | ||
72 | } else { | ||
73 | DWORD lasterr = GetLastError(); | ||
74 | /* POSIX says you shouldn't set errno when readdir can't | ||
75 | find any more files; so, if another error we leave it set. */ | ||
76 | if (lasterr != ERROR_NO_MORE_FILES) | ||
77 | errno = err_win_to_posix(); | ||
78 | return NULL; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | ++dir->dd_stat; | ||
83 | return &dir->dd_dir; | ||
84 | } | ||
85 | |||
86 | int closedir(DIR *dir) | ||
87 | { | ||
88 | if (!dir) { | ||
89 | errno = EBADF; | ||
90 | return -1; | ||
91 | } | ||
92 | |||
93 | FindClose(dir->dd_handle); | ||
94 | free(dir); | ||
95 | return 0; | ||
96 | } | ||