diff options
Diffstat (limited to 'lib/libalpm/add.c')
-rw-r--r-- | lib/libalpm/add.c | 200 |
1 files changed, 108 insertions, 92 deletions
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index f39a0ecf..702b12e9 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -1,7 +1,7 @@ /* * add.c * - * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -40,7 +40,6 @@ #include "alpm_list.h" #include "trans.h" #include "util.h" -#include "cache.h" #include "log.h" #include "backup.h" #include "package.h" @@ -50,64 +49,92 @@ #include "remove.h" #include "handle.h" -/** Add a file target to the transaction. - * @param target the name of the file target to add +/** Add a package to the transaction. + * @param pkg the package to add * @return 0 on success, -1 on error (pm_errno is set accordingly) */ -int SYMEXPORT alpm_add_target(char *target) +int SYMEXPORT alpm_add_pkg(pmpkg_t *pkg) { - pmpkg_t *pkg = NULL; const char *pkgname, *pkgver; - alpm_list_t *i; pmtrans_t *trans; + pmdb_t *db_local; + pmpkg_t *local; ALPM_LOG_FUNC; /* Sanity checks */ - ASSERT(target != NULL && strlen(target) != 0, RET_ERR(PM_ERR_WRONG_ARGS, -1)); + ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1)); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1)); ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); + db_local = handle->db_local; - _alpm_log(PM_LOG_DEBUG, "loading target '%s'\n", target); - - if(alpm_pkg_load(target, 1, &pkg) != 0) { - goto error; - } pkgname = alpm_pkg_get_name(pkg); pkgver = alpm_pkg_get_version(pkg); - /* check if an older version of said package is already in transaction - * packages. if so, replace it in the list */ - for(i = trans->add; i; i = i->next) { - pmpkg_t *transpkg = i->data; - if(strcmp(transpkg->name, pkgname) == 0) { - if(alpm_pkg_vercmp(transpkg->version, pkgver) < 0) { - _alpm_log(PM_LOG_WARNING, - _("replacing older version %s-%s by %s in target list\n"), - transpkg->name, transpkg->version, pkgver); - _alpm_pkg_free(i->data); - i->data = pkg; + _alpm_log(PM_LOG_DEBUG, "adding package '%s'\n", pkgname); + + if(_alpm_pkg_find(trans->add, pkgname)) { + RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1); + } + + local = _alpm_db_get_pkgfromcache(db_local, pkgname); + if(local) { + const char *localpkgname = alpm_pkg_get_name(local); + const char *localpkgver = alpm_pkg_get_version(local); + int cmp = _alpm_pkg_compare_versions(pkg, local); + + if(cmp == 0) { + if(trans->flags & PM_TRANS_FLAG_NEEDED) { + /* with the NEEDED flag, packages up to date are not reinstalled */ + _alpm_log(PM_LOG_WARNING, _("%s-%s is up to date -- skipping\n"), + localpkgname, localpkgver); + return(0); } else { - _alpm_log(PM_LOG_WARNING, - _("skipping %s-%s because newer version %s is in target list\n"), - pkgname, pkgver, transpkg->version); - _alpm_pkg_free(pkg); + _alpm_log(PM_LOG_WARNING, _("%s-%s is up to date -- reinstalling\n"), + localpkgname, localpkgver); } - return(0); + } else if(cmp < 0) { + /* local version is newer */ + _alpm_log(PM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"), + localpkgname, localpkgver, pkgver); } } /* add the package to the transaction */ + pkg->reason = PM_PKG_REASON_EXPLICIT; + _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", + pkgname, pkgver); trans->add = alpm_list_add(trans->add, pkg); return(0); +} + +static int perform_extraction(struct archive *archive, + struct archive_entry *entry, const char *filename, const char *origname) +{ + int ret; + const int archive_flags = ARCHIVE_EXTRACT_OWNER | + ARCHIVE_EXTRACT_PERM | + ARCHIVE_EXTRACT_TIME; -error: - _alpm_pkg_free(pkg); - return(-1); + archive_entry_set_pathname(entry, filename); + + ret = archive_read_extract(archive, entry, archive_flags); + if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) { + /* operation succeeded but a "non-critical" error was encountered */ + _alpm_log(PM_LOG_WARNING, _("warning given when extracting %s (%s)\n"), + origname, archive_error_string(archive)); + } else if(ret != ARCHIVE_OK) { + _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), + origname, archive_error_string(archive)); + alpm_logaction("error: could not extract %s (%s)\n", + origname, archive_error_string(archive)); + return(1); + } + return(0); } static int extract_single_file(struct archive *archive, @@ -120,9 +147,6 @@ static int extract_single_file(struct archive *archive, int needbackup = 0, notouch = 0; char *hash_orig = NULL; char *entryname_orig = NULL; - const int archive_flags = ARCHIVE_EXTRACT_OWNER | - ARCHIVE_EXTRACT_PERM | - ARCHIVE_EXTRACT_TIME; int errors = 0; entryname = archive_entry_pathname(entry); @@ -161,14 +185,6 @@ static int extract_single_file(struct archive *archive, return(0); } - /* if a file is in the add skiplist we never extract it */ - if(alpm_list_find_str(trans->skip_add, filename)) { - _alpm_log(PM_LOG_DEBUG, "%s is in trans->skip_add, skipping extraction\n", - entryname); - archive_read_data_skip(archive); - return(0); - } - /* Check for file existence. This is one of the more crucial parts * to get 'right'. Here are the possibilities, with the filesystem * on the left and the package on the top: @@ -277,18 +293,10 @@ static int extract_single_file(struct archive *archive, int ret; snprintf(checkfile, PATH_MAX, "%s.paccheck", filename); - archive_entry_set_pathname(entry, checkfile); - - ret = archive_read_extract(archive, entry, archive_flags); - if(ret == ARCHIVE_WARN) { - /* operation succeeded but a non-critical error was encountered */ - _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", - entryname_orig, archive_error_string(archive)); - } else if(ret != ARCHIVE_OK) { - _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), - entryname_orig, archive_error_string(archive)); - alpm_logaction("error: could not extract %s (%s)\n", - entryname_orig, archive_error_string(archive)); + + ret = perform_extraction(archive, entry, checkfile, entryname_orig); + if(ret == 1) { + /* error */ FREE(hash_orig); FREE(entryname_orig); return(1); @@ -430,18 +438,9 @@ static int extract_single_file(struct archive *archive, unlink(filename); } - archive_entry_set_pathname(entry, filename); - - ret = archive_read_extract(archive, entry, archive_flags); - if(ret == ARCHIVE_WARN) { - /* operation succeeded but a non-critical error was encountered */ - _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", - entryname_orig, archive_error_string(archive)); - } else if(ret != ARCHIVE_OK) { - _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), - entryname_orig, archive_error_string(archive)); - alpm_logaction("error: could not extract %s (%s)\n", - entryname_orig, archive_error_string(archive)); + ret = perform_extraction(archive, entry, filename, entryname_orig); + if(ret == 1) { + /* error */ FREE(entryname_orig); return(1); } @@ -473,8 +472,8 @@ static int extract_single_file(struct archive *archive, return(errors); } -static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, - pmtrans_t *trans, pmdb_t *db) +static int commit_single_pkg(pmpkg_t *newpkg, size_t pkg_current, + size_t pkg_count, pmtrans_t *trans, pmdb_t *db) { int i, ret = 0, errors = 0; char scriptlet[PATH_MAX+1]; @@ -498,7 +497,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, oldpkg = _alpm_pkg_dup(local); /* make sure all infos are loaded because the database entry * will be removed soon */ - _alpm_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL); + _alpm_local_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL); EVENT(trans, PM_TRANS_EVT_UPGRADE_START, newpkg, oldpkg); _alpm_log(PM_LOG_DEBUG, "upgrading package %s-%s\n", @@ -544,7 +543,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, /* prepare directory for database entries so permission are correct after changelog/install script installation (FS#12263) */ - if(_alpm_db_prepare(db, newpkg)) { + if(_alpm_local_db_prepare(db, newpkg)) { alpm_logaction("error: could not create database entry %s-%s\n", alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg)); pm_errno = PM_ERR_DB_WRITE; @@ -556,6 +555,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, struct archive *archive; struct archive_entry *entry; char cwd[PATH_MAX] = ""; + int restore_cwd = 0; _alpm_log(PM_LOG_DEBUG, "extracting files\n"); @@ -579,11 +579,16 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, /* save the cwd so we can restore it later */ if(getcwd(cwd, PATH_MAX) == NULL) { _alpm_log(PM_LOG_ERROR, _("could not get current working directory\n")); - cwd[0] = 0; + } else { + restore_cwd = 1; } /* libarchive requires this for extracting hard links */ - chdir(handle->root); + if(chdir(handle->root) != 0) { + _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno)); + ret = -1; + goto cleanup; + } /* call PROGRESS once with 0 percent, as we sort-of skip that here */ if(is_upgrade) { @@ -595,31 +600,31 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, } for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) { - double percent; + int percent; if(newpkg->size != 0) { /* Using compressed size for calculations here, as newpkg->isize is not * exact when it comes to comparing to the ACTUAL uncompressed size * (missing metadata sizes) */ int64_t pos = archive_position_compressed(archive); - percent = (double)pos / (double)newpkg->size; + percent = (pos * 100) / newpkg->size; _alpm_log(PM_LOG_DEBUG, "decompression progress: " - "%f%% (%"PRId64" / %jd)\n", - percent*100.0, pos, (intmax_t)newpkg->size); - if(percent >= 1.0) { - percent = 1.0; + "%d%% (%"PRId64" / %jd)\n", + percent, pos, (intmax_t)newpkg->size); + if(percent >= 100) { + percent = 100; } } else { - percent = 0.0; + percent = 0; } if(is_upgrade) { PROGRESS(trans, PM_TRANS_PROGRESS_UPGRADE_START, - alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count, + alpm_pkg_get_name(newpkg), percent, pkg_count, pkg_current); } else { PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START, - alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count, + alpm_pkg_get_name(newpkg), percent, pkg_count, pkg_current); } @@ -629,9 +634,9 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, } archive_read_finish(archive); - /* restore the old cwd is we have it */ - if(strlen(cwd)) { - chdir(cwd); + /* restore the old cwd if we have it */ + if(restore_cwd && chdir(cwd) != 0) { + _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno)); } if(errors) { @@ -656,7 +661,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, _alpm_log(PM_LOG_DEBUG, "updating database\n"); _alpm_log(PM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name); - if(_alpm_db_write(db, newpkg, INFRQ_ALL)) { + if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) { _alpm_log(PM_LOG_ERROR, _("could not update database entry %s-%s\n"), alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg)); alpm_logaction("error: could not update database entry %s-%s\n", @@ -705,7 +710,8 @@ cleanup: int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db) { - int pkg_count, pkg_current; + size_t pkg_count, pkg_current; + int skip_ldconfig = 0, ret = 0; alpm_list_t *targ; ALPM_LOG_FUNC; @@ -723,18 +729,28 @@ int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db) /* loop through our package list adding/upgrading one at a time */ for(targ = trans->add; targ; targ = targ->next) { if(handle->trans->state == STATE_INTERRUPTED) { - return(0); + return(ret); } pmpkg_t *newpkg = (pmpkg_t *)targ->data; - commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db); + if(commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db)) { + /* something screwed up on the commit, abort the trans */ + trans->state = STATE_INTERRUPTED; + pm_errno = PM_ERR_TRANS_ABORT; + /* running ldconfig at this point could possibly screw system */ + skip_ldconfig = 1; + ret = -1; + } + pkg_current++; } - /* run ldconfig if it exists */ - _alpm_ldconfig(handle->root); + if(!skip_ldconfig) { + /* run ldconfig if it exists */ + _alpm_ldconfig(handle->root); + } - return(0); + return(ret); } /* vim: set ts=2 sw=2 noet: */ |