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 */ | ||
