-This file contains the major changes between
-libsolv versions:
+This file contains the major changes between libsolv versions:
+
+Version 0.7.21
+- selected bug fixes:
+ * fix segfault on conflict resolution when using bindings
+ * fix split provides not working if the update includes a forbidden
+ vendor change
+- new features:
+ * support strict repository priorities
+ new solver flag: SOLVER_FLAG_STRICT_REPO_PRIORITY
+ * support zstd compressed control files in debian packages
+ * add an ifdef allowing to rename Solvable dependency members
+ ("requires" is a keyword in C++20)
+ * support setting/reading userdata in solv files
+ new functions: repowriter_set_userdata, solv_read_userdata
+ * support queying of the custom vendor check function
+ new function: pool_get_custom_vendorcheck
+ * support solv files with an idarray block
+ * allow accessing the toolversion at runtime
Version 0.7.20
- selected bug fixes:
SET(LIBSOLV_MAJOR "0")
SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "20")
+SET(LIBSOLV_PATCH "21")
e = solv_calloc(1, sizeof(*e));
e->solv = solv;
e->problemid = problemid;
- e->solutionid = id;
+ e->solutionid = solutionid;
e->id = id;
e->type = type;
e->p = p;
static const int SOLVER_FLAG_STRONG_RECOMMENDS = SOLVER_FLAG_STRONG_RECOMMENDS;
static const int SOLVER_FLAG_INSTALL_ALSO_UPDATES = SOLVER_FLAG_INSTALL_ALSO_UPDATES;
static const int SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED = SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED;
+ static const int SOLVER_FLAG_STRICT_REPO_PRIORITY = SOLVER_FLAG_STRICT_REPO_PRIORITY;
static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
Description
-----------
Libsolv's language bindings offer an abstract, object orientated interface
-to the library. The supported languages are currently perl, python, and ruby.
-All example code (except in the specifics sections, of course) lists first
-the ``C-ish'' interface, then the syntax for perl, python, and ruby (in that
-order).
+to the library. The supported languages are currently perl, python, ruby and
+tcl. All example code (except in the specifics sections, of course) lists
+first the ``C-ish'' interface, then the syntax for perl, python, and ruby
+(in that order).
Perl Specifics
to ease programming and reduce the number of pool_str2id calls. The
constant Ids are part of the binary ABI of libsolv, a minor version
update will only add new constants and not change existing Ids to
-maintain compatible. The on-disk solv format works does not use the
-fixed Ids, but instead references the strings, so solv files can still
-be read when the ABI is broken.
+maintain compatibility. The on-disk solv format does not use the fixed
+Ids, but instead references the strings, so solv files can still be
+read when the ABI is broken.
Special Strings
Solvable Attributes
-------------------
-These are Ids for keyname of attributes. They can be used in the
+These are Ids for keynames of attributes. They can be used in the
lookup and storage functions to select the correct attribute in the
solvable. The descriptions below describe the intended semantics
of the values stored in the attribute with the keyname.
to see that this indeed was the missing piece: SAT algorithms are well
researched and there are quite some open source implementations.
I decided to look at the minisat code, as it is one of the fastest
-solvers while consisting of too many lines of code.
+solvers while consisting of not too many lines of code.
Of course, directly using minisat would not work, as a package solver
does not need to find just one correct solution, but it also has to
optimize some metrics, i.e. keep as many packages installed as possible.
-Thus, I needed to write my own solver incorporation the ideas and
+Thus, I needed to write my own solver, incorporating the ideas and
algorithms used in minisat. This wasn't very hard, and at the end of
the hack week the solver calculated the first right solutions.
Pointer Validity
----------------
Note that all pointers to objects that have an Id have only a limited
-validity period, with the exception of Repo pointers. There are only
+validity period, with the exception of Repo pointers. They are only
guaranteed to be valid until a new object of that type is added or an
object of that type is removed. Thus pointers to Solvable objects are only
valid until another solvable is created, because adding a Solvable may
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
+#ifdef ENABLE_ZLIB_COMPRESSION
#include <zlib.h>
+#endif
+#ifdef ENABLE_LZMA_COMPRESSION
#include <lzma.h>
-#include <errno.h>
+#endif
+#ifdef ENABLE_ZSTD_COMPRESSION
+#include <zstd.h>
+#endif
#include "pool.h"
#include "repo.h"
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
+#define MAX_CONTROL_SIZE 0x1000000
+
+#ifdef ENABLE_ZLIB_COMPRESSION
+
static unsigned char *
decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
{
return out;
}
+#else
+
+static unsigned char *
+decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+ return 0;
+}
+
+#endif /* ENABLE_ZLIB_COMPRESSION */
+
+#ifdef ENABLE_LZMA_COMPRESSION
+
static unsigned char *
decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
{
return out;
}
+#else
+
+static unsigned char *
+decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+ return 0;
+}
+
+#endif /* ENABLE_LZMA_COMPRESSION */
+
+#ifdef ENABLE_ZSTD_COMPRESSION
+
+static unsigned char *
+decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+ ZSTD_DStream *dstream;
+ ZSTD_inBuffer inbuf;
+ ZSTD_outBuffer outbuf;
+ int ret;
+
+ dstream = ZSTD_createDStream();
+ if (!dstream)
+ return 0;
+ if (ZSTD_isError(ZSTD_initDStream(dstream)))
+ {
+ ZSTD_freeDStream(dstream);
+ return 0;
+ }
+ inbuf.src = in;
+ inbuf.pos = 0;
+ inbuf.size = inl;
+ outbuf.dst = solv_malloc(4096);
+ outbuf.pos = 0;
+ outbuf.size = 4096;
+ for (;;)
+ {
+ if (outbuf.pos == outbuf.size)
+ {
+ outbuf.size += 4096;
+ if (outbuf.size >= maxoutl)
+ {
+ ret = 1;
+ break;
+ }
+ outbuf.dst = solv_realloc(outbuf.dst, outbuf.size + 4096);
+ }
+ ret = ZSTD_decompressStream(dstream, &outbuf, &inbuf);
+ if (ret == 0 && inbuf.pos == inbuf.size)
+ break;
+ if (ZSTD_isError(ret) || (inbuf.pos == inbuf.size && outbuf.pos < outbuf.size))
+ {
+ ret = 1;
+ break;
+ }
+ }
+ ZSTD_freeDStream(dstream);
+ if (ret)
+ {
+ solv_free(outbuf.dst);
+ return 0;
+ }
+ *outlp = outbuf.pos;
+ return outbuf.dst;
+}
+
+#else
+
+static unsigned char *
+decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+ return 0;
+}
+
+#endif /* ENABLE_ZSTD_COMPRESSION */
+
static Id
parseonedep(Pool *pool, char *p)
{
#define CONTROL_COMP_NONE 0
#define CONTROL_COMP_GZIP 1
#define CONTROL_COMP_XZ 2
+#define CONTROL_COMP_ZSTD 3
Id
repo_add_deb(Repo *repo, const char *deb, int flags)
control_comp = CONTROL_COMP_GZIP;
else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
control_comp = CONTROL_COMP_XZ;
+ else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst/", 16))
+ control_comp = CONTROL_COMP_ZSTD;
else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/ ", 16))
control_comp = CONTROL_COMP_NONE;
else
* just keeps from allocating arbitrarily large amounts of memory.
*/
clen = atoi((char *)buf + 8 + 60 + vlen + 48);
- if (clen <= 0 || clen >= 0x1000000)
+ if (clen <= 0 || clen >= MAX_CONTROL_SIZE)
{
pool_error(pool, -1, "%s: control.tar has illegal size", deb);
fclose(fp);
}
ctar = 0;
if (control_comp == CONTROL_COMP_GZIP)
- ctar = decompress_gz(ctgz, clen, &ctarlen, 0x1000000);
+ ctar = decompress_gz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
else if (control_comp == CONTROL_COMP_XZ)
- ctar = decompress_xz(ctgz, clen, &ctarlen, 0x1000000);
+ ctar = decompress_xz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
+ else if (control_comp == CONTROL_COMP_ZSTD)
+ ctar = decompress_zstd(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
else
{
ctarlen = clen;
solv_free(ctgz);
if (!ctar)
{
- pool_error(pool, -1, "%s: control.tar is corrupt", deb);
+ pool_error(pool, -1, "%s: control.tar decompression error", deb);
return 0;
}
bp = ctar;
ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
if (ti)
fprintf(fp, "=Tim: %u\n", ti);
+ ti = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0);
+ if (ti)
+ fprintf(fp, "=Itm: %u\n", ti);
writefilelist(repo, fp, "Fls:", s);
}
queue_free(&q);
if (t)
repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
break;
+ case 'I' << 16 | 't' << 8 | 'm':
+ t = atoi(line + 6);
+ if (t)
+ repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, t);
+ break;
case 'R' << 16 | 'e' << 8 | 'q':
s->requires = adddep(repo, s->requires, line + 6, -SOLVABLE_PREREQMARKER);
break;
{ TESTCASE_RESULT_CLEANDEPS, "cleandeps" },
{ TESTCASE_RESULT_JOBS, "jobs" },
{ TESTCASE_RESULT_USERINSTALLED, "userinstalled" },
+ { TESTCASE_RESULT_ORDER, "order" },
{ 0, 0 }
};
{ SOLVER_FLAG_STRONG_RECOMMENDS, "strongrecommends", 0 },
{ SOLVER_FLAG_INSTALL_ALSO_UPDATES, "installalsoupdates", 0 },
{ SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED, "onlynamespacerecommended", 0 },
+ { SOLVER_FLAG_STRICT_REPO_PRIORITY, "strictrepopriority", 0 },
{ 0, 0, 0 }
};
return repo;
}
+static const char *
+testcase_escape(Pool *pool, const char *str)
+{
+ size_t nbad = 0;
+ const char *p;
+ char *new, *np;
+ for (p = str; *p; p++)
+ if (*p == '\\' || *p == ' ' || *p == '\t')
+ nbad++;
+ if (!nbad)
+ return str;
+ new = pool_alloctmpspace(pool, strlen(str) + 1 + nbad * 2);
+ for (np = new, p = str; *p; p++)
+ {
+ *np++ = *p;
+ if (*p == '\\' || *p == ' ' || *p == '\t')
+ {
+ np[-1] = '\\';
+ solv_bin2hex((unsigned char *)p, 1, np);
+ np += 2;
+ }
+ }
+ *np = 0;
+ return new;
+}
+
+static void
+testcase_unescape_inplace(char *str)
+{
+ char *p, *q;
+ for (p = q = str; *p;)
+ {
+ *q++ = *p++;
+ if (p[-1] == '\\')
+ solv_hex2bin((const char **)&p, (unsigned char *)q - 1, 1);
+ }
+ *q = 0;
+}
+
/* check evr and buildflavors */
static int
str2solvid_check(Pool *pool, Solvable *s, const char *start, const char *end, Id evrid)
{ SOLVER_RULE_YUMOBS, "yumobs" },
{ SOLVER_RULE_BLACK, "black" },
{ SOLVER_RULE_RECOMMENDS, "recommends" },
+ { SOLVER_RULE_STRICT_REPO_PRIORITY, "strictrepoprio" },
{ 0, 0 }
};
}
queue_free(&q);
}
+ if ((resultflags & TESTCASE_RESULT_ORDER) != 0)
+ {
+ int i;
+ char buf[256];
+ Id p;
+ Transaction *trans = solver_create_transaction(solv);
+ transaction_order(trans, 0);
+ for (i = 0; i < trans->steps.count; i++)
+ {
+ p = trans->steps.elements[i];
+ if (pool->installed && pool->solvables[p].repo == pool->installed)
+ sprintf(buf, "%4d erase ", i + 1);
+ else
+ sprintf(buf, "%4d install ", i + 1);
+ s = pool_tmpjoin(pool, "order ", buf, testcase_solvid2str(pool, p));
+ strqueue_push(&sq, s);
+ }
+ transaction_free(trans);
+ }
if ((resultflags & TESTCASE_RESULT_ALTERNATIVES) != 0)
{
char *altprefix;
return result;
}
+static void
+dump_custom_vendorcheck(Pool *pool, Strqueue *sq, int (*vendorcheck)(Pool *, Solvable *, Solvable *))
+{
+ Id p, lastvendor = 0;
+ Queue vq;
+ int i, j;
+ char *cmd;
+
+ queue_init(&vq);
+ FOR_POOL_SOLVABLES(p)
+ {
+ Id vendor = pool->solvables[p].vendor;
+ if (!vendor || vendor == lastvendor)
+ continue;
+ lastvendor = vendor;
+ for (i = 0; i < vq.count; i += 2)
+ if (vq.elements[i] == vendor)
+ break;
+ if (i == vq.count)
+ queue_push2(&vq, vendor, p);
+ }
+ for (i = 0; i < vq.count; i += 2)
+ {
+ Solvable *s1 = pool->solvables + vq.elements[i + 1];
+ for (j = i + 2; j < vq.count; j += 2)
+ {
+ Solvable *s2 = pool->solvables + vq.elements[j + 1];
+ if (vendorcheck(pool, s1, s2) || vendorcheck(pool, s2, s1))
+ continue;
+ cmd = pool_tmpjoin(pool, "vendorclass", 0, 0);
+ cmd = pool_tmpappend(pool, cmd, " ", testcase_escape(pool, pool_id2str(pool, vq.elements[i])));
+ cmd = pool_tmpappend(pool, cmd, " ", testcase_escape(pool, pool_id2str(pool, vq.elements[j])));
+ strqueue_push(sq, cmd);
+ }
+ }
+ queue_free(&vq);
+}
static int
testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname)
Strqueue sq;
char *cmd, *out, *result;
const char *s;
+ int (*vendorcheck)(Pool *, Solvable *, Solvable *);
if (!testcasename)
testcasename = "testcase.t";
strqueue_push(&sq, cmd);
}
- if (pool->vendorclasses)
+ vendorcheck = pool_get_custom_vendorcheck(pool);
+ if (vendorcheck)
+ dump_custom_vendorcheck(pool, &sq, vendorcheck);
+ else if (pool->vendorclasses)
{
cmd = 0;
for (i = 0; pool->vendorclasses[i]; i++)
{
- cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", pool->vendorclasses[i]);
+ cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", testcase_escape(pool, pool->vendorclasses[i]));
if (!pool->vendorclasses[i + 1])
{
strqueue_push(&sq, cmd);
}
repo->priority = prio;
repo->subpriority = subprio;
- if (strcmp(pieces[3], "empty") != 0)
+ if (strcmp(pieces[3], "empty") != 0 && npieces > 4)
{
const char *repotype = pool_tmpjoin(pool, pieces[3], 0, 0); /* gets overwritten in <inline> case */
if (!strcmp(pieces[4], "<inline>"))
}
else if (!strcmp(pieces[0], "vendorclass") && npieces > 1)
{
+ int i;
+ for (i = 1; i < npieces; i++)
+ testcase_unescape_inplace(pieces[i]);
pool_addvendorclass(pool, (const char **)(pieces + 1));
}
else if (!strcmp(pieces[0], "namespace") && npieces > 1)
#define TESTCASE_RESULT_CLEANDEPS (1 << 9)
#define TESTCASE_RESULT_JOBS (1 << 10)
#define TESTCASE_RESULT_USERINSTALLED (1 << 11)
+#define TESTCASE_RESULT_ORDER (1 << 12)
/* reuse solver hack, testsolv use only */
#define TESTCASE_RESULT_REUSE_SOLVER (1 << 31)
-------------------------------------------------------------------
+Fri Feb 25 17:32:20 CET 2022 - mls@suse.de
+
+- fix segfault on conflict resolution when using bindings
+- fix split provides not working if the update includes a forbidden
+ vendor change
+- support strict repository priorities
+ new solver flag: SOLVER_FLAG_STRICT_REPO_PRIORITY
+- support zstd compressed control files in debian packages
+- add an ifdef allowing to rename Solvable dependency members
+ ("requires" is a keyword in C++20)
+- support setting/reading userdata in solv files
+ new functions: repowriter_set_userdata, solv_read_userdata
+- support queying of the custom vendor check function
+ new function: pool_get_custom_vendorcheck
+- support solv files with an idarray block
+- allow accessing the toolversion at runtime
+- bump version to 0.7.21
+
+-------------------------------------------------------------------
Sat Sep 25 22:45:07 CEST 2021 - mls@suse.de
- fix misparsing of '&' in attributes with libxml2
- fix compatibility with Python 3.10
- new SOLVER_EXCLUDEFROMWEAK job type
- support for environments in comps parser
+- bump version to 0.7.20
-------------------------------------------------------------------
Fri Jul 30 11:43:29 UTC 2021 - Dominique Leuenberger <dimstar@opensuse.org>
pool_freewhatprovides;
pool_get_flag;
pool_get_rootdir;
+ pool_get_custom_vendorcheck;
pool_id2evr;
pool_id2langid;
pool_id2rel;
repowriter_set_keyqueue;
repowriter_set_repodatarange;
repowriter_set_solvablerange;
+ repowriter_set_userdata;
repowriter_write;
selection_add;
selection_filter;
solv_malloc;
solv_malloc2;
solv_oom;
+ solv_read_userdata;
solv_realloc;
solv_realloc2;
solv_replacebadutf8;
solv_version_major;
solv_version_minor;
solv_version_patch;
+ solv_toolversion;
solvable_add_deparray;
solvable_add_idarray;
solvable_add_poolstr_array;
}
}
+static int
+share_cycle(struct orderdata *od, Id p1, Id p2)
+{
+ int i, seen = 0;
+ for (i = 0; i < od->cyclesdata.count; i++)
+ {
+ Id p = od->cyclesdata.elements[i];
+ if (p == 0)
+ seen = 0;
+ else if ((p == p1 || p == p2) && ++seen == 2)
+ return 1;
+ }
+ return 0;
+}
+
void
transaction_order(Transaction *trans, int flags)
{
int oldcount;
int start, now;
Repo *lastrepo;
- int lastmedia;
+ int lastmedia, lastte;
Id *temedianr;
+ unsigned char *incycle;
start = now = solv_timems(0);
POOL_DEBUG(SOLV_DEBUG_STATS, "ordering transaction\n");
POOL_DEBUG(SOLV_DEBUG_STATS, "cycles broken: %d\n", od.ncycles);
POOL_DEBUG(SOLV_DEBUG_STATS, "cycle breaking took %d ms\n", solv_timems(now));
- now = solv_timems(0);
- /* now go through all broken cycles and create cycle edges to help
- the ordering */
- for (i = od.cycles.count - 4; i >= 0; i -= 4)
- {
- if (od.cycles.elements[i + 2] >= TYPE_REQ)
- addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
- }
- for (i = od.cycles.count - 4; i >= 0; i -= 4)
- {
- if (od.cycles.elements[i + 2] < TYPE_REQ)
- addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
- }
- POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now));
+ incycle = 0;
+ if (od.cycles.count)
+ {
+ now = solv_timems(0);
+ incycle = solv_calloc(numte, 1);
+ /* now go through all broken cycles and create cycle edges to help
+ the ordering */
+ for (i = od.cycles.count - 4; i >= 0; i -= 4)
+ {
+ if (od.cycles.elements[i + 2] >= TYPE_REQ)
+ addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
+ }
+ for (i = od.cycles.count - 4; i >= 0; i -= 4)
+ {
+ if (od.cycles.elements[i + 2] < TYPE_REQ)
+ addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
+ }
+ for (i = od.cycles.count - 4; i >= 0; i -= 4)
+ {
+ for (j = od.cycles.elements[i]; od.cyclesdata.elements[j]; j++)
+ incycle[od.cyclesdata.elements[j]] = 1;
+ }
+ POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now));
+ }
#if 0
dump_tes(&od);
lastrepo = 0;
lastmedia = 0;
+ lastte = 0;
temedianr = solv_calloc(numte, sizeof(Id));
for (i = 1; i < numte; i++)
{
if (uninstq.count)
i = queue_shift(&uninstq);
else if (samerepoq.count)
- i = queue_shift(&samerepoq);
+ {
+ if (lastte && incycle && incycle[lastte])
+ {
+ /* last installed package was in a cycle, prefer packages from the same cycle */
+ for (j = 0; j < samerepoq.count; j++)
+ if (incycle[samerepoq.elements[j]] && share_cycle(&od, lastte, samerepoq.elements[j]))
+ {
+ /* yes, bring to front! */
+ i = samerepoq.elements[j];
+ queue_delete(&samerepoq, j);
+ queue_unshift(&samerepoq, i);
+ break;
+ }
+ }
+ i = queue_shift(&samerepoq);
+ }
else if (todo.count)
{
/* find next repo/media */
te = od.tes + i;
queue_push(tr, te->p);
+ if (pool->solvables[te->p].repo != installed)
+ lastte = i;
+
#if 0
printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]);
#endif
}
}
solv_free(temedianr);
+ solv_free(incycle);
queue_free(&todo);
queue_free(&samerepoq);
queue_free(&uninstq);
pool->custom_vendorcheck = vendorcheck;
}
+int (*pool_get_custom_vendorcheck(Pool *pool))(Pool *, Solvable *, Solvable *)
+{
+ return pool->custom_vendorcheck;
+}
+
/* EOF */
extern void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct s_Pool *, Solvable *, Solvable *));
-
+extern int (*pool_get_custom_vendorcheck(Pool *pool))(struct s_Pool *, Solvable *, Solvable *);
extern char *pool_alloctmpspace(Pool *pool, int len);
extern void pool_freetmpspace(Pool *pool, const char *space);
#define SOLV_VERSION_6 6
#define SOLV_VERSION_7 7
#define SOLV_VERSION_8 8
+#define SOLV_VERSION_9 9
-#define SOLV_FLAG_PREFIX_POOL 4
-#define SOLV_FLAG_SIZE_BYTES 8
+#define SOLV_FLAG_PREFIX_POOL 4
+#define SOLV_FLAG_SIZE_BYTES 8
+#define SOLV_FLAG_USERDATA 16
+#define SOLV_FLAG_IDARRAYBLOCK 32
struct s_Stringpool;
typedef struct s_Stringpool Stringpool;
vstr = pool_id2str(pool, vendor);
m = 1;
mask = 0;
- for (v = pool->vendorclasses; ; v++)
+ for (v = pool->vendorclasses; ; )
{
- vs = *v;
+ vs = *v++;
if (vs == 0) /* end of block? */
{
- v++;
- if (*v == 0)
+ vs = *v++;
+ if (vs == 0)
break;
if (m == (1 << 31))
break; /* sorry, out of bits */
{
if (*vs != '!')
mask |= m;
- while (v[1]) /* forward to next block */
+ while (*v) /* forward to next block */
v++;
}
}
assert(solv->rules[why].p < 0);
queue_push(solutionq, -solv->rules[why].p);
}
+ if (why >= solv->strictrepopriorules && why < solv->strictrepopriorules_end)
+ {
+ queue_push(solutionq, SOLVER_SOLUTION_STRICTREPOPRIORITY);
+ assert(solv->rules[why].p < 0);
+ queue_push(solutionq, -solv->rules[why].p);
+ }
}
/*
*/
static void
-findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Id *blkrp, Map *rseen)
+findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Id *blkrp, Id *scprp, Map *rseen)
{
Id rid, d;
- Id lreqr, lconr, lsysr, ljobr, lblkr;
+ Id lreqr, lconr, lsysr, ljobr, lblkr, lscpr;
Rule *r;
Id jobassert = 0;
int i, reqset = 0; /* 0: unset, 1: installed, 2: jobassert, 3: assert */
/* the problem rules are somewhat ordered from "near to the problem" to
* "near to the job" */
- lreqr = lconr = lsysr = ljobr = lblkr = 0;
+ lreqr = lconr = lsysr = ljobr = lblkr = lscpr = 0;
while ((rid = solv->learnt_pool.elements[idx++]) != 0)
{
assert(rid > 0);
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, &lblkr, rseen);
+ findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, &lblkr, &lscpr, 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))
{
if (!*blkrp)
*blkrp = rid;
}
+ else if (rid >= solv->strictrepopriorules && rid < solv->strictrepopriorules_end)
+ {
+ if (!*scprp)
+ *scprp = rid;
+ }
else
{
assert(rid < solv->pkgrules_end);
Pool *pool = solv->pool;
Id op = -solv->rules[*reqrp].p;
if (op > 1 && pool->solvables[op].arch != pool->solvables[-r->p].arch &&
- pool->solvables[op].arch != pool->noarchid &&
pool->solvables[-r->p].arch != pool->noarchid)
continue; /* different arch, skip */
}
*sysrp = lsysr;
if (!*blkrp && lblkr)
*blkrp = lblkr;
+ if (!*scprp && lscpr)
+ *scprp = lscpr;
}
/*
Id
solver_findproblemrule(Solver *solv, Id problem)
{
- Id reqr, conr, sysr, jobr, blkr;
+ Id reqr, conr, sysr, jobr, blkr, srpr;
Id idx = solv->problems.elements[2 * problem - 2];
Map rseen;
- reqr = conr = sysr = jobr = blkr = 0;
+ reqr = conr = sysr = jobr = blkr = srpr = 0;
map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
- findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &blkr, &rseen);
+ findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &blkr, &srpr, &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 */
return conr; /* some conflict */
if (blkr)
return blkr; /* a blacklisted package */
+ if (srpr)
+ return srpr; /* a strict repo priority */
if (sysr)
return sysr; /* an update rule */
if (jobr)
return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
case SOLVER_RULE_BLACK:
return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " can only be installed by a direct request");
+ case SOLVER_RULE_STRICT_REPO_PRIORITY:
+ return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is excluded by strict repo priority");
case SOLVER_RULE_PKG_CONSTRAINS:
s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
s = pool_tmpappend(pool, s, " has constraint ", pool_dep2str(pool, dep));
}
else if (p > 0 && rp == 0)
return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
+ else if (p == SOLVER_SOLUTION_STRICTREPOPRIORITY)
+ {
+ Solvable *s = pool->solvables + rp;
+ return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the repo priority");
+ }
else if (p > 0 && rp > 0)
{
const char *sp = pool_solvid2str(pool, p);
#define SOLVER_SOLUTION_BEST (-3)
#define SOLVER_SOLUTION_POOLJOB (-4)
#define SOLVER_SOLUTION_BLACK (-5)
+#define SOLVER_SOLUTION_STRICTREPOPRIORITY (-6)
void solver_recordproblem(struct s_Solver *solv, Id rid);
void solver_fixproblem(struct s_Solver *solv, Id rid);
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#ifndef _WIN32
-#include <sys/cdefs.h>
-#endif
/* $FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.13.2.1.8.1 2010/12/21 17:10:29 kensmith Exp $ */
}
}
+static void
+read_idarray_block(Repodata *data, Id *block, int size)
+{
+ unsigned char buf[65536 + 5 + 1], *bp = buf, *oldbp;
+ unsigned char cbuf[65536 + 4]; /* can overshoot 4 bytes */
+ int left = 0;
+ int eof = 0;
+ int clen, flags;
+ Id x;
+ for (;;)
+ {
+ if (left < 5 && !eof)
+ {
+ if (left)
+ memmove(buf, bp, left);
+ bp = buf + left;
+ flags = read_u8(data);
+ clen = read_u8(data);
+ clen = (clen << 8) | read_u8(data);
+ if (data->error)
+ return;
+ if (!clen)
+ clen = 65536;
+ eof = flags & 0x80;
+ if (fread(flags & 0x40 ? cbuf : bp, clen, 1, data->fp) != 1)
+ {
+ data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
+ return;
+ }
+ if (flags & 0x40) /* compressed block */
+ clen = repopagestore_decompress_page(cbuf, clen, bp, 65536);
+ bp = buf;
+ left += clen;
+ bp[left] = 0; /* make data_read_id return */
+ continue;
+ }
+ if (size < 2)
+ {
+ data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray data overrun in block decompression");
+ return;
+ }
+ oldbp = bp;
+ bp = data_read_id(bp, &x);
+ left -= bp - oldbp;
+ if (left < 0)
+ {
+ data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "compression buffer underrun");
+ return;
+ }
+ size--;
+ *block++ = (x & 63) + (((unsigned int)x & ~127) >> 1) + 1;
+ if ((x & 64) == 0)
+ {
+ *block++ = 0;
+ if (--size == 0)
+ break;
+ }
+ }
+ if (left || !eof)
+ data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray size overrun in block decompression");
+}
/*******************************************************************************
* functions to extract data from memory
}
static unsigned char *
-data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id marker)
+data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id keyid)
{
+ Id marker = 0;
Id *store = *storep;
Id old = 0;
unsigned int x = 0;
int c;
+ if (keyid == SOLVABLE_REQUIRES)
+ marker = SOLVABLE_PREREQMARKER;
+ if (keyid == SOLVABLE_PROVIDES)
+ marker = SOLVABLE_FILEMARKER;
for (;;)
{
c = *dp++;
data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "incore_map_idarray: id too large (%u/%u)", id, max);
break;
}
- id = map[id];
+ if (map)
+ id = map[id];
incore_add_ideof(data, id, eof);
if (eof)
break;
}
}
+static int
+convert_idarray_block(Repodata *data, Id *block, Id *map, Id max)
+{
+ int cnt = 0;
+ int old = 0;
+ for (;;)
+ {
+ Id id = *block;
+ cnt++;
+ if (!id)
+ return cnt;
+ id--; /* idarray_block unpacking added 1 */
+ if (id < 2 * old)
+ {
+ if (id & 1)
+ id = old - (id >> 1) - 1;
+ else
+ id = old + (id >> 1);
+ }
+ old = id;
+ if (id < 0 || (max && id >= max))
+ {
+ data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "convert_idarray_block: id too large (%u/%u)", id, max);
+ return cnt;
+ }
+ if (map)
+ id = map[id];
+ *block++ = id;
+ }
+}
+
#if 0
static void
incore_add_u32(Repodata *data, unsigned int x)
Repodata data;
int extendstart = 0, extendend = 0; /* set in case we're extending */
+ int idarray_block_offset = 0;
+ int idarray_block_end = 0;
now = solv_timems(0);
switch (solvversion)
{
case SOLV_VERSION_8:
+ case SOLV_VERSION_9:
break;
default:
return pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported SOLV version");
return pool_error(pool, SOLV_ERROR_CORRUPT, "main repository contains holes, cannot extend");
}
+ /******* Part 0: skip optional userdata ******************************/
+
+ if (solvflags & SOLV_FLAG_USERDATA)
+ {
+ unsigned int userdatalen = read_u32(&data);
+ if (userdatalen >= 65536)
+ return pool_error(pool, SOLV_ERROR_CORRUPT, "illegal userdata length");
+ while (userdatalen--)
+ if (getc(data.fp) == EOF)
+ return pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
+ }
+
/******* Part 1: string IDs *****************************************/
sizeid = read_u32(&data); /* size of string space */
/* keys start at 1 */
for (i = 1; i < numkeys; i++)
{
+ Repokey *key;
+ if (data.error)
+ break;
id = read_id(&data, numid);
if (idmap)
id = idmap[id];
data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type));
type = REPOKEY_TYPE_VOID;
}
- keys[i].name = id;
- keys[i].type = type;
- keys[i].size = read_id(&data, keys[i].type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
- keys[i].storage = read_id(&data, 0);
+ key = keys + i;
+ key->name = id;
+ key->type = type;
+ key->size = read_id(&data, type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
+ key->storage = read_id(&data, 0);
/* old versions used SOLVABLE for main solvable data */
- if (keys[i].storage == KEY_STORAGE_SOLVABLE)
- keys[i].storage = KEY_STORAGE_INCORE;
- if (keys[i].storage != KEY_STORAGE_INCORE && keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
- data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", keys[i].storage);
+ if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET && key->storage != KEY_STORAGE_SOLVABLE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
+ data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", key->storage);
+ /* change KEY_STORAGE_SOLVABLE to KEY_STORAGE_INCORE */
+ if (key->storage == KEY_STORAGE_SOLVABLE)
+ key->storage = KEY_STORAGE_INCORE;
+ if (key->storage == KEY_STORAGE_IDARRAYBLOCK && type != REPOKEY_TYPE_IDARRAY)
+ data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "typr %d does not support idarrayblock storage\n", type);
if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
{
- if (keys[i].storage != KEY_STORAGE_INCORE)
- data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage %d", keys[i].storage);
- keys[i].storage = KEY_STORAGE_SOLVABLE;
+ /* we will put those directly into the storable */
+ if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
+ data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage, not %d", key->storage);
}
- if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && keys[i].storage != KEY_STORAGE_INCORE)
+ if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && key->storage != KEY_STORAGE_INCORE)
data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "flex/fixarrays must use incore storage\n");
/* cannot handle rel idarrays in incore/vertical */
- if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_SOLVABLE)
- data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_SOLVABLE");
+ if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_INCORE)
+ data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_INCORE");
/* cannot handle mapped ids in vertical */
- if (!(flags & REPO_LOCALPOOL) && keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
+ if (!(flags & REPO_LOCALPOOL) && key->storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "mapped ids are not supported for STORAGE_VERTICAL_OFFSET");
- if (keys[i].type == REPOKEY_TYPE_CONSTANTID && idmap)
- keys[i].size = idmap[keys[i].size];
+ if (type == REPOKEY_TYPE_CONSTANTID && idmap)
+ key->size = idmap[key->size];
#if 0
- fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool,id), pool_id2str(pool, keys[i].type),
- keys[i].size, keys[i].storage);
+ fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool, id), pool_id2str(pool, type), key->size, key->storage);
#endif
}
have_incoredata = 0;
for (i = 1; i < numkeys; i++)
- if (keys[i].storage == KEY_STORAGE_INCORE || keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
+ {
+ id = keys[i].name;
+ if (id == REPOSITORY_SOLVABLES && keys[i].type == REPOKEY_TYPE_FLEXARRAY)
+ continue;
+ if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
+ continue;
have_incoredata = 1;
+ }
data.keys = keys;
data.nkeys = numkeys;
data.schemadata = schemadata;
data.schemadatalen = schemadataend - data.schemadata;
- /******* Part 6: Data ********************************************/
+ /******* Part 6: Idarray block ***********************************/
+ if ((solvflags & SOLV_FLAG_IDARRAYBLOCK) != 0)
+ {
+ unsigned int idarray_block_size = read_id(&data, 0x30000000);
+ repo_reserve_ids(repo, 0, idarray_block_size + 1);
+ idarray_block_offset = repo->idarraysize;
+ repo->idarraysize += idarray_block_size;
+ idarray_block_end = repo->idarraysize;
+ repo->idarraydata[repo->idarraysize++] = 0;
+ if (idarray_block_size)
+ read_idarray_block(&data, repo->idarraydata + idarray_block_offset, idarray_block_size);
+ }
+
+ /******* Part 7: Data ********************************************/
idarraydatap = idarraydataend = 0;
size_idarray = 0;
l = allsize;
if (!l || fread(buf, l, 1, data.fp) != 1)
{
- data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
+ if (!data.error)
+ data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
id = 0;
}
else
break;
case REPOKEY_TYPE_IDARRAY:
case REPOKEY_TYPE_REL_IDARRAY:
- if (!s || id < INTERESTED_START || id > INTERESTED_END)
+ if (keys[key].storage == KEY_STORAGE_IDARRAYBLOCK)
{
- dps = dp;
- dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
- if (keys[key].storage != KEY_STORAGE_INCORE)
- break;
- if (idmap)
- incore_map_idarray(&data, dps, idmap, numid + numrel);
- else
- incore_add_blob(&data, dps, dp - dps);
- break;
+ int cnt = convert_idarray_block(&data, repo->idarraydata + idarray_block_offset, idmap, numid + numrel);
+ ido = idarray_block_offset;
+ idarray_block_offset += cnt;
+ if (idarray_block_offset > idarray_block_end)
+ {
+ data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray block underflow");
+ idarray_block_offset = idarray_block_end;
+ break;
+ }
+ if (!s || id < INTERESTED_START || id > INTERESTED_END)
+ {
+ do
+ incore_add_ideof(&data, repo->idarraydata[ido++], --cnt > 1 ? 0 : 1);
+ while (cnt > 1);
+ break;
+ }
}
- ido = idarraydatap - repo->idarraydata;
- if (keys[key].type == REPOKEY_TYPE_IDARRAY)
- dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
- else if (id == SOLVABLE_REQUIRES)
- dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_PREREQMARKER);
- else if (id == SOLVABLE_PROVIDES)
- dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_FILEMARKER);
else
- dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, 0);
- if (idarraydatap > idarraydataend)
{
- data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
- break;
+ if (!s || id < INTERESTED_START || id > INTERESTED_END)
+ {
+ dps = dp;
+ dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
+ if (keys[key].storage != KEY_STORAGE_INCORE)
+ break;
+ if (idmap)
+ incore_map_idarray(&data, dps, idmap, numid + numrel);
+ else
+ incore_add_blob(&data, dps, dp - dps);
+ break;
+ }
+ ido = idarraydatap - repo->idarraydata;
+ if (keys[key].type == REPOKEY_TYPE_IDARRAY)
+ dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
+ else
+ dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, id);
+ if (idarraydatap > idarraydataend)
+ {
+ data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
+ break;
+ }
}
if (id == SOLVABLE_PROVIDES)
s->provides = ido;
incore_add_sizek(&data, (unsigned int)id);
break;
}
- /* FALLTHROUGH */
- default:
- if (id == RPM_RPMDBID && s && keys[key].type == REPOKEY_TYPE_NUM)
+ if (s && id == RPM_RPMDBID)
{
dp = data_read_id(dp, &id);
if (!repo->rpmdbid)
repo->rpmdbid[(s - pool->solvables) - repo->start] = id;
break;
}
+ /* FALLTHROUGH */
+ default:
dps = dp;
dp = data_skip(dp, keys[key].type);
if (keys[key].storage == KEY_STORAGE_INCORE)
{
if (dp > bufend)
data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
+ else if (idarray_block_offset != idarray_block_end)
+ data.error = pool_error(pool, SOLV_ERROR_EOF, "unconsumed idarray block entries");
}
solv_free(buf);
}
solv_free(idmap);
- /* fixup the special idarray type */
+ /* fixup key data */
for (i = 1; i < numkeys; i++)
- if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
- keys[i].type = REPOKEY_TYPE_IDARRAY;
+ {
+ if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
+ keys[i].type = REPOKEY_TYPE_IDARRAY;
+ if (keys[i].storage == KEY_STORAGE_IDARRAYBLOCK)
+ keys[i].storage = KEY_STORAGE_INCORE;
+ if (keys[i].name >= SOLVABLE_NAME && keys[i].name <= RPM_RPMDBID)
+ keys[i].storage = KEY_STORAGE_SOLVABLE;
+ }
for (i = 1; i < numkeys; i++)
if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && keys[i].size)
return 0;
}
+int
+solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp)
+{
+ unsigned char d[4 * 10], *ud = 0;
+ unsigned int n;
+ if (fread(d, sizeof(d), 1, fp) != 1)
+ return SOLV_ERROR_EOF;
+ n = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+ if (n != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
+ return SOLV_ERROR_NOT_SOLV;
+ n = d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7];
+ switch(n)
+ {
+ case SOLV_VERSION_8:
+ case SOLV_VERSION_9:
+ break;
+ default:
+ return SOLV_ERROR_UNSUPPORTED;
+ }
+ n = d[32] << 24 | d[33] << 16 | d[34] << 8 | d[35];
+ if (!(n & SOLV_FLAG_USERDATA))
+ n = 0;
+ else
+ n = d[36] << 24 | d[37] << 16 | d[38] << 8 | d[39];
+ if (n >= 65536)
+ return SOLV_ERROR_CORRUPT;
+ if (n)
+ {
+ ud = solv_malloc(n + 1);
+ if (fread(ud, n, 1, fp) != 1)
+ {
+ solv_free(ud);
+ return SOLV_ERROR_EOF;
+ }
+ ud[n] = 0;
+ }
+ *datap = ud;
+ if (lenp)
+ *lenp = (int)n;
+ return 0;
+}
#endif
extern int repo_add_solv(Repo *repo, FILE *fp, int flags);
+extern int solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp);
#define SOLV_ADD_NO_STUBS (1 << 8)
#include "repo_write.h"
#include "repopage.h"
+#undef USE_IDARRAYBLOCK
+#define USE_REL_IDARRAY
+
/*------------------------------------------------------------------*/
/* Id map optimizations */
}
}
+static void
+write_compressed_blob(Repodata *data, void *blob, int len)
+{
+ unsigned char cpage[65536];
+ if (data->error)
+ return;
+ while (len > 0)
+ {
+ int chunk = len > sizeof(cpage) ? sizeof(cpage) : len;
+ int flag = (chunk == len ? 0x80 : 0x00);
+ int clen = repopagestore_compress_page(blob, chunk, cpage, sizeof(cpage) - 1);
+ if (!clen)
+ {
+ write_u8(data, flag);
+ write_u8(data, chunk >> 8);
+ write_u8(data, chunk);
+ write_blob(data, blob, chunk);
+ }
+ else
+ {
+ write_u8(data, flag | 0x40);
+ write_u8(data, clen >> 8);
+ write_u8(data, clen);
+ write_blob(data, cpage, clen);
+ }
+ blob += chunk;
+ len -= chunk;
+ }
+}
+
/*
* Id
*/
data_addid(xd, (Id)x);
}
-#define USE_REL_IDARRAY
#ifdef USE_REL_IDARRAY
static int
Id lids[64], *sids;
Id id, old;
- if (!ids)
- return;
- if (!*ids)
+ if (!ids || !*ids)
{
- data_addid(xd, 0);
+ data_addideof(xd, 0, 1);
return;
}
for (len = 0; len < 64 && ids[len]; len++)
#else
+#ifdef USE_IDARRAYBLOCK
+
+static void
+data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
+{
+ Id id;
+ Id last = 0, tmp;
+ if (!ids || !*ids)
+ {
+ data_addideof(xd, 0, 1);
+ return;
+ }
+ while ((id = *ids++) != 0)
+ {
+ if (needid)
+ id = needid[NEEDIDOFF(id)].need;
+ tmp = id;
+ if (id < last)
+ id = (last - id) * 2 - 1; /* [1, 2 * last - 1] odd */
+ else if (id < 2 * last)
+ id = (id - last) * 2; /* [0, 2 * last - 2] even */
+ last = tmp;
+ data_addideof(xd, id, *ids ? 0 : 1);
+ }
+}
+
+#else
+
static void
data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
{
Id id;
if (!ids || !*ids)
{
- data_addid(xd, 0);
+ data_addideof(xd, 0, 1);
return;
}
while ((id = *ids++) != 0)
#endif
+#endif
+
static inline void
data_addblob(struct extdata *xd, unsigned char *blob, int len)
{
Repo *repo = s->repo;
Pool *pool = repo->pool;
struct extdata *xd = cbdata->extdata;
+#ifdef USE_IDARRAYBLOCK
+ struct extdata *xda = xd + cbdata->target->nkeys; /* idarray block */
+#else
+ struct extdata *xda = xd;
+#endif
+
NeedId *needid = cbdata->needid;
Id *idarraydata = repo->idarraydata;
if (s->vendor && keymap[SOLVABLE_VENDOR])
data_addid(xd, needid[s->vendor].need);
if (s->provides && keymap[SOLVABLE_PROVIDES])
- data_adddepids(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
+ data_adddepids(xda, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
if (s->obsoletes && keymap[SOLVABLE_OBSOLETES])
- data_adddepids(xd, pool, needid, idarraydata + s->obsoletes, 0);
+ data_adddepids(xda, pool, needid, idarraydata + s->obsoletes, 0);
if (s->conflicts && keymap[SOLVABLE_CONFLICTS])
- data_adddepids(xd, pool, needid, idarraydata + s->conflicts, 0);
+ data_adddepids(xda, pool, needid, idarraydata + s->conflicts, 0);
if (s->requires && keymap[SOLVABLE_REQUIRES])
- data_adddepids(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
+ data_adddepids(xda, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
if (s->recommends && keymap[SOLVABLE_RECOMMENDS])
- data_adddepids(xd, pool, needid, idarraydata + s->recommends, 0);
+ data_adddepids(xda, pool, needid, idarraydata + s->recommends, 0);
if (s->suggests && keymap[SOLVABLE_SUGGESTS])
- data_adddepids(xd, pool, needid, idarraydata + s->suggests, 0);
+ data_adddepids(xda, pool, needid, idarraydata + s->suggests, 0);
if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS])
- data_adddepids(xd, pool, needid, idarraydata + s->supplements, 0);
+ data_adddepids(xda, pool, needid, idarraydata + s->supplements, 0);
if (s->enhances && keymap[SOLVABLE_ENHANCES])
- data_adddepids(xd, pool, needid, idarraydata + s->enhances, 0);
+ data_adddepids(xda, pool, needid, idarraydata + s->enhances, 0);
if (repo->rpmdbid && keymap[RPM_RPMDBID])
data_addid(xd, repo->rpmdbid[(s - pool->solvables) - repo->start]);
}
Repowriter *
repowriter_free(Repowriter *writer)
{
+ solv_free(writer->userdata);
return solv_free(writer);
}
writer->solvableend = solvableend;
}
+void
+repowriter_set_userdata(Repowriter *writer, const void *data, int len)
+{
+ writer->userdata = solv_free(writer->userdata);
+ writer->userdatalen = 0;
+ if (len < 0 || len >= 65536)
+ return;
+ writer->userdata = len ? solv_memdup(data, len) : 0;
+ writer->userdatalen = len;
+}
+
/*
* the code works the following way:
*
if (i < SOLVABLE_PROVIDES)
keyd.type = REPOKEY_TYPE_ID;
else if (i < RPM_RPMDBID)
-#ifdef USE_REL_IDARRAY
- keyd.type = REPOKEY_TYPE_REL_IDARRAY;
-#else
keyd.type = REPOKEY_TYPE_IDARRAY;
-#endif
else
keyd.type = REPOKEY_TYPE_NUM;
+#ifdef USE_REL_IDARRAY
+ if (keyd.type == REPOKEY_TYPE_IDARRAY)
+ keyd.type = REPOKEY_TYPE_REL_IDARRAY;
+#endif
keyd.size = 0;
keyd.storage = KEY_STORAGE_SOLVABLE;
if (writer->keyfilter)
continue;
keyd.storage = KEY_STORAGE_SOLVABLE;
}
+#ifdef USE_IDARRAYBLOCK
+ if (keyd.type == REPOKEY_TYPE_IDARRAY)
+ keyd.storage = KEY_STORAGE_IDARRAYBLOCK;
+#endif
poolusage = 1;
clonepool = 1;
keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
keymap[n] = 0;
continue;
}
+ if (keyd.storage != KEY_STORAGE_VERTICAL_OFFSET)
+ keyd.storage = KEY_STORAGE_INCORE; /* do not mess with us */
}
if (data->state != REPODATA_STUB)
id = repodata_key2id(&target, &keyd, 1);
/* collect all data
* we use extdata[0] for incore data and extdata[keyid] for vertical data
+ * we use extdata[nkeys] for the idarray_block data
*
* this must match the code above that creates the schema data!
*/
- cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
+ cbdata.extdata = solv_calloc(target.nkeys + 1, sizeof(struct extdata));
xd = cbdata.extdata;
cbdata.current_sub = 0;
target.fp = fp;
/* write header */
+ solv_flags = 0;
+ solv_flags |= SOLV_FLAG_PREFIX_POOL;
+ solv_flags |= SOLV_FLAG_SIZE_BYTES;
+ if (writer->userdatalen)
+ solv_flags |= SOLV_FLAG_USERDATA;
+ if (cbdata.extdata[target.nkeys].len)
+ solv_flags |= SOLV_FLAG_IDARRAYBLOCK;
/* write file header */
write_u32(&target, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
- write_u32(&target, SOLV_VERSION_8);
-
+ if ((solv_flags & (SOLV_FLAG_USERDATA | SOLV_FLAG_IDARRAYBLOCK)) != 0)
+ write_u32(&target, SOLV_VERSION_9);
+ else
+ write_u32(&target, SOLV_VERSION_8);
/* write counts */
write_u32(&target, nstrings);
write_u32(&target, anysolvableused ? nsolvables : 0);
write_u32(&target, target.nkeys);
write_u32(&target, target.nschemata);
- solv_flags = 0;
- solv_flags |= SOLV_FLAG_PREFIX_POOL;
- solv_flags |= SOLV_FLAG_SIZE_BYTES;
write_u32(&target, solv_flags);
+ /* write userdata */
+ if ((solv_flags & SOLV_FLAG_USERDATA) != 0)
+ {
+ write_u32(&target, writer->userdatalen);
+ write_blob(&target, writer->userdata, writer->userdatalen);
+ }
+
if (nstrings)
{
/*
}
else
{
- write_u32(&target, 0);
- write_u32(&target, 0);
+ write_u32(&target, 0); /* unpacked size */
+ write_u32(&target, 0); /* compressed size */
}
/*
for (i = 1; i < target.nschemata; i++)
write_idarray(&target, pool, 0, repodata_id2schema(&target, i));
+ /* write idarray_block data if not empty */
+ if (cbdata.extdata[target.nkeys].len)
+ {
+ unsigned int cnt = 0;
+ unsigned char *b;
+ unsigned int l;
+
+ xd = cbdata.extdata + target.nkeys;
+ /* calculate number of entries */
+ for (l = xd->len, b = xd->buf; l--;)
+ {
+ unsigned char x = *b++;
+ if ((x & 0x80) == 0)
+ cnt += (x & 0x40) ? 1 : 2;
+ }
+ write_id(&target, cnt);
+ if (cnt)
+ write_compressed_blob(&target, xd->buf, xd->len);
+ solv_free(xd->buf);
+ }
+
/*
* write incore data
*/
+ xd = cbdata.extdata;
write_id(&target, cbdata.maxdata);
- write_id(&target, cbdata.extdata[0].len);
- if (cbdata.extdata[0].len)
- write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len);
- solv_free(cbdata.extdata[0].buf);
+ write_id(&target, xd->len);
+ if (xd->len)
+ write_blob(&target, xd->buf, xd->len);
+ solv_free(xd->buf);
/*
* write vertical data if we have any
int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
void *kfdata;
Queue *keyq;
+ void *userdata;
+ int userdatalen;
} Repowriter;
/* repowriter flags */
void repowriter_set_keyqueue(Repowriter *writer, Queue *keyq);
void repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend);
void repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend);
+void repowriter_set_userdata(Repowriter *writer, const void *data, int len);
int repowriter_write(Repowriter *writer, FILE *fp);
/* convenience functions */
#define KEY_STORAGE_SOLVABLE 1
#define KEY_STORAGE_INCORE 2
#define KEY_STORAGE_VERTICAL_OFFSET 3
+#define KEY_STORAGE_IDARRAYBLOCK 4
#ifdef LIBSOLV_INTERNAL
struct dircache;
unsigned int litofs = 0;
memset(htab, -1, sizeof (htab));
memset(hnext, -1, sizeof (hnext));
+ if (in_len > BLOCK_SIZE)
+ return 0; /* Hey! */
while (io + 2 < in_len)
{
/* Search for a match of the string starting at IN, we have at
mlen = 0;
mofs = 0;
- for (tries = 0; try != -1 && tries < 12; tries++)
+ for (tries = 0; try != (Ref)-1 && tries < 12; tries++, try = hnext[try])
{
- if (try < io
- && in[try] == in[io] && in[try + 1] == in[io + 1])
+ if (in[try] == in[io] && in[try + 1] == in[io + 1])
{
mlen = 2;
mofs = (io - try) - 1;
break;
}
- try = hnext[try];
}
- for (; try != -1 && tries < 12; tries++)
+ for (; try != (Ref)-1 && tries < 12; tries++, try = hnext[try])
{
- /* assert(mlen >= 2); */
/* assert(io + mlen < in_len); */
/* Try a match starting from [io] with the strings at [try].
- That's only sensible if TRY actually is before IO (can happen
- with uninit hash table). If we have a previous match already
- we're only going to take the new one if it's longer, hence
- check the potentially last character. */
- if (try < io && in[try + mlen] == in[io + mlen])
+ If we have a previous match already we're only going to take
+ the new one if it's longer, hence check the potentially last
+ character first. */
+ if (in[try + mlen] == in[io + mlen] && !memcmp(in + try, in + io, mlen))
{
- unsigned int this_len, this_ofs;
- if (memcmp(in + try, in + io, mlen))
- goto no_match;
- this_len = mlen + 1;
+ /* Found a longer match */
+ mlen++;
/* Now try extending the match by more characters. */
- for (;
- io + this_len < in_len
- && in[try + this_len] == in[io + this_len]; this_len++)
- ;
-#if 0
- unsigned int testi;
- for (testi = 0; testi < this_len; testi++)
- assert(in[try + testi] == in[io + testi]);
-#endif
- this_ofs = (io - try) - 1;
- /*if (this_ofs > 65535)
- goto no_match; */
-#if 0
- assert(this_len >= 2);
- assert(this_len >= mlen);
- assert(this_len > mlen || (this_len == mlen && this_ofs > mofs));
-#endif
- mlen = this_len, mofs = this_ofs;
+ while (io + mlen < in_len && in[try + mlen] == in[io + mlen])
+ mlen++;
+ mofs = (io - try) - 1;
/* If our match extends up to the end of input, no next
match can become better. This is not just an
- optimization, it establishes a loop invariant
+ optimization, it establishes the loop invariant
(io + mlen < in_len). */
if (io + mlen >= in_len)
- goto match_done;
+ break;
}
- no_match:
- try = hnext[try];
- /*if (io - try - 1 >= 65536)
- break;*/
}
-
-match_done:
+ if (mlen < 3)
+ mlen = 0;
if (mlen)
{
/*fprintf(stderr, "%d %d\n", mlen, mofs);*/
- if (mlen == 2 && (litofs || mofs >= 1024))
- mlen = 0;
- /*else if (mofs >= 65536)
- mlen = 0;*/
- else if (mofs >= 65536)
+#if BLOCK_SIZE > 65536
+ if (mofs >= 65536)
{
if (mlen >= 2048 + 5)
mlen = 2047 + 5;
else if (mlen < 5)
mlen = 0;
}
- else if (mlen < 3)
- mlen = 0;
- /*else if (mlen >= 4096 + 19)
- mlen = 4095 + 19;*/
- else if (mlen >= 2048 + 19)
+#endif
+ if (mlen >= 2048 + 19)
mlen = 2047 + 19;
/* Skip this match if the next character would deliver a better one,
but only do this if we have the chance to really extend the
hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
hval = hval & (HS - 1);
try = htab[hval];
- if (try < io + 1
- && in[try] == in[io + 1] && in[try + 1] == in[io + 2])
+ if (try != (Ref)-1 && in[try] == in[io + 1] && in[try + 1] == in[io + 2])
{
- unsigned int this_len;
- this_len = 2;
- for (;
- io + 1 + this_len < in_len
- && in[try + this_len] == in[io + 1 + this_len];
- this_len++)
- ;
+ unsigned int this_len = 2;
+ while (io + 1 + this_len < in_len && in[try + this_len] == in[io + 1 + this_len])
+ this_len++;
if (this_len >= mlen)
mlen = 0;
}
}
if (!mlen)
{
+ /* Found no match, start/extend literal */
if (!litofs)
litofs = io + 1;
io++;
}
else
{
+ /* Found a match. First dump literals */
if (litofs)
{
unsigned litlen;
}
else if (mofs >= 65536)
{
+#if BLOCK_SIZE <= 65536
+ return 0;
+#else
assert(mlen >= 5 && mlen < 2048 + 5);
if (oo + 5 >= out_len)
return 0;
out[oo++] = mofs & 0xff;
out[oo++] = (mofs >> 8) & 0xff;
out[oo++] = mofs >> 16;
+#endif
}
else if (mlen >= 3 && mlen <= 18)
{
htab[hval] = io;
}
io++;
- };
+ }
}
}
/* We might have some characters left. */
{
o = in[0] | (in[1] << 8);
in += 2;
- first = first & 31;
- first += 3;
+ first = (first & 15) + 3;
break;
}
case 15:
- /* f1 1111llll <8o> <8o> <8l> */
- /* f2 11110lll <8o> <8o> <8l> */
- /* g 11111lll <8o> <8o> <8o> <8l> */
+ /* f2 11110lll <8l> <8o> <8o> */
+ /* g 11111lll <8l> <8o> <8o> <8o> */
{
first = first & 15;
if (first >= 8)
return out - orig_out;
}
+static unsigned int
+check_decompress_buf(const unsigned char *in, unsigned int in_len)
+{
+ unsigned int out_len = 0;
+ const unsigned char *in_end = in + in_len;
+ while (in < in_end)
+ {
+ unsigned int first = *in++;
+ int o;
+ switch (first >> 4)
+ {
+ default:
+ /* This default case can't happen, but GCCs VRP is not strong
+ enough to see this, so make this explicitely not fall to
+ the end of the switch, so that we don't have to initialize
+ o above. */
+ continue;
+ case 0: case 1:
+ case 2: case 3:
+ case 4: case 5:
+ case 6: case 7:
+ out_len++;
+ continue;
+ case 8: case 9:
+ /* b 100lllll <l+1 bytes> */
+ first = (first & 31) + 1;
+ in += first;
+ out_len += first;
+ continue;
+ case 10: case 11:
+ /* c 101oolll <8o> */
+ o = (first & (3 << 3)) << 5 | *in++;
+ first = (first & 7) + 2;
+ break;
+ case 12: case 13:
+ /* d 110lllll <8o> */
+ o = *in++;
+ first = (first & 31) + 10;
+ break;
+ case 14:
+ /* e 1110llll <8o> <8o> */
+ o = in[0] | (in[1] << 8);
+ in += 2;
+ first = (first & 15) + 3;
+ break;
+ case 15:
+ /* f1 1111llll <8l> <8o> <8o> */
+ /* g 11111lll <8l> <8o> <8o> <8o> */
+ first = first & 15;
+ if (first >= 8)
+ {
+ first = (((first - 8) << 8) | in[0]) + 5;
+ o = in[1] | (in[2] << 8) | (in[3] << 16);
+ in += 4;
+ }
+ else
+ {
+ first = ((first << 8) | in[0]) + 19;
+ o = in[1] | (in[2] << 8);
+ in += 3;
+ }
+ break;
+ }
+ /* fprintf(stderr, "ref: %d @ %d\n", first, o); */
+ if (o >= out_len)
+ return 0;
+ out_len += first;
+ }
+ return out_len;
+}
+
/**********************************************************************/
void repopagestore_init(Repopagestore *store)
return compress_buf(page, len, cpage, max);
}
+unsigned int
+repopagestore_decompress_page(const unsigned char *cpage, unsigned int len, unsigned char *page, unsigned int max)
+{
+ unsigned int l = check_decompress_buf(cpage, len);
+ if (l == 0 || l > max)
+ return 0;
+ return unchecked_decompress_buf(cpage, len, page, max);
+}
+
+
#define SOLV_ERROR_EOF 3
#define SOLV_ERROR_CORRUPT 6
/* compress a page, return compressed len */
unsigned int repopagestore_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max);
+/* uncompress a page, return uncompressed len */
+unsigned int repopagestore_decompress_page(const unsigned char *cpage, unsigned int len, unsigned char *page, unsigned int max);
/* setup page data for repodata_load_page_range */
int repopagestore_read_or_setup_pages(Repopagestore *store, FILE *fp, unsigned int pagesz, unsigned int blobsz);
/***********************************************************************
***
+ *** Strict repo prio rule part
+ ***/
+
+/* add rules to exclude solvables provided by lower
+ * precedence repositories */
+void solver_addstrictrepopriorules(struct s_Solver *solv, Map *addedmap)
+{
+ Pool *pool = solv->pool;
+ Solvable *s;
+ Id p, p2, pp2;
+ Map priomap;
+ int max_prio;
+
+ map_init_clone(&priomap, addedmap);
+ solv->strictrepopriorules = solv->nrules;
+
+ FOR_POOL_SOLVABLES(p)
+ {
+ if (!MAPTST(&priomap, p))
+ continue;
+
+ s = pool->solvables + p;
+ max_prio = s->repo->priority;
+ FOR_PROVIDES(p2, pp2, s->name)
+ {
+ Solvable *s2 = pool->solvables + p2;
+ if (s->name != s2->name)
+ continue;
+ if (s2->repo->priority > max_prio)
+ max_prio = s2->repo->priority;
+ }
+
+ FOR_PROVIDES(p2, pp2, s->name)
+ {
+ Solvable *s2 = pool->solvables + p2;
+ if (s->name != s2->name || !MAPTST(&priomap, p2))
+ continue;
+ MAPCLR(&priomap, p2);
+ if (pool->installed && s2->repo == pool->installed)
+ continue;
+ if (s2->repo->priority < max_prio)
+ solver_addrule(solv, -p2, 0, 0);
+ }
+ }
+ solv->strictrepopriorules_end = solv->nrules;
+ map_free(&priomap);
+}
+
+static inline void
+disablerepopriorule(Solver *solv, Id name)
+{
+ Pool *pool = solv->pool;
+ Rule *r;
+ int i;
+ for (i = solv->strictrepopriorules, r = solv->rules + i; i < solv->strictrepopriorules_end; i++, r++)
+ {
+ if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
+ solver_disablerule(solv, r);
+ }
+}
+
+static inline void
+reenablerepopriorule(Solver *solv, Id name)
+{
+ Pool *pool = solv->pool;
+ Rule *r;
+ int i;
+ for (i = solv->strictrepopriorules, r = solv->rules + i; i < solv->strictrepopriorules_end; i++, r++)
+ {
+ if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
+ {
+ solver_enablerule(solv, r);
+ IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+ {
+ POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+ solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ ***
*** Policy rule disabling/reenabling
***
*** Disable all policy rules that conflict with our jobs. If a job
***
***/
-#define DISABLE_UPDATE 1
-#define DISABLE_INFARCH 2
-#define DISABLE_DUP 3
-#define DISABLE_BLACK 4
+#define DISABLE_UPDATE 1
+#define DISABLE_INFARCH 2
+#define DISABLE_DUP 3
+#define DISABLE_BLACK 4
+#define DISABLE_REPOPRIO 5
static void
jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
}
}
}
+ if ((set & SOLVER_SETREPO) != 0 && solv->strictrepopriorules != solv->strictrepopriorules_end)
+ {
+ if (select == SOLVER_SOLVABLE)
+ queue_push2(q, DISABLE_REPOPRIO, pool->solvables[what].name);
+ else
+ {
+ int qcnt = q->count;
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ s = pool->solvables + p;
+ /* unify names */
+ for (i = qcnt; i < q->count; i += 2)
+ if (q->elements[i + 1] == s->name)
+ break;
+ if (i < q->count)
+ continue;
+ queue_push2(q, DISABLE_REPOPRIO, s->name);
+ }
+ }
+ }
if ((set & SOLVER_SETEVR) != 0 && solv->blackrules != solv->blackrules_end)
{
if (select == SOLVER_SOLVABLE)
case DISABLE_BLACK:
disableblackrule(solv, arg);
break;
+ case DISABLE_REPOPRIO:
+ disablerepopriorule(solv, arg);
+ break;
default:
break;
}
case DISABLE_BLACK:
reenableblackrule(solv, arg);
break;
+ case DISABLE_REPOPRIO:
+ reenablerepopriorule(solv, arg);
+ break;
}
}
queue_free(&q);
*fromp = -r->p;
return SOLVER_RULE_BLACK;
}
+ if (rid >= solv->strictrepopriorules && rid < solv->strictrepopriorules_end)
+ {
+ if (fromp)
+ *fromp = -r->p;
+ return SOLVER_RULE_STRICT_REPO_PRIORITY;
+ }
if (rid >= solv->choicerules && rid < solv->choicerules_end)
return SOLVER_RULE_CHOICE;
if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
return SOLVER_RULE_CHOICE;
if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
return SOLVER_RULE_RECOMMENDS;
- if (rid >= solv->blackrules && rid < solv->blackrules_end)
- return SOLVER_RULE_BLACK;
+ if (rid >= solv->strictrepopriorules && rid < solv->strictrepopriorules_end)
+ return SOLVER_RULE_STRICT_REPO_PRIORITY;
if (rid >= solv->learntrules && rid < solv->nrules)
return SOLVER_RULE_LEARNT;
return SOLVER_RULE_UNKNOWN;
SOLVER_RULE_BEST = 0x900,
SOLVER_RULE_YUMOBS = 0xa00,
SOLVER_RULE_RECOMMENDS = 0xb00,
- SOLVER_RULE_BLACK = 0xc00
+ SOLVER_RULE_BLACK = 0xc00,
+ SOLVER_RULE_STRICT_REPO_PRIORITY = 0xd00
} SolverRuleinfo;
#define SOLVER_RULE_TYPEMASK 0xff00
/* recommends rules */
extern void solver_addrecommendsrules(struct s_Solver *solv);
+/* channel priority rules */
+extern void solver_addstrictrepopriorules(struct s_Solver *solv, Map *addedmap);
+
/* policy rule disabling/reenabling */
extern void solver_disablepolicyrules(struct s_Solver *solv);
extern void solver_reenablepolicyrules(struct s_Solver *solv, int jobidx);
SHA256_Transform(context, context->buffer);
}
-void solv_SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
+void solv_SHA256_Final(sha2_byte digest[SHA256_DIGEST_LENGTH], SHA256_CTX* context) {
sha2_word32 *d = (sha2_word32*)digest;
/* Sanity check: */
SHA512_Transform(context, context->buffer);
}
-void solv_SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
+void solv_SHA512_Final(sha2_byte digest[SHA512_DIGEST_LENGTH], SHA512_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
solv_SHA512_Update((SHA512_CTX*)context, data, len);
}
-void solv_SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
+void solv_SHA384_Final(sha2_byte digest[SHA384_DIGEST_LENGTH], SHA384_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
solv_SHA256_Update((SHA256_CTX*)context, data, len);
}
-void solv_SHA224_Final(sha2_byte digest[], SHA224_CTX* context) {
+void solv_SHA224_Final(sha2_byte digest[SHA224_DIGEST_LENGTH], SHA224_CTX* context) {
sha2_word32 *d = (sha2_word32*)digest;
/* Sanity check: */
struct s_Repo *repo; /* repo we belong to */
/* dependencies are offsets into repo->idarraydata */
+ /* the ifdef resolves "requires" conflicting with a C++20 keyword */
+#ifdef LIBSOLV_SOLVABLE_PREPEND_DEP
+ Offset dep_provides; /* terminated with Id 0 */
+ Offset dep_obsoletes;
+ Offset dep_conflicts;
+
+ Offset dep_requires;
+ Offset dep_recommends;
+ Offset dep_suggests;
+
+ Offset dep_supplements;
+ Offset dep_enhances;
+#else
Offset provides; /* terminated with Id 0 */
Offset obsoletes;
Offset conflicts;
Offset supplements;
Offset enhances;
-
+#endif
} Solvable;
/* lookup functions */
return solv->install_also_updates;
case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
return solv->only_namespace_recommended;
+ case SOLVER_FLAG_STRICT_REPO_PRIORITY:
+ return solv->strict_repo_priority;
default:
break;
}
case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
solv->only_namespace_recommended = value;
break;
+ case SOLVER_FLAG_STRICT_REPO_PRIORITY:
+ solv->strict_repo_priority = value;
+ break;
default:
break;
}
else
solv->recommendsrules = solv->recommendsrules_end = solv->nrules;
+ if (solv->strict_repo_priority)
+ solver_addstrictrepopriorules(solv, &addedmap);
+ else
+ solv->strictrepopriorules = solv->strictrepopriorules_end = solv->nrules;
+
if (1)
solver_addchoicerules(solv);
else
map_free(&installcandidatemap);
queue_free(&q);
- POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules);
+ POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n",
+ solv->pkgrules_end - 1,
+ solv->updaterules_end - solv->updaterules,
+ solv->jobrules_end - solv->jobrules,
+ solv->infarchrules_end - solv->infarchrules,
+ solv->duprules_end - solv->duprules,
+ solv->choicerules_end - solv->choicerules,
+ solv->bestrules_end - solv->bestrules,
+ solv->yumobsrules_end - solv->yumobsrules);
+ POOL_DEBUG(SOLV_DEBUG_STATS, "%d black rules, %d recommends rules, %d repo priority rules\n",
+ solv->blackrules_end - solv->blackrules,
+ solv->recommendsrules_end - solv->recommendsrules,
+ solv->strictrepopriorules_end - solv->strictrepopriorules);
POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
/* create weak map */
Id blackrules; /* rules from blacklisted packages */
Id blackrules_end;
+ Id strictrepopriorules; /* rules from strict priority repositories */
+ Id strictrepopriorules_end;
+
Id choicerules; /* choice rules (always weak) */
Id choicerules_end;
Id *choicerules_info; /* the rule we used to generate the choice rule */
int strongrecommends; /* true: create weak rules for recommends */
int install_also_updates; /* true: do not prune install job rules to installed packages */
int only_namespace_recommended; /* true: only install packages recommended by namespace */
+ int strict_repo_priority; /* true: only use packages from highest precedence/priority */
int process_orphans; /* true: do special orphan processing */
Map dupmap; /* dup to those packages */
#define SOLVER_FLAG_STRONG_RECOMMENDS 25
#define SOLVER_FLAG_INSTALL_ALSO_UPDATES 26
#define SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED 27
+#define SOLVER_FLAG_STRICT_REPO_PRIORITY 28
#define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead of ids */
#define GET_USERINSTALLED_INVERTED (1 << 1) /* autoinstalled */
#include "pool.h"
#include "poolarch.h"
#include "util.h"
+#include "evr.h"
/*-------------------------------------------------------------------
Id l, pp;
if (solv->decisionmap[p] >= 0)
return 0; /* old package stayed */
- r = solv->rules + solv->updaterules + (p - solv->installed->start);
+ r = solv->rules + solv->featurerules + (p - solv->installed->start);
+ if (!r->p)
+ r = solv->rules + solv->updaterules + (p - solv->installed->start);
FOR_RULELITERALS(l, pp, r)
if (l > 0 && l != p && solv->decisionmap[l] > 0)
- return 1;
+ {
+ /* check that this is really an upgrade */
+ Solvable *si = pool->solvables + p;
+ Solvable *s = pool->solvables + l;
+ if (s->name != si->name || pool_evrcmp(pool, s->evr, si->evr, EVRCMP_COMPARE) > 0)
+ return 1;
+ }
return 0;
}
POOL_DEBUG(type, "YUMOBS ");
else if (p >= solv->blackrules && p < solv->blackrules_end)
POOL_DEBUG(type, "BLACK ");
+ else if (p >= solv->strictrepopriorules && p < solv->strictrepopriorules_end)
+ POOL_DEBUG(type, "REPOPRIO ");
else if (p >= solv->recommendsrules && p < solv->recommendsrules_end)
POOL_DEBUG(type, "RECOMMENDS ");
solver_printrule(solv, type, r);
int solv_version_major = LIBSOLV_VERSION_MAJOR;
int solv_version_minor = LIBSOLV_VERSION_MINOR;
int solv_version_patch = LIBSOLV_VERSION_PATCH;
+const char solv_toolversion[] = LIBSOLV_TOOLVERSION;
extern int solv_version_major;
extern int solv_version_minor;
extern int solv_version_patch;
+extern const char solv_toolversion[];
#cmakedefine LIBSOLV_FEATURE_LINKED_PKGS
#cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS
#cmakedefine LIBSOLVEXT_FEATURE_ZCHUNK_COMPRESSION
/* see tools/common_write.c for toolversion history */
-#define LIBSOLV_TOOLVERSION "1.1"
+#define LIBSOLV_TOOLVERSION "1.2"
#endif
return buf;
}
-static inline void *solv_memdup(void *buf, size_t len)
+static inline void *solv_memdup(const void *buf, size_t len)
{
void *newbuf;
if (!buf)
return newbuf;
}
-static inline void *solv_memdup2(void *buf, size_t num, size_t len)
+static inline void *solv_memdup2(const void *buf, size_t num, size_t len)
{
void *newbuf;
if (!buf)
--- /dev/null
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+repo available 1 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Req: B
+system i686 rpm system
+
+solverflags strictrepopriority
+job install name A
+result transaction,problems <inline>
+#>problem 30c1639e info nothing provides B needed by A-1-1.noarch
+#>problem 30c1639e solution 23f73f5b deljob install name A
+#>problem 30c1639e solution 5dd1416b allow A-2-1.noarch@available
+
+nextjob
+
+solverflags strictrepopriority
+job install pkg A-2-1.noarch@available
+result transaction,problems <inline>
+#>install A-2-1.noarch@available
+
/* toolversion history
* 1.0: initial tool version
* 1.1: changed PRODUCT_ENDOFLIFE parsing
+ * 1.2: added UPDATE_COLLECTIONLIST to updateinfo
*/
static int
static int with_attr;
static int dump_json;
+static int dump_userdata;
#include "pool.h"
#include "chksum.h"
int c, i, j, n;
Solvable *s;
- pool = pool_create();
- pool_setloadcallback(pool, loadcallback, 0);
-
- while ((c = getopt(argc, argv, "haj")) >= 0)
+ while ((c = getopt(argc, argv, "uhaj")) >= 0)
{
switch(c)
{
case 'j':
dump_json = 1;
break;
+ case 'u':
+ dump_userdata++;
+ break;
default:
usage(1);
break;
}
}
+ if (dump_userdata)
+ {
+ if (optind == argc)
+ argc++;
+ for (; optind < argc; optind++)
+ {
+ unsigned char *userdata = 0;
+ int r, userdatalen = 0;
+ if (argv[optind] && freopen(argv[optind], "r", stdin) == 0)
+ {
+ perror(argv[optind]);
+ exit(1);
+ }
+ r = solv_read_userdata(stdin, &userdata, &userdatalen);
+ if (r)
+ {
+ fprintf(stderr, "could not read userdata: error %d\n", r);
+ exit(1);
+ }
+ if (dump_userdata > 1)
+ {
+ /* dump raw */
+ if (userdatalen && fwrite(userdata, userdatalen, 1, stdout) != 1)
+ {
+ perror("fwrite");
+ exit(1);
+ }
+ }
+ else
+ {
+ for (r = 0; r < userdatalen; r++)
+ printf("%02x", userdata[r]);
+ printf("\n");
+ }
+ solv_free(userdata);
+ }
+ exit(0);
+ }
+
+ pool = pool_create();
+ pool_setloadcallback(pool, loadcallback, 0);
if (!dump_json)
pool_setdebuglevel(pool, 1);
if (dump_json)
{
int pcnt = solver_solve(solv, &job);
if (writetestcase)
- testcase_write(solv, writetestcase, resultflags, 0, 0);
+ {
+ if (!testcase_write(solv, writetestcase, resultflags, 0, 0))
+ {
+ fprintf(stderr, "Could not write testcase: %s\n", pool_errstr(pool));
+ exit(1);
+ }
+ }
if (pcnt && solq.count)
{
int i, taken = 0;