From 329dedc33bca35a19dc5ee4a0754e3f3f920c1b5 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Tue, 25 Aug 2020 21:08:23 +0200 Subject: [PATCH 01/10] Read dirlist from templates Reads header, footer and entry templates from files defined in config.h. Defaults to original output if not found. --- Makefile | 5 +- config.def.h | 4 ++ dirl.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++ dirl.h | 29 ++++++++ http.c | 14 +--- resp.c | 50 ++++++-------- util.c | 36 ++++++++++ util.h | 1 + 8 files changed, 280 insertions(+), 44 deletions(-) create mode 100644 dirl.c create mode 100644 dirl.h diff --git a/Makefile b/Makefile index cf57f13..f5208ac 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,15 @@ include config.mk -COMPONENTS = util sock http resp +COMPONENTS = util sock http resp dirl all: quark util.o: util.c util.h config.mk sock.o: sock.c sock.h util.h config.mk http.o: http.c http.h util.h http.h resp.h config.h config.mk -resp.o: resp.c resp.h util.h http.h config.mk +resp.o: resp.c resp.h util.h http.h dirl.h config.mk +dirl.o: dirl.c dirl.h util.h http.h config.mk main.o: main.c util.h sock.h http.h arg.h config.h config.mk quark: $(COMPONENTS:=.o) $(COMPONENTS:=.h) main.o config.mk diff --git a/config.def.h b/config.def.h index 6d7f690..7197ca8 100644 --- a/config.def.h +++ b/config.def.h @@ -1,5 +1,9 @@ #define HEADER_MAX 4096 #define FIELD_MAX 200 +#define DIRL_HEADER "header.qhtml" +#define DIRL_ENTRY "entry.qhtml" +#define DIRL_FOOTER "footer.qhtml" +#define DIRL_STYLE "dirlist.css" /* mime-types */ static const struct { diff --git a/dirl.c b/dirl.c new file mode 100644 index 0000000..d047b4e --- /dev/null +++ b/dirl.c @@ -0,0 +1,185 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dirl.h" +#include "http.h" +#include "util.h" +#include "config.h" + +static char *suffix(int t) { + switch (t) { + case DT_FIFO: + return "|"; + case DT_DIR: + return "/"; + case DT_LNK: + return "@"; + case DT_SOCK: + return "="; + } + + return ""; +} + +enum status +dirl_header_default(int fd, const struct response *res) { + char esc[PATH_MAX]; + html_escape(res->uri, esc, sizeof(esc)); + if (dprintf(fd, + "\n\n\t" + "Index of %s\n" + "\t\n" + "\t\t

Index of %s

