summaryrefslogtreecommitdiff
path: root/browse.c
diff options
context:
space:
mode:
Diffstat (limited to 'browse.c')
-rw-r--r--browse.c151
1 files changed, 123 insertions, 28 deletions
diff --git a/browse.c b/browse.c
index 5093242..0c81f83 100644
--- a/browse.c
+++ b/browse.c
@@ -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;
+ }
}