summaryrefslogtreecommitdiffabout
path: root/cache.c
Side-by-side diff
Diffstat (limited to 'cache.c') (more/less context) (ignore whitespace changes)
-rw-r--r--cache.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/cache.c b/cache.c
index e590d7b..b701e13 100644
--- a/cache.c
+++ b/cache.c
@@ -239,105 +239,173 @@ static int process_slot(struct cache_slot *slot)
}
print_slot(slot);
close_slot(slot);
return 0;
}
/* 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);
return 0;
}
if ((err = fill_slot(slot)) != 0) {
cache_log("[cgit] Unable to fill slot %s: %s (%d)\n",
slot->lock_name, strerror(err), err);
unlock_slot(slot, 0);
close_lock(slot);
slot->fn(slot->cbdata);
return 0;
}
// We've got a valid cache slot in the lock file, which
// is about to replace the old cache slot. But if we
// release the lockfile and then try to open the new cache
// slot, we might get a race condition with a concurrent
// writer for the same cache slot (with a different key).
// Lets avoid such a race by just printing the content of
// the lock file.
slot->cache_fd = slot->lock_fd;
unlock_slot(slot, 1);
err = print_slot(slot);
close_slot(slot);
return err;
}
/* 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)
{
unsigned long hash;
int len, i;
char filename[1024];
char lockname[1024 + 5]; /* 5 = ".lock" */
struct cache_slot slot;
/* If the cache is disabled, just generate the content */
if (size <= 0) {
fn(cbdata);
return 0;
}
/* Verify input, calculate filenames */
if (!path) {
cache_log("[cgit] Cache path not specified, caching is disabled\n");
fn(cbdata);
return 0;
}
len = strlen(path);
if (len > sizeof(filename) - 10) { /* 10 = "/01234567\0" */
cache_log("[cgit] Cache path too long, caching is disabled: %s\n",
path);
fn(cbdata);
return 0;
}
if (!key)
key = "";
hash = hash_str(key) % size;
strcpy(filename, path);
if (filename[len - 1] != '/')
filename[len++] = '/';
for(i = 0; i < 8; i++) {
sprintf(filename + len++, "%x",
(unsigned char)(hash & 0xf));
hash >>= 4;
}
filename[len] = '\0';
strcpy(lockname, filename);
strcpy(lockname + len, ".lock");
slot.fn = fn;
slot.cbdata = cbdata;
slot.ttl = ttl;
slot.cache_name = filename;
slot.lock_name = lockname;
slot.key = key;
slot.keylen = strlen(key);
return process_slot(&slot);
}
+/* Return a strftime formatted date/time
+ * NB: the result from this function is to shared memory
+ */
+char *sprintftime(const char *format, time_t time)
+{
+ static char buf[64];
+ struct tm *tm;
+
+ if (!time)
+ return NULL;
+ tm = gmtime(&time);
+ strftime(buf, sizeof(buf)-1, format, tm);
+ return buf;
+}
+
+int cache_ls(const char *path)
+{
+ DIR *dir;
+ struct dirent *ent;
+ int err = 0;
+ struct cache_slot slot;
+ char fullname[1024];
+ char *name;
+
+ if (!path) {
+ cache_log("[cgit] cache path not specified\n");
+ return -1;
+ }
+ if (strlen(path) > 1024 - 10) {
+ cache_log("[cgit] cache path too long: %s\n",
+ path);
+ return -1;
+ }
+ dir = opendir(path);
+ if (!dir) {
+ err = errno;
+ cache_log("[cgit] unable to open path %s: %s (%d)\n",
+ path, strerror(err), err);
+ return err;
+ }
+ strcpy(fullname, path);
+ name = fullname + strlen(path);
+ if (*(name - 1) != '/') {
+ *name++ = '/';
+ *name = '\0';
+ }
+ slot.cache_name = fullname;
+ while((ent = readdir(dir)) != NULL) {
+ if (strlen(ent->d_name) != 8)
+ continue;
+ strcpy(name, ent->d_name);
+ if ((err = open_slot(&slot)) != 0) {
+ cache_log("[cgit] unable to open path %s: %s (%d)\n",
+ fullname, strerror(err), err);
+ continue;
+ }
+ printf("%s %s %10lld %s\n",
+ name,
+ sprintftime("%Y-%m-%d %H:%M:%S",
+ slot.cache_st.st_mtime),
+ slot.cache_st.st_size,
+ slot.buf);
+ close_slot(&slot);
+ }
+ closedir(dir);
+ return 0;
+}
+
/* Print a message to stdout */
void cache_log(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
}