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 ee24c4a..174b1f6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,3 +7,16 @@ steps: image: gcc commands: - make + - mv quark quark-dirl + +- 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/.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/Makefile b/Makefile index 0c0ebed..7573552 100644 --- a/Makefile +++ b/Makefile @@ -4,11 +4,12 @@ include config.mk -COMPONENTS = data http sock util +COMPONENTS = data http sock util dirl all: quark -data.o: data.c data.h util.h http.h config.mk +data.o: data.c data.h util.h http.h dirl.h config.mk +dirl.o: dirl.c dirl.h util.h http.h config.mk http.o: http.c http.h util.h http.h data.h config.h config.mk main.o: main.c util.h sock.h http.h arg.h config.h config.mk sock.o: sock.c sock.h util.h config.mk diff --git a/README.md b/README.md index ebb6cfe..c2d1193 100644 --- a/README.md +++ b/README.md @@ -5,36 +5,94 @@ found at https://git.suckless.org/quark. Quark is a small http server. -# Feature Patches +# DIRL -## Dirl: Customizable directory listing -[dirl](https://git.friedl.net/playground/suckless-quark/src/branch/dirlist) lets -you serve a fully customizable directory listing. +dirl is a quark extension for customized directory listings. -You can compile `dirl` from the `dirlist` branch, download a pre-compiled [musl -binary](https://dirlist.friedl.net/bin/suckless/quark/quark-dirl) or even pull a -pre-made [docker -image](https://hub.docker.com/repository/docker/arminfriedl/quark). +Per default dirl generates html for a directory listing like this: -You can find an example deployment of [here](https://dirlist.friedl.net/). It -uses the default template just with a custom css. You can define your own -templates too for full customization. For details see the dirl -[README.md](https://git.friedl.net/playground/suckless-quark/src/branch/dirlist/README.md). +```html + + + +
+ +Name | Modified | Size |
---|---|---|
{entry}{suffix} + | {modified} | +{size} | +
Name | Modified | Size |
---|---|---|
{entry}{suffix}\n" \ + " | {modified} | \n" \ + "{size} | \n" \ + "
" \ + "Served by" \ + " quark" \ + " and" \ + " " \ + "dirl" \ + "" \ + "
\n" \ + "\n" \ + "" + +struct dirl_templ +{ + char* header; + char* entry; + 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 response*, const struct dirl_templ*); + +/* Print footer into the response */ +enum status +dirl_footer(int, const struct dirl_templ*); + +#endif /* DIRL_H */ diff --git a/util.c b/util.c index b281613..9127ae7 100644 --- a/util.c +++ b/util.c @@ -20,107 +20,194 @@ 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 +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 */ + 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; + 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) < (size_t) 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 @@ -131,39 +218,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; } /* @@ -175,10 +262,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 bc7f8ec..be152bd 100644 --- a/util.h +++ b/util.h @@ -52,6 +52,8 @@ void eunveil(const char *, const char *); int timestamp(char *, size_t, time_t); int esnprintf(char *, size_t, const char *, ...); int prepend(char *, size_t, 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 **);