diff options
-rw-r--r-- | src/apk_database.h | 5 | ||||
-rw-r--r-- | src/apk_io.h | 3 | ||||
-rw-r--r-- | src/database.c | 142 | ||||
-rw-r--r-- | src/io.c | 58 |
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); @@ -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; |