diff --git a/CMakeLists.txt b/CMakeLists.txt index c1ada00..3541f49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,9 @@ ENDIF (NOT PKGCONFIG_INSTALL_DIR) SET (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) INSTALL( FILES ${CMAKE_MODULE_PATH}/FindLibSolv.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}/share/cmake/Modules ) +# for shared libraries on windows (DLLs), we just export all symbols for now +SET(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + INCLUDE (${CMAKE_SOURCE_DIR}/VERSION.cmake) SET (have_system x) @@ -206,6 +209,12 @@ ENDIF (ENABLE_RPMDB) INCLUDE (CheckIncludeFile) IF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM) + FIND_PATH (RPM_INCLUDE_DIR NAMES rpm/rpmio.h) + IF (RPM_INCLUDE_DIR) + INCLUDE_DIRECTORIES (${RPM_INCLUDE_DIR}) + SET (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${RPM_INCLUDE_DIR}) + ENDIF (RPM_INCLUDE_DIR) + FIND_LIBRARY (RPMDB_LIBRARY NAMES rpmdb) IF (NOT RPMDB_LIBRARY) @@ -245,7 +254,6 @@ IF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM) ENDIF (ENABLE_RPMDB) INCLUDE (CheckLibraryExists) - CHECK_LIBRARY_EXISTS(rpmio pgpDigGetParams "" HAVE_PGPDIGGETPARAMS) CHECK_LIBRARY_EXISTS(rpm rpmdbNextIteratorHeaderBlob "" HAVE_RPMDBNEXTITERATORHEADERBLOB) CHECK_LIBRARY_EXISTS(rpm rpmdbFStat "" HAVE_RPMDBFSTAT) ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM) @@ -280,7 +288,7 @@ ENDIF (${CMAKE_MAJOR_VERSION} GREATER 2) # should create config.h with #cmakedefine instead... FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN - HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS HAVE_RPMDBNEXTITERATORHEADERBLOB HAVE_RPMDBFSTAT + HAVE_RPM_DB_H HAVE_RPMDBNEXTITERATORHEADERBLOB HAVE_RPMDBFSTAT WITH_LIBXML2 WITHOUT_COOKIEOPEN) IF(${VAR}) ADD_DEFINITIONS (-D${VAR}=1) @@ -431,9 +439,9 @@ ENDIF (HAVE_LINKER_AS_NEEDED) ADD_SUBDIRECTORY (src) ADD_SUBDIRECTORY (ext) ADD_SUBDIRECTORY (tools) -IF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL) +IF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_PYTHON3 OR ENABLE_RUBY OR ENABLE_TCL) ADD_SUBDIRECTORY (bindings) -ENDIF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL) +ENDIF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_PYTHON3 OR ENABLE_RUBY OR ENABLE_TCL) ADD_SUBDIRECTORY (examples) ADD_SUBDIRECTORY (doc) diff --git a/NEWS b/NEWS index 9d2d833..ca6efa9 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,45 @@ This file contains the major changes between libsolv versions: +Version 0.7.16 +- selected bug fixes: + * do not ask the namespace callback for splitprovides when writing + a testcase + * fix add_complex_recommends() selecting conflicted packages in + rare cases leading to crashes + * improve choicerule generation so that package updates are + prefered in more cases + * deal with missing repos in testcase_mangle_repo_names + +Version 0.7.15 +- selected bug fixes: + * fix deduceq2addedmap clearing bits outside of the map + * conda: feature depriorization first + * conda: fix startswith implementation + * move find_update_seeds() call in cleandeps calculation +- new features: + * set SOLVABLE_BUILDHOST in rpm and rpmmd parsers + * new testcase_mangle_repo_names() function + * new solv_fmemopen() function + +Version 0.7.14 +- added support for ed25519 signatures +- selected bug fixes: + * Support blacklisted packages in solver_findproblemrule() + * Support rules with multiple negative literals in choice rule + generation + * Also detect rpmdb.sqlite in /usr/share/rpm + +Version 0.7.13 +- fix solvable swapping messing up uninternalized idarrays + +Version 0.7.12 +- conda: support packages.conda repositories +- conda: de-priorize track features +- allow win32 to build shared lib +- selected bug fixes: + * fix ruleinfo of complex dependencies returning the wrong origin + Version 0.7.11 - ENABLE_RPMDB_LIBRPM is now the default - selected bug fixes: diff --git a/VERSION.cmake b/VERSION.cmake index 180eda5..c218401 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "1") SET(LIBSOLV_MAJOR "0") SET(LIBSOLV_MINOR "7") -SET(LIBSOLV_PATCH "11") +SET(LIBSOLV_PATCH "16") diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver index 6423837..4102301 100644 --- a/ext/libsolvext.ver +++ b/ext/libsolvext.ver @@ -55,6 +55,7 @@ SOLV_1.0 { rpm_stat_database; rpm_state_create; rpm_state_free; + solv_fmemopen; solv_verify_sig; solv_xfopen; solv_xfopen_buf; @@ -66,6 +67,7 @@ SOLV_1.0 { testcase_add_testtags; testcase_dep2str; testcase_job2str; + testcase_mangle_repo_names; testcase_solvid2str; testcase_str2dep; testcase_str2job; diff --git a/ext/repo_conda.c b/ext/repo_conda.c index 9352b71..6e9a963 100644 --- a/ext/repo_conda.c +++ b/ext/repo_conda.c @@ -22,6 +22,9 @@ struct parsedata { Pool *pool; Repo *repo; Repodata *data; + + Stringpool fnpool; + Queue fndata; }; static int @@ -61,17 +64,91 @@ parse_otherdeps(struct parsedata *pd, struct solv_jsonparser *jp, Id handle, Id } static int +parse_trackfeatures_array(struct parsedata *pd, struct solv_jsonparser *jp, Id handle) +{ + int type = JP_ARRAY; + while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END) + { + if (type == JP_STRING) + { + char *p = jp->value, *pe; + while (*p == ' ' || *p == '\t') + p++; + if (!*p) + continue; + for (pe = p + strlen(p) - 1; pe > p; pe--) + if (*pe != ' ' && *pe != '\t') + break; + repodata_add_idarray(pd->data, handle, SOLVABLE_TRACK_FEATURES, pool_strn2id(pd->pool, p, pe - p + 1, 1)); + } + else + type = jsonparser_skip(jp, type); + } + return type; +} + +static void +parse_trackfeatures_string(struct parsedata *pd, const char *p, Id handle) +{ + const char *pe; + for (; *p; p++) + { + if (*p == ' ' || *p == '\t' || *p == ',') + continue; + pe = p + 1; + while (*pe && *pe != ' ' && *pe != '\t' && *pe != ',') + pe++; + repodata_add_idarray(pd->data, handle, SOLVABLE_TRACK_FEATURES, pool_strn2id(pd->pool, p, pe - p, 1)); + p = pe - 1; + } +} + +static void +swap_solvables(Pool *pool, Repodata *data, Id pa, Id pb) +{ + Solvable tmp; + + tmp = pool->solvables[pa]; + pool->solvables[pa] = pool->solvables[pb]; + pool->solvables[pb] = tmp; + repodata_swap_attrs(data, pa, pb); +} + +static Id * +fn2data(struct parsedata *pd, const char *fn, Id *fntypep, int create) +{ + size_t l = strlen(fn), extl = 0; + Id fnid; + if (l > 6 && !strcmp(fn + l - 6, ".conda")) + extl = 6; + else if (l > 8 && !strcmp(fn + l - 8, ".tar.bz2")) + extl = 8; + else + return 0; + fnid = stringpool_strn2id(&pd->fnpool, fn, l - extl, create); + if (!fnid) + return 0; + if (fnid * 2 + 2 > pd->fndata.count) + queue_insertn(&pd->fndata, pd->fndata.count, fnid * 2 + 2 - pd->fndata.count, 0); + if (fntypep) + *fntypep = extl == 8 ? 1 : 2; /* 1: legacy .tar.bz2 2: .conda */ + return pd->fndata.elements + 2 * fnid; +} + +static int parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn) { int type = JP_OBJECT; Pool *pool= pd->pool; Repodata *data = pd->data; Solvable *s; - Id handle = repo_add_solvable(pd->repo); - s = pool_id2solvable(pool, handle); + Id handle; char *fn = 0; char *subdir = 0; + Id *fndata = 0, fntype = 0; + handle = repo_add_solvable(pd->repo); + s = pool_id2solvable(pool, handle); while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END) { if (type == JP_STRING && !strcmp(jp->key, "build")) @@ -107,17 +184,44 @@ parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn) ts /= 1000; repodata_set_num(data, handle, SOLVABLE_BUILDTIME, ts); } + else if (type == JP_STRING && !strcmp(jp->key, "track_features")) + parse_trackfeatures_string(pd, jp->value, handle); + else if (type == JP_ARRAY && !strcmp(jp->key, "track_features")) + type = parse_trackfeatures_array(pd, jp, handle); else type = jsonparser_skip(jp, type); } if (fn || kfn) - repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn); + { + repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn); + fndata = fn2data(pd, fn ? fn : kfn, &fntype, 1); + } solv_free(fn); solv_free(subdir); if (!s->evr) s->evr = 1; if (s->name) s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); + + if (fndata) + { + /* deal with legacy package entries */ + if (fndata[0] && fndata[0] > fntype) + { + /* ignore this package */ + repo_free_solvable(pd->repo, handle, 1); + return type; + } + if (fndata[0] && fndata[0] < fntype) + { + /* replace old package */ + swap_solvables(pool, data, handle, fndata[1]); + repo_free_solvable(pd->repo, handle, 1); + handle = fndata[1]; + } + fndata[0] = fntype; + fndata[1] = handle; + } return type; } @@ -161,7 +265,11 @@ parse_main(struct parsedata *pd, struct solv_jsonparser *jp) { if (type == JP_OBJECT && !strcmp("packages", jp->key)) type = parse_packages(pd, jp); - if (type == JP_ARRAY && !strcmp("packages", jp->key)) + else if (type == JP_ARRAY && !strcmp("packages", jp->key)) + type = parse_packages2(pd, jp); + else if (type == JP_OBJECT && !strcmp("packages.conda", jp->key)) + type = parse_packages(pd, jp); + else if (type == JP_ARRAY && !strcmp("packages.conda", jp->key)) type = parse_packages2(pd, jp); else type = jsonparser_skip(jp, type); @@ -184,6 +292,8 @@ repo_add_conda(Repo *repo, FILE *fp, int flags) pd.pool = pool; pd.repo = repo; pd.data = data; + stringpool_init_empty(&pd.fnpool); + queue_init(&pd.fndata); jsonparser_init(&jp, fp); if ((type = jsonparser_parse(&jp)) != JP_OBJECT) @@ -192,6 +302,8 @@ repo_add_conda(Repo *repo, FILE *fp, int flags) ret = pool_error(pool, -1, "parse error line %d", jp.line); jsonparser_free(&jp); + queue_free(&pd.fndata); + stringpool_free(&pd.fnpool); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); diff --git a/ext/repo_pubkey.c b/ext/repo_pubkey.c index eb83839..883e13a 100644 --- a/ext/repo_pubkey.c +++ b/ext/repo_pubkey.c @@ -503,11 +503,12 @@ static int parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) { Repo *repo = s->repo; + Pool *pool = repo->pool; unsigned char *pstart = p; int tag, l; unsigned char keyid[8]; char subkeyofstr[17]; - unsigned int kcr = 0, maxex = 0, maxsigcr = 0; + unsigned int kcr = 0, maxex = 0, maxsigcr = 0, rpmsigcr = 0; unsigned char *pubkey = 0; int pubkeyl = 0; int insubkey = 0; @@ -524,10 +525,10 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) { /* finish old key */ if (kcr) - repodata_set_num(data, s - repo->pool->solvables, SOLVABLE_BUILDTIME, kcr); + repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, kcr); if (maxex && maxex != -1) - repodata_set_num(data, s - repo->pool->solvables, PUBKEY_EXPIRES, maxex); - s->name = pool_str2id(s->repo->pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1); + repodata_set_num(data, s - pool->solvables, PUBKEY_EXPIRES, maxex); + s->name = pool_str2id(pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1); s->evr = 1; s->arch = 1; if (userid && useridl) @@ -535,7 +536,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) char *useridstr = solv_malloc(useridl + 1); memcpy(useridstr, userid, useridl); useridstr[useridl] = 0; - setutf8string(data, s - repo->pool->solvables, SOLVABLE_SUMMARY, useridstr); + setutf8string(data, s - pool->solvables, SOLVABLE_SUMMARY, useridstr); free(useridstr); } if (pubdata) @@ -543,16 +544,16 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) char keyidstr[17]; char evr[8 + 1 + 8 + 1]; solv_bin2hex(keyid, 8, keyidstr); - repodata_set_str(data, s - repo->pool->solvables, PUBKEY_KEYID, keyidstr); + repodata_set_str(data, s - pool->solvables, PUBKEY_KEYID, keyidstr); /* build rpm-style evr */ strcpy(evr, keyidstr + 8); - sprintf(evr + 8, "-%08x", maxsigcr); - s->evr = pool_str2id(repo->pool, evr, 1); + sprintf(evr + 8, "-%08x", (flags & USE_RPM_PUBKEY_BUILTTIME) ? rpmsigcr : maxsigcr); + s->evr = pool_str2id(pool, evr, 1); } if (insubkey && *subkeyofstr) - repodata_set_str(data, s - repo->pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr); + repodata_set_str(data, s - pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr); if (pubdata) /* set data blob */ - repodata_set_binary(data, s - repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal); + repodata_set_binary(data, s - pool->solvables, PUBKEY_DATA, pubdata, pubdatal); if (!pl) break; if (!hl) @@ -565,7 +566,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) if (tag == 14 && pubdata && !insubkey) solv_bin2hex(keyid, 8, subkeyofstr); /* create new solvable for subkey */ - s = pool_id2solvable(repo->pool, repo_add_solvable(repo)); + s = pool_id2solvable(pool, repo_add_solvable(repo)); } p += hl; pl -= hl; @@ -616,7 +617,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) solv_chksum_add(h, q + 2, ql2); solv_chksum_free(h, fp); solv_bin2hex(fp, 16, fpx); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); + repodata_set_str(data, s - pool->solvables, PUBKEY_FINGERPRINT, fpx); } } pubdata = p + 7; @@ -640,7 +641,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) solv_chksum_add(h, p, l); solv_chksum_free(h, fp); solv_bin2hex(fp, 20, fpx); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); + repodata_set_str(data, s - pool->solvables, PUBKEY_FINGERPRINT, fpx); memcpy(keyid, fp + 12, 8); /* keyid is last 64 bits of fingerprint */ pubdata = p + 5; pubdatal = l - 5; @@ -664,6 +665,8 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) pgpsig_makesigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h); solv_chksum_free(h, 0); } + if (!rpmsigcr) + rpmsigcr = sig.created; if (!memcmp(keyid, sig.issuer, 8)) { #ifdef ENABLE_PGPVRFY @@ -694,7 +697,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires); if (sig.sigdata) repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal); - repodata_add_flexarray(data, s - s->repo->pool->solvables, PUBKEY_SIGNATURES, shandle); + repodata_add_flexarray(data, s - pool->solvables, PUBKEY_SIGNATURES, shandle); } solv_free(sig.sigdata); } @@ -711,83 +714,6 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) return p ? p - pstart : 0; } - -#ifdef ENABLE_RPMDB - -/* this is private to rpm, but rpm lacks an interface to retrieve - * the values. Sigh. */ -struct pgpDigParams_s { - const char * userid; - const unsigned char * hash; -#ifndef HAVE_PGPDIGGETPARAMS - const char * params[4]; -#endif - unsigned char tag; - unsigned char version; /*!< version number. */ - unsigned char time[4]; /*!< time that the key was created. */ - unsigned char pubkey_algo; /*!< public key algorithm. */ - unsigned char hash_algo; - unsigned char sigtype; - unsigned char hashlen; - unsigned char signhash16[2]; - unsigned char signid[8]; - unsigned char saved; -}; - -#ifndef HAVE_PGPDIGGETPARAMS -struct pgpDig_s { - struct pgpDigParams_s signature; - struct pgpDigParams_s pubkey; -}; -#endif - - -/* only rpm knows how to do the release calculation, we don't dare - * to recreate all the bugs in libsolv */ -static void -parsepubkey_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl) -{ - Pool *pool = s->repo->pool; - struct pgpDigParams_s *digpubkey; - pgpDig dig = 0; - char keyid[16 + 1]; - char evrbuf[8 + 1 + 8 + 1]; - unsigned int btime; - -#ifndef RPM5 - dig = pgpNewDig(); -#else - dig = pgpDigNew(RPMVSF_DEFAULT, 0); -#endif - (void) pgpPrtPkts(pkts, pktsl, dig, 0); -#ifdef HAVE_PGPDIGGETPARAMS - digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY); -#else - digpubkey = &dig->pubkey; -#endif - if (digpubkey) - { - btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->time[3]; - solv_bin2hex(digpubkey->signid, 8, keyid); - solv_bin2hex(digpubkey->signid + 4, 4, evrbuf); - evrbuf[8] = '-'; - solv_bin2hex(digpubkey->time, 4, evrbuf + 9); - s->evr = pool_str2id(pool, evrbuf, 1); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid); - if (digpubkey->userid) - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid); - if (btime) - repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime); - } -#ifndef RPM5 - (void)pgpFreeDig(dig); -#else - (void)pgpDigFree(dig); -#endif -} - -#endif /* ENABLE_RPMDB */ - /* parse an ascii armored pubkey * adds multiple pubkeys if ADD_MULTIPLE_PUBKEYS is set */ static int @@ -809,9 +735,6 @@ pubkey2solvable(Pool *pool, Id p, Repodata *data, char *pubkey, int flags) { setutf8string(data, p, SOLVABLE_DESCRIPTION, pubkey); pl = parsepubkey(pool->solvables + p, data, pkts, pktsl, flags); -#ifdef ENABLE_RPMDB - parsepubkey_rpm(pool->solvables + p, data, pkts, pktsl); -#endif if (!pl || !(flags & ADD_MULTIPLE_PUBKEYS)) break; } @@ -988,9 +911,6 @@ add_one_pubkey(Pool *pool, Repo *repo, Repodata *data, unsigned char *pbuf, int char *descr = armor(pbuf, pbufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----", solvversion); setutf8string(data, p, SOLVABLE_DESCRIPTION, descr); parsepubkey(pool->solvables + p, data, pbuf, pbufl, flags); -#ifdef ENABLE_RPMDB - parsepubkey_rpm(pool->solvables + p, data, pbuf, pbufl); -#endif } int diff --git a/ext/repo_pubkey.h b/ext/repo_pubkey.h index 26cf0e1..51946bf 100644 --- a/ext/repo_pubkey.h +++ b/ext/repo_pubkey.h @@ -12,6 +12,7 @@ #define ADD_WITH_SUBKEYS (1 << 9) #define ADD_MULTIPLE_PUBKEYS (1 << 10) #define ADD_WITH_KEYSIGNATURES (1 << 11) +#define USE_RPM_PUBKEY_BUILTTIME (1 << 12) extern int repo_add_rpmdb_pubkeys(Repo *repo, int flags); extern Id repo_add_pubkey(Repo *repo, const char *keyfile, int flags); diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index ed98628..67ce81d 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -1189,6 +1189,9 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe u32 = headint32(rpmhead, TAG_BUILDTIME); if (u32) repodata_set_num(data, handle, SOLVABLE_BUILDTIME, u32); + str = headstring(rpmhead, TAG_BUILDHOST); + if (str) + repodata_set_str(data, handle, SOLVABLE_BUILDHOST, str); u32 = headint32(rpmhead, TAG_INSTALLTIME); if (u32) repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, u32); diff --git a/ext/repo_rpmdb_librpm.h b/ext/repo_rpmdb_librpm.h index 34e6698..35a46fa 100644 --- a/ext/repo_rpmdb_librpm.h +++ b/ext/repo_rpmdb_librpm.h @@ -46,7 +46,7 @@ static void detect_dbpath(struct rpmdbstate *state) { state->dbpath = access_rootdir(state, "/var/lib/rpm", W_OK) == -1 - && access_rootdir(state, "/usr/share/rpm/Packages", R_OK) == 0 + && (access_rootdir(state, "/usr/share/rpm/Packages", R_OK) == 0 || access_rootdir(state, "/usr/share/rpm/rpmdb.sqlite", R_OK) == 0) ? "/usr/share/rpm" : "/var/lib/rpm"; } diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c index 9bb50a0..1232e43 100644 --- a/ext/repo_rpmmd.c +++ b/ext/repo_rpmmd.c @@ -96,6 +96,7 @@ enum state { STATE_FRESHENS, STATE_SOURCERPM, STATE_HEADERRANGE, + STATE_BUILDHOST, STATE_PROVIDESENTRY, STATE_REQUIRESENTRY, @@ -196,6 +197,7 @@ static struct solv_xmlparser_element stateswitches[] = { { STATE_SOLVABLE, "rpm:freshens", STATE_FRESHENS, 0 }, { STATE_SOLVABLE, "rpm:sourcerpm", STATE_SOURCERPM, 1 }, { STATE_SOLVABLE, "rpm:header-range", STATE_HEADERRANGE, 0 }, + { STATE_SOLVABLE, "rpm:buildhost", STATE_BUILDHOST, 1 }, { STATE_SOLVABLE, "file", STATE_FILE, 1 }, { STATE_SOLVABLE, "changelog", STATE_CHANGELOG, 1 }, @@ -1036,6 +1038,10 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content) if (*content) repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, content); break; + case STATE_BUILDHOST: + if (*content) + repodata_set_str(pd->data, handle, SOLVABLE_BUILDHOST, content); + break; case STATE_SOURCERPM: if (*content) repodata_set_sourcepkg(pd->data, handle, content); diff --git a/ext/repo_updateinfoxml.c b/ext/repo_updateinfoxml.c index 5b980a1..36d76b5 100644 --- a/ext/repo_updateinfoxml.c +++ b/ext/repo_updateinfoxml.c @@ -524,7 +524,7 @@ repo_mark_retracted_packages(Repo *repo, Id retractedmarker) Queue q; queue_init(&q); - for (p = 1; p < pool->nsolvables; p++) + FOR_REPO_SOLVABLES(repo, p, s) { const char *status; s = pool->solvables + p; @@ -578,7 +578,7 @@ repo_mark_retracted_packages(Repo *repo, Id retractedmarker) else if (q.elements[i + 1] == retractedname && q.elements[i + 2] == retractedevr) { s = pool->solvables + q.elements[i]; - s->provides = repo_addid_dep(repo, s->provides, retractedmarker, 0); + s->provides = repo_addid_dep(s->repo, s->provides, retractedmarker, 0); } } queue_free(&q); diff --git a/ext/solv_ed25519.h b/ext/solv_ed25519.h new file mode 100644 index 0000000..0772cee --- /dev/null +++ b/ext/solv_ed25519.h @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2020, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* simple and slow ed25519 verification code. */ + +#ifndef LIBSOLV_CHKSUM_H +#include "chksum.h" +#endif + +#define MPED25519_LEN (32 / MP_T_BYTES) + +#if MP_T_BYTES == 4 +# define MPED25519_CONST1(x) (mp_t)x +#elif MP_T_BYTES == 1 +# define MPED25519_CONST1(x) (mp_t)(x >> 0), (mp_t)(x >> 8), (mp_t)(x >> 16), (mp_t)(x >> 24) +#endif + +#define MPED25519_CONST(a, b, c, d, e, f, g, h) { \ + MPED25519_CONST1(h), MPED25519_CONST1(g), MPED25519_CONST1(f), MPED25519_CONST1(e), \ + MPED25519_CONST1(d), MPED25519_CONST1(c), MPED25519_CONST1(b), MPED25519_CONST1(a) \ +} + +static mp_t ed25519_q[] = /* mod prime */ + MPED25519_CONST(0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFED); +static mp_t ed25519_d[] = /* -(121665/121666) */ + MPED25519_CONST(0x52036CEE, 0x2B6FFE73, 0x8CC74079, 0x7779E898, 0x00700A4D, 0x4141D8AB, 0x75EB4DCA, 0x135978A3); +static mp_t ed25519_sqrtm1[] = /* sqrt(-1) */ + MPED25519_CONST(0x2B832480, 0x4FC1DF0B, 0x2B4D0099, 0x3DFBD7A7, 0x2F431806, 0xAD2FE478, 0xC4EE1B27, 0x4A0EA0B0); +static mp_t ed25519_l[] = /* order of base point */ + MPED25519_CONST(0x10000000, 0x00000000, 0x00000000, 0x00000000, 0x14DEF9DE, 0xA2F79CD6, 0x5812631A, 0x5CF5D3ED); +static mp_t ed25519_gx[] = /* base point */ + MPED25519_CONST(0x216936D3, 0xCD6E53FE, 0xC0A4E231, 0xFDD6DC5C, 0x692CC760, 0x9525A7B2, 0xC9562D60, 0x8F25D51A); +static mp_t ed25519_gy[] = /* base point */ + MPED25519_CONST(0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666658); +static mp_t ed25519_one[] = /* 1 */ + MPED25519_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001); + +/* small helpers to save some typing */ +static inline void +mped25519_add(mp_t *target, mp_t *m1, mp_t *m2) +{ + mpadd(MPED25519_LEN, target, m1, m2, ed25519_q); +} + +static inline void +mped25519_sub(mp_t *target, mp_t *m1, mp_t *m2) +{ + mpsub(MPED25519_LEN, target, m1, m2, ed25519_q); +} + +/* target = 512 bit input modulo ed25519_q */ +static void +mped25519_reduce512(mp_t *target, mp_t *a) +{ + int i; + mp2_t x; + + for (x = 0, i = 0; i < MPED25519_LEN; i++) + { + x += (mp2_t)a[i] + (mp2_t)a[i + MPED25519_LEN] * 38; + target[i] = x; + x >>= MP_T_BITS; + } + x *= 38; + if ((target[MPED25519_LEN - 1] & (1 << (MP_T_BITS - 1))) != 0) + { + x += 19; + target[MPED25519_LEN - 1] -= 1 << (MP_T_BITS - 1); + } + for (i = 0; x && i < MPED25519_LEN; i++) + { + x += (mp2_t)target[i]; + target[i] = x; + x >>= MP_T_BITS; + } + if (target[MPED25519_LEN - 1] > ed25519_q[MPED25519_LEN - 1] || + (target[MPED25519_LEN - 1] == ed25519_q[MPED25519_LEN - 1] && !mpisless(MPED25519_LEN - 1, target, ed25519_q))) + mpsubmod(MPED25519_LEN, target, ed25519_q); +} + +static void +mped25519_mul(mp_t *target, mp_t *m1, mp_t *m2) +{ + mp_t tmp[MPED25519_LEN * 2]; + int i, j; + mp2_t x; + + mpzero(MPED25519_LEN * 2, tmp); + for (i = 0; i < MPED25519_LEN; i++) + { + for (x = 0, j = 0; j < MPED25519_LEN; j++) + { + x += (mp2_t)tmp[i + j] + (mp2_t)m1[i] * m2[j]; + tmp[i + j] = x; + x >>= MP_T_BITS; + } + tmp[i + j] = x; + } + mped25519_reduce512(target, tmp); +} + +static inline void +mped25519_sqr(mp_t *target, mp_t *m) +{ + mped25519_mul(target, m, m); +} + +/* target = a ^ (2^252 - 4), a11 = a ^ 11 */ +static void +mped25519_pow_252_4(mp_t *target, mp_t *a, mp_t *a_11) +{ + static const int todo[16] = { 0, 5, 1, 10, 2, 20, 3, 10, 2, 50, 5, 100, 6, 50, 5, 2 }; + mp_t data[9][MPED25519_LEN]; + int i, j; + + mpcpy(MPED25519_LEN, target, a); + mped25519_sqr(target, target); + mpcpy(MPED25519_LEN, a_11, target); + mped25519_sqr(target, target); + mped25519_sqr(target, target); + mped25519_mul(data[0], target, a); /* data[0] = 9 */ + mped25519_mul(a_11, data[0], a_11); /* a_11 = 11 */ + mped25519_mul(target, a_11, a_11); /* target = 22 */ + for (i = 0; i < 8; i++) + { + mped25519_mul(target, target, data[todo[i * 2]]); + mpcpy(MPED25519_LEN, data[i + 1], target); + for (j = todo[i * 2 + 1]; j-- > 0;) + mped25519_sqr(target, target); + } +} + +/* target = a ^ (2^252 - 3) */ +static void +mped25519_pow_252_3(mp_t *target, mp_t *a) +{ + mp_t t11[MPED25519_LEN]; + mped25519_pow_252_4(target, a, t11); + mped25519_mul(target, target, a); +} + +/* target = a ^ -1 = a ^ (2^255 - 21) */ +static void +mped25519_inv(mp_t *target, mp_t *a) +{ + mp_t t[MPED25519_LEN], t11[MPED25519_LEN]; + mped25519_pow_252_4(t, a, t11); + mped25519_sqr(t, t); + mped25519_sqr(t, t); + mped25519_sqr(t, t); /* 2^255 - 32 */ + mped25519_mul(target, t, t11); +} + +static void +mped25519_reduce512_l(mp_t *target, mp_t *a) +{ + mp_t tmp[MPED25519_LEN]; + mpzero(MPED25519_LEN, target); + mpmul_add(MPED25519_LEN, target, ed25519_one, MPED25519_LEN * 2, a, tmp, ed25519_l); +} + +/* recover x coordinate from y and sign */ +static int +mped25519_recover_x(mp_t *x, mp_t *y, int sign) +{ + mp_t num[MPED25519_LEN], den[MPED25519_LEN]; + mp_t tmp1[MPED25519_LEN], tmp2[MPED25519_LEN]; + + if (!mpisless(MPED25519_LEN, y, ed25519_q)) + return 0; + /* calculate num=y^2-1 and den=dy^2+1 */ + mped25519_sqr(num, y); + mped25519_mul(den, num, ed25519_d); + mped25519_sub(num, num, ed25519_one); + mped25519_add(den, den, ed25519_one); + + /* calculate x = num*den^3 * (num*den^7)^((q-5)/8) */ + mped25519_sqr(tmp1, den); /* tmp1 = den^2 */ + mped25519_mul(tmp2, tmp1, den); /* tmp2 = den^3 */ + mped25519_sqr(tmp1, tmp2); /* tmp1 = den^6 */ + mped25519_mul(x, tmp1, den); /* x = den^7 */ + mped25519_mul(tmp1, x, num); /* tmp1 = num * den^7 */ + mped25519_pow_252_3(x, tmp1); /* x = tmp1^((q-5)/8) */ + mped25519_mul(tmp1, x, tmp2); /* tmp1 = x * den^3 */ + mped25519_mul(x, tmp1, num); /* x = tmp1 * num */ + + /* check if den*x^2 == num */ + mped25519_sqr(tmp2, x); + mped25519_mul(tmp1, tmp2, den); + if (!mpisequal(MPED25519_LEN, tmp1, num)) { + mped25519_mul(x, x, ed25519_sqrtm1); /* x = x * sqrt(-1) */ + mped25519_sqr(tmp2, x); + mped25519_mul(tmp1, tmp2, den); + if (!mpisequal(MPED25519_LEN, tmp1, num)) + return 0; + } + if (mpiszero(MPED25519_LEN, x)) + return 0; /* (0,1) is bad */ + if ((x[0] & 1) != sign) + mped25519_sub(x, ed25519_q, x); + return 1; +} + +/* see https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html */ +/* M=7 add=6 */ +static void +mped25519_ptdouble(mp_t *p_x, mp_t *p_y, mp_t *p_z) +{ + mp_t B[MPED25519_LEN], C[MPED25519_LEN], D[MPED25519_LEN]; + mp_t F[MPED25519_LEN], H[MPED25519_LEN], J[MPED25519_LEN]; + + mped25519_add(C, p_x, p_y); + mped25519_sqr(B, C); + mped25519_sqr(C, p_x); + mped25519_sqr(D, p_y); + mped25519_sub(F, C, D); + mped25519_sqr(H, p_z); + mped25519_add(H, H, H); + mped25519_add(J, F, H); + mped25519_add(H, C, D); + mped25519_mul(p_y, H, F); + mped25519_mul(p_z, J, F); + mped25519_sub(H, H, B); + mped25519_mul(p_x, J, H); +} + +/* M=12 add=7 */ +static void +mped25519_ptadd(mp_t *p_x, mp_t *p_y, mp_t *p_z, mp_t *q_x, mp_t *q_y, mp_t *q_z) +{ + mp_t A[MPED25519_LEN], B[MPED25519_LEN], C[MPED25519_LEN]; + mp_t D[MPED25519_LEN], E[MPED25519_LEN], F[MPED25519_LEN]; + mp_t G[MPED25519_LEN], H[MPED25519_LEN], J[MPED25519_LEN]; + + mped25519_mul(A, p_z, q_z); + mped25519_sqr(B, A); + mped25519_mul(C, p_x, q_x); + mped25519_mul(D, p_y, q_y); + mped25519_mul(F, ed25519_d, C); + mped25519_mul(E, F, D); + mped25519_sub(F, B, E); + mped25519_add(G, B, E); + mped25519_add(H, p_x, p_y); + mped25519_add(J, q_x, q_y); + mped25519_mul(p_x, H, J); + mped25519_sub(p_x, p_x, C); + mped25519_sub(p_x, p_x, D); + mped25519_mul(H, p_x, F); + mped25519_mul(p_x, H, A); + mped25519_add(H, D, C); + mped25519_mul(J, H, G); + mped25519_mul(p_y, J, A); + mped25519_mul(p_z, F, G); +} + +static inline void +mped25519_ptcpy(mp_t *p_x, mp_t *p_y, mp_t *p_z, mp_t *q_x, mp_t *q_y, mp_t *q_z) +{ + mpcpy(MPED25519_LEN, p_x, q_x); + mpcpy(MPED25519_LEN, p_y, q_y); + mpcpy(MPED25519_LEN, p_z, q_z); +} + +#if 0 +static void +mped25519_mpdump(mp_t *p, char *s, int c) +{ + if (c) + fprintf(stderr, "%c.", c); + mpdump(MPED25519_LEN, p, s); +} + +static void +mped25519_ptdump(mp_t *p_x, mp_t *p_y, mp_t *p_z, char *s) +{ + mp_t zi[MPED25519_LEN], px[MPED25519_LEN], py[MPED25519_LEN]; + mped25519_mpdump(p_x, s, 'X'); + mped25519_mpdump(p_y, s, 'Y'); + mped25519_mpdump(p_z, s, 'Z'); + mped25519_inv(zi, p_z); + mped25519_mul(px, p_x, zi); + mped25519_mul(py, p_y, zi); + mped25519_mpdump(px, s, 'x'); + mped25519_mpdump(py, s, 'y'); +} +#endif + + +/* scalar multiplication and add: r = s1*p1 + s2*p2 */ +/* needs about 13 + (256 - 32) / 2 = 125 point additions */ +static int +mped25519_scmult2(mp_t *r_x, mp_t *r_y, mp_t *s1, mp_t *p1_x, mp_t * p1_y, mp_t *s2, mp_t *p2_x, mp_t * p2_y) +{ + mp_t p_x[MPED25519_LEN], p_y[MPED25519_LEN], p_z[MPED25519_LEN]; + mp_t pi_z[MPED25519_LEN]; + mp_t tabx[16][MPED25519_LEN], taby[16][MPED25519_LEN], tabz[16][MPED25519_LEN]; + int i, x, dodouble = 0; + + mpzero(MPED25519_LEN, p_x); + mpzero(MPED25519_LEN, p_y); + mpzero(MPED25519_LEN, p_z); + p_y[0] = p_z[0] = 1; + + /* setup table: tab[i * 4 + j] = i * p1 + j * p2 */ + mped25519_ptcpy(tabx[0], taby[0], tabz[0], p_x, p_y, p_z); + for (i = 4; i < 16; i += 4) + mped25519_ptcpy(tabx[i], taby[i], tabz[i], p1_x, p1_y, ed25519_one); + mped25519_ptdouble(tabx[8], taby[8], tabz[8]); + mped25519_ptadd(tabx[12], taby[12], tabz[12], tabx[8], taby[8], tabz[8]); + mped25519_ptcpy(tabx[1], taby[1], tabz[1], p2_x, p2_y, ed25519_one); + for (i = 2; i < 16; i++) + { + if ((i & 3) == 0) + continue; + mped25519_ptcpy(tabx[i], taby[i], tabz[i], tabx[i - 1], taby[i - 1], tabz[i - 1]); + mped25519_ptadd(tabx[i], taby[i], tabz[i], p2_x, p2_y, ed25519_one); + } + /* now do the scalar multiplication */ + for (i = 255; i >= 0; i--) + { + if (dodouble) + mped25519_ptdouble(p_x, p_y, p_z); + x = s1[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 4 : 0; + x |= s2[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 1 : 0; + if (!x) + continue; + if (i > 0) + { + i--; + if (dodouble) + mped25519_ptdouble(p_x, p_y, p_z); + x <<= 1; + x |= s1[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 4 : 0; + x |= s2[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 1 : 0; + } + mped25519_ptadd(p_x, p_y, p_z, tabx[x], taby[x], tabz[x]); + dodouble = 1; + } +#if 0 + mped25519_ptdump(p_x, p_y, p_z, "r = "); +#endif + mped25519_inv(pi_z, p_z); + mped25519_mul(r_x, p_x, pi_z); + mped25519_mul(r_y, p_y, pi_z); + return mpiszero(MPED25519_LEN, p_z) ? 0 : 1; +} + +static void +mped25519_setfromle(int len, mp_t *out, const unsigned char *buf, int bufl, int highmask) +{ + unsigned char bebuf[64]; /* bufl must be <= 64 */ + int i; + for (i = 0; i < bufl; i++) + bebuf[bufl - 1 - i] = buf[i]; + bebuf[0] &= highmask; + mpsetfrombe(len, out, bebuf, bufl); +} + +static int +mped25519(const unsigned char *pub, const unsigned char *sig, const unsigned char *data, unsigned int datal) +{ + unsigned char hbuf[64], rbuf[32]; + int i; + mp_t pub_x[MPED25519_LEN], pub_y[MPED25519_LEN]; + mp_t h[MPED25519_LEN], s[MPED25519_LEN], h2[MPED25519_LEN * 2]; + mp_t r_x[MPED25519_LEN], r_y[MPED25519_LEN]; + Chksum *chk; + + mped25519_setfromle(MPED25519_LEN, s, sig + 32, 32, 0xff); + if (!mpisless(MPED25519_LEN, s, ed25519_l)) + return 0; /* bad s */ + /* uncompress pubkey, we invert the sign to get -pub */ + mped25519_setfromle(MPED25519_LEN, pub_y, pub, 32, 0x7f); + if (!mped25519_recover_x(pub_x, pub_y, pub[31] & 0x80 ? 0 : 1)) + return 0; /* bad pubkey */ +#if 0 + mped25519_mpdump(pub_x, "-pubx = ", 0); + mped25519_mpdump(pub_y, "puby = ", 0); +#endif + /* calculate h = H(sig[0..31]|pub|data) mod l */ + chk = solv_chksum_create(REPOKEY_TYPE_SHA512); + if (!chk) + return 0; + solv_chksum_add(chk, sig, 32); + solv_chksum_add(chk, pub, 32); + solv_chksum_add(chk, data, datal); + solv_chksum_free(chk, hbuf); + mped25519_setfromle(MPED25519_LEN * 2, h2, hbuf, 64, 0xff); + mped25519_reduce512_l(h, h2); +#if 0 + mped25519_mpdump(s, "s = ", 0); + mped25519_mpdump(h, "h = ", 0); +#endif + /* calculate r = s * G - h * pub */ + if (!mped25519_scmult2(r_x, r_y, s, ed25519_gx, ed25519_gy, h, pub_x, pub_y)) + return 0; + /* compress r into rbuf and verify that it matches sig */ + for (i = 0; i < 32; i++) + rbuf[i] = r_y[i / MP_T_BYTES] >> (8 * (i % MP_T_BYTES)); + if ((r_x[0] & 1) != 0) + rbuf[31] |= 0x80; + return memcmp(sig, rbuf, 32) == 0 ? 1 : 0; +} + diff --git a/ext/solv_pgpvrfy.c b/ext/solv_pgpvrfy.c index 9bc256c..8fec835 100644 --- a/ext/solv_pgpvrfy.c +++ b/ext/solv_pgpvrfy.c @@ -1,11 +1,11 @@ /* - * Copyright (c) 2013, SUSE Inc. + * Copyright (c) 2013-2020, SUSE LLC. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information */ -/* simple and slow rsa/dsa verification code. */ +/* simple and slow pgp signature verification code. */ #include #include @@ -14,18 +14,16 @@ #include "util.h" #include "solv_pgpvrfy.h" +#ifndef ENABLE_PGPVRFY_ED25519 +#define ENABLE_PGPVRFY_ED25519 1 +#endif + typedef unsigned int mp_t; typedef unsigned long long mp2_t; #define MP_T_BYTES 4 #define MP_T_BITS (MP_T_BYTES * 8) -static inline void -mpzero(int len, mp_t *target) -{ - memset(target, 0, MP_T_BYTES * len); -} - static inline mp_t * mpnew(int len) { @@ -33,11 +31,58 @@ mpnew(int len) } static inline void +mpzero(int len, mp_t *target) +{ + memset(target, 0, MP_T_BYTES * len); +} + +static inline void mpcpy(int len, mp_t *target, mp_t *source) { memcpy(target, source, len * MP_T_BYTES); } +static void +mpsetfrombe(int len, mp_t *target, const unsigned char *buf, int bufl) +{ + int i, mpl = len * MP_T_BYTES; + buf += bufl; + if (bufl >= mpl) + bufl = mpl; + if (mpl) + memset(target, 0, mpl); + for (i = 0; bufl > 0; bufl--, i++) + target[i / MP_T_BYTES] |= (int)(*--buf) << (8 * (i % MP_T_BYTES)); +} + +static int +mpisless(int len, mp_t *a, mp_t *b) +{ + int i; + for (i = len - 1; i >= 0; i--) + if (a[i] < b[i]) + return 1; + else if (a[i] > b[i]) + return 0; + return 0; +} + +static int +mpisequal(int len, mp_t *a, mp_t *b) +{ + return memcmp(a, b, len * MP_T_BYTES) == 0; +} + +static int +mpiszero(int len, mp_t *a) +{ + int i; + for (i = 0; i < len; i++) + if (a[i]) + return 0; + return 1; +} + #if 0 static void mpdump(int l, mp_t *a, char *s) { @@ -50,6 +95,19 @@ static void mpdump(int l, mp_t *a, char *s) } #endif +/* subtract mod from target. target >= mod */ +static inline void mpsubmod(int len, mp_t *target, mp_t *mod) +{ + int i; + mp2_t n; + for (n = 0, i = 0; i < len; i++) + { + mp2_t n2 = (mp2_t)mod[i] + n; + n = n2 > target[i] ? 1 : 0; + target[i] -= (mp_t)n2; + } +} + /* target[len] = x, target = target % mod * assumes that target < (mod << MP_T_BITS)! */ static void @@ -86,31 +144,13 @@ mpdomod(int len, mp_t *target, mp2_t x, mp_t *mod) x -= n; } target[i] = x; - if (x >= mod[i]) - { - mp_t n; - if (x == mod[i]) - { - for (j = i - 1; j >= 0; j--) - if (target[j] < mod[j]) - return; - else if (target[j] > mod[j]) - break; - } - /* target >= mod, subtract mod */ - n = 0; - for (j = 0; j <= i; j++) - { - mp2_t n2 = mod[j] + n; - n = n2 > target[j] ? 1 : 0; - target[j] -= (mp_t)n2; - } - } + if (x > mod[i] || (x == mod[i] && !mpisless(i, target, mod))) + mpsubmod(i + 1, target, mod); } /* target += src * m */ static void -mpmult_add_int(int len, mp_t *target, mp_t *src, mp2_t m, mp_t *mod) +mpmul_add_int(int len, mp_t *target, mp_t *src, mp2_t m, mp_t *mod) { int i; mp2_t x = 0; @@ -139,7 +179,7 @@ mpshift(int len, mp_t *target, mp_t *mod) /* target += m1 * m2 */ static void -mpmult_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t *mod) +mpmul_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t *mod) { int i, j; for (j = m2len - 1; j >= 0; j--) @@ -151,19 +191,19 @@ mpmult_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t for (i = 0; i < j; i++) { if (m2[i]) - mpmult_add_int(len, target, tmp, m2[i], mod); + mpmul_add_int(len, target, tmp, m2[i], mod); mpshift(len, tmp, mod); } if (m2[i]) - mpmult_add_int(len, target, tmp, m2[i], mod); + mpmul_add_int(len, target, tmp, m2[i], mod); } /* target = target * m */ static void -mpmult_inplace(int len, mp_t *target, mp_t *m, mp_t *tmp1, mp_t *tmp2, mp_t *mod) +mpmul_inplace(int len, mp_t *target, mp_t *m, mp_t *tmp1, mp_t *tmp2, mp_t *mod) { mpzero(len, tmp1); - mpmult_add(len, tmp1, target, len, m, tmp2, mod); + mpmul_add(len, tmp1, target, len, m, tmp2, mod); mpcpy(len, target, tmp1); } @@ -172,15 +212,15 @@ static void mppow_int(int len, mp_t *target, mp_t *t, mp_t *mod, int e) { mp_t *t2 = t + len * 16; - mpmult_inplace(len, target, target, t, t2, mod); - mpmult_inplace(len, target, target, t, t2, mod); - mpmult_inplace(len, target, target, t, t2, mod); - mpmult_inplace(len, target, target, t, t2, mod); + mpmul_inplace(len, target, target, t, t2, mod); + mpmul_inplace(len, target, target, t, t2, mod); + mpmul_inplace(len, target, target, t, t2, mod); + mpmul_inplace(len, target, target, t, t2, mod); if (e) - mpmult_inplace(len, target, t + len * e, t, t2, mod); + mpmul_inplace(len, target, t + len * e, t, t2, mod); } -/* target = b ^ e (b has to be < mod) */ +/* target = b ^ e (b < mod) */ static void mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod) { @@ -196,7 +236,7 @@ mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod) t = mpnew(len * 17); mpcpy(len, t + len, b); for (j = 2; j < 16; j++) - mpmult_add(len, t + len * j, b, len, t + len * j - len, t + len * 16, mod); + mpmul_add(len, t + len * j, b, len, t + len * j - len, t + len * 16, mod); for (; i >= 0; i--) { #if MP_T_BYTES == 4 @@ -216,48 +256,67 @@ mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod) free(t); } -/* target = m1 * m2 (m1 has to be < mod) */ +/* target = m1 * m2 (m1 < mod) */ static void -mpmult(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *mod) +mpmul(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *mod) { mp_t *tmp = mpnew(len); mpzero(len, target); - mpmult_add(len, target, m1, m2len, m2, tmp, mod); + mpmul_add(len, target, m1, m2len, m2, tmp, mod); free(tmp); } -static int -mpisless(int len, mp_t *a, mp_t *b) +static void +mpdec(int len, mp_t *a) { int i; - for (i = len - 1; i >= 0; i--) - if (a[i] < b[i]) - return 1; - else if (a[i] > b[i]) - return 0; - return 0; + for (i = 0; i < len; i++) + if (a[i]--) + return; } -static int -mpiszero(int len, mp_t *a) +#if ENABLE_PGPVRFY_ED25519 +/* target = m1 + m2 (m1, m2 < mod). target may be m1 or m2 */ +static void +mpadd(int len, mp_t *target, mp_t *m1, mp_t *m2, mp_t *mod) { int i; + mp2_t x = 0; for (i = 0; i < len; i++) - if (a[i]) - return 0; - return 1; + { + x += (mp2_t)m1[i] + m2[i]; + target[i] = x; + x >>= MP_T_BITS; + } + if (x || target[len - 1] > mod[len - 1] || + (target[len -1 ] == mod[len - 1] && !mpisless(len - 1, target, mod))) + mpsubmod(len, target, mod); } +/* target = m1 - m2 (m1, m2 < mod). target may be m1 or m2 */ static void -mpdec(int len, mp_t *a) +mpsub(int len, mp_t *target, mp_t *m1, mp_t *m2, mp_t *mod) { int i; + mp2_t x = 0; for (i = 0; i < len; i++) - if (a[i]--) - return; - else - a[i] = -(mp_t)1; + { + x = (mp2_t)m1[i] - m2[i] - x; + target[i] = x; + x = x & ((mp2_t)1 << MP_T_BITS) ? 1 : 0; + } + if (x) + { + for (x = 0, i = 0; i < len; i++) + { + x += (mp2_t)target[i] + mod[i]; + target[i] = x; + x >>= MP_T_BITS; + } + } } +#endif + static int mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int hl, mp_t *h) @@ -266,6 +325,7 @@ mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int mp_t *tmp; mp_t *u1, *u2; mp_t *gu1, *yu2; + int res; #if 0 mpdump(pl, p, "p = "); mpdump(ql, q, "q = "); @@ -286,41 +346,38 @@ mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int mpdec(ql, tmp); /* tmp-- */ mpdec(ql, tmp); /* tmp-- */ w = mpnew(ql); - mppow(ql, w, s, ql, tmp, q); /* w = s ^ tmp (s ^ -1) */ + mppow(ql, w, s, ql, tmp, q); /* w = s ^ tmp = (s ^ -1) */ u1 = mpnew(pl); /* note pl */ /* order is important here: h can be >= q */ - mpmult(ql, u1, w, hl, h, q); /* u1 = w * h */ + mpmul(ql, u1, w, hl, h, q); /* u1 = w * h */ u2 = mpnew(ql); /* u2 = 0 */ - mpmult(ql, u2, w, ql, r, q); /* u2 = w * r */ + mpmul(ql, u2, w, ql, r, q); /* u2 = w * r */ free(w); gu1 = mpnew(pl); yu2 = mpnew(pl); mppow(pl, gu1, g, ql, u1, p); /* gu1 = g ^ u1 */ mppow(pl, yu2, y, ql, u2, p); /* yu2 = y ^ u2 */ - mpmult(pl, u1, gu1, pl, yu2, p); /* u1 = gu1 * yu2 */ + mpmul(pl, u1, gu1, pl, yu2, p); /* u1 = gu1 * yu2 */ free(gu1); free(yu2); mpzero(ql, u2); u2[0] = 1; /* u2 = 1 */ - mpmult(ql, tmp, u2, pl, u1, q); /* tmp = u2 * u1 */ + mpmul(ql, tmp, u2, pl, u1, q); /* tmp = u2 * u1 */ free(u1); free(u2); #if 0 mpdump(ql, tmp, "res = "); #endif - if (memcmp(tmp, r, ql * MP_T_BYTES) != 0) - { - free(tmp); - return 0; - } + res = mpisequal(ql, tmp, r); free(tmp); - return 1; + return res; } static int mprsa(int nl, mp_t *n, int el, mp_t *e, mp_t *m, mp_t *c) { mp_t *tmp; + int res; #if 0 mpdump(nl, n, "n = "); mpdump(el, e, "e = "); @@ -336,34 +393,24 @@ mprsa(int nl, mp_t *n, int el, mp_t *e, mp_t *m, mp_t *c) #if 0 mpdump(nl, tmp, "res = "); #endif - if (memcmp(tmp, c, nl * MP_T_BYTES) != 0) - { - free(tmp); - return 0; - } + res = mpisequal(nl, tmp, c); free(tmp); - return 1; + return res; } +#if ENABLE_PGPVRFY_ED25519 +# include "solv_ed25519.h" +#endif + /* create mp with size tbits from data with size dbits */ static mp_t * mpbuild(const unsigned char *d, int dbits, int tbits, int *mplp) { int l = (tbits + MP_T_BITS - 1) / MP_T_BITS; - int dl, i; - mp_t *out = mpnew(l ? l : 1); if (mplp) *mplp = l; - dl = (dbits + 7) / 8; - d += dl; - if (dbits > tbits) - dl = (tbits + 7) / 8; - for (i = 0; dl > 0; dl--, i++) - { - int x = *--d; - out[i / MP_T_BYTES] |= x << (8 * (i % MP_T_BYTES)); - } + mpsetfrombe(l, out, d, (dbits + 7) / 8); return out; } @@ -390,6 +437,8 @@ findmpi(const unsigned char **mpip, int *mpilp, int maxbits, int *outlen) return mpi + 2; } +/* sig: 0:algo 1:hash 2-:mpidata */ +/* pub: 0:algo 1-:mpidata */ int solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int sigl) { @@ -515,6 +564,36 @@ solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int s free(hx); break; } +#if ENABLE_PGPVRFY_ED25519 + case 22: /* EdDSA */ + { + unsigned char sigdata[64]; + const unsigned char *r, *s; + int rlen, slen; + + /* check the curve */ + if (publ < 11 || memcmp(pub + 1, "\011\053\006\001\004\001\332\107\017\001", 10) != 0) + return 0; /* we only support the Ed25519 curve */ + /* the pubkey always has 7 + 256 bits */ + if (publ != 1 + 10 + 2 + 1 + 32 || pub[1 + 10 + 0] != 1 || pub[1 + 10 + 1] != 7 || pub[1 + 10 + 2] != 0x40) + return 0; + mpi = sig + 2 + hashl; + mpil = sigl - (2 + hashl); + r = findmpi(&mpi, &mpil, 256, &rlen); + s = findmpi(&mpi, &mpil, 256, &slen); + if (!r || !s) + return 0; + memset(sigdata, 0, 64); + rlen = (rlen + 7) / 8; + slen = (slen + 7) / 8; + if (rlen) + memcpy(sigdata + 32 - rlen, r, rlen); + if (slen) + memcpy(sigdata + 64 - slen, s, rlen); + res = mped25519(pub + 1 + 10 + 2 + 1, sigdata, sig + 2, hashl); + break; + } +#endif default: return 0; /* unsupported pubkey algo */ } diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c index 9aab68b..7e974a9 100644 --- a/ext/solv_xfopen.c +++ b/ext/solv_xfopen.c @@ -61,7 +61,15 @@ static FILE *cookieopen(void *cookie, const char *mode, static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes) { - return gzread((gzFile)cookie, buf, nbytes); + ssize_t r = gzread((gzFile)cookie, buf, nbytes); + if (r == 0) + { + int err = 0; + gzerror((gzFile)cookie, &err); + if (err == Z_BUF_ERROR) + r = -1; + } + return r; } static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes) @@ -790,6 +798,7 @@ struct bufcookie { size_t *buflp; char *freemem; size_t bufl_int; + char *buf_int; }; static ssize_t cookie_bufread(void *cookie, char *buf, size_t nbytes) @@ -862,30 +871,48 @@ solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode) return fp; } +FILE * +solv_fmemopen(const char *buf, size_t bufl, const char *mode) +{ + struct bufcookie *bc; + FILE *fp; + if (*mode != 'r') + return 0; + bc = solv_calloc(1, sizeof(*bc)); + bc->buf_int = (char *)buf; + bc->bufl_int = bufl; + bc->bufp = &bc->buf_int; + bc->buflp = &bc->bufl_int; + fp = cookieopen(bc, mode, cookie_bufread, cookie_bufwrite, cookie_bufclose); + if (!strcmp(mode, "rf")) /* auto-free */ + bc->freemem = bc->buf_int; + if (!fp) + cookie_bufclose(bc); + return fp; +} + #else FILE * -solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode) +solv_fmemopen(const char *buf, size_t bufl, const char *mode) { FILE *fp; - size_t l; if (*mode != 'r') return 0; - l = buflp ? *buflp : strlen(*bufp); if (!strcmp(mode, "rf")) { - if (!(fp = fmemopen(0, l, "r+"))) + if (!(fp = fmemopen(0, bufl, "r+"))) return 0; - if (l && fwrite(*bufp, l, 1, fp) != 1) + if (bufl && fwrite(buf, bufl, 1, fp) != 1) { fclose(fp); return 0; } - solv_free(*bufp); + solv_free((char *)buf); rewind(fp); } else - fp = fmemopen(*bufp, l, "r"); + fp = fmemopen((char *)buf, bufl, "r"); return fp; } diff --git a/ext/solv_xfopen.h b/ext/solv_xfopen.h index aa8740e..613f331 100644 --- a/ext/solv_xfopen.h +++ b/ext/solv_xfopen.h @@ -12,5 +12,6 @@ extern FILE *solv_xfopen(const char *fn, const char *mode); extern FILE *solv_xfopen_fd(const char *fn, int fd, const char *mode); extern FILE *solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode); extern int solv_xfopen_iscompressed(const char *fn); +extern FILE *solv_fmemopen(const char *buf, size_t bufl, const char *mode); #endif diff --git a/ext/testcase.c b/ext/testcase.c index d6c4a57..0be7a21 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -1711,7 +1711,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha for (rid = 1; rid < pool->nrels; rid++) { Reldep *rd = pool->rels + rid; - if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS) + if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS || rd->name == NAMESPACE_SPLITPROVIDES) continue; /* evaluate all namespace ids, skip empty results */ d = pool_whatprovides(pool, MAKERELDEP(rid)); @@ -1809,49 +1809,63 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha return 1; } -int -testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname) +const char ** +testcase_mangle_repo_names(Pool *pool) { - Pool *pool = solv->pool; - int i, r, repoid; - int mangle = 1; - const char **orignames; - - /* mangle repo names so that there are no conflicts */ - orignames = solv_calloc(pool->nrepos, sizeof(char *)); - for (repoid = 1; repoid < pool->nrepos; repoid++) + int i, repoid, mangle = 1; + Repo *repo; + const char **names = solv_calloc(pool->nrepos, sizeof(char *)); + FOR_REPOS(repoid, repo) { - Repo *repo = pool_id2repo(pool, repoid); - char *buf = solv_malloc((repo->name ? strlen(repo->name) : 0) + 40); - char *mp; - orignames[repoid] = repo->name; + char *buf, *mp; + buf = solv_malloc((repo->name ? strlen(repo->name) : 0) + 40); if (!repo->name || !repo->name[0]) sprintf(buf, "#%d", repoid); else strcpy(buf, repo->name); - for (i = 0; buf[i]; i++) - if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '/') - buf[i] = '_'; - mp = buf + strlen(buf); - for (;;) - { - for (i = 1; i < repoid; i++) - if (!strcmp(buf, pool_id2repo(pool, i)->name)) - break; - if (i == repoid) - break; + for (mp = buf; *mp; mp++) + if (*mp == ' ' || *mp == '\t' || *mp == '/') + *mp = '_'; + for (i = 1; i < repoid; i++) + { + if (!names[i] || strcmp(buf, names[i]) != 0) + continue; sprintf(mp, "_%d", mangle++); + i = 0; /* restart conflict check */ } - repo->name = buf; + names[repoid] = buf; } - r = testcase_write_mangled(solv, dir, resultflags, testcasename, resultname); - for (repoid = 1; repoid < pool->nrepos; repoid++) + return names; +} + +static void +swap_repo_names(Pool *pool, const char **names) +{ + int repoid; + Repo *repo; + FOR_REPOS(repoid, repo) { - Repo *repo = pool_id2repo(pool, repoid); - solv_free((void *)repo->name); - repo->name = orignames[repoid]; + const char *n = repo->name; + repo->name = names[repoid]; + names[repoid] = n; } - solv_free(orignames); +} + +int +testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname) +{ + Pool *pool = solv->pool; + int r, repoid; + const char **names; + + /* mangle repo names so that there are no conflicts */ + names = testcase_mangle_repo_names(pool); + swap_repo_names(pool, names); + r = testcase_write_mangled(solv, dir, resultflags, testcasename, resultname); + swap_repo_names(pool, names); + for (repoid = 1; repoid < pool->nrepos; repoid++) + solv_free((void *)names[repoid]); + solv_free((void *)names); return r; } @@ -2071,7 +2085,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res { char *idata = read_inline_file(fp, &buf, &bufp, &bufl); rdata = ""; - rfp = solv_xfopen_buf(rdata, &idata, 0, "rf"); + rfp = solv_fmemopen(idata, strlen(idata), "rf"); } else { diff --git a/ext/testcase.h b/ext/testcase.h index 997feaf..5b2e573 100644 --- a/ext/testcase.h +++ b/ext/testcase.h @@ -42,3 +42,5 @@ extern char *testcase_solverresult(Solver *solv, int flags); extern int testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname); extern Solver *testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **resultp, int *resultflagsp); extern char *testcase_resultdiff(const char *result1, const char *result2); +extern const char **testcase_mangle_repo_names(Pool *pool); + diff --git a/package/libsolv.changes b/package/libsolv.changes index 253784b..2f4bfe3 100644 --- a/package/libsolv.changes +++ b/package/libsolv.changes @@ -1,4 +1,64 @@ ------------------------------------------------------------------- +Tue Oct 20 12:04:00 CEST 2020 - mls@suse.de + +- do not ask the namespace callback for splitprovides when writing + a testcase +- fix add_complex_recommends() selecting conflicted packages in + rare cases leading to crashes +- improve choicerule generation so that package updates are + prefered in more cases +- bump version to 0.7.16 + +------------------------------------------------------------------- +Mon Oct 5 13:06:44 CEST 2020 - mls@suse.de + +- make testcase_mangle_repo_names deal correctly with freed repos + [bnc#1177238] + +------------------------------------------------------------------- +Fri Sep 11 12:31:27 CEST 2020 - mls@suse.de + +- fix deduceq2addedmap clearing bits outside of the map +- conda: feature depriorization first +- conda: fix startswith implementation +- move find_update_seeds() call in cleandeps calculation +- set SOLVABLE_BUILDHOST in rpm and rpmmd parsers +- new testcase_mangle_repo_names() function +- new solv_fmemopen() function +- bump version to 0.7.15 + +------------------------------------------------------------------- +Tue Jun 23 12:43:16 CEST 2020 - ma@suse.de + +- Enable zstd compression support for sle15 + +------------------------------------------------------------------- +Thu May 28 11:51:27 CEST 2020 - mls@suse.de + +- Enable zstd compression support for sle15-sp2 + +------------------------------------------------------------------- +Wed May 27 11:48:46 CEST 2020 - mls@suse.de + +- Support blacklisted packages in solver_findproblemrule() + [bnc#1172135] +- Support rules with multiple negative literals in choice rule + generation +- bump version to 0.7.14 + +------------------------------------------------------------------- +Fri Apr 24 12:00:30 CEST 2020 - mls@suse.de + +- Fix solvable swapping messing up idarrays +- bump version to 0.7.13 + +------------------------------------------------------------------- +Mon Apr 20 17:24:21 CEST 2020 - mls@suse.de + +- fix ruleinfo of complex dependencies returning the wrong origin +- bump version to 0.7.12 + +------------------------------------------------------------------- Wed Jan 22 13:52:48 CET 2020 - mls@suse.de - fixed solv_zchunk decoding error if large chunks are used diff --git a/package/libsolv.spec.in b/package/libsolv.spec.in index cd56c67..0964ad6 100644 --- a/package/libsolv.spec.in +++ b/package/libsolv.spec.in @@ -24,7 +24,7 @@ %bcond_with bz2 %bcond_with xz %endif -%if 0%{?is_opensuse} && (0%{?sle_version} >= 150000 || 0%{?suse_version} >= 1500) +%if 0%{?sle_version} >= 150000 || 0%{?suse_version} >= 1500 %bcond_without zstd %else %bcond_with zstd diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6abb3ad..bbf30ba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,11 +48,19 @@ SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,- ENDIF (HAVE_LINKER_VERSION_SCRIPT) IF (DISABLE_SHARED) -ADD_LIBRARY (libsolv STATIC ${libsolv_SRCS}) + ADD_LIBRARY (libsolv STATIC ${libsolv_SRCS}) ELSE (DISABLE_SHARED) -ADD_LIBRARY (libsolv SHARED ${libsolv_SRCS}) + ADD_LIBRARY (libsolv SHARED ${libsolv_SRCS}) ENDIF (DISABLE_SHARED) +IF (WIN32) + IF (DISABLE_SHARED) + TARGET_COMPILE_DEFINITIONS(libsolv PUBLIC SOLV_STATIC_LIB) + ELSE (DISABLE_SHARED) + TARGET_COMPILE_DEFINITIONS(libsolv PRIVATE SOLV_EXPORTS) + ENDIF (DISABLE_SHARED) +ENDIF (WIN32) + SET_TARGET_PROPERTIES(libsolv PROPERTIES OUTPUT_NAME "solv") SET_TARGET_PROPERTIES(libsolv PROPERTIES SOVERSION ${LIBSOLV_SOVERSION}) diff --git a/src/cleandeps.c b/src/cleandeps.c index aa83c10..31b1ad9 100644 --- a/src/cleandeps.c +++ b/src/cleandeps.c @@ -669,6 +669,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) queue_init(&iq); queue_init(&xsuppq); + /* setup userinstalled map and search for special namespace cleandeps erases */ for (i = 0; i < job->count; i += 2) { how = job->elements[i]; @@ -874,23 +875,38 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) } queue_init_clone(&iqcopy, &iq); - if (!unneeded) - { - if (solv->cleandeps_updatepkgs) - for (i = 0; i < solv->cleandeps_updatepkgs->count; i++) - queue_push(&iq, solv->cleandeps_updatepkgs->elements[i]); - } - if (unneeded) queue_empty(&iq); /* just in case... */ - /* clear userinstalled bit for the packages we really want to delete/update */ + /* clear userinstalled bits for the packages we really want to delete */ for (i = 0; i < iq.count; i++) { p = iq.elements[i]; - if (pool->solvables[p].repo != installed) - continue; - MAPCLR(&userinstalled, p - installed->start); + if (pool->solvables[p].repo == installed) + MAPCLR(&userinstalled, p - installed->start); + } + /* set userinstalled bits for all packages not in the considered map */ + if (pool->considered) + { + for (p = installed->start; p < installed->end; p++) + if (!MAPTST(pool->considered, p)) + MAPSET(&userinstalled, p - installed->start); /* we may not remove those */ + } + if (!unneeded && solv->cleandeps_updatepkgs) + { + /* find update seeds */ + queue_init(&updatepkgs_filtered); + find_update_seeds(solv, &updatepkgs_filtered, &userinstalled); + /* clear userinstalled bit for the packages we want to update */ + /* also add them to the erase list */ + for (i = 0; i < solv->cleandeps_updatepkgs->count; i++) + { + p = solv->cleandeps_updatepkgs->elements[i]; + if (pool->considered && !MAPTST(pool->considered, p)) + continue; + queue_push(&iq, p); + MAPCLR(&userinstalled, p - installed->start); + } } for (p = installed->start; p < installed->end; p++) @@ -898,8 +914,6 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) if (pool->solvables[p].repo != installed) continue; MAPSET(&installedm, p); - if (pool->considered && !MAPTST(pool->considered, p)) - MAPSET(&userinstalled, p - installed->start); /* we may not remove those */ if (unneeded && !MAPTST(&userinstalled, p - installed->start)) continue; MAPSET(&im, p); @@ -907,13 +921,6 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) MAPSET(&installedm, SYSTEMSOLVABLE); MAPSET(&im, SYSTEMSOLVABLE); - if (!unneeded && solv->cleandeps_updatepkgs) - { - /* find update "seeds" */ - queue_init(&updatepkgs_filtered); - find_update_seeds(solv, &updatepkgs_filtered, &userinstalled); - } - #ifdef CLEANDEPSDEBUG printf("REMOVE PASS\n"); #endif diff --git a/src/conda.c b/src/conda.c index 7f2538a..21ad6bf 100644 --- a/src/conda.c +++ b/src/conda.c @@ -212,7 +212,7 @@ pool_evrcmp_conda_int(const char *evr1, const char *evr1e, const char *evr2, con r = solv_vercmp_conda(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2, r2 ? 0 : startswith); if (r) return r; - if (!r1 && !r2) + if ((!r2 && startswith) || (!r1 && !r2)) return 0; if (!r1 && r2) return -1; diff --git a/src/knownid.h b/src/knownid.h index 96c9adf..4c1730b 100644 --- a/src/knownid.h +++ b/src/knownid.h @@ -266,6 +266,7 @@ KNOWNID(UPDATE_STATUS, "update:status"), /* "stable", "testing", ...*/ KNOWNID(LIBSOLV_SELF_DESTRUCT_PKG, "libsolv-self-destruct-pkg()"), /* this package will self-destruct on installation */ KNOWNID(SOLVABLE_CONSTRAINS, "solvable:constrains"), /* conda */ +KNOWNID(SOLVABLE_TRACK_FEATURES, "solvable:track_features"), /* conda */ KNOWNID(ID_NUM_INTERNAL, 0) diff --git a/src/policy.c b/src/policy.c index 10a2c4d..c02d237 100644 --- a/src/policy.c +++ b/src/policy.c @@ -833,11 +833,22 @@ move_installed_to_front(Pool *pool, Queue *plist) } } +#ifdef ENABLE_CONDA +static int +pool_featurecountcmp(Pool *pool, Solvable *s1, Solvable *s2) +{ + unsigned int cnt1, cnt2; + cnt1 = solvable_lookup_count(s1, SOLVABLE_TRACK_FEATURES); + cnt2 = solvable_lookup_count(s2, SOLVABLE_TRACK_FEATURES); + return cnt1 == cnt2 ? 0 : cnt1 > cnt2 ? -1 : 1; +} + static int pool_buildversioncmp(Pool *pool, Solvable *s1, Solvable *s2) { - const char *bv1 = solvable_lookup_str(s1, SOLVABLE_BUILDVERSION); - const char *bv2 = solvable_lookup_str(s2, SOLVABLE_BUILDVERSION); + const char *bv1, *bv2; + bv1 = solvable_lookup_str(s1, SOLVABLE_BUILDVERSION); + bv2 = solvable_lookup_str(s2, SOLVABLE_BUILDVERSION); if (!bv1 && !bv2) return 0; return pool_evrcmp_str(pool, bv1 ? bv1 : "" , bv2 ? bv2 : "", EVRCMP_COMPARE); @@ -852,6 +863,7 @@ pool_buildflavorcmp(Pool *pool, Solvable *s1, Solvable *s2) return 0; return pool_evrcmp_str(pool, f1 ? f1 : "" , f2 ? f2 : "", EVRCMP_COMPARE); } +#endif /* * prune_to_best_version @@ -895,15 +907,29 @@ prune_to_best_version(Pool *pool, Queue *plist) best = s; /* take current as new best */ continue; } - r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0; + + r = 0; +#ifdef ENABLE_CONDA + if (pool->disttype == DISTTYPE_CONDA) + r = pool_featurecountcmp(pool, best, s); +#endif + if (r == 0) + r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0; #ifdef ENABLE_LINKED_PKGS if (r == 0 && has_package_link(pool, s)) r = pool_link_evrcmp(pool, best, s); #endif - if (r == 0 && pool->disttype == DISTTYPE_CONDA) - r = pool_buildversioncmp(pool, best, s); - if (r == 0 && pool->disttype == DISTTYPE_CONDA) - r = pool_buildflavorcmp(pool, best, s); +#ifdef ENABLE_CONDA + if (pool->disttype == DISTTYPE_CONDA) + { + if (r == 0) + r = (best->repo ? best->repo->subpriority : 0) - (s->repo ? s->repo->subpriority : 0); + if (r == 0) + r = pool_buildversioncmp(pool, best, s); + if (r == 0) + r = pool_buildflavorcmp(pool, best, s); + } +#endif if (r < 0) best = s; } diff --git a/src/problems.c b/src/problems.c index 63165f3..a6b9394 100644 --- a/src/problems.c +++ b/src/problems.c @@ -1068,10 +1068,10 @@ solver_take_solution(Solver *solv, Id problem, Id solution, Queue *job) */ static void -findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Map *rseen) +findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Id *blkrp, Map *rseen) { Id rid, d; - Id lreqr, lconr, lsysr, ljobr; + Id lreqr, lconr, lsysr, ljobr, lblkr; Rule *r; Id jobassert = 0; int i, reqset = 0; /* 0: unset, 1: installed, 2: jobassert, 3: assert */ @@ -1093,7 +1093,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, /* the problem rules are somewhat ordered from "near to the problem" to * "near to the job" */ - lreqr = lconr = lsysr = ljobr = 0; + lreqr = lconr = lsysr = ljobr = lblkr = 0; while ((rid = solv->learnt_pool.elements[idx++]) != 0) { assert(rid > 0); @@ -1102,9 +1102,9 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, if (MAPTST(rseen, rid - solv->learntrules)) continue; MAPSET(rseen, rid - solv->learntrules); - findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, rseen); + findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, &lblkr, rseen); } - else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end) || (rid >= solv->yumobsrules && rid <= solv->yumobsrules_end)) + else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end) || (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)) { if (!*jobrp) *jobrp = rid; @@ -1114,6 +1114,11 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, if (!*sysrp) *sysrp = rid; } + else if (rid >= solv->blackrules && rid < solv->blackrules_end) + { + if (!*blkrp) + *blkrp = rid; + } else { assert(rid < solv->pkgrules_end); @@ -1176,6 +1181,8 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, *jobrp = ljobr; if (!*sysrp && lsysr) *sysrp = lsysr; + if (!*blkrp && lblkr) + *blkrp = lblkr; } /* @@ -1190,12 +1197,12 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id solver_findproblemrule(Solver *solv, Id problem) { - Id reqr, conr, sysr, jobr; + Id reqr, conr, sysr, jobr, blkr; Id idx = solv->problems.elements[2 * problem - 2]; Map rseen; - reqr = conr = sysr = jobr = 0; + reqr = conr = sysr = jobr = blkr = 0; map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0); - findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &rseen); + findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &blkr, &rseen); map_free(&rseen); /* check if the request is about a not-installed package requiring a installed * package conflicting with the non-installed package. In that case return the conflict */ @@ -1223,6 +1230,8 @@ solver_findproblemrule(Solver *solv, Id problem) return reqr; /* some requires */ if (conr) return conr; /* some conflict */ + if (blkr) + return blkr; /* a blacklisted package */ if (sysr) return sysr; /* an update rule */ if (jobr) diff --git a/src/repo.c b/src/repo.c index da40219..b266d8d 100644 --- a/src/repo.c +++ b/src/repo.c @@ -213,6 +213,8 @@ repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids) int j; for (j = dstart; j < dend; j++) data->attrs[j - data->start] = solv_free(data->attrs[j - data->start]); + if (data->lasthandle >= dstart && data->lasthandle < dend) + data->lasthandle = 0; } if (data->incoreoffset) memset(data->incoreoffset + (dstart - data->start), 0, (dend - dstart) * sizeof(Id)); @@ -737,6 +739,32 @@ domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida) } } +static Offset * +solvable_offsetptr(Solvable *s, Id keyname) +{ + switch(keyname) + { + case SOLVABLE_PROVIDES: + return &s->provides; + case SOLVABLE_OBSOLETES: + return &s->obsoletes; + case SOLVABLE_CONFLICTS: + return &s->conflicts; + case SOLVABLE_REQUIRES: + return &s->requires; + case SOLVABLE_RECOMMENDS: + return &s->recommends; + case SOLVABLE_SUGGESTS: + return &s->suggests; + case SOLVABLE_SUPPLEMENTS: + return &s->supplements; + case SOLVABLE_ENHANCES: + return &s->enhances; + default: + return 0; + } +} + static void repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md) { @@ -1131,18 +1159,6 @@ repo_lookup_id(Repo *repo, Id entry, Id keyname) return 0; } -static int -lookup_idarray_solvable(Repo *repo, Offset off, Queue *q) -{ - Id *p; - - queue_empty(q); - if (off) - for (p = repo->idarraydata + off; *p; p++) - queue_push(q, *p); - return 1; -} - int repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q) { @@ -1150,24 +1166,25 @@ repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q) int i; if (entry >= 0) { + Offset *offp; switch (keyname) { case SOLVABLE_PROVIDES: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].provides, q); case SOLVABLE_OBSOLETES: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].obsoletes, q); case SOLVABLE_CONFLICTS: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].conflicts, q); case SOLVABLE_REQUIRES: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].requires, q); case SOLVABLE_RECOMMENDS: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].recommends, q); case SOLVABLE_SUGGESTS: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].suggests, q); case SOLVABLE_SUPPLEMENTS: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].supplements, q); case SOLVABLE_ENHANCES: - return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q); + offp = solvable_offsetptr(repo->pool->solvables + entry, keyname); + if (*offp) + { + Id *p; + for (p = repo->idarraydata + *offp; *p; p++) + queue_push(q, *p); + } + return 1; } } data = repo_lookup_repodata_opt(repo, entry, keyname); @@ -1270,6 +1287,37 @@ repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp) return 0; } +unsigned int +repo_lookup_count(Repo *repo, Id entry, Id keyname) +{ + Repodata *data; + if (keyname >= SOLVABLE_NAME && keyname <= RPM_RPMDBID) + if (entry >= 0 && keyname >= SOLVABLE_NAME && keyname <= RPM_RPMDBID) + { + Id *p; + Offset *offp; + unsigned int cnt; + switch (keyname) + { + case SOLVABLE_PROVIDES: + case SOLVABLE_OBSOLETES: + case SOLVABLE_CONFLICTS: + case SOLVABLE_REQUIRES: + case SOLVABLE_RECOMMENDS: + case SOLVABLE_SUGGESTS: + case SOLVABLE_SUPPLEMENTS: + case SOLVABLE_ENHANCES: + offp = solvable_offsetptr(repo->pool->solvables + entry, keyname); + for (cnt = 0, p = repo->idarraydata + *offp; *p; p++) + cnt++; + return cnt; + } + return 1; + } + data = repo_lookup_repodata_opt(repo, entry, keyname); + return data ? repodata_lookup_count(data, entry, keyname) : 0; +} + /***********************************************************************/ Repodata * @@ -1429,32 +1477,19 @@ repo_add_deparray(Repo *repo, Id p, Id keyname, Id dep, Id marker) marker = solv_depmarker(keyname, marker); if (p >= 0) { - Solvable *s = repo->pool->solvables + p; + Offset *offp; switch (keyname) { case SOLVABLE_PROVIDES: - s->provides = repo_addid_dep(repo, s->provides, dep, marker); - return; case SOLVABLE_OBSOLETES: - s->obsoletes = repo_addid_dep(repo, s->obsoletes, dep, marker); - return; case SOLVABLE_CONFLICTS: - s->conflicts = repo_addid_dep(repo, s->conflicts, dep, marker); - return; case SOLVABLE_REQUIRES: - s->requires = repo_addid_dep(repo, s->requires, dep, marker); - return; case SOLVABLE_RECOMMENDS: - s->recommends = repo_addid_dep(repo, s->recommends, dep, marker); - return; case SOLVABLE_SUGGESTS: - s->suggests = repo_addid_dep(repo, s->suggests, dep, marker); - return; case SOLVABLE_SUPPLEMENTS: - s->supplements = repo_addid_dep(repo, s->supplements, dep, marker); - return; case SOLVABLE_ENHANCES: - s->enhances = repo_addid_dep(repo, s->enhances, dep, marker); + offp = solvable_offsetptr(repo->pool->solvables + p, keyname); + *offp = repo_addid_dep(repo, *offp, dep, marker); return; } } @@ -1468,16 +1503,6 @@ repo_add_idarray(Repo *repo, Id p, Id keyname, Id id) repo_add_deparray(repo, p, keyname, id, 0); } -static Offset -repo_set_idarray_solvable(Repo *repo, Queue *q) -{ - Offset o = 0; - int i; - for (i = 0; i < q->count; i++) - repo_addid_dep(repo, o, q->elements[i], 0); - return o; -} - void repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker) { @@ -1512,32 +1537,23 @@ repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker) } if (p >= 0) { - Solvable *s = repo->pool->solvables + p; + Offset off, *offp; + int i; switch (keyname) { case SOLVABLE_PROVIDES: - s->provides = repo_set_idarray_solvable(repo, q); - return; case SOLVABLE_OBSOLETES: - s->obsoletes = repo_set_idarray_solvable(repo, q); - return; case SOLVABLE_CONFLICTS: - s->conflicts = repo_set_idarray_solvable(repo, q); - return; case SOLVABLE_REQUIRES: - s->requires = repo_set_idarray_solvable(repo, q); - return; case SOLVABLE_RECOMMENDS: - s->recommends = repo_set_idarray_solvable(repo, q); - return; case SOLVABLE_SUGGESTS: - s->suggests = repo_set_idarray_solvable(repo, q); - return; case SOLVABLE_SUPPLEMENTS: - s->supplements = repo_set_idarray_solvable(repo, q); - return; case SOLVABLE_ENHANCES: - s->enhances = repo_set_idarray_solvable(repo, q); + off = 0; + for (i = 0; i < q->count; i++) + off = repo_addid_dep(repo, off, q->elements[i], 0); + offp = solvable_offsetptr(repo->pool->solvables + p, keyname); + *offp = off; return; } } diff --git a/src/repo.h b/src/repo.h index 9a5e981..b503431 100644 --- a/src/repo.h +++ b/src/repo.h @@ -189,6 +189,7 @@ int repo_lookup_void(Repo *repo, Id entry, Id keyname); const char *repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep); const unsigned char *repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep); const void *repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp); +unsigned int repo_lookup_count(Repo *repo, Id entry, Id keyname); /* internal */ Id solv_depmarker(Id keyname, Id marker); void repo_set_id(Repo *repo, Id p, Id keyname, Id id); diff --git a/src/repodata.c b/src/repodata.c index 3cae0fe..72f03d4 100644 --- a/src/repodata.c +++ b/src/repodata.c @@ -388,7 +388,7 @@ repodata_dir2str(Repodata *data, Id did, const char *suf) comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp); l = strlen(comps); p -= l; - strncpy(p, comps, l); + memcpy(p, comps, l); parent = dirpool_parent(&data->dirpool, parent); if (parent) *--p = '/'; @@ -841,6 +841,57 @@ repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp) return dp; } +unsigned int +repodata_lookup_count(Repodata *data, Id solvid, Id keyname) +{ + unsigned char *dp; + Repokey *key; + unsigned int cnt = 0; + + dp = find_key_data(data, solvid, keyname, &key); + if (!dp) + return 0; + switch (key->type) + { + case REPOKEY_TYPE_IDARRAY: + case REPOKEY_TYPE_REL_IDARRAY: + for (cnt = 1; (*dp & 0xc0) != 0; dp++) + if ((*dp & 0xc0) == 0x40) + cnt++; + return cnt; + case REPOKEY_TYPE_FIXARRAY: + case REPOKEY_TYPE_FLEXARRAY: + data_read_id(dp, (int *)&cnt); + return cnt; + case REPOKEY_TYPE_DIRSTRARRAY: + for (;;) + { + cnt++; + while (*dp & 0x80) + dp++; + if (!(*dp++ & 0x40)) + return cnt; + dp += strlen((const char *)dp) + 1; + } + case REPOKEY_TYPE_DIRNUMNUMARRAY: + for (;;) + { + cnt++; + while (*dp++ & 0x80) + ; + while (*dp++ & 0x80) + ; + while (*dp & 0x80) + dp++; + if (!(*dp++ & 0x40)) + return cnt; + } + default: + break; + } + return 1; +} + /* highly specialized function to speed up fileprovides adding. * - repodata must be available * - solvid must be >= data->start and < data->end @@ -3049,6 +3100,8 @@ repodata_swap_attrs(Repodata *data, Id dest, Id src) tmpattrs = data->attrs[dest - data->start]; data->attrs[dest - data->start] = data->attrs[src - data->start]; data->attrs[src - data->start] = tmpattrs; + if (data->lasthandle == src || data->lasthandle == dest) + data->lasthandle = 0; } diff --git a/src/repodata.h b/src/repodata.h index f204e34..7dd5259 100644 --- a/src/repodata.h +++ b/src/repodata.h @@ -229,6 +229,7 @@ int repodata_lookup_void(Repodata *data, Id solvid, Id keyname); const unsigned char *repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep); int repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q); const void *repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp); +unsigned int repodata_lookup_count(Repodata *data, Id solvid, Id keyname); /* internal */ /* internal, used in fileprovides code */ const unsigned char *repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname); diff --git a/src/rules.c b/src/rules.c index f735e5d..6c8e82b 100644 --- a/src/rules.c +++ b/src/rules.c @@ -613,7 +613,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w } else { - Id *qele; + Id *qele, d; int qcnt; qele = bq.elements + i; @@ -653,7 +653,17 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w break; if (j < qcnt) continue; - addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep); + d = pool_ids2whatprovides(pool, qele + 1, qcnt - 1); + if (solv->ruleinfoq && qele[0] != p) + { + int oldcount = solv->ruleinfoq->count; + addpkgrule(solv, qele[0], 0, d, type, dep); + /* fixup from element of ruleinfo */ + if (solv->ruleinfoq->count > oldcount) + solv->ruleinfoq->elements[oldcount + 1] = p; + } + else + addpkgrule(solv, qele[0], 0, d, type, dep); if (m) for (j = 0; j < qcnt; j++) if (qele[j] > 0 && !MAPTST(m, qele[j])) @@ -2729,7 +2739,8 @@ addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep) if (*odp) return; } - if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS) + /* set p2 for multiversion conflicts */ + if (p < 0 && pool->whatprovidesdata[d] < 0 && pool->whatprovidesdata[d + 1] >= 0 && type == SOLVER_RULE_PKG_CONFLICTS) p2 = pool->whatprovidesdata[d]; } else @@ -3176,6 +3187,44 @@ solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q) return 1; /* none of the new packages provided it */ } +static int +solver_choicerulecheck2(Solver *solv, Id pi, Id pt, Queue *q) +{ + Pool *pool = solv->pool; + Rule *ur; + Id p, pp; + int i; + + if (!q->count || q->elements[0] != pi) + { + if (q->count) + queue_empty(q); + ur = solv->rules + solv->updaterules + (pi - pool->installed->start); + if (!ur->p) + ur = solv->rules + solv->featurerules + (pi - pool->installed->start); + if (!ur->p) + return 0; + queue_push2(q, pi, 0); + FOR_RULELITERALS(p, pp, ur) + if (p > 0 && p != pi) + queue_push(q, p); + queue_push(q, pi); + } + if (q->count <= 3) + return q->count == 3 && q->elements[2] == pt ? 1 : 0; + if (!q->elements[1]) + { + queue_deleten(q, 0, 2); + policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE); + queue_unshift(q, 1); /* filter mark */ + queue_unshift(q, pi); + } + for (i = 2; i < q->count; i++) + if (q->elements[i] == pt) + return 1; + return 0; /* not newest */ +} + static inline void queue_removeelement(Queue *q, Id el) { @@ -3192,20 +3241,62 @@ queue_removeelement(Queue *q, Id el) } } +static Id +choicerule_find_installed(Pool *pool, Id p) +{ + Solvable *s = pool->solvables + p; + Id p2, pp2; + + if (!s->repo) + return 0; + if (s->repo == pool->installed) + return p; + FOR_PROVIDES(p2, pp2, s->name) + { + Solvable *s2 = pool->solvables + p2; + if (s2->repo != pool->installed) + continue; + if (!pool->implicitobsoleteusesprovides && s->name != s2->name) + continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) + continue; + return p2; + } + if (s->obsoletes) + { + Id obs, *obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + { + FOR_PROVIDES(p2, pp2, obs) + { + Solvable *s2 = pool->solvables + p2; + if (s2->repo != pool->installed) + continue; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) + continue; + return p2; + } + } + } + return 0; +} + void solver_addchoicerules(Solver *solv) { Pool *pool = solv->pool; Map m, mneg; Rule *r; - Queue q, qi, qcheck, infoq; - int i, j, rid, havechoice; - Id p, d, pp; - Id p2, pp2; - Solvable *s, *s2; + Queue q, qi, qcheck, qcheck2, infoq; + int i, j, rid, havechoice, negcnt; + Id p, d, pp, p2; + Solvable *s; Id lastaddedp, lastaddedd; int lastaddedcnt; unsigned int now; + int isnewest = 0; solv->choicerules = solv->nrules; if (!pool->installed) @@ -3218,6 +3309,7 @@ solver_addchoicerules(Solver *solv) queue_init(&q); queue_init(&qi); queue_init(&qcheck); + queue_init(&qcheck2); queue_init(&infoq); map_init(&m, pool->nsolvables); map_init(&mneg, pool->nsolvables); @@ -3249,80 +3341,28 @@ solver_addchoicerules(Solver *solv) continue; if (s->repo == pool->installed) { + queue_push2(&qi, p, p); queue_push(&q, p); continue; } - /* check if this package is "blocked" by a installed package */ - s2 = 0; - FOR_PROVIDES(p2, pp2, s->name) - { - s2 = pool->solvables + p2; - if (s2->repo != pool->installed) - continue; - if (!pool->implicitobsoleteusesprovides && s->name != s2->name) - continue; - if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) - continue; - break; - } + /* find an installed package p2 that we can update/downgrade to p */ + p2 = choicerule_find_installed(pool, p); if (p2) { - /* found installed package p2 that we can update to p */ if (MAPTST(&mneg, p)) continue; - if (policy_is_illegal(solv, s2, s, 0)) + if (policy_is_illegal(solv, pool->solvables + p2, s, 0)) continue; -#if 0 - if (solver_choicerulecheck(solv, p2, r, &m)) - continue; - queue_push(&qi, p2); -#else queue_push2(&qi, p2, p); -#endif queue_push(&q, p); continue; } - if (s->obsoletes) - { - Id obs, *obsp = s->repo->idarraydata + s->obsoletes; - s2 = 0; - while ((obs = *obsp++) != 0) - { - FOR_PROVIDES(p2, pp2, obs) - { - s2 = pool->solvables + p2; - if (s2->repo != pool->installed) - continue; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) - continue; - break; - } - if (p2) - break; - } - if (obs) - { - /* found installed package p2 that we can update to p */ - if (MAPTST(&mneg, p)) - continue; - if (policy_is_illegal(solv, s2, s, 0)) - continue; -#if 0 - if (solver_choicerulecheck(solv, p2, r, &m)) - continue; - queue_push(&qi, p2); -#else - queue_push2(&qi, p2, p); -#endif - queue_push(&q, p); - continue; - } - } /* package p is independent of the installed ones */ havechoice = 1; } +#if 0 + printf("havechoice: %d qcount %d qicount %d\n", havechoice, q.count, qi.count); +#endif if (!havechoice || !q.count || !qi.count) continue; /* no choice */ @@ -3330,13 +3370,25 @@ solver_addchoicerules(Solver *solv) if (p > 0) MAPSET(&m, p); + isnewest = 1; + FOR_RULELITERALS(p, pp, r) + { + if (p > 0) + break; + p2 = choicerule_find_installed(pool, -p); + if (p2 && !solver_choicerulecheck2(solv, p2, -p, &qcheck2)) + { + isnewest = 0; + break; + } + } /* do extra checking */ for (i = j = 0; i < qi.count; i += 2) { p2 = qi.elements[i]; if (!p2) continue; - if (solver_choicerulecheck(solv, p2, r, &m, &qcheck)) + if (isnewest && solver_choicerulecheck(solv, p2, r, &m, &qcheck)) { /* oops, remove element p from q */ queue_removeelement(&q, qi.elements[i + 1]); @@ -3378,9 +3430,12 @@ solver_addchoicerules(Solver *solv) qi.elements[j] = 0; } /* empty map again */ + negcnt = 0; FOR_RULELITERALS(p, pp, r) if (p > 0) MAPCLR(&m, p); + else + negcnt++; if (i == qi.count) { #if 0 @@ -3389,7 +3444,14 @@ solver_addchoicerules(Solver *solv) #endif continue; } - + /* add neg elements to the front */ + if (negcnt > 1) + { + i = 0; + FOR_RULELITERALS(p, pp, r) + if (p < 0 && p != r->p) + queue_insert(&q, i++, p); + } /* don't add identical rules */ if (lastaddedp == r->p && lastaddedcnt == q.count) { @@ -3420,6 +3482,7 @@ solver_addchoicerules(Solver *solv) queue_free(&q); queue_free(&qi); queue_free(&qcheck); + queue_free(&qcheck2); queue_free(&infoq); map_free(&m); map_free(&mneg); diff --git a/src/selection.c b/src/selection.c index 5f01e2b..a8e60f7 100644 --- a/src/selection.c +++ b/src/selection.c @@ -150,6 +150,7 @@ selection_flatten(Pool *pool, Queue *selection) if (!q.count) { queue_empty(selection); + queue_free(&q); return; } queue_truncate(selection, 2); @@ -163,6 +164,7 @@ selection_flatten(Pool *pool, Queue *selection) selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; selection->elements[1] = q.elements[0]; } + queue_free(&q); } /* only supports simple rels plus REL_ARCH */ diff --git a/src/solvable.c b/src/solvable.c index 474e6f5..181d9bc 100644 --- a/src/solvable.c +++ b/src/solvable.c @@ -323,6 +323,12 @@ solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep) return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0; } +unsigned int +solvable_lookup_count(Solvable *s, Id keyname) +{ + return s->repo ? repo_lookup_count(s->repo, s - s->repo->pool->solvables, keyname) : 0; +} + static inline const char * evrid2vrstr(Pool *pool, Id evrid) { diff --git a/src/solvable.h b/src/solvable.h index 7788e7c..0298db4 100644 --- a/src/solvable.h +++ b/src/solvable.h @@ -64,6 +64,7 @@ const unsigned char *solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *t const char *solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep); int solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q); int solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker); +unsigned int solvable_lookup_count(Solvable *s, Id keyname); /* internal */ /* setter functions */ void solvable_set_id(Solvable *s, Id keyname, Id id); diff --git a/src/solver.c b/src/solver.c index 7fcc3fb..9c02cc7 100644 --- a/src/solver.c +++ b/src/solver.c @@ -1198,7 +1198,7 @@ createbranch(Solver *solv, int level, Queue *dq, Id p, Id data) int i; IF_POOLDEBUG (SOLV_DEBUG_POLICY) { - POOL_DEBUG (SOLV_DEBUG_POLICY, "creating a branch:\n"); + POOL_DEBUG (SOLV_DEBUG_POLICY, "creating a branch [data=%d]:\n", data); for (i = 0; i < dq->count; i++) POOL_DEBUG (SOLV_DEBUG_POLICY, " - %s\n", pool_solvid2str(pool, dq->elements[i])); } @@ -1218,7 +1218,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) #if 0 { int i; - printf("branch group level %d [%d-%d] %d %d:\n", solv->branches.elements[end - 1], start, end, solv->branches.elements[end - 4], solv->branches.elements[end - 3]); + printf("branch group level %d [%d-%d] %d %d:\n", solv->branches.elements[end - 1], end - solv->branches.elements[end - 2], end, solv->branches.elements[end - 4], solv->branches.elements[end - 3]); for (i = end - solv->branches.elements[end - 2]; i < end - 4; i++) printf("%c %c%s\n", i == pos ? 'x' : ' ', solv->branches.elements[i] >= 0 ? ' ' : '-', pool_solvid2str(pool, solv->branches.elements[i] >= 0 ? solv->branches.elements[i] : -solv->branches.elements[i])); } @@ -2089,6 +2089,8 @@ add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap) queue_truncate(dq, blkcnt); break; } + if (solv->decisionmap[p] < 0) + continue; if (dqmap) { if (!MAPTST(dqmap, p)) @@ -2096,8 +2098,6 @@ add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap) } else { - if (solv->decisionmap[p] < 0) - continue; if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) continue; } @@ -3240,7 +3240,7 @@ addedmap2deduceq(Solver *solv, Map *addedmap) p = -r->p; if (!MAPTST(addedmap, p)) { - /* should never happen, but... */ + /* this can happen with complex dependencies that have more than one pos literal */ if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p) queue_push(&solv->addedmap_deduceq, -p); continue; @@ -3280,7 +3280,7 @@ deduceq2addedmap(Solver *solv, Map *addedmap) if (p > 0) MAPSET(addedmap, p); else - MAPCLR(addedmap, p); + MAPCLR(addedmap, -p); } } diff --git a/test/testcases/blacklist/ptf.t b/test/testcases/blacklist/ptf.t new file mode 100644 index 0000000..0005042 --- /dev/null +++ b/test/testcases/blacklist/ptf.t @@ -0,0 +1,52 @@ +repo system 0 testtags +#>=Pkg: ptf-2 1 1 noarch +#>=Prv: ptf-package() +repo available 0 testtags +#>=Pkg: ptf-1 1 1 noarch +#>=Prv: ptf-package() +#>=Pkg: ptf-2 2 1 noarch +#>=Prv: ptf-package() +#>=Pkg: A 1 1 noarch +#>=Req: ptf-1 + +system unset * system + +# +# test 1: a ptf package cannot be pulled in via a dependency +# +job blacklist provides ptf-package() +job install name A +result transaction,problems +#>problem 78613afb info package A-1-1.noarch requires ptf-1, but none of the providers can be installed +#>problem 78613afb solution 23f73f5b deljob install name A +#>problem 78613afb solution b79aeb6f allow ptf-1-1-1.noarch@available + +# +# test 2: a ptf package cannot be pulled in via a unspecific job +# +nextjob +job blacklist provides ptf-package() +job install name ptf-1 +result transaction,problems +#>problem 021b17e2 info package ptf-1-1-1.noarch can only be installed by a direct request +#>problem 021b17e2 solution 932a6c2f deljob install name ptf-1 +#>problem 021b17e2 solution b79aeb6f allow ptf-1-1-1.noarch@available + +# +# test 3: a ptf package can be pulled in via a specific job +# +nextjob +job blacklist provides ptf-package() +job install name ptf-1 [setevr] +result transaction,problems +#>install ptf-1-1-1.noarch@available + +# +# test 4: a ptf package can be updated +# +nextjob +job blacklist provides ptf-package() +job update all packages +result transaction,problems +#>upgrade ptf-2-1-1.noarch@system ptf-2-2-1.noarch@available + diff --git a/test/testcases/blacklist/retracted.t b/test/testcases/blacklist/retracted.t new file mode 100644 index 0000000..a36e244 --- /dev/null +++ b/test/testcases/blacklist/retracted.t @@ -0,0 +1,23 @@ +repo system 0 testtags +#>=Pkg: B 1 1 noarch +repo available 0 testtags +#>=Pkg: patch 1 1 noarch +#>=Con: B < 2-1 +#>=Pkg: B 2 1 noarch +#>=Prv: retracted-patch-package() + +system unset rpm system + +job blacklist provides retracted-patch-package() +job install name patch +result transaction,problems +#>problem 3a66200a info package patch-1-1.noarch conflicts with B < 2-1 provided by B-1-1.noarch +#>problem 3a66200a solution 14805cf8 deljob install name patch +#>problem 3a66200a solution 4a9277b8 allow B-2-1.noarch@available +#>problem 3a66200a solution 718064ed erase B-1-1.noarch@system + +nextjob +job blacklist provides retracted-patch-package() +job install pkg B-2-1.noarch@available +result transaction,problems +#>upgrade B-1-1.noarch@system B-2-1.noarch@available diff --git a/test/testcases/choicerules/choice2.t b/test/testcases/choicerules/choice2.t new file mode 100644 index 0000000..7c78fc6 --- /dev/null +++ b/test/testcases/choicerules/choice2.t @@ -0,0 +1,23 @@ +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Req: P = 1 +#>=Pkg: B 1 1 noarch +#>=Prv: P = 1 +repo available 0 testtags +#>=Pkg: A 2 1 noarch +#>=Req: P = 2 +#>=Pkg: A 2 2 noarch +#>=Req: P = 2 +#>=Pkg: B 2 1 noarch +#>=Prv: P = 2 +#>=Pkg: C 1 1 noarch +#>=Prv: P = 1 +#>=Pkg: C 2 1 noarch +#>=Prv: P = 2 +system i686 rpm system + +job update name B +result transaction,problems +result transaction,problems +#>upgrade A-1-1.noarch@system A-2-2.noarch@available +#>upgrade B-1-1.noarch@system B-2-1.noarch@available diff --git a/tools/testsolv.c b/tools/testsolv.c index 18dfcfe..a9e67ec 100644 --- a/tools/testsolv.c +++ b/tools/testsolv.c @@ -66,6 +66,16 @@ reportsolutioncb(Solver *solv, void *cbdata) return 0; } +static void +free_considered(Pool *pool) +{ + if (pool->considered) + { + map_free(pool->considered); + pool->considered = solv_free(pool->considered); + } +} + int main(int argc, char **argv) { @@ -149,7 +159,9 @@ main(int argc, char **argv) solv = testcase_read(pool, fp, argv[optind], &job, &result, &resultflags); if (!solv) { + free_considered(pool); pool_free(pool); + queue_free(&job); exit(resultflags == 77 ? 77 : 1); } if (reusesolv) @@ -349,6 +361,7 @@ main(int argc, char **argv) } if (reusesolv) solver_free(reusesolv); + free_considered(pool); pool_free(pool); fclose(fp); } diff --git a/win32/config.h b/win32/config.h new file mode 100644 index 0000000..68eca63 --- /dev/null +++ b/win32/config.h @@ -0,0 +1,13 @@ +#ifdef _WIN32 + #ifdef SOLV_STATIC_LIB + #define SOLV_API + #else + #ifdef SOLV_EXPORTS + #define SOLV_API __declspec(dllexport) + #else + #define SOLV_API __declspec(dllimport) + #endif + #endif +#else + #define SOLV_API +#endif \ No newline at end of file diff --git a/win32/getopt.c b/win32/getopt.c index 1e7e451..c4fc964 100644 --- a/win32/getopt.c +++ b/win32/getopt.c @@ -5,8 +5,10 @@ #include #include -char *optarg; -int optind=1, opterr=1, optopt, __optpos, __optreset=0; +#include "config.h" + +SOLV_API char *optarg; +SOLV_API int optind=1, opterr=1, optopt, __optpos, __optreset=0; #define optpos __optpos diff --git a/win32/getopt.h b/win32/getopt.h index 35cbd35..861ff0b 100644 --- a/win32/getopt.h +++ b/win32/getopt.h @@ -5,9 +5,12 @@ extern "C" { #endif +#include "config.h" + int getopt(int, char * const [], const char *); -extern char *optarg; -extern int optind, opterr, optopt, optreset; + +SOLV_API extern char *optarg; +SOLV_API extern int optind, opterr, optopt, optreset; struct option { const char *name;