Example #1
0
static int
reldep_init(_ReldepObject *self, PyObject *args, PyObject *kwds)
{
    PyObject *sack;
    int cmp_type = 0;
    const char *reldep_str = NULL;
    char *name, *evr = NULL;
    if (!PyArg_ParseTuple(args, "O!s", &sack_Type, &sack, &reldep_str))
	return -1;
    HySack csack = sackFromPyObject(sack);
    if (csack == NULL)
	return -1;

    if (parse_reldep_str(reldep_str, &name, &evr, &cmp_type) == -1) {
	PyErr_Format(HyExc_Value, "Wrong reldep format: %s", reldep_str);
	return -1;
    }

    self->reldep = hy_reldep_create(csack, name, cmp_type, evr);
    solv_free(name);
    solv_free(evr);
    if (self->reldep == NULL) {
	PyErr_Format(HyExc_Value, "No such reldep: %s", name);
	return -1;
    }
    return 0;
}
Example #2
0
static int
glob_for_cachedir(char *path)
{
    int ret = 1;
    if (!str_endswith(path, "XXXXXX"))
	return ret;

    wordexp_t word_vector;
    char *p = solv_strdup(path);
    const int len = strlen(p);
    struct stat s;

    ret = 2;
    p[len-6] = '*';
    p[len-5] = '\0';
    if (wordexp(p, &word_vector, 0)) {
	solv_free(p);
	return ret;
    }
    for (int i = 0; i < word_vector.we_wordc; ++i) {
	char *entry = word_vector.we_wordv[i];
	if (stat(entry, &s))
	    continue;
	if (S_ISDIR(s.st_mode) &&
	    s.st_uid == getuid()) {
	    assert(strlen(path) == strlen(entry));
	    strcpy(path, entry);
	    ret = 0;
	    break;
	}
    }
    wordfree(&word_vector);
    solv_free(p);
    return ret;
}
Example #3
0
File: repo.c Project: gmoro/libsolv
void
repo_empty(Repo *repo, int reuseids)
{
  Pool *pool = repo->pool;
  Solvable *s;
  int i;

  pool_freewhatprovides(pool);
  if (reuseids && repo->end == pool->nsolvables)
    {
      /* it's ok to reuse the ids. As this is the last repo, we can
         just shrink the solvable array */
      for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
	if (s->repo != repo)
	  break;
      pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids);
    }
  /* zero out (i.e. free) solvables belonging to this repo */
  for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
    if (s->repo == repo)
      memset(s, 0, sizeof(*s));
  repo->nsolvables = 0;

  /* free all data belonging to this repo */
  repo->idarraydata = solv_free(repo->idarraydata);
  repo->idarraysize = 0;
  repo->lastoff = 0;
  repo->rpmdbid = solv_free(repo->rpmdbid);
  for (i = 1; i < repo->nrepodata; i++)
    repodata_freedata(repo->repodata + i);
  solv_free(repo->repodata);
  repo->repodata = 0;
  repo->nrepodata = 0;
}
Example #4
0
void
hy_packagedelta_free(HyPackageDelta delta)
{
    solv_free(delta->location);
    solv_free(delta->baseurl);
    solv_free(delta->checksum);
    solv_free(delta);
}
Example #5
0
static int cookie_bufclose(void *cookie)
{
  struct bufcookie *bc = cookie;
  if (bc->freemem)
    solv_free(bc->freemem);
  solv_free(bc);
  return 0;
}
Example #6
0
char *
findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep)
{
  char buf[4096], *bp, *ep;
  char **urls = 0;
  int nurls = 0;
  int i;

  if (chksumtypep)
    *chksumtypep = 0;
  while((bp = fgets(buf, sizeof(buf), fp)) != 0)
    {
      while (*bp == ' ' || *bp == '\t')
	bp++;
      if (chksumtypep && !*chksumtypep && !strncmp(bp, "<hash type=\"sha256\">", 20))
	{
	  bp += 20;
	  if (solv_hex2bin((const char **)&bp, chksump, 32) == 32)
	    *chksumtypep = REPOKEY_TYPE_SHA256;
	  continue;
	}
      if (strncmp(bp, "<url", 4))
	continue;
      bp = strchr(bp, '>');
      if (!bp)
	continue;
      bp++;
      ep = strstr(bp, "repodata/repomd.xml</url>");
      if (!ep)
	continue;
      *ep = 0;
      if (strncmp(bp, "http", 4))
	continue;
      urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15);
      urls[nurls++] = strdup(bp);
    }
  if (nurls)
    {
      if (nurls > 1)
        findfastest(urls, nurls > 5 ? 5 : nurls);
      bp = urls[0];
      urls[0] = 0;
      for (i = 0; i < nurls; i++)
        solv_free(urls[i]);
      solv_free(urls);
      ep = strchr(bp, '/');
      if ((ep = strchr(ep + 2, '/')) != 0)
	{
	  *ep = 0;
	  printf("[using mirror %s]\n", bp);
	  *ep = '/';
	}
      return bp;
    }
  return 0;
}
Example #7
0
void
hy_packagelist_free(HyPackageList plist)
{
    int i;

    for (i = 0; i < plist->count; ++i)
	hy_package_free(plist->elements[i]);
    solv_free(plist->elements);
    solv_free(plist);
}
Example #8
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;
}
Example #9
0
static void
free_dirs_names_array(struct addfileprovides_cbdata *cbd)
{
  int i;
  if (cbd->dirs)
    {
      for (i = 0; i < cbd->nfiles; i++)
	solv_free(cbd->dirs[i]);
      cbd->dirs = solv_free(cbd->dirs);
      cbd->names = solv_free(cbd->names);
    }
}
Example #10
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;
}
int
repo_add_releasefile_products(Repo *repo, const char *dirpath, int flags)
{
  DIR *dir;
  struct dirent *entry;
  FILE *fp;
  char *fullpath;
  struct parsedata pd;

  if (!dirpath)
    dirpath = "/etc";
  if (flags & REPO_USE_ROOTDIR)
    dirpath = pool_prepend_rootdir(repo->pool, dirpath);
  dir = opendir(dirpath);
  if (!dir)
    {
      if (flags & REPO_USE_ROOTDIR)
        solv_free((char *)dirpath);
      return 0;
    }

  memset(&pd, 0, sizeof(pd));
  pd.repo = repo;
  while ((entry = readdir(dir)))
    {
      int len = strlen(entry->d_name);
      if (len > 8 && !strcmp(entry->d_name + len - 8, "-release"))
        {
	  /* skip /etc/lsb-release, thats not a product per-se */
	  if (strcmp(entry->d_name, "lsb-release") == 0)
	    continue;
	  fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
	  if ((fp = fopen(fullpath, "r")) == 0)
	    {
	      pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
	      continue;
	    }
	  add_releasefile_product(&pd, fp);
	  fclose(fp);
	}
    }
  closedir(dir);
  join_freemem(&pd.jd);
  if (flags & REPO_USE_ROOTDIR)
    solv_free((char *)dirpath);

  if (!(flags & REPO_NO_INTERNALIZE) && (flags & REPO_REUSE_REPODATA) != 0)
    repodata_internalize(repo_last_repodata(repo));
  return 0;
}
Example #12
0
void
repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids)
{
  Solvable *s;
  Repodata *data;
  int i;
  if (start + count == repo->end)
    repo->end -= count;
  repo->nsolvables -= count;
  for (s = repo->pool->solvables + start, i = count; i--; s++)
    s->repo = 0;
  pool_free_solvable_block(repo->pool, start, count, reuseids);
  FOR_REPODATAS(repo, i, data)
    {
      int dstart, dend;
      if (data->end > repo->end)
        repodata_shrink(data, repo->end);
      dstart = data->start > start ? data->start : start;
      dend = data->end < start + count ? data->end : start + count;
      if (dstart < dend)
	{
	  if (data->attrs)
	    {
	      int j;
	      for (j = dstart; j < dend; j++)	
		data->attrs[j - data->start] = solv_free(data->attrs[j - data->start]);
	    }
	  if (data->incoreoffset)
	    memset(data->incoreoffset + (dstart - data->start), 0, (dend - dstart) * sizeof(Id));
	}
    }
Example #13
0
/* free all hash tables */
void
pool_freeidhashes(Pool *pool)
{
  stringpool_freehash(&pool->ss);
  pool->relhashtbl = solv_free(pool->relhashtbl);
  pool->relhashmask = 0;
}
Example #14
0
static int
reportsolutioncb(Solver *solv, void *cbdata)
{
  struct reportsolutiondata *sd = cbdata;
  char *res;

  sd->count++;
  res = testcase_solverresult(solv, TESTCASE_RESULT_TRANSACTION);
  if (*res)
    {
      char prefix[64];
      char *p2, *p = res;
      sprintf(prefix, "callback%d:", sd->count);
      while ((p2 = strchr(p, '\n')) != 0)
	{
	  char c = p2[1];
	  p2[1] = 0;
	  sd->result = solv_dupappend(sd->result, prefix, p);
	  p2[1] = c;
	  p = p2 + 1;
	}
    }
  solv_free(res);
  return 0;
}
Example #15
0
/**
 * Recursively create directory.
 *
 * If it is in the format accepted by mkdtemp() the function globs for a
 * matching name and if not found it uses mkdtemp() to create the path. 'path'
 * is modified in those two cases.
 */
int
mkcachedir(char *path)
{
    int ret = 1;

    if (!glob_for_cachedir(path))
	return 0;

    const int len = strlen(path);
    if (len < 1 || path[0] != '/')
	return 1; // only absolute pathnames are accepted

    char *p = solv_strdup(path);

    if (p[len-1] == '/')
	p[len-1] = '\0';

    if (access(p, X_OK)) {
	*(strrchr(p, '/')) = '\0';
	ret = mkcachedir(p);
	if (str_endswith(path, "XXXXXX")) {
	    char *retptr = mkdtemp(path);
	    if (retptr == NULL)
		ret |= 1;
	} else
	    ret |= mkdir(path, CACHEDIR_PERMISSIONS);
    } else {
	ret = 0;
    }

    solv_free(p);
    return ret;
}
Example #16
0
END_TEST

START_TEST(test_two_sacks)
{
    /* This clumsily mimics create_ut_sack() and setup_with() to
     * create a second HySack. */
    char *tmpdir = solv_dupjoin(test_globals.tmpdir, "/tmp", NULL);
    HySack sack1 = hy_sack_create(tmpdir, TEST_FIXED_ARCH, NULL, NULL,
                                  HY_MAKE_CACHE_DIR);
    Pool *pool1 = sack_pool(sack1);
    const char *path = pool_tmpjoin(pool1, test_globals.repo_dir,
                                    "change.repo", NULL);
    fail_if(load_repo(pool1, "change", path, 0));
    HyPackage pkg1 = by_name(sack1, "penny-lib");
    fail_if(pkg1 == NULL);

    HySack sack2 = test_globals.sack;
    Pool *pool2 = sack_pool(sack2);
    HyPackage pkg2 = by_name(sack2, "penny-lib");
    fail_if(pkg2 == NULL);

    /* "penny-lib" is in both pools but at different offsets */
    Solvable *s1 = pool_id2solvable(pool1, pkg1->id);
    Solvable *s2 = pool_id2solvable(pool2, pkg2->id);
    fail_if(s1->name == s2->name);

    fail_if(hy_package_cmp(pkg1, pkg2) != 0);

    hy_package_free(pkg1);
    hy_package_free(pkg2);

    hy_sack_free(sack1);
    solv_free(tmpdir);
}
Example #17
0
FILE *
solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode)
{
  struct bufcookie *bc;
  FILE *fp;
  if (*mode != 'r' && *mode != 'w')
    return 0;
  bc = solv_calloc(1, sizeof(*bc));
  bc->freemem = 0;
  bc->bufp = bufp;
  if (!buflp)
    {
      bc->bufl_int = *mode == 'w' ? 0 : strlen(*bufp);
      buflp = &bc->bufl_int;
    }
  bc->buflp = buflp;
  if (*mode == 'w')
    {
      *bc->bufp = solv_extend(0, 0, 1, 1, 4095);	/* always zero-terminate */
      (*bc->bufp)[0] = 0;
      *bc->buflp = 0;
    }
  fp = cookieopen(bc, mode, cookie_bufread, cookie_bufwrite, cookie_bufclose);
  if (!strcmp(mode, "rf"))	/* auto-free */
    bc->freemem = *bufp;
  if (!fp)
    {
      if (*mode == 'w')
	*bc->bufp = solv_free(*bc->bufp);
      cookie_bufclose(bc);
    }
  return fp;
}
Example #18
0
int
solv_zchunk_close(struct solv_zchunk *zck)
{
  if (zck->data_chk)
    solv_chksum_free(zck->data_chk, 0);
  if (zck->ddict)
    ZSTD_freeDDict(zck->ddict);
  if (zck->dctx)
    ZSTD_freeDCtx(zck->dctx);
  solv_free(zck->hdr);
  solv_free(zck->buf);
  if (zck->fp)
    fclose(zck->fp);
  solv_free(zck);
  return 0;
}
Example #19
0
static int
parse_cpu_flags(int *flags, const char *section)
{
    char *cpuinfo = read_whole_file("/proc/cpuinfo");
    if (cpuinfo == NULL)
	return hy_get_errno();

    char *features = strstr(cpuinfo, section);
    if (features != NULL) {
	char *saveptr;
	features = strtok_r(features, "\n", &saveptr);
	char *tok = strtok_r(features, " ", &saveptr);
	while (tok) {
	    if (!strcmp(tok, "neon"))
		*flags |= ARM_NEON;
	    else if (!strcmp(tok, "vfpv3"))
		*flags |= ARM_VFP3;
	    else if (!strcmp(tok, "vfp"))
		*flags |= ARM_VFP;
	    tok = strtok_r(NULL, " ", &saveptr);
	}
    }

    solv_free(cpuinfo);
    return 0;
}
Example #20
0
static Hashtable
growhash(Hashtable map, Hashval *mapnp)
{
  Hashval mapn = *mapnp;
  Hashval newn = (mapn + 1) * 2 - 1;
  Hashval i, h, hh;
  Hashtable m;
  Id hx, qx;

  m = solv_calloc(newn + 1, 2 * sizeof(Id));
  for (i = 0; i <= mapn; i++)
    {
      hx = map[2 * i];
      if (!hx)
	continue;
      h = hx & newn;
      hh = HASHCHAIN_START;
      for (;;)
	{
	  qx = m[2 * h];
	  if (!qx)
	    break;
	  h = HASHCHAIN_NEXT(h, hh, newn);
	}
      m[2 * h] = hx;
      m[2 * h + 1] = map[2 * i + 1];
    }
  solv_free(map);
  *mapnp = newn;
  return m;
}
static PyObject *
package_str(_PackageObject *self)
{
    char *cstr = hy_package_get_nevra(self->package);
    PyObject *ret = PyString_FromString(cstr);
    solv_free(cstr);
    return ret;
}
Example #22
0
void
queue_free(Queue *q)
{
  if (q->alloc)
    solv_free(q->alloc);
  q->alloc = q->elements = 0;
  q->count = q->left = 0;
}
Example #23
0
static void XMLCALL
endElement(void *userData, const char *name)
{
  struct parsedata *pd = userData;
  Solvable *s = pd->solvable;

#if 0
  fprintf(stderr, "end: [%d]%s\n", pd->state, name);
#endif
  if (pd->depth != pd->statedepth)
    {
      pd->depth--;
#if 0
      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
#endif
      return;
    }

  pd->depth--;
  pd->statedepth--;

  switch (pd->state)
    {
    case STATE_PRODUCT:
      if (!s->arch)
	s->arch = ARCH_NOARCH;
      if (!s->evr)
	s->evr = ID_EMPTY;
      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
	s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
      pd->solvable = 0;
      break;
    case STATE_NAME:
      s->name = pool_str2id(pd->pool, join2("product", ":", pd->content), 1);
      break;
    case STATE_ARCH:
      s->arch = pool_str2id(pd->pool, pd->content, 1);
      break;
    case STATE_SUMMARY:
      repodata_set_str(pd->data, pd->handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), pd->content);
      pd->tmplang = solv_free((void *)pd->tmplang);
      break;
    case STATE_VENDOR:
      s->vendor = pool_str2id(pd->pool, pd->content, 1);
      break;
    case STATE_INSTALLTIME:
      repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(pd->content));
    default:
      break;
    }

  pd->state = pd->sbtab[pd->state];
  pd->docontent = 0;

