+ slot->lock_fd = open(slot->lock_name, O_RDWR | O_CREAT,
+ S_IRUSR | S_IWUSR);
+ if (slot->lock_fd == -1)
+ return errno;
+ if (fcntl(slot->lock_fd, F_SETLK, &lock) < 0) {
+ int saved_errno = errno;
+ close(slot->lock_fd);
+ slot->lock_fd = -1;
+ return saved_errno;
+ }
+ if (xwrite(slot->lock_fd, slot->key, slot->keylen + 1) < 0)
+ return errno;
+ return 0;
+}
+
+/* Release the current lockfile. If `replace_old_slot` is set the
+ * lockfile replaces the old cache slot, otherwise the lockfile is
+ * just deleted.
+ */
+static int unlock_slot(struct cache_slot *slot, int replace_old_slot)
+{
+ int err;
+
+ if (replace_old_slot)
+ err = rename(slot->lock_name, slot->cache_name);
+ else
+ err = unlink(slot->lock_name);
+
+ if (err)
+ return errno;
+
+ return 0;
+}
+
+/* Generate the content for the current cache slot by redirecting
+ * stdout to the lock-fd and invoking the callback function
+ */
+static int fill_slot(struct cache_slot *slot)
+{
+ int tmp;
+
+ /* Preserve stdout */
+ tmp = dup(STDOUT_FILENO);
+ if (tmp == -1)
+ return errno;
+
+ /* Redirect stdout to lockfile */
+ if (dup2(slot->lock_fd, STDOUT_FILENO) == -1) {
+ close(tmp);
+ return errno;
+ }
+
+ /* Generate cache content */
+ slot->fn();
+
+ /* Make sure any buffered data is flushed to the file */
+ if (fflush(stdout)) {
+ close(tmp);
+ return errno;
+ }
+
+ /* update stat info */
+ if (fstat(slot->lock_fd, &slot->cache_st)) {
+ close(tmp);
+ return errno;
+ }
+
+ /* Restore stdout */
+ if (dup2(tmp, STDOUT_FILENO) == -1) {
+ close(tmp);
+ 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;