From 00dd37604d50cbf3fb27ec0631b4d4b6d2ee893a Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Mon, 6 Oct 2025 23:02:51 +0200 Subject: Implement directory download as ZIP Thanks to the fdzipstream library [1] and zlib [2], it is possible to generate ZIP files on-the-fly, therefore requiring no extra disk space usage and only a small amount of memory. Unfortunately, as of the time of this writing fdzipstream is not packaged by any distributions yet [3], so it had to be imported as a git submodule as a workaround. While libarchive [4] could be an interesting alternative, writing ZIP files is only supported by very recent versions (>= 3.8.0), which are still not packaged by many distributions [5], either. Moreover, libarchive is a package with several dependencies other than zlib and is significantly larger compared to fdzipstreams, so fdzipstreams was ultimately considered a better fit for this purpose. [1]: https://github.com/CTrabant/fdzipstream.git [2]: http://zlib.net/ [3]: https://repology.org/projects/?search=fdzipstream [4]: https://www.libarchive.org/ [5]: https://repology.org/project/libarchive/versions --- page.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'page.c') diff --git a/page.c b/page.c index af24e70..9d1ea8e 100644 --- a/page.c +++ b/page.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include "page.h" +#include "zip.h" #include #include #include @@ -1812,6 +1813,21 @@ static bool preview(const struct page_resource *const pr) return false; } +static bool download(const struct page_resource *const pr) +{ + for (size_t i = 0; i < pr->n_args; i++) + { + const struct http_arg *const a = &pr->args[i]; + + if (!strcmp(a->key, "download") + && (!strcmp(a->value, "1") + || !strcasecmp(a->value, "true"))) + return true; + } + + return false; +} + int page_resource(const struct page_resource *const pr) { int ret = -1; @@ -1840,7 +1856,15 @@ int page_resource(const struct page_resource *const pr) if (S_ISDIR(m)) { - if ((ret = list_dir(pr))) + if (download(pr)) + { + if ((ret = zip(pr->res, pr->r))) + { + fprintf(stderr, "%s: zip_dir failed\n", __func__); + goto end; + } + } + else if ((ret = list_dir(pr))) { if (ret < 0) { -- cgit v1.2.3