Beispiel #1
0
void
queue_alloc_one(Queue *q)
{
  if (!q->alloc)
    {
      q->alloc = solv_malloc2(q->count + EXTRA_SPACE, sizeof(Id));
      if (q->count)
	memcpy(q->alloc, q->elements, q->count * sizeof(Id));
      q->elements = q->alloc;
      q->left = EXTRA_SPACE;
    }
  else if (q->alloc != q->elements)
    {
      int l = q->elements - q->alloc;
      if (q->count)
        memmove(q->alloc, q->elements, q->count * sizeof(Id));
      q->elements -= l;
      q->left += l;
    }
  else
    {
      q->elements = q->alloc = solv_realloc2(q->alloc, q->count + EXTRA_SPACE, sizeof(Id));
      q->left = EXTRA_SPACE;
    }
}
Beispiel #2
0
/*
 * we support three relations:
 *
 * a = b   both architectures a and b are treated as equivalent
 * a > b   a is considered a "better" architecture, the solver
 *         should change from a to b, but must not change from b to a
 * a : b   a is considered a "better" architecture, the solver
 *         must not change the architecture from a to b or b to a
 */
void
pool_setarchpolicy(Pool *pool, const char *arch)
{
  unsigned int score = 0x10001;
  size_t l;
  char d;
  Id *id2arch;
  Id id, lastarch;

  pool->id2arch = solv_free(pool->id2arch);
  pool->id2color = solv_free(pool->id2color);
  if (!arch)
    {
      pool->lastarch = 0;
      return;
    }
  id = pool->noarchid;
  lastarch = id + 255;
  /* note that we overallocate one element to be compatible with
   * old versions that accessed id2arch[lastarch].
   * id2arch[lastarch] will always be zero */
  id2arch = solv_calloc(lastarch + 1, sizeof(Id));
  id2arch[id] = 1;	/* the "noarch" class */

  d = 0;
  while (*arch)
    {
      l = strcspn(arch, ":=>");
      if (l)
	{
	  id = pool_strn2id(pool, arch, l, 1);
	  if (id >= lastarch)
	    {
	      id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id));
	      memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id));
	      lastarch = id + 255;
	    }
	  if (id2arch[id] == 0)
	    {
	      if (d == ':')
		score += 0x10000;
	      else if (d == '>')
		score += 0x00001;
	      id2arch[id] = score;
	    }
	}
      arch += l;
      if ((d = *arch++) == 0)
	break;
    }
  pool->id2arch = id2arch;
  pool->lastarch = lastarch;
}
Beispiel #3
0
/* allocate room for n more elements */
void
queue_prealloc(Queue *q, int n)
{
  int off;
  if (n <= 0 || q->left >= n)
    return;
  if (!q->alloc)
    queue_alloc_one(q);
  off = q->elements - q->alloc;
  q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id));
  q->elements = q->alloc + off;
  q->left = n + EXTRA_SPACE;
}
Beispiel #4
0
/*
 * we support three relations:
 *
 * a = b   both architectures a and b are treated as equivalent
 * a > b   a is considered a "better" architecture, the solver
 *         should change from a to b, but must not change from b to a
 * a : b   a is considered a "better" architecture, the solver
 *         must not change the architecture from a to b or b to a
 */
