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