From a22ac176ca35012c2ac3f84ac5ce75ff9b98267c Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sat, 29 Aug 2020 20:36:10 +0200 Subject: [PATCH] Template overrides in subdirs, prefetch templates --- dirl.c | 179 +++++++++++++++++++++++++++------------------------------ dirl.h | 75 ++++++++++++++++++------ resp.c | 14 ++--- util.c | 5 +- 4 files changed, 150 insertions(+), 123 deletions(-) diff --git a/dirl.c b/dirl.c index 90364bb..711b3c8 100644 --- a/dirl.c +++ b/dirl.c @@ -1,5 +1,6 @@ /* See LICENSE file for copyright and license details. */ #include +#include #include #include #include @@ -31,25 +32,13 @@ suffix(int t) } static char* -dirl_read_template(char* tpl) +dirl_read(char* tpl) { - /* Try find template in root (note that we are chroot'ed) */ FILE* tpl_fp; - char* tpl_abs; - tpl_abs = calloc(strlen(tpl)+2, sizeof(char)); - if(tpl_abs == NULL) { + if (!(tpl_fp = fopen(tpl, "r"))) { return NULL; } - tpl_abs[0] = '/'; - strcat(tpl_abs, tpl); - - if (!(tpl_fp = fopen(tpl_abs, "r"))) { - free(tpl_abs); - return NULL; - } - - free(tpl_abs); /* Get size of template */ if (fseek(tpl_fp, 0L, SEEK_END) < 0) { @@ -66,7 +55,7 @@ dirl_read_template(char* tpl) rewind(tpl_fp); /* Read template into tpl_buf */ - char* tpl_buf = (char*)malloc(sizeof(char) * tpl_size); + char* tpl_buf = (char*)calloc(sizeof(char), tpl_size); if (tpl_buf == NULL) { fclose(tpl_fp); @@ -91,119 +80,120 @@ dirl_read_template(char* tpl) return tpl_buf; } -static enum status -dirl_header_default(int fd, const struct response* res) +/* Try to find templates up until root + * + * Iterates the directory hierarchy upwards. Returns the closest path containing + * a template file or NULL if none could be found. + * + * Note that we are chrooted. + */ +static char* +dirl_find_templ_dir(const char* start_path) { - char esc[PATH_MAX]; - html_escape(res->uri, esc, sizeof(esc)); - if (dprintf(fd, - "\n" - "\n" - " \n" - " \n" - " Index of %s\n" - " \n" - " \n" - "

Index of %s

