diff options
author | darix <darix@152afb58-edef-0310-8abb-c4023f1b3aa9> | 2006-09-07 11:00:02 +0000 |
---|---|---|
committer | darix <darix@152afb58-edef-0310-8abb-c4023f1b3aa9> | 2006-09-07 11:00:02 +0000 |
commit | fa0e293832e406624fdb542240e27e924da32e64 (patch) | |
tree | a86b868ab977928eba8e912eee2b77b824d237b6 /src/stat_cache.c | |
parent | c0b725ddc699871a7b657cae12743726e35d41d0 (diff) | |
download | lighttpd-fa0e293832e406624fdb542240e27e924da32e64.tar.gz |
- backport symlink patch in hard version to 1.4.11
git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.11-ssl-fixes@1281 152afb58-edef-0310-8abb-c4023f1b3aa9
Diffstat (limited to 'src/stat_cache.c')
-rw-r--r-- | src/stat_cache.c | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/src/stat_cache.c b/src/stat_cache.c index 148f4c83..623e5ea5 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -39,7 +39,7 @@ #define lstat stat #endif -#if 0 +#if 1 /* enables debug code for testing if all nodes in the stat-cache as accessable */ #define DEBUG_STAT_CACHE #endif @@ -328,6 +328,20 @@ static int buffer_copy_dirname(buffer *dst, buffer *file) { } #endif +#ifdef HAVE_LSTAT +static int stat_cache_lstat(server *srv, char *dname, struct stat *lst) { + if (lstat(dname, lst) == 0) { + return S_ISLNK(lst->st_mode) ? 0 : 1; + } + else { + log_error_write(srv, __FILE__, __LINE__, "sss", + "lstat failed for:", + dname, strerror(errno)); + }; + return -1; +} +#endif + /*** * * @@ -450,10 +464,9 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ /* * *lol* * - open() + fstat() on a named-pipe results in a (intended) hang. - * - stat() if regualar file + open() to see if we can read from it is better + * - stat() if regular file + open() to see if we can read from it is better * * */ - if (-1 == stat(name->ptr, &st)) { return HANDLER_ERROR; } @@ -509,11 +522,52 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ * and keeping the file open for the rest of the time. But this can * only be done at network level. * ++ * per default it is not a symlink * */ - if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) { - return HANDLER_ERROR; +#ifdef HAVE_LSTAT + sce->is_symlink = 0; + struct stat lst; + if (stat_cache_lstat(srv, name->ptr, &lst) == 0) { +#ifdef DEBUG_STAT_CACHE + log_error_write(srv, __FILE__, __LINE__, "sb", + "found symlink", name); +#endif + sce->is_symlink = 1; } + /* + * we assume "/" can not be symlink, so + * skip the symlink stuff if our path is / + **/ + else if ((name->used > 2)) { + char *dname, *s_cur; + + dname = strndup(name->ptr, name->used); + while ((s_cur = strrchr(dname,'/'))) { + *s_cur = '\0'; + if (dname == s_cur) { +#ifdef DEBUG_STAT_CACHE + log_error_write(srv, __FILE__, __LINE__, "s", "reached /"); +#endif + break; + } +#ifdef DEBUG_STAT_CACHE + log_error_write(srv, __FILE__, __LINE__, "sss", + "checking if", dname, "is a symlink"); +#endif + if (stat_cache_lstat(srv, dname, &lst) == 0) { + sce->is_symlink = 1; +#ifdef DEBUG_STAT_CACHE + log_error_write(srv, __FILE__, __LINE__, "ss", + "found symlink", dname); +#endif + break; + }; + }; + free(dname); + }; +#endif + if (S_ISREG(st.st_mode)) { /* determine mimetype */ buffer_reset(sce->content_type); |