diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-02-16 12:34:53 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-02-16 12:34:53 +0200 |
commit | c93a6c17a2af32dd15c09adb926088d353ff800d (patch) | |
tree | 3d99f16caeb62c1a7b9d238031247e01f5a35f6e | |
parent | bbb854527f0b841ffedbc2ba769ad495cd13a34d (diff) | |
download | fileserv-c93a6c17a2af32dd15c09adb926088d353ff800d.tar.gz fileserv-c93a6c17a2af32dd15c09adb926088d353ff800d.tar.bz2 |
Cleanup
Move the directory listing code into a separate module. Improve error
reporting in directory index code. Don't bail out on (most of the)
out of memory errors.
* src/dirls.c: New file.
* src/dirls.h: New file.
* src/fileserv.c (errno_to_http_code): Increase resolution.
* src/fileserv.h (parse_template_string)
(parse_template_file): Change return value.
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/config.c | 5 | ||||
-rw-r--r-- | src/dirls.c | 247 | ||||
-rw-r--r-- | src/dirls.h | 17 | ||||
-rw-r--r-- | src/fileserv.c | 24 | ||||
-rw-r--r-- | src/fileserv.h | 4 | ||||
-rw-r--r-- | src/idx.c | 669 |
7 files changed, 598 insertions, 370 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index b793023..d812da5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,3 +3,3 @@ fileserv_SOURCES=fileserv.c runas.c fileserv.h logger.c pidfile.c\ wordsplit.c wordsplit.h catfile.c config.c idx.c defidx.h\ - mem.c remoteip.c icon.c + mem.c remoteip.c icon.c dirls.c dirls.h BUILT_SOURCES=defidx.h diff --git a/src/config.c b/src/config.c index a7561e7..adcc677 100644 --- a/src/config.c +++ b/src/config.c @@ -319,3 +319,6 @@ set_index_template(size_t argc, char **argv, CONFIG *conf, } - parse_template_file(argv[1]); + if (parse_template_file(argv[1])) { + error("%s:%d: invalid template", file, line); + return 1; + } return 0; diff --git a/src/dirls.c b/src/dirls.c new file mode 100644 index 0000000..62ce71c --- /dev/null +++ b/src/dirls.c @@ -0,0 +1,247 @@ +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> +#include <errno.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/queue.h> +#include <string.h> +#include <unistd.h> +#include "fileserv.h" +#include "dirls.h" +#include "mimetypes.h" + +void +dirls_init(DIRLS *lst) +{ + lst->count = 0; + STAILQ_INIT(&lst->list); +} + +void +dirls_free(DIRLS *lst) +{ + DIRLSENT *ent; + + while ((ent = STAILQ_FIRST(&lst->list))) { + STAILQ_REMOVE_HEAD(&lst->list, next); + free(ent); + } + lst->count = 0; +} + +static void +dirls_append(DIRLS *lst, DIRLSENT *ent) +{ + STAILQ_INSERT_TAIL(&lst->list, ent, next); + lst->count++; +} + +int +dirls_scan(DIRLS *dirls, char const *path, CONFIG const *conf) +{ + DIR *dir; + struct dirent *ent; + DIRLSENT *dirlsent; + int err = 0; + + dir = opendir(path); + if (!dir) { + err = errno; + error("can't open directory %s: %s", + path, strerror(err)); + return err; + } + dirls_init(dirls); + while (err == 0 && (ent = readdir(dir))) { + size_t len; + char *name; + struct stat st; + + if (filename_is_hidden(ent->d_name, conf)) + continue; + + name = catfile(path, ent->d_name); + if (!name) { + err = errno; + break; + } + + if (stat(name, &st)) { + error("can't stat %s: %s", name, strerror(errno)); + free(name); + continue; + } + + if (conf->list_unreadable == 0) { + if (access(name, R_OK)) { + free(name); + continue; + } + } + + len = strlen(ent->d_name); + dirlsent = malloc(sizeof(*dirlsent) + + len + + (S_ISDIR(st.st_mode) ? 1 : 0) + + 1); + if (!dirlsent) + err = errno; + else { + dirlsent->name = (char*)(dirlsent + 1); + memcpy(dirlsent->name, ent->d_name, len); + if (S_ISDIR(st.st_mode)) + dirlsent->name[len++] = '/'; + dirlsent->name[len] = 0; + + dirlsent->st = st; + dirlsent->type = get_file_type(name); + dirls_append(dirls, dirlsent); + } + free(name); + } + closedir(dir); + + if (err) + dirls_free(dirls); + + return err; +} + +static void +dirls_qsort(DIRLS *list, int cmp (DIRLSENT const *, DIRLSENT const *, void *), + void *data) +{ + if (list->count < 2) + return; + else if (list->count == 2) { + DIRLSENT *a, *b; + a = STAILQ_FIRST(&list->list); + b = STAILQ_NEXT(a, next); + if (cmp(a, b, data) > 0) { + STAILQ_REMOVE_HEAD(&list->list, next); + STAILQ_INSERT_TAIL(&list->list, a, next); + } + } else { + DIRLSENT *cur, *middle; + DIRLS high, low; + int rc; + + cur = middle = STAILQ_FIRST(&list->list); + do { + cur = STAILQ_NEXT(cur, next); + if (!cur) + return; + } while ((rc = cmp(middle, cur, data)) == 0); + + if (rc > 0) + middle = cur; + + dirls_init(&high); + dirls_init(&low); + + while ((cur = STAILQ_FIRST(&list->list))) { + STAILQ_REMOVE_HEAD(&list->list, next); + if (cmp(middle, cur, data) < 0) + dirls_append(&high, cur); + else + dirls_append(&low, cur); + } + + /* Sort both lists */ + dirls_qsort(&low, cmp, data); + dirls_qsort(&high, cmp, data); + + /* Join lists in order and return */ + STAILQ_CONCAT(&low.list, &high.list); + list->list = low.list; + list->count = low.count + high.count; + } +} + +static char ordargs[] = "AD"; +static char colargs[] = "NMSD"; + +INDEX_SORT_COL +index_sort_col_from_arg(int c) +{ + char const *p; + if ((p = strchr(colargs, c))) + return p - colargs; + return ISC_NAME; +} + +int +index_sort_col_to_arg(INDEX_SORT_COL c) +{ + return colargs[c]; +} + +INDEX_SORT_ORD +index_sort_ord_from_arg(int c) +{ + char const *p; + if ((p = strchr(ordargs, c))) + return p - ordargs; + return ISO_ASC; +} + +int +index_sort_ord_to_arg(INDEX_SORT_ORD c) +{ + return ordargs[c]; +} + +static inline int +comp_result(int val, void *data) +{ + if (*(INDEX_SORT_ORD*)data == ISO_DESC) + val = -val; + return val; +} + +static int +comp_name(DIRLSENT const *a, DIRLSENT const *b, void *data) +{ + return comp_result(strcmp(a->name, b->name), data); +} + +static int +comp_time(DIRLSENT const *a, DIRLSENT const *b, void *data) +{ + int r; + if (a->st.st_mtime < b->st.st_mtime) + r = -1; + else if (a->st.st_mtime > b->st.st_mtime) + r = 1; + else + r = 0; + return comp_result(r, data); +} + +static int +comp_size(DIRLSENT const *a, DIRLSENT const *b, void *data) +{ + int r; + if (a->st.st_size < b->st.st_size) + r = -1; + else if (a->st.st_size > b->st.st_size) + r = 1; + else + r = 0; + return comp_result(r, data); +} + +static int (*comp[])(DIRLSENT const *, DIRLSENT const *, void *) = { + comp_name, + comp_time, + comp_size, + comp_name +}; + +void +dirls_sort(DIRLS *dirls, INDEX_SORT_COL col, INDEX_SORT_ORD ord) +{ + dirls_qsort(dirls, comp[col], &ord); +} + diff --git a/src/dirls.h b/src/dirls.h new file mode 100644 index 0000000..0067bff --- /dev/null +++ b/src/dirls.h @@ -0,0 +1,17 @@ +typedef struct dirlsent { + char *name; + struct stat st; + char const *type; + STAILQ_ENTRY(dirlsent) next; +} DIRLSENT; + +typedef struct dirls { + size_t count; + STAILQ_HEAD(, dirlsent) list; +} DIRLS; + +void dirls_init(DIRLS *dirls); +void dirls_free(DIRLS *dirls); +int dirls_scan(DIRLS *dirls, char const *path, CONFIG const *conf); +void dirls_sort(DIRLS *dirls, INDEX_SORT_COL col, INDEX_SORT_ORD ord); + diff --git a/src/fileserv.c b/src/fileserv.c index 98c0c33..ae1599d 100644 --- a/src/fileserv.c +++ b/src/fileserv.c @@ -66,2 +66,17 @@ fileserv_panic(void *cls, const char *file, unsigned int line, +static inline int +errno_to_http_code(int ec) +{ + switch (ec) { + case EINVAL: + case ENOSYS: + case ENOMEM: + return MHD_HTTP_INTERNAL_SERVER_ERROR; + case ENOENT: + return MHD_HTTP_NOT_FOUND; + default: + return MHD_HTTP_FORBIDDEN; + } +} + void @@ -247,9 +262,2 @@ cfname(char const *fname) - -static inline int -errno_to_http_code(int ec) -{ - return ec == ENOENT ? MHD_HTTP_NOT_FOUND : MHD_HTTP_FORBIDDEN; -} - static int @@ -439,3 +447,3 @@ get_file_resp(struct MHD_Connection *conn, char const *url, FILE_RESP *resp) close(fd); - return MHD_HTTP_FORBIDDEN; + return errno_to_http_code(res); } diff --git a/src/fileserv.h b/src/fileserv.h index d22d927..cf72b39 100644 --- a/src/fileserv.h +++ b/src/fileserv.h @@ -124,4 +124,4 @@ int filename_is_valid(char const *name); -void parse_template_string(char const *str); -void parse_template_file(char const *file_name); +int parse_template_string(char const *str); +int parse_template_file(char const *file_name); @@ -7,4 +7,2 @@ #include <sys/queue.h> -#include <sys/types.h> -#include <dirent.h> #include <unistd.h> @@ -13,6 +11,6 @@ #include "fileserv.h" -#include "mimetypes.h" +#include "dirls.h" #include "wordsplit.h" -enum index_node_type { +enum tmpl_node_type { NODE_TEXT, @@ -23,16 +21,16 @@ enum index_node_type { -typedef STAILQ_HEAD(index_node_list, index_node) INDEX_NODE_LIST; +typedef STAILQ_HEAD(tmpl_node_list, tmpl_node) TMPL_NODE_LIST; -struct index_cond { +struct tmpl_cond { char *expr; - INDEX_NODE_LIST branch[2]; + TMPL_NODE_LIST branch[2]; }; -struct index_node { +struct tmpl_node { int type; - STAILQ_ENTRY(index_node) next; + STAILQ_ENTRY(tmpl_node) next; union { char *text; - struct index_node_list loop; - struct index_cond cond; + struct tmpl_node_list loop; + struct tmpl_cond cond; } v; @@ -40,6 +38,6 @@ struct index_node { -typedef struct index_node INDEX_NODE; +typedef struct tmpl_node TMPL_NODE; struct condition { - INDEX_NODE *node; + TMPL_NODE *node; int brn; @@ -49,2 +47,142 @@ typedef STAILQ_HEAD(, condition) COND_LIST; +struct eval_env; + +/* Type-agnostic node functions */ + +struct node_class { + void (*node_init)(TMPL_NODE *); + void (*node_free)(TMPL_NODE *); + int (*node_eval)(TMPL_NODE *, struct eval_env *); +}; + +static int node_text_eval(TMPL_NODE *, struct eval_env *); +static int node_loop_eval(TMPL_NODE *, struct eval_env *); +static int node_cond_eval(TMPL_NODE *, struct eval_env *); +static int node_expr_eval(TMPL_NODE *, struct eval_env *); + +static void node_loop_init(TMPL_NODE *); +static void node_loop_free(TMPL_NODE *); + +static void node_cond_init(TMPL_NODE *); +static void node_cond_free(TMPL_NODE *); + +static struct node_class node_class[] = { + [NODE_TEXT] = { NULL, NULL, node_text_eval }, + [NODE_LOOP] = { node_loop_init, node_loop_free, node_loop_eval }, + [NODE_COND] = { node_cond_init, node_cond_free, node_cond_eval }, + [NODE_EXPR] = { NULL, NULL, node_expr_eval } +}; + +#define ASSERT_NODE_TYPE(n) \ + assert((n)->type >= 0 && (n)->type <= sizeof(node_class)/sizeof(node_class[0])) + +static void +node_init(TMPL_NODE *node) +{ + ASSERT_NODE_TYPE(node); + if (node_class[node->type].node_init) + return node_class[node->type].node_init(node); +} + +static void +node_free(TMPL_NODE *node) +{ + ASSERT_NODE_TYPE(node); + if (node_class[node->type].node_free) + node_class[node->type].node_free(node); + free(node); +} + +static int +node_eval(TMPL_NODE *node, struct eval_env *env) +{ + ASSERT_NODE_TYPE(node); + assert(node_class[node->type].node_eval); + return node_class[node->type].node_eval(node, env); +} + + +/* Node list functions */ + +static void +node_list_free(TMPL_NODE_LIST *nlist) +{ + TMPL_NODE *node; + + while ((node = STAILQ_FIRST(nlist))) { + STAILQ_REMOVE_HEAD(nlist, next); + node_free(node); + } +} + +static int +node_list_eval(TMPL_NODE_LIST *nlist, struct eval_env *env) +{ + TMPL_NODE *node; + int rc = 0; + + STAILQ_FOREACH(node, nlist, next) { + rc = node_eval(node, env); + if (rc) + break; + } + return rc; +} + +/* Node-specific initialization and deallocation functions */ +static void +node_loop_init(TMPL_NODE *node) +{ + STAILQ_INIT(&node->v.loop); +} + +static void +node_loop_free(TMPL_NODE *node) +{ + node_list_free(&node->v.loop); +} + +static void +node_cond_init(TMPL_NODE *node) +{ + STAILQ_INIT(&node->v.cond.branch[0]); + STAILQ_INIT(&node->v.cond.branch[1]); +} + +static void +node_cond_free(TMPL_NODE *node) +{ + node_list_free(&node->v.cond.branch[0]); + node_list_free(&node->v.cond.branch[1]); +} + +/* Parser error codes */ +enum { + TMPL_NOERR, + TMPL_ERR_LOOP_NESTING, + TMPL_ERR_ENDLOOP_WITHOUT_LOOP, + TMPL_ERR_ENDIF_WITHOUT_IF, + TMPL_ERR_ELSE_WITHOUT_IF, + TMPL_ERR_DUP_ELSE, + TMPL_ERR_ESCAPE_NOT_CLOSED, + TMPL_ERR_LOOP_NOT_CLOSED, + TMPL_ERR_COND_NOT_CLOSED, + TMPL_ERR_NOMEM +}; + +/* Corresponding textual descriptions */ +static char const *tmpl_err_str[] = { + "no error", + "attempt to nest loops", + "endloop without loop", + "endif without if", + "else without if", + "duplicate else", + "escape not closed", + "loop not closed", + "conditional not closed", + "not enough memory" +}; + +/* Template parser state */ struct template_state { @@ -55,14 +193,30 @@ struct template_state { char const *cur; + int error; }; -static void parse_template(INDEX_NODE_LIST *nodes, struct template_state *st); +/* Allocate and initialize single node */ +static inline TMPL_NODE * +node_alloc(struct template_state *st, int type, size_t extra) +{ + TMPL_NODE *np = calloc(1, sizeof(*np) + extra); + if (np) + np->type = type; + else + st->error = TMPL_ERR_NOMEM; + node_init(np); + return np; +} + +/* Template parser */ +static void parse_template(TMPL_NODE_LIST *nodes, struct template_state *st); -static INDEX_NODE * -new_text_node(int type, char const *start, size_t len) +static TMPL_NODE * +new_text_node(struct template_state *st, int type, size_t len) { - INDEX_NODE *np = xmalloc(sizeof(*np)); - np->type = type; - np->v.text = xmalloc(len + 1); - memcpy(np->v.text, start, len); - np->v.text[len] = 0; + TMPL_NODE *np = node_alloc(st, type, len + 1); + if (np) { + np->v.text = (char*)(np + 1); + memcpy(np->v.text, st->start, len); + np->v.text[len] = 0; + } return np; @@ -70,3 +224,3 @@ new_text_node(int type, char const *start, size_t len) -static INDEX_NODE * +static TMPL_NODE * next_text_node(struct template_state *st) @@ -82,6 +236,6 @@ next_text_node(struct template_state *st) - return new_text_node(NODE_TEXT, st->start, st->cur - st->start); + return new_text_node(st, NODE_TEXT, st->cur - st->start); } -static INDEX_NODE * +static TMPL_NODE * parse_cond(struct template_state *st, int brn, size_t off, size_t len) @@ -89,3 +243,3 @@ parse_cond(struct template_state *st, int brn, size_t off, size_t len) struct condition cond; - INDEX_NODE *np; + TMPL_NODE *np; @@ -93,16 +247,16 @@ parse_cond(struct template_state *st, int brn, size_t off, size_t len) off++; - - np = xmalloc(sizeof(*np)); - np->type = NODE_COND; len -= off; - np->v.cond.expr = xmalloc(len + 1); - memcpy(np->v.cond.expr, st->start + off, len); - np->v.cond.expr[len] = 0; - cond.node = np; - cond.brn = brn; - STAILQ_INSERT_HEAD(&st->cond, &cond, next); - STAILQ_INIT(&np->v.cond.branch[!cond.brn]); - parse_template(&np->v.cond.branch[cond.brn], st); - + np = node_alloc(st, NODE_COND, len + 1); + if (np) { + np->v.cond.expr = (char*)(np + 1); + memcpy(np->v.cond.expr, st->start + off, len); + np->v.cond.expr[len] = 0; + + cond.node = np; + cond.brn = brn; + STAILQ_INSERT_HEAD(&st->cond, &cond, next); + STAILQ_INIT(&np->v.cond.branch[!cond.brn]); + parse_template(&np->v.cond.branch[cond.brn], st); + } return np; @@ -110,3 +264,3 @@ parse_cond(struct template_state *st, int brn, size_t off, size_t len) -static INDEX_NODE * +static TMPL_NODE * next_escape_node(struct template_state *st) @@ -126,4 +280,3 @@ next_escape_node(struct template_state *st) st->escape = 0; - return new_text_node(NODE_TEXT, st->start, - st->cur - st->start); + return new_text_node(st, NODE_TEXT, st->cur - st->start); } @@ -140,9 +293,12 @@ next_escape_node(struct template_state *st) if (memcmp(st->start, "loop", len) == 0) { - INDEX_NODE *np; + TMPL_NODE *np; - assert(st->loop == 0); + if (st->loop) { + st->error = TMPL_ERR_LOOP_NESTING; + return NULL; + } st->loop = 1; - np = xmalloc(sizeof(*np)); - np->type = NODE_LOOP; - parse_template(&np->v.loop, st); + np = node_alloc(st, NODE_LOOP, 0); + if (np) + parse_template(&np->v.loop, st); return np; @@ -151,3 +307,6 @@ next_escape_node(struct template_state *st) if (memcmp(st->start, "endloop", len) == 0) { - assert(st->loop); + if (!st->loop) { + st->error = TMPL_ERR_ENDLOOP_WITHOUT_LOOP; + return NULL; + } st->loop = 0; @@ -165,3 +324,6 @@ next_escape_node(struct template_state *st) if (memcmp(st->start, "endif", len) == 0) { - STAILQ_REMOVE_HEAD(&st->cond, next); + if (STAILQ_FIRST(&st->cond)) + STAILQ_REMOVE_HEAD(&st->cond, next); + else + st->error = TMPL_ERR_ENDIF_WITHOUT_IF; return NULL; @@ -171,7 +333,13 @@ next_escape_node(struct template_state *st) if (memcmp(st->start, "else", len) == 0) { - INDEX_NODE *np; + TMPL_NODE *np; struct condition *cond = STAILQ_FIRST(&st->cond); - assert(cond); + if (!cond) { + st->error = TMPL_ERR_ELSE_WITHOUT_IF; + return NULL; + } np = cond->node; - assert(STAILQ_FIRST(&np->v.cond.branch[!cond->brn]) == NULL); + if (STAILQ_FIRST(&np->v.cond.branch[!cond->brn])) { + st->error = TMPL_ERR_DUP_ELSE; + return NULL; + } parse_template(&np->v.cond.branch[!cond->brn], st); @@ -180,8 +348,10 @@ next_escape_node(struct template_state *st) - return new_text_node(NODE_EXPR, st->start, len); + return new_text_node(st, NODE_EXPR, len); } -static INDEX_NODE * +static TMPL_NODE * next_node(struct template_state *st) { + if (st->error) + return NULL; if (*st->cur == 0) @@ -192,5 +362,5 @@ next_node(struct template_state *st) static void -parse_template(INDEX_NODE_LIST *nodes, struct template_state *st) +parse_template(TMPL_NODE_LIST *nodes, struct template_state *st) { - INDEX_NODE *np; + TMPL_NODE *np; @@ -202,5 +372,5 @@ parse_template(INDEX_NODE_LIST *nodes, struct template_state *st) -INDEX_NODE_LIST node_list = STAILQ_HEAD_INITIALIZER(node_list); +TMPL_NODE_LIST node_list = STAILQ_HEAD_INITIALIZER(node_list); -void +int parse_template_string(char const *str) @@ -214,2 +384,3 @@ parse_template_string(char const *str) state.cur = str; + state.error = TMPL_NOERR; @@ -217,8 +388,28 @@ parse_template_string(char const *str) - assert(state.escape == 0); - assert(state.loop == 0); - assert(STAILQ_FIRST(&state.cond) == NULL); + if (state.error != TMPL_NOERR) { + error("error parsing template near character %d: %s", + state.start - str, + tmpl_err_str[state.error]); + node_list_free(&node_list); + return -1; + } + + if (state.escape) + state.error = TMPL_ERR_ESCAPE_NOT_CLOSED; + else if (state.loop) + state.error = TMPL_ERR_LOOP_NOT_CLOSED; + else if (STAILQ_FIRST(&state.cond)) + state.error = TMPL_ERR_COND_NOT_CLOSED; + + if (state.error != TMPL_NOERR) { + error("error parsing template (at end): %s", + tmpl_err_str[state.error]); + node_list_free(&node_list); + return -1; + } + + return 0; } -void +int parse_template_file(char const *file_name) @@ -229,2 +420,3 @@ parse_template_file(char const *file_name) ssize_t n; + int rc; @@ -232,3 +424,3 @@ parse_template_file(char const *file_name) error("can't stat %s: %s", file_name, strerror(errno)); - return; + return -1; } @@ -237,6 +429,12 @@ parse_template_file(char const *file_name) error("can't open %s: %s", file_name, strerror(errno)); - return; + return -1; + } + + buf = malloc(st.st_size + 1); + if (!buf) { + error("can't open %s: %s", file_name, strerror(errno)); + fclose(fp); + return -1; } - buf = xmalloc(st.st_size + 1); n = fread(buf, st.st_size, 1, fp); @@ -244,192 +442,19 @@ parse_template_file(char const *file_name) buf[st.st_size] = 0; - parse_template_string(buf); - } else + rc = parse_template_string(buf); + } else { error("error reading from %s: %s", file_name, strerror(errno)); + rc = 1; + } fclose(fp); free(buf); + return rc; } -typedef struct idxent { - char *name; - struct stat st; - char const *type; - STAILQ_ENTRY(idxent) next; -} IDXENT; -typedef struct idxlist { - size_t count; - STAILQ_HEAD(, idxent) list; -} IDXLIST; - -static void -idxlist_init(IDXLIST *lst) -{ - lst->count = 0; - STAILQ_INIT(&lst->list); -} - -static void -idxlist_free(IDXLIST *lst) -{ - IDXENT *ent; - - while ((ent = STAILQ_FIRST(&lst->list))) { - STAILQ_REMOVE_HEAD(&lst->list, next); - free(ent->name); - free(ent); - } - lst->count = 0; -} - -static void -idxlist_append(IDXLIST *lst, IDXENT *ent) -{ - STAILQ_INSERT_TAIL(&lst->list, ent, next); - lst->count++; -} - -static int -idxlist_scan(IDXLIST *idx_list, char const *path, CONFIG const *conf) -{ - DIR *dir; - struct dirent *ent; - IDXENT *idxent; - - dir = opendir(path); - if (!dir) { - int ec = errno; - error("can't open directory %s: %s", - path, strerror(ec)); - return ec; - } - idxlist_init(idx_list); - while ((ent = readdir(dir))) { - char *name; - struct stat st; - - if (filename_is_hidden(ent->d_name, conf)) - continue; - - name = catfile(path, ent->d_name); - - if (stat(name, &st)) { - error("can't stat %s: %s", name, strerror(errno)); - free(name); - continue; - } - - if (conf->list_unreadable == 0) { - if (access(name, R_OK)) { - free(name); - continue; - } - } - - idxent = xmalloc(sizeof(*idxent)); - - if (S_ISDIR(st.st_mode)) { - size_t len = strlen(ent->d_name); - idxent->name = xmalloc(len + 2); - memcpy(idxent->name, ent->d_name, len); - idxent->name[len++] = '/'; - idxent->name[len] = 0; - } else - idxent->name = xstrdup(ent->d_name); - idxent->st = st; - idxent->type = get_file_type(name); - idxlist_append(idx_list, idxent); - free(name); - } - closedir(dir); - - return 0; -} - -static void -idxlist_qsort(IDXLIST *list, int cmp (IDXENT const *, IDXENT const *, void *), - void *data) -{ - if (list->count < 2) - return; - else if (list->count == 2) { - IDXENT *a, *b; - a = STAILQ_FIRST(&list->list); - b = STAILQ_NEXT(a, next); - if (cmp(a, b, data) > 0) { - STAILQ_REMOVE_HEAD(&list->list, next); - STAILQ_INSERT_TAIL(&list->list, a, next); - } - } else { - IDXENT *cur, *middle; - IDXLIST high, low; - int rc; - - cur = middle = STAILQ_FIRST(&list->list); - do { - cur = STAILQ_NEXT(cur, next); - if (!cur) - return; - } while ((rc = cmp(middle, cur, data)) == 0); - - if (rc > 0) - middle = cur; - - idxlist_init(&high); - idxlist_init(&low); - - while ((cur = STAILQ_FIRST(&list->list))) { - STAILQ_REMOVE_HEAD(&list->list, next); - if (cmp(middle, cur, data) < 0) - idxlist_append(&high, cur); - else - idxlist_append(&low, cur); - } - - /* Sort both lists */ - idxlist_qsort(&low, cmp, data); - idxlist_qsort(&high, cmp, data); - - /* Join lists in order and return */ - STAILQ_CONCAT(&low.list, &high.list); - list->list = low.list; - list->count = low.count + high.count; - } -} - -static char ordargs[] = "AD"; -static char colargs[] = "NMSD"; - -INDEX_SORT_COL -index_sort_col_from_arg(int c) -{ - char const *p; - if ((p = strchr(colargs, c))) - return p - colargs; - return ISC_NAME; -} - -int -index_sort_col_to_arg(INDEX_SORT_COL c) -{ - return colargs[c]; -} - -INDEX_SORT_ORD -index_sort_ord_from_arg(int c) -{ - char const *p; - if ((p = strchr(ordargs, c))) - return p - ordargs; - return ISO_ASC; -} - -int -index_sort_ord_to_arg(INDEX_SORT_ORD c) -{ - return ordargs[c]; -} +/* Directory tmpl scanner */ -typedef struct { +/* Run-time template evaluator */ +typedef struct eval_env { int fd; CONFIG const *conf; - IDXENT *ent; + DIRLSENT *ent; int n; @@ -453,3 +478,3 @@ eval_expand(char const *str, EVAL_ENV *env) static int -node_text_eval(INDEX_NODE *node, EVAL_ENV *env) +node_text_eval(TMPL_NODE *node, EVAL_ENV *env) { @@ -459,5 +484,5 @@ node_text_eval(INDEX_NODE *node, EVAL_ENV *env) if (n == -1) - error("index write error: %s", strerror(errno)); + error("tmpl write error: %s", strerror(errno)); else - error("index write error: %s", "disk full?"); + error("tmpl write error: %s", "disk full?"); return -1; @@ -468,3 +493,3 @@ node_text_eval(INDEX_NODE *node, EVAL_ENV *env) static int -node_expr_eval(INDEX_NODE *node, EVAL_ENV *env) +node_expr_eval(TMPL_NODE *node, EVAL_ENV *env) { @@ -479,5 +504,5 @@ node_expr_eval(INDEX_NODE *node, EVAL_ENV *env) if (n == -1) - error("index write error: %s", strerror(errno)); + error("tmpl write error: %s", strerror(errno)); else - error("index write error: %s", "disk full?"); + error("tmpl write error: %s", "disk full?"); return -1; @@ -487,6 +512,4 @@ node_expr_eval(INDEX_NODE *node, EVAL_ENV *env) -static int node_list_eval(INDEX_NODE_LIST *nodes, EVAL_ENV *env); - static int -node_cond_eval(INDEX_NODE *node, EVAL_ENV *env) +node_cond_eval(TMPL_NODE *node, EVAL_ENV *env) { @@ -499,3 +522,3 @@ node_cond_eval(INDEX_NODE *node, EVAL_ENV *env) static int -node_loop_eval(INDEX_NODE *node, EVAL_ENV *env) +node_loop_eval(TMPL_NODE *node, EVAL_ENV *env) { @@ -509,24 +532,2 @@ node_loop_eval(INDEX_NODE *node, EVAL_ENV *env) } - -static int (*eval[])(INDEX_NODE *node, EVAL_ENV *env) = { - [NODE_TEXT] = node_text_eval, - [NODE_LOOP] = node_loop_eval, - [NODE_COND] = node_cond_eval, - [NODE_EXPR] = node_expr_eval -}; - -static int -node_list_eval(INDEX_NODE_LIST *nodes, EVAL_ENV *env) -{ - INDEX_NODE *node; - - STAILQ_FOREACH(node, nodes, next) { - assert(node->type >= 0 - && node->type < sizeof(eval)/sizeof(eval[0]) - && eval[node->type]); - if (eval[node->type](node, env)) - return -1; - } - return 0; -} @@ -538,2 +539,9 @@ streq(const char *v, const char *s, size_t l) +static inline int +retstr(char **ret, char const *str) +{ + *ret = strdup(str); + return *ret ? WRDSE_OK : WRDSE_NOSPACE; +} + static int @@ -541,4 +549,3 @@ exp_rowclass(char **ret, EVAL_ENV *env) { - *ret = xstrdup(env->n % 2 ? "odd" : "even"); - return WRDSE_OK; + return retstr(ret, env->n % 2 ? "odd" : "even"); } @@ -548,6 +555,5 @@ exp_filename(char **ret, EVAL_ENV *env) { - if (env->ent) { - *ret = xstrdup(env->ent->name); - return WRDSE_OK; - } else + if (env->ent) + return retstr(ret, env->ent->name); + else return WRDSE_UNDEF; @@ -571,4 +577,3 @@ exp_filesize(char **ret, EVAL_ENV *env) snprintf(buf, sizeof(buf), "%.1f%s", s, suf[i]); - *ret = strdup(buf); - return WRDSE_OK; + return retstr(ret, buf); } else @@ -580,6 +585,5 @@ exp_mimetype(char **ret, EVAL_ENV *env) { - if (env->ent && env->ent->type) { - *ret = xstrdup(env->ent->type); - return WRDSE_OK; - } else + if (env->ent && env->ent->type) + return retstr(ret, env->ent->type); + else return WRDSE_UNDEF; @@ -595,4 +599,3 @@ exp_filetime(char **ret, EVAL_ENV *env) strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", gmtime(&t)); - *ret = xstrdup(buf); - return WRDSE_OK; + return retstr(ret, buf); } else @@ -607,4 +610,4 @@ exp_filetype(char **ret, EVAL_ENV *env) s = S_ISDIR(env->ent->st.st_mode) ? "DIRECTORY" : "FILE"; - *ret = xstrdup(s); - return WRDSE_OK; + return retstr(ret, s); + return *ret ? WRDSE_OK : WRDSE_NOSPACE; } @@ -652,4 +655,3 @@ cmd_iconlookup(char **ret, char **argv, EVAL_ENV *env) env->icon = icon; - *ret = strdup(icon ? icon->src : ""); - return *ret ? WRDSE_OK : WRDSE_NOSPACE; + return retstr(ret, icon ? icon->src : ""); } @@ -662,5 +664,3 @@ cmd_iconsrc(char **ret, char **argv, EVAL_ENV *env) s = env->icon->src; - - *ret = strdup(s); - return *ret ? WRDSE_OK : WRDSE_NOSPACE; + return retstr(ret, s); } @@ -673,5 +673,3 @@ cmd_iconalt(char **ret, char **argv, EVAL_ENV *env) s = env->icon->alt; - - *ret = strdup(s); - return *ret ? WRDSE_OK : WRDSE_NOSPACE; + return retstr(ret, s); } @@ -745,49 +743,2 @@ static char defidx[] = -static inline int -comp_result(int val, void *data) -{ - if (*(INDEX_SORT_ORD*)data == ISO_DESC) - val = -val; - return val; -} - -static int -comp_name(IDXENT const *a, IDXENT const *b, void *data) -{ - return comp_result(strcmp(a->name, b->name), data); -} - -static int -comp_time(IDXENT const *a, IDXENT const *b, void *data) -{ - int r; - if (a->st.st_mtime < b->st.st_mtime) - r = -1; - else if (a->st.st_mtime > b->st.st_mtime) - r = 1; - else - r = 0; - return comp_result(r, data); -} - -static int -comp_size(IDXENT const *a, IDXENT const *b, void *data) -{ - int r; - if (a->st.st_size < b->st.st_size) - r = -1; - else if (a->st.st_size > b->st.st_size) - r = 1; - else - r = 0; - return comp_result(r, data); -} - -static int (*comp[])(IDXENT const *, IDXENT const *, void *) = { - comp_name, - comp_time, - comp_size, - comp_name -}; - int @@ -795,6 +746,6 @@ directory_index(int fd, CONFIG const *conf, char const *uri, char const *path, - INDEX_SORT_COL col, INDEX_SORT_ORD ord) + INDEX_SORT_COL col, INDEX_SORT_ORD ord) { int rc; - IDXLIST idxlist; + DIRLS dirls; EVAL_ENV env; @@ -803,11 +754,12 @@ directory_index(int fd, CONFIG const *conf, if (STAILQ_EMPTY(&node_list)) { - parse_template_string(defidx); - assert(!STAILQ_EMPTY(&node_list)); + if (parse_template_string(defidx) == 0) { + error("error compiling built-in template!"); + return ENOSYS; + } } - rc = idxlist_scan(&idxlist, path, conf); + rc = dirls_scan(&dirls, path, conf); if (rc) return rc; - /* FIXME: sort list */ - idxlist_qsort(&idxlist, comp[col], &ord); + dirls_sort(&dirls, col, ord); @@ -815,3 +767,3 @@ directory_index(int fd, CONFIG const *conf, env.conf = conf; - env.ent = STAILQ_FIRST(&idxlist.list); + env.ent = STAILQ_FIRST(&dirls.list); env.n = 0; @@ -846,6 +798,7 @@ directory_index(int f |