summaryrefslogtreecommitdiffstats
path: root/src/sysupdate/sysupdate-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sysupdate/sysupdate-cache.c')
-rw-r--r--src/sysupdate/sysupdate-cache.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/sysupdate/sysupdate-cache.c b/src/sysupdate/sysupdate-cache.c
new file mode 100644
index 0000000..8dad3ee
--- /dev/null
+++ b/src/sysupdate/sysupdate-cache.c
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "memory-util.h"
+#include "sysupdate-cache.h"
+
+#define WEB_CACHE_ENTRIES_MAX 64U
+#define WEB_CACHE_ITEM_SIZE_MAX (64U*1024U*1024U)
+
+static WebCacheItem* web_cache_item_free(WebCacheItem *i) {
+ if (!i)
+ return NULL;
+
+ free(i->url);
+ return mfree(i);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(WebCacheItem*, web_cache_item_free);
+
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(web_cache_hash_ops, char, string_hash_func, string_compare_func, WebCacheItem, web_cache_item_free);
+
+int web_cache_add_item(
+ Hashmap **web_cache,
+ const char *url,
+ bool verified,
+ const void *data,
+ size_t size) {
+
+ _cleanup_(web_cache_item_freep) WebCacheItem *item = NULL;
+ _cleanup_free_ char *u = NULL;
+ int r;
+
+ assert(web_cache);
+ assert(url);
+ assert(data || size == 0);
+
+ if (size > WEB_CACHE_ITEM_SIZE_MAX)
+ return -E2BIG;
+
+ item = web_cache_get_item(*web_cache, url, verified);
+ if (item && memcmp_nn(item->data, item->size, data, size) == 0)
+ return 0;
+
+ if (hashmap_size(*web_cache) >= (size_t) (WEB_CACHE_ENTRIES_MAX + !!hashmap_get(*web_cache, url)))
+ return -ENOSPC;
+
+ r = hashmap_ensure_allocated(web_cache, &web_cache_hash_ops);
+ if (r < 0)
+ return r;
+
+ u = strdup(url);
+ if (!u)
+ return -ENOMEM;
+
+ item = malloc(offsetof(WebCacheItem, data) + size + 1);
+ if (!item)
+ return -ENOMEM;
+
+ *item = (WebCacheItem) {
+ .url = TAKE_PTR(u),
+ .size = size,
+ .verified = verified,
+ };
+
+ /* Just to be extra paranoid, let's NUL terminate the downloaded buffer */
+ *(uint8_t*) mempcpy(item->data, data, size) = 0;
+
+ web_cache_item_free(hashmap_remove(*web_cache, url));
+
+ r = hashmap_put(*web_cache, item->url, item);
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(item);
+ return 1;
+}
+
+WebCacheItem* web_cache_get_item(Hashmap *web_cache, const char *url, bool verified) {
+ WebCacheItem *i;
+
+ i = hashmap_get(web_cache, url);
+ if (!i)
+ return NULL;
+
+ if (i->verified != verified)
+ return NULL;
+
+ return i;
+}