void
pool_setarchpolicy(Pool *pool, const char *arch)
{
  unsigned int score = 0x10001;
  size_t l;
  char d;
  Id *id2arch;
  Id id, lastarch;

  pool->id2arch = solv_free(pool->id2arch);
  pool->id2color = solv_free(pool->id2color);
  if (!arch)
    {
      pool->lastarch = 0;
      return;
    }
  id = pool->noarchid;
  lastarch = id + 255;
  id2arch = solv_calloc(lastarch + 1, sizeof(Id));
  id2arch[id] = 1;	/* the "noarch" class */

  d = 0;
  while (*arch)
    {
      l = strcspn(arch, ":=>");
      if (l)
	{
	  id = pool_strn2id(pool, arch, l, 1);
	  if (id > lastarch)
	    {
	      id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id));
	      memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id));
	      lastarch = id + 255;
	    }
	  if (id2arch[id] == 0)
	    {
	      if (d == ':')
		score += 0x10000;
	      else if (d == '>')
		score += 0x00001;
	      id2arch[id] = score;
	    }
	}
      arch += l;
      if ((d = *arch++) == 0)
	break;
    }
  pool->id2arch = id2arch;
  pool->lastarch = lastarch;
}
Beispiel #5
0
void
queue_insertn(Queue *q, int pos, int n)
{
  if (n <= 0)
    return;
  if (pos > q->count)
    pos = q->count;
  if (q->left < n)
    {
      int off;
      if (!q->alloc)
	queue_alloc_one(q);
      off = q->elements - q->alloc;
      q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id));
      q->elements = q->alloc + off;
      q->left = n + EXTRA_SPACE;
    }
  if (pos < q->count)
    memmove(q->elements + pos + n, q->elements + pos, (q->count - pos) * sizeof(Id));
  memset(q->elements + pos, 0, n * sizeof(Id));
  q->left -= n;
  q->count += n;
}
Beispiel #6
0
Repo *
repo_create(Pool *pool, const char *name)
{
  Repo *repo;

  pool_freewhatprovides(pool);
  repo = (Repo *)solv_calloc(1, sizeof(*repo));
  if (!pool->nrepos)
    {
      pool->nrepos = 1;	/* start with repoid 1 */
      pool->repos = (Repo **)solv_calloc(2, sizeof(Repo *));
    }
  else
    pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
  pool->repos[pool->nrepos] = repo;
  pool->urepos++;
  repo->repoid = pool->nrepos++;
  repo->name = name ? solv_strdup(name) : 0;
  repo->pool = pool;
  repo->start = pool->nsolvables;
  repo->end = pool->nsolvables;
  repo->nsolvables = 0;
  return repo;
}
Beispiel #7
0
void
pool_addvendorclass(Pool *pool, const char **vendorclass)
{
  int i, j;

  if (!vendorclass || !vendorclass[0])
    return;
  for (j = 1; vendorclass[j]; j++)
    ;
  i = 0;
  if (pool->vendorclasses)
    {
      for (i = 0; pool->vendorclasses[i] || pool->vendorclasses[i + 1]; i++)
	;
      if (i)
        i++;
    }
  pool->vendorclasses = solv_realloc2((void *)pool->vendorclasses, i + j + 2, sizeof(const char *));
  for (j = 0; vendorclass[j]; j++)
    pool->vendorclasses[i++] = solv_strdup(vendorclass[j]);
  pool->vendorclasses[i++] = 0;
  pool->vendorclasses[i] = 0;
  queue_empty(&pool->vendormap);
}
Beispiel #8
0
Id
pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create)
{
  Hashval h, hh, hashmask;
  int i;
  Id id;
  Hashtable hashtbl;
  Reldep *ran;

  hashmask = pool->relhashmask;
  hashtbl = pool->relhashtbl;
  ran = pool->rels;
  
  /* extend hashtable if needed */
  if (pool->nrels * 2 > hashmask)
    {
      solv_free(pool->relhashtbl);
      pool->relhashmask = hashmask = mkmask(pool->nrels + REL_BLOCK);
      pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
      /* rehash all rels into new hashtable */
      for (i = 1; i < pool->nrels; i++)
	{
	  h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
	  hh = HASHCHAIN_START;
	  while (hashtbl[h])
	    h = HASHCHAIN_NEXT(h, hh, hashmask);
	  hashtbl[h] = i;
	}
    }
  
  /* compute hash and check for match */
  h = relhash(name, evr, flags) & hashmask;
  hh = HASHCHAIN_START;
  while ((id = hashtbl[h]) != 0)
    {
      if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
	break;
      h = HASHCHAIN_NEXT(h, hh, hashmask);
    }
  if (id)
    return MAKERELDEP(id);

  if (!create)
    return ID_NULL;

  id = pool->nrels++;
  /* extend rel space if needed */
  pool->rels = solv_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK);
  hashtbl[h] = id;
  ran = pool->rels + id;
  ran->name = name;
  ran->evr = evr;
  ran->flags = flags;

  /* extend whatprovides_rel if needed */
  if (pool->whatprovides_rel && (id & WHATPROVIDES_BLOCK) == 0)
    {
      pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, id + (WHATPROVIDES_BLOCK + 1), sizeof(Offset));
      memset(pool->whatprovides_rel + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
    }
  return MAKERELDEP(id);
}
Beispiel #9
0
static void
repo_addfileprovides_search(Repo *repo, struct addfileprovides_cbdata *cbd, struct searchfiles *sf)
{
  Repodata *data;
  int rdid, p, i;
  int provstart, provend;
  Map todo;
  Map providedids;

  if (repo->end <= repo->start || !repo->nsolvables || !sf->nfiles)
    return;

  /* update search data if changed */
  if (cbd->nfiles != sf->nfiles || cbd->ids != sf->ids)
    {
      free_dirs_names_array(cbd);
      cbd->nfiles = sf->nfiles;
      cbd->ids = sf->ids;
      cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
    }

  /* create todo map and range */
  map_init(&todo, repo->end - repo->start);
  for (p = repo->start; p < repo->end; p++)
    if (repo->pool->solvables[p].repo == repo)
      MAPSET(&todo, p - repo->start);
  cbd->todo = &todo;
  cbd->todo_start = repo->start;
  cbd->todo_end = repo->end;
  prune_todo_range(repo, cbd);

  provstart = provend = 0;
  map_init(&providedids, 0);
  data = repo_lookup_repodata(repo, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES);
  if (data)
    {
      Queue fileprovidesq;
      queue_init(&fileprovidesq);
      if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
	{
	  map_grow(&providedids, repo->pool->ss.nstrings);
	  cbd->providedids = &providedids;
	  provstart = data->start;
	  provend = data->end;
	  for (i = 0; i < fileprovidesq.count; i++)
	    MAPSET(&providedids, fileprovidesq.elements[i]);
	  for (i = 0; i < cbd->nfiles; i++)
	    if (!MAPTST(&providedids, cbd->ids[i]))
	      break;
	  if (i == cbd->nfiles)
	    {
	      /* all included, clear entries from todo list */
	      if (provstart <= cbd->todo_start && provend >= cbd->todo_end)
		cbd->todo_end = cbd->todo_start;	/* clear complete range */
	      else
		{
		  for (p = provstart; p < provend; p++)
		    MAPCLR(&todo, p - repo->start);
		  prune_todo_range(repo, cbd);
		}
	    }
	}
      queue_free(&fileprovidesq);
    }

  if (cbd->todo_start >= cbd->todo_end)
    {
      map_free(&todo);
      cbd->todo = 0;
      map_free(&providedids);
      cbd->providedids = 0;
      return;
    }

  /* this is similar to repo_lookup_filelist_repodata in repo.c */

  for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++)
    if (data->filelisttype == REPODATA_FILELIST_FILTERED)
      break;
  for (; rdid < repo->nrepodata; rdid++, data++)
    if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
      break;

  if (rdid < repo->nrepodata)
    {
      /* have at least one repodata with REPODATA_FILELIST_FILTERED followed by REPODATA_FILELIST_EXTENSION */
      Map postpone;
      map_init(&postpone, 0);
      for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
	{
	  if (data->filelisttype != REPODATA_FILELIST_FILTERED)
	    continue;
	  if (!repodata_intersects_todo(data, cbd))
	    continue;
	  if (data->state != REPODATA_AVAILABLE)
	    {
	      if (data->state != REPODATA_STUB)
		continue;
	      repodata_load(data);
	      if (data->state != REPODATA_AVAILABLE || data->filelisttype != REPODATA_FILELIST_FILTERED)
		continue;
	    }
	  repo_addfileprovides_search_filtered(repo, cbd, rdid, &postpone);
	}
      if (postpone.size)
	{
	  /* add postponed entries back to todo */
	  map_or(&todo, &postpone);
	  cbd->todo_start = repo->start;
	  cbd->todo_end = repo->end;
	  prune_todo_range(repo, cbd);
	}
      map_free(&postpone);
    }

  /* search remaining entries in the standard way */
  if (cbd->todo_start < cbd->todo_end)
    {
      for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
	{
	  if (data->start >= cbd->todo_end || data->end <= cbd->todo_start)
	    continue;
	  if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
	    continue;
	  if (!repodata_intersects_todo(data, cbd))
	    continue;
	  repodata_addfileprovides_search(data, cbd);
	  if (cbd->todo_start >= cbd->todo_end)
	    break;
	}
    }

  map_free(&todo);
  cbd->todo = 0;
  map_free(&providedids);
  cbd->providedids = 0;
}
Beispiel #10
0
/* 
 * Optimization for packages with an excessive amount of provides/requires:
 * if the number of deps exceed a threshold, we build a hash of the already
 * seen ids.
 */
