X-Git-Url: https://git.cameronkatri.com/cgit.git/blobdiff_plain/6ceba453a27ead382d0116d95bdeb6b6be1149e2..c4fbb99cee30fa295e240b429b2dc7e8ad83d535:/cache.c diff --git a/cache.c b/cache.c index 801e63f..2c70be7 100644 --- a/cache.c +++ b/cache.c @@ -13,22 +13,23 @@ * */ -#ifdef HAVE_LINUX_SENDFILE -#include -#endif #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; int cache_fd; int lock_fd; + int stdout_fd; const char *cache_name; const char *lock_name; int match; @@ -44,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) @@ -61,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; } @@ -161,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; @@ -183,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; @@ -194,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 */ @@ -208,16 +228,12 @@ static int fill_slot(struct cache_slot *slot) /* Generate cache content */ slot->fn(); - /* update stat info */ - if (fstat(slot->lock_fd, &slot->cache_st)) - return errno; - - /* 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; @@ -292,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). */ @@ -367,6 +383,7 @@ int cache_process(int size, const char *path, const char *key, int ttl, strbuf_addstr(&lockname, ".lock"); slot.fn = fn; slot.ttl = ttl; + slot.stdout_fd = -1; slot.cache_name = filename.buf; slot.lock_name = lockname.buf; slot.key = key; @@ -398,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;