#if 0
  fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
#endif
}
Example #24
0
static void XMLCALL
startElement(void *userData, const char *name, const char **atts)
{
  struct parsedata *pd = userData;
  Pool *pool = pd->pool;
  Solvable *s = pd->solvable;
  struct stateswitch *sw;

#if 0
  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
#endif
  if (pd->depth != pd->statedepth)
    {
      pd->depth++;
      return;
    }

  pd->depth++;
  if (!pd->swtab[pd->state])	/* no statetable -> no substates */
    {
#if 0
      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
#endif
      return;
    }
  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
    if (!strcmp(sw->ename, name))
      break;

  if (sw->from != pd->state)
    {
#if 0
      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
#endif
      return;
    }
  pd->state = sw->to;
  pd->docontent = sw->docontent;
  pd->statedepth = pd->depth;
  pd->lcontent = 0;
  *pd->content = 0;

  switch(pd->state)
    {
    case STATE_APPLICATION:
      s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
      pd->handle = s - pool->solvables;
      break;
    case STATE_DESCRIPTION:
      pd->description = solv_free(pd->description);
      break;
    case STATE_OL:
      pd->licnt = 0;
      break;
    default:
      break;
    }
}
Example #25
0
File: sack.c Project: Tojaj/hawkey
static Map *
free_map_fully(Map *m)
{
    if (m) {
	map_free(m);
	solv_free(m);
    }
    return NULL;
}
Example #26
0
static PyObject *
reldep_str(_ReldepObject *self)
{
    HyReldep reldep = self->reldep;
    char *cstr = hy_reldep_str(reldep);
    PyObject *retval = PyString_FromString(cstr);
    solv_free(cstr);
    return retval;
}
Example #27
0
/* public */
void
hy_package_free(HyPackage pkg)
{
    if (--pkg->nrefs > 0)
	return;
    if (pkg->destroy_func)
	pkg->destroy_func(pkg->userdata);
    solv_free(pkg);
}
Example #28
0
static PyObject *
evr(_NevraObject *self, PyObject *unused)
{
    char *str;
    PyObject *o;
    str = hy_nevra_get_evr(self->nevra);
    o = PyString_FromString(str);
    solv_free(str);
    return o;
}
Example #29
0
char *
findmirrorlisturl(FILE *fp)
{
  char buf[4096], *bp, *ep;
  int i, l;
  char **urls = 0;
  int nurls = 0;

  while((bp = fgets(buf, sizeof(buf), fp)) != 0)
    {
      while (*bp == ' ' || *bp == '\t')
	bp++;
      if (!*bp || *bp == '#')
	continue;
      l = strlen(bp);
      while (l > 0 && (bp[l - 1] == ' ' || bp[l - 1] == '\t' || bp[l - 1] == '\n'))
	bp[--l] = 0;
      if ((ep = strstr(bp, "url=")) != 0)
	bp = ep + 4;
      urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15);
      urls[nurls++] = strdup(bp);
    }
  if (nurls)
    {
      if (nurls > 1)
        findfastest(urls, nurls > 5 ? 5 : nurls);
      bp = urls[0];
      urls[0] = 0;
      for (i = 0; i < nurls; i++)
        solv_free(urls[i]);
      solv_free(urls);
      ep = strchr(bp, '/');
      if ((ep = strchr(ep + 2, '/')) != 0)
	{
	  *ep = 0;
	  printf("[using mirror %s]\n", bp);
	  *ep = '/';
	}
      return bp;
    }
  return 0;
}
Example #30
0
static void 
setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
{
  if (str[solv_validutf8(str)])
    {    
      char *ustr = solv_latin1toutf8(str);	/* not utf8, assume latin1 */
      repodata_set_str(repodata, handle, tag, ustr);
      solv_free(ustr);
    }    
  else 
    repodata_set_str(repodata, handle, tag, str);
}