static Offset
repo_addid_dep_hash(Repo *repo, Offset olddeps, Id id, Id marker, int size)
{
  Id oid, *oidp;
  int before;
  Hashval h, hh;
  Id hid;

  before = 0;
  if (marker)
    {
      if (marker < 0)
	{
	  marker = -marker;
	  before = 1;
	}
      if (marker == id)
	marker = 0;
    }

  /* maintain hash and lastmarkerpos */
  if (repo->lastidhash_idarraysize != repo->idarraysize || size * 2 > repo->lastidhash_mask || repo->lastmarker != marker)
    {
      repo->lastmarkerpos = 0;
      if (size * 2 > repo->lastidhash_mask)
	{
	  repo->lastidhash_mask = mkmask(size < REPO_ADDID_DEP_HASHMIN ? REPO_ADDID_DEP_HASHMIN : size);
	  repo->lastidhash = solv_realloc2(repo->lastidhash, repo->lastidhash_mask + 1, sizeof(Id));
	}
      memset(repo->lastidhash, 0, (repo->lastidhash_mask + 1) * sizeof(Id));
      for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
	{
	  h = oid & repo->lastidhash_mask;
	  hh = HASHCHAIN_START;
	  while (repo->lastidhash[h] != 0)
	    h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
	  repo->lastidhash[h] = oid;
	  if (marker && oid == marker)
	    repo->lastmarkerpos = oidp - repo->idarraydata;
	}
      repo->lastmarker = marker;
      repo->lastidhash_idarraysize = repo->idarraysize;
    }

  /* check the hash! */
  h = id & repo->lastidhash_mask;
  hh = HASHCHAIN_START;
  while ((hid = repo->lastidhash[h]) != 0 && hid != id)
    h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
  /* put new element in hash */
  if (!hid)
    repo->lastidhash[h] = id;
  else if (marker == SOLVABLE_FILEMARKER && (!before || !repo->lastmarkerpos))
    return olddeps;
  if (marker && !before && !repo->lastmarkerpos)
    {
      /* we have to add the marker first */
      repo->lastmarkerpos = repo->idarraysize - 1;
      olddeps = repo_addid(repo, olddeps, marker);
      /* now put marker in hash */
      h = marker & repo->lastidhash_mask;
      hh = HASHCHAIN_START;
      while (repo->lastidhash[h] != 0)
	h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
      repo->lastidhash[h] = marker;
      repo->lastidhash_idarraysize = repo->idarraysize;
    }
  if (!hid)
    {
      /* new entry, insert in correct position */
      if (marker && before && repo->lastmarkerpos)
	{
	  /* need to add it before the marker */
	  olddeps = repo_addid(repo, olddeps, id);	/* dummy to make room */
	  memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (repo->idarraysize - repo->lastmarkerpos - 2) * sizeof(Id));
	  repo->idarraydata[repo->lastmarkerpos++] = id;
	}
      else
	{
	  /* just append it to the end */
	  olddeps = repo_addid(repo, olddeps, id);
	}
      repo->lastidhash_idarraysize = repo->idarraysize;
      return olddeps;
    }
  /* we already have it in the hash */
  if (!marker)
    return olddeps;
  if (marker == SOLVABLE_FILEMARKER)
    {
      /* check if it is in the wrong half */
      /* (we already made sure that "before" and "lastmarkerpos" are set, see above) */
      for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
	if (oid == id)
	  break;
      if (!oid)
	return olddeps;
      /* yes, wrong half. copy it over */
      memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (oidp - (repo->idarraydata + repo->lastmarkerpos)) * sizeof(Id));
      repo->idarraydata[repo->lastmarkerpos++] = id;
      return olddeps;
    }
  if (before)
    return olddeps;
  /* check if it is in the correct half */
  for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
    if (oid == id)
      return olddeps;
  /* nope, copy it over */
  for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
    if (oid == id)
      break;
  if (!oid)
    return olddeps;	/* should not happen */
  memmove(oidp, oidp + 1, (repo->idarraydata + repo->idarraysize - oidp - 2) * sizeof(Id));
  repo->idarraydata[repo->idarraysize - 2] = id;
  repo->lastmarkerpos--;	/* marker has been moved */
  return olddeps;
}
Beispiel #11
0
int
tool_write(Repo *repo, const char *basename, const char *attrname)
{
    Repodata *data;
    Repodata *info = 0;
    Repokey *key;
    char **languages = 0;
    int nlanguages = 0;
    int i, j, k, l;
    Id *addedfileprovides = 0;
    struct keyfilter_data kd;

    memset(&kd, 0, sizeof(kd));
    info = repo_add_repodata(repo, 0);
    repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION);
    pool_addfileprovides_ids(repo->pool, 0, &addedfileprovides);
    if (addedfileprovides && *addedfileprovides)
    {
        kd.haveaddedfileprovides = 1;
        for (i = 0; addedfileprovides[i]; i++)
            repodata_add_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[i]);
    }
    solv_free(addedfileprovides);

    pool_freeidhashes(repo->pool);	/* free some mem */

    if (basename)
    {
        char fn[4096];
        FILE *fp;
        int has_DU = 0;
        int has_FL = 0;

        /* find languages and other info */
        FOR_REPODATAS(repo, i, data)
        {
            for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++)
            {
                const char *keyname = pool_id2str(repo->pool, key->name);
                if (key->name == SOLVABLE_DISKUSAGE)
                    has_DU = 1;
                if (key->name == SOLVABLE_FILELIST)
                    has_FL = 1;
                for (k = 0; languagetags[k] != 0; k++)
                    if (!strncmp(keyname, languagetags[k], strlen(languagetags[k])))
                        break;
                if (!languagetags[k])
                    continue;
                l = strlen(languagetags[k]);
                if (strlen(keyname + l) > 5)
                    continue;
                for (k = 0; k < nlanguages; k++)
                    if (!strcmp(languages[k], keyname + l))
                        break;
                if (k < nlanguages)
                    continue;
                languages = solv_realloc2(languages, nlanguages + 1, sizeof(char *));
                languages[nlanguages++] = strdup(keyname + l);
            }
        }
        /* write language subfiles */
        for (i = 0; i < nlanguages; i++)
        {
            sprintf(fn, "%s.%s.solv", basename, languages[i]);
            if (!(fp = fopen(fn, "w")))
            {
                perror(fn);
                exit(1);
            }
            write_info(repo, fp, keyfilter_language, languages[i], info, fn);
            fclose(fp);
            kd.haveexternal = 1;
        }
        /* write DU subfile */
        if (has_DU)
        {
            sprintf(fn, "%s.DU.solv", basename);
            if (!(fp = fopen(fn, "w")))
            {
                perror(fn);
                exit(1);
            }
            write_info(repo, fp, keyfilter_DU, 0, info, fn);
            fclose(fp);
            kd.haveexternal = 1;
        }
        /* write filelist */
        if (has_FL)
        {
            sprintf(fn, "%s.FL.solv", basename);
            if (!(fp = fopen(fn, "w")))
            {
                perror(fn);
                exit(1);
            }
            write_info(repo, fp, keyfilter_FL, 0, info, fn);
            fclose(fp);
            kd.haveexternal = 1;
        }
        /* write everything else */
        sprintf(fn, "%s.solv", basename);
        if (!(fp = fopen(fn, "w")))
        {
            perror(fn);
            exit(1);
        }
        kd.languages = languages;
        kd.nlanguages = nlanguages;
        repodata_internalize(info);
        repo_write(repo, fp, keyfilter_other, &kd, 0);
        fclose(fp);
        for (i = 0; i < nlanguages; i++)
            free(languages[i]);
        solv_free(languages);
        repodata_free(info);
        return 0;
    }
    if (attrname)
    {
        FILE *fp;
        test_separate = 1;
        fp = fopen(attrname, "w");
        write_info(repo, fp, keyfilter_attr, 0, info, attrname);
        fclose(fp);
        kd.haveexternal = 1;
    }
    repodata_internalize(info);
    repo_write(repo, stdout, keyfilter_solv, &kd, 0);
    repodata_free(info);
    return 0;
}