diff options
Diffstat (limited to 'lib/libalpm/sync.c')
-rw-r--r-- | lib/libalpm/sync.c | 704 |
1 files changed, 271 insertions, 433 deletions
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index a927f61b..decd52b5 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -34,7 +34,6 @@ #include "sync.h" #include "alpm_list.h" #include "log.h" -#include "error.h" #include "package.h" #include "db.h" #include "cache.h" @@ -44,10 +43,10 @@ #include "util.h" #include "handle.h" #include "alpm.h" -#include "server.h" +#include "dload.h" #include "delta.h" -pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data) +pmsyncpkg_t *_alpm_sync_new(pmpkgreason_t newreason, pmpkg_t *spkg, alpm_list_t *removes) { pmsyncpkg_t *sync; @@ -55,9 +54,9 @@ pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data) CALLOC(sync, 1, sizeof(pmsyncpkg_t), RET_ERR(PM_ERR_MEMORY, NULL)); - sync->type = type; + sync->newreason = newreason; sync->pkg = spkg; - sync->data = data; + sync->removes = removes; return(sync); } @@ -70,32 +69,11 @@ void _alpm_sync_free(pmsyncpkg_t *sync) return; } - /* TODO wow this is ugly */ - if(sync->type == PM_SYNC_TYPE_REPLACE) { - alpm_list_free_inner(sync->data, (alpm_list_fn_free)_alpm_pkg_free); - alpm_list_free(sync->data); - sync->data = NULL; - } else { - _alpm_pkg_free(sync->data); - sync->data = NULL; - } + alpm_list_free(sync->removes); + sync->removes = NULL; FREE(sync); } -static void synclist_free(alpm_list_t *syncpkgs) -{ - if(syncpkgs) { - alpm_list_t *tmp; - for(tmp = syncpkgs; tmp; tmp = alpm_list_next(tmp)) { - if(tmp->data) { - _alpm_sync_free(tmp->data); - } - } - alpm_list_free(syncpkgs); - } - -} - /* Find recommended replacements for packages during a sync. */ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local, @@ -147,27 +125,29 @@ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local, * the package to replace. */ pmsyncpkg_t *sync; - pmpkg_t *dummy = _alpm_pkg_dup(lpkg); - if(dummy == NULL) { - pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); - return(-1); - } + /* check if spkg->name is already in the packages list. */ + /* TODO: same package name doesn't mean same package */ sync = _alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg)); if(sync) { - /* found it -- just append to the replaces list */ - sync->data = alpm_list_add(sync->data, dummy); + /* found it -- just append to the removes list */ + sync->removes = alpm_list_add(sync->removes, lpkg); + /* check the to-be-replaced package's reason field */ + if(lpkg->reason == PM_PKG_REASON_EXPLICIT) { + sync->newreason = PM_PKG_REASON_EXPLICIT; + } } else { /* none found -- enter pkg into the final sync list */ - sync = _alpm_sync_new(PM_SYNC_TYPE_REPLACE, spkg, NULL); + /* copy over reason */ + sync = _alpm_sync_new(alpm_pkg_get_reason(lpkg), spkg, NULL); if(sync == NULL) { - _alpm_pkg_free(dummy); pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); + alpm_list_free_inner(*syncpkgs, (alpm_list_fn_free)_alpm_sync_free); + alpm_list_free(*syncpkgs); + *syncpkgs = NULL; return(-1); } - sync->data = alpm_list_add(NULL, dummy); + sync->removes = alpm_list_add(NULL, lpkg); *syncpkgs = alpm_list_add(*syncpkgs, sync); } _alpm_log(PM_LOG_DEBUG, "%s-%s elected for removal (to be replaced by %s-%s)\n", @@ -180,6 +160,35 @@ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local, return(0); } +/** Check for new version of pkg in sync repos + * (only the first occurrence is considered in sync) + */ +pmpkg_t SYMEXPORT *alpm_sync_newversion(pmpkg_t *pkg, alpm_list_t *dbs_sync) +{ + alpm_list_t *i; + pmpkg_t *spkg = NULL; + + for(i = dbs_sync; !spkg && i; i = i->next) { + spkg = _alpm_db_get_pkgfromcache(i->data, alpm_pkg_get_name(pkg)); + } + + if(spkg == NULL) { + _alpm_log(PM_LOG_DEBUG, "'%s' not found in sync db => no upgrade\n", + alpm_pkg_get_name(pkg)); + return(NULL); + } + + /* compare versions and see if spkg is an upgrade */ + if(_alpm_pkg_compare_versions(pkg, spkg)) { + _alpm_log(PM_LOG_DEBUG, "new version of '%s' found (%s => %s)\n", + alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg), + alpm_pkg_get_version(spkg)); + return(spkg); + } else { + return(NULL); + } +} + /** Get a list of upgradable packages on the current system * Adds out of date packages to *list. * @arg list pointer to a list of pmsyncpkg_t. @@ -193,7 +202,7 @@ int SYMEXPORT alpm_sync_sysupgrade(pmdb_t *db_local, int _alpm_sync_sysupgrade(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync, alpm_list_t **syncpkgs) { - alpm_list_t *i, *j; + alpm_list_t *i, *j, *replaced = NULL; ALPM_LOG_FUNC; @@ -205,76 +214,61 @@ int _alpm_sync_sysupgrade(pmtrans_t *trans, return(-1); } - /* match installed packages with the sync dbs and compare versions */ + /* compute the to-be-replaced packages for efficiency */ + for(i = *syncpkgs; i; i = i->next) { + pmsyncpkg_t *sync = i->data; + for(j = sync->removes; j; j = j->next) { + replaced = alpm_list_add(replaced, j->data); + } + } + + /* for all not-replaced local package we check for upgrade */ _alpm_log(PM_LOG_DEBUG, "checking for package upgrades\n"); for(i = _alpm_db_get_pkgcache(db_local); i; i = i->next) { - int replace = 0; pmpkg_t *local = i->data; - pmpkg_t *spkg = NULL; - pmsyncpkg_t *sync; - for(j = dbs_sync; !spkg && j; j = j->next) { - spkg = _alpm_db_get_pkgfromcache(j->data, alpm_pkg_get_name(local)); - } - if(spkg == NULL) { - _alpm_log(PM_LOG_DEBUG, "'%s' not found in sync db -- skipping\n", - alpm_pkg_get_name(local)); - continue; - } - - /* we don't care about a to-be-replaced package's newer version */ - for(j = *syncpkgs; j && !replace; j=j->next) { - sync = j->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - if(_alpm_pkg_find(alpm_pkg_get_name(spkg), sync->data)) { - replace = 1; - } - } - } - if(replace) { + if(_alpm_pkg_find(alpm_pkg_get_name(local), replaced)) { _alpm_log(PM_LOG_DEBUG, "'%s' is already elected for removal -- skipping\n", alpm_pkg_get_name(local)); continue; } - /* compare versions and see if we need to upgrade */ - if(_alpm_pkg_compare_versions(local, spkg)) { - _alpm_log(PM_LOG_DEBUG, "%s elected for upgrade (%s => %s)\n", - alpm_pkg_get_name(local), alpm_pkg_get_version(local), - alpm_pkg_get_version(spkg)); - if(!_alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg))) { - /* If package is in the ignorepkg list, skip it */ - if(_alpm_pkg_should_ignore(spkg)) { - _alpm_log(PM_LOG_WARNING, _("%s: ignoring package upgrade (%s => %s)\n"), - alpm_pkg_get_name(local), alpm_pkg_get_version(local), - alpm_pkg_get_version(spkg)); - continue; - } + pmpkg_t *spkg = alpm_sync_newversion(local, dbs_sync); + if(spkg) { + /* we found a new version */ + /* skip packages in IgnorePkg or in IgnoreGroup */ + if(_alpm_pkg_should_ignore(spkg)) { + _alpm_log(PM_LOG_WARNING, _("%s: ignoring package upgrade (%s => %s)\n"), + alpm_pkg_get_name(local), alpm_pkg_get_version(local), + alpm_pkg_get_version(spkg)); + continue; + } - pmpkg_t *tmp = _alpm_pkg_dup(local); - if(tmp == NULL) { - pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); - return(-1); - } - sync = _alpm_sync_new(PM_SYNC_TYPE_UPGRADE, spkg, tmp); - if(sync == NULL) { - _alpm_pkg_free(tmp); - pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); - return(-1); - } - *syncpkgs = alpm_list_add(*syncpkgs, sync); + /* add the upgrade package to our pmsyncpkg_t list */ + if(_alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg))) { + /* avoid duplicated targets */ + continue; } + /* we can set any reason here, it will be overridden by add_commit */ + pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_EXPLICIT, spkg, NULL); + if(sync == NULL) { + alpm_list_free_inner(*syncpkgs, (alpm_list_fn_free)_alpm_sync_free); + alpm_list_free(*syncpkgs); + *syncpkgs = NULL; + alpm_list_free(replaced); + return(-1); + } + *syncpkgs = alpm_list_add(*syncpkgs, sync); } } + alpm_list_free(replaced); return(0); } int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync, char *name) { - char targline[PKG_FULLNAME_LEN]; + char *targline; char *targ; alpm_list_t *j; pmpkg_t *local; @@ -287,8 +281,8 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy ASSERT(db_local != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); ASSERT(name != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); + STRDUP(targline, name, RET_ERR(PM_ERR_MEMORY, -1)); - strncpy(targline, name, PKG_FULLNAME_LEN); targ = strchr(targline, '/'); if(targ) { /* we are looking for a package in a specific database */ @@ -301,13 +295,15 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy repo_found = 1; spkg = _alpm_db_get_pkgfromcache(db, targ); if(spkg == NULL) { - RET_ERR(PM_ERR_PKG_NOT_FOUND, -1); + pm_errno = PM_ERR_PKG_NOT_FOUND; + goto error; } } } if(!repo_found) { _alpm_log(PM_LOG_ERROR, _("repository '%s' not found\n"), targline); - RET_ERR(PM_ERR_PKG_REPO_NOT_FOUND, -1); + pm_errno = PM_ERR_PKG_REPO_NOT_FOUND; + goto error; } } else { targ = targline; @@ -316,10 +312,16 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy spkg = _alpm_db_get_pkgfromcache(db, targ); } if(spkg == NULL) { - RET_ERR(PM_ERR_PKG_NOT_FOUND, -1); + pm_errno = PM_ERR_PKG_NOT_FOUND; + goto error; } } + if(_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) { + FREE(targline); + RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1); + } + if(_alpm_pkg_should_ignore(spkg)) { int resp; QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, spkg, NULL, NULL, &resp); @@ -346,37 +348,34 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy } /* add the package to the transaction */ - if(!_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) { - pmpkg_t *dummy = NULL; - if(local) { - dummy = _alpm_pkg_dup(local); - if(dummy == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - } - sync = _alpm_sync_new(PM_SYNC_TYPE_UPGRADE, spkg, dummy); - if(sync == NULL) { - _alpm_pkg_free(dummy); - RET_ERR(PM_ERR_MEMORY, -1); - } - _alpm_log(PM_LOG_DEBUG, "adding target '%s' to the transaction set\n", - alpm_pkg_get_name(spkg)); - trans->packages = alpm_list_add(trans->packages, sync); + sync = _alpm_sync_new(PM_PKG_REASON_EXPLICIT, spkg, NULL); + if(sync == NULL) { + goto error; } + _alpm_log(PM_LOG_DEBUG, "adding target '%s' to the transaction set\n", + alpm_pkg_get_name(spkg)); + trans->packages = alpm_list_add(trans->packages, sync); + FREE(targline); return(0); + +error: + if(targline) { + FREE(targline); + } + return(-1); } /* Helper functions for alpm_list_remove - */ +*/ static int syncpkg_cmp(const void *s1, const void *s2) { const pmsyncpkg_t *sp1 = s1; const pmsyncpkg_t *sp2 = s2; pmpkg_t *p1, *p2; - p1 = alpm_sync_get_pkg(sp1); - p2 = alpm_sync_get_pkg(sp2); + p1 = alpm_sync_get_pkg(sp1); + p2 = alpm_sync_get_pkg(sp2); return(strcmp(alpm_pkg_get_name(p1), alpm_pkg_get_name(p2))); } @@ -397,14 +396,15 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync *data = NULL; } - if(!(trans->flags & PM_TRANS_FLAG_DEPENDSONLY)) { - for(i = trans->packages; i; i = i->next) { - pmsyncpkg_t *sync = i->data; - list = alpm_list_add(list, sync->pkg); - } + for(i = trans->packages; i; i = i->next) { + pmsyncpkg_t *sync = i->data; + list = alpm_list_add(list, sync->pkg); } if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) { + /* store a pointer to the last original target so we can tell what was + * pulled by resolvedeps */ + alpm_list_t *pulled = alpm_list_last(list); /* Resolve targets dependencies */ EVENT(trans, PM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL); _alpm_log(PM_LOG_DEBUG, "resolving target's dependencies\n"); @@ -412,10 +412,8 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync /* build remove list for resolvedeps */ for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - for(j = sync->data; j; j = j->next) { - remove = alpm_list_add(remove, j->data); - } + for(j = sync->removes; j; j = j->next) { + remove = alpm_list_add(remove, j->data); } } @@ -429,33 +427,27 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync } } - if((trans->flags & PM_TRANS_FLAG_DEPENDSONLY)) { - FREELIST(trans->packages); - } - - for(i = list; i; i = i->next) { - /* add the dependencies found by resolvedeps to the transaction set */ + for(i = pulled->next; i; i = i->next) { pmpkg_t *spkg = i->data; - if(!_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) { - pmsyncpkg_t *sync = _alpm_sync_new(PM_SYNC_TYPE_DEPEND, spkg, NULL); - if(sync == NULL) { - ret = -1; - goto cleanup; - } - trans->packages = alpm_list_add(trans->packages, sync); - _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", - alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg)); + pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_DEPEND, spkg, NULL); + if(sync == NULL) { + ret = -1; + goto cleanup; } + trans->packages = alpm_list_add(trans->packages, sync); + _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", + alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg)); } /* re-order w.r.t. dependencies */ - alpm_list_t *sortlist = _alpm_sortbydeps(list, PM_TRANS_TYPE_ADD); + alpm_list_t *sortlist = _alpm_sortbydeps(list, 0); alpm_list_t *newpkgs = NULL; for(i = sortlist; i; i = i->next) { for(j = trans->packages; j; j = j->next) { pmsyncpkg_t *s = j->data; if(s->pkg == i->data) { newpkgs = alpm_list_add(newpkgs, s); + break; } } } @@ -472,180 +464,126 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync EVENT(trans, PM_TRANS_EVT_INTERCONFLICTS_START, NULL, NULL); _alpm_log(PM_LOG_DEBUG, "looking for conflicts\n"); - deps = _alpm_checkconflicts(db_local, list); - if(deps) { - int errorout = 0; - alpm_list_t *asked = NULL; - pmconflict_t *conflict = NULL; - - for(i = deps; i && !errorout; i = i->next) { - pmsyncpkg_t *sync; - pmpkg_t *found = NULL; - - conflict = i->data; - _alpm_log(PM_LOG_DEBUG, "package '%s' conflicts with '%s'\n", - conflict->package1, conflict->package2); - /* check if the conflicting package is about to be removed/replaced. - * if so, then just ignore it. */ - for(j = trans->packages; j && !found; j = j->next) { - sync = j->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - found = _alpm_pkg_find(conflict->package2, sync->data); - } - } - if(found) { - _alpm_log(PM_LOG_DEBUG, "'%s' is already elected for removal -- skipping\n", - alpm_pkg_get_name(found)); - continue; - } - sync = _alpm_sync_find(trans->packages, conflict->package1); - if(sync == NULL) { - _alpm_log(PM_LOG_DEBUG, "'%s' not found in transaction set -- skipping\n", - conflict->package1); - continue; - } - pmpkg_t *local = _alpm_db_get_pkgfromcache(db_local, conflict->package2); - /* check if this package provides the package it's conflicting with */ - if(alpm_list_find(alpm_pkg_get_provides(sync->pkg), - conflict->package2, _alpm_prov_cmp)) { - /* treat like a replaces item so requiredby fields are - * inherited properly. */ - _alpm_log(PM_LOG_DEBUG, "package '%s' provides its own conflict\n", - conflict->package1); - if(!local) { - char *rmpkg = NULL; - void *target, *depend; - /* hmmm, package2 isn't installed, so it must be conflicting - * with another package in our final list. For example: - * - * pacman -S blackbox xfree86 - * - * If no x-servers are installed and blackbox pulls in xorg, then - * xorg and xfree86 will conflict with each other. In this case, - * we should follow the user's preference and rip xorg out of final, - * opting for xfree86 instead. - */ - - /* figure out which one was requested in targets. If they both - * were, then it's still an unresolvable conflict. */ - target = alpm_list_find_str(trans->targets, conflict->package1); - depend = alpm_list_find_str(trans->targets, conflict->package2); - if(depend && !target) { - _alpm_log(PM_LOG_DEBUG, "'%s' is in the target list -- keeping it\n", - conflict->package2); - /* remove conflict->package1 */ - rmpkg = conflict->package1; - } else if(target && !depend) { - _alpm_log(PM_LOG_DEBUG, "'%s' is in the target list -- keeping it\n", - conflict->package1); - /* remove conflict->package2 */ - rmpkg = conflict->package2; - } else { - /* miss->target2 is not needed, miss->target already provides - * it, let's resolve the conflict */ - rmpkg = conflict->package2; - } - if(rmpkg) { - pmsyncpkg_t *rsync = _alpm_sync_find(trans->packages, rmpkg); - if(rsync) { - void *vpkg; - _alpm_log(PM_LOG_DEBUG, "removing '%s' from target list\n", - rsync->pkg->name); - trans->packages = alpm_list_remove(trans->packages, rsync, - syncpkg_cmp, &vpkg); - _alpm_sync_free(vpkg); - } - continue; - } + /* 1. check for conflicts in the target list */ + _alpm_log(PM_LOG_DEBUG, "check targets vs targets\n"); + deps = _alpm_innerconflicts(list); + + for(i = deps; i; i = i->next) { + pmconflict_t *conflict = i->data; + pmsyncpkg_t *rsync, *sync, *sync1, *sync2; + + /* have we already removed one of the conflicting targets? */ + sync1 = _alpm_sync_find(trans->packages, conflict->package1); + sync2 = _alpm_sync_find(trans->packages, conflict->package2); + if(!sync1 || !sync2) { + continue; + } + + _alpm_log(PM_LOG_DEBUG, "conflicting packages in the sync list: '%s' <-> '%s'\n", + conflict->package1, conflict->package2); + + /* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */ + if(alpm_list_find(alpm_pkg_get_provides(sync1->pkg), + conflict->package2, _alpm_prov_cmp)) { + rsync = sync2; + sync = sync1; + } else if(alpm_list_find(alpm_pkg_get_provides(sync2->pkg), + conflict->package1, _alpm_prov_cmp)) { + rsync = sync1; + sync = sync2; + } else { + _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); + pm_errno = PM_ERR_CONFLICTING_DEPS; + ret = -1; + if(data) { + pmconflict_t *newconflict = _alpm_conflict_dup(conflict); + if(newconflict) { + *data = alpm_list_add(*data, newconflict); } } - /* It's a conflict -- see if they want to remove it */ - _alpm_log(PM_LOG_DEBUG, "resolving package '%s' conflict\n", - conflict->package1); - if(local) { - int doremove = 0; - if(!alpm_list_find_str(asked, conflict->package2)) { - QUESTION(trans, PM_TRANS_CONV_CONFLICT_PKG, conflict->package1, - conflict->package2, NULL, &doremove); - asked = alpm_list_add(asked, strdup(conflict->package2)); - if(doremove) { - pmpkg_t *q = _alpm_pkg_dup(local); - if(sync->type != PM_SYNC_TYPE_REPLACE) { - /* switch this sync type to REPLACE */ - sync->type = PM_SYNC_TYPE_REPLACE; - _alpm_pkg_free(sync->data); - sync->data = NULL; - } - /* append to the replaces list */ - _alpm_log(PM_LOG_DEBUG, "electing '%s' for removal\n", - conflict->package2); - sync->data = alpm_list_add(sync->data, q); - /* see if the package is in the current target list */ - pmsyncpkg_t *rsync = _alpm_sync_find(trans->packages, - conflict->package2); - if(rsync) { - /* remove it from the target list */ - void *vpkg; - _alpm_log(PM_LOG_DEBUG, "removing '%s' from target list\n", - conflict->package2); - trans->packages = alpm_list_remove(trans->packages, rsync, - syncpkg_cmp, &vpkg); - _alpm_sync_free(vpkg); - } - } else { - /* abort */ - _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); - errorout = 1; - } - } - } else { - _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); - errorout = 1; + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); + goto cleanup; + } + + /* Prints warning */ + _alpm_log(PM_LOG_WARNING, + _("removing '%s' from target list because it conflicts with '%s'\n"), + rsync->pkg->name, sync->pkg->name); + void *vpkg; + trans->packages = alpm_list_remove(trans->packages, rsync, + syncpkg_cmp, &vpkg); + pmsyncpkg_t *syncpkg = vpkg; + list = alpm_list_remove(list, syncpkg->pkg, _alpm_pkg_cmp, NULL); + _alpm_sync_free(syncpkg); + continue; + } + + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); + deps = NULL; + + /* 2. we check for target vs db conflicts (and resolve)*/ + _alpm_log(PM_LOG_DEBUG, "check targets vs db and db vs targets\n"); + deps = _alpm_outerconflicts(db_local, list); + + for(i = deps; i; i = i->next) { + pmconflict_t *conflict = i->data; + + /* if conflict->package2 (the local package) is not elected for removal, + we ask the user */ + int found = 0; + for(j = trans->packages; j && !found; j = j->next) { + pmsyncpkg_t *sync = j->data; + if(_alpm_pkg_find(conflict->package2, sync->removes)) { + found = 1; } } - if(errorout) { - /* The last conflict was unresolvable, so we duplicate it and add it to *data */ + if(found) { + continue; + } + + _alpm_log(PM_LOG_DEBUG, "package '%s' conflicts with '%s'\n", + conflict->package1, conflict->package2); + + pmsyncpkg_t *sync = _alpm_sync_find(trans->packages, conflict->package1); + pmpkg_t *local = _alpm_db_get_pkgfromcache(db_local, conflict->package2); + int doremove = 0; + QUESTION(trans, PM_TRANS_CONV_CONFLICT_PKG, conflict->package1, + conflict->package2, NULL, &doremove); + if(doremove) { + /* append to the removes list */ + _alpm_log(PM_LOG_DEBUG, "electing '%s' for removal\n", conflict->package2); + sync->removes = alpm_list_add(sync->removes, local); + } else { /* abort */ + _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); pm_errno = PM_ERR_CONFLICTING_DEPS; + ret = -1; if(data) { - pmconflict_t *lastconflict = conflict; - if((conflict = malloc(sizeof(pmconflict_t))) == NULL) { - _alpm_log(PM_LOG_ERROR, _("malloc failure: could not allocate %zd bytes\n"), - sizeof(pmconflict_t)); - FREELIST(*data); - pm_errno = PM_ERR_MEMORY; - } else { - *conflict = *lastconflict; - *data = alpm_list_add(*data, conflict); + pmconflict_t *newconflict = _alpm_conflict_dup(conflict); + if(newconflict) { + *data = alpm_list_add(*data, newconflict); } } - FREELIST(asked); - FREELIST(deps); - ret = -1; + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); goto cleanup; } - FREELIST(asked); - FREELIST(deps); } EVENT(trans, PM_TRANS_EVT_INTERCONFLICTS_DONE, NULL, NULL); + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); } if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) { - /* rebuild remove and list */ - alpm_list_free(list); - list = NULL; - for(i = trans->packages; i; i = i->next) { - pmsyncpkg_t *sync = i->data; - list = alpm_list_add(list, sync->pkg); - } + /* rebuild remove list */ alpm_list_free(remove); remove = NULL; for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - for(j = sync->data; j; j = j->next) { - remove = alpm_list_add(remove, j->data); - } + for(j = sync->removes; j; j = j->next) { + remove = alpm_list_add(remove, j->data); } } @@ -657,7 +595,8 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync if(data) { *data = deps; } else { - FREELIST(deps); + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(deps); } goto cleanup; } @@ -778,7 +717,7 @@ static int apply_deltas(pmtrans_t *trans, alpm_list_t *patches) pmpkg_t *pkg; pmdelta_t *d; char command[PATH_MAX], fname[PATH_MAX]; - char pkgfilename[PKG_FILENAME_LEN]; + char pkgfilename[PATH_MAX]; pkg = alpm_list_getdata(p); p = alpm_list_next(p); @@ -813,7 +752,7 @@ static int apply_deltas(pmtrans_t *trans, alpm_list_t *patches) _alpm_log(PM_LOG_DEBUG, _("command: %s\n"), command); - snprintf(pkgfilename, PKG_FILENAME_LEN, "%s-%s-%s" PKGEXT, + snprintf(pkgfilename, PATH_MAX, "%s-%s-%s" PKGEXT, pkg->name, d->to, pkg->arch); EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_START, pkgfilename, d->filename); @@ -854,107 +793,29 @@ static int apply_deltas(pmtrans_t *trans, alpm_list_t *patches) * @param trans the transaction * @param filename the filename of the file to test * @param md5sum the expected md5sum of the file - * @param data data to write the error messages to * - * @return 0 if the md5sum matched, 1 otherwise + * @return 0 if the md5sum matched, 1 if not, -1 in case of errors */ static int test_md5sum(pmtrans_t *trans, const char *filename, - const char *md5sum, alpm_list_t **data) + const char *md5sum) { char *filepath; - char *md5sum2; - char *errormsg = NULL; - int ret = 0; + int ret; filepath = _alpm_filecache_find(filename); - md5sum2 = alpm_get_md5sum(filepath); - if(md5sum == NULL) { - if(data) { - /* TODO wtf is this? malloc'd strings for error messages? */ - if((errormsg = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(errormsg, 512, _("can't get md5 checksum for file %s\n"), - filename); - *data = alpm_list_add(*data, errormsg); - } - ret = 1; - } else if(md5sum2 == NULL) { - if(data) { - if((errormsg = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(errormsg, 512, _("can't get md5 checksum for file %s\n"), - filename); - *data = alpm_list_add(*data, errormsg); - } - ret = 1; - } else if(strcmp(md5sum, md5sum2) != 0) { + ret = _alpm_test_md5sum(filepath, md5sum); + + if(ret == 1) { int doremove = 0; QUESTION(trans, PM_TRANS_CONV_CORRUPTED_PKG, (char *)filename, NULL, NULL, &doremove); if(doremove) { unlink(filepath); } - if(data) { - if((errormsg = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(errormsg, 512, _("file %s was corrupted (bad MD5 checksum)\n"), - filename); - *data = alpm_list_add(*data, errormsg); - } - ret = 1; } FREE(filepath); - FREE(md5sum2); - - return(ret); -} - -/** Compares the md5sum of a delta to the expected value. - * - * @param trans the transaction - * @param delta the delta to test - * @param data data to write the error messages to - * - * @return 0 if the md5sum matched, 1 otherwise - */ -static int test_delta_md5sum(pmtrans_t *trans, pmdelta_t *delta, - alpm_list_t **data) -{ - const char *filename; - const char *md5sum; - int ret = 0; - - filename = alpm_delta_get_filename(delta); - md5sum = alpm_delta_get_md5sum(delta); - - ret = test_md5sum(trans, filename, md5sum, data); - - return(ret); -} - -/** Compares the md5sum of a package to the expected value. - * - * @param trans the transaction - * @param pkg the package to test - * @param data data to write the error messages to - * - * @return 0 if the md5sum matched, 1 otherwise - */ -static int test_pkg_md5sum(pmtrans_t *trans, pmpkg_t *pkg, alpm_list_t **data) -{ - const char *filename; - const char *md5sum; - int ret = 0; - - filename = alpm_pkg_get_filename(pkg); - md5sum = alpm_pkg_get_md5sum(pkg); - - ret = test_md5sum(trans, filename, md5sum, data); return(ret); } @@ -964,9 +825,9 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) alpm_list_t *i, *j, *files = NULL; alpm_list_t *patches = NULL, *deltas = NULL; pmtrans_t *tr = NULL; - int replaces = 0, retval = 0; + int replaces = 0; + int errors = 0; const char *cachedir = NULL; - int dltotal = 0, dl = 0; ALPM_LOG_FUNC; @@ -976,14 +837,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) cachedir = _alpm_filecache_setup(); trans->state = STATE_DOWNLOADING; - /* Sum up the download sizes. This has to be in its own loop because - * the download loop is grouped by db. */ - for(j = trans->packages; j; j = j->next) { - pmsyncpkg_t *sync = j->data; - pmpkg_t *spkg = sync->pkg; - dltotal += alpm_pkg_download_size(spkg, db_local); - } - /* group sync records by repository and download */ for(i = handle->dbs_sync; i; i = i->next) { pmdb_t *current = i->data; @@ -1047,7 +900,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) if(files) { EVENT(trans, PM_TRANS_EVT_RETRIEVE_START, current->treename, NULL); - if(_alpm_downloadfiles(current->servers, cachedir, files, &dl, dltotal)) { + if(_alpm_download_files(files, current->servers, cachedir)) { _alpm_log(PM_LOG_WARNING, _("failed to retrieve some files from %s\n"), current->treename); RET_ERR(PM_ERR_RETRIEVE, -1); @@ -1064,22 +917,22 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) /* only output if there are deltas to work with */ if(deltas) { + errors = 0; /* Check integrity of deltas */ EVENT(trans, PM_TRANS_EVT_DELTA_INTEGRITY_START, NULL, NULL); for(i = deltas; i; i = i->next) { pmdelta_t *d = alpm_list_getdata(i); + const char *filename = alpm_delta_get_filename(d); + const char *md5sum = alpm_delta_get_md5sum(d); - ret = test_delta_md5sum(trans, d, data); - - if(ret == 1) { - retval = 1; - } else if(ret == -1) { /* -1 is for serious errors */ - RET_ERR(pm_errno, -1); + if(test_md5sum(trans, filename, md5sum) != 0) { + errors++; + *data = alpm_list_add(*data, strdup(filename)); } } - if(retval) { - pm_errno = PM_ERR_DLT_CORRUPTED; + if(errors) { + pm_errno = PM_ERR_DLT_INVALID; goto error; } EVENT(trans, PM_TRANS_EVT_DELTA_INTEGRITY_DONE, NULL, NULL); @@ -1103,21 +956,20 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) /* Check integrity of packages */ EVENT(trans, PM_TRANS_EVT_INTEGRITY_START, NULL, NULL); + errors = 0; for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; pmpkg_t *spkg = sync->pkg; - int ret = 0; - - ret = test_pkg_md5sum(trans, spkg, data); + const char *filename = alpm_pkg_get_filename(spkg); + const char *md5sum = alpm_pkg_get_md5sum(spkg); - if(ret == 1) { - retval = 1; - } else if(ret == -1) { /* -1 is for serious errors */ - RET_ERR(pm_errno, -1); + if(test_md5sum(trans, filename, md5sum) != 0) { + errors++; + *data = alpm_list_add(*data, strdup(filename)); } } - if(retval) { - pm_errno = PM_ERR_PKG_CORRUPTED; + if(errors) { + pm_errno = PM_ERR_PKG_INVALID; goto error; } EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL); @@ -1130,7 +982,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) tr = _alpm_trans_new(); if(tr == NULL) { _alpm_log(PM_LOG_ERROR, _("could not create removal transaction\n")); - pm_errno = PM_ERR_MEMORY; goto error; } @@ -1141,16 +992,14 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - alpm_list_t *j; - for(j = sync->data; j; j = j->next) { - pmpkg_t *pkg = j->data; - if(!_alpm_pkg_find(pkg->name, tr->packages)) { - if(_alpm_trans_addtarget(tr, pkg->name) == -1) { - goto error; - } - replaces++; + alpm_list_t *j; + for(j = sync->removes; j; j = j->next) { + pmpkg_t *pkg = j->data; + if(!_alpm_pkg_find(pkg->name, tr->packages)) { + if(_alpm_trans_addtarget(tr, pkg->name) == -1) { + goto error; } + replaces++; } } } @@ -1175,7 +1024,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) tr = _alpm_trans_new(); if(tr == NULL) { _alpm_log(PM_LOG_ERROR, _("could not create transaction\n")); - pm_errno = PM_ERR_MEMORY; goto error; } if(_alpm_trans_init(tr, PM_TRANS_TYPE_UPGRADE, trans->flags | PM_TRANS_FLAG_NODEPS, trans->cb_event, trans->cb_conv, trans->cb_progress) == -1) { @@ -1201,9 +1049,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) /* using alpm_list_last() is ok because addtarget() adds the new target at the * end of the tr->packages list */ spkg = alpm_list_last(tr->packages)->data; - if(sync->type == PM_SYNC_TYPE_DEPEND) { - spkg->reason = PM_PKG_REASON_DEPEND; - } + spkg->reason = sync->newreason; } if(_alpm_trans_prepare(tr, data) == -1) { _alpm_log(PM_LOG_ERROR, _("could not prepare transaction\n")); @@ -1246,14 +1092,6 @@ pmsyncpkg_t *_alpm_sync_find(alpm_list_t *syncpkgs, const char* pkgname) return(NULL); /* not found */ } -pmsynctype_t SYMEXPORT alpm_sync_get_type(const pmsyncpkg_t *sync) -{ - /* Sanity checks */ - ASSERT(sync != NULL, return(-1)); - - return sync->type; -} - pmpkg_t SYMEXPORT *alpm_sync_get_pkg(const pmsyncpkg_t *sync) { /* Sanity checks */ @@ -1262,12 +1100,12 @@ pmpkg_t SYMEXPORT *alpm_sync_get_pkg(const pmsyncpkg_t *sync) return sync->pkg; } -void SYMEXPORT *alpm_sync_get_data(const pmsyncpkg_t *sync) +alpm_list_t SYMEXPORT *alpm_sync_get_removes(const pmsyncpkg_t *sync) { /* Sanity checks */ ASSERT(sync != NULL, return(NULL)); - return sync->data; + return sync->removes; } /* vim: set ts=2 sw=2 noet: */ |