summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2023-02-15 19:32:37 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2023-05-03 23:11:34 -0400
commit05b3d156c31af25bc08a6a7117899e39e337b48f (patch)
treed977efa7a2d7be78eb03f1972bf1fcee779809e0 /src
parent3f4e686cdcb2932057b4108c702bbb4aa4018846 (diff)
downloadlighttpd-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.txt2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/fdevent_win32.c3
-rw-r--r--src/fs_win32.c67
-rw-r--r--src/fs_win32.h70
-rw-r--r--src/stat_cache.c19
-rw-r--r--src/sys-stat.h6
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