4
struct dirent dd_dir; /* includes d_type */
5
HANDLE dd_handle; /* FindFirstFile handle */
6
int dd_stat; /* 0-based index */
7
- char dd_name[1]; /* extend struct */
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
+ memcpy(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
+
21
DIR *opendir(const char *name)
22
{
12
- DWORD attrs = GetFileAttributesA(name);
23
+ char pattern[MAX_PATH];
24
+ WIN32_FIND_DATAA fdata;
25
+ HANDLE h;
26
int len;
14
- DIR *p;
27
+ DIR *dir;
28
16
- /* check for valid path */
17
- if (attrs == INVALID_FILE_ATTRIBUTES) {
18
- errno = ENOENT;
29
+ /* check that name is not NULL */
30
+ if (!name) {
31
+ errno = EINVAL;
32
return NULL;
33
}
21
-
22
- /* check if it's a directory */
23
- if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
24
- errno = ENOTDIR;
25
- return NULL;
26
- }
27
-
34
/* check that the pattern won't be too long for FindFirstFileA */
35
len = strlen(name);
30
- if (is_dir_sep(name[len - 1]))
31
- len--;
36
if (len + 2 >= MAX_PATH) {
37
errno = ENAMETOOLONG;
38
return NULL;
39
}
36
-
37
- p = malloc(sizeof(DIR) + len + 2);
38
- if (!p)
40
+ /* copy name to temp buffer */
41
+ memcpy(pattern, name, len + 1);
42
+
43
+ /* append optional '/' and wildcard '*' */
44
+ if (len && !is_dir_sep(pattern[len - 1]))
45
+ pattern[len++] = '/';
46
+ pattern[len++] = '*';
47
+ pattern[len] = 0;
48
+
49
+ /* open find handle */
50
+ h = FindFirstFileA(pattern, &fdata);
51
+ if (h == INVALID_HANDLE_VALUE) {
52
+ DWORD err = GetLastError();
53
+ errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
54
return NULL;
55
+ }
56
41
- memset(p, 0, sizeof(DIR) + len + 2);
42
- strcpy(p->dd_name, name);
43
- p->dd_name[len] = '/';
44
- p->dd_name[len+1] = '*';
45
-
46
- p->dd_handle = INVALID_HANDLE_VALUE;
47
- return p;
57
+ /* initialize DIR structure and copy first dir entry */
58
+ dir = xmalloc(sizeof(DIR));
59
+ dir->dd_handle = h;
60
+ dir->dd_stat = 0;
61
+ finddata2dirent(&dir->dd_dir, &fdata);
62
+ return dir;
63
}
64
65
struct dirent *readdir(DIR *dir)
66
{
52
- WIN32_FIND_DATAA buf;
53
- HANDLE handle;
54
-
55
- if (!dir || !dir->dd_handle) {
67
+ if (!dir) {
68
errno = EBADF; /* No set_errno for mingw */
69
return NULL;
70
}
71
60
- if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
61
- DWORD lasterr;
62
- handle = FindFirstFileA(dir->dd_name, &buf);
63
- lasterr = GetLastError();
64
- dir->dd_handle = handle;
65
- if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
66
- errno = err_win_to_posix(lasterr);
72
+ /* if first entry, dirent has already been set up by opendir */
73
+ if (dir->dd_stat) {
74
+ /* get next entry and convert from WIN32_FIND_DATA to dirent */
75
+ WIN32_FIND_DATAA fdata;
76
+ if (FindNextFileA(dir->dd_handle, &fdata)) {
77
+ finddata2dirent(&dir->dd_dir, &fdata);
78
+ } else {
79
+ DWORD lasterr = GetLastError();
80
+ /* POSIX says you shouldn't set errno when readdir can't
81
+ find any more files; so, if another error we leave it set. */
82
+ if (lasterr != ERROR_NO_MORE_FILES)
83
+ errno = err_win_to_posix(lasterr);
84
return NULL;
85
}
69
- } else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
70
- return NULL;
71
- } else if (!FindNextFileA(dir->dd_handle, &buf)) {
72
- DWORD lasterr = GetLastError();
73
- FindClose(dir->dd_handle);
74
- dir->dd_handle = INVALID_HANDLE_VALUE;
75
- /* POSIX says you shouldn't set errno when readdir can't
76
- find any more files; so, if another error we leave it set. */
77
- if (lasterr != ERROR_NO_MORE_FILES)
78
- errno = err_win_to_posix(lasterr);
79
- return NULL;
86
}
87
82
- /* We get here if `buf' contains valid data. */
83
- strcpy(dir->dd_dir.d_name, buf.cFileName);
88
++dir->dd_stat;
85
-
86
- /* Set file type, based on WIN32_FIND_DATA */
87
- dir->dd_dir.d_type = 0;
88
- if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
89
- dir->dd_dir.d_type |= DT_DIR;
90
- else
91
- dir->dd_dir.d_type |= DT_REG;
92
-
89
return &dir->dd_dir;
90
}
91
96
return -1;
97
}
98
103
- if (dir->dd_handle != INVALID_HANDLE_VALUE)
104
- FindClose(dir->dd_handle);
99
+ FindClose(dir->dd_handle);
100
free(dir);
101
return 0;
102
}