From f7e4fe39a69b82bcef1aaa68111ccfa68b209ada Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 13 Jun 2021 08:13:25 +0100 Subject: 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. --- Makefile.flags | 2 +- win32/Kbuild | 1 + win32/dirent.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ win32/dirent.h | 19 ++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 win32/dirent.c create mode 100644 win32/dirent.h diff --git a/Makefile.flags b/Makefile.flags index 0950ddb0d..2687781f1 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -149,7 +149,7 @@ endif ifeq ($(CONFIG_PLATFORM_MINGW32),y) CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup EXEEXT = .exe -LDLIBS += ws2_32 mingwex -l:libssp.a +LDLIBS += ws2_32 endif 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 @@ lib-y:= +lib-$(CONFIG_PLATFORM_MINGW32) += dirent.o lib-$(CONFIG_PLATFORM_MINGW32) += env.o lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o 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 @@ +#include "libbb.h" + +struct DIR { + struct dirent dd_dir; + HANDLE dd_handle; /* FindFirstFile handle */ + int dd_stat; /* 0-based index */ +}; + +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); +} + +DIR *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 = FindFirstFileA(pattern, &fdata); + if (h == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(); + return NULL; + } + + /* initialize DIR structure and copy first dir entry */ + dir = xmalloc(sizeof(DIR)); + dir->dd_handle = h; + dir->dd_stat = 0; + finddata2dirent(&dir->dd_dir, &fdata); + return dir; +} + +struct dirent *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->dd_stat) { + /* get next entry and convert from WIN32_FIND_DATA to dirent */ + WIN32_FIND_DATAA fdata; + if (FindNextFileA(dir->dd_handle, &fdata)) { + finddata2dirent(&dir->dd_dir, &fdata); + } 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; + } + } + + ++dir->dd_stat; + return &dir->dd_dir; +} + +int closedir(DIR *dir) +{ + if (!dir) { + errno = EBADF; + return -1; + } + + FindClose(dir->dd_handle); + free(dir); + return 0; +} 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 @@ +#ifndef DIRENT_H +#define DIRENT_H + +typedef struct DIR DIR; + +#define DT_UNKNOWN 0 +#define DT_DIR 1 +#define DT_REG 2 +#define DT_LNK 3 + +struct dirent { + char d_name[PATH_MAX]; // file name +}; + +DIR *opendir(const char *dirname); +struct dirent *readdir(DIR *dir); +int closedir(DIR *dir); + +#endif /* DIRENT_H */ -- cgit v1.2.3-55-g6feb