diff options
Diffstat (limited to 'page.c')
| -rw-r--r-- | page.c | 254 |
1 files changed, 211 insertions, 43 deletions
@@ -3,6 +3,7 @@ #include "page.h" #include "http.h" #include "html.h" +#include "thumbnail.h" #include <dynstr.h> #include <dirent.h> #include <fcntl.h> @@ -45,7 +46,102 @@ " </form>\n" #define MAXSIZEFMT "18446744073709551615.0 XiB" -static int prepare_name(struct html_node *const n, struct stat *const sb, +static const char *dir_separator(const char *const dir) +{ + return dir[strlen(dir) - 1] != '/' ? "/" : ""; +} + +static int prepare_thumbnail(struct html_node *const n, + const struct stat *const sb, + const struct page_resource *const r, const char *const name) +{ + int ret = -1, res; + const char *const sep = dir_separator(r->res); + struct html_node *img; + struct dynstr abs, rel; + struct stat tsb; + struct thumbnail_dim dim; + char w[sizeof "18446744073709551615"], h[sizeof w]; + + dynstr_init(&abs); + dynstr_init(&rel); + + if (!S_ISREG(sb->st_mode)) + { + ret = 0; + goto end; + } + else if (dynstr_append(&rel, "/thumbnails/%s%s%s%s", + r->username, r->res, sep, name)) + { + fprintf(stderr, "%s: dynstr_append rel failed\n", __func__); + goto end; + } + else if (dynstr_append(&abs, "%s%s", r->root, rel.str)) + { + fprintf(stderr, "%s: dynstr_append rel failed\n", __func__); + goto end; + } + else if (stat(abs.str, &tsb)) + { + if (errno == ENOENT) + ret = 0; + else + fprintf(stderr, "%s: stat(2): %s\n", __func__, strerror(errno)); + + goto end; + } + else if (thumbnail_dim(abs.str, &dim)) + { + fprintf(stderr, "%s: thumbnail_dim failed\n", __func__); + goto end; + } + + res = snprintf(w, sizeof w, "%lu", dim.w); + + if (res < 0 || res >= sizeof w) + { + fprintf(stderr, "%s: snprintf(3) w failed with %d\n", __func__, res); + goto end; + } + + res = snprintf(h, sizeof h, "%lu", dim.h); + + if (res < 0 || res >= sizeof h) + { + fprintf(stderr, "%s: snprintf(3) h failed with %d\n", __func__, res); + goto end; + } + else if (!(img = html_node_add_child(n, "img"))) + { + fprintf(stderr, "%s: html_node_add_child failed\n", __func__); + goto end; + } + else if (html_node_add_attr(img, "src", rel.str)) + { + fprintf(stderr, "%s: html_node_add_attr src failed\n", __func__); + goto end; + } + else if (html_node_add_attr(img, "width", w)) + { + fprintf(stderr, "%s: html_node_add_attr w failed\n", __func__); + goto end; + } + else if (html_node_add_attr(img, "height", h)) + { + fprintf(stderr, "%s: html_node_add_attr h failed\n", __func__); + goto end; + } + + ret = 0; + +end: + dynstr_free(&abs); + dynstr_free(&rel); + return ret; +} + +static int prepare_name(struct html_node *const n, const struct stat *const sb, const char *const dir, const char *const name) { int ret = -1; @@ -169,7 +265,7 @@ static int prepare_share(struct html_node *const n, const struct stat *const sb, const char *const dir, const char *const name) { int ret = -1; - const char *const fdir = dir + strlen("/user"); + const char *const sep = dir_separator(dir); struct html_node *form, *file, *submit; struct dynstr d; @@ -213,7 +309,7 @@ static int prepare_share(struct html_node *const n, fprintf(stderr, "%s: html_node_add_attr file name failed\n", __func__); goto end; } - else if (dynstr_append(&d, "%s%s", fdir, name)) + else if (dynstr_append(&d, "%s%s%s", dir, sep, name)) { fprintf(stderr, "%s: dynstr_append failed\n", __func__); goto end; @@ -243,18 +339,37 @@ end: return ret; } -static int add_element(struct html_node *const n, const char *const dir, - const char *const res, const char *const name) +static int user_resource(const struct page_resource *const r, + struct dynstr *const d) +{ + if (dynstr_append(d, "%s/user/%s%s", r->root, r->username, r->res)) + { + fprintf(stderr, "%s: dynstr_append failed\n", __func__); + return -1; + } + + return 0; +} + +static int add_element(const struct page_resource *const r, + struct html_node *const n, const char *const absres, + const char *const name) { int ret = -1; - enum {NAME, SIZE, DATE, SHARE, COLUMNS}; + enum {THUMBNAIL, NAME, SIZE, DATE, SHARE, COLUMNS}; + const char *const sep = dir_separator(r->res); struct html_node *tr, *td[COLUMNS]; - struct dynstr path; - const char *const sep = res[strlen(res) - 1] != '/' ? "/" : ""; + struct dynstr path, rel; dynstr_init(&path); + dynstr_init(&rel); - if (dynstr_append(&path, "%s%s%s", res, sep, name)) + if (dynstr_append(&path, "%s%s%s", absres, sep, name)) + { + fprintf(stderr, "%s: dynstr_append failed\n", __func__); + goto end; + } + else if (dynstr_append(&rel, "/user%s%s", r->res, sep)) { fprintf(stderr, "%s: dynstr_append failed\n", __func__); goto end; @@ -266,7 +381,9 @@ static int add_element(struct html_node *const n, const char *const dir, } for (size_t i = 0; i < sizeof td / sizeof *td; i++) - if (!(td[i] = html_node_add_child(tr, "td"))) + if (i == THUMBNAIL && !thumbnail_configured()) + continue; + else if (!(td[i] = html_node_add_child(tr, "td"))) { fprintf(stderr, "%s: html_node_add_child td[%zu] failed\n", __func__, i); @@ -281,7 +398,13 @@ static int add_element(struct html_node *const n, const char *const dir, __func__, path.str, strerror(errno)); goto end; } - else if (prepare_name(td[NAME], &sb, dir, name)) + else if (thumbnail_configured() + && prepare_thumbnail(td[THUMBNAIL], &sb, r, name)) + { + fprintf(stderr, "%s: prepare_thumbnail failed\n", __func__); + goto end; + } + else if (prepare_name(td[NAME], &sb, rel.str, name)) { fprintf(stderr, "%s: prepare_name failed\n", __func__); goto end; @@ -296,7 +419,7 @@ static int add_element(struct html_node *const n, const char *const dir, fprintf(stderr, "%s: prepare_date failed\n", __func__); goto end; } - else if (prepare_share(td[SHARE], &sb, dir, name)) + else if (prepare_share(td[SHARE], &sb, rel.str, name)) { fprintf(stderr, "%s: prepare_date failed\n", __func__); goto end; @@ -306,6 +429,7 @@ static int add_element(struct html_node *const n, const char *const dir, end: dynstr_free(&path); + dynstr_free(&rel); return ret; } @@ -743,7 +867,6 @@ end: static struct html_node *resource_layout(const char *const dir, const struct page_quota *const q, struct html_node **const table) { - const char *const fdir = dir + strlen("/user"); struct html_node *const html = html_node_alloc("html"), *ret = NULL, *head, *body; @@ -767,17 +890,17 @@ static struct html_node *resource_layout(const char *const dir, fprintf(stderr, "%s: html_node_add_child table failed\n", __func__); goto end; } - else if (common_head(head, fdir)) + else if (common_head(head, dir)) { fprintf(stderr, "%s: common_head failed\n", __func__); goto end; } - else if (prepare_upload_form(body, fdir)) + else if (prepare_upload_form(body, dir)) { fprintf(stderr, "%s: prepare_upload_form failed\n", __func__); goto end; } - else if (prepare_mkdir_form(body, fdir)) + else if (prepare_mkdir_form(body, dir)) { fprintf(stderr, "%s: prepare_upload_form failed\n", __func__); goto end; @@ -808,14 +931,21 @@ end: return ret; } -static int add_elements(const char *const root, const char *const res, - const char *const dir, struct html_node *const table) +static int add_elements(const struct page_resource *const r, + struct html_node *const table) { - int ret = -1; + int ret = -1, n = 0; + struct dynstr d; struct dirent **pde = NULL; - const int n = scandir(res, &pde, NULL, alphasort); - if (n < 0) + dynstr_init(&d); + + if (user_resource(r, &d)) + { + fprintf(stderr, "%s: user_resource failed\n", __func__); + goto end; + } + else if ((n = scandir(d.str, &pde, NULL, alphasort)) < 0) { fprintf(stderr, "%s: scandir(3): %s\n", __func__, strerror(errno)); goto end; @@ -827,9 +957,9 @@ static int add_elements(const char *const root, const char *const res, const char *const name = de->d_name; if (!strcmp(name, ".") - || (!strcmp(name, "..") && !strcmp(root, res))) + || (!strcmp(name, "..") && !strcmp(r->user_root, d.str))) continue; - else if (add_element(table, dir, res, name)) + else if (add_element(r, table, d.str, name)) { fprintf(stderr, "%s: add_element failed\n", __func__); goto end; @@ -844,25 +974,25 @@ end: free(pde[i]); free(pde); + dynstr_free(&d); return ret; } -static int list_dir(struct http_response *const r, const char *const dir, - const char *const root, const char *const res, - const struct page_quota *const q) +static int list_dir(struct http_response *const r, + const struct page_resource *const res, const struct page_quota *const q) { int ret = -1; struct dynstr out; - struct html_node *table, *const html = resource_layout(dir, q, &table); + struct html_node *table, *html = NULL; dynstr_init(&out); - if (!html) + if (!(html = resource_layout(res->res, q, &table))) { fprintf(stderr, "%s: resource_layout failed\n", __func__); goto end; } - else if (add_elements(root, res, dir, table)) + else if (add_elements(res, table)) { fprintf(stderr, "%s: read_elements failed\n", __func__); goto end; @@ -907,14 +1037,14 @@ static int serve_file(struct http_response *const r, const struct stat *const sb, const char *const res) { int ret = -1; - FILE *const f = fopen(res, "rb"); + FILE *f = NULL; struct dynstr b, d; char *bn; dynstr_init(&b); dynstr_init(&d); - if (!f) + if (!(f = fopen(res, "rb"))) { fprintf(stderr, "%s: fopen(3): %s\n", __func__, strerror(errno)); goto end; @@ -987,32 +1117,43 @@ static int page_not_found(struct http_response *const r) return 0; } -int page_resource(struct http_response *const r, const char *const dir, - const char *const root, const char *const res, - const struct page_quota *const q) +int page_resource(struct http_response *const r, + const struct page_resource *const res, const struct page_quota *const q) { + int ret = -1; struct stat sb; + struct dynstr d; - if (stat(res, &sb)) + dynstr_init(&d); + + if (user_resource(res, &d)) + { + fprintf(stderr, "%s: user_resource failed\n", __func__); + goto end; + } + else if (stat(d.str, &sb)) { fprintf(stderr, "%s: stat(2) %s: %s\n", - __func__, res, strerror(errno)); + __func__, res->res, strerror(errno)); if (errno == ENOENT) - return page_not_found(r); - else - return -1; + ret = page_not_found(r); + + goto end; } const mode_t m = sb.st_mode; if (S_ISDIR(m)) - return list_dir(r, dir, root, res, q); + ret = list_dir(r, res, q); else if (S_ISREG(m)) - return serve_file(r, &sb, res); + ret = serve_file(r, &sb, d.str); + else + fprintf(stderr, "%s: unexpected st_mode %jd\n", __func__, (intmax_t)m); - fprintf(stderr, "%s: unexpected st_mode %jd\n", __func__, (intmax_t)m); - return -1; +end: + dynstr_free(&d); + return ret; } static char *resolve_link(const char *const res) @@ -1403,3 +1544,30 @@ end: return ret; } + +int page_thumbnail(struct http_response *const r, const char *const res) +{ + struct stat sb; + + if (stat(res, &sb)) + { + if (errno == ENOENT) + return page_not_found(r); + else + { + fprintf(stderr, "%s: stat(2) %s: %s\n", + __func__, res, strerror(errno)); + return -1; + } + } + + const mode_t m = sb.st_mode; + + if (!S_ISREG(m)) + { + fprintf(stderr, "%s: only regular files are supported\n", __func__); + return 1; + } + + return serve_file(r, &sb, res); +} |
