diff options
author | Ron Yorston <rmy@pobox.com> | 2021-06-13 08:13:25 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-06-13 08:13:25 +0100 |
commit | f7e4fe39a69b82bcef1aaa68111ccfa68b209ada (patch) | |
tree | 23d63dd3d27f4fdb6e475c35e348b3c8299e6e6c | |
parent | cfac1da2aaccaf45a669b0a53c82a32c8231827c (diff) | |
download | busybox-w32-f7e4fe39a69b82bcef1aaa68111ccfa68b209ada.tar.gz busybox-w32-f7e4fe39a69b82bcef1aaa68111ccfa68b209ada.tar.bz2 busybox-w32-f7e4fe39a69b82bcef1aaa68111ccfa68b209ada.zip |
win32: add local dirent implementation
Add a cut down version of the dirent implementation from git.
The git developers said:
The mingw-runtime implemenation of opendir, readdir and closedir
sets errno to 0 on success, something that POSIX explicitly
forbids.
This also avoids having to link against libssp.a (commit 13eb34205)
and reduces the size of the binary by 2KB.
-rw-r--r-- | Makefile.flags | 2 | ||||
-rw-r--r-- | win32/Kbuild | 1 | ||||
-rw-r--r-- | win32/dirent.c | 96 | ||||
-rw-r--r-- | win32/dirent.h | 19 |
4 files changed, 117 insertions, 1 deletions
diff --git a/Makefile.flags b/Makefile.flags index 0950ddb0d..2687781f1 100644 --- a/Makefile.flags +++ b/Makefile.flags | |||
@@ -149,7 +149,7 @@ endif | |||
149 | ifeq ($(CONFIG_PLATFORM_MINGW32),y) | 149 | ifeq ($(CONFIG_PLATFORM_MINGW32),y) |
150 | CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup | 150 | CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup |
151 | EXEEXT = .exe | 151 | EXEEXT = .exe |
152 | LDLIBS += ws2_32 mingwex -l:libssp.a | 152 | LDLIBS += ws2_32 |
153 | endif | 153 | endif |
154 | 154 | ||
155 | ifneq ($(CONFIG_PLATFORM_MINGW32),y) | 155 | ifneq ($(CONFIG_PLATFORM_MINGW32),y) |
diff --git a/win32/Kbuild b/win32/Kbuild index f3d0244d2..cabd70849 100644 --- a/win32/Kbuild +++ b/win32/Kbuild | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | lib-y:= | 5 | lib-y:= |
6 | 6 | ||
7 | lib-$(CONFIG_PLATFORM_MINGW32) += dirent.o | ||
7 | lib-$(CONFIG_PLATFORM_MINGW32) += env.o | 8 | lib-$(CONFIG_PLATFORM_MINGW32) += env.o |
8 | lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o | 9 | lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o |
9 | lib-$(CONFIG_PLATFORM_MINGW32) += fsync.o | 10 | lib-$(CONFIG_PLATFORM_MINGW32) += fsync.o |
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 | } | ||
diff --git a/win32/dirent.h b/win32/dirent.h new file mode 100644 index 000000000..b38d0d133 --- /dev/null +++ b/win32/dirent.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef DIRENT_H | ||
2 | #define DIRENT_H | ||
3 | |||
4 | typedef struct DIR DIR; | ||
5 | |||
6 | #define DT_UNKNOWN 0 | ||
7 | #define DT_DIR 1 | ||
8 | #define DT_REG 2 | ||
9 | #define DT_LNK 3 | ||
10 | |||
11 | struct dirent { | ||
12 | char d_name[PATH_MAX]; // file name | ||
13 | }; | ||
14 | |||
15 | DIR *opendir(const char *dirname); | ||
16 | struct dirent *readdir(DIR *dir); | ||
17 | int closedir(DIR *dir); | ||
18 | |||
19 | #endif /* DIRENT_H */ | ||