+static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
+ CatalogItem *items, size_t n) {
+ CatalogHeader header;
+ _cleanup_fclose_ FILE *w = NULL;
+ int r;
+ _cleanup_free_ char *d, *p = NULL;
+ size_t k;
+
+ d = dirname_malloc(database);
+ if (!d)
+ return log_oom();
+
+ r = mkdir_p(d, 0775);
+ if (r < 0)
+ return log_error_errno(r, "Recursive mkdir %s: %m", d);
+
+ r = fopen_temporary(database, &w, &p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open database for writing: %s: %m",
+ database);
+
+ zero(header);
+ memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
+ header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
+ header.catalog_item_size = htole64(sizeof(CatalogItem));
+ header.n_items = htole64(hashmap_size(h));
+
+ r = -EIO;
+
+ k = fwrite(&header, 1, sizeof(header), w);
+ if (k != sizeof(header)) {
+ log_error("%s: failed to write header.", p);
+ goto error;
+ }
+
+ k = fwrite(items, 1, n * sizeof(CatalogItem), w);
+ if (k != n * sizeof(CatalogItem)) {
+ log_error("%s: failed to write database.", p);
+ goto error;
+ }
+
+ k = fwrite(sb->buf, 1, sb->len, w);
+ if (k != sb->len) {
+ log_error("%s: failed to write strings.", p);
+ goto error;
+ }
+
+ fflush(w);
+
+ if (ferror(w)) {
+ log_error("%s: failed to write database.", p);
+ goto error;
+ }
+
+ fchmod(fileno(w), 0644);
+
+ if (rename(p, database) < 0) {
+ log_error_errno(errno, "rename (%s -> %s) failed: %m", p, database);
+ r = -errno;
+ goto error;
+ }
+
+ return ftell(w);