\n" + "\t\t\t..", + esc, esc) < 0) { + return S_REQUEST_TIMEOUT; + } + + return 0; +} + +enum status +dirl_header(int fd, const struct response *res) +{ + + /* No header file defined, default */ +#ifndef DIRL_HEADER + return dirl_header_default(fd, res); +#endif + + /* Try find header in root (note that we are chroot'ed) */ + int header_fd; + if ( (header_fd = open(("/" DIRL_HEADER), O_RDONLY)) < 0 ) { + return dirl_header_default(fd, res); + } + + /* Get size of header */ + struct stat header_stat; + if (fstat(header_fd, &header_stat) < 0) { + return dirl_header_default(fd, res); + } + + /* Allocate space for file */ + char *header = (char *) malloc(sizeof(char) * header_stat.st_size); + if (header == NULL) { + return dirl_header_default(fd, res); + } + + /* Read header into string for template replacement */ + if ( (read(header_fd, header, header_stat.st_size)) < 0) { + free(header); + return dirl_header_default(fd, res); + } + + /* Replace placeholder */ + char *nhead = replace(header, "{idx}", "something"); + + /* Write header */ + write(fd, nhead, strlen(nhead)); + + free(header); + 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) { + /* Try find entry in root (note that we are chroot'ed) */ + int entry_fd; + if ((entry_fd = open(("/" DIRL_ENTRY), O_RDONLY)) < 0) { + return dirl_entry_default(fd, entry); + } + + /* Get size of entry*/ + struct stat entry_stat; + if (fstat(entry_fd, &entry_stat) < 0) { + return dirl_entry_default(fd, entry); + } + + /* Write entry */ + if (sendfile(fd, entry_fd, NULL, entry_stat.st_size) < 0) { + return dirl_entry_default(fd, entry); + } + + return 0; +} + +static enum status +dirl_footer_default(int fd) { + if (dprintf(fd, "\n\t\n\n") < 0) { + return S_REQUEST_TIMEOUT; + } + + return 0; +} + +enum status +dirl_footer(int fd) { + /* Try find footer in root (note that we are chroot'ed) */ + int footer_fd; + if ((footer_fd = open(("/" DIRL_FOOTER), O_RDONLY)) < 0) { + return dirl_footer_default(fd); + } + + /* Get size of footer */ + struct stat footer_stat; + if (fstat(footer_fd, &footer_stat) < 0) { + return dirl_footer_default(fd); + } + + /* Write footer */ + if (sendfile(fd, footer_fd, NULL, footer_stat.st_size) < 0) { + return dirl_footer_default(fd); + } + + return 0; +} + +int dirl_skip(const char *name) { + (void) name; +#ifdef DIRL_HEADER + if(!strcmp(name, DIRL_HEADER)) { + return 1; + } +#endif +#ifdef DIRL_ENTRY + if (!strcmp(name, DIRL_ENTRY)) { + return 1; + } +#endif +#ifdef DIRL_FOOTER + if (!strcmp(name, DIRL_FOOTER)) { + return 1; + } +#endif +#ifdef DIRL_STYLE + if (!strcmp(name, DIRL_STYLE)) { + return 1; + } +#endif + + return 0; +} diff --git a/dirl.h b/dirl.h new file mode 100644 index 0000000..d8df880 --- /dev/null +++ b/dirl.h @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef DIRL_H +#define DIRL_H + +#include +#include +#include + +#include "http.h" + +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. + */ +int dirl_skip(const char*); +enum status dirl_header(int, const struct response*); +enum status dirl_entry(int, const struct dirent*); +enum status dirl_footer(int); + +#endif /* DIRL_H */ diff --git a/http.c b/http.c index b6b1ab7..cfd439c 100644 --- a/http.c +++ b/http.c @@ -61,7 +61,7 @@ const char *res_field_str[] = { enum status http_send_header(int fd, const struct response *res) { - char t[FIELD_MAX], esc[PATH_MAX]; + char t[FIELD_MAX]; size_t i; if (timestamp(t, sizeof(t), time(NULL))) { @@ -89,18 +89,6 @@ http_send_header(int fd, const struct response *res) return S_REQUEST_TIMEOUT; } - /* listing header */ - if (res->type == RESTYPE_DIRLISTING) { - html_escape(res->uri, esc, sizeof(esc)); - if (dprintf(fd, - "\n\n\t" - "Index of %s\n" - "\t\n\t\t..", - esc) < 0) { - return S_REQUEST_TIMEOUT; - } - } - return res->status; } diff --git a/resp.c b/resp.c index b7441dc..2d9b948 100644 --- a/resp.c +++ b/resp.c @@ -10,6 +10,7 @@ #include "http.h" #include "resp.h" #include "util.h" +#include "dirl.h" static int compareent(const struct dirent **d1, const struct dirent **d2) @@ -25,19 +26,6 @@ compareent(const struct dirent **d1, const struct dirent **d2) return strcmp((*d1)->d_name, (*d2)->d_name); } -static char * -suffix(int t) -{ - switch (t) { - case DT_FIFO: return "|"; - case DT_DIR: return "/"; - case DT_LNK: return "@"; - case DT_SOCK: return "="; - } - - return ""; -} - enum status resp_dir(int fd, const struct response *res) { @@ -52,30 +40,34 @@ resp_dir(int fd, const struct response *res) return S_FORBIDDEN; } - /* listing */ + /* listing header */ + if ((ret = dirl_header(fd, res))) { + return ret; + } + + /* entries */ for (i = 0; i < (size_t)dirlen; i++) { /* skip hidden files, "." and ".." */ if (e[i]->d_name[0] == '.') { continue; } - /* entry line */ - html_escape(e[i]->d_name, esc, sizeof(esc)); - if (dprintf(fd, "
\n\t\t%s%s", - esc, - (e[i]->d_type == DT_DIR) ? "/" : "", - esc, - suffix(e[i]->d_type)) < 0) { - ret = S_REQUEST_TIMEOUT; - goto cleanup; - } + /* skip dirl special files */ + if(dirl_skip(e[i]->d_name)) { + continue; + } + + /* entry line */ + if ((ret = dirl_entry(fd, e[i]))) { + goto cleanup; + } + } - /* listing footer */ - if (dprintf(fd, "\n\t\n\n") < 0) { - ret = S_REQUEST_TIMEOUT; - goto cleanup; - } + /* listing footer */ + if ((ret = dirl_footer(fd))) { + goto cleanup; + } cleanup: while (dirlen--) { diff --git a/util.c b/util.c index 2b54df1..487b94a 100644 --- a/util.c +++ b/util.c @@ -168,6 +168,42 @@ html_escape(const char *src, char *dst, size_t dst_siz) dst[j] = '\0'; } +char* +replace(const char *src, const char *old, const char* new) { + int old_len = strlen(old); + int new_len = strlen(new); + int src_len = strlen(src); + + /* Count needed replacements */ + const char* tmp = src; + int replc=0; + while ((tmp=strstr(tmp, old))) { + replc++; + tmp += old_len; + } + + /* Allocate enough space for the new string */ + char *buf = malloc( (sizeof(char)*src_len) + (sizeof(char)*replc*(new_len-old_len)) + 1); + + /* Now start replacing */ + const char *srcidx = src; + const char *srcidx_old = src; + char *bufidx = buf; + + while (replc--) { + srcidx_old = strstr(srcidx, old); + + bufidx = strncpy(bufidx, srcidx, srcidx_old - srcidx) + (srcidx_old-srcidx); + bufidx = strcpy(bufidx, new) + new_len; + + srcidx = srcidx_old+old_len; + } + + strcpy(bufidx, srcidx); // copy tail + + return buf; +} + #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 diff --git a/util.h b/util.h index 6b6d17d..70179ac 100644 --- a/util.h +++ b/util.h @@ -53,6 +53,7 @@ int timestamp(char *, size_t, time_t); int esnprintf(char *, size_t, const char *, ...); int prepend(char *, size_t, const char *); void html_escape(const char *, char *, size_t); +char *replace(const char *, const char *, const char *); void *reallocarray(void *, size_t, size_t); long long strtonum(const char *, long long, long long, const char **); From 5b6f8e50832ddbd3cdd742b4eda9c1ce91148f89 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Fri, 28 Aug 2020 00:40:04 +0200 Subject: [PATCH 02/10] Read from template files with placeholder replacement --- .clang-format | 137 +++++++++++++++++++++++++++++ .drone.yml | 4 +- .gitignore | 4 + config.def.h | 4 - dirl.c | 239 +++++++++++++++++++++++++++++--------------------- dirl.h | 6 ++ util.c | 2 +- 7 files changed, 287 insertions(+), 109 deletions(-) create mode 100644 .clang-format create mode 100644 .gitignore diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..95d63a5 --- /dev/null +++ b/.clang-format @@ -0,0 +1,137 @@ +--- +Language: Cpp +# BasedOnStyle: Mozilla +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: TopLevel +AlwaysBreakAfterReturnType: TopLevel +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: false + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: false + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Mozilla +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeComma +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: false +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: true +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +... + diff --git a/.drone.yml b/.drone.yml index e0a18e0..02cdb2c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,8 +12,8 @@ steps: image: debian commands: - cp quark /usr/local/bin - - useradd web && su web && cd - - mkdir -p web && cd web && echo "hello from quark" > index.html + - useradd web + - mkdir -p web && cd web && echo "hello from quark" > index.html - quark -p 9130 -h run -l -u web -g web detach: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..78eb9d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +.gdb_history +config.h +quark \ No newline at end of file diff --git a/config.def.h b/config.def.h index 7197ca8..6d7f690 100644 --- a/config.def.h +++ b/config.def.h @@ -1,9 +1,5 @@ #define HEADER_MAX 4096 #define FIELD_MAX 200 -#define DIRL_HEADER "header.qhtml" -#define DIRL_ENTRY "entry.qhtml" -#define DIRL_FOOTER "footer.qhtml" -#define DIRL_STYLE "dirlist.css" /* mime-types */ static const struct { diff --git a/dirl.c b/dirl.c index d047b4e..90364bb 100644 --- a/dirl.c +++ b/dirl.c @@ -8,37 +8,106 @@ #include #include +#include "config.h" #include "dirl.h" #include "http.h" #include "util.h" -#include "config.h" -static char *suffix(int t) { +static char* +suffix(int t) +{ switch (t) { - case DT_FIFO: - return "|"; - case DT_DIR: - return "/"; - case DT_LNK: - return "@"; - case DT_SOCK: - return "="; + case DT_FIFO: + return "|"; + case DT_DIR: + return "/"; + case DT_LNK: + return "@"; + case DT_SOCK: + return "="; } return ""; } -enum status -dirl_header_default(int fd, const struct response *res) { +static char* +dirl_read_template(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) { + 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) { + fclose(tpl_fp); + return NULL; + } + + long tpl_size; + if ((tpl_size = ftell(tpl_fp)) < 0) { + fclose(tpl_fp); + return NULL; + } + + rewind(tpl_fp); + + /* Read template into tpl_buf */ + char* tpl_buf = (char*)malloc(sizeof(char) * tpl_size); + + if (tpl_buf == NULL) { + fclose(tpl_fp); + free(tpl_buf); + return NULL; + } + + if (fread(tpl_buf, 1, tpl_size, tpl_fp) < tpl_size) { + if (feof(tpl_fp)) { + warn("Reached end of template %s prematurely", tpl); + } else if (ferror(tpl_fp)) { + warn("Error while reading template %s", tpl); + } + + fclose(tpl_fp); + free(tpl_buf); + clearerr(tpl_fp); + + return NULL; + } + + return tpl_buf; +} + +static enum status +dirl_header_default(int fd, const struct response* res) +{ char esc[PATH_MAX]; html_escape(res->uri, esc, sizeof(esc)); if (dprintf(fd, - "\n\n\t" - "Index of %s\n" - "\t\n" - "\t\t

Index of %s

\n" - "\t\t\t..", - esc, esc) < 0) { + "\n" + "\n" + " \n" + " \n" + " Index of %s\n" + " \n" + " \n" + "

