-rw-r--r-- | cache.c | 68 |
1 files changed, 68 insertions, 0 deletions
@@ -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); } |