summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2023-01-31 04:38:44 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2023-05-03 23:11:34 -0400
commitb5a691b27af9d4b1b600c19f7fb0bfafd22f2bb2 (patch)
tree1f838c83f67681fecb604b6d98b53d4f439883d4
parent186c28bd106e749a98e74ee4e46797ca3c9cb650 (diff)
downloadlighttpd-git-b5a691b27af9d4b1b600c19f7fb0bfafd22f2bb2.tar.gz
[core] _WIN32 stat(), '/' and '\\' adjustments
The adjustments are minimal; not intended to be complete.
-rw-r--r--src/buffer.c8
-rw-r--r--src/configfile.c11
-rw-r--r--src/response.c10
-rw-r--r--src/stat_cache.c20
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);