Index of %s

\n" + " ..", + esc, + esc) < 0) { return S_REQUEST_TIMEOUT; } @@ -46,45 +115,21 @@ dirl_header_default(int fd, const struct response *res) { } enum status -dirl_header(int fd, const struct response *res) +dirl_header(int fd, const struct response* res) { + char* tpl = dirl_read_template(DIRL_HEADER); - /* No header file defined, default */ -#ifndef DIRL_HEADER - return dirl_header_default(fd, res); -#endif - - /* Try find header in root (note that we are chroot'ed) */ - int header_fd; - if ( (header_fd = open(("/" DIRL_HEADER), O_RDONLY)) < 0 ) { - return dirl_header_default(fd, res); - } - - /* Get size of header */ - struct stat header_stat; - if (fstat(header_fd, &header_stat) < 0) { - return dirl_header_default(fd, res); - } - - /* Allocate space for file */ - char *header = (char *) malloc(sizeof(char) * header_stat.st_size); - if (header == NULL) { - return dirl_header_default(fd, res); - } - - /* Read header into string for template replacement */ - if ( (read(header_fd, header, header_stat.st_size)) < 0) { - free(header); + if(tpl == NULL) { return dirl_header_default(fd, res); } /* Replace placeholder */ - char *nhead = replace(header, "{idx}", "something"); + char* nhead = replace(tpl, "{idx}", "something"); /* Write header */ write(fd, nhead, strlen(nhead)); - free(header); + free(tpl); free(nhead); /* listing header */ @@ -92,12 +137,16 @@ dirl_header(int fd, const struct response *res) } static enum status -dirl_entry_default(int fd, const struct dirent* entry) { +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, + if (dprintf(fd, + "
\n\t\t%s%s", + esc, + (entry->d_type == DT_DIR) ? "/" : "", + esc, suffix(entry->d_type)) < 0) { return S_REQUEST_TIMEOUT; } @@ -106,30 +155,33 @@ dirl_entry_default(int fd, const struct dirent* entry) { } enum status -dirl_entry(int fd, const struct dirent* entry) { - /* Try find entry in root (note that we are chroot'ed) */ - int entry_fd; - if ((entry_fd = open(("/" DIRL_ENTRY), O_RDONLY)) < 0) { +dirl_entry(int fd, const struct dirent* entry) +{ + char* tpl = dirl_read_template(DIRL_ENTRY); + + if (tpl == NULL) { return dirl_entry_default(fd, entry); } - /* Get size of entry*/ - struct stat entry_stat; - if (fstat(entry_fd, &entry_stat) < 0) { - return dirl_entry_default(fd, entry); - } + /* Replace placeholder */ + char* nentry = replace(tpl, "{entry}", entry->d_name); /* Write entry */ - if (sendfile(fd, entry_fd, NULL, entry_stat.st_size) < 0) { - return dirl_entry_default(fd, entry); - } + write(fd, nentry, strlen(nentry)); + + free(tpl); + free(nentry); return 0; } static enum status -dirl_footer_default(int fd) { - if (dprintf(fd, "\n\t\n\n") < 0) { +dirl_footer_default(int fd) +{ + if (dprintf(fd, + "\n" + " \n" + "") < 0) { return S_REQUEST_TIMEOUT; } @@ -137,49 +189,32 @@ dirl_footer_default(int fd) { } enum status -dirl_footer(int fd) { - /* Try find footer in root (note that we are chroot'ed) */ - int footer_fd; - if ((footer_fd = open(("/" DIRL_FOOTER), O_RDONLY)) < 0) { +dirl_footer(int fd) +{ + char* tpl = dirl_read_template(DIRL_FOOTER); + + if(tpl == NULL) { return dirl_footer_default(fd); } - /* Get size of footer */ - struct stat footer_stat; - if (fstat(footer_fd, &footer_stat) < 0) { - return dirl_footer_default(fd); - } + /* Replace placeholder */ + char* nfoot = replace(tpl, "{idx}", "something"); /* Write footer */ - if (sendfile(fd, footer_fd, NULL, footer_stat.st_size) < 0) { - return dirl_footer_default(fd); - } - - return 0; -} - -int dirl_skip(const char *name) { - (void) name; -#ifdef DIRL_HEADER - if(!strcmp(name, DIRL_HEADER)) { - return 1; - } -#endif -#ifdef DIRL_ENTRY - if (!strcmp(name, DIRL_ENTRY)) { - return 1; - } -#endif -#ifdef DIRL_FOOTER - if (!strcmp(name, DIRL_FOOTER)) { - return 1; - } -#endif -#ifdef DIRL_STYLE - if (!strcmp(name, DIRL_STYLE)) { - return 1; - } -#endif + write(fd, nfoot, strlen(nfoot)); + free(tpl); + free(nfoot); return 0; } + +int +dirl_skip(const char* name) +{ + (void)name; // noop; avoid unused warning + + return !strcmp(name, DIRL_HEADER) // + || !strcmp(name, DIRL_ENTRY) // + || !strcmp(name, DIRL_FOOTER) // + || !strcmp(name, DIRL_STYLE); +} diff --git a/dirl.h b/dirl.h index d8df880..f147106 100644 --- a/dirl.h +++ b/dirl.h @@ -8,6 +8,11 @@ #include "http.h" +#define DIRL_HEADER ".header.tpl" +#define DIRL_ENTRY ".entry.tpl" +#define DIRL_FOOTER ".footer.tpl" +#define DIRL_STYLE "style.css" + struct dirl_env_entry { char *name; char *value; @@ -22,6 +27,7 @@ struct dirl_env { * meaning. Skips header-, entry-, footer templates and dirlist style css. */ int dirl_skip(const char*); + enum status dirl_header(int, const struct response*); enum status dirl_entry(int, const struct dirent*); enum status dirl_footer(int); diff --git a/util.c b/util.c index 487b94a..65e80e6 100644 --- a/util.c +++ b/util.c @@ -199,7 +199,7 @@ replace(const char *src, const char *old, const char* new) { srcidx = srcidx_old+old_len; } - strcpy(bufidx, srcidx); // copy tail + strncpy(bufidx, srcidx, strlen(srcidx)); // copy tail return buf; } From a22ac176ca35012c2ac3f84ac5ce75ff9b98267c Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sat, 29 Aug 2020 20:36:10 +0200 Subject: [PATCH 03/10] 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; From bd51ff593d3d889869de4ad47015507fa99c1af4 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 30 Aug 2020 08:43:10 +0200 Subject: [PATCH 04/10] Refactoring --- dirl.c | 117 +++++++--------------- dirl.h | 8 +- util.c | 309 +++++++++++++++++++++++++++++++++------------------------ util.h | 3 +- 4 files changed, 219 insertions(+), 218 deletions(-) diff --git a/dirl.c b/dirl.c index 711b3c8..900ecd0 100644 --- a/dirl.c +++ b/dirl.c @@ -31,59 +31,10 @@ suffix(int t) return ""; } -static char* -dirl_read(char* tpl) -{ - FILE* tpl_fp; - - if (!(tpl_fp = fopen(tpl, "r"))) { - return NULL; - } - - /* Get size of template */ - if (fseek(tpl_fp, 0L, SEEK_END) < 0) { - fclose(tpl_fp); - return NULL; - } - - long tpl_size; - if ((tpl_size = ftell(tpl_fp)) < 0) { - fclose(tpl_fp); - return NULL; - } - - rewind(tpl_fp); - - /* Read template into tpl_buf */ - char* tpl_buf = (char*)calloc(sizeof(char), tpl_size); - - if (tpl_buf == NULL) { - fclose(tpl_fp); - free(tpl_buf); - return NULL; - } - - if (fread(tpl_buf, 1, tpl_size, tpl_fp) < tpl_size) { - if (feof(tpl_fp)) { - warn("Reached end of template %s prematurely", tpl); - } else if (ferror(tpl_fp)) { - warn("Error while reading template %s", tpl); - } - - fclose(tpl_fp); - free(tpl_buf); - clearerr(tpl_fp); - - return NULL; - } - - return tpl_buf; -} - /* 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. + * one of the template files or NULL if none could be found. * * Note that we are chrooted. */ @@ -115,52 +66,47 @@ dirl_find_templ_dir(const char* start_path) return NULL; } +/* Helper function to fill template from base+name if file exists */ +static void +dirl_fill_templ(char** templ, char* base, char* name, char* def) +{ + char* path = calloc(sizeof(char), strlen(base) + strlen(name)); + strcpy(path, base); + strcat(path, name); + + char* file_buf = read_file(path); + free(path); + + if (file_buf) { + *templ = file_buf; + } else { + *templ = def; + } +} + 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 }; + struct dirl_templ templ; 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); + dirl_fill_templ(&templ.header, templ_dir, DIRL_HEADER, DIRL_HEADER_DEFAULT); + dirl_fill_templ(&templ.entry, templ_dir, DIRL_ENTRY, DIRL_ENTRY_DEFAULT); + dirl_fill_templ(&templ.footer, templ_dir, DIRL_FOOTER, DIRL_FOOTER_DEFAULT); free(templ_dir); - return templates; + return templ; } enum status dirl_header(int fd, const struct response* res, const struct dirl_templ* templ) { /* Replace placeholder */ - char* nhead = replace(templ->header, "{curdir}", "something"); + char* nhead = calloc(sizeof(char), strlen(templ->header)); + memcpy(nhead, templ->header, strlen(templ->header)); + replace(&nhead, "{curdir}", res->path); /* Write header */ write(fd, nhead, strlen(nhead)); @@ -175,7 +121,10 @@ enum status dirl_entry(int fd, const struct dirent* entry, const struct dirl_templ* templ) { /* Replace placeholder */ - char* nentry = replace(templ->entry, "{entry}", entry->d_name); + char* nentry = calloc(sizeof(char), strlen(templ->entry)); + memcpy(nentry, templ->entry, strlen(templ->entry)); + replace(&nentry, "{entry}", entry->d_name); + replace(&nentry, "{suffix}", suffix(entry->d_type)); /* Write entry */ write(fd, nentry, strlen(nentry)); @@ -189,7 +138,9 @@ enum status dirl_footer(int fd, const struct dirl_templ* templ) { /* Replace placeholder */ - char* nfoot = replace(templ->footer, "{idx}", "something"); + char* nfoot = calloc(sizeof(char), strlen(templ->footer)); + memcpy(nfoot, templ->footer, strlen(templ->footer)); + replace(&nfoot, "{idx}", "something"); /* Write footer */ write(fd, nfoot, strlen(nfoot)); diff --git a/dirl.h b/dirl.h index 5b6478c..b374c01 100644 --- a/dirl.h +++ b/dirl.h @@ -30,7 +30,7 @@ #define DIRL_ENTRY_DEFAULT \ "
\n" \ - " {entry}\n" + " {entry}{suffix}\n" #define DIRL_FOOTER_DEFAULT \ " \n" \ @@ -38,9 +38,9 @@ struct dirl_templ { - const char* header; - const char* entry; - const char* footer; + char* header; + char* entry; + char* footer; }; struct dirl_templ diff --git a/util.c b/util.c index e59aaa8..c998d8c 100644 --- a/util.c +++ b/util.c @@ -20,162 +20,162 @@ char *argv0; static void verr(const char *fmt, va_list ap) { - if (argv0 && strncmp(fmt, "usage", sizeof("usage") - 1)) { - fprintf(stderr, "%s: ", argv0); - } + if (argv0 && strncmp(fmt, "usage", sizeof("usage") - 1)) { + fprintf(stderr, "%s: ", argv0); + } - vfprintf(stderr, fmt, ap); + vfprintf(stderr, fmt, ap); - if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { - fputc(' ', stderr); - perror(NULL); - } else { - fputc('\n', stderr); - } + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } } void warn(const char *fmt, ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - verr(fmt, ap); - va_end(ap); + va_start(ap, fmt); + verr(fmt, ap); + va_end(ap); } void die(const char *fmt, ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - verr(fmt, ap); - va_end(ap); + va_start(ap, fmt); + verr(fmt, ap); + va_end(ap); - exit(1); + exit(1); } void epledge(const char *promises, const char *execpromises) { - (void)promises; - (void)execpromises; + (void)promises; + (void)execpromises; #ifdef __OpenBSD__ - if (pledge(promises, execpromises) == -1) { - die("pledge:"); - } + if (pledge(promises, execpromises) == -1) { + die("pledge:"); + } #endif /* __OpenBSD__ */ } void eunveil(const char *path, const char *permissions) { - (void)path; - (void)permissions; + (void)path; + (void)permissions; #ifdef __OpenBSD__ - if (unveil(path, permissions) == -1) { - die("unveil:"); - } + if (unveil(path, permissions) == -1) { + die("unveil:"); + } #endif /* __OpenBSD__ */ } int timestamp(char *buf, size_t len, time_t t) { - struct tm tm; + struct tm tm; - if (gmtime_r(&t, &tm) == NULL || - strftime(buf, len, "%a, %d %b %Y %T GMT", &tm) == 0) { - return 1; - } + if (gmtime_r(&t, &tm) == NULL || + strftime(buf, len, "%a, %d %b %Y %T GMT", &tm) == 0) { + return 1; + } - return 0; + return 0; } int esnprintf(char *str, size_t size, const char *fmt, ...) { - va_list ap; - int ret; + va_list ap; + int ret; - va_start(ap, fmt); - ret = vsnprintf(str, size, fmt, ap); - va_end(ap); + va_start(ap, fmt); + ret = vsnprintf(str, size, fmt, ap); + va_end(ap); - return (ret < 0 || (size_t)ret >= size); + return (ret < 0 || (size_t)ret >= size); } int prepend(char *str, size_t size, const char *prefix) { - size_t len = strlen(str), prefixlen = strlen(prefix); + size_t len = strlen(str), prefixlen = strlen(prefix); - if (len + prefixlen + 1 > size) { - return 1; - } + if (len + prefixlen + 1 > size) { + return 1; + } - memmove(str + prefixlen, str, len + 1); - memcpy(str, prefix, prefixlen); + memmove(str + prefixlen, str, len + 1); + memcpy(str, prefix, prefixlen); - return 0; + return 0; } void html_escape(const char *src, char *dst, size_t dst_siz) { - const struct { - char c; - char *s; - } escape[] = { - { '&', "&" }, - { '<', "<" }, - { '>', ">" }, - { '"', """ }, - { '\'', "'" }, - }; - size_t i, j, k, esclen; + const struct { + char c; + char *s; + } escape[] = { + { '&', "&" }, + { '<', "<" }, + { '>', ">" }, + { '"', """ }, + { '\'', "'" }, + }; + size_t i, j, k, esclen; - for (i = 0, j = 0; src[i] != '\0'; i++) { - for (k = 0; k < LEN(escape); k++) { - if (src[i] == escape[k].c) { - break; - } - } - if (k == LEN(escape)) { - /* no escape char at src[i] */ - if (j == dst_siz - 1) { - /* silent truncation */ - break; - } else { - dst[j++] = src[i]; - } - } else { - /* escape char at src[i] */ - esclen = strlen(escape[k].s); + for (i = 0, j = 0; src[i] != '\0'; i++) { + for (k = 0; k < LEN(escape); k++) { + if (src[i] == escape[k].c) { + break; + } + } + if (k == LEN(escape)) { + /* no escape char at src[i] */ + if (j == dst_siz - 1) { + /* silent truncation */ + break; + } else { + dst[j++] = src[i]; + } + } else { + /* escape char at src[i] */ + esclen = strlen(escape[k].s); - if (j >= dst_siz - esclen) { - /* silent truncation */ - break; - } else { - memcpy(&dst[j], escape[k].s, esclen); - j += esclen; - } - } - } - dst[j] = '\0'; + if (j >= dst_siz - esclen) { + /* silent truncation */ + break; + } else { + memcpy(&dst[j], escape[k].s, esclen); + j += esclen; + } + } + } + dst[j] = '\0'; } -char* -replace(const char *src, const char *old, const char* new) { +void +replace(char **src, const char *old, const char* new) { int old_len = strlen(old); int new_len = strlen(new); - int src_len = strlen(src); + int src_len = strlen(*src); /* Count needed replacements */ - const char* tmp = src; + const char* tmp = *src; int replc=0; while ((tmp=strstr(tmp, old))) { replc++; @@ -186,8 +186,8 @@ replace(const char *src, const char *old, const char* new) { char *buf = calloc( sizeof(char), src_len + replc*(abs(new_len-old_len)) + 1); /* Now start replacing */ - const char *srcidx = src; - const char *srcidx_old = src; + const char *srcidx = *src; + const char *srcidx_old = *src; char *bufidx = buf; while (replc--) { @@ -202,7 +202,56 @@ replace(const char *src, const char *old, const char* new) { strncpy(bufidx, srcidx, strlen(srcidx)); // copy tail - return buf; + free(*src); + *src = buf; +} + +char* +read_file(const char* path){ + FILE* tpl_fp; + + if (!(tpl_fp = fopen(path, "r"))) { + return NULL; + } + + /* Get size of template */ + if (fseek(tpl_fp, 0L, SEEK_END) < 0) { + fclose(tpl_fp); + return NULL; + } + + long tpl_size; + if ((tpl_size = ftell(tpl_fp)) < 0) { + fclose(tpl_fp); + return NULL; + } + + rewind(tpl_fp); + + /* Read template into tpl_buf */ + char* tpl_buf = (char*)calloc(sizeof(char), tpl_size); + + if (tpl_buf == NULL) { + fclose(tpl_fp); + free(tpl_buf); + return NULL; + } + + if (fread(tpl_buf, 1, tpl_size, tpl_fp) < tpl_size) { + if (feof(tpl_fp)) { + warn("Reached end of file %s prematurely", path); + } else if (ferror(tpl_fp)) { + warn("Error while reading file %s", path); + } + + fclose(tpl_fp); + free(tpl_buf); + clearerr(tpl_fp); + + return NULL; + } + + return tpl_buf; } #define INVALID 1 @@ -213,39 +262,39 @@ long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { - long long ll = 0; - int error = 0; - char *ep; - struct errval { - const char *errstr; - int err; - } ev[4] = { - { NULL, 0 }, - { "invalid", EINVAL }, - { "too small", ERANGE }, - { "too large", ERANGE }, - }; + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; - ev[0].err = errno; - errno = 0; - if (minval > maxval) { - error = INVALID; - } else { - ll = strtoll(numstr, &ep, 10); - if (numstr == ep || *ep != '\0') - error = INVALID; - else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) - error = TOOSMALL; - else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) - error = TOOLARGE; - } - if (errstrp != NULL) - *errstrp = ev[error].errstr; - errno = ev[error].err; - if (error) - ll = 0; + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; - return ll; + return ll; } /* @@ -257,10 +306,10 @@ strtonum(const char *numstr, long long minval, long long maxval, void * reallocarray(void *optr, size_t nmemb, size_t size) { - if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - nmemb > 0 && SIZE_MAX / nmemb < size) { - errno = ENOMEM; - return NULL; - } - return realloc(optr, size * nmemb); + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); } diff --git a/util.h b/util.h index 70179ac..c595ace 100644 --- a/util.h +++ b/util.h @@ -53,7 +53,8 @@ int timestamp(char *, size_t, time_t); int esnprintf(char *, size_t, const char *, ...); int prepend(char *, size_t, const char *); void html_escape(const char *, char *, size_t); -char *replace(const char *, const char *, const char *); +void replace(char **, const char *, const char *); +char *read_file(const char* path); void *reallocarray(void *, size_t, size_t); long long strtonum(const char *, long long, long long, const char **); From eba491b4b5bc9b061f78276d4a741294dc94b3a2 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 30 Aug 2020 09:38:02 +0200 Subject: [PATCH 05/10] Find template in root, don't search tail dir twice --- dirl.c | 25 ++++++++++++++++++++++--- dirl.h | 6 ++++-- resp.c | 2 +- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/dirl.c b/dirl.c index 900ecd0..764d750 100644 --- a/dirl.c +++ b/dirl.c @@ -44,6 +44,11 @@ dirl_find_templ_dir(const char* start_path) char* path_buf = calloc(sizeof(char), strlen(start_path)); strcat(path_buf, start_path); + if(path_buf[strlen(path_buf)-1] == '/') { + // don't read last dir twice + path_buf[strlen(path_buf)-1] = '\0'; + } + while (strlen(path_buf) != 0) { DIR* cur = opendir(path_buf); struct dirent* de; @@ -58,8 +63,17 @@ dirl_find_templ_dir(const char* start_path) } } - char* parent = strrchr(path_buf, '/'); - (*parent) = '\0'; // strip tail from path_buf + if (strlen(path_buf) > 1) { + char* parent = strrchr(path_buf, '/'); + (*parent) = '\0'; // strip tail from path_buf + + if(strlen(path_buf) == 0) { // we stripped root, let it loop once more + path_buf[0] = '/'; + path_buf[1] = '\0'; + } + } else { + path_buf[0] = '\0'; // we checked root, now terminate loop + } } free(path_buf); @@ -70,6 +84,11 @@ dirl_find_templ_dir(const char* start_path) static void dirl_fill_templ(char** templ, char* base, char* name, char* def) { + if (!base || !name) { + *templ = def; + return; + } + char* path = calloc(sizeof(char), strlen(base) + strlen(name)); strcpy(path, base); strcat(path, name); @@ -106,7 +125,7 @@ dirl_header(int fd, const struct response* res, const struct dirl_templ* templ) /* Replace placeholder */ char* nhead = calloc(sizeof(char), strlen(templ->header)); memcpy(nhead, templ->header, strlen(templ->header)); - replace(&nhead, "{curdir}", res->path); + replace(&nhead, "{uri}", res->uri); /* Write header */ write(fd, nhead, strlen(nhead)); diff --git a/dirl.h b/dirl.h index b374c01..ebdc4f8 100644 --- a/dirl.h +++ b/dirl.h @@ -22,10 +22,11 @@ "\n" \ " \n" \ " \n" \ - " Index of {curdir}\n" \ + " Index of {uri}\n" \ " \n" \ " \n" \ - "

Index of {curdir}

\n" \ + "

Index of {uri}

\n" \ + "
" \ " ..\n" #define DIRL_ENTRY_DEFAULT \ @@ -33,6 +34,7 @@ " {entry}{suffix}\n" #define DIRL_FOOTER_DEFAULT \ + "
" \ " \n" \ "" diff --git a/resp.c b/resp.c index 2042405..ea9d388 100644 --- a/resp.c +++ b/resp.c @@ -41,7 +41,7 @@ resp_dir(int fd, const struct response *res) } /* read templates */ - struct dirl_templ templates = dirl_read_templ(res->path); + struct dirl_templ templates = dirl_read_templ(res->uri); /* listing header */ if ((ret = dirl_header(fd, res, &templates))) { From e262166522c151329499b0a286cb41383c31b7f4 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 30 Aug 2020 14:32:48 +0200 Subject: [PATCH 06/10] Re-add replace and read_file to util --- util.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/util.c b/util.c index 5719b4b..78633dc 100644 --- a/util.c +++ b/util.c @@ -123,6 +123,92 @@ prepend(char *str, size_t size, const char *prefix) return 0; } +void +replace(char **src, const char *old, const char* new) { + int old_len = strlen(old); + int new_len = strlen(new); + int src_len = strlen(*src); + + /* Count needed replacements */ + const char* tmp = *src; + int replc=0; + while ((tmp=strstr(tmp, old))) { + replc++; + tmp += old_len; + } + + /* Allocate enough space for the new string */ + char *buf = calloc( sizeof(char), src_len + replc*(abs(new_len-old_len)) + 1); + + /* Now start replacing */ + const char *srcidx = *src; + const char *srcidx_old = *src; + char *bufidx = buf; + + while (replc--) { + srcidx_old = strstr(srcidx, old); + + 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; + } + + strncpy(bufidx, srcidx, strlen(srcidx)); // copy tail + + free(*src); + *src = buf; +} + +char* +read_file(const char* path){ + FILE* tpl_fp; + + if (!(tpl_fp = fopen(path, "r"))) { + return NULL; + } + + /* Get size of template */ + if (fseek(tpl_fp, 0L, SEEK_END) < 0) { + fclose(tpl_fp); + return NULL; + } + + long tpl_size; + if ((tpl_size = ftell(tpl_fp)) < 0) { + fclose(tpl_fp); + return NULL; + } + + rewind(tpl_fp); + + /* Read template into tpl_buf */ + char* tpl_buf = (char*)calloc(sizeof(char), tpl_size); + + if (tpl_buf == NULL) { + fclose(tpl_fp); + free(tpl_buf); + return NULL; + } + + if (fread(tpl_buf, 1, tpl_size, tpl_fp) < tpl_size) { + if (feof(tpl_fp)) { + warn("Reached end of file %s prematurely", path); + } else if (ferror(tpl_fp)) { + warn("Error while reading file %s", path); + } + + fclose(tpl_fp); + free(tpl_buf); + clearerr(tpl_fp); + + return NULL; + } + + return tpl_buf; +} + #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 From 2a3e25dc6b52883aa45700e42356b5cf5c5a73f5 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 30 Aug 2020 18:07:23 +0200 Subject: [PATCH 07/10] Fix merge leftovers, add attribution footer by default --- data.c | 59 ----------------------------------------- dirl.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++------- dirl.h | 27 ++++++++++++++----- util.c | 5 ++-- 4 files changed, 99 insertions(+), 76 deletions(-) diff --git a/data.c b/data.c index da3aa24..88e4ace 100644 --- a/data.c +++ b/data.c @@ -26,64 +26,6 @@ compareent(const struct dirent **d1, const struct dirent **d2) return strcmp((*d1)->d_name, (*d2)->d_name); } -static char * -suffix(int t) -{ - switch (t) { - case DT_FIFO: return "|"; - case DT_DIR: return "/"; - case DT_LNK: return "@"; - case DT_SOCK: return "="; - } - - return ""; -} - -static void -html_escape(const char *src, char *dst, size_t dst_siz) -{ - const struct { - char c; - char *s; - } escape[] = { - { '&', "&" }, - { '<', "<" }, - { '>', ">" }, - { '"', """ }, - { '\'', "'" }, - }; - size_t i, j, k, esclen; - - for (i = 0, j = 0; src[i] != '\0'; i++) { - for (k = 0; k < LEN(escape); k++) { - if (src[i] == escape[k].c) { - break; - } - } - if (k == LEN(escape)) { - /* no escape char at src[i] */ - if (j == dst_siz - 1) { - /* silent truncation */ - break; - } else { - dst[j++] = src[i]; - } - } else { - /* escape char at src[i] */ - esclen = strlen(escape[k].s); - - if (j >= dst_siz - esclen) { - /* silent truncation */ - break; - } else { - memcpy(&dst[j], escape[k].s, esclen); - j += esclen; - } - } - } - dst[j] = '\0'; -} - enum status data_send_dirlisting(int fd, const struct response *res) { @@ -91,7 +33,6 @@ data_send_dirlisting(int fd, const struct response *res) struct dirent **e; size_t i; int dirlen; - char esc[PATH_MAX /* > NAME_MAX */ * 6]; /* strlen("&...;") <= 6 */ /* read directory */ if ((dirlen = scandir(res->path, &e, NULL, compareent)) < 0) { diff --git a/dirl.c b/dirl.c index 764d750..0a9147b 100644 --- a/dirl.c +++ b/dirl.c @@ -2,11 +2,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include "config.h" @@ -31,6 +33,49 @@ suffix(int t) return ""; } +static void +html_escape(const char* src, char* dst, size_t dst_siz) +{ + const struct + { + char c; + char* s; + } escape[] = { + { '&', "&" }, { '<', "<" }, { '>', ">" }, + { '"', """ }, { '\'', "'" }, + }; + size_t i, j, k, esclen; + + for (i = 0, j = 0; src[i] != '\0'; i++) { + for (k = 0; k < LEN(escape); k++) { + if (src[i] == escape[k].c) { + break; + } + } + if (k == LEN(escape)) { + /* no escape char at src[i] */ + if (j == dst_siz - 1) { + /* silent truncation */ + break; + } else { + dst[j++] = src[i]; + } + } else { + /* escape char at src[i] */ + esclen = strlen(escape[k].s); + + if (j >= dst_siz - esclen) { + /* silent truncation */ + break; + } else { + memcpy(&dst[j], escape[k].s, esclen); + j += esclen; + } + } + } + dst[j] = '\0'; +} + /* Try to find templates up until root * * Iterates the directory hierarchy upwards. Returns the closest path containing @@ -44,8 +89,8 @@ dirl_find_templ_dir(const char* start_path) char* path_buf = calloc(sizeof(char), strlen(start_path)); strcat(path_buf, start_path); - if(path_buf[strlen(path_buf)-1] == '/') { - // don't read last dir twice + if(strlen(path_buf) > 1 && path_buf[strlen(path_buf)-1] == '/') { + // don't read last dir twice, except at root path_buf[strlen(path_buf)-1] = '\0'; } @@ -123,8 +168,8 @@ enum status dirl_header(int fd, const struct response* res, const struct dirl_templ* templ) { /* Replace placeholder */ - char* nhead = calloc(sizeof(char), strlen(templ->header)); - memcpy(nhead, templ->header, strlen(templ->header)); + char* nhead = calloc(sizeof(char), strlen(templ->header)+1); + memcpy(nhead, templ->header, strlen(templ->header)+1); replace(&nhead, "{uri}", res->uri); /* Write header */ @@ -139,12 +184,34 @@ dirl_header(int fd, const struct response* res, const struct dirl_templ* templ) enum status dirl_entry(int fd, const struct dirent* entry, const struct dirl_templ* templ) { + struct stat stat_buf; + lstat(entry->d_name, &stat_buf); + + char* nentry = calloc(sizeof(char), strlen(templ->entry)+1); + //strcat(nentry, templ->entry); + memcpy(nentry, templ->entry, strlen(templ->entry)+1); + /* Replace placeholder */ - char* nentry = calloc(sizeof(char), strlen(templ->entry)); - memcpy(nentry, templ->entry, strlen(templ->entry)); + char esc[PATH_MAX * 6]; + html_escape(entry->d_name, esc, PATH_MAX*6); replace(&nentry, "{entry}", entry->d_name); + replace(&nentry, "{suffix}", suffix(entry->d_type)); + char size_buf[1024]; + if(entry->d_type == DT_REG) { + snprintf(size_buf, 1024, "%ld", stat_buf.st_size); + } else { + sprintf(size_buf, "-"); + } + replace(&nentry, "{size}", size_buf); + + char time_buf[1024]; + struct tm tm; + gmtime_r(&stat_buf.st_mtim.tv_sec, &tm); + strftime(time_buf, 1024, "%F %H:%m", &tm); + replace(&nentry, "{modified}", time_buf); + /* Write entry */ write(fd, nentry, strlen(nentry)); @@ -157,9 +224,8 @@ enum status dirl_footer(int fd, const struct dirl_templ* templ) { /* Replace placeholder */ - char* nfoot = calloc(sizeof(char), strlen(templ->footer)); - memcpy(nfoot, templ->footer, strlen(templ->footer)); - replace(&nfoot, "{idx}", "something"); + char* nfoot = calloc(sizeof(char), strlen(templ->footer)+1); + memcpy(nfoot, templ->footer, strlen(templ->footer)+1); /* Write footer */ write(fd, nfoot, strlen(nfoot)); diff --git a/dirl.h b/dirl.h index ebdc4f8..3855e2a 100644 --- a/dirl.h +++ b/dirl.h @@ -26,16 +26,31 @@ " \n" \ " \n" \ "

Index of {uri}

\n" \ - "
" \ - " ..\n" + "

↵ Parent Directory

\n" \ + "
\n" \ + " \n" \ + " " #define DIRL_ENTRY_DEFAULT \ - "
\n" \ - " {entry}{suffix}\n" + " \n" \ + " \n" \ + " \n" \ + " \n" #define DIRL_FOOTER_DEFAULT \ - "
" \ - " \n" \ + "
NameModifiedSize
{entry}{suffix}\n" \ + " {modified}{size}
\n" \ + "
\n" \ + "

" \ + "Served by" \ + " quark" \ + " and" \ + " " \ + "dirl" \ + "" \ + "

\n" \ + "\n" \ "" struct dirl_templ diff --git a/util.c b/util.c index 78633dc..9127ae7 100644 --- a/util.c +++ b/util.c @@ -138,7 +138,8 @@ replace(char **src, const char *old, const char* new) { } /* Allocate enough space for the new string */ - char *buf = calloc( sizeof(char), src_len + replc*(abs(new_len-old_len)) + 1); + size_t buf_size = src_len + replc * (new_len - old_len) + 1; + char* buf = calloc(sizeof(char), buf_size); /* Now start replacing */ const char *srcidx = *src; @@ -192,7 +193,7 @@ read_file(const char* path){ return NULL; } - if (fread(tpl_buf, 1, tpl_size, tpl_fp) < tpl_size) { + if (fread(tpl_buf, 1, tpl_size, tpl_fp) < (size_t) tpl_size) { if (feof(tpl_fp)) { warn("Reached end of file %s prematurely", path); } else if (ferror(tpl_fp)) { From d06c37fbd5693fe363ae2f2e6569e8fe6cc93f2a Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 30 Aug 2020 19:07:57 +0200 Subject: [PATCH 08/10] Add README for dirl, publish CI builds --- .drone.yml | 26 +++++++-------- README.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 95 insertions(+), 23 deletions(-) diff --git a/.drone.yml b/.drone.yml index 02cdb2c..174b1f6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,18 +7,16 @@ steps: image: gcc commands: - make + - mv quark quark-dirl -- name: run - image: debian - commands: - - cp quark /usr/local/bin - - useradd web - - mkdir -p web && cd web && echo "hello from quark" > index.html - - quark -p 9130 -h run -l -u web -g web - detach: true - -- name: test - image: curlimages/curl - commands: - - sleep 15 - - curl http://run:9130 +- name: publish + image: appleboy/drone-scp + settings: + host: friedl.net + username: + from_secret: deploy_user + password: + from_secret: deploy_password + port: 22 + target: /var/services/dirlist/repo/bin/suckless/quark + source: quark-dirl diff --git a/README.md b/README.md index c26554f..c2d1193 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,94 @@ found at https://git.suckless.org/quark. Quark is a small http server. -# Issues +# DIRL -## fork: Resource temporarily unavailable -When running [quark](http://tools.suckless.org/quark/) (#6606994) on my system -with `sudo ./quark -p 9763 -u -g ` it dies with `./quark: fork: -Resource temporarily unavailable` at `fork()`. +dirl is a quark extension for customized directory listings. -Reason being that by default quark sets the RLIMIT_NPROC to 512 processes. When running as a non-exclusive user this limit is easily reached before even starting quark. +Per default dirl generates html for a directory listing like this: -`resource-depletion-fix` contains a small forkbomb (`minibomb.c`) to simulate a user with > 512 processes. Compile it with `make minibomb`. When running the minibomb and quark with the same user quark fails. +```html + + + + + + Index of {uri} + + +

Index of {uri}

+

↵ Parent Directory

+
+ + + -The `resource-depletion-fix` branch contains a fix by setting the RLIMIT_NPROC only if the current system limit is lower than what would be set by quark. You can [download the patch](https://dirlist.friedl.net/suckless/quark/), or compile from the `resource-depletion-fix` branch. + + + + + + + -Note that quark also has a `-n` parameter with which the max number of processes can be set as an alternative to this patch. + +
NameModifiedSize
{entry}{suffix} + {modified}{size}
+
+

+ Served by quark and dirl +

+ + + +``` + +## Customize + +The default listing can be styled by a `style.css` in the root directory. + +You can also use your fully customized template by creating one or all the +template files for each section. Per default the section templates are named: +- .header.tpl +- .entry.tpl (repeated for each directory entry) +- .footer.tpl + +Note that if you only provide some of the template files, they have to be +compatible with the generated default for the other sections. + +For each of these templates you can use placeholders that are replaced by their respective values: +- header + * `{uri}`: Replaced by the current path +- entry + * `{entry}`: Name of the entry + * `{suffix}`: A suffix for the entry, mostly useful to distinguish directories (suffix '/') from files + * `{modified}`: Date the entry was last modified + * `{size}`: Size of the entry (if available) + +### Subdirectory styling + +dirl tries to the closest template for the currently visited path. This gives +you the opportunity to override templates in subdirectories. dirl walks the +directory hierarchy upwards from the currently visited path. As soon as it finds +one of the template files in a directory, it stops searching and uses the +templates in that directory. + +In case no templates are found up until and including root, the default +templates are used. + +### Customize names + +The files defined as templates and style are ignored in the directory listing +itself. In case you need to list one of these directories, or have any other +reason to choose different names, the filenames can be configured in `dirl.h`. +Note that you need to compile your own quark version then. + +# Download +You can also download CI builds for [quark-dirl](https://dirlist.friedl.net/bin/suckless/quark/). + +There are no official releases. Quark has no dependencies and you can easily +build it from source. Don't forget to read up on the [suckless +philosophy](http://suckless.org/philosophy/). # Github Users If you are visiting this repository on GitHub, you are on a mirror of From 66558aa615cb80827384e37c7e07f6c9070ba082 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Mon, 31 Aug 2020 06:42:23 +0200 Subject: [PATCH 09/10] Stat full path, allocate enough space Not stat'ing the full path (just entry->d_name) strangely works on glibc/fedora but fails on musl/alpine. Stat'ing the full path is the right thing to do, anyways. There was a heap corruption in `dirl_find_templ_dir` due not allocating enough space for the terminating NULL in `path_buf`. This again only showed up in musl/alpine. --- data.c | 2 +- dirl.c | 39 ++++++++++++++++++++++----------------- dirl.h | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/data.c b/data.c index 88e4ace..ae06a0c 100644 --- a/data.c +++ b/data.c @@ -55,7 +55,7 @@ data_send_dirlisting(int fd, const struct response *res) } /* entry line */ - if ((ret = dirl_entry(fd, e[i], &templates))) { + if ((ret = dirl_entry(fd, e[i], res, &templates))) { goto cleanup; } diff --git a/dirl.c b/dirl.c index 0a9147b..1c0689a 100644 --- a/dirl.c +++ b/dirl.c @@ -86,12 +86,12 @@ html_escape(const char* src, char* dst, size_t dst_siz) static char* dirl_find_templ_dir(const char* start_path) { - char* path_buf = calloc(sizeof(char), strlen(start_path)); + char* path_buf = calloc(sizeof(char), strlen(start_path)+1); strcat(path_buf, start_path); - if(strlen(path_buf) > 1 && path_buf[strlen(path_buf)-1] == '/') { + if (strlen(path_buf) > 1 && path_buf[strlen(path_buf) - 1] == '/') { // don't read last dir twice, except at root - path_buf[strlen(path_buf)-1] = '\0'; + path_buf[strlen(path_buf) - 1] = '\0'; } while (strlen(path_buf) != 0) { @@ -100,8 +100,8 @@ dirl_find_templ_dir(const char* start_path) 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)) { + if (!strcmp(DIRL_HEADER, de->d_name) || !strcmp(DIRL_ENTRY, de->d_name) || + !strcmp(DIRL_FOOTER, de->d_name)) { closedir(cur); return path_buf; } @@ -112,7 +112,7 @@ dirl_find_templ_dir(const char* start_path) char* parent = strrchr(path_buf, '/'); (*parent) = '\0'; // strip tail from path_buf - if(strlen(path_buf) == 0) { // we stripped root, let it loop once more + if (strlen(path_buf) == 0) { // we stripped root, let it loop once more path_buf[0] = '/'; path_buf[1] = '\0'; } @@ -168,8 +168,8 @@ enum status dirl_header(int fd, const struct response* res, const struct dirl_templ* templ) { /* Replace placeholder */ - char* nhead = calloc(sizeof(char), strlen(templ->header)+1); - memcpy(nhead, templ->header, strlen(templ->header)+1); + char* nhead = calloc(sizeof(char), strlen(templ->header) + 1); + memcpy(nhead, templ->header, strlen(templ->header) + 1); replace(&nhead, "{uri}", res->uri); /* Write header */ @@ -182,24 +182,29 @@ dirl_header(int fd, const struct response* res, const struct dirl_templ* templ) } enum status -dirl_entry(int fd, const struct dirent* entry, const struct dirl_templ* templ) +dirl_entry(int fd, + const struct dirent* entry, + const struct response* res, + const struct dirl_templ* templ) { struct stat stat_buf; - lstat(entry->d_name, &stat_buf); + char* path_buf = calloc(sizeof(char), strlen(res->path)+strlen(entry->d_name)); + strcat(path_buf, res->path); + strcat(path_buf, entry->d_name); + lstat(path_buf, &stat_buf); - char* nentry = calloc(sizeof(char), strlen(templ->entry)+1); - //strcat(nentry, templ->entry); - memcpy(nentry, templ->entry, strlen(templ->entry)+1); + char* nentry = calloc(sizeof(char), strlen(templ->entry) + 1); + memcpy(nentry, templ->entry, strlen(templ->entry) + 1); /* Replace placeholder */ char esc[PATH_MAX * 6]; - html_escape(entry->d_name, esc, PATH_MAX*6); + html_escape(entry->d_name, esc, PATH_MAX * 6); replace(&nentry, "{entry}", entry->d_name); replace(&nentry, "{suffix}", suffix(entry->d_type)); char size_buf[1024]; - if(entry->d_type == DT_REG) { + if (entry->d_type == DT_REG) { snprintf(size_buf, 1024, "%ld", stat_buf.st_size); } else { sprintf(size_buf, "-"); @@ -224,8 +229,8 @@ enum status dirl_footer(int fd, const struct dirl_templ* templ) { /* Replace placeholder */ - char* nfoot = calloc(sizeof(char), strlen(templ->footer)+1); - memcpy(nfoot, templ->footer, strlen(templ->footer)+1); + char* nfoot = calloc(sizeof(char), strlen(templ->footer) + 1); + memcpy(nfoot, templ->footer, strlen(templ->footer) + 1); /* Write footer */ write(fd, nfoot, strlen(nfoot)); diff --git a/dirl.h b/dirl.h index 3855e2a..b6505c7 100644 --- a/dirl.h +++ b/dirl.h @@ -82,7 +82,7 @@ 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*); +dirl_entry(int, const struct dirent*, const struct response*, const struct dirl_templ*); /* Print footer into the response */ enum status From 48db5eea1d86f68db8b08958d63a86026b8fc296 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Mon, 31 Aug 2020 18:58:01 +0200 Subject: [PATCH 10/10] Fix path for root case In case of root, res->path returns '.' which does not mix well with concatenating the entry name. For example this may result in `.bin` for a folder `bin` in root. --- dirl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dirl.c b/dirl.c index 1c0689a..67ec21f 100644 --- a/dirl.c +++ b/dirl.c @@ -189,7 +189,7 @@ dirl_entry(int fd, { struct stat stat_buf; char* path_buf = calloc(sizeof(char), strlen(res->path)+strlen(entry->d_name)); - strcat(path_buf, res->path); + strcat(path_buf, res->uri); strcat(path_buf, entry->d_name); lstat(path_buf, &stat_buf);