RPM Community Forums

Mailing List Message of <rpm-cvs>

[CVS] RPM: rpm/rpmdb/ rpmrepo.c rpmrepo.h rpm/rpmio/ rpmrepo.c rpmrepo...

From: Jeff Johnson <jbj@rpm5.org>
Date: Mon 27 Sep 2010 - 21:41:46 CEST
Message-Id: <20100927194146.79385DC9DE@rpm5.org>
  RPM Package Manager, CVS Repository
  /cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  jbj@rpm5.org
  Module: rpm                              Date:   27-Sep-2010 21:41:46
  Branch: HEAD                             Handle: 2010092719414501

  Added files:
    rpm/rpmdb               rpmrepo.c rpmrepo.h
  Removed files:
    rpm/rpmio               rpmrepo.c rpmrepo.h

  Log:
    - orphans

  Summary:
    Revision    Changes     Path
    1.2         +1501 -0    rpm/rpmdb/rpmrepo.c
    1.2         +438 -0     rpm/rpmdb/rpmrepo.h
    2.6         +0  -1501   rpm/rpmio/rpmrepo.c
    2.6         +0  -438    rpm/rpmio/rpmrepo.h
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: rpm/rpmdb/rpmrepo.c
  ============================================================================
  $ cvs diff -u -r0 -r1.2 rpmrepo.c
  --- /dev/null	2010-09-27 21:38:30.000000000 +0200
  +++ rpmrepo.c	2010-09-27 21:41:45.848167425 +0200
  @@ -0,0 +1,1501 @@
  +/** \ingroup rpmio
  + * \file rpmio/rpmrepo.c
  + */
  +
  +#include "system.h"
  +
  +#if defined(WITH_SQLITE)
  +#include <sqlite3.h>
  +#ifdef	__LCLINT__
  +/*@-incondefs -redecl @*/
  +extern const char *sqlite3_errmsg(sqlite3 *db)
  +	/*@*/;
  +extern int sqlite3_open(
  +  const char *filename,		   /* Database filename (UTF-8) */
  +  /*@out@*/ sqlite3 **ppDb	   /* OUT: SQLite db handle */
  +)
  +	/*@modifies *ppDb @*/;
  +extern int sqlite3_exec(
  +  sqlite3 *db,			   /* An open database */
  +  const char *sql,		   /* SQL to be evaluted */
  +  int (*callback)(void*,int,char**,char**),  /* Callback function */
  +  void *,			   /* 1st argument to callback */
  +  /*@out@*/ char **errmsg	   /* Error msg written here */
  +)
  +	/*@modifies db, *errmsg @*/;
  +extern int sqlite3_prepare(
  +  sqlite3 *db,			   /* Database handle */
  +  const char *zSql,		   /* SQL statement, UTF-8 encoded */
  +  int nByte,			   /* Maximum length of zSql in bytes. */
  +  /*@out@*/ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
  +  /*@out@*/ const char **pzTail	   /* OUT: Pointer to unused portion of zSql */
  +)
  +	/*@modifies *ppStmt, *pzTail @*/;
  +extern int sqlite3_reset(sqlite3_stmt *pStmt)
  +	/*@modifies pStmt @*/;
  +extern int sqlite3_step(sqlite3_stmt *pStmt)
  +	/*@modifies pStmt @*/;
  +extern int sqlite3_finalize(/*@only@*/ sqlite3_stmt *pStmt)
  +	/*@modifies pStmt @*/;
  +extern int sqlite3_close(sqlite3 * db)
  +	/*@modifies db @*/;
  +/*@=incondefs =redecl @*/
  +#endif	/* __LCLINT__ */
  +#endif	/* WITH_SQLITE */
  +
  +#include <rpmio_internal.h>	/* XXX fdInitDigest() et al */
  +#include <rpmiotypes.h>
  +#include <rpmio.h>	/* for *Pool methods */
  +#include <rpmlog.h>
  +#include <rpmurl.h>
  +#include <poptIO.h>
  +
  +#define	_RPMREPO_INTERNAL
  +#include <rpmrepo.h>
  +
  +#include "debug.h"
  +
  +/*@unchecked@*/
  +int _rpmrepo_debug = 0;
  +
  +#define REPODBG(_l) if (_rpmrepo_debug) fprintf _l
  +
  +/*==============================================================*/
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char primary_xml_init[] =
  +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  +"<metadata xmlns=\"http://linux.duke.edu/metadata/common\" xmlns:rpm=\"http://linux.duke.edu/metadata/rpm\" packages=\"0\">\n";
  +/*@unchecked@*/ /*@observer@*/
  +static const char primary_xml_fini[] = "</metadata>\n";
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char filelists_xml_init[] =
  +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  +"<filelists xmlns=\"http://linux.duke.edu/metadata/filelists\" packages=\"0\">\n";
  +/*@unchecked@*/ /*@observer@*/
  +static const char filelists_xml_fini[] = "</filelists>\n";
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char other_xml_init[] =
  +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  +"<otherdata xmlns=\"http://linux.duke.edu/metadata/other\" packages=\"0\">\n";
  +/*@unchecked@*/ /*@observer@*/
  +static const char other_xml_fini[] = "</otherdata>\n";
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char repomd_xml_init[] = "\
  +<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
  +<repomd xmlns=\"http://linux.duke.edu/metadata/repo\">\n";
  +/*@unchecked@*/ /*@observer@*/
  +static const char repomd_xml_fini[] = "</repomd>\n";
  +
  +/* XXX todo: wire up popt aliases and bury the --queryformat glop externally. */
  +/*@unchecked@*/ /*@observer@*/
  +static const char primary_xml_qfmt[] =
  +#include "yum_primary_xml"
  +;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char filelists_xml_qfmt[] =
  +#include "yum_filelists_xml"
  +;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char other_xml_qfmt[] =
  +#include "yum_other_xml"
  +;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char primary_yaml_qfmt[] =
  +#include "wnh_primary_yaml"
  +;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char filelists_yaml_qfmt[] =
  +#include "wnh_filelists_yaml"
  +;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char other_yaml_qfmt[] =
  +#include "wnh_other_yaml"
  +;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char Packages_qfmt[] =
  +#include "deb_Packages"
  +;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char Sources_qfmt[] =
  +#include "deb_Sources"
  +;
  +
  +/*@-nullassign@*/
  +/*@unchecked@*/ /*@observer@*/
  +static const char *primary_sql_init[] = {
  +"PRAGMA synchronous = \"OFF\";",
  +"pragma locking_mode = \"EXCLUSIVE\";",
  +"CREATE TABLE conflicts (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT );",
  +"CREATE TABLE db_info (dbversion INTEGER,  checksum TEXT);",
  +"CREATE TABLE files (  pkgKey INTEGER,  name TEXT,  type TEXT );",
  +"CREATE TABLE obsoletes (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT );",
  +"CREATE TABLE packages (  pkgKey INTEGER PRIMARY KEY,  pkgId TEXT,  name TEXT,  arch TEXT,  version TEXT,  epoch TEXT,  release TEXT,  summary TEXT,  description TEXT,  url TEXT,  time_file INTEGER,  time_build INTEGER,  rpm_license TEXT,  rpm_vendor TEXT,  rpm_group TEXT,  rpm_buildhost TEXT,  rpm_sourcerpm TEXT,  rpm_header_start INTEGER,  rpm_header_end INTEGER,  rpm_packager TEXT,  size_package INTEGER,  size_installed INTEGER,  size_archive INTEGER,  location_href TEXT,  location_base TEXT,  checksum_type TEXT);",
  +"CREATE TABLE provides (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT );",
  +"CREATE TABLE requires (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT  );",
  +"CREATE INDEX filenames ON files (name);",
  +"CREATE INDEX packageId ON packages (pkgId);",
  +"CREATE INDEX packagename ON packages (name);",
  +"CREATE INDEX pkgconflicts on conflicts (pkgKey);",
  +"CREATE INDEX pkgobsoletes on obsoletes (pkgKey);",
  +"CREATE INDEX pkgprovides on provides (pkgKey);",
  +"CREATE INDEX pkgrequires on requires (pkgKey);",
  +"CREATE INDEX providesname ON provides (name);",
  +"CREATE INDEX requiresname ON requires (name);",
  +"CREATE TRIGGER removals AFTER DELETE ON packages\
  +\n    BEGIN\n\
  +\n    DELETE FROM files WHERE pkgKey = old.pkgKey;\
  +\n    DELETE FROM requires WHERE pkgKey = old.pkgKey;\
  +\n    DELETE FROM provides WHERE pkgKey = old.pkgKey;\
  +\n    DELETE FROM conflicts WHERE pkgKey = old.pkgKey;\
  +\n    DELETE FROM obsoletes WHERE pkgKey = old.pkgKey;\
  +\n    END;",
  +"INSERT into db_info values (9, 'direct_create');",
  +    NULL
  +};
  +/*XXX todo: DBVERSION needs to be set */
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char *filelists_sql_init[] = {
  +"PRAGMA synchronous = \"OFF\";",
  +"pragma locking_mode = \"EXCLUSIVE\";",
  +"CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);",
  +"CREATE TABLE filelist (  pkgKey INTEGER,  name TEXT,  type TEXT );",
  +"CREATE TABLE packages (  pkgKey INTEGER PRIMARY KEY,  pkgId TEXT);",
  +"CREATE INDEX filelistnames ON filelist (name);",
  +"CREATE INDEX keyfile ON filelist (pkgKey);",
  +"CREATE INDEX pkgId ON packages (pkgId);",
  +"CREATE TRIGGER remove_filelist AFTER DELETE ON packages\
  +\n    BEGIN\
  +\n    DELETE FROM filelist WHERE pkgKey = old.pkgKey;\
  +\n    END;",
  +"INSERT into db_info values (9, 'direct_create');",
  +    NULL
  +};
  +/*XXX todo: DBVERSION needs to be set */
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char *other_sql_init[] = {
  +"PRAGMA synchronous = \"OFF\";",
  +"pragma locking_mode = \"EXCLUSIVE\";",
  +"CREATE TABLE changelog (  pkgKey INTEGER,  author TEXT,  date INTEGER,  changelog TEXT);",
  +"CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);",
  +"CREATE TABLE packages (  pkgKey INTEGER PRIMARY KEY,  pkgId TEXT);",
  +"CREATE INDEX keychange ON changelog (pkgKey);",
  +"CREATE INDEX pkgId ON packages (pkgId);",
  +"CREATE TRIGGER remove_changelogs AFTER DELETE ON packages\
  +\n    BEGIN\
  +\n    DELETE FROM changelog WHERE pkgKey = old.pkgKey;\
  +\n    END;",
  +"INSERT into db_info values (9, 'direct_create');",
  +    NULL
  +};
  +/*XXX todo: DBVERSION needs to be set */
  +/*@=nullassign@*/
  +
  +/* packages   1 pkgKey INTEGER PRIMARY KEY */
  +/* packages   2 pkgId TEXT */
  +/* packages   3 name TEXT */
  +/* packages   4 arch TEXT */
  +/* packages   5 version TEXT */
  +/* packages   6 epoch TEXT */
  +/* packages   7 release TEXT */
  +/* packages   8 summary TEXT */
  +/* packages   9 description TEXT */
  +/* packages  10 url TEXT */
  +/* packages  11 time_file INTEGER */
  +/* packages  12 time_build INTEGER */
  +/* packages  13 rpm_license TEXT */
  +/* packages  14 rpm_vendor TEXT */
  +/* packages  15 rpm_group TEXT */
  +/* packages  16 rpm_buildhost TEXT */
  +/* packages  17 rpm_sourcerpm TEXT */
  +/* packages  18 rpm_header_start INTEGER */
  +/* packages  19 rpm_header_end INTEGER */
  +/* packages  20 rpm_packager TEXT */
  +/* packages  21 size_package INTEGER */
  +/* packages  22 size_installed INTEGER */
  +/* packages  23 size_archive INTEGER */
  +/* packages  24 location_href TEXT */
  +/* packages  25 location_base TEXT */
  +/* packages  26 checksum_type TEXT */
  +/* obsoletes  1 pkgKey INTEGER */
  +/* obsoletes  2 name TEXT */
  +/* obsoletes  3 flags TEXT */
  +/* obsoletes  4 epoch TEXT */
  +/* obsoletes  5 version TEXT */
  +/* obsoletes  6 release TEXT */
  +/* provides   1 pkgKey INTEGER */
  +/* provides   2 name TEXT */
  +/* provides   3 flags TEXT */
  +/* provides   4 epoch TEXT */
  +/* provides   5 version TEXT */
  +/* provides   6 release TEXT */
  +/* conflicts  1 pkgKey INTEGER */
  +/* conflicts  2 name TEXT */
  +/* conflicts  3 flags TEXT */
  +/* conflicts  4 epoch TEXT */
  +/* conflicts  5 version TEXT */
  +/* conflicts  6 release TEXT */
  +/* requires   1 pkgKey INTEGER */
  +/* requires   2 name TEXT */
  +/* requires   3 flags TEXT */
  +/* requires   4 epoch TEXT */
  +/* requires   5 version TEXT */
  +/* requires   6 release TEXT */
  +/* files      1 pkgKey INTEGER */
  +/* files      2 name TEXT */
  +/* files      3 type TEXT */
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char primary_sql_qfmt[] =
  +#include "yum_primary_sqlite"
  +;
  +
  +/* packages  1 pkgKey INTEGER PRIMARY KEY */
  +/* packages  2 pkgId TEXT */
  +/* filelist  1 pkgKey INTEGER */
  +/* filelist  2 name TEXT */
  +/* filelist  3 type TEXT */
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char filelists_sql_qfmt[] =
  +#include "yum_filelists_sqlite"
  +;
  +
  +/* packages  1 pkgKey INTEGER PRIMARY KEY */
  +/* packages  2 pkgId TEXT */
  +/* changelog 1 pkgKey INTEGER */
  +/* changelog 2 author TEXT */
  +/* changelog 3 date INTEGER */
  +/* changelog 4 changelog TEXT */
  +
  +/*@unchecked@*/ /*@observer@*/
  +static const char other_sql_qfmt[] =
  +#include "yum_other_sqlite"
  +;
  +
  +/* XXX static when ready. */
  +/*@-fullinitblock@*/
  +/*@unchecked@*/
  +static struct rpmrepo_s __repo = {
  +    .flags	= REPO_FLAGS_PRETTY,
  +
  +    .tempdir	= ".repodata",
  +    .finaldir	= "repodata",
  +    .olddir	= ".olddata",
  +    .markup	= ".xml",
  +    .pkgalgo	= PGPHASHALGO_SHA1,
  +    .algo	= PGPHASHALGO_SHA1,
  +    .primary	= {
  +	.type	= "primary",
  +	.xml_init= primary_xml_init,
  +	.xml_qfmt= primary_xml_qfmt,
  +	.xml_fini= primary_xml_fini,
  +	.sql_init= primary_sql_init,
  +	.sql_qfmt= primary_sql_qfmt,
  +#ifdef	NOTYET	/* XXX char **?!? */
  +	.sql_fini= NULL,
  +#endif
  +	.yaml_init= NULL,
  +	.yaml_qfmt= primary_yaml_qfmt,
  +	.yaml_fini= NULL,
  +	.Packages_init= NULL,
  +	.Packages_qfmt= NULL,
  +	.Packages_fini= NULL,
  +	.Sources_init= NULL,
  +	.Sources_qfmt= NULL,
  +	.Sources_fini= NULL
  +    },
  +    .filelists	= {
  +	.type	= "filelists",
  +	.xml_init= filelists_xml_init,
  +	.xml_qfmt= filelists_xml_qfmt,
  +	.xml_fini= filelists_xml_fini,
  +	.sql_init= filelists_sql_init,
  +	.sql_qfmt= filelists_sql_qfmt,
  +#ifdef	NOTYET	/* XXX char **?!? */
  +	.sql_fini= NULL,
  +#endif
  +	.yaml_init= NULL,
  +	.yaml_qfmt= filelists_yaml_qfmt,
  +	.yaml_fini= NULL,
  +	.Packages_init= NULL,
  +	.Packages_qfmt= NULL,
  +	.Packages_fini= NULL,
  +	.Sources_init= NULL,
  +	.Sources_qfmt= NULL,
  +	.Sources_fini= NULL
  +    },
  +    .other	= {
  +	.type	= "other",
  +	.xml_init= other_xml_init,
  +	.xml_qfmt= other_xml_qfmt,
  +	.xml_fini= other_xml_fini,
  +	.sql_init= other_sql_init,
  +	.sql_qfmt= other_sql_qfmt,
  +#ifdef	NOTYET	/* XXX char **?!? */
  +	.sql_fini= NULL,
  +#endif
  +	.yaml_init= NULL,
  +	.yaml_qfmt= other_yaml_qfmt,
  +	.yaml_fini= NULL,
  +	.Packages_init= NULL,
  +	.Packages_qfmt= NULL,
  +	.Packages_fini= NULL,
  +	.Sources_init= NULL,
  +	.Sources_qfmt= NULL,
  +	.Sources_fini= NULL
  +    },
  +    .repomd	= {
  +	.type	= "repomd",
  +	.xml_init= repomd_xml_init,
  +	.xml_qfmt= NULL,
  +	.xml_fini= repomd_xml_fini,
  +	.sql_init= NULL,
  +	.sql_qfmt= NULL,
  +#ifdef	NOTYET	/* XXX char **?!? */
  +	.sql_fini= NULL,
  +#endif
  +	.yaml_init= NULL,
  +	.yaml_qfmt= NULL,
  +	.yaml_fini= NULL,
  +	.Packages_init= NULL,
  +	.Packages_qfmt= Packages_qfmt,
  +	.Packages_fini= NULL,
  +	.Sources_init= NULL,
  +	.Sources_qfmt= Sources_qfmt,
  +	.Sources_fini= NULL
  +    }
  +};
  +/*@=fullinitblock@*/
  +
  +/*@unchecked@*/
  +static rpmrepo _repo = &__repo;
  +
  +/*==============================================================*/
  +
  +int rpmioExists(const char * fn, /*@out@*/ struct stat * st)
  +{
  +    return (Stat(fn, st) == 0);
  +}
  +
  +time_t rpmioCtime(const char * fn)
  +{
  +    struct stat sb;
  +    time_t stctime = 0;
  +
  +    if (rpmioExists(fn, &sb))
  +	stctime = sb.st_ctime;
  +    return stctime;
  +}
  +
  +/*==============================================================*/
  +
  +void
  +rpmrepoError(int lvl, const char *fmt, ...)
  +{
  +    va_list ap;
  +
  +    va_start(ap, fmt);
  +    (void) fflush(NULL);
  +    (void) fprintf(stderr, "%s: ", __progname);
  +    (void) vfprintf(stderr, fmt, ap);
  +    va_end (ap);
  +    (void) fprintf(stderr, "\n");
  +    if (lvl)
  +	exit(EXIT_FAILURE);
  +}
  +
  +const char * rpmrepoGetPath(rpmrepo repo, const char * dir,
  +		const char * type, int compress)
  +{
  +    return rpmGetPath(repo->outputdir, "/", dir, "/", type,
  +		(repo->markup != NULL ? repo->markup : ""),
  +		(repo->suffix != NULL && compress ? repo->suffix : ""), NULL);
  +}
  +
  +void rpmrepoProgress(/*@unused@*/ rpmrepo repo,
  +		/*@null@*/ const char * item, int current, int total)
  +{
  +    static size_t ncols = 80 - 1;	/* XXX TIOCGWINSIZ */
  +    const char * bn = (item != NULL ? strrchr(item, '/') : NULL);
  +    size_t nb;
  +
  +    if (bn != NULL)
  +	bn++;
  +    else
  +	bn = item;
  +    nb = fprintf(stdout, "\r%s: %d/%d", __progname, current, total);
  +    if (bn != NULL)
  +	nb += fprintf(stdout, " - %s", bn);
  +    nb--;
  +    if (nb < ncols)
  +	fprintf(stdout, "%*s", (int)(ncols - nb), "");
  +    ncols = nb;
  +    (void) fflush(stdout);
  +}
  +
  +int rpmrepoMkdir(rpmrepo repo, const char * dn)
  +{
  +    const char * dnurl = rpmGetPath(repo->outputdir, "/", dn, NULL);
  +/*@-mods@*/
  +    int ut = urlPath(dnurl, &dn);
  +/*@=mods@*/
  +    int rc = 0;;
  +
  +    /* XXX todo: rpmioMkpath doesn't grok URI's */
  +    if (ut == URL_IS_UNKNOWN)
  +	rc = rpmioMkpath(dn, 0755, (uid_t)-1, (gid_t)-1);
  +    else
  +	rc = (Mkdir(dnurl, 0755) == 0 || errno == EEXIST ? 0 : -1);
  +    if (rc)
  +	rpmrepoError(0, _("Cannot create/verify %s: %s"), dnurl, strerror(errno));
  +    dnurl = _free(dnurl);
  +    return rc;
  +}
  +
  +const char * rpmrepoRealpath(const char * lpath)
  +{
  +    /* XXX GLIBC: realpath(path, NULL) return malloc'd */
  +    const char *rpath = Realpath(lpath, NULL);
  +    if (rpath == NULL) {
  +	char fullpath[MAXPATHLEN];
  +	rpath = Realpath(lpath, fullpath);
  +	if (rpath != NULL)
  +	    rpath = xstrdup(rpath);
  +    }
  +    return rpath;
  +}
  +
  +/*==============================================================*/
  +
  +int rpmrepoTestSetupDirs(rpmrepo repo)
  +{
  +    const char ** directories = repo->directories;
  +    struct stat sb, *st = &sb;
  +    const char * dn;
  +    const char * fn;
  +    int rc = 0;
  +
  +    /* XXX todo: check repo->pkglist existence? */
  +
  +    if (directories != NULL)
  +    while ((dn = *directories++) != NULL) {
  +	if (!rpmioExists(dn, st) || !S_ISDIR(st->st_mode)) {
  +	    rpmrepoError(0, _("Directory %s must exist"), dn);
  +	    rc = 1;
  +	}
  +    }
  +
  +    /* XXX todo create outputdir if it doesn't exist? */
  +    if (!rpmioExists(repo->outputdir, st)) {
  +	rpmrepoError(0, _("Directory %s does not exist."), repo->outputdir);
  +	rc = 1;
  +    }
  +    if (Access(repo->outputdir, W_OK)) {
  +	rpmrepoError(0, _("Directory %s must be writable."), repo->outputdir);
  +	rc = 1;
  +    }
  +
  +    if (rpmrepoMkdir(repo, repo->tempdir)
  +     || rpmrepoMkdir(repo, repo->finaldir))
  +	rc = 1;
  +
  +    dn = rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
  +    if (rpmioExists(dn, st)) {
  +	rpmrepoError(0, _("Old data directory exists, please remove: %s"), dn);
  +	rc = 1;
  +    }
  +    dn = _free(dn);
  +
  +  { /*@observer@*/
  +    static const char * dirs[] = { ".repodata", "repodata", NULL };
  +    /*@observer@*/
  +    static const char * types[] =
  +	{ "primary", "filelists", "other", "repomd", NULL };
  +    const char ** dirp, ** typep;
  +    for (dirp = dirs; *dirp != NULL; dirp++) {
  +	for (typep = types; *typep != NULL; typep++) {
  +	    fn = rpmrepoGetPath(repo, *dirp, *typep, strcmp(*typep, "repomd"));
  +	    if (rpmioExists(fn, st)) {
  +		if (Access(fn, W_OK)) {
  +		    rpmrepoError(0, _("Path must be writable: %s"), fn);
  +		    rc = 1;
  +		} else
  +		if (REPO_ISSET(CHECKTS) && st->st_ctime > repo->mdtimestamp)
  +		    repo->mdtimestamp = st->st_ctime;
  +	    }
  +	    fn = _free(fn);
  +	}
  +    }
  +  }
  +
  +#ifdef	NOTYET		/* XXX repo->package_dir needs to go away. */
  +    if (repo->groupfile != NULL) {
  +	if (REPO_ISSET(SPLIT) || repo->groupfile[0] != '/') {
  +	    fn = rpmGetPath(repo->package_dir, "/", repo->groupfile, NULL);
  +	    repo->groupfile = _free(repo->groupfile);
  +	    repo->groupfile = fn;
  +	    fn = NULL;
  +	}
  +	if (!rpmioExists(repo->groupfile, st)) {
  +	    rpmrepoError(0, _("groupfile %s cannot be found."), repo->groupfile);
  +	    rc = 1;
  +	}
  +    }
  +#endif
  +    return rc;
  +}
  +
  +/**
  + * Check file name for a suffix.
  + * @param fn            file name
  + * @param suffix        suffix
  + * @return              1 if file name ends with suffix
  + */
  +static int chkSuffix(const char * fn, const char * suffix)
  +        /*@*/
  +{
  +    size_t flen = strlen(fn);
  +    size_t slen = strlen(suffix);
  +    return (flen > slen && !strcmp(fn + flen - slen, suffix));
  +}
  +
  +const char ** rpmrepoGetFileList(rpmrepo repo, const char *roots[],
  +		const char * ext)
  +{
  +    const char ** pkglist = NULL;
  +    FTS * t;
  +    FTSENT * p;
  +    int xx;
  +
  +    if ((t = Fts_open((char *const *)roots, repo->ftsoptions, NULL)) == NULL)
  +	rpmrepoError(1, _("Fts_open: %s"), strerror(errno));
  +
  +    while ((p = Fts_read(t)) != NULL) {
  +#ifdef	NOTYET
  +	const char * fts_name = p->fts_name;
  +	size_t fts_namelen = p->fts_namelen;
  +
  +	/* XXX fts(3) (and Fts(3)) have fts_name = "" with pesky trailing '/' */
  +	if (p->fts_level == 0 && fts_namelen == 0) {
  +            fts_name = ".";
  +            fts_namelen = sizeof(".") - 1;
  +	}
  +#endif
  +
  +	/* Should this element be excluded/included? */
  +	/* XXX todo: apply globs to fts_path rather than fts_name? */
  +/*@-onlytrans@*/
  +	if (mireApply(repo->excludeMire, repo->nexcludes, p->fts_name, 0, -1) >= 0)
  +	    continue;
  +	if (mireApply(repo->includeMire, repo->nincludes, p->fts_name, 0, +1) < 0)
  +	    continue;
  +/*@=onlytrans@*/
  +
  +	switch (p->fts_info) {
  +	case FTS_D:
  +	case FTS_DP:
  +	default:
  +	    continue;
  +	    /*@notreached@*/ /*@switchbreak@*/ break;
  +	case FTS_SL:
  +	    if (REPO_ISSET(NOFOLLOW))
  +		continue;
  +	    /* XXX todo: fuss with symlinks */
  +	    /*@notreached@*/ /*@switchbreak@*/ break;
  +	case FTS_F:
  +	    /* Is this a *.rpm file? */
  +	    if (chkSuffix(p->fts_name, ext))
  +		xx = argvAdd(&pkglist, p->fts_path);
  +	    /*@switchbreak@*/ break;
  +	}
  +    }
  +
  +    (void) Fts_close(t);
  +
  +if (_rpmrepo_debug)
  +argvPrint("pkglist", pkglist, NULL);
  +
  +    return pkglist;
  +}
  +
  +int rpmrepoCheckTimeStamps(rpmrepo repo)
  +{
  +    int rc = 0;
  +
  +    if (REPO_ISSET(CHECKTS)) {
  +	const char ** pkg;
  +
  +	if (repo->pkglist != NULL)
  +	for (pkg = repo->pkglist; *pkg != NULL ; pkg++) {
  +	    struct stat sb, *st = &sb;
  +	    if (!rpmioExists(*pkg, st)) {
  +		rpmrepoError(0, _("cannot get to file: %s"), *pkg);
  +		rc = 1;
  +	    } else if (st->st_ctime > repo->mdtimestamp)
  +		rc = 1;
  +	}
  +    } else
  +	rc = 1;
  +
  +    return rc;
  +}
  +
  +int rpmrfileXMLWrite(rpmrfile rfile, const char * spew)
  +{
  +    size_t nspew = (spew != NULL ? strlen(spew) : 0);
  +/*@-nullpass@*/	/* XXX spew != NULL @*/
  +    size_t nb = (nspew > 0 ? Fwrite(spew, 1, nspew, rfile->fd) : 0);
  +/*@=nullpass@*/
  +    int rc = 0;
  +    if (nspew != nb) {
  +	rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
  +		(unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
  +	rc = 1;
  +    }
  +    spew = _free(spew);
  +    return rc;
  +}
  +
  +int rpmrepoFclose(rpmrepo repo, FD_t fd)
  +{
  +    int rc = 0;
  +
  +    if (fd != NULL) {
  +#ifdef	NOTYET
  +	rpmts ts = repo->_ts;
  +	if (ts != NULL) {
  +	    (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS),
  +			fdstat_op(fd, FDSTAT_READ));
  +	    (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
  +			fdstat_op(fd, FDSTAT_DIGEST));
  +	}
  +#endif
  +	rc = Fclose(fd);
  +    }
  +    return rc;
  +}
  +
  +int rpmrepoOpenMDFile(const rpmrepo repo, rpmrfile rfile)
  +{
  +    const char * spew = rfile->xml_init;
  +    size_t nspew = strlen(spew);
  +    const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1);
  +    const char * tail;
  +    size_t nb;
  +    int rc = 0;
  +
  +    rfile->fd = Fopen(fn, repo->wmode);
  +assert(rfile->fd != NULL);
  +
  +    if (repo->algo != PGPHASHALGO_NONE)
  +	fdInitDigest(rfile->fd, repo->algo, 0);
  +
  +    if ((tail = strstr(spew, " packages=\"0\">\n")) != NULL)
  +	nspew -= strlen(tail);
  +
  +    nb = Fwrite(spew, 1, nspew, rfile->fd);
  +
  +    if (tail != NULL) {
  +	char buf[64];
  +	size_t tnb = snprintf(buf, sizeof(buf), " packages=\"%d\">\n",
  +				repo->pkgcount);
  +	nspew += tnb;
  +	nb += Fwrite(buf, 1, tnb, rfile->fd);
  +    }
  +    if (nspew != nb) {
  +	rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
  +		(unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
  +	rc = 1;
  +    }
  +
  +    fn = _free(fn);
  +
  +#if defined(WITH_SQLITE)
  +    if (REPO_ISSET(DATABASE)) {
  +	const char ** stmt;
  +	int xx;
  +	fn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
  +		rfile->type, ".sqlite", NULL);
  +	if ((xx = sqlite3_open(fn, &rfile->sqldb)) != SQLITE_OK)
  +	    rpmrepoError(1, "sqlite3_open(%s): %s", fn, sqlite3_errmsg(rfile->sqldb));
  +	for (stmt = rfile->sql_init; *stmt != NULL; stmt++) {
  +	    char * msg;
  +	    xx = sqlite3_exec(rfile->sqldb, *stmt, NULL, NULL, &msg);
  +	    if (xx != SQLITE_OK)
  +		rpmrepoError(1, "sqlite3_exec(%s, \"%s\"): %s\n", fn, *stmt,
  +			(msg != NULL ? msg : "failed"));
  +	}
  +	fn = _free(fn);
  +    }
  +#endif
  +
  +    return rc;
  +}
  +
  +#if defined(WITH_SQLITE)
  +int rpmrfileSQL(rpmrfile rfile, const char * msg, int rc)
  +{
  +    if (rc != SQLITE_OK || _rpmrepo_debug)
  +	rpmrepoError(0, "sqlite3_%s(%s): %s", msg, rfile->type,
  +		sqlite3_errmsg(rfile->sqldb));
  +    return rc;
  +}
  +
  +int rpmrfileSQLStep(rpmrfile rfile, sqlite3_stmt * stmt)
  +{
  +    int loop = 1;
  +    int rc = 0;
  +    int xx;
  +
  +/*@-infloops@*/
  +    while (loop) {
  +	rc = sqlite3_step(stmt);
  +	switch (rc) {
  +	default:
  +	    rc = rpmrfileSQL(rfile, "step", rc);
  +	    /*@fallthrough@*/
  +	case SQLITE_DONE:
  +	    loop = 0;
  +	    /*@switchbreak@*/ break;
  +	}
  +    }
  +/*@=infloops@*/
  +
  +    xx = rpmrfileSQL(rfile, "reset",
  +	sqlite3_reset(stmt));
  +
  +    return rc;
  +}
  +
  +int rpmrfileSQLWrite(rpmrfile rfile, const char * cmd)
  +{
  +    sqlite3_stmt * stmt;
  +    const char * tail;
  +    int xx;
  +
  +    xx = rpmrfileSQL(rfile, "prepare",
  +	sqlite3_prepare(rfile->sqldb, cmd, (int)strlen(cmd), &stmt, &tail));
  +
  +    xx = rpmrfileSQL(rfile, "reset",
  +	sqlite3_reset(stmt));
  +
  +    xx = rpmrfileSQLStep(rfile, stmt);
  +
  +    xx = rpmrfileSQL(rfile, "finalize",
  +	sqlite3_finalize(stmt));
  +
  +    cmd = _free(cmd);
  +
  +    return 0;
  +}
  +#endif	/* WITH_SQLITE */
  +
  +int rpmrepoRfileDigest(const rpmrepo repo, rpmrfile rfile,
  +		const char ** digestp)
  +{
  +    static int asAscii = 1;
  +    struct stat sb, *st = &sb;
  +    const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1);
  +    const char * path = NULL;
  +    int ut = urlPath(fn, &path);
  +    FD_t fd = NULL;
  +    int rc = 1;
  +    int xx;
  +
  +    memset(st, 0, sizeof(*st));
  +    if (!rpmioExists(fn, st))
  +	goto exit;
  +    fd = Fopen(fn, "r.ufdio");
  +    if (fd == NULL || Ferror(fd))
  +	goto exit;
  +
  +    switch (ut) {
  +    case URL_IS_PATH:
  +    case URL_IS_UNKNOWN:
  +#if defined(HAVE_MMAP)
  +    {   void * mapped = (void *)-1;
  +
  +	if (st->st_size > 0)
  +	    mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fd), 0);
  +	if (mapped != (void *)-1) {
  +#ifdef	NOTYET
  +	    rpmts ts = repo->_ts;
  +	    rpmop op = rpmtsOp(ts, RPMTS_OP_DIGEST);
  +	    rpmtime_t tstamp = rpmswEnter(op, 0);
  +#endif
  +	    DIGEST_CTX ctx = rpmDigestInit(repo->algo, RPMDIGEST_NONE);
  +	    xx = rpmDigestUpdate(ctx, mapped, st->st_size);
  +	    xx = rpmDigestFinal(ctx, digestp, NULL, asAscii);
  +#ifdef	NOTYET
  +	    tstamp = rpmswExit(op, st->st_size);
  +#endif
  +	    xx = munmap(mapped, st->st_size);
  +	    break;
  +	}
  +    }	/*@fallthrough@*/
  +#endif
  +    default:
  +    {	char buf[64 * BUFSIZ];
  +	size_t nb;
  +	size_t fsize = 0;
  +
  +	fdInitDigest(fd, repo->algo, 0);
  +	while ((nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
  +	    fsize += nb;
  +	if (Ferror(fd))
  +	    goto exit;
  +	fdFiniDigest(fd, repo->algo, digestp, NULL, asAscii);
  +    }	break;
  +    }
  +
  +    rc = 0;
  +
  +exit:
  +    if (fd)
  +	xx = rpmrepoFclose(repo, fd);
  +    fn = _free(fn);
  +    return rc;
  +}
  +
  +int rpmrepoCloseMDFile(const rpmrepo repo, rpmrfile rfile)
  +{
  +    static int asAscii = 1;
  +    char * xmlfn = xstrdup(fdGetOPath(rfile->fd));
  +    int rc = 0;
  +
  +    if (!repo->quiet)
  +	rpmrepoError(0, _("Saving %s metadata"), basename(xmlfn));
  +
  +    if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
  +	rc = 1;
  +
  +    if (repo->algo > 0)
  +	fdFiniDigest(rfile->fd, repo->algo, &rfile->digest, NULL, asAscii);
  +    else
  +	rfile->digest = xstrdup("");
  +
  +    (void) rpmrepoFclose(repo, rfile->fd);
  +    rfile->fd = NULL;
  +
  +    /* Compute the (usually compressed) ouput file digest too. */
  +    rfile->Zdigest = NULL;
  +    (void) rpmrepoRfileDigest(repo, rfile, &rfile->Zdigest);
  +
  +#if defined(WITH_SQLITE)
  +    if (REPO_ISSET(DATABASE) && rfile->sqldb != NULL) {
  +	const char *dbfn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
  +		rfile->type, ".sqlite", NULL);
  +	int xx;
  +	if ((xx = sqlite3_close(rfile->sqldb)) != SQLITE_OK)
  +	    rpmrepoError(1, "sqlite3_close(%s): %s", dbfn, sqlite3_errmsg(rfile->sqldb));
  +	rfile->sqldb = NULL;
  +	dbfn = _free(dbfn);
  +    }
  +#endif
  +
  +    rfile->ctime = rpmioCtime(xmlfn);
  +    xmlfn = _free(xmlfn);
  +
  +    return rc;
  +}
  +
  +/**
  + */
  +static /*@observer@*/ /*@null@*/ const char *
  +algo2tagname(uint32_t algo)
  +	/*@*/
  +{
  +    const char * tagname = NULL;
  +
  +    switch (algo) {
  +    case PGPHASHALGO_NONE:	tagname = "none";	break;
  +    case PGPHASHALGO_MD5:	tagname = "md5";	break;
  +    /* XXX todo: should be "sha1" */
  +    case PGPHASHALGO_SHA1:	tagname = "sha";	break;
  +    case PGPHASHALGO_RIPEMD160:	tagname = "rmd160";	break;
  +    case PGPHASHALGO_MD2:	tagname = "md2";	break;
  +    case PGPHASHALGO_TIGER192:	tagname = "tiger192";	break;
  +    case PGPHASHALGO_HAVAL_5_160: tagname = "haval160";	break;
  +    case PGPHASHALGO_SHA256:	tagname = "sha256";	break;
  +    case PGPHASHALGO_SHA384:	tagname = "sha384";	break;
  +    case PGPHASHALGO_SHA512:	tagname = "sha512";	break;
  +    case PGPHASHALGO_MD4:	tagname = "md4";	break;
  +    case PGPHASHALGO_RIPEMD128:	tagname = "rmd128";	break;
  +    case PGPHASHALGO_CRC32:	tagname = "crc32";	break;
  +    case PGPHASHALGO_ADLER32:	tagname = "adler32";	break;
  +    case PGPHASHALGO_CRC64:	tagname = "crc64";	break;
  +    case PGPHASHALGO_JLU32:	tagname = "jlu32";	break;
  +    case PGPHASHALGO_SHA224:	tagname = "sha224";	break;
  +    case PGPHASHALGO_RIPEMD256:	tagname = "rmd256";	break;
  +    case PGPHASHALGO_RIPEMD320:	tagname = "rmd320";	break;
  +    case PGPHASHALGO_SALSA10:	tagname = "salsa10";	break;
  +    case PGPHASHALGO_SALSA20:	tagname = "salsa20";	break;
  +    default:			tagname = NULL;		break;
  +    }
  +    return tagname;
  +}
  +
  +const char * rpmrepoMDExpand(rpmrepo repo, rpmrfile rfile)
  +{
  +    const char * spewalgo = algo2tagname(repo->algo);
  +    char spewtime[64];
  +
  +    (void) snprintf(spewtime, sizeof(spewtime), "%u", (unsigned)rfile->ctime);
  +    return rpmExpand("\
  +  <data type=\"", rfile->type, "\">\n\
  +    <checksum type=\"", spewalgo, "\">", rfile->Zdigest, "</checksum>\n\
  +    <timestamp>", spewtime, "</timestamp>\n\
  +    <open-checksum type=\"",spewalgo,"\">", rfile->digest, "</open-checksum>\n\
  +    <location href=\"", repo->finaldir, "/", rfile->type, (repo->markup != NULL ? repo->markup : ""), (repo->suffix != NULL ? repo->suffix : ""), "\"/>\n\
  +  </data>\n", NULL);
  +}
  +
  +int rpmrepoDoRepoMetadata(rpmrepo repo)
  +{
  +    rpmrfile rfile = &repo->repomd;
  +    const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 0);
  +    int rc = 0;
  +
  +    if ((rfile->fd = Fopen(fn, "w.ufdio")) != NULL) {	/* no compression */
  +	if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_init))
  +	 || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->other))
  +	 || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->filelists))
  +	 || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->primary))
  +	 || rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
  +	    rc = 1;
  +	(void) rpmrepoFclose(repo, rfile->fd);
  +	rfile->fd = NULL;
  +    }
  +
  +    fn = _free(fn);
  +    if (rc) return rc;
  +
  +#ifdef	NOTYET
  +    def doRepoMetadata(self):
  +        """wrapper to generate the repomd.xml file that stores the info on the other files"""
  +    const char * repopath =
  +		rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
  +        repodoc = libxml2.newDoc("1.0")
  +        reporoot = repodoc.newChild(None, "repomd", None)
  +        repons = reporoot.newNs("http://linux.duke.edu/metadata/repo", None)
  +        reporoot.setNs(repons)
  +        repopath = rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
  +        fn = rpmrepoGetPath(repo, repo->tempdir, repo->repomd.type, 1);
  +
  +        repoid = "garbageid";
  +
  +        if (REPO_ISSET(DATABASE)) {
  +            if (!repo->quiet) rpmrepoError(0, _("Generating sqlite DBs"));
  +            try:
  +                dbversion = str(sqlitecachec.DBVERSION)
  +            except AttributeError:
  +                dbversion = "9"
  +            rp = sqlitecachec.RepodataParserSqlite(repopath, repoid, None)
  +	}
  +
  +  { static const char * types[] =
  +	{ "primary", "filelists", "other", NULL };
  +    const char ** typep;
  +	for (typep = types; *typep != NULL; typep++) {
  +	    complete_path = rpmrepoGetPath(repo, repo->tempdir, *typep, 1);
  +
  +            zfo = _gzipOpen(complete_path)
  +            uncsum = misc.checksum(algo2tagname(repo->algo), zfo)
  +            zfo.close()
  +            csum = misc.checksum(algo2tagname(repo->algo), complete_path)
  +	    (void) rpmioExists(complete_path, st)
  +            timestamp = os.stat(complete_path)[8]
  +
  +            db_csums = {}
  +            db_compressed_sums = {}
  +
  +            if (REPO_ISSET(repo)) {
  +                if (repo->verbose) {
  +		    time_t now = time(NULL);
  +                    rpmrepoError(0, _("Starting %s db creation: %s"),
  +			*typep, ctime(&now));
  +		}
  +
  +                if (!strcmp(*typep, "primary"))
  +                    rp.getPrimary(complete_path, csum)
  +                else if (!strcmp(*typep, "filelists"));
  +                    rp.getFilelists(complete_path, csum)
  +                else if (!strcmp(*typep, "other"))
  +                    rp.getOtherdata(complete_path, csum)
  +
  +		{   const char *  tmp_result_path =
  +			rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
  +				*typep, ".xml.gz.sqlite", NULL);
  +		    const char * resultpath =
  +			rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
  +				*typep, ".sqlite", NULL);
  +
  +		    /* rename from silly name to not silly name */
  +		    xx = Rename(tmp_result_path, resultpath);
  +		    tmp_result_path = _free(tmp_result_path);
  +		    result_compressed =
  +			rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
  +				*typep, ".sqlite.bz2", NULL);
  +		    db_csums[*typep] = misc.checksum(algo2tagname(repo->algo), resultpath)
  +
  +		    /* compress the files */
  +		    bzipFile(resultpath, result_compressed)
  +		    /* csum the compressed file */
  +		    db_compressed_sums[*typep] = misc.checksum(algo2tagname(repo->algo), result_compressed)
  +		    /* remove the uncompressed file */
  +		    xx = Unlink(resultpath);
  +		    resultpath = _free(resultpath);
  +		}
  +
  +                if (REPO_ISSET(UNIQUEMDFN)) {
  +                    const char * csum_result_compressed =
  +			rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
  +				db_compressed_sums[*typep], "-", *typep, ".sqlite.bz2", NULL);
  +                    xx = Rename(result_compressed, csum_result_compressed);
  +		    result_compressed = _free(result_compressed);
  +		    result_compressed = csum_result_compressed;
  +		}
  +
  +                /* timestamp the compressed file */
  +		(void) rpmioExists(result_compressed, st)
  +                db_timestamp = os.stat(result_compressed)[8]
  +
  +                /* add this data as a section to the repomdxml */
  +                db_data_type = rpmExpand(*typep, "_db", NULL);
  +                data = reporoot.newChild(None, 'data', None)
  +                data.newProp('type', db_data_type)
  +                location = data.newChild(None, 'location', None)
  +                if (repo->baseurl != NULL) {
  +                    location.newProp('xml:base', repo->baseurl)
  +		}
  +
  +                location.newProp('href', rpmGetPath(repo->finaldir, "/", *typep, ".sqlite.bz2", NULL));
  +                checksum = data.newChild(None, 'checksum', db_compressed_sums[*typep])
  +                checksum.newProp('type', algo2tagname(repo->algo))
  +                db_tstamp = data.newChild(None, 'timestamp', str(db_timestamp))
  +                unchecksum = data.newChild(None, 'open-checksum', db_csums[*typep])
  +                unchecksum.newProp('type', algo2tagname(repo->algo))
  +                database_version = data.newChild(None, 'database_version', dbversion)
  +                if (repo->verbose) {
  +		   time_t now = time(NULL);
  +                   rpmrepoError(0, _("Ending %s db creation: %s"),
  +			*typep, ctime(&now));
  +		}
  +	    }
  +
  +            data = reporoot.newChild(None, 'data', None)
  +            data.newProp('type', *typep)
  +
  +            checksum = data.newChild(None, 'checksum', csum)
  +            checksum.newProp('type', algo2tagname(repo->algo))
  +            timestamp = data.newChild(None, 'timestamp', str(timestamp))
  +            unchecksum = data.newChild(None, 'open-checksum', uncsum)
  +            unchecksum.newProp('type', algo2tagname(repo->algo))
  +            location = data.newChild(None, 'location', None)
  +            if (repo->baseurl != NULL)
  +                location.newProp('xml:base', repo->baseurl)
  +            if (REPO_ISSET(UNIQUEMDFN)) {
  +                orig_file = rpmrepoGetPath(repo, repo->tempdir, *typep, strcmp(*typep, "repomd"));
  +                res_file = rpmExpand(csum, "-", *typep,
  +			(repo->markup ? repo->markup : ""),
  +			(repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
  +                dest_file = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", res_file, NULL);
  +                xx = Rename(orig_file, dest_file);
  +
  +            } else
  +                res_file = rpmExpand(*typep,
  +			(repo->markup ? repo->markup : ""),
  +			(repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
  +
  +            location.newProp('href', rpmGetPath(repo->finaldir, "/", res_file, NULL));
  +	}
  +  }
  +
  +        if (!repo->quiet && REPO_ISSET(DATABASE))
  +	    rpmrepoError(0, _("Sqlite DBs complete"));
  +
  +        if (repo->groupfile != NULL) {
  +            self.addArbitraryMetadata(repo->groupfile, 'group_gz', reporoot)
  +            self.addArbitraryMetadata(repo->groupfile, 'group', reporoot, compress=False)
  +	}
  +
  +        /* save it down */
  +        try:
  +            repodoc.saveFormatFileEnc(fn, 'UTF-8', 1)
  +        except:
  +            rpmrepoError(0, _("Error saving temp file for %s%s%s: %s"),
  +		rfile->type,
  +		(repo->markup ? repo->markup : ""),
  +		(repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""),
  +		fn);
  +            rpmrepoError(1, _("Could not save temp file: %s"), fn);
  +
  +        del repodoc
  +#endif
  +
  +    return rc;
  +}
  +
  +int rpmrepoDoFinalMove(rpmrepo repo)
  +{
  +    char * output_final_dir =
  +		rpmGetPath(repo->outputdir, "/", repo->finaldir, NULL);
  +    char * output_old_dir =
  +		rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
  +    struct stat sb, *st = &sb;
  +    int xx;
  +
  +    if (rpmioExists(output_final_dir, st)) {
  +	if ((xx = Rename(output_final_dir, output_old_dir)) != 0)
  +	    rpmrepoError(1, _("Error moving final %s to old dir %s"),
  +			output_final_dir, output_old_dir);
  +    }
  +
  +    {	const char * output_temp_dir =
  +		rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
  +	if ((xx = Rename(output_temp_dir, output_final_dir)) != 0) {
  +	    xx = Rename(output_old_dir, output_final_dir);
  +	    rpmrepoError(1, _("Error moving final metadata into place"));
  +	}
  +	output_temp_dir = _free(output_temp_dir);
  +    }
  +
  +    /* Merge old tree into new, unlink/rename as needed. */
  +  { 
  +    char *const _av[] = { output_old_dir, NULL };
  +    int _ftsoptions = FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV;
  +    int (*_compar)(const FTSENT **, const FTSENT **) = NULL;
  +    FTS * t = Fts_open(_av, _ftsoptions, _compar);
  +    FTSENT * p = NULL;
  +
  +    if (t != NULL)
  +    while ((p = Fts_read(t)) != NULL) {
  +	const char * opath = p->fts_accpath;
  +	const char * ofn = p->fts_path;
  +	const char * obn = p->fts_name;
  +	const char * nfn = NULL;
  +	switch (p->fts_info) {
  +	default:
  +	    break;
  +	case FTS_DP:
  +	    /* Remove empty directories on post-traversal visit. */
  +	    if ((xx = Rmdir(opath)) != 0)
  +		rpmrepoError(1, _("Could not remove old metadata directory: %s: %s"),
  +				ofn, strerror(errno));
  +	    break;
  +	case FTS_F:
  +	    /* Remove all non-toplevel files. */
  +	    if (p->fts_level > 0) {
  +		if ((xx = Unlink(opath)) != 0)
  +		    rpmrepoError(1, _("Could not remove old metadata file: %s: %s"),
  +				ofn, strerror(errno));
  +		break;
  +	    }
  +
  +	    /* Remove/rename toplevel files, dependent on target existence. */
  +	    nfn = rpmGetPath(output_final_dir, "/", obn, NULL);
  +	    if (rpmioExists(nfn, st)) {
  +		if ((xx = Unlink(opath)) != 0)
  +		    rpmrepoError(1, _("Could not remove old metadata file: %s: %s"),
  +				ofn, strerror(errno));
  +	    } else {
  +		if ((xx = Rename(opath, nfn)) != 0)
  +		    rpmrepoError(1, _("Could not restore old non-metadata file: %s -> %s: %s"),
  +				ofn, nfn, strerror(errno));
  +	    }
  +	    nfn = _free(nfn);
  +	    break;
  +	case FTS_SL:
  +	case FTS_SLNONE:
  +	    /* Remove all symlinks. */
  +	    if ((xx = Unlink(opath)) != 0)
  +		rpmrepoError(1, _("Could not remove old metadata symlink: %s: %s"),
  +				ofn, strerror(errno));
  +	    break;
  +	}
  +    }
  +    if (t != NULL)
  +        Fts_close(t);
  +  }
  +
  +    output_old_dir = _free(output_old_dir);
  +    output_final_dir = _free(output_final_dir);
  +
  +    return 0;
  +}
  +
  +/*==============================================================*/
  +
  +/*@unchecked@*/
  +static int compression = -1;
  +
  +/*@unchecked@*/ /*@observer@*/
  +static struct poptOption repoCompressionPoptTable[] = {
  + { "uncompressed", '\0', POPT_ARG_VAL,		&compression, 0,
  +	N_("don't compress"), NULL },
  + { "gzip", 'Z', POPT_ARG_VAL,			&compression, 1,
  +	N_("use gzip compression"), NULL },
  + { "bzip2", '\0', POPT_ARG_VAL,			&compression, 2,
  +	N_("use bzip2 compression"), NULL },
  + { "lzma", '\0', POPT_ARG_VAL,			&compression, 3,
  +	N_("use lzma compression"), NULL },
  + { "xz", '\0', POPT_ARG_VAL,			&compression, 4,
  +	N_("use xz compression"), NULL },
  +  POPT_TABLEEND
  +};
  +
  +/*@unchecked@*/ /*@observer@*/
  +struct poptOption _rpmrepoOptions[] = {
  +
  + { "quiet", 'q', POPT_ARG_VAL,			&__repo.quiet, 0,
  +	N_("output nothing except for serious errors"), NULL },
  + { "verbose", 'v', 0,				NULL, (int)'v',
  +	N_("output more debugging info."), NULL },
  + { "dryrun", '\0', POPT_BIT_SET,	&__repo.flags, REPO_FLAGS_DRYRUN,
  +	N_("sanity check arguments, don't create metadata"), NULL },
  + { "excludes", 'x', POPT_ARG_ARGV,		&__repo.exclude_patterns, 0,
  +	N_("glob PATTERN(s) to exclude"), N_("PATTERN") },
  + { "includes", 'i', POPT_ARG_ARGV,		&__repo.include_patterns, 0,
  +	N_("glob PATTERN(s) to include"), N_("PATTERN") },
  + { "basedir", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,	&__repo.basedir, 0,
  +	N_("top level directory"), N_("DIR") },
  + { "baseurl", 'u', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,	&__repo.baseurl, 0,
  +	N_("baseurl to append on all files"), N_("BASEURL") },
  +#ifdef	NOTYET
  + { "groupfile", 'g', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,	&__repo.groupfile, 0,
  +	N_("path to groupfile to include in metadata"), N_("FILE") },
  +#endif
  + { "pretty", 'p', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,		&__repo.flags, REPO_FLAGS_PRETTY,
  +	N_("make sure all xml generated is formatted"), NULL },
  + { "checkts", 'C', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,	&__repo.flags, REPO_FLAGS_CHECKTS,
  +	N_("check timestamps on files vs the metadata to see if we need to update"), NULL },
  + { "database", 'd', POPT_BIT_SET,		&__repo.flags, REPO_FLAGS_DATABASE,
  +	N_("create sqlite3 database files"), NULL },
  + { "split", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,		&__repo.flags, REPO_FLAGS_SPLIT,
  +	N_("generate split media"), NULL },
  + { "pkglist", 'l', POPT_ARG_ARGV|POPT_ARGFLAG_DOC_HIDDEN,	&__repo.manifests, 0,
  +	N_("use only the files listed in this file from the directory specified"), N_("FILE") },
  + { "outputdir", 'o', POPT_ARG_STRING,		&__repo.outputdir, 0,
  +	N_("<dir> = optional directory to output to"), N_("DIR") },
  + { "skip-symlinks", 'S', POPT_BIT_SET,		&__repo.flags, REPO_FLAGS_NOFOLLOW,
  +	N_("ignore symlinks of packages"), NULL },
  + { "unique-md-filenames", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_UNIQUEMDFN,
  +	N_("include the file's checksum in the filename, helps with proxies"), NULL },
  +
  +  POPT_TABLEEND
  +
  +};
  +
  +/*@unchecked@*/ /*@observer@*/
  +static struct poptOption rpmrepoOptionsTable[] = {
  +
  + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, _rpmrepoOptions, 0,
  +	N_("Repository options:"), NULL },
  +
  + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0,
  +	N_("Fts(3) traversal options:"), NULL },
  +
  + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, repoCompressionPoptTable, 0,
  +	N_("Available compressions:"), NULL },
  +
  + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0,
  +	N_("Available digests:"), NULL },
  +
  + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
  +	N_("Common options for all rpmio executables:"),
  +	NULL },
  +
  +  POPT_AUTOALIAS
  +  POPT_AUTOHELP
  +  POPT_TABLEEND
  +};
  +
  +static int rpmrepoInitPopt(rpmrepo repo, char ** av)
  +	/*@modifies repo @*/
  +{
  +    void *use =  repo->_item.use;
  +    void *pool = repo->_item.pool;
  +    int ac = argvCount((ARGV_t)av);
  +    poptContext con = rpmioInit(ac, av, rpmrepoOptionsTable);
  +    int rc = 0;		/* XXX assume success */
  +    int xx;
  +    int i;
  +
  +    *repo = *_repo;	/* structure assignment */
  +    repo->_item.use = use;
  +    repo->_item.pool = pool;
  +
  +    repo->con = con;
  +
  +    /* XXX Impedanace match against poptIO common code. */
  +    if (rpmIsVerbose())
  +	repo->verbose++;
  +    if (rpmIsDebug())
  +	repo->verbose++;
  +
  +    repo->ftsoptions = (rpmioFtsOpts ? rpmioFtsOpts : FTS_PHYSICAL);
  +    switch (repo->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)) {
  +    case (FTS_LOGICAL|FTS_PHYSICAL):
  +	rpmrepoError(1, "FTS_LOGICAL and FTS_PYSICAL are mutually exclusive");
  +        /*@notreached@*/ break;
  +    case 0:
  +        repo->ftsoptions |= FTS_PHYSICAL;
  +        break;
  +    }
  +
  +    repo->algo = (rpmioDigestHashAlgo >= 0
  +		? (rpmioDigestHashAlgo & 0xff)  : PGPHASHALGO_SHA1);
  +
  +    repo->compression = (compression >= 0 ? compression : 1);
  +    switch (repo->compression) {
  +    case 0:
  +	repo->suffix = NULL;
  +	repo->wmode = "w.ufdio";
  +	break;
  +    default:
  +	/*@fallthrough@*/
  +    case 1:
  +	repo->suffix = ".gz";
  +	repo->wmode = "w9.gzdio";
  +	break;
  +    case 2:
  +	repo->suffix = ".bz2";
  +	repo->wmode = "w9.bzdio";
  +	break;
  +    case 3:
  +	repo->suffix = ".lzma";
  +	repo->wmode = "w.lzdio";
  +	break;
  +    case 4:
  +	repo->suffix = ".xz";
  +	repo->wmode = "w.xzdio";
  +	break;
  +    }
  +
  +    repo->av = poptGetArgs(repo->con);
  +
  +    if (repo->av == NULL || repo->av[0] == NULL)
  +	rpmrepoError(1, _("Must specify path(s) to index."));
  +
  +    if (repo->av != NULL)
  +    for (i = 0; repo->av[i] != NULL; i++) {
  +	char fullpath[MAXPATHLEN];
  +	struct stat sb;
  +	const char * rpath;
  +	const char * lpath = NULL;
  +	int ut = urlPath(repo->av[i], &lpath);
  +	size_t nb = (size_t)(lpath - repo->av[i]);
  +	int isdir = (lpath[strlen(lpath)-1] == '/');
  +	
  +	/* Convert to absolute/clean/malloc'd path. */
  +	if (lpath[0] != '/') {
  +	    if ((rpath = rpmrepoRealpath(lpath)) == NULL)
  +		rpmrepoError(1, _("Realpath(%s): %s"), lpath, strerror(errno));
  +	    lpath = rpmGetPath(rpath, NULL);
  +	    rpath = _free(rpath);
  +	} else
  +	    lpath = rpmGetPath(lpath, NULL);
  +
  +	/* Reattach the URI to the absolute/clean path. */
  +	/* XXX todo: rpmGenPath was confused by file:///path/file URI's. */
  +	switch (ut) {
  +	case URL_IS_DASH:
  +	case URL_IS_UNKNOWN:
  +	    rpath = lpath;
  +	    lpath = NULL;
  +	    /*@switchbreak@*/ break;
  +	default:
  +assert(nb < sizeof(fullpath));
  +	    strncpy(fullpath, repo->av[i], nb);
  +	    fullpath[nb] = '\0';
  +	    rpath = rpmGenPath(fullpath, lpath, NULL);
  +	    lpath = _free(lpath);
  +	    /*@switchbreak@*/ break;
  +	}
  +
  +	/* Add a trailing '/' on directories. */
  +	lpath = (isdir || (!Stat(rpath, &sb) && S_ISDIR(sb.st_mode))
  +		? "/" : NULL);
  +	if (lpath != NULL) {
  +	    lpath = rpmExpand(rpath, lpath, NULL);
  +	    xx = argvAdd(&repo->directories, lpath);
  +	    lpath = _free(lpath);
  +	} else {
  +	    xx = argvAdd(&repo->pkglist, rpath);
  +	}
  +	rpath = _free(rpath);
  +    }
  +
  +    return rc;
  +}
  +
  +static void rpmrepoFini(void * _repo)
  +	/*@globals fileSystem @*/
  +	/*@modifies *_repo, fileSystem @*/
  +{
  +    rpmrepo repo = _repo;
  +
  +    repo->primary.digest = _free(repo->primary.digest);
  +    repo->primary.Zdigest = _free(repo->primary.Zdigest);
  +    repo->filelists.digest = _free(repo->filelists.digest);
  +    repo->filelists.Zdigest = _free(repo->filelists.Zdigest);
  +    repo->other.digest = _free(repo->other.digest);
  +    repo->other.Zdigest = _free(repo->other.Zdigest);
  +    repo->repomd.digest = _free(repo->repomd.digest);
  +    repo->repomd.Zdigest = _free(repo->repomd.Zdigest);
  +    repo->outputdir = _free(repo->outputdir);
  +    repo->pkglist = argvFree(repo->pkglist);
  +    repo->directories = argvFree(repo->directories);
  +    repo->manifests = argvFree(repo->manifests);
  +/*@-onlytrans -refcounttrans @*/
  +    repo->excludeMire = mireFreeAll(repo->excludeMire, repo->nexcludes);
  +    repo->includeMire = mireFreeAll(repo->includeMire, repo->nincludes);
  +/*@=onlytrans =refcounttrans @*/
  +    repo->exclude_patterns = argvFree(repo->exclude_patterns);
  +    repo->include_patterns = argvFree(repo->include_patterns);
  +
  +    repo->con = poptFreeContext(repo->con);
  +
  +}
  +
  +/*@unchecked@*/ /*@only@*/ /*@null@*/
  +rpmioPool _rpmrepoPool = NULL;
  +
  +static rpmrepo rpmrepoGetPool(/*@null@*/ rpmioPool pool)
  +	/*@globals _rpmrepoPool, fileSystem @*/
  +	/*@modifies pool, _rpmrepoPool, fileSystem @*/
  +{
  +    rpmrepo repo;
  +
  +    if (_rpmrepoPool == NULL) {
  +	_rpmrepoPool = rpmioNewPool("repo", sizeof(*repo), -1, _rpmrepo_debug,
  +			NULL, NULL, rpmrepoFini);
  +	pool = _rpmrepoPool;
  +    }
  +    repo = (rpmrepo) rpmioGetPool(pool, sizeof(*repo));
  +    memset(((char *)repo)+sizeof(repo->_item), 0, sizeof(*repo)-sizeof(repo->_item));
  +    return repo;
  +}
  +
  +rpmrepo rpmrepoNew(char ** av, int flags)
  +{
  +    rpmrepo repo = rpmrepoGetPool(_rpmrepoPool);
  +    int xx;
  +
  +    xx = rpmrepoInitPopt(repo, av);
  +
  +    return rpmrepoLink(repo);
  +}
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmdb/rpmrepo.h
  ============================================================================
  $ cvs diff -u -r0 -r1.2 rpmrepo.h
  --- /dev/null	2010-09-27 21:38:30.000000000 +0200
  +++ rpmrepo.h	2010-09-27 21:41:45.888170678 +0200
  @@ -0,0 +1,438 @@
  +#ifndef	H_RPMREPO
  +#define	H_RPMREPO
  +
  +/** \ingroup rpmio
  + * \file rpmio/rpmrepo.h
  + */
  +
  +#include <rpmiotypes.h>
  +#include <rpmio.h>
  +#include <argv.h>
  +#include <mire.h>
  +#include <popt.h>
  +
  +/** \ingroup rpmio
  + */
  +typedef /*@abstract@*/ /*@refcounted@*/ struct rpmrepo_s * rpmrepo;
  +typedef /*@abstract@*/ /*@refcounted@*/ struct rpmrfile_s * rpmrfile;
  +
  +/** \ingroup rpmio
  + */
  +/*@unchecked@*/
  +extern int _rpmrepo_debug;
  +
  +#if defined(_RPMREPO_INTERNAL)
  +/**
  + * Repository metadata file.
  + */
  +struct rpmrfile_s {
  +/*@observer@*/
  +    const char * type;
  +/*@observer@*/
  +    const char * xml_init;
  +/*@observer@*/ /*@relnull@*/
  +    const char * xml_qfmt;
  +/*@observer@*/
  +    const char * xml_fini;
  +/*@observer@*/
  +    const char ** sql_init;
  +/*@observer@*/
  +    const char * sql_qfmt;
  +#ifdef	NOTYET	/* XXX char **?!? */
  +/*@observer@*/
  +    const char ** sql_fini;
  +#endif
  +/*@observer@*/
  +    const char * yaml_init;
  +/*@observer@*/
  +    const char * yaml_qfmt;
  +/*@observer@*/
  +    const char * yaml_fini;
  +/*@observer@*/
  +    const char * Packages_init;
  +/*@observer@*/
  +    const char * Packages_qfmt;
  +/*@observer@*/
  +    const char * Packages_fini;
  +/*@observer@*/
  +    const char * Sources_init;
  +/*@observer@*/
  +    const char * Sources_qfmt;
  +/*@observer@*/
  +    const char * Sources_fini;
  +/*@relnull@*/
  +    FD_t fd;
  +#if defined(WITH_SQLITE)
  +    sqlite3 * sqldb;
  +#endif
  +/*@null@*/
  +    const char * digest;
  +/*@null@*/
  +    const char * Zdigest;
  +    time_t ctime;
  +};
  +
  +/**
  + * Repository.
  + */
  +#define	_RFB(n)	((1U << (n)) | 0x40000000)
  +
  +/**
  + * Bit field enum for copy CLI options.
  + */
  +typedef enum rpmrepoFlags_e {
  +    REPO_FLAGS_NONE		= 0,
  +    REPO_FLAGS_DRYRUN		= _RFB( 0), /*!<    --dryrun ... */
  +    REPO_FLAGS_PRETTY		= _RFB( 1), /*!< -p,--pretty ... */
  +    REPO_FLAGS_DATABASE		= _RFB( 2), /*!< -d,--database ... */
  +    REPO_FLAGS_CHECKTS		= _RFB( 3), /*!< -C,--checkts ... */
  +    REPO_FLAGS_SPLIT		= _RFB( 4), /*!<    --split ... */
  +    REPO_FLAGS_NOFOLLOW		= _RFB( 5), /*!< -S,--skip-symlinks ... */
  +    REPO_FLAGS_UNIQUEMDFN	= _RFB( 6), /*!<    --unique-md-filenames ... */
  +
  +	/* 7-31 unused */
  +} rpmrepoFlags;
  +
  +#define REPO_ISSET(_FLAG) ((repo->flags & ((REPO_FLAGS_##_FLAG) & ~0x40000000)) != REPO_FLAGS_NONE)
  +
  +struct rpmrepo_s {
  +    struct rpmioItem_s _item;	/*!< usage mutex and pool identifier. */
  +    const char * fn;
  +
  +    rpmrepoFlags flags;		/*!< control bits */
  +    poptContext con;		/*!< parsing state */
  +    const char ** av;		/*!< arguments */
  +
  +    int quiet;
  +    int verbose;
  +/*@null@*/
  +    ARGV_t exclude_patterns;
  +/*@relnull@*/
  +    miRE excludeMire;
  +    int nexcludes;
  +/*@null@*/
  +    ARGV_t include_patterns;
  +/*@relnull@*/
  +    miRE includeMire;
  +    int nincludes;
  +/*@null@*/
  +    const char * basedir;
  +/*@null@*/
  +    const char * baseurl;
  +#ifdef	NOTYET
  +/*@null@*/
  +    const char * groupfile;
  +#endif
  +/*@relnull@*/
  +    const char * outputdir;
  +
  +/*@null@*/
  +    ARGV_t manifests;
  +
  +/*@observer@*/ /*@relnull@*/
  +    const char * tempdir;
  +/*@observer@*/ /*@relnull@*/
  +    const char * finaldir;
  +/*@observer@*/ /*@relnull@*/
  +    const char * olddir;
  +
  +    time_t mdtimestamp;
  +
  +/*@null@*/
  +    void * _ts;
  +/*@null@*/
  +    ARGV_t pkglist;
  +    unsigned current;
  +    unsigned pkgcount;
  +
  +/*@null@*/
  +    ARGV_t directories;
  +    int ftsoptions;
  +    uint32_t pkgalgo;
  +    uint32_t algo;
  +    int compression;
  +/*@observer@*/
  +    const char * markup;
  +/*@observer@*/ /*@null@*/
  +    const char * suffix;
  +/*@observer@*/
  +    const char * wmode;
  +
  +    struct rpmrfile_s primary;
  +    struct rpmrfile_s filelists;
  +    struct rpmrfile_s other;
  +    struct rpmrfile_s repomd;
  +
  +#if defined(__LCLINT__)
  +/*@refs@*/
  +    int nrefs;			/*!< (unused) keep splint happy */
  +#endif
  +};
  +
  +#endif	/* _RPMREPO_INTERNAL */
  +
  +#ifdef __cplusplus
  +extern "C" {
  +#endif
  +
  +/**
  + * Unreference a repo wrapper instance.
  + * @param repo		repo wrapper
  + * @return		NULL on last dereference
  + */
  +/*@unused@*/ /*@null@*/
  +rpmrepo rpmrepoUnlink (/*@killref@*/ /*@only@*/ /*@null@*/ rpmrepo repo)
  +	/*@modifies repo @*/;
  +#define	rpmrepoUnlink(_repo)	\
  +    ((rpmrepo)rpmioUnlinkPoolItem((rpmioItem)(_repo), __FUNCTION__, __FILE__, __LINE__))
  +
  +/**
  + * Reference a repo wrapper instance.
  + * @param repo		repo wrapper
  + * @return		new repo wrapper reference
  + */
  +/*@unused@*/ /*@newref@*/ /*@null@*/
  +rpmrepo rpmrepoLink (/*@null@*/ rpmrepo repo)
  +	/*@modifies repo @*/;
  +#define	rpmrepoLink(_repo)	\
  +    ((rpmrepo)rpmioLinkPoolItem((rpmioItem)(_repo), __FUNCTION__, __FILE__, __LINE__))
  +
  +/**
  + * Destroy a repo wrapper.
  + * @param repo		repo wrapper
  + * @return		NULL on last dereference
  + */
  +/*@null@*/
  +rpmrepo rpmrepoFree(/*@killref@*/ /*@null@*/rpmrepo repo)
  +	/*@globals fileSystem @*/
  +	/*@modifies repo, fileSystem @*/;
  +#define	rpmrepoFree(_repo)	\
  +    ((rpmrepo)rpmioFreePoolItem((rpmioItem)(_repo), __FUNCTION__, __FILE__, __LINE__))
  +
  +/**
  + * Create and load a repo wrapper.
  + * @param av		repo argv
  + * @param flags		repo flags
  + * @return		new repo wrapper
  + */
  +/*@newref@*/ /*@null@*/
  +rpmrepo rpmrepoNew(char ** av, int flags)
  +	/*@globals fileSystem, internalState @*/
  +	/*@modifies fileSystem, internalState @*/;
  +
  +#if defined(_RPMREPO_INTERNAL)
  +/**
  + * Return stat(2) for a file.
  + * @retval st		stat(2) buffer
  + * @return		0 on success
  + */
  +int rpmioExists(const char * fn, /*@out@*/ struct stat * st)
  +	/*@globals h_errno, fileSystem, internalState @*/
  +	/*@modifies st, fileSystem, internalState @*/;
  +
  +/**
  + * Return stat(2) creation time of a file.
  + * @param fn		file path
  + * @return		st_ctime
  + */
  +time_t rpmioCtime(const char * fn)
  +	/*@globals h_errno, fileSystem, internalState @*/
  +	/*@modifies fileSystem, internalState @*/;
  +
  +/*@unchecked@*/
  +extern struct poptOption _rpmrepoOptions[];
  +
  +/**
  + * Print an error message and exit (if requested).
  + * @param lvl		error level (non-zero exits)
  + * @param fmt		msg format
  + */
  +/*@mayexit@*/
  +void rpmrepoError(int lvl, const char *fmt, ...)
  +	/*@globals fileSystem @*/
  +	/*@modifies fileSystem @*/;
  +
  +/**
  + * Return /repository/directory/component.markup.compression path.
  + * @param repo		repository
  + * @param dir		directory
  + * @param type		file
  + * @return		repository file path
  + */
  +const char * rpmrepoGetPath(rpmrepo repo, const char * dir,
  +		const char * type, int compress)
  +	/*@globals h_errno, rpmGlobalMacroContext, internalState @*/
  +	/*@modifies rpmGlobalMacroContext, internalState @*/;
  +
  +/**
  + * Display progress.
  + * @param repo		repository 
  + * @param item		repository item (usually a file path)
  + * @param current	current iteration index
  + * @param total		maximum iteration index
  + */
  +void rpmrepoProgress(/*@unused@*/ rpmrepo repo,
  +		/*@null@*/ const char * item, int current, int total)
  +	/*@globals fileSystem, internalState @*/
  +	/*@modifies fileSystem, internalState @*/;
  +
  +/**
  + * Create directory path.
  + * @param repo		repository 
  + * @param dn		directory path
  + * @return		0 on success
  + */
  +int rpmrepoMkdir(rpmrepo repo, const char * dn)
  +	/*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
  +	/*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/;
  +
  +/**
  + * Return realpath(3) canonicalized absolute path.
  + * @param lpath		file path
  + * @retrun		canonicalized absolute path
  + */
  +/*@null@*/
  +const char * rpmrepoRealpath(const char * lpath)
  +	/*@globals fileSystem, internalState @*/
  +	/*@modifies fileSystem, internalState @*/;
  +
  +/**
  + * Test for repository sanity.
  + * @param repo		repository
  + * @return		0 on success
  + */
  +int rpmrepoTestSetupDirs(rpmrepo repo)
  +	/*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
  +	/*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/;
  +
  +/**
  + * Walk file/directory trees, looking for files with an extension.
  + * @param repo		repository
  + * @param roots		file/directory trees to search
  + * @param ext		file extension to match (usually ".rpm")
  + * @return		list of files with the extension
  + */
  +/*@null@*/
  +const char ** rpmrepoGetFileList(rpmrepo repo, const char *roots[],
  +		const char * ext)
  +	/*@globals fileSystem, internalState @*/
  +	/*@modifies repo, fileSystem, internalState @*/;
  +
  +/**
  + * Check that repository time stamp is newer than any contained package.
  + * @param repo		repository
  + * @return		0 on success
  + */
  +int rpmrepoCheckTimeStamps(rpmrepo repo)
  +	/*@globals h_errno, fileSystem, internalState @*/
  +	/*@modifies fileSystem, internalState @*/;
  +
  +/**
  + * Write to a repository metadata file.
  + * @param rfile		repository metadata file
  + * @param spew		contents
  + * @return		0 on success
  + */
  +int rpmrfileXMLWrite(rpmrfile rfile, /*@only@*/ /*@null@*/ const char * spew)
  +	/*@globals fileSystem @*/
  +	/*@modifies rfile, fileSystem @*/;
  +
  +/**
  + * Close an I/O stream, accumulating uncompress/digest statistics.
  + * @param repo		repository
  + * @param fd		I/O stream
  + * @return		0 on success
  + */
  +int rpmrepoFclose(rpmrepo repo, FD_t fd)
  +	/*@modifies repo, fd @*/;
  +
  +/**
  + * Open a repository metadata file.
  + * @param repo		repository
  + * @param rfile		repository metadata file
  + * @return		0 on success
  + */
  +int rpmrepoOpenMDFile(const rpmrepo repo, rpmrfile rfile)
  +	/*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
  +	/*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/;
  +
  +/**
  + * Check sqlite3 return, displaying error messages.
  + * @param rfile		repository metadata file
  + * @return		SQLITE_OK on success
  + */
  +int rpmrfileSQL(rpmrfile rfile, const char * msg, int rc)
  +	/*@globals fileSystem @*/
  +	/*@modifies fileSystem @*/;
  +
  +/**
  + * Execute a compiled SQL command.
  + * @param rfile		repository metadata file
  + * @return		SQLITE_OK on success
  + */
  +int rpmrfileSQLStep(rpmrfile rfile, sqlite3_stmt * stmt)
  +	/*@globals fileSystem @*/
  +	/*@modifies fileSystem @*/;
  +
  +/**
  + * Run a sqlite3 command.
  + * @param rfile		repository metadata file
  + * @param cmd		sqlite3 command to run
  + * @return		0 always
  + */
  +int rpmrfileSQLWrite(rpmrfile rfile, /*@only@*/ const char * cmd)
  +	/*@globals fileSystem @*/
  +	/*@modifies fileSystem @*/;
  +
  +/**
  + * Compute digest of a file.
  + * @return		0 on success
  + */
  +int rpmrepoRfileDigest(const rpmrepo repo, rpmrfile rfile,
  +		const char ** digestp)
  +	/*@modifies *digestp @*/;
  +
  +/**
  + * Close a repository metadata file.
  + * @param repo		repository
  + * @param rfile		repository metadata file
  + * @return		0 on success
  + */
  +int rpmrepoCloseMDFile(const rpmrepo repo, rpmrfile rfile)
  +	/*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
  +	/*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/;
  +
  +/**
  + * Return a repository metadata file item.
  + * @param repo		repository
  + * @return		repository metadata file item
  + */
  +const char * rpmrepoMDExpand(rpmrepo repo, rpmrfile rfile)
  +	/*@globals h_errno, rpmGlobalMacroContext, internalState @*/
  +	/*@modifies rpmGlobalMacroContext, internalState @*/;
  +
  +/**
  + * Write repository manifest.
  + * @param repo		repository
  + * @return		0 on success.
  + */
  +int rpmrepoDoRepoMetadata(rpmrepo repo)
  +	/*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
  +	/*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/;
  +
  +/**
  + * Rename temporary repository to final paths.
  + * @param repo		repository
  + * @return		0 always
  + */
  +int rpmrepoDoFinalMove(rpmrepo repo)
  +	/*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
  +	/*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/;
  +
  +#endif	/* _RPMREPO_INTERNAL */
  +
  +#ifdef __cplusplus
  +}
  +#endif
  +
  +#endif	/* H_RPMREPO */
  @@ .
  rm -f rpm/rpmio/rpmrepo.c <<'@@ .'
  Index: rpm/rpmio/rpmrepo.c
  ============================================================================
  [NO CHANGE SUMMARY BECAUSE FILE AS A WHOLE IS JUST REMOVED]
  @@ .
  rm -f rpm/rpmio/rpmrepo.h <<'@@ .'
  Index: rpm/rpmio/rpmrepo.h
  ============================================================================
  [NO CHANGE SUMMARY BECAUSE FILE AS A WHOLE IS JUST REMOVED]
  @@ .
Received on Mon Sep 27 21:41:46 2010
Driven by Jeff Johnson and the RPM project team.
Hosted by OpenPKG and Ralf S. Engelschall.
Powered by FreeBSD and OpenPKG.