1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#include "libbb.h"
struct DIR {
struct dirent dd_dir;
HANDLE dd_handle; /* FindFirstFile handle */
int not_first;
int got_dot;
int got_dotdot;
};
static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
{
/* copy file name from WIN32_FIND_DATA to dirent */
strcpy(ent->d_name, fdata->cFileName);
if ((fdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
(fdata->dwReserved0 == IO_REPARSE_TAG_SYMLINK ||
fdata->dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT ||
fdata->dwReserved0 == IO_REPARSE_TAG_APPEXECLINK))
ent->d_type = DT_LNK;
else if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ent->d_type = DT_DIR;
else
ent->d_type = DT_REG;
}
DIR * FAST_FUNC opendir(const char *name)
{
char pattern[MAX_PATH];
WIN32_FIND_DATAA fdata;
HANDLE h;
int len;
DIR *dir;
/* check that name is not NULL */
if (!name) {
errno = EINVAL;
return NULL;
}
/* check that the pattern won't be too long for FindFirstFileA */
len = strlen(name);
if (len + 2 >= MAX_PATH) {
errno = ENAMETOOLONG;
return NULL;
}
/* copy name to temp buffer */
strcpy(pattern, name);
/* append optional '/' and wildcard '*' */
if (len && !is_dir_sep(pattern[len - 1]))
pattern[len++] = '/';
pattern[len++] = '*';
pattern[len] = 0;
/* open find handle */
h = mingw_find_first_file(pattern, &fdata);
/* If FindFirstFileA fails on a path that's a volume mount
* don't return an error, instead fake '.' and '..'. */
if (h == INVALID_HANDLE_VALUE && !is_volume_mount(name)) {
DWORD err = GetLastError();
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix();
return NULL;
}
/* initialize DIR structure and copy first dir entry */
dir = xzalloc(sizeof(DIR));
dir->dd_handle = h;
/* dir->not_first = 0; */
/* dir->got_dot = 0; */
/* dir->got_dotdot = 0; */
if (h == INVALID_HANDLE_VALUE)
dir->not_first = 1;
else
finddata2dirent(&dir->dd_dir, &fdata);
return dir;
}
struct dirent * FAST_FUNC readdir(DIR *dir)
{
if (!dir) {
errno = EBADF; /* No set_errno for mingw */
return NULL;
}
/* if first entry, dirent has already been set up by opendir */
if (dir->not_first) {
/* get next entry and convert from WIN32_FIND_DATA to dirent */
WIN32_FIND_DATAA fdata;
/* If the handle is invalid we fake '.' and '..' directories. */
if (dir->dd_handle != INVALID_HANDLE_VALUE &&
FindNextFileA(dir->dd_handle, &fdata)) {
finddata2dirent(&dir->dd_dir, &fdata);
} else if (!dir->got_dot) {
strcpy(dir->dd_dir.d_name, ".");
dir->dd_dir.d_type = DT_DIR;
} else if (!dir->got_dotdot) {
strcpy(dir->dd_dir.d_name, "..");
dir->dd_dir.d_type = DT_DIR;
} else {
DWORD lasterr = GetLastError();
/* POSIX says you shouldn't set errno when readdir can't
find any more files; so, if another error we leave it set. */
if (lasterr != ERROR_NO_MORE_FILES)
errno = err_win_to_posix();
return NULL;
}
}
/* Have we seen '.' or '..'? */
if (dir->dd_dir.d_name[0] == '.') {
if (dir->dd_dir.d_name[1] == '\0')
dir->got_dot = TRUE;
else if (dir->dd_dir.d_name[1] == '.' && dir->dd_dir.d_name[2] == '\0')
dir->got_dotdot = TRUE;
}
dir->not_first = TRUE;
return &dir->dd_dir;
}
int FAST_FUNC closedir(DIR *dir)
{
if (!dir) {
errno = EBADF;
return -1;
}
FindClose(dir->dd_handle);
free(dir);
return 0;
}
|