summaryrefslogtreecommitdiff
path: root/src/stat_cache.c
diff options
context:
space:
mode:
authordarix <darix@152afb58-edef-0310-8abb-c4023f1b3aa9>2006-09-07 11:00:02 +0000
committerdarix <darix@152afb58-edef-0310-8abb-c4023f1b3aa9>2006-09-07 11:00:02 +0000
commitfa0e293832e406624fdb542240e27e924da32e64 (patch)
treea86b868ab977928eba8e912eee2b77b824d237b6 /src/stat_cache.c
parentc0b725ddc699871a7b657cae12743726e35d41d0 (diff)
downloadlighttpd-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.c64
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);