\n" - " ..", - esc, - esc) < 0) { - return S_REQUEST_TIMEOUT; + char* path_buf = calloc(sizeof(char), strlen(start_path)); + strcat(path_buf, start_path); + + while (strlen(path_buf) != 0) { + DIR* cur = opendir(path_buf); + struct dirent* de; + errno = 0; + while ((de = readdir(cur))) { + if (de->d_type == DT_REG) { + if (strcmp(DIRL_HEADER, de->d_name) || strcmp(DIRL_ENTRY, de->d_name) || + strcmp(DIRL_FOOTER, de->d_name)) { + closedir(cur); + return path_buf; + } + } + } + + char* parent = strrchr(path_buf, '/'); + (*parent) = '\0'; // strip tail from path_buf } - return 0; + free(path_buf); + return NULL; +} + +struct dirl_templ +dirl_read_templ(const char* path) +{ + struct dirl_templ templates = { .header = DIRL_HEADER_DEFAULT, + .entry = DIRL_ENTRY_DEFAULT, + .footer = DIRL_FOOTER_DEFAULT }; + + char* templ_dir = dirl_find_templ_dir(path); + + char* header_file = + calloc(sizeof(char), strlen(templ_dir) + strlen(DIRL_HEADER)); + strcpy(header_file, templ_dir); + strcat(header_file, DIRL_HEADER); + char* header = dirl_read(header_file); + if (header) + templates.header = header; + free(header_file); + + char* entry_file = + calloc(sizeof(char), strlen(templ_dir) + strlen(DIRL_ENTRY)); + strcpy(entry_file, templ_dir); + strcat(entry_file, DIRL_ENTRY); + char* entry = dirl_read(entry_file); + if (entry) + templates.entry = entry; + free(entry_file); + + char* footer_file = + calloc(sizeof(char), strlen(templ_dir) + strlen(DIRL_FOOTER)); + strcpy(footer_file, templ_dir); + strcat(footer_file, DIRL_FOOTER); + char* footer = dirl_read(footer_file); + if (footer) + templates.footer = footer; + free(footer_file); + + free(templ_dir); + + return templates; } enum status -dirl_header(int fd, const struct response* res) +dirl_header(int fd, const struct response* res, const struct dirl_templ* templ) { - char* tpl = dirl_read_template(DIRL_HEADER); - - if(tpl == NULL) { - return dirl_header_default(fd, res); - } - /* Replace placeholder */ - char* nhead = replace(tpl, "{idx}", "something"); + char* nhead = replace(templ->header, "{curdir}", "something"); /* Write header */ write(fd, nhead, strlen(nhead)); - free(tpl); free(nhead); /* listing header */ return 0; } -static enum status -dirl_entry_default(int fd, const struct dirent* entry) -{ - char esc[PATH_MAX]; - - html_escape(entry->d_name, esc, sizeof(esc)); - if (dprintf(fd, - "
\n\t\t%s%s", - esc, - (entry->d_type == DT_DIR) ? "/" : "", - esc, - suffix(entry->d_type)) < 0) { - return S_REQUEST_TIMEOUT; - } - - return 0; -} - enum status -dirl_entry(int fd, const struct dirent* entry) +dirl_entry(int fd, const struct dirent* entry, const struct dirl_templ* templ) { - char* tpl = dirl_read_template(DIRL_ENTRY); - - if (tpl == NULL) { - return dirl_entry_default(fd, entry); - } - /* Replace placeholder */ - char* nentry = replace(tpl, "{entry}", entry->d_name); + char* nentry = replace(templ->entry, "{entry}", entry->d_name); /* Write entry */ write(fd, nentry, strlen(nentry)); - free(tpl); free(nentry); return 0; } -static enum status -dirl_footer_default(int fd) -{ - if (dprintf(fd, - "\n" - " \n" - "") < 0) { - return S_REQUEST_TIMEOUT; - } - - return 0; -} - enum status -dirl_footer(int fd) +dirl_footer(int fd, const struct dirl_templ* templ) { - char* tpl = dirl_read_template(DIRL_FOOTER); - - if(tpl == NULL) { - return dirl_footer_default(fd); - } - /* Replace placeholder */ - char* nfoot = replace(tpl, "{idx}", "something"); + char* nfoot = replace(templ->footer, "{idx}", "something"); /* Write footer */ write(fd, nfoot, strlen(nfoot)); - free(tpl); free(nfoot); return 0; } @@ -211,10 +201,9 @@ dirl_footer(int fd) int dirl_skip(const char* name) { - (void)name; // noop; avoid unused warning - - return !strcmp(name, DIRL_HEADER) // + return name[0] == '.' // + || !strcmp(name, DIRL_HEADER) // || !strcmp(name, DIRL_ENTRY) // || !strcmp(name, DIRL_FOOTER) // - || !strcmp(name, DIRL_STYLE); + || !strcmp(name, DIRL_STYLE); // } diff --git a/dirl.h b/dirl.h index f147106..5b6478c 100644 --- a/dirl.h +++ b/dirl.h @@ -9,27 +9,66 @@ #include "http.h" #define DIRL_HEADER ".header.tpl" -#define DIRL_ENTRY ".entry.tpl" +#define DIRL_ENTRY ".entry.tpl" #define DIRL_FOOTER ".footer.tpl" -#define DIRL_STYLE "style.css" +#define DIRL_STYLE "style.css" -struct dirl_env_entry { - char *name; - char *value; -}; - -struct dirl_env { - struct dirl_env_entry *entries; -}; - -/* - * Determine if an dirlist entry should be skipped because it has special - * meaning. Skips header-, entry-, footer templates and dirlist style css. +/* Default template definitions + * + * Used if no template files can be found */ -int dirl_skip(const char*); +#define DIRL_HEADER_DEFAULT \ + "\n" \ + "\n" \ + " \n" \ + " \n" \ + " Index of {curdir}\n" \ + " \n" \ + " \n" \ + "

