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