aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-06-13 08:13:25 +0100
committerRon Yorston <rmy@pobox.com>2021-06-13 08:13:25 +0100
commitf7e4fe39a69b82bcef1aaa68111ccfa68b209ada (patch)
tree23d63dd3d27f4fdb6e475c35e348b3c8299e6e6c
parentcfac1da2aaccaf45a669b0a53c82a32c8231827c (diff)
downloadbusybox-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.flags2
-rw-r--r--win32/Kbuild1
-rw-r--r--win32/dirent.c96
-rw-r--r--win32/dirent.h19
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
149ifeq ($(CONFIG_PLATFORM_MINGW32),y) 149ifeq ($(CONFIG_PLATFORM_MINGW32),y)
150CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup 150CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup
151EXEEXT = .exe 151EXEEXT = .exe
152LDLIBS += ws2_32 mingwex -l:libssp.a 152LDLIBS += ws2_32
153endif 153endif
154 154
155ifneq ($(CONFIG_PLATFORM_MINGW32),y) 155ifneq ($(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
5lib-y:= 5lib-y:=
6 6
7lib-$(CONFIG_PLATFORM_MINGW32) += dirent.o
7lib-$(CONFIG_PLATFORM_MINGW32) += env.o 8lib-$(CONFIG_PLATFORM_MINGW32) += env.o
8lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o 9lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o
9lib-$(CONFIG_PLATFORM_MINGW32) += fsync.o 10lib-$(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
3struct DIR {
4 struct dirent dd_dir;
5 HANDLE dd_handle; /* FindFirstFile handle */
6 int dd_stat; /* 0-based index */
7};
8
9static 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
15DIR *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
59struct 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
86int 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
4typedef 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
11struct dirent {
12 char d_name[PATH_MAX]; // file name
13};
14
15DIR *opendir(const char *dirname);
16struct dirent *readdir(DIR *dir);
17int closedir(DIR *dir);
18
19#endif /* DIRENT_H */