10 #include "repo_solv.h"
11 #include "repo_write.h"
14 #include "repoinfo_cache.h"
16 #define COOKIE_IDENT "1.1"
18 #define SOLVCACHE_PATH "/var/cache/solv"
20 static char *userhome;
25 userhome = getenv("HOME");
26 if (userhome && userhome[0] != '/')
31 calc_cookie_fp(FILE *fp, Id chktype, unsigned char *out)
34 Chksum *h = solv_chksum_create(chktype);
37 solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT));
38 while ((l = fread(buf, 1, sizeof(buf), fp)) > 0)
39 solv_chksum_add(h, buf, l);
41 solv_chksum_free(h, out);
45 calc_cookie_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out)
47 Chksum *h = solv_chksum_create(chktype);
48 solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT));
50 solv_chksum_add(h, cookie, 32);
51 solv_chksum_add(h, &stb->st_dev, sizeof(stb->st_dev));
52 solv_chksum_add(h, &stb->st_ino, sizeof(stb->st_ino));
53 solv_chksum_add(h, &stb->st_size, sizeof(stb->st_size));
54 solv_chksum_add(h, &stb->st_mtime, sizeof(stb->st_mtime));
55 solv_chksum_free(h, out);
59 calc_cachepath(Repo *repo, const char *repoext, int forcesystemloc)
63 if (!forcesystemloc && userhome && getuid())
64 p = pool_tmpjoin(repo->pool, userhome, "/.solvcache/", 0);
66 p = pool_tmpjoin(repo->pool, SOLVCACHE_PATH, "/", 0);
68 p = pool_tmpappend(repo->pool, p, repo->name, 0);
71 p = pool_tmpappend(repo->pool, p, "_", repoext);
72 p = pool_tmpappend(repo->pool, p, ".solvx", 0);
75 p = pool_tmpappend(repo->pool, p, ".solv", 0);
86 usecachedrepo(struct repoinfo *cinfo, const char *repoext, int mark)
88 Repo *repo = cinfo->repo;
90 unsigned char *cookie = repoext ? cinfo->extcookie : (cinfo->cookieset ? cinfo->cookie : 0);
91 unsigned char mycookie[32];
92 unsigned char myextcookie[32];
96 if (repoext && !cinfo->extcookieset)
98 forcesystemloc = mark & 2 ? 0 : 1;
99 if (mark < 2 && userhome && getuid())
101 /* first try home location */
102 int res = usecachedrepo(cinfo, repoext, mark | 2);
107 if (!(fp = fopen(calc_cachepath(repo, repoext, forcesystemloc), "r")))
109 if (!repoext && !cinfo->cookieset && cinfo->autorefresh && cinfo->metadata_expire != -1)
111 struct stat stb; /* no cookie set yet, check cache expiry time */
112 if (fstat(fileno(fp), &stb) || time(0) - stb.st_mtime >= cinfo->metadata_expire)
118 if (fseek(fp, -sizeof(mycookie), SEEK_END) || fread(mycookie, sizeof(mycookie), 1, fp) != 1)
123 if (cookie && memcmp(cookie, mycookie, sizeof(mycookie)) != 0)
128 if (cinfo->type != TYPE_INSTALLED && !repoext)
130 if (fseek(fp, -sizeof(mycookie) * 2, SEEK_END) || fread(myextcookie, sizeof(myextcookie), 1, fp) != 1)
141 flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
142 if (strcmp(repoext, "DL") != 0)
143 flags |= REPO_LOCALPOOL; /* no local pool for DL so that we can compare IDs */
145 if (repo_add_solv(repo, fp, flags))
150 if (cinfo->type != TYPE_INSTALLED && !repoext)
152 memcpy(cinfo->cookie, mycookie, sizeof(mycookie));
153 cinfo->cookieset = 1;
154 memcpy(cinfo->extcookie, myextcookie, sizeof(myextcookie));
155 cinfo->extcookieset = 1;
158 futimens(fileno(fp), 0); /* try to set modification time */
164 switchtowritten(struct repoinfo *cinfo, const char *repoext, Repodata *repodata, char *tmpl)
166 Repo *repo = cinfo->repo;
170 if (!repoext && repodata)
171 return; /* rewrite case, don't bother for the added fileprovides */
172 for (i = repo->start; i < repo->end; i++)
173 if (repo->pool->solvables[i].repo != repo)
176 return; /* not a simple block */
177 /* switch to just saved repo to activate paging and save memory */
178 fp = fopen(tmpl, "r");
185 if (repo_add_solv(repo, fp, SOLV_ADD_NO_STUBS))
187 /* oops, no way to recover from here */
188 fprintf(stderr, "internal error\n");
194 int flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
195 /* make sure repodata contains complete repo */
196 /* (this is how repodata_write saves it) */
197 repodata_extend_block(repodata, repo->start, repo->end - repo->start);
198 repodata->state = REPODATA_LOADING;
199 if (strcmp(repoext, "DL") != 0)
200 flags |= REPO_LOCALPOOL;
201 repo_add_solv(repo, fp, flags);
202 repodata->state = REPODATA_AVAILABLE; /* in case the load failed */
208 writecachedrepo(struct repoinfo *cinfo, const char *repoext, Repodata *repodata)
210 Repo *repo = cinfo->repo;
213 char *tmpl, *cachedir;
215 if (cinfo->incomplete || (repoext && !cinfo->extcookieset) || (!repoext && !cinfo->cookieset))
217 cachedir = userhome && getuid() ? pool_tmpjoin(repo->pool, userhome, "/.solvcache", 0) : SOLVCACHE_PATH;
218 if (access(cachedir, W_OK | X_OK) != 0 && mkdir(cachedir, 0755) == 0)
219 printf("[created %s]\n", cachedir);
220 /* use dupjoin instead of tmpjoin because tmpl must survive repo_write */
221 tmpl = solv_dupjoin(cachedir, "/", ".newsolv-XXXXXX");
229 if (!(fp = fdopen(fd, "w")))
238 repo_write(repo, fp);
240 repodata_write(repodata, fp);
243 int oldnrepodata = repo->nrepodata;
244 repo->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata; /* XXX: do this right */
245 repo_write(repo, fp);
246 repo->nrepodata = oldnrepodata;
249 if (!repoext && cinfo->type != TYPE_INSTALLED)
251 if (!cinfo->extcookieset)
253 /* create the ext cookie and append it */
254 /* we just need some unique ID */
256 if (fstat(fileno(fp), &stb))
257 memset(&stb, 0, sizeof(stb));
258 calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->cookie, cinfo->extcookie);
259 cinfo->extcookieset = 1;
261 if (fwrite(cinfo->extcookie, 32, 1, fp) != 1)
269 /* append our cookie describing the metadata state */
270 if (fwrite(repoext ? cinfo->extcookie : cinfo->cookie, 32, 1, fp) != 1)
284 switchtowritten(cinfo, repoext, repodata, tmpl);
286 if (!rename(tmpl, calc_cachepath(repo, repoext, 0)))