+ /* Generate cache content */
+ slot->fn(slot->cbdata);
+
+ /* Restore stdout */
+ if (dup2(tmp, STDOUT_FILENO) == -1)
+ return errno;
+
+ /* Close the temporary filedescriptor */
+ if (close(tmp))
+ return errno;
+
+ return 0;
+}
+
+/* Crude implementation of 32-bit FNV-1 hash algorithm,
+ * see http://www.isthe.com/chongo/tech/comp/fnv/ for details
+ * about the magic numbers.
+ */
+#define FNV_OFFSET 0x811c9dc5
+#define FNV_PRIME 0x01000193
+
+unsigned long hash_str(const char *str)
+{
+ unsigned long h = FNV_OFFSET;
+ unsigned char *s = (unsigned char *)str;
+
+ if (!s)
+ return h;
+
+ while(*s) {
+ h *= FNV_PRIME;
+ h ^= *s++;
+ }
+ return h;
+}
+
+static int process_slot(struct cache_slot *slot)
+{
+ int err;
+
+ err = open_slot(slot);
+ if (!err && slot->match) {
+ if (is_expired(slot)) {
+ if (!lock_slot(slot)) {
+ /* If the cachefile has been replaced between
+ * `open_slot` and `lock_slot`, we'll just
+ * serve the stale content from the original
+ * cachefile. This way we avoid pruning the
+ * newly generated slot. The same code-path
+ * is chosen if fill_slot() fails for some
+ * reason.
+ *
+ * TODO? check if the new slot contains the
+ * same key as the old one, since we would
+ * prefer to serve the newest content.
+ * This will require us to open yet another
+ * file-descriptor and read and compare the
+ * key from the new file, so for now we're
+ * lazy and just ignore the new file.
+ */
+ if (is_modified(slot) || fill_slot(slot)) {
+ unlock_slot(slot, 0);
+ close_lock(slot);
+ } else {
+ close_slot(slot);
+ unlock_slot(slot, 1);
+ slot->cache_fd = slot->lock_fd;
+ }
+ }
+ }
+ if ((err = print_slot(slot)) != 0) {
+ cache_log("[cgit] error printing cache %s: %s (%d)\n",
+ slot->cache_name,
+ strerror(err),
+ err);
+ }
+ close_slot(slot);
+ return err;
+ }
+
+ /* If the cache slot does not exist (or its key doesn't match the
+ * current key), lets try to create a new cache slot for this
+ * request. If this fails (for whatever reason), lets just generate
+ * the content without caching it and fool the caller to belive
+ * everything worked out (but print a warning on stdout).
+ */
+
+ close_slot(slot);
+ if ((err = lock_slot(slot)) != 0) {
+ cache_log("[cgit] Unable to lock slot %s: %s (%d)\n",
+ slot->lock_name, strerror(err), err);
+ slot->fn(slot->cbdata);