1 /* cache.c: cache management
3 * Copyright (C) 2006 Lars Hjemli
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
11 const int NOLOCK
= -1;
13 void cache_prepare(struct cacheitem
*item
)
15 if (!cgit_query_repo
) {
16 item
->name
= xstrdup(fmt("%s/index.html", cgit_cache_root
));
17 item
->ttl
= cgit_cache_root_ttl
;
18 } else if (!cgit_query_page
) {
19 item
->name
= xstrdup(fmt("%s/%s/index.html", cgit_cache_root
,
21 item
->ttl
= cgit_cache_repo_ttl
;
23 item
->name
= xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root
,
24 cgit_query_repo
, cgit_query_page
,
26 if (cgit_query_has_symref
)
27 item
->ttl
= cgit_cache_dynamic_ttl
;
28 else if (cgit_query_has_sha1
)
29 item
->ttl
= cgit_cache_static_ttl
;
31 item
->ttl
= cgit_cache_repo_ttl
;
35 int cache_exist(struct cacheitem
*item
)
37 if (stat(item
->name
, &item
->st
)) {
38 item
->st
.st_mtime
= 0;
44 int cache_create_dirs()
48 path
= fmt("%s", cgit_cache_root
);
49 if (mkdir(path
, S_IRWXU
) && errno
!=EEXIST
)
55 path
= fmt("%s/%s", cgit_cache_root
, cgit_query_repo
);
56 if (mkdir(path
, S_IRWXU
) && errno
!=EEXIST
)
59 if (cgit_query_page
) {
60 path
= fmt("%s/%s/%s", cgit_cache_root
, cgit_query_repo
,
62 if (mkdir(path
, S_IRWXU
) && errno
!=EEXIST
)
68 int cache_refill_overdue(const char *lockfile
)
72 if (stat(lockfile
, &st
))
75 return (time(NULL
) - st
.st_mtime
> cgit_cache_max_create_time
);
78 int cache_lock(struct cacheitem
*item
)
81 char *lockfile
= xstrdup(fmt("%s.lock", item
->name
));
84 if (++i
> cgit_max_lock_attempts
)
85 die("cache_lock: unable to lock %s: %s",
86 item
->name
, strerror(errno
));
88 item
->fd
= open(lockfile
, O_WRONLY
|O_CREAT
|O_EXCL
, S_IRUSR
|S_IWUSR
);
90 if (item
->fd
== NOLOCK
&& errno
== ENOENT
&& cache_create_dirs())
93 if (item
->fd
== NOLOCK
&& errno
== EEXIST
&&
94 cache_refill_overdue(lockfile
) && !unlink(lockfile
))
98 return (item
->fd
> 0);
101 int cache_unlock(struct cacheitem
*item
)
104 return (rename(fmt("%s.lock", item
->name
), item
->name
) == 0);
107 int cache_cancel_lock(struct cacheitem
*item
)
109 return (unlink(fmt("%s.lock", item
->name
)) == 0);
112 int cache_expired(struct cacheitem
*item
)
116 return item
->st
.st_mtime
+ item
->ttl
* 60 < time(NULL
);