Index of {curdir}

\n" \ + " ..\n" -enum status dirl_header(int, const struct response*); -enum status dirl_entry(int, const struct dirent*); -enum status dirl_footer(int); +#define DIRL_ENTRY_DEFAULT \ + "
\n" \ + " {entry}\n" + +#define DIRL_FOOTER_DEFAULT \ + " \n" \ + "" + +struct dirl_templ +{ + const char* header; + const char* entry; + const char* footer; +}; + +struct dirl_templ +dirl_read_templ(const char* path); + +/* Determine if an dirlist entry should be skipped + * + * Skips: + * - hidden files and directories + * - special directory entries (., ..) + * - header template: DIRL_HEADER + * - entry template: DIRL_ENTRY + * - footer template: DIRL_FOOTER + * - dirlist style: DRIL_STYLE + */ +int +dirl_skip(const char*); + +/* Print header into the response */ +enum status +dirl_header(int, const struct response*, const struct dirl_templ*); + +/* Print entry into the response */ +enum status +dirl_entry(int, const struct dirent*, const struct dirl_templ*); + +/* Print footer into the response */ +enum status +dirl_footer(int, const struct dirl_templ*); #endif /* DIRL_H */ diff --git a/resp.c b/resp.c index 2d9b948..2042405 100644 --- a/resp.c +++ b/resp.c @@ -40,32 +40,30 @@ resp_dir(int fd, const struct response *res) return S_FORBIDDEN; } + /* read templates */ + struct dirl_templ templates = dirl_read_templ(res->path); + /* listing header */ - if ((ret = dirl_header(fd, res))) { + if ((ret = dirl_header(fd, res, &templates))) { return ret; } /* entries */ for (i = 0; i < (size_t)dirlen; i++) { - /* skip hidden files, "." and ".." */ - if (e[i]->d_name[0] == '.') { - continue; - } - /* skip dirl special files */ if(dirl_skip(e[i]->d_name)) { continue; } /* entry line */ - if ((ret = dirl_entry(fd, e[i]))) { + if ((ret = dirl_entry(fd, e[i], &templates))) { goto cleanup; } } /* listing footer */ - if ((ret = dirl_footer(fd))) { + if ((ret = dirl_footer(fd, &templates))) { goto cleanup; } diff --git a/util.c b/util.c index 65e80e6..e59aaa8 100644 --- a/util.c +++ b/util.c @@ -183,7 +183,7 @@ replace(const char *src, const char *old, const char* new) { } /* Allocate enough space for the new string */ - char *buf = malloc( (sizeof(char)*src_len) + (sizeof(char)*replc*(new_len-old_len)) + 1); + char *buf = calloc( sizeof(char), src_len + replc*(abs(new_len-old_len)) + 1); /* Now start replacing */ const char *srcidx = src; @@ -193,7 +193,8 @@ replace(const char *src, const char *old, const char* new) { while (replc--) { srcidx_old = strstr(srcidx, old); - bufidx = strncpy(bufidx, srcidx, srcidx_old - srcidx) + (srcidx_old-srcidx); + long repl_len = labs(srcidx_old - srcidx); + bufidx = strncpy(bufidx, srcidx, repl_len) + repl_len; bufidx = strcpy(bufidx, new) + new_len; srcidx = srcidx_old+old_len;