/** Check for new version of pkg in sync repos * (only the first occurrence is considered in sync) */ alpm_pkg_t SYMEXPORT *alpm_sync_newversion(alpm_pkg_t *pkg, alpm_list_t *dbs_sync) { alpm_list_t *i; alpm_pkg_t *spkg = NULL; ASSERT(pkg != NULL, return NULL); pkg->handle->pm_errno = 0; for(i = dbs_sync; !spkg && i; i = i->next) { alpm_db_t *db = i->data; if(!(db->usage & ALPM_DB_USAGE_SEARCH)) { continue; } spkg = _alpm_db_get_pkgfromcache(db, pkg->name); } if(spkg == NULL) { _alpm_log(pkg->handle, ALPM_LOG_DEBUG, "'%s' not found in sync db => no upgrade\n", pkg->name); return NULL; } /* compare versions and see if spkg is an upgrade */ if(_alpm_pkg_compare_versions(spkg, pkg) > 0) { _alpm_log(pkg->handle, ALPM_LOG_DEBUG, "new version of '%s' found (%s => %s)\n", pkg->name, pkg->version, spkg->version); return spkg; } /* spkg is not an upgrade */ return NULL; }
/** Check for new version of pkg in sync repos * (only the first occurrence is considered in sync) */ alpm_pkg_t SYMEXPORT *alpm_sync_newversion(alpm_pkg_t *pkg, alpm_list_t *dbs_sync) { alpm_list_t *i; alpm_pkg_t *spkg = NULL; ASSERT(pkg != NULL, return NULL); pkg->handle->pm_errno = 0; 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(pkg->handle, ALPM_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(spkg, pkg) > 0) { _alpm_log(pkg->handle, ALPM_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; } /* spkg is not an upgrade */ return NULL; }
/** * @brief Add dependencies to the removal transaction for cascading. * * @param handle the context handle * @param lp list of missing dependencies caused by the removal transaction * * @return 0 on success, -1 on error */ static int remove_prepare_cascade(alpm_handle_t *handle, alpm_list_t *lp) { alpm_trans_t *trans = handle->trans; while(lp) { alpm_list_t *i; for(i = lp; i; i = i->next) { alpm_depmissing_t *miss = i->data; alpm_pkg_t *info = _alpm_db_get_pkgfromcache(handle->db_local, miss->target); if(info) { alpm_pkg_t *copy; if(!alpm_pkg_find(trans->remove, info->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "pulling %s in target list\n", info->name); if(_alpm_pkg_dup(info, ©) == -1) { return -1; } trans->remove = alpm_list_add(trans->remove, copy); } } else { _alpm_log(handle, ALPM_LOG_ERROR, _("could not find %s in database -- skipping\n"), miss->target); } } alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(lp); lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), trans->remove, NULL, 1); } return 0; }
/** Add a package to the transaction. */ int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) { const char *pkgname, *pkgver; alpm_trans_t *trans; alpm_pkg_t *local; /* Sanity checks */ CHECK_HANDLE(handle, return -1); ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); ASSERT(pkg->origin != ALPM_PKG_FROM_LOCALDB, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); ASSERT(handle == pkg->handle, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); pkgname = pkg->name; pkgver = pkg->version; _alpm_log(handle, ALPM_LOG_DEBUG, "adding package '%s'\n", pkgname); if(alpm_pkg_find(trans->add, pkgname)) { RET_ERR(handle, ALPM_ERR_TRANS_DUP_TARGET, -1); } local = _alpm_db_get_pkgfromcache(handle->db_local, pkgname); if(local) { const char *localpkgname = local->name; const char *localpkgver = local->version; int cmp = _alpm_pkg_compare_versions(pkg, local); if(cmp == 0) { if(trans->flags & ALPM_TRANS_FLAG_NEEDED) { /* with the NEEDED flag, packages up to date are not reinstalled */ _alpm_log(handle, ALPM_LOG_WARNING, _("%s-%s is up to date -- skipping\n"), localpkgname, localpkgver); return 0; } else if(!(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY)) { _alpm_log(handle, ALPM_LOG_WARNING, _("%s-%s is up to date -- reinstalling\n"), localpkgname, localpkgver); } } else if(cmp < 0 && !(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY)) { /* local version is newer */ _alpm_log(handle, ALPM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"), localpkgname, localpkgver, pkgver); } } /* add the package to the transaction */ pkg->reason = ALPM_PKG_REASON_EXPLICIT; _alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction add list\n", pkgname, pkgver); trans->add = alpm_list_add(trans->add, pkg); return 0; }
/** Search for packages to upgrade and add them to the transaction. */ int SYMEXPORT alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade) { alpm_list_t *i, *j; alpm_trans_t *trans; CHECK_HANDLE(handle, return -1); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); _alpm_log(handle, ALPM_LOG_DEBUG, "checking for package upgrades\n"); for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) { alpm_pkg_t *lpkg = i->data; if(alpm_pkg_find(trans->add, lpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is already in the target list -- skipping\n", lpkg->name); continue; } /* Search for literal then replacers in each sync database. */ for(j = handle->dbs_sync; j; j = j->next) { alpm_db_t *sdb = j->data; /* Check sdb */ alpm_pkg_t *spkg = _alpm_db_get_pkgfromcache(sdb, lpkg->name); int literal_upgrade = 0; if(spkg) { literal_upgrade = check_literal(handle, lpkg, spkg, enable_downgrade); if(literal_upgrade) { trans->add = alpm_list_add(trans->add, spkg); } /* jump to next local package */ break; } else { alpm_list_t *replacers; replacers = check_replacers(handle, lpkg, sdb); if(replacers) { trans->add = alpm_list_join(trans->add, replacers); } } } } return 0; }
static alpm_list_t *check_replacers(alpm_handle_t *handle, alpm_pkg_t *lpkg, alpm_db_t *sdb) { /* 2. search for replacers in sdb */ alpm_list_t *replacers = NULL; alpm_list_t *k; _alpm_log(handle, ALPM_LOG_DEBUG, "searching for replacements for %s in %s\n", lpkg->name, sdb->treename); for(k = _alpm_db_get_pkgcache(sdb); k; k = k->next) { int found = 0; alpm_pkg_t *spkg = k->data; alpm_list_t *l; for(l = alpm_pkg_get_replaces(spkg); l; l = l->next) { alpm_depend_t *replace = l->data; /* we only want to consider literal matches at this point. */ if(_alpm_depcmp_literal(lpkg, replace)) { found = 1; break; } } if(found) { alpm_question_replace_t question = { .type = ALPM_QUESTION_REPLACE_PKG, .replace = 0, .oldpkg = lpkg, .newpkg = spkg, .newdb = sdb }; alpm_pkg_t *tpkg; /* check IgnorePkg/IgnoreGroup */ if(alpm_pkg_should_ignore(handle, spkg) || alpm_pkg_should_ignore(handle, lpkg)) { _alpm_log(handle, ALPM_LOG_WARNING, _("ignoring package replacement (%s-%s => %s-%s)\n"), lpkg->name, lpkg->version, spkg->name, spkg->version); continue; } QUESTION(handle, &question); if(!question.replace) { continue; } /* If spkg is already in the target list, we append lpkg to spkg's * removes list */ tpkg = alpm_pkg_find(handle->trans->add, spkg->name); if(tpkg) { /* sanity check, multiple repos can contain spkg->name */ if(tpkg->origin_data.db != sdb) { _alpm_log(handle, ALPM_LOG_WARNING, _("cannot replace %s by %s\n"), lpkg->name, spkg->name); continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "appending %s to the removes list of %s\n", lpkg->name, tpkg->name); tpkg->removes = alpm_list_add(tpkg->removes, lpkg); /* check the to-be-replaced package's reason field */ if(alpm_pkg_get_reason(lpkg) == ALPM_PKG_REASON_EXPLICIT) { tpkg->reason = ALPM_PKG_REASON_EXPLICIT; } } else { /* add spkg to the target list */ /* copy over reason */ spkg->reason = alpm_pkg_get_reason(lpkg); spkg->removes = alpm_list_add(NULL, lpkg); _alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", spkg->name, spkg->version); replacers = alpm_list_add(replacers, spkg); } } } return replacers; } /** Search for packages to upgrade and add them to the transaction. */ int SYMEXPORT alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade) { alpm_list_t *i, *j; alpm_trans_t *trans; CHECK_HANDLE(handle, return -1); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); _alpm_log(handle, ALPM_LOG_DEBUG, "checking for package upgrades\n"); for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) { alpm_pkg_t *lpkg = i->data; if(alpm_pkg_find(trans->remove, lpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is marked for removal -- skipping\n", lpkg->name); continue; } if(alpm_pkg_find(trans->add, lpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is already in the target list -- skipping\n", lpkg->name); continue; } /* Search for replacers then literal (if no replacer) in each sync database. */ for(j = handle->dbs_sync; j; j = j->next) { alpm_db_t *sdb = j->data; alpm_list_t *replacers; if(!(sdb->usage & ALPM_DB_USAGE_UPGRADE)) { continue; } /* Check sdb */ replacers = check_replacers(handle, lpkg, sdb); if(replacers) { trans->add = alpm_list_join(trans->add, replacers); /* jump to next local package */ break; } else { alpm_pkg_t *spkg = _alpm_db_get_pkgfromcache(sdb, lpkg->name); if(spkg) { if(check_literal(handle, lpkg, spkg, enable_downgrade)) { trans->add = alpm_list_add(trans->add, spkg); } /* jump to next local package */ break; } } } } return 0; }
/** * helper function for resolvedeps: search for dep satisfier in dbs * * @param handle the context handle * @param dep is the dependency to search for * @param dbs are the databases to search * @param excluding are the packages to exclude from the search * @param prompt if true, will cause an unresolvable dependency to issue an * interactive prompt asking whether the package should be removed from * the transaction or the transaction aborted; if false, simply returns * an error code without prompting * @return the resolved package **/ static pmpkg_t *resolvedep(pmhandle_t *handle, pmdepend_t *dep, alpm_list_t *dbs, alpm_list_t *excluding, int prompt) { alpm_list_t *i, *j; int ignored = 0; alpm_list_t *providers = NULL; int count; /* 1. literals */ for(i = dbs; i; i = i->next) { pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name); if(pkg && _alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) { if(_alpm_pkg_should_ignore(handle, pkg)) { int install = 0; if(prompt) { QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, pkg, NULL, NULL, &install); } else { _alpm_log(handle, PM_LOG_WARNING, _("ignoring package %s-%s\n"), pkg->name, pkg->version); } if(!install) { ignored = 1; continue; } } return pkg; } } /* 2. satisfiers (skip literals here) */ for(i = dbs; i; i = i->next) { for(j = _alpm_db_get_pkgcache(i->data); j; j = j->next) { pmpkg_t *pkg = j->data; if(_alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) != 0 && !_alpm_pkg_find(excluding, pkg->name)) { if(_alpm_pkg_should_ignore(handle, pkg)) { int install = 0; if(prompt) { QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, pkg, NULL, NULL, &install); } else { _alpm_log(handle, PM_LOG_WARNING, _("ignoring package %s-%s\n"), pkg->name, pkg->version); } if(!install) { ignored = 1; continue; } } _alpm_log(handle, PM_LOG_DEBUG, "provider found (%s provides %s)\n", pkg->name, dep->name); providers = alpm_list_add(providers, pkg); /* keep looking for other providers in the all dbs */ } } } /* first check if one provider is already installed locally */ for(i = providers; i; i = i->next) { pmpkg_t *pkg = i->data; if(_alpm_pkghash_find(_alpm_db_get_pkgcache_hash(handle->db_local), pkg->name)) { alpm_list_free(providers); return pkg; } } count = alpm_list_count(providers); if(count >= 1) { /* default to first provider if there is no QUESTION callback */ int index = 0; if(count > 1) { /* if there is more than one provider, we ask the user */ QUESTION(handle->trans, PM_TRANS_CONV_SELECT_PROVIDER, providers, dep, NULL, &index); } if(index >= 0 && index < count) { pmpkg_t *pkg = alpm_list_getdata(alpm_list_nth(providers, index)); alpm_list_free(providers); return pkg; } alpm_list_free(providers); providers = NULL; } if(ignored) { /* resolvedeps will override these */ handle->pm_errno = PM_ERR_PKG_IGNORED; } else { handle->pm_errno = PM_ERR_PKG_NOT_FOUND; } return NULL; }
/** Search for packages to upgrade and add them to the transaction. */ int SYMEXPORT alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade) { alpm_list_t *i, *j, *k; alpm_trans_t *trans; alpm_db_t *db_local; alpm_list_t *dbs_sync; CHECK_HANDLE(handle, return -1); trans = handle->trans; db_local = handle->db_local; dbs_sync = handle->dbs_sync; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); _alpm_log(handle, ALPM_LOG_DEBUG, "checking for package upgrades\n"); for(i = _alpm_db_get_pkgcache(db_local); i; i = i->next) { alpm_pkg_t *lpkg = i->data; if(_alpm_pkg_find(trans->add, lpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is already in the target list -- skipping\n", lpkg->name); continue; } /* Search for literal then replacers in each sync database. * If found, don't check other databases */ for(j = dbs_sync; j; j = j->next) { alpm_db_t *sdb = j->data; /* Check sdb */ alpm_pkg_t *spkg = _alpm_db_get_pkgfromcache(sdb, lpkg->name); if(spkg) { /* 1. literal was found in sdb */ int cmp = _alpm_pkg_compare_versions(spkg, lpkg); if(cmp > 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "new version of '%s' found (%s => %s)\n", lpkg->name, lpkg->version, spkg->version); /* check IgnorePkg/IgnoreGroup */ if(_alpm_pkg_should_ignore(handle, spkg) || _alpm_pkg_should_ignore(handle, lpkg)) { _alpm_log(handle, ALPM_LOG_WARNING, _("%s: ignoring package upgrade (%s => %s)\n"), lpkg->name, lpkg->version, spkg->version); } else { _alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", spkg->name, spkg->version); trans->add = alpm_list_add(trans->add, spkg); } } else if(cmp < 0) { if(enable_downgrade) { /* check IgnorePkg/IgnoreGroup */ if(_alpm_pkg_should_ignore(handle, spkg) || _alpm_pkg_should_ignore(handle, lpkg)) { _alpm_log(handle, ALPM_LOG_WARNING, _("%s: ignoring package downgrade (%s => %s)\n"), lpkg->name, lpkg->version, spkg->version); } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s: downgrading from version %s to version %s\n"), lpkg->name, lpkg->version, spkg->version); trans->add = alpm_list_add(trans->add, spkg); } } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s: local (%s) is newer than %s (%s)\n"), lpkg->name, lpkg->version, sdb->treename, spkg->version); } } /* jump to next local package */ break; } else { /* 2. search for replacers in sdb */ int found = 0; for(k = _alpm_db_get_pkgcache(sdb); k; k = k->next) { spkg = k->data; if(alpm_list_find_str(alpm_pkg_get_replaces(spkg), lpkg->name)) { found = 1; /* check IgnorePkg/IgnoreGroup */ if(_alpm_pkg_should_ignore(handle, spkg) || _alpm_pkg_should_ignore(handle, lpkg)) { _alpm_log(handle, ALPM_LOG_WARNING, _("ignoring package replacement (%s-%s => %s-%s)\n"), lpkg->name, lpkg->version, spkg->name, spkg->version); continue; } int doreplace = 0; QUESTION(trans, ALPM_TRANS_CONV_REPLACE_PKG, lpkg, spkg, sdb->treename, &doreplace); if(!doreplace) { continue; } /* If spkg is already in the target list, we append lpkg to spkg's * removes list */ alpm_pkg_t *tpkg = _alpm_pkg_find(trans->add, spkg->name); if(tpkg) { /* sanity check, multiple repos can contain spkg->name */ if(tpkg->origin_data.db != sdb) { _alpm_log(handle, ALPM_LOG_WARNING, _("cannot replace %s by %s\n"), lpkg->name, spkg->name); continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "appending %s to the removes list of %s\n", lpkg->name, tpkg->name); tpkg->removes = alpm_list_add(tpkg->removes, lpkg); /* check the to-be-replaced package's reason field */ if(alpm_pkg_get_reason(lpkg) == ALPM_PKG_REASON_EXPLICIT) { tpkg->reason = ALPM_PKG_REASON_EXPLICIT; } } else { /* add spkg to the target list */ /* copy over reason */ spkg->reason = alpm_pkg_get_reason(lpkg); spkg->removes = alpm_list_add(NULL, lpkg); _alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", spkg->name, spkg->version); trans->add = alpm_list_add(trans->add, spkg); } } } if(found) { break; /* jump to next local package */ } } } } return 0; }
int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) { alpm_list_t *i, *j; alpm_list_t *deps = NULL; alpm_list_t *unresolvable = NULL; alpm_list_t *remove = NULL; int ret = 0; alpm_trans_t *trans = handle->trans; if(data) { *data = NULL; } /* ensure all sync database are valid since we will be using them */ for(i = handle->dbs_sync; i; i = i->next) { const alpm_db_t *db = i->data; if(!(db->status & DB_STATUS_VALID)) { RET_ERR(handle, ALPM_ERR_DB_INVALID, -1); } } if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { alpm_list_t *resolved = NULL; /* target list after resolvedeps */ /* Build up list by repeatedly resolving each transaction package */ /* Resolve targets dependencies */ EVENT(trans, ALPM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "resolving target's dependencies\n"); /* build remove list for resolvedeps */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; for(j = spkg->removes; j; j = j->next) { remove = alpm_list_add(remove, j->data); } } /* Compute the fake local database for resolvedeps (partial fix for the * phonon/qt issue) */ alpm_list_t *localpkgs = alpm_list_diff(_alpm_db_get_pkgcache(handle->db_local), trans->add, _alpm_pkg_cmp); /* Resolve packages in the transaction one at a time, in addition building up a list of packages which could not be resolved. */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *pkg = i->data; if(_alpm_resolvedeps(handle, localpkgs, pkg, trans->add, &resolved, remove, data) == -1) { unresolvable = alpm_list_add(unresolvable, pkg); } /* Else, [resolved] now additionally contains [pkg] and all of its dependencies not already on the list */ } alpm_list_free(localpkgs); /* If there were unresolvable top-level packages, prompt the user to see if they'd like to ignore them rather than failing the sync */ if(unresolvable != NULL) { int remove_unresolvable = 0; QUESTION(trans, ALPM_TRANS_CONV_REMOVE_PKGS, unresolvable, NULL, NULL, &remove_unresolvable); if(remove_unresolvable) { /* User wants to remove the unresolvable packages from the transaction. The packages will be removed from the actual transaction when the transaction packages are replaced with a dependency-reordered list below */ handle->pm_errno = 0; /* pm_errno was set by resolvedeps */ if(data) { alpm_list_free_inner(*data, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(*data); *data = NULL; } } else { /* pm_errno is set by resolvedeps */ alpm_list_free(resolved); ret = -1; goto cleanup; } } /* Set DEPEND reason for pulled packages */ for(i = resolved; i; i = i->next) { alpm_pkg_t *pkg = i->data; if(!_alpm_pkg_find(trans->add, pkg->name)) { pkg->reason = ALPM_PKG_REASON_DEPEND; } } /* Unresolvable packages will be removed from the target list, so we free the transaction specific fields */ alpm_list_free_inner(unresolvable, (alpm_list_fn_free)_alpm_pkg_free_trans); /* re-order w.r.t. dependencies */ alpm_list_free(trans->add); trans->add = _alpm_sortbydeps(handle, resolved, 0); alpm_list_free(resolved); EVENT(trans, ALPM_TRANS_EVT_RESOLVEDEPS_DONE, NULL, NULL); } if(!(trans->flags & ALPM_TRANS_FLAG_NOCONFLICTS)) { /* check for inter-conflicts and whatnot */ EVENT(trans, ALPM_TRANS_EVT_INTERCONFLICTS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "looking for conflicts\n"); /* 1. check for conflicts in the target list */ _alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs targets\n"); deps = _alpm_innerconflicts(handle, trans->add); for(i = deps; i; i = i->next) { alpm_conflict_t *conflict = i->data; alpm_pkg_t *rsync, *sync, *sync1, *sync2; /* have we already removed one of the conflicting targets? */ sync1 = _alpm_pkg_find(trans->add, conflict->package1); sync2 = _alpm_pkg_find(trans->add, conflict->package2); if(!sync1 || !sync2) { continue; } _alpm_log(handle, ALPM_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 */ alpm_depend_t *dep1 = _alpm_splitdep(conflict->package1); alpm_depend_t *dep2 = _alpm_splitdep(conflict->package2); if(_alpm_depcmp(sync1, dep2)) { rsync = sync2; sync = sync1; } else if(_alpm_depcmp(sync2, dep1)) { rsync = sync1; sync = sync2; } else { _alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n")); handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS; ret = -1; if(data) { alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict); if(newconflict) { *data = alpm_list_add(*data, newconflict); } } alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); alpm_list_free(deps); _alpm_dep_free(dep1); _alpm_dep_free(dep2); goto cleanup; } _alpm_dep_free(dep1); _alpm_dep_free(dep2); /* Prints warning */ _alpm_log(handle, ALPM_LOG_WARNING, _("removing '%s' from target list because it conflicts with '%s'\n"), rsync->name, sync->name); trans->add = alpm_list_remove(trans->add, rsync, _alpm_pkg_cmp, NULL); _alpm_pkg_free_trans(rsync); /* rsync is not transaction target anymore */ 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(handle, ALPM_LOG_DEBUG, "check targets vs db and db vs targets\n"); deps = _alpm_outerconflicts(handle->db_local, trans->add); for(i = deps; i; i = i->next) { alpm_conflict_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->add; j && !found; j = j->next) { alpm_pkg_t *spkg = j->data; if(_alpm_pkg_find(spkg->removes, conflict->package2)) { found = 1; } } if(found) { continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "package '%s' conflicts with '%s'\n", conflict->package1, conflict->package2); alpm_pkg_t *sync = _alpm_pkg_find(trans->add, conflict->package1); alpm_pkg_t *local = _alpm_db_get_pkgfromcache(handle->db_local, conflict->package2); int doremove = 0; QUESTION(trans, ALPM_TRANS_CONV_CONFLICT_PKG, conflict->package1, conflict->package2, conflict->reason, &doremove); if(doremove) { /* append to the removes list */ _alpm_log(handle, ALPM_LOG_DEBUG, "electing '%s' for removal\n", conflict->package2); sync->removes = alpm_list_add(sync->removes, local); } else { /* abort */ _alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n")); handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS; ret = -1; if(data) { alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict); if(newconflict) { *data = alpm_list_add(*data, newconflict); } } alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); alpm_list_free(deps); goto cleanup; } } EVENT(trans, ALPM_TRANS_EVT_INTERCONFLICTS_DONE, NULL, NULL); alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); alpm_list_free(deps); } /* Build trans->remove list */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; for(j = spkg->removes; j; j = j->next) { alpm_pkg_t *rpkg = j->data; if(!_alpm_pkg_find(trans->remove, rpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "adding '%s' to remove list\n", rpkg->name); trans->remove = alpm_list_add(trans->remove, _alpm_pkg_dup(rpkg)); } } } if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { _alpm_log(handle, ALPM_LOG_DEBUG, "checking dependencies\n"); deps = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), trans->remove, trans->add, 1); if(deps) { handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS; ret = -1; if(data) { *data = deps; } else { alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(deps); } goto cleanup; } } for(i = trans->add; i; i = i->next) { /* update download size field */ alpm_pkg_t *spkg = i->data; if(compute_download_size(spkg) != 0) { ret = -1; goto cleanup; } } cleanup: alpm_list_free(unresolvable); alpm_list_free(remove); return ret; }
static int extract_single_file(alpm_handle_t *handle, struct archive *archive, struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg) { const char *entryname = archive_entry_pathname(entry); mode_t entrymode = archive_entry_mode(entry); alpm_backup_t *backup = _alpm_needbackup(entryname, newpkg); char filename[PATH_MAX]; /* the actual file we're extracting */ int needbackup = 0, notouch = 0; const char *hash_orig = NULL; int errors = 0; struct stat lsbuf; size_t filename_len; if(*entryname == '.') { return extract_db_file(handle, archive, entry, newpkg, entryname); } if (!alpm_filelist_contains(&newpkg->files, entryname)) { _alpm_log(handle, ALPM_LOG_WARNING, _("file not found in file list for package %s. skipping extraction of %s\n"), newpkg->name, entryname); return 0; } /* build the new entryname relative to handle->root */ filename_len = snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname); if(filename_len >= PATH_MAX) { _alpm_log(handle, ALPM_LOG_ERROR, _("unable to extract %s%s: path too long"), handle->root, entryname); return 1; } /* if a file is in NoExtract then we never extract it */ if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract," " skipping extraction of %s\n", entryname, filename); 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: * (F=file, N=node, S=symlink, D=dir) * | F/N | D * non-existent | 1 | 2 * F/N | 3 | 4 * D | 5 | 6 * * 1,2- extract, no magic necessary. lstat (llstat) will fail here. * 3,4- conflict checks should have caught this. either overwrite * or backup the file. * 5- file replacing directory- don't allow it. * 6- skip extraction, dir already exists. */ if(llstat(filename, &lsbuf) != 0) { /* cases 1,2: file doesn't exist, skip all backup checks */ } else if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) { #if 0 uid_t entryuid = archive_entry_uid(entry); gid_t entrygid = archive_entry_gid(entry); #endif /* case 6: existing dir, ignore it */ if(lsbuf.st_mode != entrymode) { /* if filesystem perms are different than pkg perms, warn user */ mode_t mask = 07777; _alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n" "filesystem: %o package: %o\n"), filename, lsbuf.st_mode & mask, entrymode & mask); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: directory permissions differ on %s\n" "filesystem: %o package: %o\n", filename, lsbuf.st_mode & mask, entrymode & mask); } #if 0 /* Disable this warning until our user management in packages has improved. Currently many packages have to create users in post_install and chown the directories. These all resulted in "false-positive" warnings. */ if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) { _alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n" "filesystem: %u:%u package: %u:%u\n"), filename, lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: directory ownership differs on %s\n" "filesystem: %u:%u package: %u:%u\n", filename, lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid); } #endif _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n", filename); archive_read_data_skip(archive); return 0; } else if(S_ISDIR(lsbuf.st_mode)) { /* case 5: trying to overwrite dir with file, don't allow it */ _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"), filename); archive_read_data_skip(archive); return 1; } else if(S_ISDIR(entrymode)) { /* case 4: trying to overwrite file with dir */ _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n", filename); } else { /* case 3: trying to overwrite file with file */ /* if file is in NoUpgrade, don't touch it */ if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) { notouch = 1; } else { alpm_backup_t *oldbackup; if(oldpkg && (oldbackup = _alpm_needbackup(entryname, oldpkg))) { hash_orig = oldbackup->hash; needbackup = 1; } else if(backup) { /* allow adding backup files retroactively */ needbackup = 1; } } } if(notouch || needbackup) { if(filename_len + strlen(".pacnew") >= PATH_MAX) { _alpm_log(handle, ALPM_LOG_ERROR, _("unable to extract %s.pacnew: path too long"), filename); return 1; } strcpy(filename + filename_len, ".pacnew"); } if(handle->trans->flags & ALPM_TRANS_FLAG_FORCE) { /* if FORCE was used, unlink() each file (whether it's there * or not) before extracting. This prevents the old "Text file busy" * error that crops up if forcing a glibc or pacman upgrade. */ unlink(filename); } _alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename); if(perform_extraction(handle, archive, entry, filename)) { errors++; return errors; } if(backup) { FREE(backup->hash); backup->hash = alpm_compute_md5sum(filename); } if(notouch) { alpm_event_pacnew_created_t event = { .type = ALPM_EVENT_PACNEW_CREATED, .from_noupgrade = 1, .oldpkg = oldpkg, .newpkg = newpkg, .file = filename }; /* "remove" the .pacnew suffix */ filename[filename_len] = '\0'; EVENT(handle, &event); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s installed as %s.pacnew\n", filename, filename); } else if(needbackup) { char *hash_local = NULL, *hash_pkg = NULL; char origfile[PATH_MAX] = ""; strncat(origfile, filename, filename_len); hash_local = alpm_compute_md5sum(origfile); hash_pkg = backup ? backup->hash : alpm_compute_md5sum(filename); _alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", origfile); _alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local); _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg); _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig); if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { /* local and new files are the same, updating anyway to get * correct timestamps */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", origfile); if(try_rename(handle, filename, origfile)) { errors++; } } else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { /* original and new files are the same, leave the local version alone, * including any user changes */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); unlink(filename); } else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) { /* installed file has NOT been changed by user, * update to the new version */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", origfile); if(try_rename(handle, filename, origfile)) { errors++; } } else { /* none of the three files matched another, leave the unpacked * file alongside the local file */ alpm_event_pacnew_created_t event = { .type = ALPM_EVENT_PACNEW_CREATED, .from_noupgrade = 0, .oldpkg = oldpkg, .newpkg = newpkg, .file = origfile }; _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" " new one with .pacnew ending\n"); EVENT(handle, &event); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s installed as %s\n", origfile, filename); } free(hash_local); if(!backup) { free(hash_pkg); } } return errors; } static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, size_t pkg_current, size_t pkg_count) { int i, ret = 0, errors = 0; int is_upgrade = 0; alpm_pkg_t *oldpkg = NULL; alpm_db_t *db = handle->db_local; alpm_trans_t *trans = handle->trans; alpm_progress_t progress = ALPM_PROGRESS_ADD_START; alpm_event_package_operation_t event; const char *log_msg = "adding"; const char *pkgfile; ASSERT(trans != NULL, return -1); /* see if this is an upgrade. if so, remove the old package first */ alpm_pkg_t *local = _alpm_db_get_pkgfromcache(db, newpkg->name); if(local) { int cmp = _alpm_pkg_compare_versions(newpkg, local); if(cmp < 0) { log_msg = "downgrading"; progress = ALPM_PROGRESS_DOWNGRADE_START; event.operation = ALPM_PACKAGE_DOWNGRADE; } else if(cmp == 0) { log_msg = "reinstalling"; progress = ALPM_PROGRESS_REINSTALL_START; event.operation = ALPM_PACKAGE_REINSTALL; } else { log_msg = "upgrading"; progress = ALPM_PROGRESS_UPGRADE_START; event.operation = ALPM_PACKAGE_UPGRADE; } is_upgrade = 1; /* we'll need to save some record for backup checks later */ if(_alpm_pkg_dup(local, &oldpkg) == -1) { ret = -1; goto cleanup; } /* copy over the install reason */ newpkg->reason = alpm_pkg_get_reason(local); } else { event.operation = ALPM_PACKAGE_INSTALL; } event.type = ALPM_EVENT_PACKAGE_OPERATION_START; event.oldpkg = oldpkg; event.newpkg = newpkg; EVENT(handle, &event); pkgfile = newpkg->origin_data.file; _alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n", log_msg, newpkg->name, newpkg->version); /* pre_install/pre_upgrade scriptlet */ if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install"; _alpm_runscriptlet(handle, pkgfile, scriptlet_name, newpkg->version, oldpkg ? oldpkg->version : NULL, 1); } /* we override any pre-set reason if we have alldeps or allexplicit set */ if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) { newpkg->reason = ALPM_PKG_REASON_DEPEND; } else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) { newpkg->reason = ALPM_PKG_REASON_EXPLICIT; } if(oldpkg) { /* set up fake remove transaction */ if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) { handle->pm_errno = ALPM_ERR_TRANS_ABORT; ret = -1; goto cleanup; } } /* prepare directory for database entries so permission are correct after changelog/install script installation */ if(_alpm_local_db_prepare(db, newpkg)) { alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not create database entry %s-%s\n", newpkg->name, newpkg->version); handle->pm_errno = ALPM_ERR_DB_WRITE; ret = -1; goto cleanup; } if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) { struct archive *archive; struct archive_entry *entry; struct stat buf; int fd, cwdfd; _alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n"); fd = _alpm_open_archive(db->handle, pkgfile, &buf, &archive, ALPM_ERR_PKG_OPEN); if(fd < 0) { ret = -1; goto cleanup; } /* save the cwd so we can restore it later */ OPEN(cwdfd, ".", O_RDONLY | O_CLOEXEC); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } /* libarchive requires this for extracting hard links */ if(chdir(handle->root) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno)); _alpm_archive_read_free(archive); close(fd); ret = -1; goto cleanup; } /* call PROGRESS once with 0 percent, as we sort-of skip that here */ PROGRESS(handle, progress, newpkg->name, 0, pkg_count, pkg_current); for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) { 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 = _alpm_archive_compressed_ftell(archive); percent = (pos * 100) / newpkg->size; if(percent >= 100) { percent = 100; } } else { percent = 0; } PROGRESS(handle, progress, newpkg->name, percent, pkg_count, pkg_current); /* extract the next file from the archive */ errors += extract_single_file(handle, archive, entry, newpkg, oldpkg); } _alpm_archive_read_free(archive); close(fd); /* restore the old cwd if we have it */ if(cwdfd >= 0) { if(fchdir(cwdfd) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } close(cwdfd); } if(errors) { ret = -1; if(is_upgrade) { _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"), newpkg->name); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: problem occurred while upgrading %s\n", newpkg->name); } else { _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"), newpkg->name); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: problem occurred while installing %s\n", newpkg->name); } } } /* make an install date (in UTC) */ newpkg->installdate = time(NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n"); _alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name); if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"), newpkg->name, newpkg->version); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not update database entry %s-%s\n", newpkg->name, newpkg->version); handle->pm_errno = ALPM_ERR_DB_WRITE; ret = -1; goto cleanup; } if(_alpm_db_add_pkgincache(db, newpkg) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"), newpkg->name); } PROGRESS(handle, progress, newpkg->name, 100, pkg_count, pkg_current); switch(event.operation) { case ALPM_PACKAGE_INSTALL: alpm_logaction(handle, ALPM_CALLER_PREFIX, "installed %s (%s)\n", newpkg->name, newpkg->version); break; case ALPM_PACKAGE_DOWNGRADE: alpm_logaction(handle, ALPM_CALLER_PREFIX, "downgraded %s (%s -> %s)\n", newpkg->name, oldpkg->version, newpkg->version); break; case ALPM_PACKAGE_REINSTALL: alpm_logaction(handle, ALPM_CALLER_PREFIX, "reinstalled %s (%s)\n", newpkg->name, newpkg->version); break; case ALPM_PACKAGE_UPGRADE: alpm_logaction(handle, ALPM_CALLER_PREFIX, "upgraded %s (%s -> %s)\n", newpkg->name, oldpkg->version, newpkg->version); break; default: /* we should never reach here */ break; } /* run the post-install script if it exists */ if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install"); const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install"; _alpm_runscriptlet(handle, scriptlet, scriptlet_name, newpkg->version, oldpkg ? oldpkg->version : NULL, 0); free(scriptlet); } event.type = ALPM_EVENT_PACKAGE_OPERATION_DONE; EVENT(handle, &event); cleanup: _alpm_pkg_free(oldpkg); return ret; }
/* Find file conflicts that may occur during the transaction with two checks: * 1: check every target against every target * 2: check every target against the filesystem */ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *root) { alpm_list_t *i, *conflicts = NULL; alpm_list_t *targets = trans->packages; int numtargs = alpm_list_count(targets); int current; ALPM_LOG_FUNC; if(db == NULL || targets == NULL || root == NULL) { return(NULL); } /* TODO this whole function needs a huge change, which hopefully will * be possible with real transactions. Right now we only do half as much * here as we do when we actually extract files in add.c with our 12 * different cases. */ for(current = 1, i = targets; i; i = i->next, current++) { alpm_list_t *j, *k, *tmpfiles = NULL; pmpkg_t *p1, *p2, *dbpkg; char path[PATH_MAX+1]; p1 = i->data; if(!p1) { continue; } double percent = (double)current / numtargs; PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", (percent * 100), numtargs, current); /* CHECK 1: check every target against every target */ _alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s\n", alpm_pkg_get_name(p1)); for(j = i->next; j; j = j->next) { p2 = j->data; if(!p2) { continue; } tmpfiles = chk_fileconflicts(alpm_pkg_get_files(p1), alpm_pkg_get_files(p2)); if(tmpfiles) { for(k = tmpfiles; k; k = k->next) { snprintf(path, PATH_MAX, "%s%s", root, (char *)k->data); conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_TARGET, path, alpm_pkg_get_name(p1), alpm_pkg_get_name(p2)); } FREELIST(tmpfiles); } } /* declarations for second check */ struct stat lsbuf, sbuf; char *filestr = NULL; /* CHECK 2: check every target against the filesystem */ _alpm_log(PM_LOG_DEBUG, "searching for filesystem conflicts: %s\n", p1->name); dbpkg = _alpm_db_get_pkgfromcache(db, p1->name); /* Do two different checks here. f the package is currently installed, * then only check files that are new in the new package. If the package * is not currently installed, then simply stat the whole filelist */ if(dbpkg) { /* older ver of package currently installed */ tmpfiles = chk_filedifference(alpm_pkg_get_files(p1), alpm_pkg_get_files(dbpkg)); } else { /* no version of package currently installed */ tmpfiles = alpm_list_strdup(alpm_pkg_get_files(p1)); } /* loop over each file to be installed */ for(j = tmpfiles; j; j = j->next) { int skip_conflict = 0; filestr = j->data; snprintf(path, PATH_MAX, "%s%s", root, filestr); /* stat the file - if it exists, do some checks */ if(_alpm_lstat(path, &lsbuf) != 0) { continue; } stat(path, &sbuf); if(path[strlen(path)-1] == '/') { if(S_ISDIR(lsbuf.st_mode)) { _alpm_log(PM_LOG_DEBUG, "%s is a directory, not a conflict\n", path); skip_conflict = 1; } else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(sbuf.st_mode)) { _alpm_log(PM_LOG_DEBUG, "%s is a symlink to a dir, hopefully not a conflict\n", path); skip_conflict = 1; } } if(!skip_conflict) { _alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path); /* Look at all the targets to see if file has changed hands */ int resolved_conflict = 0; /* have we acted on this conflict? */ for(k = targets; k; k = k->next) { p2 = k->data; if(!p2 || strcmp(p1->name, p2->name) == 0) { continue; } pmpkg_t *localp2 = _alpm_db_get_pkgfromcache(db, p2->name); /* Check if it used to exist in a package, but doesn't anymore */ alpm_list_t *pkgfiles, *localfiles; /* added for readability */ pkgfiles = alpm_pkg_get_files(p2); localfiles = alpm_pkg_get_files(localp2); if(localp2 && !alpm_list_find_str(pkgfiles, filestr) && alpm_list_find_str(localfiles, filestr)) { /* skip removal of file, but not add. this will prevent a second * package from removing the file when it was already installed * by its new owner (whether the file is in backup array or not */ trans->skip_remove = alpm_list_add(trans->skip_remove, strdup(path)); _alpm_log(PM_LOG_DEBUG, "file changed packages, adding to remove skiplist: %s\n", filestr); resolved_conflict = 1; break; } } if(!resolved_conflict) { _alpm_log(PM_LOG_DEBUG, "file found in conflict: %s\n", path); conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_FILESYSTEM, path, p1->name, NULL); } } } FREELIST(tmpfiles); } return(conflicts); }
int _alpm_check_diskspace(alpm_handle_t *handle) { alpm_list_t *mount_points, *i; alpm_mountpoint_t *root_mp; size_t replaces = 0, current = 0, numtargs; int error = 0; alpm_list_t *targ; alpm_trans_t *trans = handle->trans; numtargs = alpm_list_count(trans->add); mount_points = mount_point_list(handle); if(mount_points == NULL) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n")); return -1; } root_mp = match_mount_point(mount_points, handle->root); if(root_mp == NULL) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not determine root mount point %s\n"), handle->root); error = 1; goto finish; } replaces = alpm_list_count(trans->remove); if(replaces) { numtargs += replaces; for(targ = trans->remove; targ; targ = targ->next, current++) { alpm_pkg_t *local_pkg; int percent = (current * 100) / numtargs; PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", percent, numtargs, current); local_pkg = targ->data; calculate_removed_size(handle, mount_points, local_pkg); } } for(targ = trans->add; targ; targ = targ->next, current++) { alpm_pkg_t *pkg, *local_pkg; int percent = (current * 100) / numtargs; PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", percent, numtargs, current); pkg = targ->data; /* is this package already installed? */ local_pkg = _alpm_db_get_pkgfromcache(handle->db_local, pkg->name); if(local_pkg) { calculate_removed_size(handle, mount_points, local_pkg); } calculate_installed_size(handle, mount_points, pkg); for(i = mount_points; i; i = i->next) { alpm_mountpoint_t *data = i->data; if(data->blocks_needed > data->max_blocks_needed) { data->max_blocks_needed = data->blocks_needed; } } } PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", 100, numtargs, current); for(i = mount_points; i; i = i->next) { alpm_mountpoint_t *data = i->data; if(data->used && data->read_only) { _alpm_log(handle, ALPM_LOG_ERROR, _("Partition %s is mounted read only\n"), data->mount_dir); error = 1; } else if(data->used & USED_INSTALL && check_mountpoint(handle, data)) { error = 1; } } finish: mount_point_list_free(mount_points); if(error) { RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1); } return 0; }