X-Git-Url: https://git.cameronkatri.com/cgit.git/blobdiff_plain/382ecf152e1bd9546f6c84ace71c62ca07f6648b..892ba8c3cc0617d2087a2337d8c6e71524d7b49c:/cache.c diff --git a/cache.c b/cache.c index fa83ddc..2c70be7 100644 --- a/cache.c +++ b/cache.c @@ -16,22 +16,24 @@ #include "cgit.h" #include "cache.h" #include "html.h" +#ifdef HAVE_LINUX_SENDFILE +#include +#endif #define CACHE_BUFSIZE (1024 * 4) struct cache_slot { const char *key; - int keylen; + size_t keylen; int ttl; cache_fill_fn fn; - void *cbdata; int cache_fd; int lock_fd; + int stdout_fd; const char *cache_name; const char *lock_name; int match; struct stat cache_st; - struct stat lock_st; int bufsize; char buf[CACHE_BUFSIZE]; }; @@ -43,7 +45,7 @@ struct cache_slot { static int open_slot(struct cache_slot *slot) { char *bufz; - int bufkeylen = -1; + ssize_t bufkeylen = -1; slot->cache_fd = open(slot->cache_name, O_RDONLY); if (slot->cache_fd == -1) @@ -60,8 +62,9 @@ static int open_slot(struct cache_slot *slot) if (bufz) bufkeylen = bufz - slot->buf; - slot->match = bufkeylen == slot->keylen && - !memcmp(slot->key, slot->buf, bufkeylen + 1); + if (slot->key) + slot->match = bufkeylen == slot->keylen && + !memcmp(slot->key, slot->buf, bufkeylen + 1); return 0; } @@ -82,6 +85,23 @@ static int close_slot(struct cache_slot *slot) /* Print the content of the active cache slot (but skip the key). */ static int print_slot(struct cache_slot *slot) { +#ifdef HAVE_LINUX_SENDFILE + off_t start_off; + int ret; + + start_off = slot->keylen + 1; + + do { + ret = sendfile(STDOUT_FILENO, slot->cache_fd, &start_off, + slot->cache_st.st_size - start_off); + if (ret < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + return errno; + } + return 0; + } while (1); +#else ssize_t i, j; i = lseek(slot->cache_fd, slot->keylen + 1, SEEK_SET); @@ -98,6 +118,7 @@ static int print_slot(struct cache_slot *slot) return errno; else return 0; +#endif } /* Check if the slot has expired */ @@ -142,10 +163,23 @@ static int close_lock(struct cache_slot *slot) */ static int lock_slot(struct cache_slot *slot) { - slot->lock_fd = open(slot->lock_name, O_RDWR | O_CREAT | O_EXCL, + struct flock lock = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + + 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; @@ -164,6 +198,13 @@ static int unlock_slot(struct cache_slot *slot, int replace_old_slot) else err = unlink(slot->lock_name); + /* Restore stdout and close the temporary FD. */ + if (slot->stdout_fd >= 0) { + dup2(slot->stdout_fd, STDOUT_FILENO); + close(slot->stdout_fd); + slot->stdout_fd = -1; + } + if (err) return errno; @@ -175,11 +216,9 @@ static int unlock_slot(struct cache_slot *slot, int replace_old_slot) */ static int fill_slot(struct cache_slot *slot) { - int tmp; - /* Preserve stdout */ - tmp = dup(STDOUT_FILENO); - if (tmp == -1) + slot->stdout_fd = dup(STDOUT_FILENO); + if (slot->stdout_fd == -1) return errno; /* Redirect stdout to lockfile */ @@ -187,14 +226,14 @@ static int fill_slot(struct cache_slot *slot) return errno; /* Generate cache content */ - slot->fn(slot->cbdata); + slot->fn(); - /* Restore stdout */ - if (dup2(tmp, STDOUT_FILENO) == -1) + /* Make sure any buffered data is flushed to the file */ + if (fflush(stdout)) return errno; - /* Close the temporary filedescriptor */ - if (close(tmp)) + /* update stat info */ + if (fstat(slot->lock_fd, &slot->cache_st)) return errno; return 0; @@ -269,7 +308,7 @@ static int process_slot(struct cache_slot *slot) /* 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 + * the content without caching it and fool the caller to believe * everything worked out (but print a warning on stdout). */ @@ -277,7 +316,7 @@ static int process_slot(struct cache_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); + slot->fn(); return 0; } @@ -286,7 +325,7 @@ static int process_slot(struct cache_slot *slot) slot->lock_name, strerror(err), err); unlock_slot(slot, 0); close_lock(slot); - slot->fn(slot->cbdata); + slot->fn(); return 0; } // We've got a valid cache slot in the lock file, which @@ -310,7 +349,7 @@ static int process_slot(struct cache_slot *slot) /* Print cached content to stdout, generate the content if necessary. */ int cache_process(int size, const char *path, const char *key, int ttl, - cache_fill_fn fn, void *cbdata) + cache_fill_fn fn) { unsigned long hash; int i; @@ -320,15 +359,15 @@ int cache_process(int size, const char *path, const char *key, int ttl, int result; /* If the cache is disabled, just generate the content */ - if (size <= 0) { - fn(cbdata); + if (size <= 0 || ttl == 0) { + fn(); return 0; } /* Verify input, calculate filenames */ if (!path) { cache_log("[cgit] Cache path not specified, caching is disabled\n"); - fn(cbdata); + fn(); return 0; } if (!key) @@ -343,8 +382,8 @@ int cache_process(int size, const char *path, const char *key, int ttl, strbuf_addbuf(&lockname, &filename); strbuf_addstr(&lockname, ".lock"); slot.fn = fn; - slot.cbdata = cbdata; slot.ttl = ttl; + slot.stdout_fd = -1; slot.cache_name = filename.buf; slot.lock_name = lockname.buf; slot.key = key; @@ -376,7 +415,7 @@ int cache_ls(const char *path) DIR *dir; struct dirent *ent; int err = 0; - struct cache_slot slot = { 0 }; + struct cache_slot slot = { NULL }; struct strbuf fullname = STRBUF_INIT; size_t prefixlen;