diff options
author | Vincent Douillet <vincent@vdouillet.fr> | 2023-10-12 14:24:58 +0200 |
---|---|---|
committer | Vincent Douillet <vincent@vdouillet.fr> | 2023-10-12 16:43:43 +0200 |
commit | a8158372e4173f760d893516c0d8aecbb0e737ac (patch) | |
tree | 865057956abb564d271665941987018e027ed862 | |
parent | 9487ad2ef9c7b67511e04bb6b9c31f30fdc3e87c (diff) |
browse: introduce file struct to prepare for kthttp_template
-rw-r--r-- | browse.c | 151 |
1 files changed, 123 insertions, 28 deletions
@@ -28,11 +28,14 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/queue.h> + #include <dirent.h> #include <kcgi.h> #include <kcgihtml.h> #include <limits.h> #include <stdbool.h> +#include <stdlib.h> #include <string.h> #include "browse.h" @@ -42,26 +45,120 @@ #include "url.h" /* + * list of files for current directory + */ +SLIST_HEAD(, file) list; +struct file { + char *name; + char *url; + SLIST_ENTRY(file) files; +}; + +/* + * should be able to free incomplete files as per file_new usage + */ +static void +file_free(struct file * file) +{ + if (file == NULL) + return; + + if (file->name != NULL) { + free(file->name); + file->name = NULL; + } + if (file->url != NULL) { + free(file->url); + file->url = NULL; + } + free(file); +} + +static struct file * +file_new(char *name, size_t name_len, char *url, size_t url_len) +{ + struct file *file; + + file = calloc(1, sizeof(struct file)); + if (file == NULL) + return NULL; + file->name = malloc(sizeof(char) * (name_len + 1)); + if (strlcpy(file->name, name, name_len + 1) >= name_len + 1) { + free(file); + return NULL; + } + file->url = malloc(sizeof(char) * (url_len + 1)); + if (strlcpy(file->url, url, url_len + 1) >= url_len + 1) { + free(file); + return NULL; + } + return file; +} + +/* * file url = r->pname / r->pagename / r->path / file_name */ static size_t -build_browse_url(struct kreq * r, char *url, size_t url_size, const char *file) +build_browse_url(struct kreq * r, char *url, size_t url_len, const char *file) { char *page_name; page_name = strlen(r->pagename) == 0 ? BROWSE_URL : r->pagename; - return url_build(url, url_size, r->pname, page_name, r->path, file, + return url_build(url, url_len, r->pname, page_name, r->path, file, NULL); } +static int +build_file_list(struct kreq * r, char *request_dir) +{ + char *file_name; + char url[PATH_MAX]; + DIR *data_dir; + size_t url_len; + struct dirent *dir; + struct file *file; + struct file *last_file; + + data_dir = opendir(request_dir); + if (NULL == data_dir) + return -1; + + SLIST_INIT(&list); + last_file = NULL; + while ((dir = readdir(data_dir)) != NULL) { + /* ignore special . and .. folders */ + file_name = dir->d_name; + if (strcmp(".", file_name) == 0 || strcmp("..", file_name) == 0) + continue; + url_len = build_browse_url(r, url, PATH_MAX, file_name); + if (url_len == 0 || url_len >= PATH_MAX) { + kutil_warn(r, NULL, "browse: Detected URL overflow: %s", url); + continue; + } + /* build file and add to list */ + file = file_new(dir->d_name, dir->d_namlen, url, url_len); + if (file == NULL) { + kutil_warn(r, NULL, "browse: unable to build file info"); + continue; + } + if (last_file == NULL) + SLIST_INSERT_HEAD(&list, file, files); + else + SLIST_INSERT_AFTER(last_file, file, files); + + last_file = file; + } + + closedir(data_dir); + return 0; +} + void browse(struct kreq * r) { - struct dirent *dir; - DIR *data_dir; - char *file_name; - size_t url_size; - char url[PATH_MAX], current_dir[PATH_MAX]; + size_t url_len; + char current_dir[PATH_MAX]; + struct file *file; struct khtmlreq html; /* check that the requested URL can be safely processed */ @@ -69,21 +166,20 @@ browse(struct kreq * r) http_exit(r, KHTTP_400, "browse: Invalid request path"); /* list requested directory content */ - url_size = url_build(current_dir, PATH_MAX, DATA_DIR, r->path, - NULL); - if (url_size == 0) + url_len = url_build(current_dir, PATH_MAX, DATA_DIR, r->path, + NULL); + if (url_len == 0) http_exit(r, KHTTP_404, "browse: Unable to build data path"); - if (url_size >= PATH_MAX) + if (url_len >= PATH_MAX) http_exit(r, KHTTP_414, NULL); - data_dir = opendir(current_dir); - if (NULL == data_dir) - http_exit(r, KHTTP_404, NULL); + if (build_file_list(r, current_dir) < 0) + http_exit(r, KHTTP_500, "browse: Unable to build file list"); + /* we have all the data we need, we can start to write output page */ http_open(r, KHTTP_200, r->mime); K_OK(khtml_open(&html, r, 0), r); - /* build basic html page */ K_OK(khtml_elem(&html, KELEM_DOCTYPE), r); K_OK(khtml_elem(&html, KELEM_HEAD), r); K_OK(khtml_attr(&html, KELEM_META, KATTR_CHARSET, "utf-8", KATTR__MAX), @@ -95,22 +191,21 @@ browse(struct kreq * r) K_OK(khtml_closeelem(&html, 1), r); K_OK(khtml_elem(&html, KELEM_UL), r); - while ((dir = readdir(data_dir)) != NULL) { - /* ignore special . and .. folders */ - file_name = dir->d_name; - if (strcmp(".", file_name) == 0 || strcmp("..", file_name) == 0) - continue; - url_size = build_browse_url(r, url, PATH_MAX, file_name); - if (url_size == 0 || url_size >= PATH_MAX) { - kutil_warn(r, NULL, "browse: Detected URL overflow: %s", url); - continue; - } + SLIST_FOREACH(file, &list, files) { K_OK(khtml_elem(&html, KELEM_LI), r); - K_OK(khtml_attr(&html, KELEM_A, KATTR_HREF, url, KATTR__MAX), + K_OK(khtml_attr(&html, KELEM_A, KATTR_HREF, file->url, KATTR__MAX), r); - K_OK(khtml_puts(&html, dir->d_name), r); + K_OK(khtml_puts(&html, file->name), r); K_OK(khtml_closeelem(&html, 2), r); } K_OK(khtml_close(&html), r); - closedir(data_dir); + + /* free list */ + file = NULL; + while (!SLIST_EMPTY(&list)) { + file = SLIST_FIRST(&list); + SLIST_REMOVE_HEAD(&list, files); + file_free(file); + file = NULL; + } } |