summaryrefslogtreecommitdiffabout
path: root/cgit.c
authorLars Hjemli <hjemli@gmail.com>2006-12-11 21:53:50 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2006-12-11 21:53:50 (UTC)
commitfbaf1171b4e343929dd43ecac7cd9d1c692b84ec (patch) (unidiff)
tree40b7007b2e1e85f2e91e052b33555df2e9fb5e14 /cgit.c
parent44923f8953c66dc9b852316b655ab3b5aec9478e (diff)
downloadcgit-fbaf1171b4e343929dd43ecac7cd9d1c692b84ec.zip
cgit-fbaf1171b4e343929dd43ecac7cd9d1c692b84ec.tar.gz
cgit-fbaf1171b4e343929dd43ecac7cd9d1c692b84ec.tar.bz2
Don't truncate valid cachefiles
An embarrassing thinko in cgit_check_cache() would truncate valid cachefiles in the following situation: 1) process A notices a missing/expired cachefile 2) process B gets scheduled, locks, fills and unlocks the cachefile 3) process A gets scheduled, locks the cachefile, notices that the cachefile now exist/is not expired anymore, and continues to overwrite it with an empty lockfile. Thanks to Linus for noticing (again). Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'cgit.c') (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/cgit.c b/cgit.c
index d1abaa0..0f72f2d 100644
--- a/cgit.c
+++ b/cgit.c
@@ -40,55 +40,61 @@ static void cgit_fill_cache(struct cacheitem *item)
40{ 40{
41 htmlfd = item->fd; 41 htmlfd = item->fd;
42 item->st.st_mtime = time(NULL); 42 item->st.st_mtime = time(NULL);
43 if (cgit_query_repo) 43 if (cgit_query_repo)
44 cgit_print_repo_page(item); 44 cgit_print_repo_page(item);
45 else 45 else
46 cgit_print_repolist(item); 46 cgit_print_repolist(item);
47} 47}
48 48
49static void cgit_check_cache(struct cacheitem *item) 49static void cgit_check_cache(struct cacheitem *item)
50{ 50{
51 int i = 0; 51 int i = 0;
52 52
53 cache_prepare(item); 53 cache_prepare(item);
54 top: 54 top:
55 if (++i > cgit_max_lock_attempts) { 55 if (++i > cgit_max_lock_attempts) {
56 die("cgit_refresh_cache: unable to lock %s: %s", 56 die("cgit_refresh_cache: unable to lock %s: %s",
57 item->name, strerror(errno)); 57 item->name, strerror(errno));
58 } 58 }
59 if (!cache_exist(item)) { 59 if (!cache_exist(item)) {
60 if (!cache_lock(item)) { 60 if (!cache_lock(item)) {
61 sleep(1); 61 sleep(1);
62 goto top; 62 goto top;
63 } 63 }
64 if (!cache_exist(item)) 64 if (!cache_exist(item)) {
65 cgit_fill_cache(item); 65 cgit_fill_cache(item);
66 cache_unlock(item); 66 cache_unlock(item);
67 } else {
68 cache_cancel_lock(item);
69 }
67 } else if (cache_expired(item) && cache_lock(item)) { 70 } else if (cache_expired(item) && cache_lock(item)) {
68 if (cache_expired(item)) 71 if (cache_expired(item)) {
69 cgit_fill_cache(item); 72 cgit_fill_cache(item);
70 cache_unlock(item); 73 cache_unlock(item);
74 } else {
75 cache_cancel_lock(item);
76 }
71 } 77 }
72} 78}
73 79
74static void cgit_print_cache(struct cacheitem *item) 80static void cgit_print_cache(struct cacheitem *item)
75{ 81{
76 static char buf[4096]; 82 static char buf[4096];
77 ssize_t i; 83 ssize_t i;
78 84
79 int fd = open(item->name, O_RDONLY); 85 int fd = open(item->name, O_RDONLY);
80 if (fd<0) 86 if (fd<0)
81 die("Unable to open cached file %s", item->name); 87 die("Unable to open cached file %s", item->name);
82 88
83 while((i=read(fd, buf, sizeof(buf))) > 0) 89 while((i=read(fd, buf, sizeof(buf))) > 0)
84 write(STDOUT_FILENO, buf, i); 90 write(STDOUT_FILENO, buf, i);
85 91
86 close(fd); 92 close(fd);
87} 93}
88 94
89int main(int argc, const char **argv) 95int main(int argc, const char **argv)
90{ 96{
91 struct cacheitem item; 97 struct cacheitem item;
92 98
93 cgit_read_config("/etc/cgitrc", cgit_global_config_cb); 99 cgit_read_config("/etc/cgitrc", cgit_global_config_cb);
94 cgit_querystring = xstrdup(getenv("QUERY_STRING")); 100 cgit_querystring = xstrdup(getenv("QUERY_STRING"));