diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2023-02-15 19:32:37 -0500 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2023-05-03 23:11:34 -0400 |
commit | 05b3d156c31af25bc08a6a7117899e39e337b48f (patch) | |
tree | d977efa7a2d7be78eb03f1972bf1fcee779809e0 /src | |
parent | 3f4e686cdcb2932057b4108c702bbb4aa4018846 (diff) | |
download | lighttpd-git-05b3d156c31af25bc08a6a7117899e39e337b48f.tar.gz |
[core] _WIN32 custom fs funcs on UTF-8 paths
open(), stat(), mkdir() on UTF-8 paths
lighttpd provides large file support and 64-bit time,
so provide override to use _stati64() (and _wstati64())
Additionally, provide custom function to support stat on UTF-8 path,
which must first be converted to wide-char and _wstati64(),
since _stati64() is naive and does not properly support UTF-8.
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/fdevent_win32.c | 3 | ||||
-rw-r--r-- | src/fs_win32.c | 67 | ||||
-rw-r--r-- | src/fs_win32.h | 70 | ||||
-rw-r--r-- | src/stat_cache.c | 19 | ||||
-rw-r--r-- | src/sys-stat.h | 6 |
7 files changed, 148 insertions, 21 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8cce9c9..d525f240 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -847,7 +847,7 @@ set(COMMON_SRC ck.c ) if(WIN32) - set(COMMON_SRC ${COMMON_SRC} fdevent_win32.c) + set(COMMON_SRC ${COMMON_SRC} fdevent_win32.c fs_win32.c) endif() set(BUILTIN_MODS diff --git a/src/Makefile.am b/src/Makefile.am index 8cefde69..4e347fa0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,7 +66,7 @@ common_src=base64.c buffer.c burl.c log.c \ sys-setjmp.c \ ck.c -common_src += fdevent_win32.c +common_src += fdevent_win32.c fs_win32.c src = server.c response.c connections.c h2.c reqpool.c \ plugin.c \ diff --git a/src/fdevent_win32.c b/src/fdevent_win32.c index 00b37cb0..da69433d 100644 --- a/src/fdevent_win32.c +++ b/src/fdevent_win32.c @@ -776,11 +776,12 @@ int fdevent_dup_cloexec (int fd) #include <fcntl.h> +#include "fs_win32.h" int fdevent_open_cloexec (const char *pathname, int symlinks, int flags, mode_t mode) { UNUSED(symlinks); - return _open(pathname, flags | _O_BINARY | _O_NOINHERIT, mode); + return fs_win32_openUTF8(pathname, flags | _O_BINARY | _O_NOINHERIT, mode); } diff --git a/src/fs_win32.c b/src/fs_win32.c new file mode 100644 index 00000000..8c51e824 --- /dev/null +++ b/src/fs_win32.c @@ -0,0 +1,67 @@ +/* + * fs_win32 - filesystem _WIN32 API wrapper + * + * Copyright(c) 2023 Glenn Strauss gstrauss()gluelogic.com All rights reserved + * License: BSD 3-clause (same as lighttpd) + */ +#include "first.h" + +#include "fs_win32.h" + +#ifdef _WIN32 + +/* MS filesystem API does not support UTF-8? WTH? write our own; not hard */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <direct.h> +#include <io.h> + +#include <windows.h> /*(otherwise get No Target Architecture error)*/ +#include <stringapiset.h> +#include <errno.h> + +int fs_win32_openUTF8 (const char *path, int oflag, int pmode) +{ + WCHAR wbuf[4096]; + int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, + wbuf, sizeof(wbuf)/sizeof(*wbuf)); + return wlen > 0 ? _wopen(wbuf, oflag, pmode) : -1; +} + +int fs_win32_mkdirUTF8 (const char *path, mode_t mode) +{ + UNUSED(mode); + WCHAR wbuf[4096]; + int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, + wbuf, sizeof(wbuf)/sizeof(*wbuf)); + return wlen > 0 ? _wmkdir(wbuf) : -1; +} + +int fs_win32_stati64UTF8 (const char *path, struct fs_win32_stati64UTF8 *st) +{ + WCHAR wbuf[4096]; + size_t len = strlen(path); + if (0 == len) { + errno = EINVAL; + return -1; + } + /* omit trailing '/' (if present) or else _WIN32 stat() fails */ + int final_slash = (path[len-1] == '/' || path[len-1] == '\\'); + int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + path, len - final_slash, + wbuf, (sizeof(wbuf)/sizeof(*wbuf))-1); + if (wlen <= 0) /* 0 indicates error; < 0 should not happen */ + return -1; + wbuf[wlen] = 0; + if (-1 == _wstati64(wbuf, (struct _stati64 *)st)) + return -1; + /* must check since stat() w/o trailing '/' above */ + if (final_slash && (st->st_mode & _S_IFMT) == _S_IFREG) { /* S_ISREG() */ + errno = ENOTDIR; + return -1; + } + return 0; +} + +#endif /* _WIN32 */ diff --git a/src/fs_win32.h b/src/fs_win32.h new file mode 100644 index 00000000..0b1af742 --- /dev/null +++ b/src/fs_win32.h @@ -0,0 +1,70 @@ +/* + * fs_win32 - filesystem _WIN32 API wrapper + * + * Copyright(c) 2023 Glenn Strauss gstrauss()gluelogic.com All rights reserved + * License: BSD 3-clause (same as lighttpd) + */ +#ifndef INCLUDED_FS_WIN32_H +#define INCLUDED_FS_WIN32_H +#include "first.h" + +#ifdef _WIN32 + +#include <sys/types.h> +#include <sys/stat.h> + +/* MS filesystem API does not support UTF-8? WTH? write our own; not hard */ + +int fs_win32_openUTF8 (const char *path, int oflag, int pmode); + +#include <direct.h> +#undef mkdir +#define mkdir(a,b) fs_win32_mkdirUTF8((a),(b)) +int fs_win32_mkdirUTF8 (const char *path, mode_t mode); + +#undef stat +#undef fstat +#define stat fs_win32_stati64UTF8 +#define fstat(fd,st) _fstati64((fd),(struct _stati64 *)(st)) + +/*('#define stat fs_win32_stati64UTF8' must handle 'struct stat' definitions)*/ +struct fs_win32_stati64UTF8 { +#if 1 /*(?non-standard?) (appears to work)*/ + struct _stati64; /*(intentionally unnamed for transparent struct)*/ +#else +/* /usr/x86_64-w64-mingw32/sys-root/mingw/include/_mingw_stat64.h */ + #ifdef __MINGW_EXTENSION + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __MINGW_EXTENSION __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + #else +/* C:/Program Files (x86)/Windows Kits/10/Include/10.0.19041.0/ucrt/sys/stat.h*/ + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + #endif +#endif +}; + +/* could be inline compat func here, but fairly large func */ +int fs_win32_stati64UTF8 (const char *path, struct fs_win32_stati64UTF8 *st); + +#endif /* _WIN32 */ + +#endif diff --git a/src/stat_cache.c b/src/stat_cache.c index ed212927..3f7c034b 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -1321,35 +1321,18 @@ stat_cache_entry * stat_cache_get_entry(const buffer * const name) { } struct stat st; - #ifdef _WIN32 - if (final_slash && len < 4096) { - char buf[4096]; - memcpy(buf, name->ptr, len); - buf[len] = '\0'; - if (-1 == stat(buf, &st)) { - return NULL; - } - /* must check since stat() w/o trailing '/' above */ - if (S_ISREG(st.st_mode)) { - errno = ENOTDIR; - return NULL; - } - } - else - #endif if (-1 == stat(name->ptr, &st)) { return NULL; } if (NULL == sce) { - #ifdef _WIN32 /*(already checked above)*/ /* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */ + /* (local fs_win32_stati64UTF8() checks, but repeat since not obvious)*/ if (final_slash && S_ISREG(st.st_mode)) { errno = ENOTDIR; return NULL; } - #endif sce = stat_cache_entry_init(); buffer_copy_string_len(&sce->name, name->ptr, len); diff --git a/src/sys-stat.h b/src/sys-stat.h index 9d282858..b3f1e033 100644 --- a/src/sys-stat.h +++ b/src/sys-stat.h @@ -142,6 +142,12 @@ #endif /* _WIN32 */ +#ifdef _WIN32 +/* local overrides to support UTF-8 path strings */ +/* note: redefines stat, fstat, mkdir, ... */ +#include "fs_win32.h" +#endif + #ifndef S_ISFIFO #define S_ISFIFO(mode) 0 |