summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-06-28 20:36:16 +0300
committerTimo Teras <timo.teras@iki.fi>2009-06-29 09:29:57 +0300
commit233918e518f72e469ba39206abf70250bd6fc54a (patch)
tree426a311a98ffa3c4bc592287730b3a55e58a9197 /src
parentfac4cdb3fad6037e0841724a50d5364d16603f07 (diff)
downloadapk-tools-233918e518f72e469ba39206abf70250bd6fc54a.tar.bz2
apk-tools-233918e518f72e469ba39206abf70250bd6fc54a.tar.xz
db: cache packages (ref #49)
If /etc/apk/cache is a symlink to directory, a copy of all installed packages is stored there, and the index of remote repositories will be there instead of /var/lib/apk. This enables to reconstruct running system during boot. Left as todo: remove cached copy when the package is removed, and additional apk applet to download missing packages to cache and/or remove extra items.
Diffstat (limited to 'src')
-rw-r--r--src/apk_database.h5
-rw-r--r--src/apk_io.h3
-rw-r--r--src/database.c142
-rw-r--r--src/io.c58
4 files changed, 149 insertions, 59 deletions
diff --git a/src/apk_database.h b/src/apk_database.h
index 6f18277..de7ce4b 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -4,7 +4,7 @@
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
+ * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
@@ -68,13 +68,14 @@ struct apk_name {
struct apk_repository {
char *url;
- char *cache;
+ csum_t url_csum;
};
struct apk_database {
char *root;
int root_fd, lock_fd;
unsigned name_id, num_repos;
+ const char *cache_dir;
struct apk_dependency_array *world;
struct apk_string_array *protected_paths;
diff --git a/src/apk_io.h b/src/apk_io.h
index e0d9629..2bb862c 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -3,7 +3,7 @@
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
+ * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
@@ -59,6 +59,7 @@ struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream);
struct apk_bstream *apk_bstream_from_fd(int fd);
struct apk_bstream *apk_bstream_from_file(const char *file);
struct apk_bstream *apk_bstream_from_url(const char *url);
+struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, const char *to);
struct apk_ostream *apk_ostream_to_fd(int fd);
struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode);
diff --git a/src/database.c b/src/database.c
index 00faf97..28da3b9 100644
--- a/src/database.c
+++ b/src/database.c
@@ -25,6 +25,10 @@
#include "apk_state.h"
#include "apk_applet.h"
+static const char * const apk_index_gz = "APK_INDEX.gz";
+static const char * const apk_static_cache_dir = "var/lib/apk";
+static const char * const apk_linked_cache_dir = "etc/apk/cache";
+
struct install_ctx {
struct apk_database *db;
struct apk_package *pkg;
@@ -645,10 +649,11 @@ static int apk_db_create(struct apk_database *db)
int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
{
- apk_blob_t blob;
const char *apk_repos = getenv("APK_REPOS"), *msg = NULL;
- int r;
struct apk_repository_url *repo = NULL;
+ struct stat st;
+ apk_blob_t blob;
+ int r;
memset(db, 0, sizeof(*db));
apk_hash_init(&db->available.names, &pkg_name_hash_ops, 1000);
@@ -656,6 +661,7 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
apk_hash_init(&db->installed.dirs, &dir_hash_ops, 1000);
apk_hash_init(&db->installed.files, &file_hash_ops, 4000);
list_init(&db->installed.packages);
+ db->cache_dir = apk_static_cache_dir;
if (root != NULL) {
fchdir(apk_cwd_fd);
@@ -722,6 +728,9 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
free(blob.ptr);
}
}
+
+ if (stat(apk_linked_cache_dir, &st) == 0 && S_ISDIR(st.st_mode))
+ db->cache_dir = apk_linked_cache_dir;
}
if (!(flags & APK_OPENF_EMPTY_REPOS)) {
@@ -801,8 +810,6 @@ void apk_db_close(struct apk_database *db)
for (i = 0; i < db->num_repos; i++) {
free(db->repos[i].url);
- if (db->repos[i].cache != NULL)
- free(db->repos[i].cache);
}
if (db->protected_paths) {
for (i = 0; i < db->protected_paths->num; i++)
@@ -895,33 +902,27 @@ int apk_db_index_write(struct apk_database *db, struct apk_ostream *os)
return ctx.count;
}
-static struct apk_bstream *apk_db_cache_open(struct apk_database *db,
- const char *file)
+static void apk_db_cache_get_name(char *buf, size_t bufsz,
+ struct apk_database *db, csum_t csum,
+ const char *file, int temp)
{
- char tmp[256];
+ char csumstr[sizeof(csum_t)*2+1];
- if (db->root == NULL)
- return NULL;
-
- snprintf(tmp, sizeof(tmp), "%s/var/lib/apk/%s", db->root, file);
- return apk_bstream_from_file(tmp);
+ apk_hexdump_format(sizeof(csumstr), csumstr, APK_BLOB_BUF(csum));
+ snprintf(buf, bufsz, "%s/%s/%s.%s%s",
+ db->root, db->cache_dir, csumstr, file, temp ? ".new" : "");
}
-static int apk_db_cache_has(struct apk_database *db, const char *file)
+static struct apk_bstream *apk_db_cache_open(struct apk_database *db,
+ csum_t csum, const char *file)
{
char tmp[256];
- struct apk_file_info fi;
- int r;
if (db->root == NULL)
- return FALSE;
-
- snprintf(tmp, sizeof(tmp), "%s/var/lib/apk/%s", db->root, file);
- r = apk_file_get_info(tmp, &fi);
- if (r < 0)
- return FALSE;
+ return NULL;
- return TRUE;
+ apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, file, FALSE);
+ return apk_bstream_from_file(tmp);
}
static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo,
@@ -939,20 +940,21 @@ int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
char tmp[256], tmp2[256];
int r;
- if (repo->cache == NULL)
+ if (!csum_valid(repo->url_csum))
return 0;
apk_message("fetch index %s", repo->url);
- snprintf(tmp, sizeof(tmp), "%s/APK_INDEX.gz", repo->url);
- snprintf(tmp2, sizeof(tmp2), "%s/var/lib/apk/%s.new",
- db->root, repo->cache);
+ snprintf(tmp, sizeof(tmp), "%s/%s", repo->url, apk_index_gz);
+ apk_db_cache_get_name(tmp2, sizeof(tmp2), db, repo->url_csum,
+ apk_index_gz, TRUE);
+
r = apk_url_download(tmp, tmp2);
if (r < 0)
return r;
- snprintf(tmp, sizeof(tmp), "%s/var/lib/apk/%s",
- db->root, repo->cache);
+ apk_db_cache_get_name(tmp, sizeof(tmp), db, repo->url_csum,
+ apk_index_gz, FALSE);
if (rename(tmp2, tmp) < 0)
return -errno;
@@ -974,7 +976,8 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
{
struct apk_database *db = _db.db;
struct apk_istream *is = NULL;
- char buf[2*sizeof(csum_t)+32], *name;
+ struct apk_bstream *bs = NULL;
+ struct apk_repository *repo;
int r, n;
if (repository.ptr == NULL || *repository.ptr == '\0'
@@ -985,33 +988,29 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
return -1;
r = db->num_repos++;
- db->repos[r] = (struct apk_repository) {
+
+ repo = &db->repos[r];
+ *repo = (struct apk_repository) {
.url = apk_blob_cstr(repository),
- .cache = NULL,
};
- if (apk_url_local_file(db->repos[r].url) == NULL) {
- csum_t cs;
-
- apk_blob_csum(repository, cs);
- n = apk_hexdump_format(sizeof(buf), buf, APK_BLOB_BUF(cs)) - 1;
- snprintf(&buf[n], sizeof(buf) - n, ".index.gz");
+ if (apk_url_local_file(repo->url) == NULL) {
+ apk_blob_csum(repository, repo->url_csum);
- db->repos[r].cache = strdup(buf);
-
- if (!apk_db_cache_has(db, db->repos[r].cache)) {
- n = apk_repository_update(db, &db->repos[r]);
+ bs = apk_db_cache_open(db, repo->url_csum, apk_index_gz);
+ if (bs == NULL) {
+ n = apk_repository_update(db, repo);
if (n < 0)
return n;
+ bs = apk_db_cache_open(db, repo->url_csum,
+ apk_index_gz);
}
- name = db->repos[r].cache;
- is = apk_bstream_gunzip(apk_db_cache_open(db, db->repos[r].cache), 1);
} else {
- name = "APK_INDEX.gz";
- is = apk_bstream_gunzip(apk_repository_file_open(&db->repos[r], name), 1);
+ bs = apk_repository_file_open(repo, apk_index_gz);
}
+ is = apk_bstream_gunzip(bs, 1);
if (is == NULL) {
- apk_warning("Failed to open index for %s", db->repos[r].url);
+ apk_warning("Failed to open index for %s", repo->url);
return -1;
}
apk_db_index_read(db, is, r);
@@ -1237,11 +1236,17 @@ static int apk_db_unpack_pkg(struct apk_database *db,
apk_progress_cb cb, void *cb_ctx)
{
struct install_ctx ctx;
- struct apk_bstream *bs;
- char file[256];
- int i;
+ struct apk_bstream *bs = NULL;
+ char pkgname[256], file[256];
+ int i, need_copy = TRUE;
+ size_t length;
+
+ snprintf(pkgname, sizeof(pkgname), "%s-%s.apk",
+ newpkg->name->name, newpkg->version);
if (newpkg->filename == NULL) {
+ struct apk_repository *repo;
+
for (i = 0; i < APK_MAX_REPOS; i++)
if (newpkg->repos & BIT(i))
break;
@@ -1252,13 +1257,27 @@ static int apk_db_unpack_pkg(struct apk_database *db,
return -1;
}
- snprintf(file, sizeof(file),
- "%s/%s-%s.apk",
- db->repos[i].url,
- newpkg->name->name, newpkg->version);
- bs = apk_bstream_from_url(file);
- } else
+ repo = &db->repos[i];
+ if (db->cache_dir != apk_static_cache_dir &&
+ csum_valid(repo->url_csum))
+ bs = apk_db_cache_open(db, newpkg->csum, pkgname);
+
+ if (bs == NULL) {
+ snprintf(file, sizeof(file), "%s/%s",
+ repo->url, pkgname);
+ bs = apk_bstream_from_url(file);
+ if (csum_valid(repo->url_csum))
+ need_copy = TRUE;
+ }
+ } else {
bs = apk_bstream_from_file(newpkg->filename);
+ need_copy = TRUE;
+ }
+ if (need_copy) {
+ apk_db_cache_get_name(file, sizeof(file), db, newpkg->csum,
+ pkgname, TRUE);
+ bs = apk_bstream_tee(bs, file);
+ }
if (bs == NULL) {
apk_error("%s: %s", file, strerror(errno));
@@ -1276,7 +1295,18 @@ static int apk_db_unpack_pkg(struct apk_database *db,
if (apk_parse_tar_gz(bs, apk_db_install_archive_entry, &ctx) != 0)
goto err_close;
- bs->close(bs, csum, NULL);
+ bs->close(bs, csum, &length);
+ if (need_copy) {
+ if (length == newpkg->size) {
+ char file2[256];
+ apk_db_cache_get_name(file2, sizeof(file2), db,
+ newpkg->csum, pkgname, FALSE);
+ rename(file, file2);
+ } else {
+ unlink(file);
+ }
+ }
+
return 0;
err_close:
bs->close(bs, NULL, NULL);
diff --git a/src/io.c b/src/io.c
index defbe46..22a69e5 100644
--- a/src/io.c
+++ b/src/io.c
@@ -319,6 +319,64 @@ struct apk_bstream *apk_bstream_from_file(const char *file)
return apk_bstream_from_fd(fd);
}
+
+struct apk_tee_bstream {
+ struct apk_bstream bs;
+ struct apk_bstream *inner_bs;
+ int fd;
+ size_t size;
+};
+
+static size_t tee_read(void *stream, void **ptr)
+{
+ struct apk_tee_bstream *tbs =
+ container_of(stream, struct apk_tee_bstream, bs);
+ size_t size;
+
+ size = tbs->inner_bs->read(tbs->inner_bs, ptr);
+ if (size >= 0)
+ tbs->size += write(tbs->fd, *ptr, size);
+
+ return size;
+}
+
+static void tee_close(void *stream, csum_t csum, size_t *size)
+{
+ struct apk_tee_bstream *tbs =
+ container_of(stream, struct apk_tee_bstream, bs);
+
+ tbs->inner_bs->close(tbs->inner_bs, csum, NULL);
+ if (size != NULL)
+ *size = tbs->size;
+ close(tbs->fd);
+ free(tbs);
+}
+
+struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, const char *to)
+{
+ struct apk_tee_bstream *tbs;
+ int fd;
+
+ fd = creat(to, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ return NULL;
+
+ tbs = malloc(sizeof(struct apk_tee_bstream));
+ if (tbs == NULL) {
+ close(fd);
+ return NULL;
+ }
+
+ tbs->bs = (struct apk_bstream) {
+ .read = tee_read,
+ .close = tee_close,
+ };
+ tbs->inner_bs = from;
+ tbs->fd = fd;
+
+ return &tbs->bs;
+}
+
apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
{
void *ptr;