diff options
author | Timo Teras <timo.teras@iki.fi> | 2009-04-15 09:56:09 +0300 |
---|---|---|
committer | Timo Teras <timo.teras@iki.fi> | 2009-04-15 09:56:09 +0300 |
commit | 9567337fd2444aa9b30a6cbfdd5bc9a98d171f25 (patch) | |
tree | 7811255a8e028774b154d67245283022092312b9 /src | |
parent | a23f6f4afb0f819c6c478975df41e235e8d0953a (diff) | |
download | apk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.tar.gz apk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.tar.bz2 apk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.tar.xz apk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.zip |
fetch: new applet to download .apk files
Fixes #24.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 1 | ||||
-rw-r--r-- | src/apk_archive.h | 2 | ||||
-rw-r--r-- | src/apk_database.h | 1 | ||||
-rw-r--r-- | src/apk_defines.h | 1 | ||||
-rw-r--r-- | src/apk_io.h | 2 | ||||
-rw-r--r-- | src/apk_state.h | 14 | ||||
-rw-r--r-- | src/database.c | 20 | ||||
-rw-r--r-- | src/fetch.c | 185 | ||||
-rw-r--r-- | src/state.c | 14 |
9 files changed, 214 insertions, 26 deletions
diff --git a/src/Makefile b/src/Makefile index b9414ae..d4a7244 100644 --- a/src/Makefile +++ b/src/Makefile @@ -27,6 +27,7 @@ apk_OBJS = \ index.o \ info.o \ search.o \ + fetch.o \ audit.o \ apk.o diff --git a/src/apk_archive.h b/src/apk_archive.h index b048398..4651255 100644 --- a/src/apk_archive.h +++ b/src/apk_archive.h @@ -20,8 +20,6 @@ typedef int (*apk_archive_entry_parser)(void *ctx, const struct apk_file_info *ae, struct apk_istream *istream); -int apk_file_get_info(const char *filename, struct apk_file_info *fi); - int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx); int apk_parse_tar_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx); diff --git a/src/apk_database.h b/src/apk_database.h index b7d0eed..6ca630b 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -111,6 +111,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, #define APK_OPENF_READ 0x0000 #define APK_OPENF_WRITE 0x0001 #define APK_OPENF_CREATE 0x0002 +#define APK_OPENF_EMPTY_STATE 0x0004 int apk_db_open(struct apk_database *db, const char *root, unsigned int flags); int apk_db_write_config(struct apk_database *db); diff --git a/src/apk_defines.h b/src/apk_defines.h index e8029de..ecb80d0 100644 --- a/src/apk_defines.h +++ b/src/apk_defines.h @@ -58,6 +58,7 @@ extern unsigned int apk_flags; #define APK_CLEAN_PROTECTED 0x0004 #define APK_PROGRESS 0x0008 #define APK_UPGRADE 0x0010 +#define APK_RECURSIVE 0x0020 #define apk_error(args...) apk_log("ERROR: ", args); #define apk_warning(args...) if (apk_verbosity > 0) { apk_log("WARNING: ", args); } diff --git a/src/apk_io.h b/src/apk_io.h index 8ee80f8..a903277 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -67,4 +67,6 @@ struct apk_ostream *apk_ostream_to_file_gz(const char *file, mode_t mode); apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size); apk_blob_t apk_blob_from_file(const char *file); +int apk_file_get_info(const char *filename, struct apk_file_info *fi); + #endif diff --git a/src/apk_state.h b/src/apk_state.h index d065411..402b919 100644 --- a/src/apk_state.h +++ b/src/apk_state.h @@ -14,7 +14,19 @@ #include "apk_database.h" -struct apk_state; +typedef void *apk_name_state_t; + +struct apk_change { + struct list_head change_list; + struct apk_package *oldpkg; + struct apk_package *newpkg; +}; + +struct apk_state { + int refs; + struct list_head change_list_head; + apk_name_state_t name[]; +}; struct apk_state *apk_state_new(struct apk_database *db); struct apk_state *apk_state_dup(struct apk_state *state); diff --git a/src/database.c b/src/database.c index 9bf34ba..7162ef7 100644 --- a/src/database.c +++ b/src/database.c @@ -693,18 +693,20 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) apk_blob_for_each_segment(blob, ":", add_protected_path, db); if (root != NULL) { - r = apk_db_read_state(db); - if (r == -ENOENT && (flags & APK_OPENF_CREATE)) { - r = apk_db_create(db); + if (!(flags & APK_OPENF_EMPTY_STATE)) { + r = apk_db_read_state(db); + if (r == -ENOENT && (flags & APK_OPENF_CREATE)) { + r = apk_db_create(db); + if (r != 0) { + msg = "Unable to create database"; + goto ret_r; + } + r = apk_db_read_state(db); + } if (r != 0) { - msg = "Unable to create database"; + msg = "Unable to read database state"; goto ret_r; } - r = apk_db_read_state(db); - } - if (r != 0) { - msg = "Unable to read database state"; - goto ret_r; } if (apk_repos == NULL) diff --git a/src/fetch.c b/src/fetch.c new file mode 100644 index 0000000..40b8a24 --- /dev/null +++ b/src/fetch.c @@ -0,0 +1,185 @@ +/* fetch.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org> + * 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 + * 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. + */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_state.h" +#include "apk_io.h" + +#define FETCH_RECURSIVE 1 +#define FETCH_STDOUT 2 + +struct fetch_ctx { + unsigned int flags; + const char *outdir; +}; + +static int fetch_parse(void *ctx, int optch, int optindex, const char *optarg) +{ + struct fetch_ctx *fctx = (struct fetch_ctx *) ctx; + + switch (optch) { + case 'R': + fctx->flags |= FETCH_RECURSIVE; + break; + case 's': + fctx->flags |= FETCH_STDOUT; + break; + case 'o': + fctx->outdir = optarg; + break; + default: + return -1; + } + return 0; +} + +static int fetch_package(struct fetch_ctx *fctx, + struct apk_database *db, + struct apk_package *pkg) +{ + struct apk_istream *is; + char file[256]; + int i, r, fd; + + if (fctx->flags & FETCH_STDOUT) { + fd = STDOUT_FILENO; + } else { + struct apk_file_info fi; + + snprintf(file, sizeof(file), "%s/%s-%s.apk", + fctx->outdir ? fctx->outdir : ".", + pkg->name->name, pkg->version); + + if (apk_file_get_info(file, &fi) == 0 && + fi.size == pkg->size) + return 0; + + fd = creat(file, 0644); + if (fd < 0) { + apk_error("Unable to create '%s'", file); + return -1; + } + } + + apk_message("Downloading %s-%s", pkg->name->name, pkg->version); + + for (i = 0; i < APK_MAX_REPOS; i++) + if (pkg->repos & BIT(i)) + break; + + if (i >= APK_MAX_REPOS) { + apk_error("%s-%s: not present in any repository", + pkg->name->name, pkg->version); + return -1; + } + + snprintf(file, sizeof(file), "%s/%s-%s.apk", + db->repos[i].url, pkg->name->name, pkg->version); + is = apk_istream_from_url(file); + if (is == NULL) { + apk_error("Unable to download '%s'", file); + return -1; + } + + r = apk_istream_splice(is, fd, pkg->size, NULL, NULL); + if (r != pkg->size) { + is->close(is); + apk_error("Unable to download '%s'", file); + return -1; + } + + return 0; +} + +static int fetch_main(void *ctx, int argc, char **argv) +{ + struct fetch_ctx *fctx = (struct fetch_ctx *) ctx; + struct apk_database db; + int i, j, r; + + r = apk_db_open(&db, apk_root, APK_OPENF_EMPTY_STATE); + if (r != 0) + return r; + + for (i = 0; i < argc; i++) { + struct apk_dependency dep = (struct apk_dependency) { + .name = apk_db_get_name(&db, APK_BLOB_STR(argv[i])), + .result_mask = APK_DEPMASK_REQUIRE, + }; + + if (fctx->flags & FETCH_RECURSIVE) { + struct apk_state *state; + struct apk_change *change; + + state = apk_state_new(&db); + r = apk_state_lock_dependency(state, &dep); + if (r != 0) { + apk_state_unref(state); + apk_error("Unable to install '%s'", + dep.name->name); + goto err; + } + + list_for_each_entry(change, &state->change_list_head, change_list) { + r = fetch_package(fctx, &db, change->newpkg); + if (r != 0) + goto err; + } + + apk_state_unref(state); + } else if (dep.name->pkgs != NULL) { + struct apk_package *pkg = NULL; + + for (j = 0; j < dep.name->pkgs->num; j++) + if (pkg == NULL || + apk_version_compare(APK_BLOB_STR(dep.name->pkgs->item[j]->version), + APK_BLOB_STR(pkg->version)) + == APK_VERSION_GREATER) + pkg = dep.name->pkgs->item[j]; + + r = fetch_package(fctx, &db, pkg); + if (r != 0) + goto err; + } else { + apk_message("Unable to get '%s'", dep.name->name); + r = -1; + break; + } + } + +err: + apk_db_close(&db); + return r; +} + +static struct option fetch_options[] = { + { "recursive", no_argument, NULL, 'R' }, + { "stdout", no_argument, NULL, 's' }, + { "output", required_argument, NULL, 'o' }, +}; + +static struct apk_applet apk_fetch = { + .name = "fetch", + .usage = "[-R|--recursive|--stdout] [-o dir] apkname...", + .context_size = sizeof(struct fetch_ctx), + .num_options = ARRAY_SIZE(fetch_options), + .options = fetch_options, + .parse = fetch_parse, + .main = fetch_main, +}; + +APK_DEFINE_APPLET(apk_fetch); + diff --git a/src/state.c b/src/state.c index a0abb57..79655a9 100644 --- a/src/state.c +++ b/src/state.c @@ -16,25 +16,11 @@ #include "apk_state.h" #include "apk_database.h" -typedef void *apk_name_state_t; - -struct apk_change { - struct list_head change_list; - struct apk_package *oldpkg; - struct apk_package *newpkg; -}; - struct apk_name_choices { unsigned short refs, num; struct apk_package *pkgs[]; }; -struct apk_state { - int refs; - struct list_head change_list_head; - apk_name_state_t name[]; -}; - #if 0 struct apk_deferred_state { unsigned int preference; |