From b5a691b27af9d4b1b600c19f7fb0bfafd22f2bb2 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Tue, 31 Jan 2023 04:38:44 -0500 Subject: [core] _WIN32 stat(), '/' and '\\' adjustments The adjustments are minimal; not intended to be complete. --- src/buffer.c | 8 +++++++- src/configfile.c | 11 ++++++----- src/response.c | 10 ++++++++-- src/stat_cache.c | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index 99e29289..7cacfb30 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -233,8 +233,14 @@ void buffer_append_iovec(buffer * const restrict b, const struct const_iovec * c void buffer_append_path_len(buffer * restrict b, const char * restrict a, size_t alen) { char * restrict s = buffer_string_prepare_append(b, alen+1); + #ifdef _WIN32 + const int aslash = (alen && (a[0] == '/' || a[0] == '\\')); + if (b->used > 1 && (s[-1] == '/' || s[-1] == '\\')) + #else const int aslash = (alen && a[0] == '/'); - if (b->used > 1 && s[-1] == '/') { + if (b->used > 1 && s[-1] == '/') + #endif + { if (aslash) { ++a; --alen; diff --git a/src/configfile.c b/src/configfile.c index 3adf0048..a44a937c 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -2363,7 +2363,8 @@ int config_parse_file(server *srv, config_t *context, const char *fn) { if (buffer_is_blank(context->basedir) || (fn[0] == '/' || fn[0] == '\\') || (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\')) || - (fn[0] == '.' && fn[1] == '.' && (fn[2] == '/' || fn[2] == '\\'))) { + (fn[0] == '.' && fn[1] == '.' && (fn[2] == '/' || fn[2] == '\\')) || + (light_isalpha(fn[0]) && fn[1] == ':' && (fn[2] == '/' || fn[2] == '\\'))) { buffer_copy_string_len(filename, fn, fnlen); } else { buffer_copy_path_len2(filename, BUF_PTR_LEN(context->basedir), @@ -2595,11 +2596,11 @@ int config_read(server *srv, const char *fn) { context_init(srv, &context); context.all_configs = srv->config_context; -#ifdef __WIN32 - pos = strrchr(fn, '\\'); -#else pos = strrchr(fn, '/'); -#endif + #ifdef _WIN32 + char * const spos = strrchr(fn, '\\'); + if (spos > pos) pos = spos; + #endif if (pos) { buffer_copy_string_len(context.basedir, fn, pos - fn + 1); } diff --git a/src/response.c b/src/response.c index 8b09550b..12bf648e 100644 --- a/src/response.c +++ b/src/response.c @@ -224,14 +224,20 @@ static handler_t http_response_physical_path_check(request_st * const r) { break; case EACCES: return http_response_physical_path_error(r, 403, NULL); - case ENAMETOOLONG: - /* file name to be read was too long. return 404 */ case ENOENT: if (r->http_method == HTTP_METHOD_OPTIONS && light_btst(r->resp_htags, HTTP_HEADER_ALLOW)) { r->http_status = 200; return HANDLER_FINISHED; } + #ifdef _WIN32 + /* _WIN32 returns ENOENT instead of ENOTDIR for PATH_INFO */ + break; + #else + __attribute_fallthrough__ + #endif + case ENAMETOOLONG: + /* file name to be read was too long. return 404 */ return http_response_physical_path_error(r, 404, NULL); default: /* we have no idea what happened. let's tell the user so. */ diff --git a/src/stat_cache.c b/src/stat_cache.c index 9db1d210..ed212927 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -1265,10 +1265,12 @@ stat_cache_entry * stat_cache_get_entry(const buffer * const name) { /* Note: paths are expected to be normalized before calling stat_cache, * e.g. without repeated '/' */ + #ifndef _WIN32 if (name->ptr[0] != '/') { errno = EINVAL; return NULL; } + #endif /* * check if the directory for this file has changed @@ -1319,17 +1321,35 @@ 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 */ 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); -- cgit v1.2.1