summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorbiao716.wang <biao716.wang@samsung.com>2023-08-28 14:57:22 +0900
committerbiao716.wang <biao716.wang@samsung.com>2023-08-28 14:57:22 +0900
commit0fb104edc1e949fd224866aa900463aa2d6588d0 (patch)
treecdc9ddc3123edd5741e5151f3076c9bfc9535916 /lib
parenta0dea826f88a4c5c9ceb722592cceedeb75a32fe (diff)
downloadlibrpm-tizen-0fb104edc1e949fd224866aa900463aa2d6588d0.tar.gz
librpm-tizen-0fb104edc1e949fd224866aa900463aa2d6588d0.tar.bz2
librpm-tizen-0fb104edc1e949fd224866aa900463aa2d6588d0.zip
Upgrade version to 4.14sandbox/wangbiao/rpm414_tizen
Change-Id: Ifd629ba679a11ede4d831195c6aea2245efc3300 Signed-off-by: biao716.wang <biao716.wang@samsung.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/.gitignore1
-rw-r--r--lib/Makefile.am34
-rw-r--r--lib/backend/db3.c994
-rw-r--r--lib/backend/dbconfig.c2
-rw-r--r--lib/backend/dbi.c184
-rw-r--r--lib/backend/dbi.h202
-rw-r--r--lib/backend/dbiset.c214
-rw-r--r--lib/backend/dbiset.h130
-rw-r--r--lib/backend/lmdb.c939
-rw-r--r--lib/backend/ndb/glue.c492
-rw-r--r--lib/backend/ndb/rpmidx.c1280
-rw-r--r--lib/backend/ndb/rpmidx.h18
-rw-r--r--lib/backend/ndb/rpmpkg.c1312
-rw-r--r--lib/backend/ndb/rpmpkg.h20
-rw-r--r--lib/backend/ndb/rpmxdb.c1221
-rw-r--r--lib/backend/ndb/rpmxdb.h27
-rw-r--r--lib/cpio.c320
-rw-r--r--lib/cpio.h113
-rw-r--r--lib/depends.c517
-rw-r--r--lib/formats.c639
-rw-r--r--lib/fprint.c186
-rw-r--r--lib/fsm.c1751
-rw-r--r--lib/fsm.h13
-rw-r--r--lib/header.c646
-rw-r--r--lib/header.h92
-rw-r--r--lib/header_internal.h92
-rw-r--r--lib/headerfmt.c83
-rw-r--r--lib/headerutil.c285
-rw-r--r--lib/legacy.c379
-rw-r--r--lib/manifest.c12
-rw-r--r--lib/merge.c347
-rw-r--r--lib/misc.h34
-rw-r--r--lib/order.c153
-rw-r--r--lib/package.c741
-rw-r--r--lib/poptALL.c89
-rw-r--r--lib/poptI.c22
-rw-r--r--lib/poptQV.c36
-rw-r--r--lib/psm.c925
-rw-r--r--lib/query.c70
-rw-r--r--lib/relocation.c560
-rw-r--r--lib/rpmal.c188
-rw-r--r--lib/rpmal.h15
-rw-r--r--lib/rpmarchive.h149
-rw-r--r--lib/rpmcallback.h21
-rw-r--r--lib/rpmchecksig.c419
-rw-r--r--lib/rpmcli.h17
-rw-r--r--lib/rpmdb.c1933
-rw-r--r--lib/rpmdb.h48
-rw-r--r--lib/rpmdb_internal.h92
-rw-r--r--lib/rpmds.c786
-rw-r--r--lib/rpmds.h207
-rw-r--r--lib/rpmds_internal.h67
-rw-r--r--lib/rpmfi.c2208
-rw-r--r--lib/rpmfi.h385
-rw-r--r--lib/rpmfi_internal.h180
-rw-r--r--lib/rpmfiles.h519
-rw-r--r--lib/rpmfs.c11
-rw-r--r--lib/rpmfs.h3
-rw-r--r--lib/rpmgi.c25
-rw-r--r--lib/rpmhash.C6
-rw-r--r--lib/rpminstall.c76
-rw-r--r--lib/rpmlead.c41
-rw-r--r--lib/rpmlead.h23
-rw-r--r--lib/rpmlib.h5
-rw-r--r--lib/rpmlock.c89
-rw-r--r--lib/rpmlock.h17
-rw-r--r--lib/rpmplugin.h145
-rw-r--r--lib/rpmplugins.c422
-rw-r--r--lib/rpmplugins.h181
-rw-r--r--lib/rpmprob.h2
-rw-r--r--lib/rpmrc.c745
-rw-r--r--lib/rpmscript.c284
-rw-r--r--lib/rpmscript.h48
-rw-r--r--lib/rpmtag.h100
-rw-r--r--lib/rpmtd.c92
-rw-r--r--lib/rpmtd.h15
-rw-r--r--lib/rpmte.c290
-rw-r--r--lib/rpmte.h22
-rw-r--r--lib/rpmte_internal.h56
-rw-r--r--lib/rpmtriggers.c632
-rw-r--r--lib/rpmtriggers.h84
-rw-r--r--lib/rpmts.c249
-rw-r--r--lib/rpmts.h74
-rw-r--r--lib/rpmts_internal.h54
-rw-r--r--lib/rpmtypes.h3
-rw-r--r--lib/rpmug.c54
-rw-r--r--lib/rpmug.h4
-rw-r--r--lib/rpmvercmp.c2
-rw-r--r--lib/rpmvf.h7
-rw-r--r--lib/rpmvs.c456
-rw-r--r--lib/rpmvs.h75
-rw-r--r--lib/signature.c586
-rw-r--r--lib/signature.h59
-rw-r--r--lib/tagexts.c186
-rw-r--r--lib/tagname.c247
-rw-r--r--lib/transaction.c579
-rw-r--r--lib/verify.c200
97 files changed, 19105 insertions, 9553 deletions
diff --git a/lib/.gitignore b/lib/.gitignore
deleted file mode 100644
index 1fb7263f8..000000000
--- a/lib/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/tagtbl.C
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 9e725b36d..baf3238ee 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,10 +1,13 @@
# Makefile for rpm library.
include $(top_srcdir)/rpm.am
+AM_CFLAGS = @RPMCFLAGS@
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/include/
+AM_CPPFLAGS += @WITH_BEECRYPT_INCLUDE@
AM_CPPFLAGS += @WITH_NSS_INCLUDE@
AM_CPPFLAGS += @WITH_POPT_INCLUDE@
+AM_CPPFLAGS += $(LMDB_CFLAGS)
AM_CPPFLAGS += -I$(top_srcdir)/misc
AM_CPPFLAGS += -DLOCALEDIR="\"$(localedir)\""
AM_CPPFLAGS += -DSYSCONFDIR="\"$(sysconfdir)\""
@@ -21,7 +24,8 @@ EXTRA_PROGRAMS =
usrlib_LTLIBRARIES = librpm.la
librpm_la_SOURCES = \
- backend/dbconfig.c backend/db3.c backend/dbi.h \
+ backend/db3.c backend/dbi.c backend/dbi.h \
+ backend/dbiset.c backend/dbiset.h \
headerutil.c header.c headerfmt.c header_internal.h \
rpmdb.c rpmdb_internal.h \
fprint.c fprint.h tagname.c rpmtd.c \
@@ -34,17 +38,17 @@ librpm_la_SOURCES = \
rpmlead.c rpmlead.h rpmps.c rpmprob.c rpmrc.c \
rpmte.c rpmte_internal.h rpmts.c rpmfs.h rpmfs.c \
rpmvercmp.c signature.c signature.h transaction.c \
- verify.c rpmlock.c rpmlock.h misc.h \
- rpmscript.h rpmscript.c legacy.c merge.c \
+ verify.c rpmlock.c rpmlock.h misc.h relocation.c \
+ rpmscript.h rpmscript.c \
rpmchroot.c rpmchroot.h \
- rpmplugins.c rpmplugins.h rpmug.c rpmug.h
+ rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \
+ rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h
-librpm_la_LDFLAGS = -version-info 4:0:1
+librpm_la_LDFLAGS = -version-info $(rpm_version_info)
librpm_la_LIBADD = \
$(top_builddir)/rpmio/librpmio.la \
@WITH_POPT_LIB@ \
- @WITH_SELINUX_LIB@ \
@WITH_CAP_LIB@ \
@WITH_ACL_LIB@ \
@LIBINTL@
@@ -61,6 +65,24 @@ else
librpm_la_LIBADD += @WITH_DB_LIB@
endif
+if NDB
+librpm_la_SOURCES += \
+ backend/ndb/glue.c \
+ backend/ndb/rpmpkg.c \
+ backend/ndb/rpmpkg.h \
+ backend/ndb/rpmidx.c \
+ backend/ndb/rpmidx.h \
+ backend/ndb/rpmxdb.c \
+ backend/ndb/rpmxdb.h
+endif
+
+if LMDB
+AM_CPPFLAGS += $(LMDB_CFLAGS)
+librpm_la_LIBADD += $(LMDB_LIBS)
+librpm_la_SOURCES += \
+ backend/lmdb.c
+endif
+
tagtbl.C: Makefile.am $(srcdir)/rpmtag.h gentagtbl.sh
@AWK=${AWK} ${SHELL} $(srcdir)/gentagtbl.sh \
$(srcdir)/rpmtag.h > $@.new && \
diff --git a/lib/backend/db3.c b/lib/backend/db3.c
index a55a608cf..771018467 100644
--- a/lib/backend/db3.c
+++ b/lib/backend/db3.c
@@ -8,6 +8,9 @@ static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
#include <errno.h>
#include <sys/wait.h>
+#include <popt.h>
+#include <db.h>
+#include <signal.h>
#include <rpm/rpmtypes.h>
#include <rpm/rpmmacro.h>
@@ -22,19 +25,80 @@ static const char * _errpfx = "rpmdb";
struct dbiCursor_s {
dbiIndex dbi;
+ const void *key;
+ unsigned int keylen;
+ int flags;
DBC *cursor;
};
+static struct dbiConfig_s staticdbicfg;
+static struct dbConfig_s staticcfg;
+
+/** \ingroup dbi
+ */
+static const struct poptOption rdbOptions[] = {
+ /* Environment options */
+
+ { "cdb", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_INIT_CDB,
+ NULL, NULL },
+ { "lock", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_INIT_LOCK,
+ NULL, NULL },
+ { "log", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_INIT_LOG,
+ NULL, NULL },
+ { "txn", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_INIT_TXN,
+ NULL, NULL },
+ { "recover", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_RECOVER,
+ NULL, NULL },
+ { "recover_fatal", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_RECOVER_FATAL,
+ NULL, NULL },
+ { "lockdown", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_LOCKDOWN,
+ NULL, NULL },
+ { "private", 0,POPT_BIT_SET, &staticcfg.db_eflags, DB_PRIVATE,
+ NULL, NULL },
+
+ { "deadlock", 0,POPT_BIT_SET, &staticcfg.db_verbose, DB_VERB_DEADLOCK,
+ NULL, NULL },
+ { "recovery", 0,POPT_BIT_SET, &staticcfg.db_verbose, DB_VERB_RECOVERY,
+ NULL, NULL },
+ { "waitsfor", 0,POPT_BIT_SET, &staticcfg.db_verbose, DB_VERB_WAITSFOR,
+ NULL, NULL },
+ { "verbose", 0,POPT_ARG_VAL, &staticcfg.db_verbose, -1,
+ NULL, NULL },
+
+ { "cachesize", 0,POPT_ARG_INT, &staticcfg.db_cachesize, 0,
+ NULL, NULL },
+ { "mmapsize", 0,POPT_ARG_INT, &staticcfg.db_mmapsize, 0,
+ NULL, NULL },
+ { "mp_mmapsize", 0,POPT_ARG_INT, &staticcfg.db_mmapsize, 0,
+ NULL, NULL },
+ { "mp_size", 0,POPT_ARG_INT, &staticcfg.db_cachesize, 0,
+ NULL, NULL },
+
+ { "nofsync", 0,POPT_ARG_NONE, &staticcfg.db_no_fsync, 0,
+ NULL, NULL },
+
+ /* Per-dbi options */
+ { "nommap", 0,POPT_BIT_SET, &staticdbicfg.dbi_oflags, DB_NOMMAP,
+ NULL, NULL },
+
+ { "nodbsync", 0,POPT_ARG_NONE, &staticdbicfg.dbi_no_dbsync, 0,
+ NULL, NULL },
+ { "lockdbfd", 0,POPT_ARG_NONE, &staticdbicfg.dbi_lockdbfd, 0,
+ NULL, NULL },
+
+ POPT_TABLEEND
+};
+
+
static int dbapi_err(rpmdb rdb, const char * msg, int error, int printit)
{
if (printit && error) {
- int db_api = rdb->db_ver;
if (msg)
- rpmlog(RPMLOG_ERR, _("db%d error(%d) from %s: %s\n"),
- db_api, error, msg, db_strerror(error));
+ rpmlog(RPMLOG_ERR, _("%s error(%d) from %s: %s\n"),
+ rdb->db_descr, error, msg, db_strerror(error));
else
- rpmlog(RPMLOG_ERR, _("db%d error(%d): %s\n"),
- db_api, error, db_strerror(error));
+ rpmlog(RPMLOG_ERR, _("%s error(%d): %s\n"),
+ rdb->db_descr, error, db_strerror(error));
}
return error;
}
@@ -49,6 +113,11 @@ static void errlog(const DB_ENV * env, const char *errpfx, const char *msg)
rpmlog(RPMLOG_ERR, "%s: %s\n", errpfx, msg);
}
+static void warnlog(const DB_ENV *env, const char *msg)
+{
+ rpmlog(RPMLOG_WARNING, "%s: %s\n", _errpfx, msg);
+}
+
static uint32_t db_envflags(DB * db)
{
DB_ENV * env = db->get_env(db);
@@ -57,10 +126,42 @@ static uint32_t db_envflags(DB * db)
return eflags;
}
+/*
+ * Try to acquire db environment open/close serialization lock.
+ * Return the open, locked fd on success, -1 on failure.
+ */
+static int serialize_env(const char *dbhome)
+{
+ char *lock_path = rstrscat(NULL, dbhome, "/.dbenv.lock", NULL);
+ mode_t oldmask = umask(022);
+ int fd = open(lock_path, (O_RDWR|O_CREAT), 0644);
+ umask(oldmask);
+
+ if (fd >= 0) {
+ int rc;
+ struct flock info;
+ memset(&info, 0, sizeof(info));
+ info.l_type = F_WRLCK;
+ info.l_whence = SEEK_SET;
+ do {
+ rc = fcntl(fd, F_SETLKW, &info);
+ } while (rc == -1 && errno == EINTR);
+
+ if (rc == -1) {
+ close(fd);
+ fd = -1;
+ }
+ }
+
+ free(lock_path);
+ return fd;
+}
+
static int db_fini(rpmdb rdb, const char * dbhome)
{
DB_ENV * dbenv = rdb->db_dbenv;
int rc;
+ int lockfd = -1;
uint32_t eflags = 0;
if (dbenv == NULL)
@@ -72,6 +173,9 @@ static int db_fini(rpmdb rdb, const char * dbhome)
}
(void) dbenv->get_open_flags(dbenv, &eflags);
+ if (!(eflags & DB_PRIVATE))
+ lockfd = serialize_env(dbhome);
+
rc = dbenv->close(dbenv, 0);
rc = dbapi_err(rdb, "dbenv->close", rc, _debug);
@@ -89,6 +193,10 @@ static int db_fini(rpmdb rdb, const char * dbhome)
rpmlog(RPMLOG_DEBUG, "removed db environment %s\n", dbhome);
}
+
+ if (lockfd >= 0)
+ close(lockfd);
+
return rc;
}
@@ -117,18 +225,200 @@ static int isalive(DB_ENV *dbenv, pid_t pid, db_threadid_t tid, uint32_t flags)
return alive;
}
+
+static void dbConfigure(rpmDbiTagVal rpmtag, struct dbConfig_s *cfg, struct dbiConfig_s *dbicfg)
+{
+ char *dbOpts;
+
+ dbOpts = rpmExpand("%{_dbi_config_", rpmTagGetName(rpmtag), "}", NULL);
+
+ if (!(dbOpts && *dbOpts && *dbOpts != '%')) {
+ dbOpts = _free(dbOpts);
+ dbOpts = rpmExpand("%{_dbi_config}", NULL);
+ if (!(dbOpts && *dbOpts && *dbOpts != '%')) {
+ dbOpts = _free(dbOpts);
+ }
+ }
+
+ /* Parse the options for the database element(s). */
+ if (dbOpts && *dbOpts && *dbOpts != '%') {
+ char *o, *oe;
+ char *p, *pe;
+
+ memset(&staticdbicfg, 0, sizeof(staticdbicfg));
+/*=========*/
+ for (o = dbOpts; o && *o; o = oe) {
+ const struct poptOption *opt;
+ const char * tok;
+ unsigned int argInfo;
+
+ /* Skip leading white space. */
+ while (*o && risspace(*o))
+ o++;
+
+ /* Find and terminate next key=value pair. Save next start point. */
+ for (oe = o; oe && *oe; oe++) {
+ if (risspace(*oe))
+ break;
+ if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
+ break;
+ }
+ if (oe && *oe)
+ *oe++ = '\0';
+ if (*o == '\0')
+ continue;
+
+ /* Separate key from value, save value start (if any). */
+ for (pe = o; pe && *pe && *pe != '='; pe++)
+ {};
+ p = (pe ? *pe++ = '\0', pe : NULL);
+
+ /* Skip over negation at start of token. */
+ for (tok = o; *tok == '!'; tok++)
+ {};
+
+ /* Find key in option table. */
+ for (opt = rdbOptions; opt->longName != NULL; opt++) {
+ if (!rstreq(tok, opt->longName))
+ continue;
+ break;
+ }
+ if (opt->longName == NULL) {
+ rpmlog(RPMLOG_ERR,
+ _("unrecognized db option: \"%s\" ignored.\n"), o);
+ continue;
+ }
+
+ /* Toggle the flags for negated tokens, if necessary. */
+ argInfo = opt->argInfo;
+ if (argInfo == POPT_BIT_SET && *o == '!' && ((tok - o) % 2))
+ argInfo = POPT_BIT_CLR;
+
+ /* Save value in template as appropriate. */
+ switch (argInfo & POPT_ARG_MASK) {
+
+ case POPT_ARG_NONE:
+ (void) poptSaveInt((int *)opt->arg, argInfo, 1L);
+ break;
+ case POPT_ARG_VAL:
+ (void) poptSaveInt((int *)opt->arg, argInfo, (long)opt->val);
+ break;
+ case POPT_ARG_STRING:
+ { char ** t = opt->arg;
+ if (t) {
+/* FIX: opt->arg annotation in popt.h */
+ *t = _free(*t);
+ *t = xstrdup( (p ? p : "") );
+ }
+ } break;
+
+ case POPT_ARG_INT:
+ case POPT_ARG_LONG:
+ { long aLong = strtol(p, &pe, 0);
+ if (pe) {
+ if (!rstrncasecmp(pe, "Mb", 2))
+ aLong *= 1024 * 1024;
+ else if (!rstrncasecmp(pe, "Kb", 2))
+ aLong *= 1024;
+ else if (*pe != '\0') {
+ rpmlog(RPMLOG_ERR,
+ _("%s has invalid numeric value, skipped\n"),
+ opt->longName);
+ continue;
+ }
+ }
+
+ if ((argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
+ if (aLong == LONG_MIN || aLong == LONG_MAX) {
+ rpmlog(RPMLOG_ERR,
+ _("%s has too large or too small long value, skipped\n"),
+ opt->longName);
+ continue;
+ }
+ (void) poptSaveLong((long *)opt->arg, argInfo, aLong);
+ break;
+ } else {
+ if (aLong > INT_MAX || aLong < INT_MIN) {
+ rpmlog(RPMLOG_ERR,
+ _("%s has too large or too small integer value, skipped\n"),
+ opt->longName);
+ continue;
+ }
+ (void) poptSaveInt((int *)opt->arg, argInfo, aLong);
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+/*=========*/
+ }
+
+ dbOpts = _free(dbOpts);
+ if (cfg) {
+ *cfg = staticcfg; /* structure assignment */
+ /* Throw in some defaults if configuration didn't set any */
+ if (!cfg->db_mmapsize)
+ cfg->db_mmapsize = 16 * 1024 * 1024;
+ if (!cfg->db_cachesize)
+ cfg->db_cachesize = 8 * 1024 * 1024;
+ }
+ if (dbicfg) {
+ *dbicfg = staticdbicfg;
+ }
+}
+
+static char * prDbiOpenFlags(int dbflags, int print_dbenv_flags)
+{
+ ARGV_t flags = NULL;
+ const struct poptOption *opt;
+ char *buf;
+
+ for (opt = rdbOptions; opt->longName != NULL; opt++) {
+ if (opt->argInfo != POPT_BIT_SET)
+ continue;
+ if (print_dbenv_flags) {
+ if (!(opt->arg == &staticcfg.db_eflags))
+ continue;
+ } else {
+ if (!(opt->arg == &staticdbicfg.dbi_oflags))
+ continue;
+ }
+ if ((dbflags & opt->val) != opt->val)
+ continue;
+ argvAdd(&flags, opt->longName);
+ dbflags &= ~opt->val;
+ }
+ if (dbflags) {
+ char *df = NULL;
+ rasprintf(&df, "0x%x", (unsigned)dbflags);
+ argvAdd(&flags, df);
+ free(df);
+ }
+ buf = argvJoin(flags, ":");
+ argvFree(flags);
+
+ return buf ? buf : xstrdup("(none)");
+}
+
static int db_init(rpmdb rdb, const char * dbhome)
{
DB_ENV *dbenv = NULL;
int rc, xx;
int retry_open = 2;
+ int lockfd = -1;
+ int rdonly = ((rdb->db_mode & O_ACCMODE) == O_RDONLY);
struct dbConfig_s * cfg = &rdb->cfg;
/* This is our setup, thou shall not have other setups before us */
- uint32_t eflags = (DB_CREATE|DB_INIT_MPOOL|DB_INIT_CDB);
+ uint32_t eflags = (DB_CREATE|DB_INIT_MPOOL|DB_INIT_CDB|DB_PRIVATE);
if (rdb->db_dbenv != NULL) {
rdb->db_opens++;
return 0;
+ } else {
+ /* On first call, set backend description to something... */
+ free(rdb->db_descr);
+ rasprintf(&rdb->db_descr, "db%u", DB_VERSION_MAJOR);
}
/*
@@ -150,6 +440,7 @@ static int db_init(rpmdb rdb, const char * dbhome)
dbenv->set_alloc(dbenv, rmalloc, rrealloc, NULL);
dbenv->set_errcall(dbenv, NULL);
dbenv->set_errpfx(dbenv, _errpfx);
+ dbenv->set_msgcall(dbenv, warnlog);
/*
* These enable automatic stale lock removal.
@@ -176,6 +467,24 @@ static int db_init(rpmdb rdb, const char * dbhome)
}
/*
+ * Serialize shared environment open (and clock) via fcntl() lock.
+ * Otherwise we can end up calling dbenv->failchk() while another
+ * process is joining the environment, leading to transient
+ * DB_RUNRECOVER errors. Also prevents races wrt removing the
+ * environment (eg chrooted operation). Silently fall back to
+ * private environment on failure to allow non-privileged queries
+ * to "work", broken as it might be.
+ */
+ if (!(eflags & DB_PRIVATE)) {
+ lockfd = serialize_env(dbhome);
+ if (lockfd < 0 && rdonly) {
+ eflags |= DB_PRIVATE;
+ retry_open--;
+ rpmlog(RPMLOG_DEBUG, "serialize failed, using private dbenv\n");
+ }
+ }
+
+ /*
* Actually open the environment. Fall back to private environment
* if we dont have permission to join/create shared environment or
* system doesn't support it..
@@ -186,7 +495,10 @@ static int db_init(rpmdb rdb, const char * dbhome)
free(fstr);
rc = (dbenv->open)(dbenv, dbhome, eflags, rdb->db_perms);
- if ((rc == EACCES || rc == EROFS || rc == EINVAL) && errno == rc) {
+ if (rc == EINVAL && errno == rc) {
+ eflags |= DB_PRIVATE;
+ retry_open--;
+ } else if (rdonly && (rc == EACCES || rc == EROFS || rc == DB_VERSION_MISMATCH)) {
eflags |= DB_PRIVATE;
retry_open--;
} else {
@@ -208,6 +520,8 @@ static int db_init(rpmdb rdb, const char * dbhome)
rdb->db_dbenv = dbenv;
rdb->db_opens = 1;
+ if (lockfd >= 0)
+ close(lockfd);
return 0;
errxit:
@@ -216,10 +530,12 @@ errxit:
xx = dbenv->close(dbenv, 0);
xx = dbapi_err(rdb, "dbenv->close", xx, _debug);
}
+ if (lockfd >= 0)
+ close(lockfd);
return rc;
}
-void dbSetFSync(void *dbenv, int enable)
+static void db3_dbSetFSync(rpmdb rdb, int enable)
{
#ifdef HAVE_FDATASYNC
db_env_set_func_fsync(enable ? fdatasync : fsync_disable);
@@ -228,19 +544,24 @@ void dbSetFSync(void *dbenv, int enable)
#endif
}
-int dbiSync(dbiIndex dbi, unsigned int flags)
+static int db3_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
+{
+ return 0;
+}
+
+static int dbiSync(dbiIndex dbi, unsigned int flags)
{
DB * db = dbi->dbi_db;
int rc = 0;
- if (db != NULL && !dbi->dbi_no_dbsync) {
+ if (db != NULL && !dbi->cfg.dbi_no_dbsync) {
rc = db->sync(db, flags);
rc = cvtdberr(dbi, "db->sync", rc, _debug);
}
return rc;
}
-dbiCursor dbiCursorInit(dbiIndex dbi, unsigned int flags)
+static dbiCursor db3_dbiCursorInit(dbiIndex dbi, unsigned int flags)
{
dbiCursor dbc = NULL;
@@ -248,33 +569,52 @@ dbiCursor dbiCursorInit(dbiIndex dbi, unsigned int flags)
DB * db = dbi->dbi_db;
DBC * cursor;
int cflags;
- int rc;
+ int rc = 0;
uint32_t eflags = db_envflags(db);
/* DB_WRITECURSOR requires CDB and writable db */
- if ((flags & DB_WRITECURSOR) &&
- (eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
+ if ((flags & DBC_WRITE) &&
+ (eflags & DB_INIT_CDB) && !(dbi->dbi_flags & DBI_RDONLY))
{
cflags = DB_WRITECURSOR;
} else
cflags = 0;
- rc = db->cursor(db, NULL, &cursor, cflags);
- rc = cvtdberr(dbi, "db->cursor", rc, _debug);
+ /*
+ * Check for stale locks which could block writes "forever".
+ * XXX: Should we also do this on reads? Reads are less likely
+ * to get blocked so it seems excessive...
+ * XXX: On DB_RUNRECOVER, we should abort everything. Now
+ * we'll just fail to open a cursor again and again and again.
+ */
+ if (cflags & DB_WRITECURSOR) {
+ DB_ENV *dbenv = db->get_env(db);
+ rc = dbenv->failchk(dbenv, 0);
+ rc = cvtdberr(dbi, "dbenv->failchk", rc, _debug);
+ }
+
+ if (rc == 0) {
+ rc = db->cursor(db, NULL, &cursor, cflags);
+ rc = cvtdberr(dbi, "db->cursor", rc, _debug);
+ }
if (rc == 0) {
dbc = xcalloc(1, sizeof(*dbc));
dbc->cursor = cursor;
dbc->dbi = dbi;
+ dbc->flags = flags;
}
}
return dbc;
}
-dbiCursor dbiCursorFree(dbiCursor dbc)
+static dbiCursor db3_dbiCursorFree(dbiIndex dbi, dbiCursor dbc)
{
if (dbc) {
+ /* Automatically sync on write-cursor close */
+ if (dbc->flags & DBC_WRITE)
+ dbiSync(dbc->dbi, 0);
DBC * cursor = dbc->cursor;
int rc = cursor->c_close(cursor);
cvtdberr(dbc->dbi, "dbcursor->c_close", rc, _debug);
@@ -283,7 +623,7 @@ dbiCursor dbiCursorFree(dbiCursor dbc)
return NULL;
}
-int dbiCursorPut(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
+static int dbiCursorPut(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
{
int rc = EINVAL;
int sane = (key->data != NULL && key->size > 0 &&
@@ -302,7 +642,7 @@ int dbiCursorPut(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
return rc;
}
-int dbiCursorGet(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
+static int dbiCursorGet(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
{
int rc = EINVAL;
int sane = ((flags == DB_NEXT) || (key->data != NULL && key->size > 0));
@@ -319,12 +659,21 @@ int dbiCursorGet(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
_printit = (rc == DB_NOTFOUND ? 0 : _debug);
rc = cvtdberr(dbc->dbi, "dbcursor->c_get", rc, _printit);
+ /* Remember the last key fetched */
+ if (rc == 0) {
+ dbc->key = key->data;
+ dbc->keylen = key->size;
+ } else {
+ dbc->key = NULL;
+ dbc->keylen = 0;
+ }
+
rpmswExit(&rdb->db_getops, data->size);
}
return rc;
}
-int dbiCursorDel(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
+static int dbiCursorDel(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
{
int rc = EINVAL;
int sane = (key->data != NULL && key->size > 0);
@@ -350,23 +699,7 @@ int dbiCursorDel(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
return rc;
}
-unsigned int dbiCursorCount(dbiCursor dbc)
-{
- db_recno_t count = 0;
- if (dbc) {
- DBC * cursor = dbc->cursor;
- int rc = cursor->c_count(cursor, &count, 0);
- cvtdberr(dbc->dbi, "dbcursor->c_count", rc, _debug);
- }
- return count;
-}
-
-dbiIndex dbiCursorIndex(dbiCursor dbc)
-{
- return (dbc != NULL) ? dbc->dbi : NULL;
-}
-
-int dbiByteSwapped(dbiIndex dbi)
+static int dbiByteSwapped(dbiIndex dbi)
{
DB * db = dbi->dbi_db;
int rc = 0;
@@ -383,32 +716,7 @@ int dbiByteSwapped(dbiIndex dbi)
return rc;
}
-dbiIndexType dbiType(dbiIndex dbi)
-{
- return dbi->dbi_type;
-}
-
-int dbiFlags(dbiIndex dbi)
-{
- DB *db = dbi->dbi_db;
- int flags = DBI_NONE;
- uint32_t oflags = 0;
-
- if (db && db->get_open_flags(db, &oflags) == 0) {
- if (oflags & DB_CREATE)
- flags |= DBI_CREATED;
- if (oflags & DB_RDONLY)
- flags |= DBI_RDONLY;
- }
- return flags;
-}
-
-const char * dbiName(dbiIndex dbi)
-{
- return dbi->dbi_file;
-}
-
-int dbiVerify(dbiIndex dbi, unsigned int flags)
+static int db3_dbiVerify(dbiIndex dbi, unsigned int flags)
{
int rc = 0;
@@ -426,9 +734,7 @@ int dbiVerify(dbiIndex dbi, unsigned int flags)
return rc;
}
-static int _lockdbfd = 0;
-
-int dbiClose(dbiIndex dbi, unsigned int flags)
+static int db3_dbiClose(dbiIndex dbi, unsigned int flags)
{
rpmdb rdb = dbi->dbi_rpmdb;
const char * dbhome = rpmdbHome(rdb);
@@ -445,8 +751,6 @@ int dbiClose(dbiIndex dbi, unsigned int flags)
rpmlog(RPMLOG_DEBUG, "closed db index %s/%s\n",
dbhome, dbi->dbi_file);
- if (dbi->dbi_lockdbfd && _lockdbfd)
- _lockdbfd--;
}
db_fini(rdb, dbhome ? dbhome : "");
@@ -486,7 +790,6 @@ static int dbiFlock(dbiIndex dbi, int mode)
rc = 1;
} else {
const char *dbhome = rpmdbHome(dbi->dbi_rpmdb);
- int tries;
struct flock l;
memset(&l, 0, sizeof(l));
l.l_whence = 0;
@@ -496,44 +799,26 @@ static int dbiFlock(dbiIndex dbi, int mode)
? F_RDLCK : F_WRLCK;
l.l_pid = 0;
- for (tries = 0; ; tries++) {
- rc = fcntl(fdno, F_SETLK, (void *) &l);
- if (rc) {
- uint32_t eflags = db_envflags(db);
- /* Warning iff using non-private CDB locking. */
- rc = (((eflags & DB_INIT_CDB) && !(eflags & DB_PRIVATE)) ? 0 : 1);
- if (errno == EAGAIN && rc) {
- struct timespec ts;
- if (tries == 0)
- rpmlog(RPMLOG_WARNING,
- _("waiting for %s lock on %s/%s\n"),
- ((mode & O_ACCMODE) == O_RDONLY)
- ? _("shared") : _("exclusive"),
- dbhome, dbi->dbi_file);
- ts.tv_sec = (time_t)0;
- ts.tv_nsec = 100000000; /* .1 seconds */
- if (tries < 10*60*3) { /* 3 minutes */
- nanosleep(&ts, (struct timespec *)0);
- continue;
- }
- }
- rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING),
- _("cannot get %s lock on %s/%s\n"),
- ((mode & O_ACCMODE) == O_RDONLY)
- ? _("shared") : _("exclusive"),
- dbhome, dbi->dbi_file);
- } else {
- rpmlog(RPMLOG_DEBUG,
- "locked db index %s/%s\n",
- dbhome, dbi->dbi_file);
- }
- break;
+ rc = fcntl(fdno, F_SETLK, (void *) &l);
+ if (rc) {
+ uint32_t eflags = db_envflags(db);
+ /* Warning iff using non-private CDB locking. */
+ rc = (((eflags & DB_INIT_CDB) && !(eflags & DB_PRIVATE)) ? 0 : 1);
+ rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING),
+ _("cannot get %s lock on %s/%s\n"),
+ ((mode & O_ACCMODE) == O_RDONLY)
+ ? _("shared") : _("exclusive"),
+ dbhome, dbi->dbi_file);
+ } else {
+ rpmlog(RPMLOG_DEBUG,
+ "locked db index %s/%s\n",
+ dbhome, dbi->dbi_file);
}
}
return rc;
}
-int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
+static int db3_dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
{
const char *dbhome = rpmdbHome(rdb);
dbiIndex dbi = NULL;
@@ -544,22 +829,25 @@ int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
DB * db = NULL;
DBTYPE dbtype = DB_UNKNOWN;
uint32_t oflags;
+ static int _lockdbfd = 0;
if (dbip)
*dbip = NULL;
- /*
- * Parse db configuration parameters.
- */
if ((dbi = dbiNew(rdb, rpmtag)) == NULL)
return 1;
- oflags = dbi->dbi_oflags;
+ /*
+ * Parse db configuration parameters.
+ */
+ dbConfigure(rpmtag, rdb->db_dbenv == NULL ? &rdb->cfg : NULL, &dbi->cfg);
/*
* Map open mode flags onto configured database/environment flags.
*/
- if ((rdb->db_mode & O_ACCMODE) == O_RDONLY) oflags |= DB_RDONLY;
+ oflags = dbi->cfg.dbi_oflags;
+ if ((rdb->db_mode & O_ACCMODE) == O_RDONLY)
+ oflags |= DB_RDONLY;
rc = db_init(rdb, dbhome);
@@ -587,7 +875,7 @@ int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
if (rc == ENOENT) {
oflags |= DB_CREATE;
oflags &= ~DB_RDONLY;
- dbtype = (dbiType(dbi) == DBI_PRIMARY) ? DB_HASH : DB_BTREE;
+ dbtype = (rpmtag == RPMDBI_PACKAGES) ? DB_HASH : DB_BTREE;
retry_open--;
} else {
retry_open = 0;
@@ -615,12 +903,14 @@ int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
}
dbi->dbi_db = db;
- dbi->dbi_oflags = oflags;
- if (verifyonly)
- dbi->dbi_lockdbfd = 0; /* disable locking in verify mode */
+ dbi->dbi_flags = 0;
+ if (oflags & DB_CREATE)
+ dbi->dbi_flags |= DBI_CREATED;
+ if (oflags & DB_RDONLY)
+ dbi->dbi_flags |= DBI_RDONLY;
- if (rc == 0 && dbi->dbi_lockdbfd && _lockdbfd++ == 0) {
+ if (!verifyonly && rc == 0 && dbi->cfg.dbi_lockdbfd && _lockdbfd++ == 0) {
rc = dbiFlock(dbi, rdb->db_mode);
}
@@ -633,58 +923,456 @@ int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
return rc;
}
-int dbiSuspendDBLock(dbiIndex dbi, unsigned int flags)
+/**
+ * Convert retrieved data to index set.
+ * @param dbi index database handle
+ * @param data retrieved data
+ * @retval setp (malloc'ed) index set
+ * @return 0 on success
+ */
+static int dbt2set(dbiIndex dbi, DBT * data, dbiIndexSet * setp)
{
- struct flock l;
- int rc = 0;
- int fdno = -1;
+ int _dbbyteswapped = dbiByteSwapped(dbi);
+ const char * sdbir;
+ dbiIndexSet set;
+ unsigned int i;
- if (!dbi->dbi_lockdbfd)
- return 0;
- if (!(dbi->dbi_rpmdb->db_mode & (O_RDWR|O_WRONLY)))
+ if (dbi == NULL || data == NULL || setp == NULL)
+ return -1;
+
+ if ((sdbir = data->data) == NULL) {
+ *setp = NULL;
return 0;
- if (_lockdbfd == 0)
+ }
+
+ set = dbiIndexSetNew(data->size / (2 * sizeof(int32_t)));
+ set->count = data->size / (2 * sizeof(int32_t));
+
+ for (i = 0; i < set->count; i++) {
+ union _dbswap hdrNum, tagNum;
+
+ memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
+ sdbir += sizeof(hdrNum.ui);
+ memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
+ sdbir += sizeof(tagNum.ui);
+ if (_dbbyteswapped) {
+ _DBSWAP(hdrNum);
+ _DBSWAP(tagNum);
+ }
+ set->recs[i].hdrNum = hdrNum.ui;
+ set->recs[i].tagNum = tagNum.ui;
+ }
+ *setp = set;
+ return 0;
+}
+
+/**
+ * Convert index set to database representation.
+ * @param dbi index database handle
+ * @param data retrieved data
+ * @param set index set
+ * @return 0 on success
+ */
+static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
+{
+ int _dbbyteswapped = dbiByteSwapped(dbi);
+ char * tdbir;
+ unsigned int i;
+
+ if (dbi == NULL || data == NULL || set == NULL)
+ return -1;
+
+ data->size = set->count * (2 * sizeof(int32_t));
+ if (data->size == 0) {
+ data->data = NULL;
return 0;
- if (!(dbi->dbi_db->fd(dbi->dbi_db, &fdno) == 0 && fdno >= 0))
- return 1;
- memset(&l, 0, sizeof(l));
- l.l_whence = 0;
- l.l_start = 0;
- l.l_len = 0;
- l.l_type = F_RDLCK;
- rc = fcntl(fdno, F_SETLK, (void *)&l);
+ }
+ tdbir = data->data = xmalloc(data->size);
+
+ for (i = 0; i < set->count; i++) {
+ union _dbswap hdrNum, tagNum;
+
+ memset(&hdrNum, 0, sizeof(hdrNum));
+ memset(&tagNum, 0, sizeof(tagNum));
+ hdrNum.ui = set->recs[i].hdrNum;
+ tagNum.ui = set->recs[i].tagNum;
+ if (_dbbyteswapped) {
+ _DBSWAP(hdrNum);
+ _DBSWAP(tagNum);
+ }
+ memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
+ tdbir += sizeof(hdrNum.ui);
+ memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
+ tdbir += sizeof(tagNum.ui);
+ }
+ return 0;
+}
+
+static rpmRC db3_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexSet *set, int searchType)
+{
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ if (dbi != NULL && dbc != NULL && set != NULL) {
+ int cflags = DB_NEXT;
+ int dbrc;
+ DBT data, key;
+ memset(&data, 0, sizeof(data));
+ memset(&key, 0, sizeof(key));
+
+ if (keyp) {
+ if (keylen == 0) { /* XXX "/" fixup */
+ keyp = "";
+ keylen = 1;
+ }
+ key.data = (void *) keyp; /* discards const */
+ key.size = keylen;
+ cflags = searchType == DBC_PREFIX_SEARCH ? DB_SET_RANGE : DB_SET;
+ }
+
+ for (;;) {
+ dbiIndexSet newset = NULL;
+ dbrc = dbiCursorGet(dbc, &key, &data, cflags);
+ if (dbrc != 0)
+ break;
+ if (searchType == DBC_PREFIX_SEARCH &&
+ (key.size < keylen || memcmp(key.data, keyp, keylen) != 0))
+ break;
+ dbt2set(dbi, &data, &newset);
+ if (*set == NULL) {
+ *set = newset;
+ } else {
+ dbiIndexSetAppendSet(*set, newset, 0);
+ dbiIndexSetFree(newset);
+ }
+ if (searchType != DBC_PREFIX_SEARCH)
+ break;
+ key.data = NULL;
+ key.size = 0;
+ cflags = DB_NEXT;
+ }
+
+ /* fixup result status for prefix search */
+ if (searchType == DBC_PREFIX_SEARCH) {
+ if (dbrc == DB_NOTFOUND && *set != NULL && (*set)->count > 0)
+ dbrc = 0;
+ else if (dbrc == 0 && (*set == NULL || (*set)->count == 0))
+ dbrc = DB_NOTFOUND;
+ }
+
+ if (dbrc == 0) {
+ rc = RPMRC_OK;
+ } else if (dbrc == DB_NOTFOUND) {
+ rc = RPMRC_NOTFOUND;
+ } else {
+ rpmlog(RPMLOG_ERR,
+ _("error(%d) getting \"%s\" records from %s index: %s\n"),
+ dbrc, keyp ? keyp : "???", dbiName(dbi), db_strerror(dbrc));
+ }
+ }
+ return rc;
+}
+
+/* Update secondary index. NULL set deletes the key */
+static rpmRC updateIndex(dbiCursor dbc, const char *keyp, unsigned int keylen,
+ dbiIndexSet set)
+{
+ rpmRC rc = RPMRC_FAIL;
+
+ if (dbc && keyp) {
+ dbiIndex dbi = dbc->dbi;
+ int dbrc;
+ DBT data, key;
+ memset(&key, 0, sizeof(data));
+ memset(&data, 0, sizeof(data));
+
+ key.data = (void *) keyp; /* discards const */
+ key.size = keylen;
+
+ if (set)
+ set2dbt(dbi, &data, set);
+
+ if (dbiIndexSetCount(set) > 0) {
+ dbrc = dbiCursorPut(dbc, &key, &data, DB_KEYLAST);
+ if (dbrc) {
+ rpmlog(RPMLOG_ERR,
+ _("error(%d) storing record \"%s\" into %s\n"),
+ dbrc, (char*)key.data, dbiName(dbi));
+ }
+ free(data.data);
+ } else {
+ dbrc = dbiCursorDel(dbc, &key, &data, 0);
+ if (dbrc) {
+ rpmlog(RPMLOG_ERR,
+ _("error(%d) removing record \"%s\" from %s\n"),
+ dbrc, (char*)key.data, dbiName(dbi));
+ }
+ }
+
+ if (dbrc == 0)
+ rc = RPMRC_OK;
+ }
+
+ return rc;
+}
+
+static rpmRC db3_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexItem rec)
+{
+ dbiIndexSet set = NULL;
+ rpmRC rc;
+
+ if (keyp && keylen == 0) { /* XXX "/" fixup */
+ keyp = "";
+ keylen++;
+ }
+ rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
+
+ /* Not found means a new key and is not an error. */
+ if (rc && rc != RPMRC_NOTFOUND)
+ return rc;
+
+ if (set == NULL)
+ set = dbiIndexSetNew(1);
+ dbiIndexSetAppend(set, rec, 1, 0);
+
+ rc = updateIndex(dbc, keyp, keylen, set);
+
+ dbiIndexSetFree(set);
+ return rc;
+}
+
+static rpmRC db3_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexItem rec)
+{
+ dbiIndexSet set = NULL;
+ rpmRC rc;
+
+ if (keyp && keylen == 0) { /* XXX "/" fixup */
+ keyp = "";
+ keylen++;
+ }
+ rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
if (rc)
- rpmlog(RPMLOG_WARNING, _("could not suspend database lock\n"));
+ return rc;
+
+ if (dbiIndexSetPrune(set, rec, 1, 1)) {
+ /* Nothing was pruned. XXX: Can this actually happen? */
+ rc = RPMRC_OK;
+ } else {
+ /* If there's data left, update data. Otherwise delete the key. */
+ if (dbiIndexSetCount(set) > 0) {
+ rc = updateIndex(dbc, keyp, keylen, set);
+ } else {
+ rc = updateIndex(dbc, keyp, keylen, NULL);
+ }
+ };
+ dbiIndexSetFree(set);
+
return rc;
}
-int dbiResumeDBLock(dbiIndex dbi, unsigned int flags)
+static const void * db3_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
{
- struct flock l;
+ const void *key = NULL;
+ if (dbc) {
+ key = dbc->key;
+ if (key && keylen)
+ *keylen = dbc->keylen;
+ }
+ return key;
+}
+
+
+/* Update primary Packages index. NULL hdr means remove */
+static rpmRC updatePackages(dbiCursor dbc, unsigned int hdrNum, DBT *hdr)
+{
+ union _dbswap mi_offset;
int rc = 0;
- int tries;
- int fdno = -1;
+ DBT key;
- if (!dbi->dbi_lockdbfd)
- return 0;
- if (!(dbi->dbi_rpmdb->db_mode & (O_RDWR|O_WRONLY)))
- return 0;
- if (_lockdbfd == 0)
- return 0;
- if (!(dbi->dbi_db->fd(dbi->dbi_db, &fdno) == 0 && fdno >= 0))
- return 1;
- for (tries = 0; tries < 2; tries++) {
- memset(&l, 0, sizeof(l));
- l.l_whence = 0;
- l.l_start = 0;
- l.l_len = 0;
- l.l_type = F_WRLCK;
- rc = fcntl(fdno, tries ? F_SETLKW : F_SETLK, (void *)&l);
- if (!rc)
- break;
- if (tries == 0)
- rpmlog(RPMLOG_WARNING, _("waiting to reestablish exclusive database lock\n"));
+ if (dbc == NULL || hdrNum == 0)
+ return RPMRC_FAIL;
+
+ memset(&key, 0, sizeof(key));
+
+ mi_offset.ui = hdrNum;
+ if (dbiByteSwapped(dbc->dbi) == 1)
+ _DBSWAP(mi_offset);
+ key.data = (void *) &mi_offset;
+ key.size = sizeof(mi_offset.ui);
+
+ if (hdr) {
+ rc = dbiCursorPut(dbc, &key, hdr, DB_KEYLAST);
+ if (rc) {
+ rpmlog(RPMLOG_ERR,
+ _("error(%d) adding header #%d record\n"), rc, hdrNum);
+ }
+ } else {
+ DBT data;
+
+ memset(&data, 0, sizeof(data));
+ rc = dbiCursorGet(dbc, &key, &data, DB_SET);
+ if (rc) {
+ rpmlog(RPMLOG_ERR,
+ _("error(%d) removing header #%d record\n"), rc, hdrNum);
+ } else
+ rc = dbiCursorDel(dbc, &key, &data, 0);
}
- return rc;
+
+ return rc == 0 ? RPMRC_OK : RPMRC_FAIL;
}
+/* Get current header instance number or try to allocate a new one */
+static unsigned int pkgInstance(dbiIndex dbi, int alloc)
+{
+ unsigned int hdrNum = 0;
+
+ if (dbi != NULL && dbi->dbi_type == DBI_PRIMARY) {
+ dbiCursor dbc;
+ DBT key, data;
+ unsigned int firstkey = 0;
+ union _dbswap mi_offset;
+ int ret;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ dbc = dbiCursorInit(dbi, alloc ? DBC_WRITE : 0);
+
+ /* Key 0 holds the current largest instance, fetch it */
+ key.data = &firstkey;
+ key.size = sizeof(firstkey);
+ ret = dbiCursorGet(dbc, &key, &data, DB_SET);
+
+ if (ret == 0 && data.data) {
+ memcpy(&mi_offset, data.data, sizeof(mi_offset.ui));
+ if (dbiByteSwapped(dbi) == 1)
+ _DBSWAP(mi_offset);
+ hdrNum = mi_offset.ui;
+ }
+
+ if (alloc) {
+ /* Rather complicated "increment by one", bswapping as needed */
+ ++hdrNum;
+ mi_offset.ui = hdrNum;
+ if (dbiByteSwapped(dbi) == 1)
+ _DBSWAP(mi_offset);
+ if (ret == 0 && data.data) {
+ memcpy(data.data, &mi_offset, sizeof(mi_offset.ui));
+ } else {
+ data.data = &mi_offset;
+ data.size = sizeof(mi_offset.ui);
+ }
+
+ /* Unless we manage to insert the new instance number, we failed */
+ ret = dbiCursorPut(dbc, &key, &data, DB_KEYLAST);
+ if (ret) {
+ hdrNum = 0;
+ rpmlog(RPMLOG_ERR,
+ _("error(%d) allocating new package instance\n"), ret);
+ }
+ }
+ dbiCursorFree(dbi, dbc);
+ }
+
+ return hdrNum;
+}
+
+static rpmRC db3_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
+ unsigned char *hdrBlob, unsigned int hdrLen)
+{
+ DBT hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.data = hdrBlob;
+ hdr.size = hdrLen;
+ return updatePackages(dbc, hdrNum, &hdr);
+}
+
+static rpmRC db3_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
+{
+ return updatePackages(dbc, hdrNum, NULL);
+}
+
+static rpmRC db3_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
+ unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ DBT key, data;
+ union _dbswap mi_offset;
+ int rc;
+
+ if (dbc == NULL)
+ return RPMRC_FAIL;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ if (hdrNum) {
+ mi_offset.ui = hdrNum;
+ if (dbiByteSwapped(dbc->dbi) == 1)
+ _DBSWAP(mi_offset);
+ key.data = (void *) &mi_offset;
+ key.size = sizeof(mi_offset.ui);
+ }
+
+#if !defined(_USE_COPY_LOAD)
+ data.flags |= DB_DBT_MALLOC;
+#endif
+ rc = dbiCursorGet(dbc, &key, &data, hdrNum ? DB_SET : DB_NEXT);
+ if (rc == 0) {
+ if (hdrBlob)
+ *hdrBlob = data.data;
+ if (hdrLen)
+ *hdrLen = data.size;
+ return RPMRC_OK;
+ } else if (rc == DB_NOTFOUND)
+ return RPMRC_NOTFOUND;
+ else
+ return RPMRC_FAIL;
+}
+
+static unsigned int db3_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
+{
+ union _dbswap mi_offset;
+
+ if (dbc == NULL || dbc->key == NULL)
+ return 0;
+ memcpy(&mi_offset, dbc->key, sizeof(mi_offset.ui));
+ if (dbiByteSwapped(dbc->dbi) == 1)
+ _DBSWAP(mi_offset);
+ return mi_offset.ui;
+}
+
+static rpmRC db3_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum)
+{
+ unsigned int num;
+ if (dbc == NULL)
+ return RPMRC_FAIL;
+ num = pkgInstance(dbc->dbi, 1);
+ if (!num)
+ return RPMRC_FAIL;
+ *hdrNum = num;
+ return RPMRC_OK;
+}
+
+struct rpmdbOps_s db3_dbops = {
+ .open = db3_dbiOpen,
+ .close = db3_dbiClose,
+ .verify = db3_dbiVerify,
+
+ .setFSync = db3_dbSetFSync,
+ .ctrl = db3_Ctrl,
+
+ .cursorInit = db3_dbiCursorInit,
+ .cursorFree = db3_dbiCursorFree,
+
+ .pkgdbGet = db3_pkgdbGet,
+ .pkgdbPut = db3_pkgdbPut,
+ .pkgdbDel = db3_pkgdbDel,
+ .pkgdbNew = db3_pkgdbNew,
+ .pkgdbKey = db3_pkgdbKey,
+
+ .idxdbGet = db3_idxdbGet,
+ .idxdbPut = db3_idxdbPut,
+ .idxdbDel = db3_idxdbDel,
+ .idxdbKey = db3_idxdbKey
+};
diff --git a/lib/backend/dbconfig.c b/lib/backend/dbconfig.c
index 446be13f9..fe7c01e81 100644
--- a/lib/backend/dbconfig.c
+++ b/lib/backend/dbconfig.c
@@ -71,10 +71,8 @@ static const struct poptOption rdbOptions[] = {
NULL, NULL },
{ "lockdbfd", 0,POPT_ARG_NONE, &staticdbi.dbi_lockdbfd, 0,
NULL, NULL },
-#ifndef WITH_EXTERNAL_DB
{ "nofsync", 0,POPT_BIT_SET, &staticdbi.dbi_oflags, DB_NOFSYNC,
NULL, NULL },
-#endif
POPT_TABLEEND
};
diff --git a/lib/backend/dbi.c b/lib/backend/dbi.c
new file mode 100644
index 000000000..e99a5f2b2
--- /dev/null
+++ b/lib/backend/dbi.c
@@ -0,0 +1,184 @@
+/** \ingroup rpmdb
+ * \file lib/dbi.c
+ */
+
+#include "system.h"
+
+#include <stdlib.h>
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmstring.h>
+#include <rpm/rpmmacro.h>
+#include <rpm/rpmlog.h>
+#include "lib/rpmdb_internal.h"
+#include "debug.h"
+
+
+dbiIndex dbiFree(dbiIndex dbi)
+{
+ if (dbi) {
+ free(dbi);
+ }
+ return NULL;
+}
+
+dbiIndex dbiNew(rpmdb rdb, rpmDbiTagVal rpmtag)
+{
+ dbiIndex dbi = xcalloc(1, sizeof(*dbi));
+ /* FIX: figger lib/dbi refcounts */
+ dbi->dbi_rpmdb = rdb;
+ dbi->dbi_file = rpmTagGetName(rpmtag);
+ dbi->dbi_type = (rpmtag == RPMDBI_PACKAGES) ? DBI_PRIMARY : DBI_SECONDARY;
+ dbi->dbi_byteswapped = -1; /* -1 unknown, 0 native order, 1 alien order */
+ return dbi;
+}
+
+static void
+dbDetectBackend(rpmdb rdb)
+{
+ const char *dbhome = rpmdbHome(rdb);
+ char *db_backend = rpmExpand("%{?_db_backend}", NULL);
+ char *path = NULL;
+
+#if defined(WITH_LMDB)
+ if (!strcmp(db_backend, "lmdb")) {
+ rdb->db_ops = &lmdb_dbops;
+ } else
+#endif
+#ifdef ENABLE_NDB
+ if (!strcmp(db_backend, "ndb")) {
+ rdb->db_ops = &ndb_dbops;
+ } else
+#endif
+ {
+ rdb->db_ops = &db3_dbops;
+ if (*db_backend == '\0') {
+ free(db_backend);
+ db_backend = xstrdup("bdb");
+ }
+ }
+
+#if defined(WITH_LMDB)
+ path = rstrscat(NULL, dbhome, "/data.mdb", NULL);
+ if (access(path, F_OK) == 0 && rdb->db_ops != &lmdb_dbops) {
+ rdb->db_ops = &lmdb_dbops;
+ rpmlog(RPMLOG_WARNING, _("Found LMDB data.mdb database while attempting %s backend: using lmdb backend.\n"), db_backend);
+ }
+ free(path);
+#endif
+
+#ifdef ENABLE_NDB
+ path = rstrscat(NULL, dbhome, "/Packages.db", NULL);
+ if (access(path, F_OK) == 0 && rdb->db_ops != &ndb_dbops) {
+ rdb->db_ops = &ndb_dbops;
+ rpmlog(RPMLOG_WARNING, _("Found NDB Packages.db database while attempting %s backend: using ndb backend.\n"), db_backend);
+ }
+ free(path);
+#endif
+
+ path = rstrscat(NULL, dbhome, "/Packages", NULL);
+ if (access(path, F_OK) == 0 && rdb->db_ops != &db3_dbops) {
+ rdb->db_ops = &db3_dbops;
+ rpmlog(RPMLOG_WARNING, _("Found BDB Packages database while attempting %s backend: using bdb backend.\n"), db_backend);
+ }
+ free(path);
+
+ if (db_backend)
+ free(db_backend);
+}
+
+const char * dbiName(dbiIndex dbi)
+{
+ return dbi->dbi_file;
+}
+
+int dbiFlags(dbiIndex dbi)
+{
+ return dbi->dbi_flags;
+}
+
+void dbSetFSync(rpmdb rdb, int enable)
+{
+ if (!rdb->db_ops)
+ dbDetectBackend(rdb);
+ rdb->db_ops->setFSync(rdb, enable);
+}
+
+int dbCtrl(rpmdb rdb, dbCtrlOp ctrl)
+{
+ if (!rdb->db_ops)
+ dbDetectBackend(rdb);
+ return rdb->db_ops->ctrl(rdb, ctrl);
+}
+
+int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
+{
+ if (!rdb->db_ops)
+ dbDetectBackend(rdb);
+ return rdb->db_ops->open(rdb, rpmtag, dbip, flags);
+}
+
+int dbiClose(dbiIndex dbi, unsigned int flags)
+{
+ return dbi ? dbi->dbi_rpmdb->db_ops->close(dbi, flags) : 0;
+}
+
+int dbiVerify(dbiIndex dbi, unsigned int flags)
+{
+ return dbi->dbi_rpmdb->db_ops->verify(dbi, flags);
+}
+
+dbiCursor dbiCursorInit(dbiIndex dbi, unsigned int flags)
+{
+ return dbi->dbi_rpmdb->db_ops->cursorInit(dbi, flags);
+}
+
+dbiCursor dbiCursorFree(dbiIndex dbi, dbiCursor dbc)
+{
+ return dbi->dbi_rpmdb->db_ops->cursorFree(dbi, dbc);
+}
+
+rpmRC pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen)
+{
+ return dbi->dbi_rpmdb->db_ops->pkgdbPut(dbi, dbc, hdrNum, hdrBlob, hdrLen);
+}
+
+rpmRC pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
+{
+ return dbi->dbi_rpmdb->db_ops->pkgdbDel(dbi, dbc, hdrNum);
+}
+
+rpmRC pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ return dbi->dbi_rpmdb->db_ops->pkgdbGet(dbi, dbc, hdrNum, hdrBlob, hdrLen);
+}
+
+rpmRC pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum)
+{
+ return dbi->dbi_rpmdb->db_ops->pkgdbNew(dbi, dbc, hdrNum);
+}
+
+unsigned int pkgdbKey(dbiIndex dbi, dbiCursor dbc)
+{
+ return dbi->dbi_rpmdb->db_ops->pkgdbKey(dbi, dbc);
+}
+
+rpmRC idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int curFlags)
+{
+ return dbi->dbi_rpmdb->db_ops->idxdbGet(dbi, dbc, keyp, keylen, set, curFlags);
+}
+
+rpmRC idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
+{
+ return dbi->dbi_rpmdb->db_ops->idxdbPut(dbi, dbc, keyp, keylen, rec);
+}
+
+rpmRC idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
+{
+ return dbi->dbi_rpmdb->db_ops->idxdbDel(dbi, dbc, keyp, keylen, rec);
+}
+
+const void * idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
+{
+ return dbi->dbi_rpmdb->db_ops->idxdbKey(dbi, dbc, keylen);
+}
+
diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h
index 3d848a8a0..1833da263 100644
--- a/lib/backend/dbi.h
+++ b/lib/backend/dbi.h
@@ -1,12 +1,25 @@
#ifndef _DBI_H
#define _DBI_H
+#include "dbiset.h"
+
+/* XXX: make this backend-specific, eliminate or something... */
+#define _USE_COPY_LOAD
+
enum rpmdbFlags {
RPMDB_FLAG_JUSTCHECK = (1 << 0),
RPMDB_FLAG_REBUILD = (1 << 1),
RPMDB_FLAG_VERIFYONLY = (1 << 2),
};
+typedef enum dbCtrlOp_e {
+ DB_CTRL_LOCK_RO = 1,
+ DB_CTRL_UNLOCK_RO = 2,
+ DB_CTRL_LOCK_RW = 3,
+ DB_CTRL_UNLOCK_RW = 4,
+ DB_CTRL_INDEXSYNC = 5
+} dbCtrlOp;
+
typedef struct dbiIndex_s * dbiIndex;
typedef struct dbiCursor_s * dbiCursor;
@@ -15,8 +28,17 @@ struct dbConfig_s {
int db_cachesize; /*!< (128Kb) */
int db_verbose;
int db_no_fsync; /*!< no-op fsync for db */
+ int db_eflags; /*!< obsolete */
+};
+
+struct dbiConfig_s {
+ int dbi_oflags; /*!< open flags */
+ int dbi_no_dbsync; /*!< don't call dbiSync */
+ int dbi_lockdbfd; /*!< do fcntl lock on db fd */
};
+struct rpmdbOps_s;
+
/** \ingroup rpmdb
* Describes the collection of index databases used by rpm.
*/
@@ -27,16 +49,20 @@ struct rpmdb_s {
int db_flags;
int db_mode; /*!< open mode */
int db_perms; /*!< open permissions */
- int db_ver; /*!< Berkeley DB version */
+ char * db_descr; /*!< db backend description (for error msgs) */
struct dbChk_s * db_checked;/*!< headerCheck()'ed package instances */
rpmdb db_next;
int db_opens;
+ dbiIndex db_pkgs; /*!< Package db */
+ const rpmDbiTag * db_tags;
int db_ndbi; /*!< No. of tag indices. */
- dbiIndex * _dbi; /*!< Tag indices. */
+ dbiIndex * db_indexes; /*!< Tag indices. */
int db_buildindex; /*!< Index rebuild indicator */
+ struct rpmdbOps_s * db_ops; /*!< backend ops */
+
/* dbenv and related parameters */
- void * db_dbenv; /*!< Berkeley DB_ENV handle. */
+ void * db_dbenv; /*!< Backend private handle */
struct dbConfig_s cfg;
int db_remove_env;
@@ -59,24 +85,44 @@ enum dbiFlags_e {
DBI_RDONLY = (1 << 1),
};
+enum dbcFlags_e {
+ DBC_READ = 0,
+ DBC_WRITE = (1 << 0),
+};
+
+enum dbcSearchType_e {
+ DBC_NORMAL_SEARCH = 0,
+ DBC_PREFIX_SEARCH = (1 << 0),
+};
+
/** \ingroup dbi
* Describes an index database (implemented on Berkeley db functionality).
*/
struct dbiIndex_s {
+ rpmdb dbi_rpmdb; /*!< the parent rpm database */
+ dbiIndexType dbi_type; /*! Type of dbi (primary / index) */
const char * dbi_file; /*!< file component of path */
-
- int dbi_oflags; /*!< db->open flags */
- int dbi_permit_dups; /*!< permit duplicate entries? */
- int dbi_no_dbsync; /*!< don't call dbiSync */
- int dbi_lockdbfd; /*!< do fcntl lock on db fd */
+ int dbi_flags;
int dbi_byteswapped;
- rpmdb dbi_rpmdb; /*!< the parent rpm database */
- dbiIndexType dbi_type; /*! Type of dbi (primary / index) */
+ struct dbiConfig_s cfg;
+
+ void * dbi_db; /*!< Backend private handle */
+};
- DB * dbi_db; /*!< Berkeley DB * handle */
+union _dbswap {
+ unsigned int ui;
+ unsigned char uc[4];
};
+#define _DBSWAP(_a) \
+\
+ { unsigned char _b, *_c = (_a).uc; \
+ _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
+ _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
+\
+ }
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -102,7 +148,10 @@ int dbiResumeDBLock(dbiIndex dbi, unsigned int flags);
RPM_GNUC_INTERNAL
/* Globally enable/disable fsync in the backend */
-void dbSetFSync(void *dbenv, int enable);
+void dbSetFSync(rpmdb rdb, int enable);
+
+RPM_GNUC_INTERNAL
+int dbCtrl(rpmdb rdb, dbCtrlOp ctrl);
/** \ingroup dbi
* Return new configured index database handle instance.
@@ -122,15 +171,6 @@ RPM_GNUC_INTERNAL
dbiIndex dbiFree( dbiIndex dbi);
/** \ingroup dbi
- * Format dbi open flags for debugging print.
- * @param dbflags db open flags
- * @param print_dbenv_flags format db env flags instead?
- * @return formatted flags (malloced)
- */
-RPM_GNUC_INTERNAL
-char * prDbiOpenFlags(int dbflags, int print_dbenv_flags);
-
-/** \ingroup dbi
* Actually open the database of the index.
* @param db rpm database
* @param rpmtag database index tag
@@ -151,15 +191,6 @@ RPM_GNUC_INTERNAL
int dbiClose(dbiIndex dbi, unsigned int flags);
/** \ingroup dbi
- * Flush pending operations to disk.
- * @param dbi index database handle
- * @param flags (unused)
- * @return 0 on success
- */
-RPM_GNUC_INTERNAL
-int dbiSync (dbiIndex dbi, unsigned int flags);
-
-/** \ingroup dbi
* Verify (and close) index database.
* @param dbi index database handle
* @param flags (unused)
@@ -169,22 +200,6 @@ RPM_GNUC_INTERNAL
int dbiVerify(dbiIndex dbi, unsigned int flags);
/** \ingroup dbi
- * Is database byte swapped?
- * @param dbi index database handle
- * @return 0 same order, 1 swapped order
- */
-RPM_GNUC_INTERNAL
-int dbiByteSwapped(dbiIndex dbi);
-
-/** \ingroup dbi
- * Type of dbi (primary data / index)
- * @param dbi index database handle
- * @return type of dbi
- */
-RPM_GNUC_INTERNAL
-dbiIndexType dbiType(dbiIndex dbi);
-
-/** \ingroup dbi
* Retrieve index control flags (new/existing, read-only etc)
* @param dbi index database handle
* @return dbi control flags
@@ -203,7 +218,7 @@ const char * dbiName(dbiIndex dbi);
/** \ingroup dbi
* Open a database cursor.
* @param dbi index database handle
- * @param flags DB_WRITECURSOR if writing, or 0
+ * @param flags DBC_WRITE if writing, or 0 (DBC_READ) for reading
* @return database cursor handle
*/
RPM_GNUC_INTERNAL
@@ -215,56 +230,69 @@ dbiCursor dbiCursorInit(dbiIndex dbi, unsigned int flags);
* @return NULL always
*/
RPM_GNUC_INTERNAL
-dbiCursor dbiCursorFree(dbiCursor dbc);
+dbiCursor dbiCursorFree(dbiIndex dbi, dbiCursor dbc);
-/** \ingroup dbi
- * Store (key,data) pair in index database.
- * @param dbcursor database cursor handle
- * @param key store key value/length/flags
- * @param data store data value/length/flags
- * @param flags flags
- * @return 0 on success
- */
+
+RPM_GNUC_INTERNAL
+rpmRC pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
+ unsigned char *hdrBlob, unsigned int hdrLen);
+RPM_GNUC_INTERNAL
+rpmRC pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum);
RPM_GNUC_INTERNAL
-int dbiCursorPut(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags);
+rpmRC pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
+ unsigned char **hdrBlob, unsigned int *hdrLen);
+RPM_GNUC_INTERNAL
+rpmRC pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum);
+RPM_GNUC_INTERNAL
+unsigned int pkgdbKey(dbiIndex dbi, dbiCursor dbc);
-/** \ingroup dbi
- * Retrieve (key,data) pair from index database.
- * @param dbc database cursor handle
- * @param key retrieve key value/length/flags
- * @param data retrieve data value/length/flags
- * @param flags flags
- * @return 0 on success
- */
RPM_GNUC_INTERNAL
-int dbiCursorGet(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags);
+rpmRC idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexSet *set, int curFlags);
+RPM_GNUC_INTERNAL
+rpmRC idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexItem rec);
+RPM_GNUC_INTERNAL
+rpmRC idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexItem rec);
+RPM_GNUC_INTERNAL
+const void * idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen);
+
+struct rpmdbOps_s {
+ int (*open)(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags);
+ int (*close)(dbiIndex dbi, unsigned int flags);
+ int (*verify)(dbiIndex dbi, unsigned int flags);
+ void (*setFSync)(rpmdb rdb, int enable);
+ int (*ctrl)(rpmdb rdb, dbCtrlOp ctrl);
+
+ dbiCursor (*cursorInit)(dbiIndex dbi, unsigned int flags);
+ dbiCursor (*cursorFree)(dbiIndex dbi, dbiCursor dbc);
+
+ rpmRC (*pkgdbGet)(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen);
+ rpmRC (*pkgdbPut)(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen);
+ rpmRC (*pkgdbDel)(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum);
+ rpmRC (*pkgdbNew)(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum);
+ unsigned int (*pkgdbKey)(dbiIndex dbi, dbiCursor dbc);
+
+ rpmRC (*idxdbGet)(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int curFlags);
+ rpmRC (*idxdbPut)(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec);
+ rpmRC (*idxdbDel)(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec);
+ const void * (*idxdbKey)(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen);
+};
-/** \ingroup dbi
- * Delete (key,data) pair(s) from index database.
- * @param dbc database cursor handle
- * @param key delete key value/length/flags
- * @param data delete data value/length/flags
- * @param flags flags
- * @return 0 on success
- */
RPM_GNUC_INTERNAL
-int dbiCursorDel(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags);
+extern struct rpmdbOps_s db3_dbops;
-/** \ingroup dbi
- * Retrieve count of (possible) duplicate items.
- * @param dbcursor database cursor
- * @return number of duplicates
- */
+#ifdef ENABLE_NDB
RPM_GNUC_INTERNAL
-unsigned int dbiCursorCount(dbiCursor dbc);
+extern struct rpmdbOps_s ndb_dbops;
+#endif
-/** \ingroup dbi
- * Retrieve underlying index database handle.
- * @param dbcursor database cursor
- * @return index database handle
- */
+#if defined(WITH_LMDB)
RPM_GNUC_INTERNAL
-dbiIndex dbiCursorIndex(dbiCursor dbc);
+extern struct rpmdbOps_s lmdb_dbops;
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/backend/dbiset.c b/lib/backend/dbiset.c
new file mode 100644
index 000000000..8fb922ef7
--- /dev/null
+++ b/lib/backend/dbiset.c
@@ -0,0 +1,214 @@
+#include "system.h"
+#include <string.h>
+#include <stdlib.h>
+#include "dbiset.h"
+#include "debug.h"
+
+dbiIndexSet dbiIndexSetNew(unsigned int sizehint)
+{
+ dbiIndexSet set = xcalloc(1, sizeof(*set));
+ if (sizehint > 0)
+ dbiIndexSetGrow(set, sizehint);
+ return set;
+}
+
+/*
+ * Ensure sufficient memory for nrecs of new records in dbiIndexSet.
+ * Allocate in power of two sizes to avoid memory fragmentation, so
+ * realloc is not always needed.
+ */
+void dbiIndexSetGrow(dbiIndexSet set, unsigned int nrecs)
+{
+ size_t need = (set->count + nrecs) * sizeof(*(set->recs));
+ size_t alloced = set->alloced ? set->alloced : 1 << 4;
+
+ while (alloced < need)
+ alloced <<= 1;
+
+ if (alloced != set->alloced) {
+ set->recs = xrealloc(set->recs, alloced);
+ set->alloced = alloced;
+ }
+}
+
+static int hdrNumCmp(const void * one, const void * two)
+{
+ const struct dbiIndexItem_s *a = one, *b = two;
+ if (a->hdrNum - b->hdrNum != 0)
+ return a->hdrNum - b->hdrNum;
+ return a->tagNum - b->tagNum;
+}
+
+void dbiIndexSetSort(dbiIndexSet set)
+{
+ /*
+ * mergesort is much (~10x with lots of identical basenames) faster
+ * than pure quicksort, but glibc uses msort_with_tmp() on stack.
+ */
+ if (set && set->recs && set->count > 1) {
+#if HAVE_MERGESORT
+ mergesort(set->recs, set->count, sizeof(*set->recs), hdrNumCmp);
+#else
+ qsort(set->recs, set->count, sizeof(*set->recs), hdrNumCmp);
+#endif
+ }
+}
+
+void dbiIndexSetUniq(dbiIndexSet set, int sorted)
+{
+ unsigned int from;
+ unsigned int to = 0;
+ unsigned int num = set->count;
+
+ if (set->count < 2)
+ return;
+
+ if (!sorted)
+ dbiIndexSetSort(set);
+
+ for (from = 0; from < num; from++) {
+ if (from > 0 && set->recs[from - 1].hdrNum == set->recs[from].hdrNum) {
+ set->count--;
+ continue;
+ }
+ if (from != to)
+ set->recs[to] = set->recs[from]; /* structure assignment */
+ to++;
+ }
+}
+
+int dbiIndexSetAppend(dbiIndexSet set, dbiIndexItem recs,
+ unsigned int nrecs, int sortset)
+{
+ if (set == NULL || recs == NULL)
+ return 1;
+
+ if (nrecs) {
+ dbiIndexSetGrow(set, nrecs);
+ memcpy(set->recs + set->count, recs, nrecs * sizeof(*(set->recs)));
+ set->count += nrecs;
+ }
+
+ if (sortset && set->count > 1)
+ qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
+
+ return 0;
+}
+
+int dbiIndexSetAppendSet(dbiIndexSet set, dbiIndexSet oset, int sortset)
+{
+ if (oset == NULL)
+ return 1;
+ return dbiIndexSetAppend(set, oset->recs, oset->count, sortset);
+}
+
+int dbiIndexSetAppendOne(dbiIndexSet set, unsigned int hdrNum,
+ unsigned int tagNum, int sortset)
+{
+ if (set == NULL)
+ return 1;
+ dbiIndexSetGrow(set, 1);
+
+ set->recs[set->count].hdrNum = hdrNum;
+ set->recs[set->count].tagNum = tagNum;
+ set->count += 1;
+
+ if (sortset && set->count > 1)
+ qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
+
+ return 0;
+}
+
+int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,
+ unsigned int nrecs, int sorted)
+{
+ unsigned int from;
+ unsigned int to = 0;
+ unsigned int num = set->count;
+ unsigned int numCopied = 0;
+ size_t recsize = sizeof(*recs);
+
+ if (num == 0 || nrecs == 0)
+ return 1;
+
+ if (nrecs > 1 && !sorted)
+ qsort(recs, nrecs, recsize, hdrNumCmp);
+
+ for (from = 0; from < num; from++) {
+ if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
+ set->count--;
+ continue;
+ }
+ if (from != to)
+ set->recs[to] = set->recs[from]; /* structure assignment */
+ to++;
+ numCopied++;
+ }
+ return (numCopied == num);
+}
+
+int dbiIndexSetPruneSet(dbiIndexSet set, dbiIndexSet oset, int sortset)
+{
+ if (oset == NULL)
+ return 1;
+ return dbiIndexSetPrune(set, oset->recs, oset->count, sortset);
+}
+
+int dbiIndexSetFilter(dbiIndexSet set, dbiIndexItem recs,
+ unsigned int nrecs, int sorted)
+{
+ unsigned int from;
+ unsigned int to = 0;
+ unsigned int num = set->count;
+ unsigned int numCopied = 0;
+ size_t recsize = sizeof(*recs);
+
+ if (num == 0 || nrecs == 0) {
+ set->count = 0;
+ return num ? 0 : 1;
+ }
+ if (nrecs > 1 && !sorted)
+ qsort(recs, nrecs, recsize, hdrNumCmp);
+ for (from = 0; from < num; from++) {
+ if (!bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
+ set->count--;
+ continue;
+ }
+ if (from != to)
+ set->recs[to] = set->recs[from]; /* structure assignment */
+ to++;
+ numCopied++;
+ }
+ return (numCopied == num);
+}
+
+int dbiIndexSetFilterSet(dbiIndexSet set, dbiIndexSet oset, int sorted)
+{
+ return dbiIndexSetFilter(set, oset->recs, oset->count, sorted);
+}
+
+unsigned int dbiIndexSetCount(dbiIndexSet set)
+{
+ return (set != NULL) ? set->count : 0;
+}
+
+unsigned int dbiIndexRecordOffset(dbiIndexSet set, unsigned int recno)
+{
+ return set->recs[recno].hdrNum;
+}
+
+unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, unsigned int recno)
+{
+ return set->recs[recno].tagNum;
+}
+
+dbiIndexSet dbiIndexSetFree(dbiIndexSet set)
+{
+ if (set) {
+ free(set->recs);
+ memset(set, 0, sizeof(*set)); /* trash and burn */
+ free(set);
+ }
+ return NULL;
+}
+
diff --git a/lib/backend/dbiset.h b/lib/backend/dbiset.h
new file mode 100644
index 000000000..da196c865
--- /dev/null
+++ b/lib/backend/dbiset.h
@@ -0,0 +1,130 @@
+#ifndef _DBISET_H
+#define _DBISET_H
+
+#include <rpm/rpmutil.h>
+
+/* A single item from an index database (i.e. the "data returned"). */
+typedef struct dbiIndexItem_s {
+ unsigned int hdrNum; /*!< header instance in db */
+ unsigned int tagNum; /*!< tag index in header */
+} * dbiIndexItem;
+
+/* Items retrieved from the index database.*/
+typedef struct dbiIndexSet_s {
+ dbiIndexItem recs; /*!< array of records */
+ unsigned int count; /*!< number of records */
+ size_t alloced; /*!< alloced size */
+} * dbiIndexSet;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Create an empty index set, optionally with sizehint reservation for recs */
+RPM_GNUC_INTERNAL
+dbiIndexSet dbiIndexSetNew(unsigned int sizehint);
+
+/* Reserve space for at least nrecs new records */
+RPM_GNUC_INTERNAL
+void dbiIndexSetGrow(dbiIndexSet set, unsigned int nrecs);
+
+/* Sort an index set */
+RPM_GNUC_INTERNAL
+void dbiIndexSetSort(dbiIndexSet set);
+
+/* Uniq an index set */
+RPM_GNUC_INTERNAL
+void dbiIndexSetUniq(dbiIndexSet set, int sorted);
+
+/* Append an index set to another */
+RPM_GNUC_INTERNAL
+int dbiIndexSetAppendSet(dbiIndexSet set, dbiIndexSet oset, int sortset);
+
+/**
+ * Append element(s) to set of index database items.
+ * @param set set of index database items
+ * @param recs array of items to append to set
+ * @param nrecs number of items
+ * @param sortset should resulting set be sorted?
+ * @return 0 success, 1 failure (bad args)
+ */
+RPM_GNUC_INTERNAL
+int dbiIndexSetAppend(dbiIndexSet set, dbiIndexItem recs,
+ unsigned int nrecs, int sortset);
+
+/**
+ * Append a single element to a set of index database items.
+ * @param set set of index database items
+ * @param hdrNum header instance in db
+ * @param tagNum tag index in header
+ * @param sortset should resulting set be sorted?
+ * @return 0 success, 1 failure (bad args)
+ */
+RPM_GNUC_INTERNAL
+int dbiIndexSetAppendOne(dbiIndexSet set, unsigned int hdrNum,
+ unsigned int tagNum, int sortset);
+
+/**
+ * Remove element(s) from set of index database items.
+ * @param set set of index database items
+ * @param recs array of items to remove from set
+ * @param nrecs number of items
+ * @param sorted array is already sorted?
+ * @return 0 success, 1 failure (no items found)
+ */
+RPM_GNUC_INTERNAL
+int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,
+ unsigned int nrecs, int sorted);
+
+/**
+ * Remove an index set from another.
+ * @param set set of index database items
+ * @param oset set of entries that should be removed
+ * @param sorted oset is already sorted?
+ * @return 0 success, 1 failure (no items found)
+ */
+RPM_GNUC_INTERNAL
+int dbiIndexSetPruneSet(dbiIndexSet set, dbiIndexSet oset, int sorted);
+
+/**
+ * Filter element(s) from set of index database items.
+ * @param set set of index database items
+ * @param recs array of items to remove from set
+ * @param nrecs number of items
+ * @param sorted recs array is already sorted?
+ * @return 0 success, 1 failure (no items removed)
+ */
+RPM_GNUC_INTERNAL
+int dbiIndexSetFilter(dbiIndexSet set, dbiIndexItem recs,
+ unsigned int nrecs, int sorted);
+
+/**
+ * Filter (intersect) an index set with another.
+ * @param set set of index database items
+ * @param oset set of entries that should be intersected
+ * @param sorted oset is already sorted?
+ * @return 0 success, 1 failure (no items removed)
+ */
+RPM_GNUC_INTERNAL
+int dbiIndexSetFilterSet(dbiIndexSet set, dbiIndexSet oset, int sorted);
+
+/* Count items in index database set. */
+RPM_GNUC_INTERNAL
+unsigned int dbiIndexSetCount(dbiIndexSet set);
+
+/* Return record offset of header from element in index database set. */
+RPM_GNUC_INTERNAL
+unsigned int dbiIndexRecordOffset(dbiIndexSet set, unsigned int recno);
+
+/* Return file index from element in index database set. */
+RPM_GNUC_INTERNAL
+unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, unsigned int recno);
+
+/* Destroy set of index database items */
+RPM_GNUC_INTERNAL
+dbiIndexSet dbiIndexSetFree(dbiIndexSet set);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/lib/backend/lmdb.c b/lib/backend/lmdb.c
new file mode 100644
index 000000000..db1270ebc
--- /dev/null
+++ b/lib/backend/lmdb.c
@@ -0,0 +1,939 @@
+/** \ingroup rpmdb
+ * \file lib/lmdb.c
+ */
+
+#include "system.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <popt.h>
+#include <lmdb.h>
+#include <signal.h>
+
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmmacro.h>
+#include <rpm/rpmfileutil.h>
+#include <rpm/rpmlog.h>
+
+#include "lib/rpmdb_internal.h"
+
+#include "debug.h"
+
+static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
+
+struct dbiCursor_s {
+ dbiIndex dbi;
+ const void *key;
+ unsigned int keylen;
+ int flags;
+ MDB_cursor * cursor;
+ MDB_txn * txn;
+};
+
+static const char * _EnvF(unsigned eflags)
+{
+ static char t[256];
+ char *te = t;
+
+ *te = '\0';
+#define _EF(_v) if (eflags & MDB_##_v) te = stpcpy(stpcpy(te,"|"),#_v)
+ _EF(FIXEDMAP);
+ _EF(NOSUBDIR);
+ _EF(NOSYNC);
+ _EF(RDONLY);
+ _EF(NOMETASYNC);
+ _EF(WRITEMAP);
+ _EF(MAPASYNC);
+ _EF(NOTLS);
+ _EF(NOLOCK);
+ _EF(NORDAHEAD);
+ _EF(NOMEMINIT);
+#undef _EF
+ if (t[0] == '\0') te += sprintf(te, "|0x%x", eflags);
+ *te = '\0';
+ return t+1;
+}
+
+static const char * _OpenF(unsigned oflags)
+{
+ static char t[256];
+ char *te = t;
+
+ *te = '\0';
+#define _OF(_v) if (oflags & MDB_##_v) te = stpcpy(stpcpy(te,"|"),#_v)
+ _OF(REVERSEKEY);
+ _OF(DUPSORT);
+ _OF(INTEGERKEY);
+ _OF(DUPFIXED);
+ _OF(INTEGERDUP);
+ _OF(REVERSEDUP);
+ _OF(CREATE);
+#undef _OF
+ if (t[0] == '\0') te += sprintf(te, "|0x%x", oflags);
+ *te = '\0';
+ return t+1;
+}
+
+static int dbapi_err(rpmdb rdb, const char * msg, int rc, int printit)
+{
+ if (printit && rc) {
+ int lvl = RPMLOG_ERR;
+ if (msg)
+ rpmlog(lvl, _("%s:\trc(%d) = %s(): %s\n"),
+ rdb->db_descr, rc, msg, (rc ? mdb_strerror(rc) : ""));
+ else
+ rpmlog(lvl, _("%s:\trc(%d) = %s()\n"),
+ rdb->db_descr, rc, (rc ? mdb_strerror(rc) : ""));
+ }
+ return rc;
+}
+
+static int cvtdberr(dbiIndex dbi, const char * msg, int rc, int printit)
+{
+ return dbapi_err(dbi->dbi_rpmdb, msg, rc, printit);
+}
+
+static void lmdb_assert(MDB_env *env, const char *msg)
+{
+ rpmlog(RPMLOG_ERR, "%s: %s\n", __FUNCTION__, msg);
+}
+
+static void lmdb_dbSetFSync(rpmdb rdb, int enable)
+{
+}
+
+static int lmdb_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
+{
+ return 0;
+}
+
+static int db_fini(rpmdb rdb, const char * dbhome)
+{
+ int rc = 0;
+ MDB_env * env = rdb->db_dbenv;
+
+ if (env == NULL)
+ goto exit;
+ if (--rdb->db_opens > 0)
+ goto exit;
+
+ mdb_env_close(env);
+ rdb->db_dbenv = env = NULL;
+
+ rpmlog(RPMLOG_DEBUG, "closed db environment %s\n", dbhome);
+
+exit:
+ return rc;
+}
+
+static int db_init(rpmdb rdb, const char * dbhome)
+{
+ int rc = EINVAL;
+ MDB_env * env = NULL;
+ int retry_open = 2;
+ uint32_t eflags = 0;
+
+ if (rdb->db_dbenv != NULL) {
+ rdb->db_opens++;
+ return 0;
+ } else {
+ /* On first call, set backend description to something... */
+ free(rdb->db_descr);
+ rdb->db_descr = xstrdup("lmdb");
+ }
+
+ MDB_dbi maxdbs = 32;
+ unsigned int maxreaders = 16;
+ size_t mapsize = 256 * 1024 * 1024;
+
+ if ((rc = mdb_env_create(&env))
+ || (rc = mdb_env_set_maxreaders(env, maxreaders))
+ || (rc = mdb_env_set_mapsize(env, mapsize))
+ || (rc = mdb_env_set_maxdbs(env, maxdbs))
+ || (rc = mdb_env_set_assert(env, lmdb_assert))
+ || (rc = mdb_env_set_userctx(env, rdb))
+ ) {
+ rc = dbapi_err(rdb, "mdb_env_create", rc, _debug);
+ goto exit;
+ }
+
+ /*
+ * Actually open the environment. Fall back to private environment
+ * if we dont have permission to join/create shared environment or
+ * system doesn't support it..
+ */
+ while (retry_open) {
+ rpmlog(RPMLOG_DEBUG, "opening db environment %s eflags=%s perms=0%o\n", dbhome, _EnvF(eflags), rdb->db_perms);
+
+ eflags = 0;
+ eflags |= MDB_WRITEMAP;
+ eflags |= MDB_MAPASYNC;
+ eflags |= MDB_NOTLS;
+
+ if (access(dbhome, W_OK) && (rdb->db_mode & O_ACCMODE) == O_RDONLY)
+ eflags |= MDB_RDONLY;
+
+ rc = mdb_env_open(env, dbhome, eflags, rdb->db_perms);
+ if (rc) {
+ rc = dbapi_err(rdb, "mdb_env_open", rc, _debug);
+ if (rc == EPERM)
+ rpmlog(RPMLOG_ERR, "lmdb: %s(%s/lock.mdb): %s\n", __FUNCTION__, dbhome, mdb_strerror(rc));
+ }
+ retry_open = 0; /* XXX EAGAIN might need a retry */
+ }
+ if (rc)
+ goto exit;
+
+ rdb->db_dbenv = env;
+ rdb->db_opens = 1;
+
+exit:
+ if (rc && env) {
+ mdb_env_close(env);
+ rdb->db_dbenv = env = NULL;
+ }
+ return rc;
+}
+
+static int dbiSync(dbiIndex dbi, unsigned int flags)
+{
+ int rc = 0;
+ MDB_dbi db = (unsigned long) dbi->dbi_db;
+
+ if (db != 0xdeadbeef && !dbi->cfg.dbi_no_dbsync) {
+ MDB_env * env = dbi->dbi_rpmdb->db_dbenv;
+ unsigned eflags = 0;
+ rc = mdb_env_get_flags(env, &eflags);
+ if (rc) {
+ rc = cvtdberr(dbi, "mdb_env_get_flags", rc, _debug);
+ eflags |= MDB_RDONLY;
+ }
+ if (!(eflags & MDB_RDONLY)) {
+ int force = 0;
+ rc = mdb_env_sync(env, force);
+ if (rc)
+ rc = cvtdberr(dbi, "mdb_env_sync", rc, _debug);
+ }
+ }
+ return rc;
+}
+
+static dbiCursor lmdb_dbiCursorInit(dbiIndex dbi, unsigned int flags)
+{
+ dbiCursor dbc = NULL;
+
+ if (dbi && dbi->dbi_db != (void *)0xdeadbeefUL) {
+ MDB_env * env = dbi->dbi_rpmdb->db_dbenv;
+ MDB_txn * parent = NULL;
+ unsigned tflags = !(flags & DBC_WRITE) ? MDB_RDONLY : 0;
+ MDB_txn * txn = NULL;
+ MDB_cursor * cursor = NULL;
+ int rc = EINVAL;
+
+ rc = mdb_txn_begin(env, parent, tflags, &txn);
+ if (rc)
+ rc = cvtdberr(dbi, "mdb_txn_begin", rc, _debug);
+
+ if (rc == 0) {
+ MDB_dbi db = (unsigned long) dbi->dbi_db;
+ rc = mdb_cursor_open(txn, db, &cursor);
+ if (rc)
+ rc = cvtdberr(dbi, "mdb_cursor_open", rc, _debug);
+ }
+
+ if (rc == 0) {
+ dbc = xcalloc(1, sizeof(*dbc));
+ dbc->dbi = dbi;
+ dbc->flags = flags;
+ dbc->cursor = cursor;
+ dbc->txn = txn;
+ }
+ }
+
+ return dbc;
+}
+
+static dbiCursor lmdb_dbiCursorFree(dbiIndex dbi, dbiCursor dbc)
+{
+ if (dbc) {
+ int rc = 0;
+ MDB_cursor * cursor = dbc->cursor;
+ MDB_txn * txn = dbc->txn;
+ dbiIndex dbi = dbc->dbi;
+ unsigned flags = dbc->flags;
+
+ mdb_cursor_close(cursor);
+ dbc->cursor = cursor = NULL;
+ if (rc)
+ cvtdberr(dbc->dbi, "mdb_cursor_close", rc, _debug);
+
+ /* Automatically commit close */
+ if (txn) {
+ rc = mdb_txn_commit(txn);
+ dbc->txn = txn = NULL;
+ if (rc)
+ rc = cvtdberr(dbc->dbi, "mdb_txn_commit", rc, _debug);
+ }
+
+ /* Automatically sync on write-cursor close */
+ if (flags & DBC_WRITE)
+ dbiSync(dbi, 0);
+
+ free(dbc);
+ rc = 0;
+ }
+ return NULL;
+}
+
+static int dbiCursorPut(dbiCursor dbc, MDB_val * key, MDB_val * data, unsigned flags)
+{
+ int rc = EINVAL;
+ int sane = (key->mv_data != NULL && key->mv_size > 0 &&
+ data->mv_data != NULL && data->mv_size > 0);
+
+ if (dbc && sane) {
+ MDB_cursor * cursor = dbc->cursor;
+ rpmdb rdb = dbc->dbi->dbi_rpmdb;
+ rpmswEnter(&rdb->db_putops, (ssize_t) 0);
+
+ rc = mdb_cursor_put(cursor, key, data, flags);
+ if (rc) {
+ rc = cvtdberr(dbc->dbi, "mdb_cursor_put", rc, _debug);
+ if (dbc->txn) {
+ mdb_txn_abort(dbc->txn);
+ dbc->txn = NULL;
+ }
+ }
+
+ rpmswExit(&rdb->db_putops, (ssize_t) data->mv_size);
+ }
+ return rc;
+}
+
+static int dbiCursorGet(dbiCursor dbc, MDB_val *key, MDB_val *data, unsigned op)
+{
+ int rc = EINVAL;
+ int sane = ((op == MDB_NEXT) || (key->mv_data != NULL && key->mv_size > 0));
+
+ if (dbc && sane) {
+ MDB_cursor * cursor = dbc->cursor;
+ rpmdb rdb = dbc->dbi->dbi_rpmdb;
+
+ rpmswEnter(&rdb->db_getops, 0);
+
+ /* XXX db4 does DB_FIRST on uninitialized cursor */
+ rc = mdb_cursor_get(cursor, key, data, op);
+ if (rc && rc != MDB_NOTFOUND) {
+ rc = cvtdberr(dbc->dbi, "mdb_cursor_get", rc, _debug);
+ if (dbc->txn) {
+ mdb_txn_abort(dbc->txn);
+ dbc->txn = NULL;
+ }
+ }
+
+ /* Remember the last key fetched */
+ if (rc == 0) {
+ dbc->key = key->mv_data;
+ dbc->keylen = key->mv_size;
+ } else {
+ dbc->key = NULL;
+ dbc->keylen = 0;
+ }
+
+ rpmswExit(&rdb->db_getops, data->mv_size);
+ }
+ return rc;
+}
+
+static int dbiCursorDel(dbiCursor dbc, MDB_val *key, MDB_val *data, unsigned int flags)
+{
+ int rc = EINVAL;
+ int sane = (key->mv_data != NULL && key->mv_size > 0);
+
+ if (dbc && sane) {
+ MDB_cursor * cursor = dbc->cursor;
+ rpmdb rdb = dbc->dbi->dbi_rpmdb;
+ rpmswEnter(&rdb->db_delops, 0);
+
+ /* XXX TODO: ensure that cursor is positioned with duplicates */
+ rc = mdb_cursor_get(cursor, key, data, MDB_SET);
+ if (rc && rc != MDB_NOTFOUND) {
+ rc = cvtdberr(dbc->dbi, "mdb_cursor_get", rc, _debug);
+ if (dbc->txn)
+ dbc->txn = NULL;
+ }
+
+ if (rc == 0) {
+ rc = mdb_cursor_del(cursor, flags);
+ if (rc)
+ rc = cvtdberr(dbc->dbi, "mdb_cursor_del", rc, _debug);
+ }
+ rpmswExit(&rdb->db_delops, data->mv_size);
+ }
+ return rc;
+}
+
+static int lmdb_dbiVerify(dbiIndex dbi, unsigned int flags)
+{
+ return 0;
+}
+
+static int lmdb_dbiClose(dbiIndex dbi, unsigned int flags)
+{
+ int rc = 0;
+ rpmdb rdb = dbi->dbi_rpmdb;
+ const char * dbhome = rpmdbHome(rdb);
+ MDB_dbi db = (unsigned long) dbi->dbi_db;
+
+ if (db != 0xdeadbeef) {
+ MDB_env * env = dbi->dbi_rpmdb->db_dbenv;
+ mdb_dbi_close(env, db);
+ dbi->dbi_db = (void *) 0xdeadbeefUL;
+
+ rpmlog(RPMLOG_DEBUG, "closed db index %s/%s\n",
+ dbhome, dbi->dbi_file);
+ }
+
+ db_fini(rdb, dbhome ? dbhome : "");
+
+ dbi = dbiFree(dbi);
+
+ return rc;
+}
+
+static int lmdb_dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
+{
+ int rc = 1;
+ const char *dbhome = rpmdbHome(rdb);
+ dbiIndex dbi = NULL;
+ int retry_open;
+
+ MDB_dbi db = 0;
+ uint32_t oflags;
+
+ if (dbip)
+ *dbip = NULL;
+
+ if ((dbi = dbiNew(rdb, rpmtag)) == NULL)
+ goto exit;
+ dbi->dbi_flags = 0;
+ dbi->dbi_db = (void *) 0xdeadbeefUL;
+
+ rc = db_init(rdb, dbhome);
+
+ retry_open = (rc == 0) ? 2 : 0;
+
+ do {
+ MDB_env * env = rdb->db_dbenv;
+ MDB_txn * parent = NULL;
+ unsigned tflags = access(dbhome, W_OK) ? MDB_RDONLY : 0;
+ MDB_txn * txn = NULL;
+
+ if (tflags & MDB_RDONLY)
+ dbi->dbi_flags |= DBI_RDONLY;
+
+ rc = mdb_txn_begin(env, parent, tflags, &txn);
+ if (rc)
+ rc = cvtdberr(dbi, "mdb_txn_begin", rc, _debug);
+
+ const char * name = dbi->dbi_file;
+ oflags = 0;
+ if (!(tflags & MDB_RDONLY))
+ oflags |= MDB_CREATE;
+ if (!strcmp(dbi->dbi_file, "Packages"))
+ oflags |= MDB_INTEGERKEY;
+
+ rpmlog(RPMLOG_DEBUG, "opening db index %s/%s oflags=%s\n",
+ dbhome, dbi->dbi_file, _OpenF(oflags));
+
+ db = 0xdeadbeef;
+ rc = mdb_dbi_open(txn, name, oflags, &db);
+ if (rc && rc != MDB_NOTFOUND) {
+ rc = cvtdberr(dbi, "mdb_dbi_open", rc, _debug);
+ if (txn) {
+ mdb_txn_abort(txn);
+ txn = NULL;
+ db = 0xdeadbeef;
+ }
+ }
+
+ if (txn) {
+ rc = mdb_txn_commit(txn);
+ if (rc)
+ rc = cvtdberr(dbi, "mdb_txn_commit", rc, _debug);
+ }
+ retry_open = 0;
+ } while (--retry_open > 0);
+
+ dbi->dbi_db = (void *) ((unsigned long)db);
+
+ if (!rc && dbip)
+ *dbip = dbi;
+ else
+ (void) dbiClose(dbi, 0);
+
+exit:
+ return rc;
+}
+
+/* The LMDB btree implementation needs BIGENDIAN primary keys. */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+static int _dbibyteswapped = 1;
+#else
+static int _dbibyteswapped = 0;
+#endif
+
+/**
+ * Convert retrieved data to index set.
+ * @param dbi index database handle
+ * @param data retrieved data
+ * @retval setp (malloc'ed) index set
+ * @return 0 on success
+ */
+static rpmRC dbt2set(dbiIndex dbi, MDB_val * data, dbiIndexSet * setp)
+{
+ rpmRC rc = RPMRC_FAIL;
+ const char * sdbir;
+ dbiIndexSet set = NULL;
+ unsigned int i;
+
+ if (dbi == NULL || data == NULL || setp == NULL)
+ goto exit;
+
+ rc = RPMRC_OK;
+ if ((sdbir = data->mv_data) == NULL) {
+ *setp = NULL;
+ goto exit;
+ }
+
+ set = dbiIndexSetNew(data->mv_size / (2 * sizeof(int32_t)));
+ set->count = data->mv_size / (2 * sizeof(int32_t));
+
+ for (i = 0; i < set->count; i++) {
+ union _dbswap hdrNum, tagNum;
+
+ memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
+ sdbir += sizeof(hdrNum.ui);
+ memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
+ sdbir += sizeof(tagNum.ui);
+ if (_dbibyteswapped) {
+ _DBSWAP(hdrNum);
+ _DBSWAP(tagNum);
+ }
+ set->recs[i].hdrNum = hdrNum.ui;
+ set->recs[i].tagNum = tagNum.ui;
+ }
+ *setp = set;
+
+exit:
+ return rc;
+}
+
+/**
+ * Convert index set to database representation.
+ * @param dbi index database handle
+ * @param data retrieved data
+ * @param set index set
+ * @return 0 on success
+ */
+static rpmRC set2dbt(dbiIndex dbi, MDB_val * data, dbiIndexSet set)
+{
+ rpmRC rc = RPMRC_FAIL;
+ char * tdbir;
+ unsigned int i;
+
+ if (dbi == NULL || data == NULL || set == NULL)
+ goto exit;
+
+ rc = RPMRC_OK;
+ data->mv_size = set->count * (2 * sizeof(int32_t));
+ if (data->mv_size == 0) {
+ data->mv_data = NULL;
+ goto exit;
+ }
+ tdbir = data->mv_data = xmalloc(data->mv_size);
+
+ for (i = 0; i < set->count; i++) {
+ union _dbswap hdrNum, tagNum;
+
+ memset(&hdrNum, 0, sizeof(hdrNum));
+ memset(&tagNum, 0, sizeof(tagNum));
+ hdrNum.ui = set->recs[i].hdrNum;
+ tagNum.ui = set->recs[i].tagNum;
+ if (_dbibyteswapped) {
+ _DBSWAP(hdrNum);
+ _DBSWAP(tagNum);
+ }
+ memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
+ tdbir += sizeof(hdrNum.ui);
+ memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
+ tdbir += sizeof(tagNum.ui);
+ }
+exit:
+ return rc;
+}
+
+static rpmRC lmdb_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexSet *set, int searchType)
+{
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ if (dbi != NULL && dbc != NULL && set != NULL) {
+ int cflags = MDB_NEXT;
+ int dbrc;
+ MDB_val key = { 0, NULL };
+ MDB_val data = { 0, NULL };
+
+ if (keyp) {
+ if (keylen == 0) { /* XXX "/" fixup */
+ keyp = "";
+ keylen = 1;
+ }
+ key.mv_data = (void *) keyp; /* discards const */
+ key.mv_size = keylen;
+ cflags = searchType == DBC_PREFIX_SEARCH ? MDB_SET_RANGE : MDB_SET;
+ }
+
+ for (;;) {
+ dbiIndexSet newset = NULL;
+ dbrc = dbiCursorGet(dbc, &key, &data, cflags);
+ if (dbrc != 0)
+ break;
+ if (searchType == DBC_PREFIX_SEARCH &&
+ (key.mv_size < keylen || memcmp(key.mv_data, keyp, keylen) != 0))
+ break;
+ dbt2set(dbi, &data, &newset);
+ if (*set == NULL) {
+ *set = newset;
+ } else {
+ dbiIndexSetAppendSet(*set, newset, 0);
+ dbiIndexSetFree(newset);
+ }
+ if (searchType != DBC_PREFIX_SEARCH)
+ break;
+ key.mv_data = NULL;
+ key.mv_size = 0;
+ cflags = MDB_NEXT;
+ }
+
+ /* fixup result status for prefix search */
+ if (searchType == DBC_PREFIX_SEARCH) {
+ if (dbrc == MDB_NOTFOUND && *set != NULL && (*set)->count > 0)
+ dbrc = 0;
+ else if (dbrc == 0 && (*set == NULL || (*set)->count == 0))
+ dbrc = MDB_NOTFOUND;
+ }
+
+ if (dbrc == 0) {
+ rc = RPMRC_OK;
+ } else if (dbrc == MDB_NOTFOUND) {
+ rc = RPMRC_NOTFOUND;
+ } else {
+ rpmlog(RPMLOG_ERR,
+ _("rc(%d) getting \"%s\" records from %s index: %s\n"),
+ dbrc, keyp ? keyp : "???", dbiName(dbi), mdb_strerror(dbrc));
+ }
+ }
+ return rc;
+}
+
+/* Update secondary index. NULL set deletes the key */
+static rpmRC updateIndex(dbiCursor dbc, const char *keyp, unsigned int keylen,
+ dbiIndexSet set)
+{
+ rpmRC rc = RPMRC_FAIL;
+
+ if (dbc && keyp) {
+ dbiIndex dbi = dbc->dbi;
+ int dbrc;
+ MDB_val key = { 0, NULL };
+ MDB_val data = { 0, NULL };
+
+ key.mv_data = (void *) keyp; /* discards const */
+ key.mv_size = keylen;
+
+ if (set)
+ set2dbt(dbi, &data, set);
+
+ if (dbiIndexSetCount(set) > 0) {
+ dbrc = dbiCursorPut(dbc, &key, &data, 0);
+ if (dbrc) {
+ rpmlog(RPMLOG_ERR,
+ _("rc(%d) storing record \"%s\" into %s index: %s\n"),
+ dbrc, (char*)key.mv_data, dbiName(dbi), mdb_strerror(dbrc));
+ }
+ free(data.mv_data);
+ } else {
+ dbrc = dbiCursorDel(dbc, &key, &data, 0);
+ if (dbrc) {
+ rpmlog(RPMLOG_ERR,
+ _("rc(%d) removing record \"%s\" from %s index: %s\n"),
+ dbrc, (char*)key.mv_data, dbiName(dbi), mdb_strerror(dbrc));
+ }
+ }
+
+ if (dbrc == 0)
+ rc = RPMRC_OK;
+ }
+
+ return rc;
+}
+
+static rpmRC lmdb_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexItem rec)
+{
+ dbiIndexSet set = NULL;
+ rpmRC rc;
+
+ if (keyp && keylen == 0) { /* XXX "/" fixup */
+ keyp = "";
+ keylen++;
+ }
+ rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
+
+ /* Not found means a new key and is not an error. */
+ if (rc && rc != RPMRC_NOTFOUND)
+ goto exit;
+
+ if (set == NULL)
+ set = dbiIndexSetNew(1);
+ dbiIndexSetAppend(set, rec, 1, 0);
+
+ rc = updateIndex(dbc, keyp, keylen, set);
+
+ dbiIndexSetFree(set);
+
+exit:
+ return rc;
+}
+
+static rpmRC lmdb_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexItem rec)
+{
+ rpmRC rc = RPMRC_FAIL;
+ dbiIndexSet set = NULL;
+
+ if (keyp && keylen == 0) { /* XXX "/" fixup */
+ keyp = "";
+ keylen++;
+ }
+ rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
+ if (rc)
+ goto exit;
+
+ if (dbiIndexSetPrune(set, rec, 1, 1)) {
+ /* Nothing was pruned. XXX: Can this actually happen? */
+ rc = RPMRC_OK;
+ } else {
+ /* If there's data left, update data. Otherwise delete the key. */
+ if (dbiIndexSetCount(set) > 0) {
+ rc = updateIndex(dbc, keyp, keylen, set);
+ } else {
+ rc = updateIndex(dbc, keyp, keylen, NULL);
+ }
+ };
+ dbiIndexSetFree(set);
+
+exit:
+ return rc;
+}
+
+static const void * lmdb_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
+{
+ const void *key = NULL;
+ if (dbc) {
+ key = dbc->key;
+ if (key && keylen)
+ *keylen = dbc->keylen;
+ }
+ return key;
+}
+
+/* Update primary Packages index. NULL hdr means remove */
+static rpmRC updatePackages(dbiCursor dbc, unsigned int hdrNum, MDB_val *hdr)
+{
+ int rc = RPMRC_FAIL;
+ int dbrc = EINVAL;
+
+ if (dbc == NULL || hdrNum == 0)
+ goto exit;
+
+ union _dbswap mi_offset;
+ mi_offset.ui = hdrNum;
+ if (_dbibyteswapped)
+ _DBSWAP(mi_offset);
+
+ MDB_val key = { 0, NULL };
+ key.mv_data = (void *) &mi_offset;
+ key.mv_size = sizeof(mi_offset.ui);
+
+ MDB_val data = { 0, NULL };
+
+ dbrc = dbiCursorGet(dbc, &key, &data, MDB_SET);
+ if (dbrc && dbrc != MDB_NOTFOUND) {
+ rpmlog(RPMLOG_ERR,
+ _("rc(%d) positioning header #%d record: %s\n"), dbrc, hdrNum, mdb_strerror(dbrc));
+ goto exit;
+ }
+
+ if (hdr) {
+ dbrc = dbiCursorPut(dbc, &key, hdr, 0);
+ if (dbrc) {
+ rpmlog(RPMLOG_ERR,
+ _("rc(%d) adding header #%d record: %s\n"), dbrc, hdrNum, mdb_strerror(dbrc));
+ }
+ } else {
+ dbrc = dbiCursorDel(dbc, &key, &data, 0);
+ if (dbrc) {
+ rpmlog(RPMLOG_ERR,
+ _("rc(%d) deleting header #%d record: %s\n"), dbrc, hdrNum, mdb_strerror(dbrc));
+ }
+ }
+
+exit:
+ rc = dbrc == 0 ? RPMRC_OK : RPMRC_FAIL;
+ return rc;
+}
+
+/* Get current header instance number or try to allocate a new one */
+static unsigned int pkgInstance(dbiCursor dbc, int alloc)
+{
+ unsigned int hdrNum = 0;
+
+ MDB_val key = { 0, NULL };
+ MDB_val data = { 0, NULL };
+ unsigned int firstkey = 0;
+ union _dbswap mi_offset;
+ int rc;
+
+ /* Key 0 holds the current largest instance, fetch it */
+ key.mv_data = &firstkey;
+ key.mv_size = sizeof(firstkey);
+ rc = dbiCursorGet(dbc, &key, &data, MDB_SET);
+
+ if (!rc && data.mv_data) {
+ memcpy(&mi_offset, data.mv_data, sizeof(mi_offset.ui));
+ if (_dbibyteswapped)
+ _DBSWAP(mi_offset);
+ hdrNum = mi_offset.ui;
+ }
+
+ if (alloc) {
+ /* Rather complicated "increment by one", bswapping as needed */
+ ++hdrNum;
+ mi_offset.ui = hdrNum;
+ if (_dbibyteswapped)
+ _DBSWAP(mi_offset);
+ data.mv_data = &mi_offset;
+ data.mv_size = sizeof(mi_offset.ui);
+
+ /* Unless we manage to insert the new instance number, we failed */
+ rc = dbiCursorPut(dbc, &key, &data, 0);
+ if (rc) {
+ hdrNum = 0;
+ rpmlog(RPMLOG_ERR,
+ _("rc(%d) allocating new package instance: %s\n"), rc, mdb_strerror(rc));
+ }
+ }
+
+ return hdrNum;
+}
+
+static rpmRC lmdb_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
+ unsigned char *hdrBlob, unsigned int hdrLen)
+{
+ MDB_val hdr;
+ hdr.mv_data = hdrBlob;
+ hdr.mv_size = hdrLen;
+ return updatePackages(dbc, hdrNum, &hdr);
+}
+
+static rpmRC lmdb_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
+{
+ return updatePackages(dbc, hdrNum, NULL);
+}
+
+static rpmRC lmdb_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
+ unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ union _dbswap mi_offset;
+ MDB_val key = { 0, NULL };
+ MDB_val data = { 0, NULL };
+ rpmRC rc = RPMRC_FAIL;
+
+ if (dbc == NULL)
+ goto exit;
+
+ if (hdrNum) {
+ mi_offset.ui = hdrNum;
+ if (_dbibyteswapped)
+ _DBSWAP(mi_offset);
+ key.mv_data = (void *) &mi_offset;
+ key.mv_size = sizeof(mi_offset.ui);
+ }
+
+ rc = dbiCursorGet(dbc, &key, &data, hdrNum ? MDB_SET : MDB_NEXT);
+ if (rc == 0) {
+ if (hdrBlob)
+ *hdrBlob = data.mv_data;
+ if (hdrLen)
+ *hdrLen = data.mv_size;
+ rc = RPMRC_OK;
+ } else if (rc == MDB_NOTFOUND)
+ rc = RPMRC_NOTFOUND;
+ else
+ rc = RPMRC_FAIL;
+exit:
+ return rc;
+}
+
+static unsigned int lmdb_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
+{
+ union _dbswap mi_offset;
+
+ if (dbc == NULL || dbc->key == NULL)
+ return 0;
+ memcpy(&mi_offset, dbc->key, sizeof(mi_offset.ui));
+ if (_dbibyteswapped)
+ _DBSWAP(mi_offset);
+ return mi_offset.ui;
+}
+
+static rpmRC lmdb_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum)
+{
+ unsigned int num;
+ rpmRC rc = RPMRC_FAIL;
+
+ if (dbc == NULL)
+ goto exit;
+ num = pkgInstance(dbc, 1);
+ if (num) {
+ *hdrNum = num;
+ rc = RPMRC_OK;
+ }
+exit:
+ return rc;
+}
+
+struct rpmdbOps_s lmdb_dbops = {
+ .open = lmdb_dbiOpen,
+ .close = lmdb_dbiClose,
+ .verify = lmdb_dbiVerify,
+
+ .setFSync = lmdb_dbSetFSync,
+ .ctrl = lmdb_Ctrl,
+
+ .cursorInit = lmdb_dbiCursorInit,
+ .cursorFree = lmdb_dbiCursorFree,
+
+ .pkgdbGet = lmdb_pkgdbGet,
+ .pkgdbPut = lmdb_pkgdbPut,
+ .pkgdbDel = lmdb_pkgdbDel,
+ .pkgdbNew = lmdb_pkgdbNew,
+ .pkgdbKey = lmdb_pkgdbKey,
+
+ .idxdbGet = lmdb_idxdbGet,
+ .idxdbPut = lmdb_idxdbPut,
+ .idxdbDel = lmdb_idxdbDel,
+ .idxdbKey = lmdb_idxdbKey
+};
diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c
new file mode 100644
index 000000000..144ada0e4
--- /dev/null
+++ b/lib/backend/ndb/glue.c
@@ -0,0 +1,492 @@
+#include "system.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "lib/rpmdb_internal.h"
+#include <rpm/rpmstring.h>
+#include <rpm/rpmlog.h>
+
+#include "lib/backend/ndb/rpmpkg.h"
+#include "lib/backend/ndb/rpmxdb.h"
+#include "lib/backend/ndb/rpmidx.h"
+
+#include "debug.h"
+
+struct dbiCursor_s {
+ dbiIndex dbi;
+ const void *key;
+ unsigned int keylen;
+ unsigned int hdrNum;
+ int flags;
+
+ unsigned int *list;
+ unsigned int nlist;
+ unsigned int ilist;
+ unsigned char *listdata;
+};
+
+struct ndbEnv_s {
+ rpmpkgdb pkgdb;
+ rpmxdb xdb;
+ int refs;
+
+ unsigned int hdrNum;
+ void *data;
+ unsigned int datalen;
+};
+
+static void closeEnv(rpmdb rdb)
+{
+ struct ndbEnv_s *ndbenv = rdb->db_dbenv;
+ if (--ndbenv->refs == 0) {
+ if (ndbenv->xdb) {
+ rpmxdbClose(ndbenv->xdb);
+ rpmlog(RPMLOG_DEBUG, "closed db index %s/Index.db\n", rpmdbHome(rdb));
+ }
+ if (ndbenv->pkgdb) {
+ rpmpkgClose(ndbenv->pkgdb);
+ rpmlog(RPMLOG_DEBUG, "closed db index %s/Packages.db\n", rpmdbHome(rdb));
+ }
+ if (ndbenv->data)
+ free(ndbenv->data);
+ free(ndbenv);
+ rdb->db_dbenv = 0;
+ }
+}
+
+static struct ndbEnv_s *openEnv(rpmdb rdb)
+{
+ struct ndbEnv_s *ndbenv = rdb->db_dbenv;
+ if (!ndbenv)
+ rdb->db_dbenv = ndbenv = xcalloc(1, sizeof(struct ndbEnv_s));
+ ndbenv->refs++;
+ return ndbenv;
+}
+
+static int ndb_Close(dbiIndex dbi, unsigned int flags)
+{
+ rpmdb rdb = dbi->dbi_rpmdb;
+ if (dbi->dbi_type != DBI_PRIMARY && dbi->dbi_db) {
+ rpmidxClose(dbi->dbi_db);
+ rpmlog(RPMLOG_DEBUG, "closed db index %s\n", dbi->dbi_file);
+ }
+ if (rdb->db_dbenv)
+ closeEnv(rdb);
+ dbi->dbi_db = 0;
+ return 0;
+}
+
+static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
+{
+ const char *dbhome = rpmdbHome(rdb);
+ struct ndbEnv_s *ndbenv;
+ dbiIndex dbi;
+ int rc, oflags, ioflags;
+
+ if (dbip)
+ *dbip = NULL;
+
+ if ((dbi = dbiNew(rdb, rpmtag)) == NULL)
+ return 1;
+
+ ndbenv = openEnv(rdb);
+
+ oflags = O_RDWR;
+ if ((rdb->db_mode & O_ACCMODE) == O_RDONLY)
+ oflags = O_RDONLY;
+
+ if (dbi->dbi_type == DBI_PRIMARY) {
+ rpmpkgdb pkgdb = 0;
+ char *path = rstrscat(NULL, dbhome, "/Packages.db", NULL);
+ rpmlog(RPMLOG_DEBUG, "opening db index %s mode=0x%x\n", path, rdb->db_mode);
+ rc = rpmpkgOpen(&pkgdb, path, oflags, 0666);
+ if (rc && errno == ENOENT) {
+ oflags = O_RDWR|O_CREAT;
+ dbi->dbi_flags |= DBI_CREATED;
+ rc = rpmpkgOpen(&pkgdb, path, oflags, 0666);
+ }
+ if (rc) {
+ perror("rpmpkgOpen");
+ free(path);
+ ndb_Close(dbi, 0);
+ return 1;
+ }
+ free(path);
+ dbi->dbi_db = ndbenv->pkgdb = pkgdb;
+
+ if ((oflags & (O_RDWR | O_RDONLY)) == O_RDONLY)
+ dbi->dbi_flags |= DBI_RDONLY;
+ } else {
+ unsigned int id;
+ rpmidxdb idxdb = 0;
+ if (!ndbenv->pkgdb) {
+ ndb_Close(dbi, 0);
+ return 1; /* please open primary first */
+ }
+ if (!ndbenv->xdb) {
+ char *path = rstrscat(NULL, dbhome, "/Index.db", NULL);
+ rpmlog(RPMLOG_DEBUG, "opening db index %s mode=0x%x\n", path, rdb->db_mode);
+
+ /* Open indexes readwrite if possible */
+ ioflags = O_RDWR;
+ rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666);
+ if (rc && errno == EACCES) {
+ /* If it is not asked for rw explicitly, try to open ro */
+ if (!(oflags & O_RDWR)) {
+ ioflags = O_RDONLY;
+ rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666);
+ }
+ } else if (rc && errno == ENOENT) {
+ ioflags = O_CREAT|O_RDWR;
+ rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666);
+ }
+ if (rc) {
+ perror("rpmxdbOpen");
+ free(path);
+ ndb_Close(dbi, 0);
+ return 1;
+ }
+ free(path);
+ }
+ if (rpmxdbLookupBlob(ndbenv->xdb, &id, rpmtag, 0, 0) == RPMRC_NOTFOUND) {
+ dbi->dbi_flags |= DBI_CREATED;
+ }
+ rpmlog(RPMLOG_DEBUG, "opening db index %s tag=%d\n", dbiName(dbi), rpmtag);
+ if (rpmidxOpenXdb(&idxdb, rdb->db_pkgs->dbi_db, ndbenv->xdb, rpmtag)) {
+ perror("rpmidxOpenXdb");
+ ndb_Close(dbi, 0);
+ return 1;
+ }
+ dbi->dbi_db = idxdb;
+
+ if (rpmxdbIsRdonly(ndbenv->xdb))
+ dbi->dbi_flags |= DBI_RDONLY;
+ }
+
+
+ if (dbip != NULL)
+ *dbip = dbi;
+ else
+ ndb_Close(dbi, 0);
+ return 0;
+}
+
+static int ndb_Verify(dbiIndex dbi, unsigned int flags)
+{
+ return 1;
+}
+
+static void ndb_SetFSync(rpmdb rdb, int enable)
+{
+}
+
+static int indexSync(rpmpkgdb pkgdb, rpmxdb xdb)
+{
+ unsigned int generation;
+ int rc;
+ if (!pkgdb || !xdb)
+ return 1;
+ if (rpmpkgLock(pkgdb, 1))
+ return 1;
+ if (rpmpkgGeneration(pkgdb, &generation)) {
+ rpmpkgUnlock(pkgdb, 1);
+ return 1;
+ }
+ rc = rpmxdbSetUserGeneration(xdb, generation);
+ rpmpkgUnlock(pkgdb, 1);
+ return rc;
+}
+
+static int ndb_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
+{
+ struct ndbEnv_s *ndbenv = rdb->db_dbenv;
+
+ switch (ctrl) {
+ case DB_CTRL_LOCK_RO:
+ if (!rdb->db_pkgs)
+ return 1;
+ return rpmpkgLock(rdb->db_pkgs->dbi_db, 0);
+ case DB_CTRL_LOCK_RW:
+ if (!rdb->db_pkgs)
+ return 1;
+ return rpmpkgLock(rdb->db_pkgs->dbi_db, 1);
+ case DB_CTRL_UNLOCK_RO:
+ if (!rdb->db_pkgs)
+ return 1;
+ return rpmpkgUnlock(rdb->db_pkgs->dbi_db, 0);
+ case DB_CTRL_UNLOCK_RW:
+ if (!rdb->db_pkgs)
+ return 1;
+ return rpmpkgUnlock(rdb->db_pkgs->dbi_db, 1);
+ case DB_CTRL_INDEXSYNC:
+ if (!ndbenv)
+ return 1;
+ return indexSync(ndbenv->pkgdb, ndbenv->xdb);
+ default:
+ break;
+ }
+ return 0;
+}
+
+static dbiCursor ndb_CursorInit(dbiIndex dbi, unsigned int flags)
+{
+ dbiCursor dbc = xcalloc(1, sizeof(*dbc));
+ dbc->dbi = dbi;
+ dbc->flags = flags;
+ return dbc;
+}
+
+static dbiCursor ndb_CursorFree(dbiIndex dbi, dbiCursor dbc)
+{
+ if (dbc) {
+ if (dbc->list)
+ free(dbc->list);
+ if (dbc->listdata)
+ free(dbc->listdata);
+ free(dbc);
+ }
+ return NULL;
+}
+
+
+static void setdata(dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen)
+{
+ struct ndbEnv_s *ndbenv = dbc->dbi->dbi_rpmdb->db_dbenv;
+ if (ndbenv->data)
+ free(ndbenv->data);
+ ndbenv->hdrNum = hdrNum;
+ ndbenv->data = hdrBlob;
+ ndbenv->datalen = hdrLen;
+}
+
+static rpmRC ndb_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum)
+{
+ int rc = rpmpkgNextPkgIdx(dbc->dbi->dbi_db, hdrNum);
+ if (!rc)
+ setdata(dbc, *hdrNum, 0, 0);
+ return rc;
+}
+
+static rpmRC ndb_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen)
+{
+ int rc = rpmpkgPut(dbc->dbi->dbi_db, hdrNum, hdrBlob, hdrLen);
+ if (!rc) {
+ dbc->hdrNum = hdrNum;
+ setdata(dbc, hdrNum, 0, 0);
+ }
+ return rc;
+}
+
+static rpmRC ndb_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
+{
+ dbc->hdrNum = 0;
+ setdata(dbc, 0, 0, 0);
+ return rpmpkgDel(dbc->dbi->dbi_db, hdrNum);
+}
+
+/* iterate over all packages */
+static rpmRC ndb_pkgdbIter(dbiIndex dbi, dbiCursor dbc, unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ int rc;
+ unsigned int hdrNum;
+
+ if (!dbc->list) {
+ rc = rpmpkgList(dbc->dbi->dbi_db, &dbc->list, &dbc->nlist);
+ if (rc)
+ return rc;
+ dbc->ilist = 0;
+ }
+ for (;;) {
+ if (dbc->ilist >= dbc->nlist) {
+ rc = RPMRC_NOTFOUND;
+ break;
+ }
+ *hdrBlob = 0;
+ hdrNum = dbc->list[dbc->ilist];
+ rc = rpmpkgGet(dbc->dbi->dbi_db, hdrNum, hdrBlob, hdrLen);
+ if (rc && rc != RPMRC_NOTFOUND)
+ break;
+ dbc->ilist++;
+ if (!rc) {
+ dbc->hdrNum = hdrNum;
+ setdata(dbc, hdrNum, *hdrBlob, *hdrLen);
+ break;
+ }
+ }
+ return rc;
+}
+
+static rpmRC ndb_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ int rc;
+ struct ndbEnv_s *ndbenv = dbc->dbi->dbi_rpmdb->db_dbenv;
+
+ if (!hdrNum)
+ return ndb_pkgdbIter(dbi, dbc, hdrBlob, hdrLen);
+ if (hdrNum == ndbenv->hdrNum && ndbenv->data) {
+ *hdrBlob = ndbenv->data;
+ *hdrLen = ndbenv->datalen;
+ return RPMRC_OK;
+ }
+ rc = rpmpkgGet(dbc->dbi->dbi_db, hdrNum, hdrBlob, hdrLen);
+ if (!rc) {
+ dbc->hdrNum = hdrNum;
+ setdata(dbc, hdrNum, *hdrBlob, *hdrLen);
+ }
+ return rc;
+}
+
+static unsigned int ndb_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
+{
+ return dbc->hdrNum;
+}
+
+
+static void addtoset(dbiIndexSet *set, unsigned int *pkglist, unsigned int pkglistn)
+{
+ unsigned int i, j;
+ dbiIndexSet newset = dbiIndexSetNew(pkglistn / 2);
+ for (i = j = 0; i < pkglistn; i += 2) {
+ newset->recs[j].hdrNum = pkglist[i];
+ newset->recs[j].tagNum = pkglist[i + 1];
+ j++;
+ }
+ newset->count = j;
+ if (pkglist)
+ free(pkglist);
+ if (*set) {
+ dbiIndexSetAppendSet(*set, newset, 0);
+ dbiIndexSetFree(newset);
+ } else
+ *set = newset;
+}
+
+/* Iterate over all index entries */
+static rpmRC ndb_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set)
+{
+ int rc;
+ if (!dbc->list) {
+ /* setup iteration list on first call */
+ rc = rpmidxList(dbc->dbi->dbi_db, &dbc->list, &dbc->nlist, &dbc->listdata);
+ if (rc)
+ return rc;
+ dbc->ilist = 0;
+ }
+ for (;;) {
+ unsigned char *k;
+ unsigned int kl;
+ unsigned int *pkglist, pkglistn;
+ if (dbc->ilist >= dbc->nlist) {
+ rc = RPMRC_NOTFOUND;
+ break;
+ }
+ k = dbc->listdata + dbc->list[dbc->ilist];
+ kl = dbc->list[dbc->ilist + 1];
+#if 0
+ if (searchType == DBC_KEY_SEARCH) {
+ dbc->ilist += 2;
+ dbc->key = k;
+ dbc->keylen = kl;
+ rc = RPMRC_OK;
+ break;
+ }
+#endif
+ pkglist = 0;
+ pkglistn = 0;
+ rc = rpmidxGet(dbc->dbi->dbi_db, k, kl, &pkglist, &pkglistn);
+ if (rc && rc != RPMRC_NOTFOUND)
+ break;
+ dbc->ilist += 2;
+ if (!rc && pkglistn) {
+ addtoset(set, pkglist, pkglistn);
+ dbc->key = k;
+ dbc->keylen = kl;
+ break;
+ }
+ if (pkglist)
+ free(pkglist);
+ }
+ return rc;
+}
+
+static rpmRC ndb_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int searchType)
+{
+ int rc;
+ unsigned int *pkglist = 0, pkglistn = 0;
+
+ if (!keyp)
+ return ndb_idxdbIter(dbi, dbc, set);
+
+ if (searchType == DBC_PREFIX_SEARCH) {
+ unsigned int *list = 0, nlist = 0, i = 0;
+ unsigned char *listdata = 0;
+ int rrc = RPMRC_NOTFOUND;
+ rc = rpmidxList(dbc->dbi->dbi_db, &list, &nlist, &listdata);
+ if (rc)
+ return rc;
+ for (i = 0; i < nlist && !rc; i += 2) {
+ unsigned char *k = listdata + list[i];
+ unsigned int kl = list[i + 1];
+ if (kl < keylen || memcmp(k, keyp, keylen) != 0)
+ continue;
+ rc = ndb_idxdbGet(dbi, dbc, (char *)k, kl, set, DBC_NORMAL_SEARCH);
+ if (rc == RPMRC_NOTFOUND)
+ rc = 0;
+ else
+ rrc = rc;
+ }
+ if (list)
+ free(list);
+ if (listdata)
+ free(listdata);
+ return rc ? rc : rrc;
+ }
+
+ rc = rpmidxGet(dbc->dbi->dbi_db, (const unsigned char *)keyp, keylen, &pkglist, &pkglistn);
+ if (!rc)
+ addtoset(set, pkglist, pkglistn);
+ return rc;
+}
+
+static rpmRC ndb_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
+{
+ return rpmidxPut(dbc->dbi->dbi_db, (const unsigned char *)keyp, keylen, rec->hdrNum, rec->tagNum);
+}
+
+static rpmRC ndb_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
+{
+ return rpmidxDel(dbc->dbi->dbi_db, (const unsigned char *)keyp, keylen, rec->hdrNum, rec->tagNum);
+}
+
+static const void * ndb_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
+{
+ if (dbc->key && keylen)
+ *keylen = dbc->keylen;
+ return dbc->key;
+}
+
+
+
+struct rpmdbOps_s ndb_dbops = {
+ .open = ndb_Open,
+ .close = ndb_Close,
+ .verify = ndb_Verify,
+ .setFSync = ndb_SetFSync,
+ .ctrl = ndb_Ctrl,
+
+ .cursorInit = ndb_CursorInit,
+ .cursorFree = ndb_CursorFree,
+
+ .pkgdbNew = ndb_pkgdbNew,
+ .pkgdbPut = ndb_pkgdbPut,
+ .pkgdbDel = ndb_pkgdbDel,
+ .pkgdbGet = ndb_pkgdbGet,
+ .pkgdbKey = ndb_pkgdbKey,
+
+ .idxdbGet = ndb_idxdbGet,
+ .idxdbPut = ndb_idxdbPut,
+ .idxdbDel = ndb_idxdbDel,
+ .idxdbKey = ndb_idxdbKey
+};
+
diff --git a/lib/backend/ndb/rpmidx.c b/lib/backend/ndb/rpmidx.c
new file mode 100644
index 000000000..313d2e0fb
--- /dev/null
+++ b/lib/backend/ndb/rpmidx.c
@@ -0,0 +1,1280 @@
+#define _GNU_SOURCE
+
+#include "system.h"
+
+#include <rpm/rpmlog.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include <endian.h>
+
+#include "rpmidx.h"
+#include "rpmxdb.h"
+
+#define RPMRC_OK 0
+#define RPMRC_NOTFOUND 1
+#define RPMRC_FAIL 2
+
+/* Index database
+ *
+ *
+ * Layout:
+ * Header
+ * Slots
+ * Keys
+ *
+ * Each slot contains 12 bytes, they are split into a 8 byte
+ * and a 4 byte part:
+ * 4 bytes key offset + extra tag bits
+ * 4 bytes data
+ * 4 bytes data overflow
+ * The slot space first contains all 8 byte parts followed by all of
+ * the 4 byte overflow parts. This is done because most of the time we
+ * do not need the latter.
+ *
+ * If a new (key, pkgidx, datidx) tupel is added, the key is hashed with
+ * the popular murmur hash. The lower bits of the hash determine the start
+ * slot, parts of the higher bits are used as extra key equality check.
+ * The (pkgidx, datidx) pair is encoded in a (data, dataovl) pair, so that
+ * most of the time dataovl is zero.
+ *
+ * The code then checks the current entry at the start slot. If the key
+ * does not match, it advances to the next slot. If it matches, it also
+ * checks the data part for a match but it remembers the key offset.
+ * If the code found a (key, data, dataovl) match, nothing needs to be done.
+ *
+ * Otherwise, the code arrived at an empty slot. It then adds the key
+ * to the key space if it did not find a matching key, and then puts
+ * the encoded (key, data, dataovl) pair into the slot.
+ *
+ * Deleting a (key, data) pair is done by replacing the slot with a
+ * (-1, -1, 0) dummy entry.
+ *
+ */
+
+
+typedef struct rpmidxdb_s {
+ rpmpkgdb pkgdb; /* master database */
+
+ char *filename;
+ int fd; /* our file descriptor */
+ int flags;
+ int mode;
+
+ int rdonly;
+
+ /* xdb support */
+ rpmxdb xdb;
+ unsigned int xdbtag;
+ unsigned int xdbid;
+
+ unsigned char *head_mapped;
+ unsigned char *slot_mapped;
+ unsigned char *key_mapped;
+ unsigned int key_size;
+ unsigned int file_size;
+
+ unsigned int generation;
+ unsigned int nslots;
+ unsigned int usedslots;
+ unsigned int dummyslots;
+
+ unsigned int keyend;
+ unsigned int keyexcess;
+
+ unsigned int hmask;
+ unsigned int xmask;
+
+ unsigned int pagesize;
+} * rpmidxdb;
+
+static inline unsigned int le2h(unsigned char *p)
+{
+ return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+}
+
+static inline void h2le(unsigned int x, unsigned char *p)
+{
+ p[0] = x;
+ p[1] = x >> 8;
+ p[2] = x >> 16;
+ p[3] = x >> 24;
+}
+
+/* aligned versions */
+static inline unsigned int le2ha(unsigned char *p)
+{
+ unsigned int x = *(unsigned int *)p;
+ return le32toh(x);
+}
+
+static inline void h2lea(unsigned int x, unsigned char *p)
+{
+ *(unsigned int *)p = htole32(x);
+}
+
+/*** Header management ***/
+
+#define IDXDB_MAGIC ('R' | 'p' << 8 | 'm' << 16 | 'I' << 24)
+#define IDXDB_VERSION 0
+
+#define IDXDB_OFFSET_MAGIC 0
+#define IDXDB_OFFSET_VERSION 4
+#define IDXDB_OFFSET_GENERATION 8
+#define IDXDB_OFFSET_NSLOTS 12
+#define IDXDB_OFFSET_USEDSLOTS 16
+#define IDXDB_OFFSET_DUMMYSLOTS 20
+#define IDXDB_OFFSET_XMASK 24
+#define IDXDB_OFFSET_KEYEND 28
+#define IDXDB_OFFSET_KEYEXCESS 32
+#define IDXDB_OFFSET_OBSOLETE 36
+
+#define IDXDB_SLOT_OFFSET 64
+#define IDXDB_KEY_CHUNKSIZE 4096
+
+/* XDB subids */
+
+#define IDXDB_XDB_SUBTAG 0
+#define IDXDB_XDB_SUBTAG_REBUILD 1
+
+static void set_mapped(rpmidxdb idxdb, unsigned char *addr, unsigned int size)
+{
+ if (addr) {
+ idxdb->head_mapped = addr;
+ idxdb->slot_mapped = addr + IDXDB_SLOT_OFFSET;
+ idxdb->key_mapped = addr + IDXDB_SLOT_OFFSET + idxdb->nslots * 12;
+ idxdb->key_size = size - (IDXDB_SLOT_OFFSET + idxdb->nslots * 12);
+ idxdb->file_size = size;
+ } else {
+ idxdb->head_mapped = idxdb->slot_mapped = idxdb->key_mapped = 0;
+ idxdb->file_size = idxdb->key_size = 0;
+ }
+}
+
+/* XDB callbacks */
+static void mapcb(rpmxdb xdb, void *data, void *newaddr, size_t newsize) {
+ set_mapped((rpmidxdb)data, newaddr, (unsigned int)newsize);
+}
+
+static int rpmidxReadHeader(rpmidxdb idxdb);
+
+static int rpmidxMap(rpmidxdb idxdb)
+{
+ if (idxdb->xdb) {
+ if (rpmxdbMapBlob(idxdb->xdb, idxdb->xdbid, idxdb->rdonly ? O_RDONLY : O_RDWR, mapcb, idxdb))
+ return RPMRC_FAIL;
+ if (idxdb->file_size < 4096) {
+ rpmxdbUnmapBlob(idxdb->xdb, idxdb->xdbid);
+ return RPMRC_FAIL;
+ }
+ } else {
+#ifdef IDXDB_FILESUPPORT
+ struct stat stb;
+ size_t size;
+ void *mapped;
+ if (fstat(idxdb->fd, &stb))
+ return RPMRC_FAIL;
+ size = stb.st_size;
+ if (size < 4096)
+ return RPMRC_FAIL;
+ /* round up for mmap */
+ size = (size + idxdb->pagesize - 1) & ~(idxdb->pagesize - 1);
+ mapped = mmap(0, size, idxdb->rdonly ? PROT_READ : PROT_READ | PROT_WRITE, MAP_SHARED, idxdb->fd, 0);
+ if (mapped == MAP_FAILED)
+ return RPMRC_FAIL;
+ set_mapped(idxdb, mapped, (unsigned int)stb.st_size);
+#else
+ return RPMRC_FAIL;
+#endif
+ }
+ return RPMRC_OK;
+}
+
+static void rpmidxUnmap(rpmidxdb idxdb)
+{
+ if (!idxdb->head_mapped)
+ return;
+ if (idxdb->xdb) {
+ rpmxdbUnmapBlob(idxdb->xdb, idxdb->xdbid);
+ } else {
+#ifdef IDXDB_FILESUPPORT
+ size_t size = idxdb->file_size;
+ /* round up for munmap */
+ size = (size + idxdb->pagesize - 1) & ~(idxdb->pagesize - 1);
+ munmap(idxdb->head_mapped, size);
+ set_mapped(idxdb, 0, 0);
+#else
+ return;
+#endif
+ }
+}
+
+#ifdef IDXDB_FILESUPPORT
+static int rpmidxReadHeader(rpmidxdb idxdb);
+
+/* re-open file to get the new version */
+static int rpmidxHandleObsolete(rpmidxdb idxdb)
+{
+ int nfd;
+ struct stat stb1, stb2;
+
+ if (fstat(idxdb->fd, &stb1))
+ return RPMRC_FAIL;
+ nfd = open(idxdb->filename, idxdb->rdonly ? O_RDONLY : O_RDWR, 0);
+ if (nfd == -1)
+ return RPMRC_FAIL;
+ if (fstat(nfd, &stb2)) {
+ close(nfd);
+ return RPMRC_FAIL;
+ }
+ if (stb1.st_dev == stb2.st_dev && stb1.st_ino == stb2.st_ino)
+ return RPMRC_FAIL; /* openend the same obsolete file */
+ rpmidxUnmap(idxdb);
+ close(idxdb->fd);
+ idxdb->fd = nfd;
+ return rpmidxReadHeader(idxdb); /* re-try with new file */
+}
+#endif
+
+static int rpmidxReadHeader(rpmidxdb idxdb)
+{
+ unsigned int version;
+
+ if (idxdb->head_mapped) {
+ if (le2ha(idxdb->head_mapped + IDXDB_OFFSET_GENERATION) == idxdb->generation)
+ return RPMRC_OK;
+ rpmidxUnmap(idxdb);
+ }
+ idxdb->nslots = 0;
+ if (rpmidxMap(idxdb))
+ return RPMRC_FAIL;
+
+ if (le2ha(idxdb->head_mapped + IDXDB_OFFSET_MAGIC) != IDXDB_MAGIC) {
+ rpmidxUnmap(idxdb);
+ return RPMRC_FAIL;
+ }
+ version = le2ha(idxdb->head_mapped + IDXDB_OFFSET_VERSION);
+ if (version != IDXDB_VERSION) {
+ rpmlog(RPMLOG_ERR, _("rpmidx: Version mismatch. Expected version: %u. "
+ "Found version: %u\n"), IDXDB_VERSION, version);
+ rpmidxUnmap(idxdb);
+ return RPMRC_FAIL;
+ }
+#ifdef IDXDB_FILESUPPORT
+ if (!idxdb->xdb && le2ha(idxdb->head_mapped + IDXDB_OFFSET_OBSOLETE))
+ return rpmidxHandleObsolete(idxdb);
+#endif
+ idxdb->generation = le2ha(idxdb->head_mapped + IDXDB_OFFSET_GENERATION);
+ idxdb->nslots = le2ha(idxdb->head_mapped + IDXDB_OFFSET_NSLOTS);
+ idxdb->usedslots = le2ha(idxdb->head_mapped + IDXDB_OFFSET_USEDSLOTS);
+ idxdb->dummyslots = le2ha(idxdb->head_mapped + IDXDB_OFFSET_DUMMYSLOTS);
+ idxdb->xmask = le2ha(idxdb->head_mapped + IDXDB_OFFSET_XMASK);
+ idxdb->keyend = le2ha(idxdb->head_mapped + IDXDB_OFFSET_KEYEND);
+ idxdb->keyexcess = le2ha(idxdb->head_mapped + IDXDB_OFFSET_KEYEXCESS);
+
+ idxdb->hmask = idxdb->nslots - 1;
+
+ /* now that we know nslots we can split between slots and keys */
+ if (idxdb->file_size <= IDXDB_SLOT_OFFSET + idxdb->nslots * 12) {
+ rpmidxUnmap(idxdb); /* too small, somthing is wrong */
+ return RPMRC_FAIL;
+ }
+ idxdb->key_mapped = idxdb->slot_mapped + idxdb->nslots * 12;
+ idxdb->key_size = idxdb->file_size - (IDXDB_SLOT_OFFSET + idxdb->nslots * 12);
+ return RPMRC_OK;
+}
+
+static int rpmidxWriteHeader(rpmidxdb idxdb)
+{
+ if (!idxdb->head_mapped)
+ return RPMRC_FAIL;
+ h2lea(IDXDB_MAGIC, idxdb->head_mapped + IDXDB_OFFSET_MAGIC);
+ h2lea(IDXDB_VERSION, idxdb->head_mapped + IDXDB_OFFSET_VERSION);
+ h2lea(idxdb->generation, idxdb->head_mapped + IDXDB_OFFSET_GENERATION);
+ h2lea(idxdb->nslots, idxdb->head_mapped + IDXDB_OFFSET_NSLOTS);
+ h2lea(idxdb->usedslots, idxdb->head_mapped + IDXDB_OFFSET_USEDSLOTS);
+ h2lea(idxdb->dummyslots, idxdb->head_mapped + IDXDB_OFFSET_DUMMYSLOTS);
+ h2lea(idxdb->xmask, idxdb->head_mapped + IDXDB_OFFSET_XMASK);
+ h2lea(idxdb->keyend, idxdb->head_mapped + IDXDB_OFFSET_KEYEND);
+ h2lea(idxdb->keyexcess, idxdb->head_mapped + IDXDB_OFFSET_KEYEXCESS);
+ return RPMRC_OK;
+}
+
+static inline void updateUsedslots(rpmidxdb idxdb)
+{
+ h2lea(idxdb->usedslots, idxdb->head_mapped + IDXDB_OFFSET_USEDSLOTS);
+}
+
+static inline void updateDummyslots(rpmidxdb idxdb)
+{
+ h2lea(idxdb->dummyslots, idxdb->head_mapped + IDXDB_OFFSET_DUMMYSLOTS);
+}
+
+static inline void updateKeyend(rpmidxdb idxdb)
+{
+ h2lea(idxdb->keyend, idxdb->head_mapped + IDXDB_OFFSET_KEYEND);
+}
+
+static inline void updateKeyexcess(rpmidxdb idxdb)
+{
+ h2lea(idxdb->keyexcess, idxdb->head_mapped + IDXDB_OFFSET_KEYEXCESS);
+}
+
+static inline void bumpGeneration(rpmidxdb idxdb)
+{
+ idxdb->generation++;
+ h2lea(idxdb->generation, idxdb->head_mapped + IDXDB_OFFSET_GENERATION);
+}
+
+#ifdef IDXDB_FILESUPPORT
+static int createempty(rpmidxdb idxdb, off_t off, size_t size)
+{
+ char buf[4096];
+ memset(buf, 0, sizeof(buf));
+ while (size >= 4096) {
+ if (pwrite(idxdb->fd, buf, 4096, off) != 4096)
+ return RPMRC_FAIL;
+ off += 4096;
+ size -= 4096;
+ }
+ if (size > 0 && pwrite(idxdb->fd, buf, size , off) != size)
+ return RPMRC_FAIL;
+ return RPMRC_OK;
+}
+#endif
+
+/*** Key management ***/
+
+#define MURMUR_M 0x5bd1e995
+
+static unsigned int murmurhash(const unsigned char *s, unsigned int l)
+{
+ unsigned int h = l * MURMUR_M;
+
+ while (l >= 4) {
+ h += s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+ h *= MURMUR_M;
+ h ^= h >> 16;
+ s += 4;
+ l -= 4;
+ }
+ switch (l) {
+ case 3:
+ h += s[2] << 16;
+ case 2:
+ h += s[1] << 8;
+ case 1:
+ h += s[0];
+ h *= MURMUR_M;
+ h ^= h >> 16;
+ default:
+ break;
+ }
+ h *= MURMUR_M;
+ h ^= h >> 10;
+ h *= MURMUR_M;
+ h ^= h >> 17;
+ return h;
+}
+
+static inline unsigned int decodekeyl(unsigned char *p, unsigned int *hl)
+{
+ if (*p != 255) {
+ *hl = 1;
+ return *p;
+ } else if (p[1] != 255 || p[2] != 255) {
+ *hl = 3;
+ return p[1] | p[2] << 8;
+ } else {
+ *hl = 7;
+ return p[3] | p[4] << 8 | p[5] << 16 | p[6] << 24;
+ }
+}
+
+static inline void encodekeyl(unsigned char *p, unsigned int keyl)
+{
+ if (keyl && keyl < 255) {
+ p[0] = keyl;
+ } else if (keyl < 65535) {
+ p[0] = 255;
+ p[1] = keyl;
+ p[2] = keyl >> 8;
+ } else {
+ p[0] = 255;
+ p[1] = 255;
+ p[2] = 255;
+ p[3] = keyl;
+ p[4] = keyl >> 8;
+ p[5] = keyl >> 16;
+ p[6] = keyl >> 24;
+ }
+}
+
+static inline unsigned int keylsize(unsigned int keyl)
+{
+ return keyl && keyl < 255 ? 1 : keyl < 65535 ? 3 : 7;
+}
+
+static inline int equalkey(rpmidxdb idxdb, unsigned int off, const unsigned char *key, unsigned int keyl)
+{
+ unsigned char *p;
+ if (off + keyl + 1 > idxdb->keyend)
+ return 0;
+ p = idxdb->key_mapped + off;
+ if (keyl && keyl < 255) {
+ if (*p != keyl)
+ return 0;
+ p += 1;
+ } else if (keyl < 65535) {
+ if (p[0] != 255 || (p[1] | p[2] << 8) != keyl)
+ return 0;
+ p += 3;
+ } else {
+ if (p[0] != 255 || p[1] != 255 || p[2] != 255 || (p[3] | p[4] << 8 | p[5] << 16 | p[6] << 24) != keyl)
+ return 0;
+ p += 7;
+ }
+ if (keyl && memcmp(key, p, keyl))
+ return 0;
+ return 1;
+}
+
+static int addkeypage(rpmidxdb idxdb) {
+ unsigned int addsize = idxdb->pagesize > IDXDB_KEY_CHUNKSIZE ? idxdb->pagesize : IDXDB_KEY_CHUNKSIZE;
+
+ if (idxdb->xdb) {
+ if (rpmxdbResizeBlob(idxdb->xdb, idxdb->xdbid, idxdb->file_size + addsize))
+ return RPMRC_FAIL;
+ } else {
+#ifdef IDXDB_FILESUPPORT
+ /* don't use ftruncate because we want to create a "backed" page */
+ void *newaddr;
+ size_t oldsize, newsize;
+ if (createempty(idxdb, idxdb->file_size, addsize))
+ return RPMRC_FAIL;
+ oldsize = idxdb->file_size;
+ newsize = idxdb->file_size + addsize;
+ /* round up for mremap */
+ oldsize = (oldsize + idxdb->pagesize - 1) & ~(idxdb->pagesize - 1);
+ newsize = (newsize + idxdb->pagesize - 1) & ~(idxdb->pagesize - 1);
+ newaddr = mremap(idxdb->head_mapped, oldsize, newsize, MREMAP_MAYMOVE);
+ if (newaddr == MAP_FAILED)
+ return RPMRC_FAIL;
+ set_mapped(idxdb, newaddr, idxdb->file_size + addsize);
+#else
+ return RPMRC_FAIL;
+#endif
+ }
+ return RPMRC_OK;
+}
+
+static int addnewkey(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int *keyoffp)
+{
+ int hl = keylsize(keyl);
+ while (idxdb->key_size - idxdb->keyend < hl + keyl) {
+ if (addkeypage(idxdb))
+ return RPMRC_FAIL;
+ }
+ encodekeyl(idxdb->key_mapped + idxdb->keyend, keyl);
+ if (keyl)
+ memcpy(idxdb->key_mapped + idxdb->keyend + hl, key, keyl);
+ *keyoffp = idxdb->keyend;
+ idxdb->keyend += hl + keyl;
+ updateKeyend(idxdb);
+ return RPMRC_OK;
+}
+
+
+/*** Data encoding/decoding ***/
+
+/* Encode a (pkgidx, datidx) tuple into a (data, ovldata) tuple in a way
+ * that most of the time ovldata will be zero. */
+static inline unsigned int encodedata(rpmidxdb idxdb, unsigned int pkgidx, unsigned int datidx, unsigned int *ovldatap)
+{
+ if (pkgidx < 0x100000 && datidx < 0x400) {
+ *ovldatap = 0;
+ return pkgidx | datidx << 20;
+ } else if (pkgidx < 0x1000000 && datidx < 0x40) {
+ *ovldatap = 0;
+ return pkgidx | datidx << 24 | 0x40000000;
+ } else {
+ *ovldatap = pkgidx;
+ return datidx | 0x80000000;
+ }
+}
+
+/* Decode (data, ovldata) back into (pkgidx, datidx) */
+static inline unsigned int decodedata(rpmidxdb idxdb, unsigned int data, unsigned int ovldata, unsigned int *datidxp)
+{
+ if (data & 0x80000000) {
+ *datidxp = data ^ 0x80000000;
+ return ovldata;
+ } else if (data & 0x40000000) {
+ *datidxp = (data ^ 0x40000000) >> 24;
+ return data & 0xffffff;
+ } else {
+ *datidxp = data >> 20;
+ return data & 0xfffff;
+ }
+}
+
+
+/*** Rebuild helpers ***/
+
+/* copy a single data entry into the new database */
+static inline void copyentry(rpmidxdb idxdb, unsigned int keyh, unsigned int newkeyoff, unsigned int data, unsigned int ovldata)
+{
+ unsigned int h, hh = 7;
+ unsigned char *ent;
+ unsigned int hmask = idxdb->hmask;
+ unsigned int x;
+
+ /* find an empty slot */
+ for (h = keyh & hmask;; h = (h + hh++) & hmask) {
+ ent = idxdb->slot_mapped + 8 * h;
+ x = le2ha(ent);
+ if (x == 0)
+ break;
+ }
+ /* write data */
+ h2lea(newkeyoff, ent);
+ h2lea(data, ent + 4);
+ if (ovldata)
+ h2lea(ovldata, idxdb->slot_mapped + idxdb->nslots * 8 + 4 * h);
+ idxdb->usedslots++;
+}
+
+/* copy all entries belonging to a single key from the old database into the new database */
+static inline void copykeyentries(const unsigned char *key, unsigned int keyl, rpmidxdb idxdb, unsigned int oldkeyoff, rpmidxdb nidxdb, unsigned int newkeyoff, unsigned char *done)
+{
+ unsigned int h, hh;
+ unsigned int keyh = murmurhash(key, keyl);
+ unsigned int hmask = idxdb->hmask;
+
+ oldkeyoff |= keyh & idxdb->xmask;
+ newkeyoff |= keyh & nidxdb->xmask;
+ for (h = keyh & hmask, hh = 7; ; h = (h + hh++) & hmask) {
+ unsigned char *ent = idxdb->slot_mapped + 8 * h;
+ unsigned int data, ovldata;
+ unsigned int x = le2ha(ent);
+ if (x == 0)
+ break;
+ if (x != oldkeyoff)
+ continue;
+ data = le2ha(ent + 4);
+ ovldata = (data & 0x80000000) ? le2ha(idxdb->slot_mapped + idxdb->nslots * 8 + 4 * h) : 0;
+ copyentry(nidxdb, keyh, newkeyoff, data, ovldata);
+ done[h >> 3] |= 1 << (h & 7);
+ }
+}
+
+static int rpmidxRebuildInternal(rpmidxdb idxdb)
+{
+ struct rpmidxdb_s nidxdb_s, *nidxdb;
+ unsigned int i, nslots;
+ unsigned int keyend, keyoff, xmask;
+ unsigned char *done;
+ unsigned char *ent;
+ unsigned int file_size, key_size, xfile_size;
+
+ nidxdb = &nidxdb_s;
+ memset(nidxdb, 0, sizeof(*nidxdb));
+ nidxdb->pagesize = sysconf(_SC_PAGE_SIZE);
+
+ /* calculate nslots the hard way, don't trust usedslots */
+ nslots = 0;
+ for (i = 0, ent = idxdb->slot_mapped; i < idxdb->nslots; i++, ent += 8) {
+ unsigned int x = le2ha(ent);
+ if (x != 0 && x != -1)
+ nslots++;
+ }
+ if (nslots < 256)
+ nslots = 256;
+ while (nslots & (nslots - 1))
+ nslots = nslots & (nslots - 1);
+ nslots *= 4;
+
+ nidxdb->nslots = nslots;
+ nidxdb->hmask = nslots - 1;
+
+ /* calculate the new key space size */
+ key_size = idxdb->keyend;
+ if (key_size < IDXDB_KEY_CHUNKSIZE)
+ key_size = IDXDB_KEY_CHUNKSIZE;
+ file_size = IDXDB_SLOT_OFFSET + nslots * 12 + key_size;
+
+ /* round file size to multiple of the page size */
+ if (file_size & (nidxdb->pagesize - 1)) {
+ unsigned int add = nidxdb->pagesize - (file_size & (nidxdb->pagesize - 1));
+ file_size += add;
+ key_size += add;
+ }
+
+ /* calculate xmask, leave at least 8192 bytes headroom for key space */
+ for (xmask = 0x00010000; xmask && xmask < key_size + 8192; xmask <<= 1)
+ ;
+ xmask = xmask ? ~(xmask - 1) : 0;
+ nidxdb->xmask = xmask;
+
+ /* create new database */
+ if (idxdb->xdb) {
+ nidxdb->xdb = idxdb->xdb;
+ nidxdb->xdbtag = idxdb->xdbtag;
+ if (rpmxdbLookupBlob(nidxdb->xdb, &nidxdb->xdbid, idxdb->xdbtag, IDXDB_XDB_SUBTAG_REBUILD, O_CREAT|O_TRUNC)) {
+ return RPMRC_FAIL;
+ }
+ if (rpmxdbResizeBlob(nidxdb->xdb, nidxdb->xdbid, file_size)) {
+ return RPMRC_FAIL;
+ }
+ if (rpmidxMap(nidxdb)) {
+ return RPMRC_FAIL;
+ }
+ } else {
+#ifdef IDXDB_FILESUPPORT
+ void *mapped;
+ nidxdb->filename = malloc(strlen(idxdb->filename) + 8);
+ if (!nidxdb->filename)
+ return RPMRC_FAIL;
+ sprintf(nidxdb->filename, "%s-XXXXXX", idxdb->filename);
+ nidxdb->fd = mkstemp(nidxdb->filename);
+ if (nidxdb->fd == -1) {
+ free(nidxdb->filename);
+ return RPMRC_FAIL;
+ }
+ if (createempty(nidxdb, 0, file_size)) {
+ close(nidxdb->fd);
+ unlink(nidxdb->filename);
+ free(nidxdb->filename);
+ return RPMRC_FAIL;
+ }
+ mapped = mmap(0, file_size, idxdb->rdonly ? PROT_READ : PROT_READ | PROT_WRITE, MAP_SHARED, nidxdb->fd, 0);
+ if (mapped == MAP_FAILED) {
+ close(nidxdb->fd);
+ unlink(nidxdb->filename);
+ free(nidxdb->filename);
+ return RPMRC_FAIL;
+ }
+ set_mapped(nidxdb, mapped, file_size);
+#else
+ return RPMRC_FAIL;
+#endif
+ }
+
+ /* copy all entries */
+ done = calloc(idxdb->nslots / 8 + 1, 1);
+ if (!done) {
+ rpmidxUnmap(nidxdb);
+ if (!idxdb->xdb) {
+ close(nidxdb->fd);
+ unlink(nidxdb->filename);
+ free(nidxdb->filename);
+ }
+ return RPMRC_FAIL;
+ }
+ keyend = 1;
+ for (i = 0, ent = idxdb->slot_mapped; i < idxdb->nslots; i++, ent += 8) {
+ unsigned int x = le2ha(ent);
+ unsigned char *key;
+ unsigned int keyl, hl;
+
+ if (x == 0 || x == -1)
+ continue;
+ if (done[i >> 3] & (1 << (i & 7))) {
+ continue; /* we already did that one */
+ }
+ x &= ~idxdb->xmask;
+ key = idxdb->key_mapped + x;
+ keyl = decodekeyl(key, &hl);
+ keyoff = keyend;
+ keyend += hl + keyl;
+ memcpy(nidxdb->key_mapped + keyoff, key, hl + keyl);
+ copykeyentries(key + hl, keyl, idxdb, x, nidxdb, keyoff, done);
+ }
+ free(done);
+ nidxdb->keyend = keyend;
+ nidxdb->generation = idxdb->generation + 1;
+ rpmidxWriteHeader(nidxdb);
+ rpmidxUnmap(nidxdb);
+
+ /* shrink if we have allocated excessive key space */
+ xfile_size = file_size - key_size + keyend + IDXDB_KEY_CHUNKSIZE;
+ xfile_size = (xfile_size + nidxdb->pagesize - 1) & ~(nidxdb->pagesize - 1);
+ if (xfile_size < file_size) {
+ if (nidxdb->xdb) {
+ rpmxdbResizeBlob(nidxdb->xdb, nidxdb->xdbid, xfile_size);
+ } else {
+ if (ftruncate(nidxdb->fd, xfile_size)) {
+ rpmlog(RPMLOG_WARNING, _("truncate failed: %s\n"), strerror(errno));
+ }
+ }
+ }
+
+ /* now switch over to new database */
+ if (idxdb->xdb) {
+ rpmidxUnmap(idxdb);
+ if (rpmxdbRenameBlob(nidxdb->xdb, &nidxdb->xdbid, idxdb->xdbtag, IDXDB_XDB_SUBTAG))
+ return RPMRC_FAIL;
+ idxdb->xdbid = nidxdb->xdbid;
+ } else {
+#ifdef IDXDB_FILESUPPORT
+ if (rename(nidxdb->filename, idxdb->filename)) {
+ close(nidxdb->fd);
+ unlink(nidxdb->filename);
+ free(nidxdb->filename);
+ return RPMRC_FAIL;
+ }
+ if (idxdb->head_mapped) {
+ h2lea(1, idxdb->head_mapped + IDXDB_OFFSET_OBSOLETE);
+ bumpGeneration(idxdb);
+ rpmidxUnmap(idxdb);
+ }
+ free(nidxdb->filename);
+ close(idxdb->fd);
+ idxdb->fd = nidxdb->fd;
+#else
+ return RPMRC_FAIL;
+#endif
+ }
+ if (rpmidxReadHeader(idxdb))
+ return RPMRC_FAIL;
+ return RPMRC_OK;
+}
+
+/* check if we need to rebuild the index. We need to do this if
+ * - there are too many used slot, so hashing is inefficient
+ * - there is too much key excess (i.e. holes in the keys)
+ * - our keys grew so much that they need more bits
+ */
+static int rpmidxCheck(rpmidxdb idxdb)
+{
+ if (idxdb->usedslots * 2 > idxdb->nslots ||
+ (idxdb->keyexcess > 4096 && idxdb->keyexcess * 4 > idxdb->keyend) ||
+ idxdb->keyend >= ~idxdb->xmask) {
+ if (rpmidxRebuildInternal(idxdb))
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static int rpmidxPutInternal(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int pkgidx, unsigned int datidx)
+{
+ unsigned int keyh = murmurhash(key, keyl);
+ unsigned int keyoff = 0;
+ unsigned int freeh = -1;
+ unsigned int x, h, hh = 7;
+ unsigned int hmask;
+ unsigned int xmask;
+ unsigned char *ent;
+ unsigned int data, ovldata;
+
+ if (datidx >= 0x80000000)
+ return RPMRC_FAIL;
+ if (rpmidxCheck(idxdb))
+ return RPMRC_FAIL;
+ data = encodedata(idxdb, pkgidx, datidx, &ovldata);
+ hmask = idxdb->hmask;
+ xmask = idxdb->xmask;
+ for (h = keyh & hmask; ; h = (h + hh++) & hmask) {
+ ent = idxdb->slot_mapped + 8 * h;
+ x = le2ha(ent);
+ if (x == 0) /* reached an empty slot */
+ break;
+ if (x == -1) {
+ freeh = h; /* found a dummy slot, remember the position */
+ continue;
+ }
+ if (!keyoff) {
+ if (((x ^ keyh) & xmask) != 0)
+ continue;
+ if (!equalkey(idxdb, x & ~xmask, key, keyl))
+ continue;
+ keyoff = x;
+ }
+ if (keyoff != x)
+ continue;
+ /* string matches, check data/ovldata */
+ if (le2ha(ent + 4) == data) {
+ if (!ovldata || le2ha(idxdb->slot_mapped + idxdb->nslots * 8 + 4 * h) == ovldata)
+ return RPMRC_OK; /* already in database */
+ }
+ /* continue searching */
+ }
+ if (!keyoff) {
+ /* we did not find this key. add it */
+ if (addnewkey(idxdb, key, keyl, &keyoff))
+ return RPMRC_FAIL;
+ keyoff |= keyh & xmask; /* tag it with the extra bits */
+ /* re-calculate ent, addnewkey may have changed the mapping! */
+ ent = idxdb->slot_mapped + 8 * h;
+ }
+ if (freeh == -1) {
+ /* did not find a dummy slot, so use the current empty slot */
+ idxdb->usedslots++;
+ updateUsedslots(idxdb);
+ } else {
+ /* re-use dummy slot */
+ h = freeh;
+ ent = idxdb->slot_mapped + 8 * h;
+ if (idxdb->dummyslots) {
+ idxdb->dummyslots--;
+ updateDummyslots(idxdb);
+ }
+ }
+ h2lea(keyoff, ent);
+ h2lea(data, ent + 4);
+ if (ovldata)
+ h2lea(ovldata, idxdb->slot_mapped + idxdb->nslots * 8 + 4 * h);
+ bumpGeneration(idxdb);
+ return RPMRC_OK;
+}
+
+static int rpmidxDelInternal(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int pkgidx, unsigned int datidx)
+{
+ unsigned int keyoff = 0;
+ unsigned int keyh = murmurhash(key, keyl);
+ unsigned int hmask;
+ unsigned int xmask;
+ unsigned int x, h, hh = 7;
+ int otherusers = 0;
+ unsigned int data, ovldata;
+
+ if (datidx >= 0x80000000)
+ return RPMRC_FAIL;
+ if (rpmidxCheck(idxdb))
+ return RPMRC_FAIL;
+ data = encodedata(idxdb, pkgidx, datidx, &ovldata);
+ hmask = idxdb->hmask;
+ xmask = idxdb->xmask;
+ for (h = keyh & hmask; ; h = (h + hh++) & hmask) {
+ unsigned char *ent = idxdb->slot_mapped + 8 * h;
+ x = le2ha(ent);
+ if (x == 0)
+ break;
+ if (x == -1)
+ continue;
+ if (!keyoff) {
+ if (((x ^ keyh) & xmask) != 0)
+ continue;
+ if (!equalkey(idxdb, x & ~xmask, key, keyl))
+ continue;
+ keyoff = x;
+ }
+ if (keyoff != x)
+ continue;
+ /* key matches, check data/ovldata */
+ if (le2ha(ent + 4) != data) {
+ otherusers = 1;
+ continue;
+ }
+ if (ovldata && le2ha(idxdb->slot_mapped + idxdb->nslots * 8 + 4 * h) != ovldata) {
+ otherusers = 1;
+ continue;
+ }
+ /* found a match. convert entry to a dummy slot */
+ h2lea(-1, ent);
+ h2lea(-1, ent + 4);
+ if (ovldata)
+ h2lea(0, idxdb->slot_mapped + idxdb->nslots * 8 + 4 * h);
+ idxdb->dummyslots++;
+ updateDummyslots(idxdb);
+ /* continue searching (so that we find other users of the key...) */
+ }
+ if (keyoff && !otherusers) {
+ /* key is no longer in use. free it */
+ int hl = keylsize(keyl);
+ memset(idxdb->key_mapped + (keyoff & ~xmask), 0, hl + keyl);
+ idxdb->keyexcess += hl + keyl;
+ updateKeyexcess(idxdb);
+ }
+ if (keyoff)
+ bumpGeneration(idxdb);
+ return RPMRC_OK;
+}
+
+static int rpmidxGetInternal(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int **pkgidxlistp, unsigned int *pkgidxnump)
+{
+ unsigned int keyoff = 0;
+ unsigned int keyh = murmurhash(key, keyl);
+ unsigned int hmask = idxdb->hmask;
+ unsigned int xmask = idxdb->xmask;
+ unsigned int x, h, hh = 7;
+ unsigned int data, ovldata, datidx;
+ unsigned int nhits = 0;
+ unsigned int *hits = 0;
+ for (h = keyh & hmask; ; h = (h + hh++) & hmask) {
+ unsigned char *ent = idxdb->slot_mapped + 8 * h;
+ x = le2ha(ent);
+ if (x == 0)
+ break;
+ if (x == -1)
+ continue;
+ if (!keyoff) {
+ if (((x ^ keyh) & xmask) != 0)
+ continue;
+ if (!equalkey(idxdb, x & ~xmask, key, keyl))
+ continue;
+ keyoff = x;
+ }
+ if (keyoff != x)
+ continue;
+ if ((nhits & 15) == 0) {
+ if (!hits) {
+ hits = malloc(16 * sizeof(unsigned int));
+ } else {
+ hits = realloc(hits, (nhits + 16) * sizeof(unsigned int));
+ }
+ if (!hits)
+ return RPMRC_FAIL;
+ }
+ data = le2ha(ent + 4);
+ ovldata = (data & 0x80000000) ? le2ha(idxdb->slot_mapped + idxdb->nslots * 8 + 4 * h) : 0;
+ hits[nhits++] = decodedata(idxdb, data, ovldata, &datidx);
+ hits[nhits++] = datidx;
+ }
+ *pkgidxlistp = hits;
+ *pkgidxnump = nhits;
+ return nhits ? RPMRC_OK : RPMRC_NOTFOUND;
+}
+
+static int rpmidxListSort_cmp(const void *a, const void *b)
+{
+ return ((unsigned int *)a)[1] - ((unsigned int *)b)[1];
+}
+
+/* sort in hash offset order, so that we get sequential acceess */
+static void rpmidxListSort(rpmidxdb idxdb, unsigned int *keylist, unsigned int nkeylist, unsigned char *data)
+{
+ unsigned int i, *arr;
+ if (nkeylist < 2 * 2)
+ return;
+ arr = malloc(nkeylist * sizeof(unsigned int));
+ if (!arr)
+ return;
+ for (i = 0; i < nkeylist; i += 2) {
+ arr[i] = i;
+ arr[i + 1] = murmurhash(data + keylist[i], keylist[i + 1]) & idxdb->hmask;
+ }
+ qsort(arr, nkeylist / 2, 2 * sizeof(unsigned int), rpmidxListSort_cmp);
+ for (i = 0; i < nkeylist; i += 2) {
+ unsigned int ai = arr[i];
+ arr[i] = keylist[ai];
+ arr[i + 1] = keylist[ai + 1];
+ }
+ memcpy(keylist, arr, nkeylist * sizeof(unsigned int));
+ free(arr);
+}
+
+static int rpmidxListInternal(rpmidxdb idxdb, unsigned int **keylistp, unsigned int *nkeylistp, unsigned char **datap)
+{
+ unsigned int *keylist = 0;
+ unsigned int nkeylist = 0;
+ unsigned char *data, *terminate, *key, *keyendp;
+
+ data = malloc(idxdb->keyend + 1); /* +1 so we can terminate the last key */
+ if (!data)
+ return RPMRC_FAIL;
+ memcpy(data, idxdb->key_mapped, idxdb->keyend);
+ keylist = malloc(16 * sizeof(*keylist));
+ if (!keylist) {
+ free(data);
+ return RPMRC_FAIL;
+ }
+ terminate = 0;
+ for (key = data + 1, keyendp = data + idxdb->keyend; key < keyendp; ) {
+ unsigned int hl, keyl;
+ if (!*key) {
+ key++;
+ continue;
+ }
+ if ((nkeylist & 15) == 0) {
+ unsigned int *kl = realloc(keylist, (nkeylist + 16) * sizeof(*keylist));
+ if (!kl) {
+ free(keylist);
+ free(data);
+ return RPMRC_FAIL;
+ }
+ keylist = kl;
+ }
+ keyl = decodekeyl(key, &hl);
+ keylist[nkeylist++] = key + hl - data;
+ keylist[nkeylist++] = keyl;
+ key += hl + keyl;
+ if (terminate)
+ *terminate = 0;
+ terminate = key;
+ }
+ if (terminate)
+ *terminate = 0;
+ rpmidxListSort(idxdb, keylist, nkeylist, data);
+ *keylistp = keylist;
+ *nkeylistp = nkeylist;
+ *datap = data;
+ return RPMRC_OK;
+}
+
+
+static int rpmidxInitInternal(rpmidxdb idxdb)
+{
+ if (idxdb->xdb) {
+ unsigned int id;
+ int rc = rpmxdbLookupBlob(idxdb->xdb, &id, idxdb->xdbtag, IDXDB_XDB_SUBTAG, 0);
+ if (rc == RPMRC_OK && id) {
+ idxdb->xdbid = id;
+ return RPMRC_OK; /* somebody else was faster */
+ }
+ if (rc && rc != RPMRC_NOTFOUND)
+ return rc;
+ } else {
+#ifdef IDXDB_FILESUPPORT
+ struct stat stb;
+ if (stat(idxdb->filename, &stb))
+ return RPMRC_FAIL;
+ if (stb.st_size) /* somebody else was faster */
+ return rpmidxHandleObsolete(idxdb);
+#else
+ return RPMRC_FAIL;
+#endif
+ }
+ return rpmidxRebuildInternal(idxdb);
+}
+
+static int rpmidxLock(rpmidxdb idxdb, int excl)
+{
+ if (excl && idxdb->rdonly)
+ return RPMRC_FAIL;
+ if (idxdb->xdb)
+ return rpmxdbLock(idxdb->xdb, excl);
+ else
+ return rpmpkgLock(idxdb->pkgdb, excl);
+}
+
+static int rpmidxUnlock(rpmidxdb idxdb, int excl)
+{
+ if (idxdb->xdb)
+ return rpmxdbUnlock(idxdb->xdb, excl);
+ else
+ return rpmpkgUnlock(idxdb->pkgdb, excl);
+}
+
+static int rpmidxLockReadHeader(rpmidxdb idxdb, int excl)
+{
+ if (rpmidxLock(idxdb, excl))
+ return RPMRC_FAIL;
+ if (rpmidxReadHeader(idxdb)) {
+ rpmidxUnlock(idxdb, excl);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static int rpmidxInit(rpmidxdb idxdb)
+{
+ int rc;
+ if (rpmidxLock(idxdb, 1))
+ return RPMRC_FAIL;
+ rc = rpmidxInitInternal(idxdb);
+ rpmidxUnlock(idxdb, 1);
+ return rc;
+}
+
+int rpmidxOpen(rpmidxdb *idxdbp, rpmpkgdb pkgdb, const char *filename, int flags, int mode)
+{
+#ifdef IDXDB_FILESUPPORT
+ struct stat stb;
+ rpmidxdb idxdb;
+
+ *idxdbp = 0;
+ idxdb = calloc(1, sizeof(*idxdb));
+ if (!idxdb)
+ return RPMRC_FAIL;
+ idxdb->filename = strdup(filename);
+ if (!idxdb->filename) {
+ free(idxdb);
+ return RPMRC_FAIL;
+ }
+ if ((flags & (O_RDONLY|O_RDWR)) == O_RDONLY)
+ idxdb->rdonly = 1;
+ if ((idxdb->fd = open(filename, flags, mode)) == -1) {
+ free(idxdb->filename);
+ free(idxdb);
+ return RPMRC_FAIL;
+ }
+ if (fstat(idxdb->fd, &stb)) {
+ close(idxdb->fd);
+ free(idxdb->filename);
+ free(idxdb);
+ return RPMRC_FAIL;
+ }
+ idxdb->pkgdb = pkgdb;
+ idxdb->flags = flags;
+ idxdb->mode = mode;
+ idxdb->pagesize = sysconf(_SC_PAGE_SIZE);
+ if (stb.st_size == 0) {
+ if (rpmidxInit(idxdb)) {
+ close(idxdb->fd);
+ free(idxdb->filename);
+ free(idxdb);
+ return RPMRC_FAIL;
+ }
+ }
+ *idxdbp = idxdb;
+ return RPMRC_OK;
+#else
+ return RPMRC_FAIL;
+#endif
+}
+
+int rpmidxOpenXdb(rpmidxdb *idxdbp, rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag)
+{
+ rpmidxdb idxdb;
+ unsigned int id;
+ *idxdbp = 0;
+ int rc;
+
+ if (rpmxdbLock(xdb, 0))
+ return RPMRC_FAIL;
+ rc = rpmxdbLookupBlob(xdb, &id, xdbtag, IDXDB_XDB_SUBTAG, 0);
+ if (rc == RPMRC_NOTFOUND)
+ id = 0;
+ else if (rc) {
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_FAIL;
+ }
+ idxdb = calloc(1, sizeof(*idxdb));
+ if (!idxdb) {
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_FAIL;
+ }
+ idxdb->fd = -1;
+ idxdb->xdb = xdb;
+ idxdb->xdbtag = xdbtag;
+ idxdb->xdbid = id;
+ idxdb->pkgdb = pkgdb;
+ idxdb->pagesize = sysconf(_SC_PAGE_SIZE);
+ if (rpmxdbIsRdonly(xdb))
+ idxdb->rdonly = 1;
+ if (!id) {
+ if (rpmidxInit(idxdb)) {
+ free(idxdb);
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_FAIL;
+ }
+ }
+ *idxdbp = idxdb;
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_OK;
+}
+
+int rpmidxDelXdb(rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag)
+{
+ unsigned int id;
+ int rc;
+ if (rpmxdbLock(xdb, 1))
+ return RPMRC_FAIL;
+ rc = rpmxdbLookupBlob(xdb, &id, xdbtag, IDXDB_XDB_SUBTAG, 0);
+ if (rc == RPMRC_NOTFOUND)
+ id = 0;
+ else if (rc) {
+ rpmxdbUnlock(xdb, 1);
+ return rc;
+ }
+ if (id && rpmxdbDelBlob(xdb, id)) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+}
+
+void rpmidxClose(rpmidxdb idxdb)
+{
+ rpmidxUnmap(idxdb);
+ if (idxdb->fd >= 0) {
+ close(idxdb->fd);
+ idxdb->fd = -1;
+ }
+ if (idxdb->filename)
+ free(idxdb->filename);
+ free(idxdb);
+}
+
+int rpmidxPut(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int pkgidx, unsigned int datidx)
+{
+ int rc;
+ if (!pkgidx || datidx >= 0x80000000) {
+ return RPMRC_FAIL;
+ }
+ if (rpmidxLockReadHeader(idxdb, 1))
+ return RPMRC_FAIL;
+ rc = rpmidxPutInternal(idxdb, key, keyl, pkgidx, datidx);
+ rpmidxUnlock(idxdb, 1);
+ return rc;
+}
+
+int rpmidxDel(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int pkgidx, unsigned int datidx)
+{
+ int rc;
+ if (!pkgidx || datidx >= 0x80000000) {
+ return RPMRC_FAIL;
+ }
+ if (rpmidxLockReadHeader(idxdb, 1))
+ return RPMRC_FAIL;
+ rc = rpmidxDelInternal(idxdb, key, keyl, pkgidx, datidx);
+ rpmidxUnlock(idxdb, 1);
+ return rc;
+}
+
+int rpmidxGet(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int **pkgidxlistp, unsigned int *pkgidxnump)
+{
+ int rc;
+ *pkgidxlistp = 0;
+ *pkgidxnump = 0;
+ if (rpmidxLockReadHeader(idxdb, 0))
+ return RPMRC_FAIL;
+ rc = rpmidxGetInternal(idxdb, key, keyl, pkgidxlistp, pkgidxnump);
+ rpmidxUnlock(idxdb, 0);
+ return rc;
+}
+
+int rpmidxList(rpmidxdb idxdb, unsigned int **keylistp, unsigned int *nkeylistp, unsigned char **datap)
+{
+ int rc;
+ *keylistp = 0;
+ *nkeylistp = 0;
+ if (rpmidxLockReadHeader(idxdb, 0))
+ return RPMRC_FAIL;
+ rc = rpmidxListInternal(idxdb, keylistp, nkeylistp, datap);
+ rpmidxUnlock(idxdb, 0);
+ return rc;
+}
+
+int rpmidxStats(rpmidxdb idxdb)
+{
+ if (rpmidxLockReadHeader(idxdb, 0))
+ return RPMRC_FAIL;
+ printf("--- IndexDB Stats\n");
+ if (idxdb->xdb) {
+ printf("Xdb tag: %d, id: %d\n", idxdb->xdbtag, idxdb->xdbid);
+ } else {
+ printf("Filename: %s\n", idxdb->filename);
+ }
+ printf("Generation: %u\n", idxdb->generation);
+ printf("Slots: %u\n", idxdb->nslots);
+ printf("Used slots: %u\n", idxdb->usedslots);
+ printf("Dummy slots: %u\n", idxdb->dummyslots);
+ printf("Key data size: %u, left %u\n", idxdb->keyend, idxdb->key_size - idxdb->keyend);
+ printf("Key excess: %u\n", idxdb->keyexcess);
+ printf("XMask: 0x%08x\n", idxdb->xmask);
+ rpmidxUnlock(idxdb, 0);
+ return RPMRC_OK;
+}
diff --git a/lib/backend/ndb/rpmidx.h b/lib/backend/ndb/rpmidx.h
new file mode 100644
index 000000000..e89bd82f1
--- /dev/null
+++ b/lib/backend/ndb/rpmidx.h
@@ -0,0 +1,18 @@
+#include "rpmpkg.h"
+#include "rpmxdb.h"
+
+struct rpmidxdb_s;
+typedef struct rpmidxdb_s *rpmidxdb;
+
+int rpmidxOpen(rpmidxdb *idxdbp, rpmpkgdb pkgdb, const char *filename, int flags, int mode);
+int rpmidxOpenXdb(rpmidxdb *idxdbp, rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag);
+int rpmidxDelXdb(rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag);
+void rpmidxClose(rpmidxdb idxdbp);
+
+int rpmidxGet(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int **pkgidxlist, unsigned int *pkgidxnum);
+int rpmidxPut(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int pkgidx, unsigned int datidx);
+int rpmidxDel(rpmidxdb idxdb, const unsigned char *key, unsigned int keyl, unsigned int pkgidx, unsigned int datidx);
+int rpmidxList(rpmidxdb idxdb, unsigned int **keylistp, unsigned int *nkeylistp, unsigned char **datap);
+
+int rpmidxStats(rpmidxdb idxdb);
+
diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c
new file mode 100644
index 000000000..68b03eeb7
--- /dev/null
+++ b/lib/backend/ndb/rpmpkg.c
@@ -0,0 +1,1312 @@
+#include "system.h"
+
+#include <rpm/rpmlog.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libgen.h>
+
+#include "rpmpkg.h"
+
+#define RPMRC_FAIL 2
+#define RPMRC_NOTFOUND 1
+#define RPMRC_OK 0
+
+#ifdef RPMPKG_LZO
+static int rpmpkgLZOCompress(unsigned char **blobp, unsigned int *bloblp);
+static int rpmpkgLZODecompress(unsigned char **blobp, unsigned int *bloblp);
+#endif
+
+static int rpmpkgVerifyblob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt);
+
+typedef struct pkgslot_s {
+ unsigned int pkgidx;
+ unsigned int blkoff;
+ unsigned int blkcnt;
+ unsigned int slotno;
+} pkgslot;
+
+typedef struct rpmpkgdb_s {
+ int fd; /* our file descriptor */
+ int flags;
+ int mode;
+
+ int rdonly;
+
+ unsigned int locked_shared;
+ unsigned int locked_excl;
+
+ int header_ok; /* header data (e.g. generation) is valid */
+ unsigned int generation;
+ unsigned int slotnpages;
+ unsigned int nextpkgidx;
+
+ struct pkgslot_s *slots;
+ unsigned int aslots; /* allocated slots */
+ unsigned int nslots; /* used slots */
+
+ unsigned int *slothash;
+ unsigned int nslothash;
+
+ unsigned int freeslot; /* first free slot */
+ int slotorder;
+
+ char *filename;
+ unsigned int fileblks; /* file size in blks */
+ int dofsync;
+} * rpmpkgdb;
+
+#define SLOTORDER_UNORDERED 0
+#define SLOTORDER_BLKOFF 1
+
+
+static inline unsigned int le2h(unsigned char *p)
+{
+ return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+}
+
+static inline void h2le(unsigned int x, unsigned char *p)
+{
+ p[0] = x;
+ p[1] = x >> 8;
+ p[2] = x >> 16;
+ p[3] = x >> 24;
+}
+
+/* adler 32 algorithm taken from RFC 1950 */
+#define ADLER32_INIT 1
+static unsigned int update_adler32(unsigned int adler, unsigned char *buf, unsigned int len)
+{
+ unsigned int s1 = adler & 0xffff;
+ unsigned int s2 = (adler >> 16) & 0xffff;
+ int n;
+
+ for (; len >= 5552; len -= 5552) {
+ for (n = 0; n < 5552; n++) {
+ s1 += *buf++;
+ s2 += s1;
+ }
+ s1 %= 65521;
+ s2 %= 65521;
+ }
+ for (n = 0; n < len; n++) {
+ s1 += *buf++;
+ s2 += s1;
+ }
+ return ((s2 % 65521) << 16) + (s1 % 65521);
+}
+
+/*** Header management ***/
+
+#define PKGDB_MAGIC ('R' | 'p' << 8 | 'm' << 16 | 'P' << 24)
+#define PKGDB_VERSION 0
+
+/* must be a multiple of SLOT_SIZE! */
+#define PKGDB_HEADER_SIZE 32
+
+#define PKGDB_OFFSET_MAGIC 0
+#define PKGDB_OFFSET_VERSION 4
+#define PKGDB_OFFSET_GENERATION 8
+#define PKGDB_OFFSET_SLOTNPAGES 12
+#define PKGDB_OFFSET_NEXTPKGIDX 16
+
+static int rpmpkgReadHeader(rpmpkgdb pkgdb)
+{
+ unsigned int generation, slotnpages, nextpkgidx, version;
+ unsigned char header[PKGDB_HEADER_SIZE];
+
+ /* if we always head the write lock then our data matches */
+ if (pkgdb->header_ok)
+ return RPMRC_OK;
+ if (pread(pkgdb->fd, header, PKGDB_HEADER_SIZE, 0) != PKGDB_HEADER_SIZE) {
+ return RPMRC_FAIL;
+ }
+ if (le2h(header + PKGDB_OFFSET_MAGIC) != PKGDB_MAGIC) {
+ return RPMRC_FAIL;
+ }
+ version = le2h(header + PKGDB_OFFSET_VERSION);
+ if (version != PKGDB_VERSION) {
+ rpmlog(RPMLOG_ERR, _("rpmpkg: Version mismatch. Expected version: %u. "
+ "Found version: %u\n"), PKGDB_VERSION, version);
+ return RPMRC_FAIL;
+ }
+ generation = le2h(header + PKGDB_OFFSET_GENERATION);
+ slotnpages = le2h(header + PKGDB_OFFSET_SLOTNPAGES);
+ nextpkgidx = le2h(header + PKGDB_OFFSET_NEXTPKGIDX);
+ /* free slots if our internal data no longer matches */
+ if (pkgdb->slots && (pkgdb->generation != generation || pkgdb->slotnpages != slotnpages)) {
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ if (pkgdb->slothash) {
+ free(pkgdb->slothash);
+ pkgdb->slothash = 0;
+ }
+ }
+ pkgdb->generation = generation;
+ pkgdb->slotnpages = slotnpages;
+ pkgdb->nextpkgidx = nextpkgidx;
+ pkgdb->header_ok = 1;
+ return RPMRC_OK;
+}
+
+static int rpmpkgWriteHeader(rpmpkgdb pkgdb)
+{
+ unsigned char header[PKGDB_HEADER_SIZE];
+ memset(header, 0, sizeof(header));
+ h2le(PKGDB_MAGIC, header + PKGDB_OFFSET_MAGIC);
+ h2le(PKGDB_VERSION, header + PKGDB_OFFSET_VERSION);
+ h2le(pkgdb->generation, header + PKGDB_OFFSET_GENERATION);
+ h2le(pkgdb->slotnpages, header + PKGDB_OFFSET_SLOTNPAGES);
+ h2le(pkgdb->nextpkgidx, header + PKGDB_OFFSET_NEXTPKGIDX);
+ if (pwrite(pkgdb->fd, header, sizeof(header), 0) != sizeof(header)) {
+ return RPMRC_FAIL;
+ }
+ if (pkgdb->dofsync && fsync(pkgdb->fd))
+ return RPMRC_FAIL; /* write error */
+ return RPMRC_OK;
+}
+
+/*** Slot management ***/
+
+#define SLOT_MAGIC ('S' | 'l' << 8 | 'o' << 16 | 't' << 24)
+
+#define SLOT_SIZE 16
+#define BLK_SIZE 16
+#define PAGE_SIZE 4096
+
+/* the first slots (i.e. 32 bytes) are used for the header */
+#define SLOT_START (PKGDB_HEADER_SIZE / SLOT_SIZE)
+
+static inline unsigned int hashpkgidx(unsigned int h)
+{
+ h *= 0x5bd1e995;
+ h ^= h >> 16;
+ return h;
+}
+
+static int rpmpkgHashSlots(rpmpkgdb pkgdb)
+{
+ unsigned int nslots, num;
+ unsigned int *hash;
+ unsigned int h, hh, hmask;
+ int i;
+ pkgslot *slot;
+
+ pkgdb->nslothash = 0;
+ num = pkgdb->nslots;
+ while (num & (num - 1))
+ num = num & (num - 1);
+ num *= 4;
+ hash = pkgdb->slothash;
+ if (!hash || pkgdb->nslothash != num) {
+ free(pkgdb->slothash);
+ hash = pkgdb->slothash = calloc(num, sizeof(unsigned int));
+ if (!hash)
+ return RPMRC_FAIL;
+ pkgdb->nslothash = num;
+ } else {
+ memset(hash, 0, num * sizeof(unsigned int));
+ }
+ hmask = num - 1;
+ nslots = pkgdb->nslots;
+ for (i = 0, slot = pkgdb->slots; i < nslots; i++, slot++) {
+ for (h = hashpkgidx(slot->pkgidx) & hmask, hh = 7; hash[h] != 0; h = (h + hh++) & hmask)
+ ;
+ hash[h] = i + 1;
+ }
+ pkgdb->slothash = hash;
+ pkgdb->nslothash = num;
+ return RPMRC_OK;
+}
+
+static int rpmpkgReadSlots(rpmpkgdb pkgdb)
+{
+ unsigned int slotnpages = pkgdb->slotnpages;
+ struct stat stb;
+ unsigned char pagebuf[PAGE_SIZE];
+ unsigned int page;
+ unsigned int i, minblkoff, fileblks, slotno, freeslot, o;
+ pkgslot *slot;
+
+ /* free old slot data */
+ if (pkgdb->slots) {
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ }
+ if (pkgdb->slothash) {
+ free(pkgdb->slothash);
+ pkgdb->slothash = 0;
+ }
+ pkgdb->nslots = 0;
+ pkgdb->freeslot = 0;
+
+ /* calculate current database size in blks */
+ if (fstat(pkgdb->fd, &stb))
+ return RPMRC_FAIL;
+ if (stb.st_size % BLK_SIZE)
+ return RPMRC_FAIL; /* hmm */
+ fileblks = stb.st_size / BLK_SIZE;
+
+ /* read (and somewhat verify) all slots */
+ pkgdb->aslots = slotnpages * (PAGE_SIZE / SLOT_SIZE);
+ pkgdb->slots = calloc(pkgdb->aslots, sizeof(*pkgdb->slots));
+ if (!pkgdb->slots) {
+ return RPMRC_FAIL;
+ }
+ i = 0;
+ slot = pkgdb->slots;
+ minblkoff = slotnpages * (PAGE_SIZE / BLK_SIZE);
+ slotno = SLOT_START;
+ freeslot = 0;
+ for (page = 0; page < slotnpages; page++) {
+ if (pread(pkgdb->fd, pagebuf, PAGE_SIZE, page * PAGE_SIZE) != PAGE_SIZE)
+ return RPMRC_FAIL;
+ for (o = page ? 0 : SLOT_START * SLOT_SIZE; o < PAGE_SIZE; o += SLOT_SIZE, slotno++) {
+ unsigned char *pp = pagebuf + o;
+ unsigned int blkoff, blkcnt, pkgidx;
+ if (le2h(pp) != SLOT_MAGIC) {
+ return RPMRC_FAIL;
+ }
+ blkoff = le2h(pp + 8);
+ if (!blkoff) {
+ if (!freeslot)
+ freeslot = slotno;
+ continue;
+ }
+ pkgidx = le2h(pp + 4);
+ blkcnt = le2h(pp + 12);
+ slot->pkgidx = pkgidx;
+ slot->blkoff = blkoff;
+ slot->blkcnt = blkcnt;
+ slot->slotno = slotno;
+ if (slot->blkoff + slot->blkcnt > fileblks)
+ return RPMRC_FAIL; /* truncated database */
+ if (!slot->pkgidx || !slot->blkcnt || slot->blkoff < minblkoff)
+ return RPMRC_FAIL; /* bad entry */
+ i++;
+ slot++;
+ }
+ }
+ pkgdb->nslots = i;
+ pkgdb->slotorder = SLOTORDER_UNORDERED; /* XXX: always order? */
+ pkgdb->fileblks = fileblks;
+ pkgdb->freeslot = freeslot;
+ if (rpmpkgHashSlots(pkgdb)) {
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static int orderslots_blkoff_cmp(const void *a, const void *b)
+{
+ unsigned int blkoffa = ((const pkgslot *)a)->blkoff;
+ unsigned int blkoffb = ((const pkgslot *)b)->blkoff;
+ return blkoffa > blkoffb ? 1 : blkoffa < blkoffb ? -1 : 0;
+}
+
+static void rpmpkgOrderSlots(rpmpkgdb pkgdb, int slotorder)
+{
+ if (pkgdb->slotorder == slotorder)
+ return;
+ if (slotorder == SLOTORDER_BLKOFF) {
+ if (pkgdb->nslots > 1)
+ qsort(pkgdb->slots, pkgdb->nslots, sizeof(*pkgdb->slots), orderslots_blkoff_cmp);
+ }
+ pkgdb->slotorder = slotorder;
+ rpmpkgHashSlots(pkgdb);
+}
+
+static inline pkgslot *rpmpkgFindSlot(rpmpkgdb pkgdb, unsigned int pkgidx)
+{
+ unsigned int i, h, hh, hmask = pkgdb->nslothash - 1;
+ unsigned int *hash = pkgdb->slothash;
+
+ for (h = hashpkgidx(pkgidx) & hmask, hh = 7; (i = hash[h]) != 0; h = (h + hh++) & hmask)
+ if (pkgdb->slots[i - 1].pkgidx == pkgidx)
+ return pkgdb->slots + (i - 1);
+ return 0;
+}
+
+static int rpmpkgFindEmptyOffset(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkcnt, unsigned *blkoffp, pkgslot **oldslotp, int dontprepend)
+{
+ unsigned int i, nslots = pkgdb->nslots;
+ unsigned int bestblkoff = 0;
+ unsigned int freecnt, bestfreecnt = 0;
+ unsigned int lastblkend = pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE);
+ pkgslot *slot, *oldslot = 0;
+
+ if (pkgdb->slotorder != SLOTORDER_BLKOFF)
+ rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
+
+ if (dontprepend && nslots) {
+ lastblkend = pkgdb->slots[0].blkoff;
+ }
+ /* best fit strategy */
+ for (i = 0, slot = pkgdb->slots; i < nslots; i++, slot++) {
+ if (slot->blkoff < lastblkend) {
+ return RPMRC_FAIL; /* eek, slots overlap! */
+ }
+ if (slot->pkgidx == pkgidx) {
+ if (oldslot) {
+ return RPMRC_FAIL; /* eek, two slots with our pkgid ! */
+ }
+ oldslot = slot;
+ }
+ freecnt = slot->blkoff - lastblkend;
+ if (freecnt >= blkcnt) {
+ if (!bestblkoff || bestfreecnt > freecnt) {
+ bestblkoff = lastblkend;
+ bestfreecnt = freecnt;
+ }
+ }
+ lastblkend = slot->blkoff + slot->blkcnt;
+ }
+ if (!bestblkoff) {
+ bestblkoff = lastblkend; /* append to end */
+ }
+ *oldslotp = oldslot;
+ *blkoffp = bestblkoff;
+ return RPMRC_OK;
+}
+
+static int rpmpkgNeighbourCheck(rpmpkgdb pkgdb, unsigned int blkoff, unsigned int blkcnt, unsigned int *newblkcnt)
+{
+ unsigned int i, nslots = pkgdb->nslots;
+ unsigned int lastblkend = pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE);
+ pkgslot *slot, *left = 0, *right = 0;
+
+ if (pkgdb->slotorder != SLOTORDER_BLKOFF)
+ rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
+ if (blkoff < lastblkend)
+ return RPMRC_FAIL;
+ for (i = 0, slot = pkgdb->slots; i < nslots; i++, slot++) {
+ if (slot->blkoff < lastblkend)
+ return RPMRC_FAIL; /* eek, slots overlap! */
+ if (slot->blkoff < blkoff)
+ left = slot;
+ if (!right && slot->blkoff >= blkoff)
+ right = slot;
+ lastblkend = slot->blkoff + slot->blkcnt;
+ }
+ if (left && left->blkoff + left->blkcnt != blkoff)
+ return RPMRC_FAIL; /* must always start right after the block */
+ if (!left && blkoff != pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE))
+ return RPMRC_FAIL;
+ if (right && right->blkoff < blkoff + blkcnt)
+ return RPMRC_FAIL;
+ /* check if neighbour blobs are in good shape */
+ if (left && rpmpkgVerifyblob(pkgdb, left->pkgidx, left->blkoff, left->blkcnt) != RPMRC_OK)
+ return RPMRC_FAIL;
+ if (right && rpmpkgVerifyblob(pkgdb, right->pkgidx, right->blkoff, right->blkcnt) != RPMRC_OK)
+ return RPMRC_FAIL;
+ *newblkcnt = right ? right->blkoff - blkoff : blkcnt;
+ /* bounds are intect. free area. */
+ return RPMRC_OK;
+}
+
+static int rpmpkgWriteslot(rpmpkgdb pkgdb, unsigned int slotno, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt)
+{
+ unsigned char buf[SLOT_SIZE];
+ /* sanity */
+ if (slotno < SLOT_START)
+ return RPMRC_FAIL;
+ if (blkoff && slotno == pkgdb->freeslot)
+ pkgdb->freeslot = 0;
+ h2le(SLOT_MAGIC, buf);
+ h2le(pkgidx, buf + 4);
+ h2le(blkoff, buf + 8);
+ h2le(blkcnt, buf + 12);
+ if (pwrite(pkgdb->fd, buf, sizeof(buf), slotno * SLOT_SIZE) != sizeof(buf)) {
+ return RPMRC_FAIL;
+ }
+ pkgdb->generation++;
+ if (rpmpkgWriteHeader(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static int rpmpkgWriteEmptySlotpage(rpmpkgdb pkgdb, int pageno)
+{
+ unsigned char page[PAGE_SIZE];
+ int i, off = pageno ? 0 : SLOT_START * SLOT_SIZE;
+ memset(page, 0, sizeof(page));
+ for (i = 0; i < PAGE_SIZE / SLOT_SIZE; i++)
+ h2le(SLOT_MAGIC, page + i * SLOT_SIZE);
+ if (pwrite(pkgdb->fd, page, PAGE_SIZE - off, pageno * PAGE_SIZE + off) != PAGE_SIZE - off) {
+ return RPMRC_FAIL;
+ }
+ if (pkgdb->dofsync && fsync(pkgdb->fd)) {
+ return RPMRC_FAIL; /* write error */
+ }
+ return RPMRC_OK;
+}
+
+/*** Blk primitives ***/
+
+static int rpmpkgZeroBlks(rpmpkgdb pkgdb, unsigned int blkoff, unsigned int blkcnt)
+{
+ unsigned char buf[65536];
+ unsigned int towrite;
+ off_t fileoff;
+
+ memset(buf, 0, sizeof(buf));
+ fileoff = (off_t)blkoff * BLK_SIZE;
+ for (towrite = blkcnt * BLK_SIZE; towrite; ) {
+ unsigned int chunk = towrite > 65536 ? 65536 : towrite;
+ if (pwrite(pkgdb->fd, buf, chunk, fileoff) != chunk) {
+ return RPMRC_FAIL; /* write error */
+ }
+ fileoff += chunk;
+ towrite -= chunk;
+ }
+ if (blkoff + blkcnt > pkgdb->fileblks)
+ pkgdb->fileblks = blkoff + blkcnt;
+ return RPMRC_OK;
+}
+
+static int rpmpkgValidateZeroCheck(rpmpkgdb pkgdb, unsigned int blkoff, unsigned int blkcnt)
+{
+ unsigned long long buf[(65536 / sizeof(unsigned long long)) + 1];
+ off_t fileoff;
+ off_t tocheck;
+ int i;
+
+ if (blkoff > pkgdb->fileblks)
+ return RPMRC_FAIL; /* huh? */
+ fileoff = (off_t)blkoff * BLK_SIZE;
+ tocheck = blkoff + blkcnt > pkgdb->fileblks ? pkgdb->fileblks - blkoff : blkcnt;
+ tocheck *= BLK_SIZE;
+ while (tocheck >= 65536) {
+ if (pread(pkgdb->fd, (void *)buf, 65536, fileoff) != 65536)
+ return RPMRC_FAIL; /* read error */
+ for (i = 0; i < 65536 / sizeof(unsigned long long); i++)
+ if (buf[i])
+ return RPMRC_FAIL; /* not empty */
+ fileoff += 65536;
+ tocheck -= 65536;
+ }
+ if (tocheck) {
+ int cnt = (int)tocheck / sizeof(unsigned long long);
+ buf[cnt++] = 0;
+ if (pread(pkgdb->fd, (void *)buf, tocheck, fileoff) != tocheck)
+ return RPMRC_FAIL; /* read error */
+ for (i = 0; i < cnt; i++)
+ if (buf[i])
+ return RPMRC_FAIL; /* not empty */
+ }
+ return RPMRC_OK;
+}
+
+static int rpmpkgValidateZero(rpmpkgdb pkgdb, unsigned int blkoff, unsigned int blkcnt)
+{
+ if (rpmpkgValidateZeroCheck(pkgdb, blkoff, blkcnt) == RPMRC_OK)
+ return RPMRC_OK;
+ rpmlog(RPMLOG_WARNING, _("rpmpkg: detected non-zero blob, trying auto repair\n"));
+ /* auto-repair interrupted transactions */
+ if (rpmpkgNeighbourCheck(pkgdb, blkoff, blkcnt, &blkcnt) != RPMRC_OK)
+ return RPMRC_FAIL;
+ if (rpmpkgZeroBlks(pkgdb, blkoff, blkcnt) != RPMRC_OK)
+ return RPMRC_FAIL;
+ return RPMRC_OK;
+}
+
+
+/*** Blob primitives ***/
+
+/* head: magic + pkgidx + timestamp + bloblen */
+/* tail: adler32 + bloblen + magic */
+
+#define BLOBHEAD_MAGIC ('B' | 'l' << 8 | 'b' << 16 | 'S' << 24)
+#define BLOBTAIL_MAGIC ('B' | 'l' << 8 | 'b' << 16 | 'E' << 24)
+
+#define BLOBHEAD_SIZE (4 + 4 + 4 + 4)
+#define BLOBTAIL_SIZE (4 + 4 + 4)
+
+static int rpmpkgReadBlob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt, unsigned char *blob, unsigned int *bloblp, unsigned int *tstampp)
+{
+ unsigned char buf[BLOBHEAD_SIZE > BLOBTAIL_SIZE ? BLOBHEAD_SIZE : BLOBTAIL_SIZE];
+ unsigned int bloblen, toread, tstamp;
+ off_t fileoff;
+ unsigned int adl;
+ int verifyadler = bloblp ? 0 : 1;
+
+ /* sanity */
+ if (blkcnt < (BLOBHEAD_SIZE + BLOBTAIL_SIZE + BLK_SIZE - 1) / BLK_SIZE)
+ return RPMRC_FAIL; /* blkcnt too small */
+ /* read header */
+ fileoff = (off_t)blkoff * BLK_SIZE;
+ if (pread(pkgdb->fd, buf, BLOBHEAD_SIZE, fileoff) != BLOBHEAD_SIZE)
+ return RPMRC_FAIL; /* read error */
+ if (le2h(buf) != BLOBHEAD_MAGIC)
+ return RPMRC_FAIL; /* bad blob */
+ if (le2h(buf + 4) != pkgidx)
+ return RPMRC_FAIL; /* bad blob */
+ tstamp = le2h(buf + 8);
+ bloblen = le2h(buf + 12);
+ if (blkcnt != (BLOBHEAD_SIZE + bloblen + BLOBTAIL_SIZE + BLK_SIZE - 1) / BLK_SIZE)
+ return RPMRC_FAIL; /* bad blob */
+ adl = ADLER32_INIT;
+ if (verifyadler)
+ adl = update_adler32(adl, buf, BLOBHEAD_SIZE);
+ /* read in 64K chunks */
+ fileoff += BLOBHEAD_SIZE;
+ toread = blkcnt * BLK_SIZE - BLOBHEAD_SIZE;
+ if (!bloblp)
+ toread -= BLOBTAIL_SIZE;
+ while (toread) {
+ unsigned int chunk = toread > 65536 ? 65536 : toread;
+ if (pread(pkgdb->fd, blob, chunk, fileoff) != chunk) {
+ return RPMRC_FAIL; /* read error */
+ }
+ if (verifyadler) {
+ if (!bloblp)
+ adl = update_adler32(adl, blob, chunk);
+ else if (toread > BLOBTAIL_SIZE)
+ adl = update_adler32(adl, blob, toread - BLOBTAIL_SIZE > chunk ? chunk : toread - BLOBTAIL_SIZE);
+ }
+ if (bloblp)
+ blob += chunk;
+ toread -= chunk;
+ fileoff += chunk;
+ }
+ /* read trailer */
+ if (bloblp) {
+ memcpy(buf, blob - BLOBTAIL_SIZE, BLOBTAIL_SIZE);
+ } else if (pread(pkgdb->fd, buf, BLOBTAIL_SIZE, fileoff) != BLOBTAIL_SIZE) {
+ return RPMRC_FAIL; /* read error */
+ }
+ if (verifyadler && le2h(buf) != adl) {
+ return RPMRC_FAIL; /* bad blob, adler32 mismatch */
+ }
+ if (le2h(buf + 4) != bloblen) {
+ return RPMRC_FAIL; /* bad blob, bloblen mismatch */
+ }
+ if (le2h(buf + 8) != BLOBTAIL_MAGIC) {
+ return RPMRC_FAIL; /* bad blob */
+ }
+ if (bloblp)
+ *bloblp = bloblen;
+ if (tstampp)
+ *tstampp = tstamp;
+ return RPMRC_OK;
+}
+
+static int rpmpkgVerifyblob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt)
+{
+ unsigned char buf[65536];
+ return rpmpkgReadBlob(pkgdb, pkgidx, blkoff, blkcnt, buf, 0, 0);
+}
+
+static int rpmpkgWriteBlob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt, unsigned char *blob, unsigned int blobl, unsigned int now)
+{
+ unsigned char buf[(BLOBHEAD_SIZE > BLOBTAIL_SIZE ? BLOBHEAD_SIZE : BLOBTAIL_SIZE) + BLK_SIZE];
+ unsigned int towrite, pad;
+ unsigned int adl;
+ off_t fileoff;
+
+ /* sanity */
+ if (blkcnt < (BLOBHEAD_SIZE + BLOBTAIL_SIZE + BLK_SIZE - 1) / BLK_SIZE)
+ return RPMRC_FAIL; /* blkcnt too small */
+ if (blkcnt != (BLOBHEAD_SIZE + blobl + BLOBTAIL_SIZE + BLK_SIZE - 1) / BLK_SIZE)
+ return RPMRC_FAIL; /* blkcnt mismatch */
+ fileoff = (off_t)blkoff * BLK_SIZE;
+ h2le(BLOBHEAD_MAGIC, buf);
+ h2le(pkgidx, buf + 4);
+ h2le(now, buf + 8);
+ h2le(blobl, buf + 12);
+ if (pwrite(pkgdb->fd, buf, BLOBHEAD_SIZE, fileoff) != BLOBHEAD_SIZE) {
+ return RPMRC_FAIL; /* write error */
+ }
+ adl = ADLER32_INIT;
+ adl = update_adler32(adl, buf, BLOBHEAD_SIZE);
+ /* write in 64K chunks */
+ fileoff += BLOBHEAD_SIZE;
+ for (towrite = blobl; towrite;) {
+ unsigned int chunk = towrite > 65536 ? 65536 : towrite;
+ if (pwrite(pkgdb->fd, blob, chunk, fileoff) != chunk) {
+ return RPMRC_FAIL; /* write error */
+ }
+ adl = update_adler32(adl, blob, chunk);
+ blob += chunk;
+ towrite -= chunk;
+ fileoff += chunk;
+ }
+ /* pad if needed */
+ pad = blkcnt * BLK_SIZE - (BLOBHEAD_SIZE + blobl + BLOBTAIL_SIZE);
+ if (pad) {
+ memset(buf + (sizeof(buf) - BLOBTAIL_SIZE) - pad, 0, pad);
+ adl = update_adler32(adl, buf + (sizeof(buf) - BLOBTAIL_SIZE) - pad, pad);
+ }
+ h2le(adl, buf + (sizeof(buf) - BLOBTAIL_SIZE));
+ h2le(blobl, buf + (sizeof(buf) - BLOBTAIL_SIZE) + 4);
+ h2le(BLOBTAIL_MAGIC, buf + (sizeof(buf) - BLOBTAIL_SIZE) + 8);
+ if (pwrite(pkgdb->fd, buf + (sizeof(buf) - BLOBTAIL_SIZE) - pad, pad + BLOBTAIL_SIZE, fileoff) != pad + BLOBTAIL_SIZE) {
+ return RPMRC_FAIL; /* write error */
+ }
+ /* update file length */
+ if (blkoff + blkcnt > pkgdb->fileblks)
+ pkgdb->fileblks = blkoff + blkcnt;
+ if (pkgdb->dofsync && fsync(pkgdb->fd)) {
+ return RPMRC_FAIL; /* write error */
+ }
+ return RPMRC_OK;
+}
+
+static int rpmpkgDelBlob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt)
+{
+ if (rpmpkgVerifyblob(pkgdb, pkgidx, blkoff, blkcnt))
+ return RPMRC_FAIL;
+ if (rpmpkgZeroBlks(pkgdb, blkoff, blkcnt))
+ return RPMRC_FAIL;
+ if (pkgdb->dofsync && fsync(pkgdb->fd))
+ return RPMRC_FAIL; /* write error */
+ return RPMRC_OK;
+}
+
+
+static int rpmpkgMoveBlob(rpmpkgdb pkgdb, pkgslot *slot, unsigned int newblkoff)
+{
+ unsigned int pkgidx = slot->pkgidx;
+ unsigned int blkoff = slot->blkoff;
+ unsigned int blkcnt = slot->blkcnt;
+ unsigned char *blob;
+ unsigned int tstamp, blobl;
+
+ blob = malloc((size_t)blkcnt * BLK_SIZE);
+ if (rpmpkgReadBlob(pkgdb, pkgidx, blkoff, blkcnt, blob, &blobl, &tstamp)) {
+ free(blob);
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgWriteBlob(pkgdb, pkgidx, newblkoff, blkcnt, blob, blobl, tstamp)) {
+ free(blob);
+ return RPMRC_FAIL;
+ }
+ free(blob);
+ if (rpmpkgWriteslot(pkgdb, slot->slotno, pkgidx, newblkoff, blkcnt)) {
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgDelBlob(pkgdb, pkgidx, blkoff, blkcnt)) {
+ return RPMRC_FAIL;
+ }
+ slot->blkoff = newblkoff;
+ pkgdb->slotorder = SLOTORDER_UNORDERED;
+ return RPMRC_OK;
+}
+
+static int rpmpkgAddSlotPage(rpmpkgdb pkgdb)
+{
+ unsigned int cutoff;
+ if (pkgdb->slotorder != SLOTORDER_BLKOFF)
+ rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
+ cutoff = (pkgdb->slotnpages + 1) * (PAGE_SIZE / BLK_SIZE);
+
+ /* now move every blob before cutoff */
+ while (pkgdb->nslots && pkgdb->slots[0].blkoff < cutoff) {
+ unsigned int newblkoff;
+ pkgslot *slot = pkgdb->slots, *oldslot;
+
+ oldslot = 0;
+ if (rpmpkgFindEmptyOffset(pkgdb, slot->pkgidx, slot->blkcnt, &newblkoff, &oldslot, 1)) {
+ return RPMRC_FAIL;
+ }
+ if (!oldslot || oldslot != slot) {
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgMoveBlob(pkgdb, slot, newblkoff)) {
+ return RPMRC_FAIL;
+ }
+ rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
+ }
+
+ /* make sure our new page is empty */
+ if (rpmpkgValidateZero(pkgdb, pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE), PAGE_SIZE / BLK_SIZE)) {
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgWriteEmptySlotpage(pkgdb, pkgdb->slotnpages)) {
+ return RPMRC_FAIL;
+ }
+
+ /* announce free page */
+ pkgdb->freeslot = pkgdb->slotnpages * (PAGE_SIZE / SLOT_SIZE);
+ pkgdb->slotnpages++;
+ pkgdb->generation++;
+ if (rpmpkgWriteHeader(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static int rpmpkgGetLock(rpmpkgdb pkgdb, int type)
+{
+ if (!pkgdb->fd)
+ return RPMRC_FAIL;
+ if (flock(pkgdb->fd, type))
+ return RPMRC_FAIL;
+ return RPMRC_OK;
+}
+
+int rpmpkgLock(rpmpkgdb pkgdb, int excl)
+{
+ unsigned int *lockcntp = excl ? &pkgdb->locked_excl : &pkgdb->locked_shared;
+ if (*lockcntp > 0 || (!excl && pkgdb->locked_excl)) {
+ (*lockcntp)++;
+ return RPMRC_OK;
+ }
+ pkgdb->header_ok = 0;
+ if (rpmpkgGetLock(pkgdb, excl ? LOCK_EX : LOCK_SH)) {
+ return RPMRC_FAIL;
+ }
+ (*lockcntp)++;
+ return RPMRC_OK;
+}
+
+static int rpmpkgLockInternal(rpmpkgdb pkgdb, int excl)
+{
+ if (excl && pkgdb->rdonly)
+ return RPMRC_FAIL;
+
+ return rpmpkgLock(pkgdb, excl);
+}
+
+int rpmpkgUnlock(rpmpkgdb pkgdb, int excl)
+{
+ unsigned int *lockcntp = excl ? &pkgdb->locked_excl : &pkgdb->locked_shared;
+ if (*lockcntp == 0) {
+ return RPMRC_FAIL;
+ }
+ if (*lockcntp > 1 || (!excl && pkgdb->locked_excl)) {
+ (*lockcntp)--;
+ return RPMRC_OK;
+ }
+ if (excl && pkgdb->locked_shared) {
+ /* excl -> shared switch */
+ if (rpmpkgGetLock(pkgdb, LOCK_SH)) {
+ return RPMRC_FAIL;
+ }
+ (*lockcntp)--;
+ return RPMRC_OK;
+ }
+ flock(pkgdb->fd, LOCK_UN);
+ (*lockcntp)--;
+ pkgdb->header_ok = 0;
+ return RPMRC_OK;
+}
+
+static int rpmpkgLockReadHeader(rpmpkgdb pkgdb, int excl)
+{
+ if (rpmpkgLockInternal(pkgdb, excl))
+ return RPMRC_FAIL;
+ if (rpmpkgReadHeader(pkgdb)) {
+ rpmpkgUnlock(pkgdb, excl);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static int rpmpkgInitInternal(rpmpkgdb pkgdb)
+{
+ struct stat stb;
+ if (fstat(pkgdb->fd, &stb)) {
+ return RPMRC_FAIL;
+ }
+ if (stb.st_size == 0) {
+ if (rpmpkgWriteEmptySlotpage(pkgdb, 0)) {
+ return RPMRC_FAIL;
+ }
+ pkgdb->slotnpages = 1;
+ if (!pkgdb->nextpkgidx)
+ pkgdb->nextpkgidx = 1;
+ pkgdb->generation++;
+ if (rpmpkgWriteHeader(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ }
+ return RPMRC_OK;
+}
+
+static int rpmpkgInit(rpmpkgdb pkgdb)
+{
+ int rc;
+
+ if (rpmpkgLockInternal(pkgdb, 1))
+ return RPMRC_FAIL;
+ rc = rpmpkgInitInternal(pkgdb);
+ rpmpkgUnlock(pkgdb, 1);
+ return rc;
+}
+
+int rpmpkgOpen(rpmpkgdb *pkgdbp, const char *filename, int flags, int mode)
+{
+ struct stat stb;
+ rpmpkgdb pkgdb;
+
+ *pkgdbp = 0;
+ pkgdb = calloc(1, sizeof(*pkgdb));
+ pkgdb->filename = strdup(filename);
+ if (!pkgdb->filename) {
+ free(pkgdb);
+ return RPMRC_FAIL;
+ }
+ if ((flags & (O_RDONLY|O_RDWR)) == O_RDONLY)
+ pkgdb->rdonly = 1;
+ if ((pkgdb->fd = open(filename, flags, mode)) == -1) {
+ free(pkgdb->filename);
+ free(pkgdb);
+ return RPMRC_FAIL;
+ }
+ if (flags & O_CREAT) {
+ char *filenameCopy;
+ DIR *pdir;
+
+ if ((filenameCopy = strdup(pkgdb->filename)) == NULL) {
+ close(pkgdb->fd);
+ free(pkgdb->filename);
+ free(pkgdb);
+ return RPMRC_FAIL;
+ }
+
+ if ((pdir = opendir(dirname(filenameCopy))) == NULL) {
+ free(filenameCopy);
+ close(pkgdb->fd);
+ free(pkgdb->filename);
+ free(pkgdb);
+ return RPMRC_FAIL;
+ }
+
+ if (fsync(dirfd(pdir)) == -1) {
+ closedir(pdir);
+ free(filenameCopy);
+ close(pkgdb->fd);
+ free(pkgdb->filename);
+ free(pkgdb);
+ return RPMRC_FAIL;
+ }
+ closedir(pdir);
+ free(filenameCopy);
+
+ }
+ if (fstat(pkgdb->fd, &stb)) {
+ close(pkgdb->fd);
+ free(pkgdb->filename);
+ free(pkgdb);
+ return RPMRC_FAIL;
+ }
+ if (stb.st_size == 0) {
+ if (rpmpkgInit(pkgdb)) {
+ close(pkgdb->fd);
+ free(pkgdb->filename);
+ free(pkgdb);
+ return RPMRC_FAIL;
+ }
+ }
+ pkgdb->flags = flags;
+ pkgdb->mode = mode;
+ pkgdb->dofsync = 1;
+ *pkgdbp = pkgdb;
+ return RPMRC_OK;
+}
+
+void rpmpkgClose(rpmpkgdb pkgdb)
+{
+ if (pkgdb->fd >= 0) {
+ close(pkgdb->fd);
+ pkgdb->fd = -1;
+ }
+ if (pkgdb->slots)
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ if (pkgdb->slothash)
+ free(pkgdb->slothash);
+ pkgdb->slothash = 0;
+ free(pkgdb->filename);
+ free(pkgdb);
+}
+
+void rpmpkgSetFsync(rpmpkgdb pkgdb, int dofsync)
+{
+ pkgdb->dofsync = dofsync;
+}
+
+
+static int rpmpkgGetInternal(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char **blobp, unsigned int *bloblp)
+{
+ pkgslot *slot;
+ unsigned char *blob;
+
+ if (!pkgdb->slots && rpmpkgReadSlots(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ slot = rpmpkgFindSlot(pkgdb, pkgidx);
+ if (!slot) {
+ return RPMRC_NOTFOUND;
+ }
+ blob = malloc((size_t)slot->blkcnt * BLK_SIZE);
+ if (rpmpkgReadBlob(pkgdb, pkgidx, slot->blkoff, slot->blkcnt, blob, bloblp, (unsigned int *)0)) {
+ free(blob);
+ return RPMRC_FAIL;
+ }
+ *blobp = blob;
+ return RPMRC_OK;
+}
+
+static int rpmpkgPutInternal(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char *blob, unsigned int blobl)
+{
+ unsigned int blkcnt, blkoff, slotno;
+ pkgslot *oldslot;
+
+ /* we always read all slots when writing, just in case */
+ if (rpmpkgReadSlots(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ blkcnt = (BLOBHEAD_SIZE + blobl + BLOBTAIL_SIZE + BLK_SIZE - 1) / BLK_SIZE;
+ /* find a nice place for the blob */
+ if (rpmpkgFindEmptyOffset(pkgdb, pkgidx, blkcnt, &blkoff, &oldslot, 0)) {
+ return RPMRC_FAIL;
+ }
+ /* create new slot page if we don't have a free slot and can't reuse an old one */
+ if (!oldslot && !pkgdb->freeslot) {
+ if (rpmpkgAddSlotPage(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ /* redo rpmpkgFindEmptyOffset to get another free area */
+ if (rpmpkgFindEmptyOffset(pkgdb, pkgidx, blkcnt, &blkoff, &oldslot, 0)) {
+ return RPMRC_FAIL;
+ }
+ }
+ /* make sure that we don't overwrite data */
+ if (rpmpkgValidateZero(pkgdb, blkoff, blkcnt)) {
+ return RPMRC_FAIL;
+ }
+ /* write new blob */
+ if (rpmpkgWriteBlob(pkgdb, pkgidx, blkoff, blkcnt, blob, blobl, (unsigned int)time(0))) {
+ return RPMRC_FAIL;
+ }
+ /* write slot */
+ slotno = oldslot ? oldslot->slotno : pkgdb->freeslot;
+ if (!slotno) {
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgWriteslot(pkgdb, slotno, pkgidx, blkoff, blkcnt)) {
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ return RPMRC_FAIL;
+ }
+ /* erase old blob */
+ if (oldslot && oldslot->blkoff) {
+ if (rpmpkgDelBlob(pkgdb, pkgidx, oldslot->blkoff, oldslot->blkcnt)) {
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ return RPMRC_FAIL;
+ }
+ }
+ if (oldslot) {
+ /* just update the slot, no need to free the slot data */
+ oldslot->blkoff = blkoff;
+ oldslot->blkcnt = blkcnt;
+ pkgdb->slotorder = SLOTORDER_UNORDERED;
+ } else {
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ }
+ return RPMRC_OK;
+}
+
+static int rpmpkgDelInternal(rpmpkgdb pkgdb, unsigned int pkgidx)
+{
+ pkgslot *slot;
+ unsigned int blkoff, blkcnt;
+
+ /* we always read all slots when writing, just in case */
+ if (rpmpkgReadSlots(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
+ slot = rpmpkgFindSlot(pkgdb, pkgidx);
+ if (!slot) {
+ return RPMRC_OK;
+ }
+ if (rpmpkgWriteslot(pkgdb, slot->slotno, 0, 0, 0)) {
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgDelBlob(pkgdb, pkgidx, slot->blkoff, slot->blkcnt)) {
+ return RPMRC_FAIL;
+ }
+ if (pkgdb->nslots > 1 && slot->blkoff < pkgdb->fileblks / 2) {
+ /* we freed a blob in the first half of our data. do some extra work */
+ int i;
+ if (slot == pkgdb->slots) {
+ blkoff = pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE);
+ } else {
+ blkoff = slot[-1].blkoff + slot[-1].blkcnt;
+ }
+ if (slot < pkgdb->slots + pkgdb->nslots - 1) {
+ blkcnt = slot[1].blkoff - blkoff;
+ } else {
+ blkcnt = slot->blkoff + slot->blkcnt - blkoff;
+ }
+ slot->blkoff = 0;
+ slot->blkcnt = 0;
+ slot = pkgdb->slots + pkgdb->nslots - 2;
+ if (slot->blkcnt < slot[1].blkcnt)
+ slot++; /* bigger slot first */
+ for (i = 0; i < 2; i++, slot++) {
+ if (slot == pkgdb->slots + pkgdb->nslots)
+ slot -= 2;
+ if (!slot->blkoff || slot->blkoff < blkoff)
+ continue;
+ if (slot->blkoff < pkgdb->fileblks / 2)
+ continue;
+ if (slot->blkcnt > blkcnt)
+ continue;
+ rpmpkgMoveBlob(pkgdb, slot, blkoff);
+ blkoff += slot->blkcnt;
+ blkcnt -= slot->blkcnt;
+ }
+ rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
+ } else {
+ slot->blkoff = 0;
+ slot->blkcnt = 0;
+ }
+ /* check if we can truncate the file */
+ slot = pkgdb->slots + pkgdb->nslots - 1;
+ if (!slot->blkoff && pkgdb->nslots > 1) {
+ slot--;
+ }
+ if (slot->blkoff)
+ blkoff = slot->blkoff + slot->blkcnt;
+ else
+ blkoff = pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE);
+ if (blkoff < pkgdb->fileblks / 4 * 3) {
+ /* truncate the file */
+ if (!rpmpkgValidateZero(pkgdb, blkoff, pkgdb->fileblks - blkoff)) {
+ if (!ftruncate(pkgdb->fd, blkoff * BLK_SIZE)) {
+ pkgdb->fileblks = blkoff;
+ }
+ }
+ }
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ return RPMRC_OK;
+}
+
+static int rpmpkgListInternal(rpmpkgdb pkgdb, unsigned int **pkgidxlistp, unsigned int *npkgidxlistp)
+{
+ unsigned int i, nslots, *pkgidxlist;
+ pkgslot *slot;
+
+ if (!pkgdb->slots && rpmpkgReadSlots(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+ if (!pkgidxlistp) {
+ *npkgidxlistp = pkgdb->nslots;
+ return RPMRC_OK;
+ }
+ rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
+ nslots = pkgdb->nslots;
+ pkgidxlist = calloc(nslots + 1, sizeof(unsigned int));
+ for (i = 0, slot = pkgdb->slots; i < nslots; i++, slot++) {
+ pkgidxlist[i] = slot->pkgidx;
+ }
+ *pkgidxlistp = pkgidxlist;
+ *npkgidxlistp = nslots;
+ return RPMRC_OK;
+}
+
+int rpmpkgGet(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char **blobp, unsigned int *bloblp)
+{
+ int rc;
+
+ *blobp = 0;
+ *bloblp = 0;
+ if (!pkgidx)
+ return RPMRC_FAIL;
+ if (rpmpkgLockReadHeader(pkgdb, 0))
+ return RPMRC_FAIL;
+ rc = rpmpkgGetInternal(pkgdb, pkgidx, blobp, bloblp);
+ rpmpkgUnlock(pkgdb, 0);
+#ifdef RPMPKG_LZO
+ if (!rc)
+ rc = rpmpkgLZODecompress(blobp, bloblp);
+#endif
+ return rc;
+}
+
+int rpmpkgPut(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char *blob, unsigned int blobl)
+{
+ int rc;
+
+ if (!pkgidx) {
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgLockReadHeader(pkgdb, 1))
+ return RPMRC_FAIL;
+#ifdef RPMPKG_LZO
+ if (rpmpkgLZOCompress(&blob, &blobl)) {
+ rpmpkgUnlock(pkgdb, 1);
+ return RPMRC_FAIL;
+ }
+#endif
+ rc = rpmpkgPutInternal(pkgdb, pkgidx, blob, blobl);
+#ifdef RPMPKG_LZO
+ free(blob);
+#endif
+ rpmpkgUnlock(pkgdb, 1);
+ return rc;
+}
+
+int rpmpkgDel(rpmpkgdb pkgdb, unsigned int pkgidx)
+{
+ int rc;
+
+ if (!pkgidx) {
+ return RPMRC_FAIL;
+ }
+ if (rpmpkgLockReadHeader(pkgdb, 1))
+ return RPMRC_FAIL;
+ rc = rpmpkgDelInternal(pkgdb, pkgidx);
+ rpmpkgUnlock(pkgdb, 1);
+ return rc;
+}
+
+int rpmpkgList(rpmpkgdb pkgdb, unsigned int **pkgidxlistp, unsigned int *npkgidxlistp)
+{
+ int rc;
+ if (pkgidxlistp)
+ *pkgidxlistp = 0;
+ *npkgidxlistp = 0;
+ if (rpmpkgLockReadHeader(pkgdb, 0))
+ return RPMRC_FAIL;
+ rc = rpmpkgListInternal(pkgdb, pkgidxlistp, npkgidxlistp);
+ rpmpkgUnlock(pkgdb, 0);
+ return rc;
+}
+
+int rpmpkgNextPkgIdx(rpmpkgdb pkgdb, unsigned int *pkgidxp)
+{
+ if (rpmpkgLockReadHeader(pkgdb, 1))
+ return RPMRC_FAIL;
+ *pkgidxp = pkgdb->nextpkgidx++;
+ if (rpmpkgWriteHeader(pkgdb)) {
+ rpmpkgUnlock(pkgdb, 1);
+ return RPMRC_FAIL;
+ }
+ /* no fsync needed. also no need to increase the generation count,
+ * as the header is always read in */
+ rpmpkgUnlock(pkgdb, 1);
+ return RPMRC_OK;
+}
+
+int rpmpkgGeneration(rpmpkgdb pkgdb, unsigned int *generationp)
+{
+ if (rpmpkgLockReadHeader(pkgdb, 0))
+ return RPMRC_FAIL;
+ *generationp = pkgdb->generation;
+ rpmpkgUnlock(pkgdb, 0);
+ return RPMRC_OK;
+}
+
+int rpmpkgStats(rpmpkgdb pkgdb)
+{
+ unsigned int usedblks = 0;
+ int i;
+
+ if (rpmpkgLockReadHeader(pkgdb, 0))
+ return RPMRC_FAIL;
+ if (rpmpkgReadSlots(pkgdb)) {
+ rpmpkgUnlock(pkgdb, 0);
+ return RPMRC_FAIL;
+ }
+ for (i = 0; i < pkgdb->nslots; i++)
+ usedblks += pkgdb->slots[i].blkcnt;
+ printf("--- Package DB Stats\n");
+ printf("Filename: %s\n", pkgdb->filename);
+ printf("Generation: %d\n", pkgdb->generation);
+ printf("Slot pages: %d\n", pkgdb->slotnpages);
+ printf("Used slots: %d\n", pkgdb->nslots);
+ printf("Free slots: %d\n", pkgdb->slotnpages * (PAGE_SIZE / SLOT_SIZE) - pkgdb->nslots);
+ printf("Blob area size: %d\n", (pkgdb->fileblks - pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE)) * BLK_SIZE);
+ printf("Blob area used: %d\n", usedblks * BLK_SIZE);
+ rpmpkgUnlock(pkgdb, 0);
+ return RPMRC_OK;
+}
+
+#ifdef RPMPKG_LZO
+
+#include "lzo/lzoconf.h"
+#include "lzo/lzo1x.h"
+
+#define BLOBLZO_MAGIC ('L' | 'Z' << 8 | 'O' << 16 | 'B' << 24)
+
+static int rpmpkgLZOCompress(unsigned char **blobp, unsigned int *bloblp)
+{
+ unsigned char *blob = *blobp;
+ unsigned int blobl = *bloblp;
+ unsigned char *lzoblob, *workmem;
+ unsigned int lzoblobl;
+ lzo_uint blobl2;
+
+ if (lzo_init() != LZO_E_OK) {
+ return RPMRC_FAIL;
+ }
+ workmem = malloc(LZO1X_1_MEM_COMPRESS);
+ if (!workmem) {
+ return RPMRC_FAIL;
+ }
+ lzoblobl = 4 + 4 + blobl + blobl / 16 + 64 + 3;
+ lzoblob = malloc(lzoblobl);
+ if (!lzoblob) {
+ free(workmem);
+ return RPMRC_FAIL;
+ }
+ h2le(BLOBLZO_MAGIC, lzoblob);
+ h2le(blobl, lzoblob + 4);
+ if (lzo1x_1_compress(blob, blobl, lzoblob + 8, &blobl2, workmem) != LZO_E_OK) {
+ free(workmem);
+ free(lzoblob);
+ return RPMRC_FAIL;
+ }
+ free(workmem);
+ *blobp = lzoblob;
+ *bloblp = 8 + blobl2;
+ return RPMRC_OK;
+}
+
+static int rpmpkgLZODecompress(unsigned char **blobp, unsigned int *bloblp)
+{
+ unsigned char *lzoblob = *blobp;
+ unsigned int lzoblobl = *bloblp;
+ unsigned char *blob;
+ unsigned int blobl;
+ lzo_uint blobl2;
+
+ if (!lzoblob || lzoblobl < 8)
+ return RPMRC_FAIL;
+ if (le2h(lzoblob) != BLOBLZO_MAGIC)
+ return RPMRC_FAIL;
+ if (lzo_init() != LZO_E_OK)
+ return RPMRC_FAIL;
+ blobl = le2h(lzoblob + 4);
+ blob = malloc(blobl ? blobl : 1);
+ if (!blob)
+ return RPMRC_FAIL;
+ if (lzo1x_decompress(lzoblob + 8, lzoblobl - 8, blob, &blobl2, 0) != LZO_E_OK || blobl2 != blobl) {
+ free(blob);
+ return RPMRC_FAIL;
+ }
+ free(lzoblob);
+ *blobp = blob;
+ *bloblp = blobl;
+ return RPMRC_OK;
+}
+
+#endif
diff --git a/lib/backend/ndb/rpmpkg.h b/lib/backend/ndb/rpmpkg.h
new file mode 100644
index 000000000..7e5d0c67e
--- /dev/null
+++ b/lib/backend/ndb/rpmpkg.h
@@ -0,0 +1,20 @@
+struct rpmpkgdb_s;
+typedef struct rpmpkgdb_s *rpmpkgdb;
+
+int rpmpkgOpen(rpmpkgdb *pkgdbp, const char *filename, int flags, int mode);
+void rpmpkgClose(rpmpkgdb pkgdbp);
+void rpmpkgSetFsync(rpmpkgdb pkgdbp, int dofsync);
+
+int rpmpkgLock(rpmpkgdb pkgdb, int excl);
+int rpmpkgUnlock(rpmpkgdb pkgdb, int excl);
+
+int rpmpkgGet(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char **blobp, unsigned int *bloblp);
+int rpmpkgPut(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char *blob, unsigned int blobl);
+int rpmpkgDel(rpmpkgdb pkgdb, unsigned int pkgidx);
+int rpmpkgList(rpmpkgdb pkgdb, unsigned int **pkgidxlistp, unsigned int *npkgidxlistp);
+
+int rpmpkgNextPkgIdx(rpmpkgdb pkgdb, unsigned int *pkgidxp);
+int rpmpkgGeneration(rpmpkgdb pkgdb, unsigned int *generationp);
+
+int rpmpkgStats(rpmpkgdb pkgdb);
+
diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c
new file mode 100644
index 000000000..55cc197b3
--- /dev/null
+++ b/lib/backend/ndb/rpmxdb.c
@@ -0,0 +1,1221 @@
+#define _GNU_SOURCE
+
+#include "system.h"
+
+#include <rpm/rpmlog.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <endian.h>
+#include <libgen.h>
+
+#include "rpmxdb.h"
+
+#define RPMRC_OK 0
+#define RPMRC_NOTFOUND 1
+#define RPMRC_FAIL 2
+
+typedef struct rpmxdb_s {
+ rpmpkgdb pkgdb; /* master database */
+ char *filename;
+ int fd;
+ int flags;
+ int mode;
+ int rdonly;
+ unsigned int pagesize;
+ unsigned int generation;
+ unsigned int slotnpages;
+ unsigned int usergeneration;
+
+ unsigned char *mapped;
+ unsigned int mappedlen;
+
+ struct xdb_slot {
+ unsigned int slotno;
+ unsigned int blobtag;
+ unsigned int subtag;
+ unsigned char *mapped;
+ int mapflags;
+ unsigned int startpage;
+ unsigned int pagecnt;
+ void (*mapcallback)(rpmxdb xdb, void *data, void *newaddr, size_t newsize);
+ void *mapcallbackdata;
+ unsigned int next;
+ unsigned int prev;
+ } *slots;
+ unsigned int nslots;
+ unsigned int firstfree;
+ unsigned int usedblobpages;
+ unsigned int systempagesize;
+ int dofsync;
+} *rpmxdb;
+
+
+static inline void h2le(unsigned int x, unsigned char *p)
+{
+ p[0] = x;
+ p[1] = x >> 8;
+ p[2] = x >> 16;
+ p[3] = x >> 24;
+}
+
+/* aligned versions */
+static inline unsigned int le2ha(unsigned char *p)
+{
+ unsigned int x = *(unsigned int *)p;
+ return le32toh(x);
+}
+
+static inline void h2lea(unsigned int x, unsigned char *p)
+{
+ *(unsigned int *)p = htole32(x);
+}
+
+
+#define XDB_MAGIC ('R' | 'p' << 8 | 'm' << 16 | 'X' << 24)
+#define XDB_VERSION 0
+
+#define XDB_OFFSET_MAGIC 0
+#define XDB_OFFSET_VERSION 4
+#define XDB_OFFSET_GENERATION 8
+#define XDB_OFFSET_SLOTNPAGES 12
+#define XDB_OFFSET_PAGESIZE 16
+#define XDB_OFFSET_USERGENERATION 20
+
+/* must be multiple of SLOT_SIZE */
+#define XDB_HEADER_SIZE 32
+
+#define SLOT_MAGIC ('S' | 'l' << 8 | 'o' << 16)
+
+#define SLOT_SIZE 16
+#define SLOT_START (XDB_HEADER_SIZE / SLOT_SIZE)
+
+static void rpmxdbUnmap(rpmxdb xdb)
+{
+ munmap(xdb->mapped, xdb->mappedlen);
+ xdb->mapped = 0;
+ xdb->mappedlen = 0;
+}
+
+/* slot mapping functions */
+static int mapslot(rpmxdb xdb, struct xdb_slot *slot)
+{
+ void *mapped;
+ size_t off, size, shift;
+
+ if (slot->mapped)
+ return RPMRC_FAIL;
+ size = slot->pagecnt * xdb->pagesize;
+ off = slot->startpage * xdb->pagesize;
+ shift = 0;
+ if (xdb->pagesize != xdb->systempagesize) {
+ shift = off & (xdb->systempagesize - 1);
+ off -= shift;
+ size += shift;
+ size = (size + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
+ }
+ mapped = mmap(0, size, slot->mapflags, MAP_SHARED, xdb->fd, off);
+ if (mapped == MAP_FAILED)
+ return RPMRC_FAIL;
+ slot->mapped = (unsigned char *)mapped + shift;
+ return RPMRC_OK;
+}
+
+static void unmapslot(rpmxdb xdb, struct xdb_slot *slot)
+{
+ size_t size;
+ unsigned char *mapped = slot->mapped;
+ if (!mapped)
+ return;
+ size = slot->pagecnt * xdb->pagesize;
+ if (xdb->pagesize != xdb->systempagesize) {
+ size_t off = slot->startpage * xdb->pagesize;
+ size_t shift = off & (xdb->systempagesize - 1);
+ mapped -= shift;
+ size += shift;
+ size = (size + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
+ }
+ munmap(mapped, size);
+ slot->mapped = 0;
+}
+
+static int remapslot(rpmxdb xdb, struct xdb_slot *slot, unsigned int newpagecnt)
+{
+ void *mapped;
+ size_t off, oldsize, newsize, shift;
+ oldsize = slot->pagecnt * xdb->pagesize;
+ newsize = newpagecnt * xdb->pagesize;
+ off = slot->startpage * xdb->pagesize;
+ shift = 0;
+ if (xdb->pagesize != xdb->systempagesize) {
+ off = slot->startpage * xdb->pagesize;
+ shift = off & (xdb->systempagesize - 1);
+ off -= shift;
+ oldsize += shift;
+ oldsize = (oldsize + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
+ newsize += shift;
+ newsize = (newsize + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
+ }
+ if (slot->mapped)
+ mapped = mremap(slot->mapped - shift, oldsize, newsize, MREMAP_MAYMOVE);
+ else
+ mapped = mmap(0, newsize, slot->mapflags, MAP_SHARED, xdb->fd, off);
+ if (mapped == MAP_FAILED)
+ return RPMRC_FAIL;
+ slot->mapped = (unsigned char *)mapped + shift;
+ slot->pagecnt = newpagecnt;
+ return RPMRC_OK;
+}
+
+
+static int usedslots_cmp(const void *a, const void *b)
+{
+ struct xdb_slot *sa = *(struct xdb_slot **)a;
+ struct xdb_slot *sb = *(struct xdb_slot **)b;
+ if (sa->startpage == sb->startpage) {
+ return sa->pagecnt > sb->pagecnt ? 1 : sa->pagecnt < sb->pagecnt ? -1 : 0;
+ }
+ return sa->startpage > sb->startpage ? 1 : -1;
+}
+
+static int rpmxdbReadHeader(rpmxdb xdb)
+{
+ struct xdb_slot *slot;
+ unsigned int header[XDB_HEADER_SIZE / sizeof(unsigned int)];
+ unsigned int slotnpages, pagesize, generation, usergeneration, version;
+ unsigned int page, *lastfreep;
+ unsigned char *pageptr;
+ struct xdb_slot *slots, **usedslots, *lastslot;
+ unsigned int nslots;
+ unsigned int usedblobpages;
+ int i, nused, slotno;
+ struct stat stb;
+ size_t mapsize;
+
+ if (xdb->mapped) {
+ if (le2ha(xdb->mapped + XDB_OFFSET_GENERATION) == xdb->generation) {
+ return RPMRC_OK;
+ }
+ rpmxdbUnmap(xdb);
+ }
+ if (fstat(xdb->fd, &stb)) {
+ return RPMRC_FAIL;
+ }
+ if (pread(xdb->fd, header, sizeof(header), 0) != sizeof(header)) {
+ return RPMRC_FAIL;
+ }
+ if (le2ha((unsigned char *)header + XDB_OFFSET_MAGIC) != XDB_MAGIC)
+ return RPMRC_FAIL;
+ version = le2ha((unsigned char *)header + XDB_OFFSET_VERSION);
+ if (version != XDB_VERSION) {
+ rpmlog(RPMLOG_ERR, _("rpmxdb: Version mismatch. Expected version: %u. "
+ "Found version: %u\n"), XDB_VERSION, version);
+ return RPMRC_FAIL;
+ }
+
+ generation = le2ha((unsigned char *)header + XDB_OFFSET_GENERATION);
+ slotnpages = le2ha((unsigned char *)header + XDB_OFFSET_SLOTNPAGES);
+ pagesize = le2ha((unsigned char *)header + XDB_OFFSET_PAGESIZE);
+ usergeneration = le2ha((unsigned char *)header + XDB_OFFSET_USERGENERATION);
+ if (!slotnpages || !pagesize || stb.st_size % pagesize != 0)
+ return RPMRC_FAIL;
+ xdb->pagesize = pagesize;
+
+ /* round up */
+ mapsize = slotnpages * pagesize;
+ mapsize = (mapsize + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
+ xdb->mapped = mmap(0, mapsize, xdb->rdonly ? PROT_READ : PROT_READ | PROT_WRITE, MAP_SHARED, xdb->fd, 0);
+ if ((void *)xdb->mapped == MAP_FAILED) {
+ xdb->mapped = 0;
+ return RPMRC_FAIL;
+ }
+ xdb->mappedlen = mapsize;
+
+ /* read in all slots */
+ xdb->firstfree = 0;
+ nslots = slotnpages * (pagesize / SLOT_SIZE) - SLOT_START + 1;
+ slots = calloc(nslots + 1, sizeof(struct xdb_slot));
+ if (!slots) {
+ rpmxdbUnmap(xdb);
+ return RPMRC_FAIL;
+ }
+ usedslots = calloc(nslots + 1, sizeof(int));
+ if (!usedslots) {
+ rpmxdbUnmap(xdb);
+ free(slots);
+ return RPMRC_FAIL;
+ }
+ nused = 0;
+ slotno = 1;
+ slot = slots + 1;
+ usedblobpages = 0;
+ lastfreep = &xdb->firstfree;
+ for (page = 0, pageptr = xdb->mapped; page < slotnpages; page++, pageptr += pagesize) {
+ unsigned int o;
+ for (o = page ? 0 : SLOT_START * SLOT_SIZE; o < pagesize; o += SLOT_SIZE, slotno++, slot++) {
+ unsigned char *pp = pageptr + o;
+ slot->slotno = slotno;
+ slot->subtag = le2ha(pp);
+ if ((slot->subtag & 0x00ffffff) != SLOT_MAGIC) {
+ free(slots);
+ free(usedslots);
+ rpmxdbUnmap(xdb);
+ return RPMRC_FAIL;
+ }
+ slot->subtag = (slot->subtag >> 24) & 255;
+ slot->blobtag = le2ha(pp + 4);
+ slot->startpage = le2ha(pp + 8);
+ slot->pagecnt = le2ha(pp + 12);
+ if (slot->pagecnt == 0 && slot->startpage) /* empty but used slot? */
+ slot->startpage = slotnpages;
+ if (!slot->startpage) {
+ *lastfreep = slotno;
+ lastfreep = &slot->next;
+ } else {
+ usedslots[nused++] = slot;
+ usedblobpages += slot->pagecnt;
+ }
+ }
+ }
+ if (nused > 1) {
+ qsort(usedslots, nused, sizeof(*usedslots), usedslots_cmp);
+ }
+ /* now chain em */
+ slots[0].pagecnt = slotnpages;
+ lastslot = slots;
+ for (i = 0; i < nused; i++, lastslot = slot) {
+ slot = usedslots[i];
+ if (lastslot->startpage + lastslot->pagecnt > slot->startpage) {
+ free(slots);
+ free(usedslots);
+ rpmxdbUnmap(xdb);
+ return RPMRC_FAIL;
+ }
+ lastslot->next = slot->slotno;
+ slot->prev = lastslot->slotno;
+ }
+ lastslot->next = nslots;
+ slots[nslots].slotno = nslots;
+ slots[nslots].prev = lastslot->slotno;
+ slots[nslots].startpage = stb.st_size / pagesize;
+ free(usedslots);
+ /* now sync with the old slot data */
+ if (xdb->slots) {
+ for (i = 1, slot = xdb->slots + i; i < xdb->nslots; i++, slot++) {
+ if (slot->startpage && (slot->mapped || slot->mapcallback)) {
+ struct xdb_slot *nslot;
+ if (i >= nslots || !slots[i].startpage || slots[i].blobtag != slot->blobtag || slots[i].subtag != slot->subtag) {
+ /* slot is gone */
+ if (slot->mapped) {
+ unmapslot(xdb, slot);
+ slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
+ }
+ continue;
+ }
+ nslot = slots + i;
+ if (slot->mapcallback) {
+ nslot->mapflags = slot->mapflags;
+ nslot->mapcallback = slot->mapcallback;
+ nslot->mapcallbackdata = slot->mapcallbackdata;
+ }
+ if (slot->startpage != nslot->startpage || slot->pagecnt != nslot->pagecnt) {
+ /* slot moved or was resized */
+ if (slot->mapped)
+ unmapslot(xdb, slot);
+ if (nslot->mapcallback) {
+ if (nslot->pagecnt) {
+ mapslot(xdb, nslot);
+ nslot->mapcallback(xdb, nslot->mapcallbackdata, nslot->mapped, nslot->mapped ? nslot->pagecnt * xdb->pagesize : 0);
+ } else {
+ nslot->mapcallback(xdb, nslot->mapcallbackdata, 0, 0);
+ }
+ }
+ }
+ }
+ }
+ free(xdb->slots);
+ }
+ xdb->slots = slots;
+ xdb->nslots = nslots;
+ xdb->generation = generation;
+ xdb->slotnpages = slotnpages;
+ xdb->usergeneration = usergeneration;
+ xdb->usedblobpages = usedblobpages;
+ return RPMRC_OK;
+}
+
+static int rpmxdbWriteHeader(rpmxdb xdb)
+{
+ if (!xdb->mapped)
+ return RPMRC_FAIL;
+ h2lea(XDB_MAGIC, xdb->mapped + XDB_OFFSET_MAGIC);
+ h2lea(XDB_VERSION, xdb->mapped + XDB_OFFSET_VERSION);
+ h2lea(xdb->generation, xdb->mapped + XDB_OFFSET_GENERATION);
+ h2lea(xdb->slotnpages, xdb->mapped + XDB_OFFSET_SLOTNPAGES);
+ h2lea(xdb->pagesize, xdb->mapped + XDB_OFFSET_PAGESIZE);
+ h2lea(xdb->usergeneration, xdb->mapped + XDB_OFFSET_USERGENERATION);
+ return RPMRC_OK;
+}
+
+static void rpmxdbUpdateSlot(rpmxdb xdb, struct xdb_slot *slot)
+{
+ unsigned char *pp = xdb->mapped + (SLOT_START - 1 + slot->slotno) * SLOT_SIZE;
+ h2lea(SLOT_MAGIC | (slot->subtag << 24), pp);
+ h2lea(slot->blobtag, pp + 4);
+ if (slot->pagecnt || !slot->startpage)
+ h2lea(slot->startpage, pp + 8);
+ else
+ h2lea(1, pp + 8); /* "empty but used" blobs always start at 1 */
+ h2lea(slot->pagecnt, pp + 12);
+ xdb->generation++;
+ h2lea(xdb->generation, xdb->mapped + XDB_OFFSET_GENERATION);
+}
+
+static int rpmxdbWriteEmptyPages(rpmxdb xdb, unsigned int pageno, unsigned int count)
+{
+ unsigned char *page;
+ if (!count)
+ return RPMRC_OK;
+ page = malloc(xdb->pagesize);
+ if (!page)
+ return RPMRC_FAIL;
+ memset(page, 0, xdb->pagesize);
+ for (; count; count--, pageno++) {
+ if (pwrite(xdb->fd, page, xdb->pagesize, pageno * xdb->pagesize) != xdb->pagesize) {
+ free(page);
+ return RPMRC_FAIL;
+ }
+ }
+ free(page);
+ return RPMRC_OK;
+}
+
+static int rpmxdbWriteEmptySlotpage(rpmxdb xdb, int pageno)
+{
+ unsigned char *page;
+ int i, spp;
+ page = malloc(xdb->pagesize);
+ if (!page)
+ return RPMRC_FAIL;
+ memset(page, 0, xdb->pagesize);
+ spp = xdb->pagesize / SLOT_SIZE; /* slots per page */
+ for (i = pageno ? 0 : SLOT_START; i < spp; i++)
+ h2le(SLOT_MAGIC, page + i * SLOT_SIZE);
+ if (!pageno) {
+ /* only used when called from InitInternal */
+ if (xdb->mapped) {
+ free(page);
+ return RPMRC_FAIL;
+ }
+ xdb->mapped = page;
+ rpmxdbWriteHeader(xdb);
+ xdb->mapped = 0;
+ }
+ if (pwrite(xdb->fd, page, xdb->pagesize, pageno * xdb->pagesize) != xdb->pagesize) {
+ free(page);
+ return RPMRC_FAIL;
+ }
+ free(page);
+ return RPMRC_OK;
+}
+
+static int rpmxdbInitInternal(rpmxdb xdb)
+{
+ struct stat stb;
+ if (fstat(xdb->fd, &stb)) {
+ return RPMRC_FAIL;
+ }
+ if (stb.st_size == 0) {
+ xdb->slotnpages = 1;
+ xdb->generation++;
+ xdb->pagesize = sysconf(_SC_PAGE_SIZE);
+ if (rpmxdbWriteEmptySlotpage(xdb, 0)) {
+ return RPMRC_FAIL;
+ }
+ }
+ return RPMRC_OK;
+}
+
+/* we use the master pdb for locking */
+static int rpmxdbLockOnly(rpmxdb xdb, int excl)
+{
+ if (excl && xdb->rdonly)
+ return RPMRC_FAIL;
+ return rpmpkgLock(xdb->pkgdb, excl);
+}
+
+/* this is the same as rpmxdbLockReadHeader. It does the
+ * ReadHeader to sync the mappings if xdb moved some blobs.
+ */
+int rpmxdbLock(rpmxdb xdb, int excl)
+{
+ if (rpmxdbLockOnly(xdb, excl))
+ return RPMRC_FAIL;
+ if (rpmxdbReadHeader(xdb)) {
+ rpmxdbUnlock(xdb, excl);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+int rpmxdbUnlock(rpmxdb xdb, int excl)
+{
+ return rpmpkgUnlock(xdb->pkgdb, excl);
+}
+
+static int rpmxdbLockReadHeader(rpmxdb xdb, int excl)
+{
+ if (rpmxdbLockOnly(xdb, excl))
+ return RPMRC_FAIL;
+ if (rpmxdbReadHeader(xdb)) {
+ rpmxdbUnlock(xdb, excl);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static int rpmxdbInit(rpmxdb xdb)
+{
+ int rc;
+
+ if (rpmxdbLockOnly(xdb, 1))
+ return RPMRC_FAIL;
+ rc = rpmxdbInitInternal(xdb);
+ rpmxdbUnlock(xdb, 1);
+ return rc;
+}
+
+int rpmxdbOpen(rpmxdb *xdbp, rpmpkgdb pkgdb, const char *filename, int flags, int mode)
+{
+ struct stat stb;
+ rpmxdb xdb;
+
+ *xdbp = 0;
+ xdb = calloc(1, sizeof(*xdb));
+ xdb->pkgdb = pkgdb;
+ xdb->filename = strdup(filename);
+ xdb->systempagesize = sysconf(_SC_PAGE_SIZE);
+ if (!xdb->filename) {
+ free(xdb);
+ return RPMRC_FAIL;
+ }
+ if ((flags & (O_RDONLY|O_RDWR)) == O_RDONLY)
+ xdb->rdonly = 1;
+ if ((xdb->fd = open(filename, flags, mode)) == -1) {
+ free(xdb->filename);
+ free(xdb);
+ return RPMRC_FAIL;
+ }
+ if (flags & O_CREAT) {
+ char *filenameCopy;
+ DIR *pdir;
+
+ if ((filenameCopy = strdup(xdb->filename)) == NULL) {
+ close(xdb->fd);
+ free(xdb->filename);
+ free(xdb);
+ return RPMRC_FAIL;
+ }
+
+ if ((pdir = opendir(dirname(filenameCopy))) == NULL) {
+ free(filenameCopy);
+ close(xdb->fd);
+ free(xdb->filename);
+ free(xdb);
+ return RPMRC_FAIL;
+ }
+
+ if (fsync(dirfd(pdir)) == -1) {
+ closedir(pdir);
+ free(filenameCopy);
+ close(xdb->fd);
+ free(xdb->filename);
+ free(xdb);
+ return RPMRC_FAIL;
+ }
+ closedir(pdir);
+ free(filenameCopy);
+ }
+ if (fstat(xdb->fd, &stb)) {
+ close(xdb->fd);
+ free(xdb->filename);
+ free(xdb);
+ return RPMRC_FAIL;
+ }
+ if (stb.st_size == 0) {
+ if (rpmxdbInit(xdb)) {
+ close(xdb->fd);
+ free(xdb->filename);
+ free(xdb);
+ return RPMRC_FAIL;
+ }
+ }
+ xdb->flags = flags;
+ xdb->mode = mode;
+ xdb->dofsync = 1;
+ *xdbp = xdb;
+ return RPMRC_OK;
+}
+
+void rpmxdbClose(rpmxdb xdb)
+{
+ struct xdb_slot *slot;
+ int i;
+
+ for (i = 1, slot = xdb->slots + 1; i < xdb->nslots; i++, slot++) {
+ if (slot->mapped) {
+ unmapslot(xdb, slot);
+ slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
+ }
+ }
+ if (xdb->slots)
+ free(xdb->slots);
+ if (xdb->fd >= 0)
+ close(xdb->fd);
+ if (xdb->filename)
+ free(xdb->filename);
+ free(xdb);
+}
+
+/* moves the blob to a given new location (possibly resizeing) */
+static int moveblobto(rpmxdb xdb, struct xdb_slot *oldslot, struct xdb_slot *afterslot, unsigned int newpagecnt)
+{
+ struct xdb_slot *nextslot;
+ unsigned int newstartpage, oldpagecnt;
+ unsigned int tocopy;
+ int didmap;
+
+ newstartpage = afterslot->startpage + afterslot->pagecnt;
+ nextslot = xdb->slots + afterslot->next;
+
+ /* make sure there's enough room */
+ if (newpagecnt > nextslot->startpage - newstartpage)
+ return RPMRC_FAIL;
+
+#if 0
+ printf("moveblobto %d %d %d %d, afterslot %d\n", oldslot->startpage, oldslot->pagecnt, newstartpage, newpagecnt, afterslot->slotno);
+#endif
+ /* map old content */
+ didmap = 0;
+ oldpagecnt = oldslot->pagecnt;
+ if (!oldslot->mapped && oldpagecnt) {
+ if (mapslot(xdb, oldslot))
+ return RPMRC_FAIL;
+ didmap = 1;
+ }
+
+ /* copy content */
+ tocopy = newpagecnt > oldpagecnt ? oldpagecnt : newpagecnt;
+ if (tocopy && pwrite(xdb->fd, oldslot->mapped, tocopy * xdb->pagesize, newstartpage * xdb->pagesize) != tocopy * xdb->pagesize) {
+ if (didmap)
+ unmapslot(xdb, oldslot);
+ return RPMRC_FAIL;
+ }
+ /* zero out new pages */
+ if (newpagecnt > oldpagecnt) {
+ if (rpmxdbWriteEmptyPages(xdb, newstartpage + oldpagecnt, newpagecnt - oldpagecnt)) {
+ if (didmap)
+ unmapslot(xdb, oldslot);
+ return RPMRC_FAIL;
+ }
+ }
+
+ if (oldslot->mapped)
+ unmapslot(xdb, oldslot);
+
+ /* set new offset and position */
+ oldslot->startpage = newstartpage;
+ oldslot->pagecnt = newpagecnt;
+ rpmxdbUpdateSlot(xdb, oldslot);
+ xdb->usedblobpages -= oldpagecnt;
+ xdb->usedblobpages += newpagecnt;
+
+ if (afterslot != oldslot && nextslot != oldslot) {
+ /* remove from old chain */
+ xdb->slots[oldslot->prev].next = oldslot->next;
+ xdb->slots[oldslot->next].prev = oldslot->prev;
+
+ /* chain into new position, between lastslot and nextslot */
+ oldslot->prev = afterslot->slotno;
+ afterslot->next = oldslot->slotno;
+
+ oldslot->next = nextslot->slotno;
+ nextslot->prev = oldslot->slotno;
+ }
+
+ /* map again (if needed) */
+ if (oldslot->mapcallback) {
+ if (newpagecnt) {
+ if (mapslot(xdb, oldslot))
+ oldslot->mapped = 0; /* XXX: HELP, what can we do here? */
+ }
+ oldslot->mapcallback(xdb, oldslot->mapcallbackdata, oldslot->mapped, oldslot->mapped ? oldslot->pagecnt * xdb->pagesize : 0);
+ }
+ return RPMRC_OK;
+}
+
+/* moves the blob to a new location (possibly resizeing) */
+static int moveblob(rpmxdb xdb, struct xdb_slot *oldslot, unsigned int newpagecnt)
+{
+ struct xdb_slot *slot, *lastslot;
+ unsigned int nslots;
+ unsigned int freecnt;
+ int i;
+
+ nslots = xdb->nslots;
+ freecnt = 0;
+ lastslot = xdb->slots;
+ for (i = xdb->slots[0].next; ; lastslot = slot, i = slot->next) {
+ slot = xdb->slots + i;
+ freecnt = slot->startpage - (lastslot->startpage + lastslot->pagecnt);
+ if (freecnt >= newpagecnt)
+ break;
+ if (i == nslots)
+ break;
+ }
+ if (i == nslots && newpagecnt > freecnt) {
+ /* need to grow the file */
+ if (rpmxdbWriteEmptyPages(xdb, slot->startpage, newpagecnt - freecnt)) {
+ return RPMRC_FAIL;
+ }
+ slot->startpage += newpagecnt - freecnt;
+ }
+ return moveblobto(xdb, oldslot, lastslot, newpagecnt);
+}
+
+/* move the two blobs at the end of our file to the free area after the provided slot */
+static int moveblobstofront(rpmxdb xdb, struct xdb_slot *afterslot)
+{
+ struct xdb_slot *slot1, *slot2;
+ unsigned int freestart = afterslot->startpage + afterslot->pagecnt;
+ unsigned int freecount = xdb->slots[afterslot->next].startpage - freestart;
+
+ slot1 = xdb->slots + xdb->slots[xdb->nslots].prev;
+ if (slot1 == xdb->slots)
+ slot1 = slot2 = 0;
+ else {
+ slot2 = xdb->slots + slot1->prev;
+ if (slot2 == xdb->slots)
+ slot2 = 0;
+ }
+ if (slot1->pagecnt < slot2->pagecnt) {
+ struct xdb_slot *tmp = slot1;
+ slot1 = slot2;
+ slot2 = tmp;
+ }
+ if (slot1 && slot1->pagecnt && slot1->pagecnt <= freecount && slot1->startpage > freestart) {
+ if (moveblobto(xdb, slot1, afterslot, slot1->pagecnt))
+ return RPMRC_FAIL;
+ freestart += slot1->pagecnt;
+ freecount -= slot1->pagecnt;
+ afterslot = slot1;
+ }
+ if (slot2 && slot2->pagecnt && slot2->pagecnt <= freecount && slot2->startpage > freestart) {
+ if (moveblobto(xdb, slot2, afterslot, slot2->pagecnt))
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+/* add a single page containing empty slots */
+static int addslotpage(rpmxdb xdb)
+{
+ unsigned char *newaddr;
+ struct xdb_slot *slot;
+ int i, spp, nslots;
+ size_t newmappedlen;
+
+ if (xdb->firstfree)
+ return RPMRC_FAIL;
+
+ /* move first blob if needed */
+ nslots = xdb->nslots;
+ for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
+ slot = xdb->slots + i;
+ if (slot->pagecnt)
+ break;
+ }
+ if (i != nslots && slot->pagecnt && slot->startpage == xdb->slotnpages) {
+ /* the blob at this slot is in the way. move it. */
+ if (moveblob(xdb, slot, slot->pagecnt))
+ return RPMRC_FAIL;
+ }
+
+ spp = xdb->pagesize / SLOT_SIZE; /* slots per page */
+ slot = realloc(xdb->slots, (nslots + 1 + spp) * sizeof(*slot));
+ if (!slot)
+ return RPMRC_FAIL;
+ xdb->slots = slot;
+
+ if (rpmxdbWriteEmptySlotpage(xdb, xdb->slotnpages)) {
+ return RPMRC_FAIL;
+ }
+ /* remap slots */
+ newmappedlen = xdb->slotnpages * xdb->pagesize + xdb->pagesize;
+ newmappedlen = (newmappedlen + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
+ newaddr = mremap(xdb->mapped, xdb->mappedlen, newmappedlen, MREMAP_MAYMOVE);
+ if (newaddr == MAP_FAILED)
+ return RPMRC_FAIL;
+ xdb->mapped = newaddr;
+ xdb->mappedlen = newmappedlen;
+
+ /* update the header */
+ xdb->slotnpages++;
+ xdb->generation++;
+ rpmxdbWriteHeader(xdb);
+
+ /* fixup empty but used slots */
+ for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
+ slot = xdb->slots + i;
+ if (slot->startpage >= xdb->slotnpages)
+ break;
+ slot->startpage = xdb->slotnpages;
+ if (slot->pagecnt)
+ abort();
+ }
+
+ /* move tail element to the new end */
+ slot = xdb->slots + nslots + spp;
+ *slot = xdb->slots[nslots];
+ slot->slotno = nslots + spp;
+ xdb->slots[slot->prev].next = slot->slotno;
+ xdb->nslots += spp;
+
+ /* add new free slots to the firstfree chain */
+ memset(xdb->slots + nslots, 0, sizeof(*slot) * spp);
+ for (i = 0; i < spp - 1; i++) {
+ xdb->slots[nslots + i].slotno = nslots + i;
+ xdb->slots[nslots + i].next = i + 1;
+ }
+ xdb->slots[nslots + i].slotno = nslots + i;
+ xdb->firstfree = nslots;
+ return RPMRC_OK;
+}
+
+static int createblob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag)
+{
+ struct xdb_slot *slot;
+ unsigned int id;
+
+ if (subtag > 255)
+ return RPMRC_FAIL;
+ if (!xdb->firstfree) {
+ if (addslotpage(xdb))
+ return RPMRC_FAIL;
+ }
+ id = xdb->firstfree;
+ slot = xdb->slots + xdb->firstfree;
+ xdb->firstfree = slot->next;
+
+ slot->mapped = 0;
+ slot->blobtag = blobtag;
+ slot->subtag = subtag;
+ slot->startpage = xdb->slotnpages;
+ slot->pagecnt = 0;
+ rpmxdbUpdateSlot(xdb, slot);
+ /* enqueue */
+ slot->prev = 0;
+ slot->next = xdb->slots[0].next;
+ xdb->slots[slot->next].prev = id;
+ xdb->slots[0].next = id;
+#if 0
+ printf("createblob #%d %d/%d\n", id, blobtag, subtag);
+#endif
+ if (slot->slotno != id)
+ abort();
+ if (slot->mapped)
+ abort();
+ *idp = id;
+ return RPMRC_OK;
+}
+
+int rpmxdbLookupBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag, int flags)
+{
+ struct xdb_slot *slot;
+ unsigned int i, nslots;
+ if (rpmxdbLockReadHeader(xdb, flags ? 1 : 0))
+ return RPMRC_FAIL;
+ nslots = xdb->nslots;
+ slot = 0;
+ for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
+ slot = xdb->slots + i;
+ if (slot->blobtag == blobtag && slot->subtag == subtag)
+ break;
+ }
+ if (i == nslots)
+ i = 0;
+ if (i && (flags & O_TRUNC) != 0) {
+ if (rpmxdbResizeBlob(xdb, i, 0)) {
+ rpmxdbUnlock(xdb, flags ? 1 : 0);
+ return RPMRC_FAIL;
+ }
+ }
+ if (!i && (flags & O_CREAT) != 0) {
+ if (createblob(xdb, &i, blobtag, subtag)) {
+ rpmxdbUnlock(xdb, flags ? 1 : 0);
+ return RPMRC_FAIL;
+ }
+ }
+ *idp = i;
+ rpmxdbUnlock(xdb, flags ? 1 : 0);
+ return i ? RPMRC_OK : RPMRC_NOTFOUND;
+}
+
+int rpmxdbDelBlob(rpmxdb xdb, unsigned int id)
+{
+ struct xdb_slot *slot;
+ if (!id)
+ return RPMRC_FAIL;
+ if (rpmxdbLockReadHeader(xdb, 1))
+ return RPMRC_FAIL;
+ if (id >= xdb->nslots) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ slot = xdb->slots + id;
+ if (!slot->startpage) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+ }
+ if (slot->mapped) {
+ unmapslot(xdb, slot);
+ slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
+ }
+ /* remove from old chain */
+ xdb->slots[slot->prev].next = slot->next;
+ xdb->slots[slot->next].prev = slot->prev;
+ xdb->usedblobpages -= slot->pagecnt;
+
+ if (xdb->usedblobpages * 2 < xdb->slots[xdb->nslots].startpage && (slot->startpage + slot->pagecnt) * 2 < xdb->slots[xdb->nslots].startpage) {
+ /* freed in first half of pages, move last two blobs if we can */
+ moveblobstofront(xdb, xdb->slots + slot->prev);
+ }
+
+ /* zero slot */
+ memset(slot, 0, sizeof(*slot));
+ slot->slotno = id;
+ rpmxdbUpdateSlot(xdb, slot);
+
+ /* enqueue into free chain */
+ slot->next = xdb->firstfree;
+ xdb->firstfree = slot->slotno;
+
+ /* check if we should truncate the file */
+ slot = xdb->slots + xdb->slots[xdb->nslots].prev;
+ if (slot->startpage + slot->pagecnt < xdb->slots[xdb->nslots].startpage / 4 * 3) {
+ unsigned int newend = slot->startpage + slot->pagecnt;
+ if (!ftruncate(xdb->fd, newend * xdb->pagesize))
+ xdb->slots[xdb->nslots].startpage = newend;
+ }
+
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+}
+
+int rpmxdbResizeBlob(rpmxdb xdb, unsigned int id, size_t newsize)
+{
+ struct xdb_slot *slot;
+ unsigned int oldpagecnt, newpagecnt;
+ if (!id)
+ return RPMRC_FAIL;
+ if (rpmxdbLockReadHeader(xdb, 1))
+ return RPMRC_FAIL;
+ if (id >= xdb->nslots) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ slot = xdb->slots + id;
+ if (!slot->startpage) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ oldpagecnt = slot->pagecnt;
+ newpagecnt = (newsize + xdb->pagesize - 1) / xdb->pagesize;
+ if (oldpagecnt && newpagecnt && newpagecnt <= oldpagecnt) {
+ /* reducing size. zero to end of page */
+ unsigned int pg = newsize & (xdb->pagesize - 1);
+ if (pg) {
+ if (slot->mapped) {
+ memset(slot->mapped + pg, 0, xdb->pagesize - pg);
+ } else {
+ char *empty = calloc(1, xdb->pagesize - pg);
+ if (!empty) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ if (pwrite(xdb->fd, empty, xdb->pagesize - pg, (slot->startpage + newpagecnt - 1) * xdb->pagesize + pg ) != xdb->pagesize - pg) {
+ free(empty);
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ free(empty);
+ }
+ }
+ }
+ if (newpagecnt == oldpagecnt) {
+ /* no size change */
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+ }
+ if (!newpagecnt) {
+ /* special case: zero size blob, no longer mapped */
+ if (slot->mapped)
+ unmapslot(xdb, slot);
+ slot->pagecnt = 0;
+ slot->startpage = xdb->slotnpages;
+ /* remove from old chain */
+ xdb->slots[slot->prev].next = slot->next;
+ xdb->slots[slot->next].prev = slot->prev;
+ /* enqueue into head */
+ slot->prev = 0;
+ slot->next = xdb->slots[0].next;
+ xdb->slots[slot->next].prev = slot->slotno;
+ xdb->slots[0].next = slot->slotno;
+ rpmxdbUpdateSlot(xdb, slot);
+ xdb->usedblobpages -= oldpagecnt;
+ if (slot->mapcallback)
+ slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
+ } else if (newpagecnt <= xdb->slots[slot->next].startpage - slot->startpage) {
+ /* can do it inplace */
+ if (newpagecnt > oldpagecnt) {
+ /* zero new pages */
+ if (rpmxdbWriteEmptyPages(xdb, slot->startpage + oldpagecnt, newpagecnt - oldpagecnt)) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ }
+ if (slot->mapcallback) {
+ if (remapslot(xdb, slot, newpagecnt)) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ } else {
+ if (slot->mapped)
+ unmapslot(xdb, slot);
+ slot->pagecnt = newpagecnt;
+ }
+ rpmxdbUpdateSlot(xdb, slot);
+ xdb->usedblobpages -= oldpagecnt;
+ xdb->usedblobpages += newpagecnt;
+ if (slot->mapcallback)
+ slot->mapcallback(xdb, slot->mapcallbackdata, slot->mapped, slot->pagecnt * xdb->pagesize);
+ } else {
+ /* need to relocate to a new page area */
+ if (moveblob(xdb, slot, newpagecnt)) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ }
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+}
+
+int rpmxdbMapBlob(rpmxdb xdb, unsigned int id, int flags, void (*mapcallback)(rpmxdb xdb, void *data, void *newaddr, size_t newsize), void *mapcallbackdata)
+{
+ struct xdb_slot *slot;
+ if (!id || !mapcallback)
+ return RPMRC_FAIL;
+ if ((flags & (O_RDONLY|O_RDWR)) == O_RDWR && xdb->rdonly)
+ return RPMRC_FAIL;
+ if (rpmxdbLockReadHeader(xdb, 0))
+ return RPMRC_FAIL;
+ if (id >= xdb->nslots) {
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_FAIL;
+ }
+ slot = xdb->slots + id;
+ if (!slot->startpage || slot->mapped) {
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_FAIL;
+ }
+ slot->mapflags = (flags & (O_RDONLY|O_RDWR)) == O_RDWR ? PROT_READ | PROT_WRITE : PROT_READ;
+ if (slot->pagecnt) {
+ if (mapslot(xdb, slot)) {
+ slot->mapflags = 0;
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_FAIL;
+ }
+ }
+ slot->mapcallback = mapcallback;
+ slot->mapcallbackdata = mapcallbackdata;
+ mapcallback(xdb, mapcallbackdata, slot->mapped, slot->mapped ? slot->pagecnt * xdb->pagesize : 0);
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_OK;
+}
+
+int rpmxdbUnmapBlob(rpmxdb xdb, unsigned int id)
+{
+ struct xdb_slot *slot;
+ if (!id)
+ return RPMRC_OK;
+ if (rpmxdbLockReadHeader(xdb, 0))
+ return RPMRC_FAIL;
+ if (id >= xdb->nslots) {
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_FAIL;
+ }
+ slot = xdb->slots + id;
+ if (slot->mapped) {
+ unmapslot(xdb, slot);
+ slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
+ }
+ slot->mapcallback = 0;
+ slot->mapcallbackdata = 0;
+ slot->mapflags = 0;
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_OK;
+}
+
+int rpmxdbRenameBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag)
+{
+ struct xdb_slot *slot;
+ unsigned int otherid;
+ unsigned int id = *idp;
+ int rc;
+
+ if (!id || subtag > 255)
+ return RPMRC_FAIL;
+ if (rpmxdbLockReadHeader(xdb, 1))
+ return RPMRC_FAIL;
+ if (id >= xdb->nslots) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ slot = xdb->slots + id;
+#if 0
+ printf("rpmxdbRenameBlob #%d %d/%d -> %d/%d\n", id, slot->blobtag, slot->subtag, blobtag, subtag);
+#endif
+ if (!slot->startpage) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ if (slot->blobtag == blobtag && slot->subtag == subtag) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+ }
+ rc = rpmxdbLookupBlob(xdb, &otherid, blobtag, subtag, 0);
+ if (rc == RPMRC_NOTFOUND)
+ otherid = 0;
+ else if (rc) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ if (otherid) {
+#if 0
+ printf("(replacing #%d)\n", otherid);
+#endif
+ if (rpmxdbDelBlob(xdb, otherid)) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ /* get otherid back from free chain */
+ if (xdb->firstfree != otherid)
+ return RPMRC_FAIL;
+ xdb->firstfree = xdb->slots[otherid].next;
+
+ slot->blobtag = blobtag;
+ slot->subtag = subtag;
+ xdb->slots[otherid] = *slot;
+ /* fixup ids */
+ xdb->slots[otherid].slotno = otherid;
+ xdb->slots[slot->prev].next = otherid;
+ xdb->slots[slot->next].prev = otherid;
+ /* write */
+ rpmxdbUpdateSlot(xdb, xdb->slots + otherid);
+ memset(slot, 0, sizeof(*slot));
+ slot->slotno = id;
+ rpmxdbUpdateSlot(xdb, slot);
+ slot->next = xdb->firstfree;
+ xdb->firstfree = slot->slotno;
+ *idp = otherid;
+ } else {
+ slot = xdb->slots + id;
+ slot->blobtag = blobtag;
+ slot->subtag = subtag;
+ rpmxdbUpdateSlot(xdb, slot);
+ }
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+}
+
+void rpmxdbSetFsync(rpmxdb xdb, int dofsync)
+{
+ xdb->dofsync = dofsync;
+}
+
+int rpmxdbIsRdonly(rpmxdb xdb)
+{
+ return xdb->rdonly;
+}
+
+int rpmxdbSetUserGeneration(rpmxdb xdb, unsigned int usergeneration)
+{
+ if (rpmxdbLockReadHeader(xdb, 1))
+ return RPMRC_FAIL;
+ /* sync before the update */
+ if (xdb->dofsync && fsync(xdb->fd)) {
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_FAIL;
+ }
+ xdb->usergeneration = usergeneration;
+ xdb->generation++;
+ rpmxdbWriteHeader(xdb);
+ rpmxdbUnlock(xdb, 1);
+ return RPMRC_OK;
+}
+
+int rpmxdbGetUserGeneration(rpmxdb xdb, unsigned int *usergenerationp)
+{
+ if (rpmxdbLockReadHeader(xdb, 0))
+ return RPMRC_FAIL;
+ *usergenerationp = xdb->usergeneration;
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_OK;
+}
+
+int rpmxdbStats(rpmxdb xdb)
+{
+ struct xdb_slot *slot;
+ unsigned int i, nslots;
+
+ if (rpmxdbLockReadHeader(xdb, 0))
+ return RPMRC_FAIL;
+ nslots = xdb->nslots;
+ printf("--- XDB Stats\n");
+ printf("Filename: %s\n", xdb->filename);
+ printf("Generation: %d\n", xdb->generation);
+ printf("Slot pages: %d\n", xdb->slotnpages);
+ printf("Blob pages: %d\n", xdb->usedblobpages);
+ printf("Free pages: %d\n", xdb->slots[nslots].startpage - xdb->usedblobpages - xdb->slotnpages);
+ printf("Pagesize: %d / %d\n", xdb->pagesize, xdb->systempagesize);
+ for (i = 1, slot = xdb->slots + i; i < nslots; i++, slot++) {
+ if (!slot->startpage)
+ continue;
+ printf("%2d: tag %d/%d, startpage %d, pagecnt %d%s\n", i, slot->blobtag, slot->subtag, slot->startpage, slot->pagecnt, slot->mapcallbackdata ? ", mapped" : "");
+ }
+#if 0
+ printf("Again in offset order:\n");
+ for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
+ slot = xdb->slots + i;
+ printf("%2d: tag %d/%d, startpage %d, pagecnt %d%s\n", i, slot->blobtag, slot->subtag, slot->startpage, slot->pagecnt, slot->mapcallbackdata ? ", mapped" : "");
+ }
+#endif
+#if 0
+ printf("Free chain:\n");
+ for (i = xdb->firstfree; i; i = slot->next) {
+ slot = xdb->slots + i;
+ printf("%2d [%2d]: tag %d/%d, startpage %d, pagecnt %d%s\n", i, slot->slotno, slot->blobtag, slot->subtag, slot->startpage, slot->pagecnt, slot->mapcallbackdata ? ", mapped" : "");
+ }
+#endif
+ rpmxdbUnlock(xdb, 0);
+ return RPMRC_OK;
+}
+
diff --git a/lib/backend/ndb/rpmxdb.h b/lib/backend/ndb/rpmxdb.h
new file mode 100644
index 000000000..4358536ef
--- /dev/null
+++ b/lib/backend/ndb/rpmxdb.h
@@ -0,0 +1,27 @@
+#include "rpmpkg.h"
+
+struct rpmxdb_s;
+typedef struct rpmxdb_s *rpmxdb;
+
+int rpmxdbOpen(rpmxdb *xdbp, rpmpkgdb pkgdb, const char *filename, int flags, int mode);
+void rpmxdbClose(rpmxdb xdb);
+void rpmxdbSetFsync(rpmxdb xdb, int dofsync);
+int rpmxdbIsRdonly(rpmxdb xdb);
+
+int rpmxdbLock(rpmxdb xdb, int excl);
+int rpmxdbUnlock(rpmxdb xdb, int excl);
+
+int rpmxdbLookupBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag, int flags);
+int rpmxdbDelBlob(rpmxdb xdb, unsigned int id) ;
+
+int rpmxdbMapBlob(rpmxdb xdb, unsigned int id, int flags, void (*mapcallback)(rpmxdb xdb, void *data, void *newaddr, size_t newsize), void *mapcallbackdata);
+int rpmxdbUnmapBlob(rpmxdb xdb, unsigned int id);
+
+int rpmxdbResizeBlob(rpmxdb xdb, unsigned int id, size_t newsize);
+int rpmxdbRenameBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag);
+
+int rpmxdbSetUserGeneration(rpmxdb xdb, unsigned int usergeneration);
+int rpmxdbGetUserGeneration(rpmxdb xdb, unsigned int *usergenerationp);
+
+int rpmxdbStats(rpmxdb xdb);
+
diff --git a/lib/cpio.c b/lib/cpio.c
index 382eeb65a..57c959258 100644
--- a/lib/cpio.c
+++ b/lib/cpio.c
@@ -16,7 +16,6 @@
#else
#include <sys/types.h> /* already included from system.h */
#endif
-#include <errno.h>
#include <string.h>
#include <rpm/rpmio.h>
@@ -24,6 +23,7 @@
#include <rpm/rpmstring.h>
#include "lib/cpio.h"
+#include "lib/rpmarchive.h"
#include "debug.h"
@@ -35,6 +35,47 @@ struct rpmcpio_s {
off_t fileend;
};
+/*
+ * Size limit for individual files in "new ascii format" cpio archives.
+ * The max size of the entire archive is unlimited from cpio POV,
+ * but subject to filesystem limitations.
+ */
+#define CPIO_FILESIZE_MAX UINT32_MAX
+
+#define CPIO_NEWC_MAGIC "070701"
+#define CPIO_CRC_MAGIC "070702"
+#define CPIO_STRIPPED_MAGIC "07070X"
+#define CPIO_TRAILER "TRAILER!!!"
+
+/** \ingroup payload
+ * Cpio archive header information.
+ */
+struct cpioCrcPhysicalHeader {
+ /* char magic[6]; handled separately */
+ char inode[8];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char nlink[8];
+ char mtime[8];
+ char filesize[8];
+ char devMajor[8];
+ char devMinor[8];
+ char rdevMajor[8];
+ char rdevMinor[8];
+ char namesize[8];
+ char checksum[8]; /* ignored !! */
+};
+
+#define PHYS_HDR_SIZE 104 /* Don't depend on sizeof(struct) */
+
+struct cpioStrippedPhysicalHeader {
+ /* char magic[6]; handled separately */
+ char fx[8];
+};
+
+#define STRIPPED_PHYS_HDR_SIZE 8 /* Don't depend on sizeof(struct) */
+
rpmcpio_t rpmcpioOpen(FD_t fd, char mode)
{
if ((mode & O_ACCMODE) != O_RDONLY &&
@@ -83,16 +124,16 @@ static unsigned long strntoul(const char *str,char **endptr, int base, size_t nu
static int rpmcpioWritePad(rpmcpio_t cpio, ssize_t modulo)
{
char buf[modulo];
- ssize_t left, writen;
+ ssize_t left, written;
memset(buf, 0, modulo);
left = (modulo - ((cpio->offset) % modulo)) % modulo;
if (left <= 0)
return 0;
- writen = Fwrite(&buf, left, 1, cpio->fd);
- if (writen != left) {
- return CPIOERR_WRITE_FAILED;
+ written = Fwrite(&buf, left, 1, cpio->fd);
+ if (written != left) {
+ return RPMERR_WRITE_FAILED;
}
- cpio->offset += writen;
+ cpio->offset += written;
return 0;
}
@@ -107,7 +148,7 @@ static int rpmcpioReadPad(rpmcpio_t cpio)
read = Fread(&buf, left, 1, cpio->fd);
cpio->offset += read;
if (read != left) {
- return CPIOERR_READ_FAILED;
+ return RPMERR_READ_FAILED;
}
return 0;
}
@@ -116,7 +157,7 @@ static int rpmcpioReadPad(rpmcpio_t cpio)
\
log = strntoul(phys, &end, 16, sizeof(phys)); \
\
- if ( (end - phys) != sizeof(phys) ) return CPIOERR_BAD_HEADER;
+ if ( (end - phys) != sizeof(phys) ) return RPMERR_BAD_HEADER;
#define SET_NUM_FIELD(phys, val, space) \
sprintf(space, "%8.8lx", (unsigned long) (val)); \
\
@@ -126,10 +167,10 @@ static int rpmcpioTrailerWrite(rpmcpio_t cpio)
{
struct cpioCrcPhysicalHeader hdr;
int rc;
- size_t writen;
+ size_t written;
if (cpio->fileend != cpio->offset) {
- return CPIOERR_WRITE_FAILED;
+ return RPMERR_WRITE_FAILED;
}
rc = rpmcpioWritePad(cpio, 4);
@@ -137,18 +178,24 @@ static int rpmcpioTrailerWrite(rpmcpio_t cpio)
return rc;
memset(&hdr, '0', PHYS_HDR_SIZE);
- memcpy(&hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
memcpy(&hdr.nlink, "00000001", 8);
memcpy(&hdr.namesize, "0000000b", 8);
- writen = Fwrite(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
- cpio->offset += writen;
- if (writen != PHYS_HDR_SIZE) {
- return CPIOERR_WRITE_FAILED;
+
+ written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
+ cpio->offset += written;
+ if (written != 6) {
+ return RPMERR_WRITE_FAILED;
}
- writen = Fwrite(&CPIO_TRAILER, sizeof(CPIO_TRAILER), 1, cpio->fd);
- cpio->offset += writen;
- if (writen != sizeof(CPIO_TRAILER)) {
- return CPIOERR_WRITE_FAILED;
+
+ written = Fwrite(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
+ cpio->offset += written;
+ if (written != PHYS_HDR_SIZE) {
+ return RPMERR_WRITE_FAILED;
+ }
+ written = Fwrite(&CPIO_TRAILER, sizeof(CPIO_TRAILER), 1, cpio->fd);
+ cpio->offset += written;
+ if (written != sizeof(CPIO_TRAILER)) {
+ return RPMERR_WRITE_FAILED;
}
/*
@@ -166,20 +213,20 @@ int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
struct cpioCrcPhysicalHeader hdr_s;
struct cpioCrcPhysicalHeader * hdr = &hdr_s;
char field[64];
- size_t len, writen;
+ size_t len, written;
dev_t dev;
int rc = 0;
if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
- return CPIOERR_WRITE_FAILED;
+ return RPMERR_WRITE_FAILED;
}
if (cpio->fileend != cpio->offset) {
- return CPIOERR_WRITE_FAILED;
+ return RPMERR_WRITE_FAILED;
}
if (st->st_size >= CPIO_FILESIZE_MAX) {
- return CPIOERR_FILE_SIZE;
+ return RPMERR_FILE_SIZE;
}
rc = rpmcpioWritePad(cpio, 4);
@@ -187,7 +234,6 @@ int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
return rc;
}
- memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
SET_NUM_FIELD(hdr->inode, st->st_ino, field);
SET_NUM_FIELD(hdr->mode, st->st_mode, field);
SET_NUM_FIELD(hdr->uid, st->st_uid, field);
@@ -206,16 +252,22 @@ int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
memcpy(hdr->checksum, "00000000", 8);
- writen = Fwrite(hdr, PHYS_HDR_SIZE, 1, cpio->fd);
- cpio->offset += writen;
- if (writen != PHYS_HDR_SIZE) {
- return CPIOERR_WRITE_FAILED;
+ written = Fwrite(CPIO_NEWC_MAGIC, 6, 1, cpio->fd);
+ cpio->offset += written;
+ if (written != 6) {
+ return RPMERR_WRITE_FAILED;
+ }
+
+ written = Fwrite(hdr, PHYS_HDR_SIZE, 1, cpio->fd);
+ cpio->offset += written;
+ if (written != PHYS_HDR_SIZE) {
+ return RPMERR_WRITE_FAILED;
}
- writen = Fwrite(path, len, 1, cpio->fd);
- cpio->offset += writen;
- if (writen != len) {
- return CPIOERR_WRITE_FAILED;
+ written = Fwrite(path, len, 1, cpio->fd);
+ cpio->offset += written;
+ if (written != len) {
+ return RPMERR_WRITE_FAILED;
}
rc = rpmcpioWritePad(cpio, 4);
@@ -225,34 +277,77 @@ int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st)
return rc;
}
-ssize_t rpmcpioWrite(rpmcpio_t cpio, void * buf, size_t size)
+int rpmcpioStrippedHeaderWrite(rpmcpio_t cpio, int fx, off_t fsize)
+{
+ struct cpioStrippedPhysicalHeader hdr_s;
+ struct cpioStrippedPhysicalHeader * hdr = &hdr_s;
+ char field[64];
+ size_t written;
+ int rc = 0;
+
+ if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
+ return RPMERR_WRITE_FAILED;
+ }
+
+ if (cpio->fileend != cpio->offset) {
+ return RPMERR_WRITE_FAILED;
+ }
+
+ rc = rpmcpioWritePad(cpio, 4);
+ if (rc) {
+ return rc;
+ }
+
+ SET_NUM_FIELD(hdr->fx, fx, field);
+
+ written = Fwrite(CPIO_STRIPPED_MAGIC, 6, 1, cpio->fd);
+ cpio->offset += written;
+ if (written != 6) {
+ return RPMERR_WRITE_FAILED;
+ }
+
+ written = Fwrite(hdr, STRIPPED_PHYS_HDR_SIZE, 1, cpio->fd);
+ cpio->offset += written;
+ if (written != STRIPPED_PHYS_HDR_SIZE) {
+ return RPMERR_WRITE_FAILED;
+ }
+
+ rc = rpmcpioWritePad(cpio, 4);
+
+ cpio->fileend = cpio->offset + fsize;
+
+ return rc;
+}
+
+ssize_t rpmcpioWrite(rpmcpio_t cpio, const void * buf, size_t size)
{
- size_t writen, left;
+ size_t written, left;
if ((cpio->mode & O_ACCMODE) != O_WRONLY) {
- return CPIOERR_WRITE_FAILED;
+ return RPMERR_WRITE_FAILED;
}
// Do not write beyond file length
left = cpio->fileend - cpio->offset;
size = size > left ? left : size;
- writen = Fwrite(buf, size, 1, cpio->fd);
- cpio->offset += writen;
- return writen;
+ written = Fwrite(buf, size, 1, cpio->fd);
+ cpio->offset += written;
+ return written;
}
-int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, struct stat * st)
+int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, int * fx)
{
struct cpioCrcPhysicalHeader hdr;
int nameSize;
char * end;
- unsigned int major, minor;
int rc = 0;
ssize_t read;
+ char magic[6];
+ rpm_loff_t fsize;
if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
- return CPIOERR_READ_FAILED;
+ return RPMERR_READ_FAILED;
}
/* Move to next file */
@@ -262,7 +357,7 @@ int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, struct stat * st)
while (cpio->fileend != cpio->offset) {
read = cpio->fileend - cpio->offset > 8*BUFSIZ ? 8*BUFSIZ : cpio->fileend - cpio->offset;
if (rpmcpioRead(cpio, &buf, read) != read) {
- return CPIOERR_READ_FAILED;
+ return RPMERR_READ_FAILED;
}
}
}
@@ -270,56 +365,75 @@ int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, struct stat * st)
rc = rpmcpioReadPad(cpio);
if (rc) return rc;
- read = Fread(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
+ read = Fread(&magic, 6, 1, cpio->fd);
cpio->offset += read;
- if (read != PHYS_HDR_SIZE)
- return CPIOERR_READ_FAILED;
+ if (read != 6)
+ return RPMERR_BAD_MAGIC;
+
+ /* read stripped header */
+ if (!strncmp(CPIO_STRIPPED_MAGIC, magic,
+ sizeof(CPIO_STRIPPED_MAGIC)-1)) {
+ struct cpioStrippedPhysicalHeader shdr;
+ read = Fread(&shdr, STRIPPED_PHYS_HDR_SIZE, 1, cpio->fd);
+ cpio->offset += read;
+ if (read != STRIPPED_PHYS_HDR_SIZE)
+ return RPMERR_BAD_HEADER;
+
+ GET_NUM_FIELD(shdr.fx, *fx);
+ rc = rpmcpioReadPad(cpio);
+
+ if (!rc && *fx == -1)
+ rc = RPMERR_ITER_END;
+ return rc;
+ }
- if (strncmp(CPIO_CRC_MAGIC, hdr.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
- strncmp(CPIO_NEWC_MAGIC, hdr.magic, sizeof(CPIO_NEWC_MAGIC)-1)) {
- return CPIOERR_BAD_MAGIC;
+ if (strncmp(CPIO_CRC_MAGIC, magic, sizeof(CPIO_CRC_MAGIC)-1) &&
+ strncmp(CPIO_NEWC_MAGIC, magic, sizeof(CPIO_NEWC_MAGIC)-1)) {
+ return RPMERR_BAD_MAGIC;
}
- GET_NUM_FIELD(hdr.inode, st->st_ino);
- GET_NUM_FIELD(hdr.mode, st->st_mode);
- GET_NUM_FIELD(hdr.uid, st->st_uid);
- GET_NUM_FIELD(hdr.gid, st->st_gid);
- GET_NUM_FIELD(hdr.nlink, st->st_nlink);
- GET_NUM_FIELD(hdr.mtime, st->st_mtime);
- GET_NUM_FIELD(hdr.filesize, st->st_size);
-
- GET_NUM_FIELD(hdr.devMajor, major);
- GET_NUM_FIELD(hdr.devMinor, minor);
- st->st_dev = makedev(major, minor);
-
- GET_NUM_FIELD(hdr.rdevMajor, major);
- GET_NUM_FIELD(hdr.rdevMinor, minor);
- st->st_rdev = makedev(major, minor);
+ read = Fread(&hdr, PHYS_HDR_SIZE, 1, cpio->fd);
+ cpio->offset += read;
+ if (read != PHYS_HDR_SIZE)
+ return RPMERR_BAD_HEADER;
+
+ GET_NUM_FIELD(hdr.filesize, fsize);
GET_NUM_FIELD(hdr.namesize, nameSize);
+ if (nameSize <= 0 || nameSize > 4096) {
+ return RPMERR_BAD_HEADER;
+ }
- *path = xmalloc(nameSize + 1);
- read = Fread(*path, nameSize, 1, cpio->fd);
- (*path)[nameSize] = '\0';
+ char name[nameSize + 1];
+ read = Fread(name, nameSize, 1, cpio->fd);
+ name[nameSize] = '\0';
cpio->offset += read;
if (read != nameSize ) {
- return CPIOERR_BAD_HEADER;
+ return RPMERR_BAD_HEADER;
}
rc = rpmcpioReadPad(cpio);
- cpio->fileend = cpio->offset + st->st_size;
+ cpio->fileend = cpio->offset + fsize;
- if (!rc && rstreq(*path, CPIO_TRAILER))
- rc = CPIOERR_HDR_TRAILER;
+ if (!rc && rstreq(name, CPIO_TRAILER))
+ rc = RPMERR_ITER_END;
+
+ if (!rc && path)
+ *path = xstrdup(name);
return rc;
}
+void rpmcpioSetExpectedFileSize(rpmcpio_t cpio, off_t fsize)
+{
+ cpio->fileend = cpio->offset + fsize;
+}
+
ssize_t rpmcpioRead(rpmcpio_t cpio, void * buf, size_t size)
{
size_t read, left;
if ((cpio->mode & O_ACCMODE) != O_RDONLY) {
- return CPIOERR_READ_FAILED;
+ return RPMERR_READ_FAILED;
}
left = cpio->fileend - cpio->offset;
@@ -349,67 +463,3 @@ rpmcpio_t rpmcpioFree(rpmcpio_t cpio)
}
return NULL;
}
-
-const char * rpmcpioStrerror(int rc)
-{
- static char msg[256];
- const char *s;
- int myerrno = errno;
- size_t l;
-
- strcpy(msg, "cpio: ");
- switch (rc) {
- default: {
- char *t = msg + strlen(msg);
- sprintf(t, _("(error 0x%x)"), (unsigned)rc);
- s = NULL;
- break;
- }
- case CPIOERR_BAD_MAGIC: s = _("Bad magic"); break;
- case CPIOERR_BAD_HEADER: s = _("Bad/unreadable header");break;
-
- case CPIOERR_OPEN_FAILED: s = "open"; break;
- case CPIOERR_CHMOD_FAILED: s = "chmod"; break;
- case CPIOERR_CHOWN_FAILED: s = "chown"; break;
- case CPIOERR_WRITE_FAILED: s = "write"; break;
- case CPIOERR_UTIME_FAILED: s = "utime"; break;
- case CPIOERR_UNLINK_FAILED: s = "unlink"; break;
- case CPIOERR_RENAME_FAILED: s = "rename"; break;
- case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
- case CPIOERR_STAT_FAILED: s = "stat"; break;
- case CPIOERR_LSTAT_FAILED: s = "lstat"; break;
- case CPIOERR_MKDIR_FAILED: s = "mkdir"; break;
- case CPIOERR_RMDIR_FAILED: s = "rmdir"; break;
- case CPIOERR_MKNOD_FAILED: s = "mknod"; break;
- case CPIOERR_MKFIFO_FAILED: s = "mkfifo"; break;
- case CPIOERR_LINK_FAILED: s = "link"; break;
- case CPIOERR_READLINK_FAILED: s = "readlink"; break;
- case CPIOERR_READ_FAILED: s = "read"; break;
- case CPIOERR_COPY_FAILED: s = "copy"; break;
- case CPIOERR_LSETFCON_FAILED: s = "lsetfilecon"; break;
- case CPIOERR_SETCAP_FAILED: s = "cap_set_file"; break;
-
- case CPIOERR_HDR_SIZE: s = _("Header size too big"); break;
- case CPIOERR_FILE_SIZE: s = _("File too large for archive"); break;
- case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
- case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link(s)"); break;
- case CPIOERR_DIGEST_MISMATCH: s = _("Digest mismatch"); break;
- case CPIOERR_INTERNAL: s = _("Internal error"); break;
- case CPIOERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
- case CPIOERR_ENOENT: s = strerror(ENOENT); break;
- case CPIOERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break;
- }
-
- l = sizeof(msg) - strlen(msg) - 1;
- if (s != NULL) {
- if (l > 0) strncat(msg, s, l);
- l -= strlen(s);
- }
- if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
- s = _(" failed - ");
- if (l > 0) strncat(msg, s, l);
- l -= strlen(s);
- if (l > 0) strncat(msg, strerror(myerrno), l);
- }
- return msg;
-}
diff --git a/lib/cpio.h b/lib/cpio.h
index 7364caf27..b33b5fc13 100644
--- a/lib/cpio.h
+++ b/lib/cpio.h
@@ -12,81 +12,6 @@
*
*/
-/** \ingroup payload
- * @note CPIO_CHECK_ERRNO bit is set only if errno is valid.
- */
-#define CPIOERR_CHECK_ERRNO 0x00008000
-
-/** \ingroup payload
- */
-enum cpioErrorReturns {
- CPIOERR_BAD_MAGIC = 2,
- CPIOERR_BAD_HEADER = 3,
- CPIOERR_OPEN_FAILED = 4 | CPIOERR_CHECK_ERRNO,
- CPIOERR_CHMOD_FAILED = 5 | CPIOERR_CHECK_ERRNO,
- CPIOERR_CHOWN_FAILED = 6 | CPIOERR_CHECK_ERRNO,
- CPIOERR_WRITE_FAILED = 7 | CPIOERR_CHECK_ERRNO,
- CPIOERR_UTIME_FAILED = 8 | CPIOERR_CHECK_ERRNO,
- CPIOERR_UNLINK_FAILED = 9 | CPIOERR_CHECK_ERRNO,
- CPIOERR_RENAME_FAILED = 10 | CPIOERR_CHECK_ERRNO,
- CPIOERR_SYMLINK_FAILED = 11 | CPIOERR_CHECK_ERRNO,
- CPIOERR_STAT_FAILED = 12 | CPIOERR_CHECK_ERRNO,
- CPIOERR_LSTAT_FAILED = 13 | CPIOERR_CHECK_ERRNO,
- CPIOERR_MKDIR_FAILED = 14 | CPIOERR_CHECK_ERRNO,
- CPIOERR_RMDIR_FAILED = 15 | CPIOERR_CHECK_ERRNO,
- CPIOERR_MKNOD_FAILED = 16 | CPIOERR_CHECK_ERRNO,
- CPIOERR_MKFIFO_FAILED = 17 | CPIOERR_CHECK_ERRNO,
- CPIOERR_LINK_FAILED = 18 | CPIOERR_CHECK_ERRNO,
- CPIOERR_READLINK_FAILED = 19 | CPIOERR_CHECK_ERRNO,
- CPIOERR_READ_FAILED = 20 | CPIOERR_CHECK_ERRNO,
- CPIOERR_COPY_FAILED = 21 | CPIOERR_CHECK_ERRNO,
- CPIOERR_LSETFCON_FAILED = 22 | CPIOERR_CHECK_ERRNO,
- CPIOERR_HDR_SIZE = 23,
- CPIOERR_HDR_TRAILER = 24,
- CPIOERR_UNKNOWN_FILETYPE= 25,
- CPIOERR_MISSING_HARDLINK= 26,
- CPIOERR_DIGEST_MISMATCH = 27,
- CPIOERR_INTERNAL = 28,
- CPIOERR_UNMAPPED_FILE = 29,
- CPIOERR_ENOENT = 30,
- CPIOERR_ENOTEMPTY = 31,
- CPIOERR_SETCAP_FAILED = 32 | CPIOERR_CHECK_ERRNO,
- CPIOERR_FILE_SIZE = 33,
-};
-
-/*
- * Size limit for individual files in "new ascii format" cpio archives.
- * The max size of the entire archive is unlimited from cpio POV,
- * but subject to filesystem limitations.
- */
-#define CPIO_FILESIZE_MAX UINT32_MAX
-
-#define CPIO_NEWC_MAGIC "070701"
-#define CPIO_CRC_MAGIC "070702"
-#define CPIO_TRAILER "TRAILER!!!"
-
-/** \ingroup payload
- * Cpio archive header information.
- */
-struct cpioCrcPhysicalHeader {
- char magic[6];
- char inode[8];
- char mode[8];
- char uid[8];
- char gid[8];
- char nlink[8];
- char mtime[8];
- char filesize[8];
- char devMajor[8];
- char devMinor[8];
- char rdevMajor[8];
- char rdevMinor[8];
- char namesize[8];
- char checksum[8]; /* ignored !! */
-};
-
-#define PHYS_HDR_SIZE 110 /* Don't depend on sizeof(struct) */
-
typedef struct rpmcpio_s * rpmcpio_t;
#ifdef __cplusplus
@@ -109,33 +34,43 @@ rpmcpio_t rpmcpioFree(rpmcpio_t cpio);
/**
* Write cpio header.
- * @retval fsm file path and stat info
- * @param st
+ * @param cpio cpio archive
+ * @param path file name
+ * @param st stat struct with meta data
* @return 0 on success
*/
RPM_GNUC_INTERNAL
int rpmcpioHeaderWrite(rpmcpio_t cpio, char * path, struct stat * st);
+RPM_GNUC_INTERNAL
+int rpmcpioStrippedHeaderWrite(rpmcpio_t cpio, int fx, off_t fsize);
-ssize_t rpmcpioWrite(rpmcpio_t cpio, void * buf, size_t size);
+ssize_t rpmcpioWrite(rpmcpio_t cpio, const void * buf, size_t size);
/**
- * Read cpio header.
+ * Read cpio header. Iff fx is returned as -1 a cpio header was read
+ * and the file name is found in path. Otherwise a stripped header was read
+ * and the fx is the number of the file in the header/rpmfi. In this case
+ * rpmcpioSetExpectedFileSize() needs to be called with the file size of the
+ * payload content - with may be zero for hard links, directory or other
+ * special files.
* @retval fsm file path and stat info
- * @retval st
+ * @retval path path of the file
+ * @retval fx number in the header of the file read
* @return 0 on success
*/
RPM_GNUC_INTERNAL
-int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, struct stat * st);
-
-ssize_t rpmcpioRead(rpmcpio_t cpio, void * buf, size_t size);
+int rpmcpioHeaderRead(rpmcpio_t cpio, char ** path, int * fx);
-/** \ingroup payload
- * Return formatted error message on payload handling failure.
- * @param rc error code
- * @return formatted error string
+/**
+ * Tell the cpio object the expected file size in the payload.
+ * The size must be zero for all but the last of hard linked files,
+ * directories and special files.
+ * This is needed after reading a stripped cpio header! See above.
*/
-/* XXX should be RPM_GNUC_INTERNAL too but build/pack.c uses */
-const char * rpmcpioStrerror(int rc);
+RPM_GNUC_INTERNAL
+void rpmcpioSetExpectedFileSize(rpmcpio_t cpio, off_t fsize);
+
+ssize_t rpmcpioRead(rpmcpio_t cpio, void * buf, size_t size);
#ifdef __cplusplus
}
diff --git a/lib/depends.c b/lib/depends.c
index fa11725a8..4719b6738 100644
--- a/lib/depends.c
+++ b/lib/depends.c
@@ -14,8 +14,11 @@
#include "lib/rpmts_internal.h"
#include "lib/rpmte_internal.h"
#include "lib/rpmds_internal.h"
+#include "lib/rpmfi_internal.h" /* rpmfiles stuff for now */
#include "lib/misc.h"
+#include "lib/backend/dbiset.h"
+
#include "debug.h"
const char * const RPMVERSION = VERSION;
@@ -39,7 +42,7 @@ const int rpmFLAGS = RPMSENSE_EQUAL;
#undef HTKEYTYPE
#undef HTDATATYPE
-#define HASHTYPE removedHash
+#define HASHTYPE packageHash
#define HTKEYTYPE unsigned int
#define HTDATATYPE struct rpmte_s *
#include "rpmhash.C"
@@ -47,6 +50,28 @@ const int rpmFLAGS = RPMSENSE_EQUAL;
#undef HTKEYTYPE
#undef HTDATATYPE
+#define HASHTYPE filedepHash
+#define HTKEYTYPE const char *
+#define HTDATATYPE const char *
+#include "rpmhash.H"
+#include "rpmhash.C"
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+
+#define HASHTYPE depexistsHash
+#define HTKEYTYPE const char *
+#include "lib/rpmhash.H"
+#include "lib/rpmhash.C"
+#undef HASHTYPE
+#undef HTKEYTYPE
+
+enum addOp_e {
+ RPMTE_INSTALL = 0,
+ RPMTE_UPGRADE = 1,
+ RPMTE_REINSTALL = 2,
+};
+
/**
* Check for supported payload format in header.
* @param h header to check
@@ -88,22 +113,23 @@ static rpmRC headerCheckPayloadFormat(Header h) {
static int removePackage(rpmts ts, Header h, rpmte depends)
{
tsMembers tsmem = rpmtsMembers(ts);
- rpmte p;
+ rpmte p, *pp;
unsigned int dboffset = headerGetInstance(h);
/* Can't remove what's not installed */
if (dboffset == 0) return 1;
/* Filter out duplicate erasures. */
- if (removedHashHasEntry(tsmem->removedPackages, dboffset)) {
- return 0;
+ if (packageHashGetEntry(tsmem->removedPackages, dboffset, &pp, NULL, NULL)) {
+ rpmteSetDependsOn(pp[0], depends);
+ return 0;
}
p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL);
if (p == NULL)
return 1;
- removedHashAddEntry(tsmem->removedPackages, dboffset, p);
+ packageHashAddEntry(tsmem->removedPackages, dboffset, p);
if (tsmem->orderCount >= tsmem->orderAlloced) {
tsmem->orderAlloced += (tsmem->orderCount - tsmem->orderAlloced) + tsmem->delta;
@@ -119,7 +145,7 @@ static int removePackage(rpmts ts, Header h, rpmte depends)
}
/* Return rpmdb iterator with removals optionally pruned out */
-static rpmdbMatchIterator rpmtsPrunedIterator(rpmts ts, rpmDbiTagVal tag,
+rpmdbMatchIterator rpmtsPrunedIterator(rpmts ts, rpmDbiTagVal tag,
const char * key, int prune)
{
rpmdbMatchIterator mi = rpmtsInitIterator(ts, tag, key, 0);
@@ -163,22 +189,29 @@ static int rpmNameVersionCompare(Header first, Header second)
}
/* Add erase elements for older packages of same color (if any). */
-static int addUpgradeErasures(rpmts ts, rpm_color_t tscolor,
+static int addSelfErasures(rpmts ts, rpm_color_t tscolor, int op,
rpmte p, rpm_color_t hcolor, Header h)
{
Header oh;
rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(p), 0);
int rc = 0;
+ int cmp;
- while((oh = rpmdbNextIterator(mi)) != NULL) {
+ while ((oh = rpmdbNextIterator(mi)) != NULL) {
/* Ignore colored packages not in our rainbow. */
if (skipColor(tscolor, hcolor, headerGetNumber(oh, RPMTAG_HEADERCOLOR)))
continue;
- /* Skip packages that contain identical NEVRA. */
- if (rpmNameVersionCompare(h, oh) == 0)
+ cmp = rpmNameVersionCompare(h, oh);
+
+ /* On upgrade, skip packages that contain identical NEVR. */
+ if ((op == RPMTE_UPGRADE) && (cmp == 0))
continue;
+ /* On reinstall, skip packages with differing NEVR. */
+ if ((op == RPMTE_REINSTALL) && (cmp != 0))
+ continue;
+
if (removePackage(ts, oh, p)) {
rc = 1;
break;
@@ -205,7 +238,7 @@ static int addObsoleteErasures(rpmts ts, rpm_color_t tscolor, rpmte p)
mi = rpmtsPrunedIterator(ts, RPMDBI_NAME, Name, 1);
- while((oh = rpmdbNextIterator(mi)) != NULL) {
+ while ((oh = rpmdbNextIterator(mi)) != NULL) {
const char *oarch = headerGetString(oh, RPMTAG_ARCH);
int match;
@@ -396,8 +429,8 @@ rpmal rpmtsCreateAl(rpmts ts, rpmElementTypes types)
return al;
}
-int rpmtsAddInstallElement(rpmts ts, Header h,
- fnpyKey key, int upgrade, rpmRelocation * relocs)
+static int addPackage(rpmts ts, Header h,
+ fnpyKey key, int op, rpmRelocation * relocs)
{
tsMembers tsmem = rpmtsMembers(ts);
rpm_color_t tscolor = rpmtsColor(ts);
@@ -414,10 +447,10 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
/* Source packages are never "upgraded" */
if (isSource)
- upgrade = 0;
+ op = RPMTE_INSTALL;
/* Do lazy (readonly?) open of rpm database for upgrades. */
- if (upgrade && rpmtsGetRdb(ts) == NULL && rpmtsGetDBMode(ts) != -1) {
+ if (op != RPMTE_INSTALL && rpmtsGetRdb(ts) == NULL && rpmtsGetDBMode(ts) != -1) {
if ((ec = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0)
goto exit;
}
@@ -430,7 +463,7 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
/* Check binary packages for redundancies in the set */
if (!isSource) {
- oc = findPos(ts, tscolor, p, upgrade);
+ oc = findPos(ts, tscolor, p, (op == RPMTE_UPGRADE));
/* If we're replacing a previously added element, free the old one */
if (oc >= 0 && oc < tsmem->orderCount) {
rpmalDel(tsmem->addedPackages, tsmem->order[oc]);
@@ -462,22 +495,42 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
/* Add erasure elements for old versions and obsoletions on upgrades */
/* XXX TODO: If either of these fails, we'd need to undo all additions */
- if (upgrade) {
- addUpgradeErasures(ts, tscolor, p, rpmteColor(p), h);
+ if (op != RPMTE_INSTALL)
+ addSelfErasures(ts, tscolor, op, p, rpmteColor(p), h);
+ if (op == RPMTE_UPGRADE)
addObsoleteErasures(ts, tscolor, p);
- }
exit:
return ec;
}
+int rpmtsAddInstallElement(rpmts ts, Header h,
+ fnpyKey key, int upgrade, rpmRelocation * relocs)
+{
+ int op = (upgrade == 0) ? RPMTE_INSTALL : RPMTE_UPGRADE;
+ if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
+ return 1;
+ return addPackage(ts, h, key, op, relocs);
+}
+
+int rpmtsAddReinstallElement(rpmts ts, Header h, fnpyKey key)
+{
+ if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
+ return 1;
+ /* TODO: pull relocations from installed package */
+ /* TODO: should reinstall of non-installed package fail? */
+ return addPackage(ts, h, key, RPMTE_REINSTALL, NULL);
+}
+
int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
{
+ if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
+ return 1;
return removePackage(ts, h, NULL);
}
/* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */
-static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
+static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep, dbiIndexSet *matches)
{
const char * Name = rpmdsN(dep);
const char * DNEVR = rpmdsDNEVR(dep);
@@ -491,7 +544,7 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
unsigned int keyhash = 0;
/* See if we already looked this up */
- if (prune) {
+ if (prune && !matches) {
keyhash = depCacheKeyHash(dcache, DNEVR);
if (depCacheGetHEntry(dcache, DNEVR, keyhash, &cachedrc, NULL, NULL)) {
rc = *cachedrc;
@@ -500,6 +553,8 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
}
}
+ if (matches)
+ *matches = dbiIndexSetNew(0);
/*
* See if a filename dependency is a real file in some package,
* taking file state into account: replaced, wrong colored and
@@ -508,6 +563,16 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
if (deptag != RPMTAG_OBSOLETENAME && Name[0] == '/') {
mi = rpmtsPrunedIterator(ts, RPMDBI_INSTFILENAMES, Name, prune);
while ((h = rpmdbNextIterator(mi)) != NULL) {
+ /* Ignore self-conflicts */
+ if (deptag == RPMTAG_CONFLICTNAME) {
+ unsigned int instance = headerGetInstance(h);
+ if (instance && instance == rpmdsInstance(dep))
+ continue;
+ }
+ if (matches) {
+ dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
+ continue;
+ }
rpmdsNotify(dep, "(db files)", rc);
break;
}
@@ -531,7 +596,17 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
int prix = (selfevr) ? -1 : rpmdbGetIteratorFileNum(mi);
int match = rpmdsMatches(tspool, h, prix, dep, selfevr,
_rpmds_nopromote);
+ /* Ignore self-obsoletes and self-conflicts */
+ if (match && (deptag == RPMTAG_OBSOLETENAME || deptag == RPMTAG_CONFLICTNAME)) {
+ unsigned int instance = headerGetInstance(h);
+ if (instance && instance == rpmdsInstance(dep))
+ match = 0;
+ }
if (match) {
+ if (matches) {
+ dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
+ continue;
+ }
rpmdsNotify(dep, "(db provides)", rc);
break;
}
@@ -540,16 +615,85 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
}
rc = (h != NULL) ? 0 : 1;
+ if (matches) {
+ dbiIndexSetUniq(*matches, 0);
+ rc = dbiIndexSetCount(*matches) ? 0 : 1;
+ }
+
/* Cache the relatively expensive rpmdb lookup results */
/* Caching the oddball non-pruned case would mess up other results */
- if (prune)
+ if (prune && !matches)
depCacheAddHEntry(dcache, xstrdup(DNEVR), keyhash, rc);
return rc;
}
+static dbiIndexSet unsatisfiedDependSet(rpmts ts, rpmds dep)
+{
+ dbiIndexSet set1 = NULL, set2 = NULL;
+ tsMembers tsmem = rpmtsMembers(ts);
+ rpmsenseFlags dsflags = rpmdsFlags(dep);
+
+ if (dsflags & RPMSENSE_RPMLIB)
+ goto exit;
+
+ if (rpmdsIsRich(dep)) {
+ rpmds ds1, ds2;
+ rpmrichOp op;
+ char *emsg = 0;
+
+ if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {
+ rpmdsNotify(dep, emsg ? emsg : "(parse error)", 1);
+ _free(emsg);
+ goto exit;
+ }
+ /* only a subset of ops is supported in set mode */
+ if (op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT
+ && op != RPMRICHOP_OR && op != RPMRICHOP_SINGLE) {
+ rpmdsNotify(dep, "(unsupported op in set mode)", 1);
+ goto exit_rich;
+ }
+
+ set1 = unsatisfiedDependSet(ts, ds1);
+ if (op == RPMRICHOP_SINGLE)
+ goto exit_rich;
+ if (op != RPMRICHOP_OR && dbiIndexSetCount(set1) == 0)
+ goto exit_rich;
+ set2 = unsatisfiedDependSet(ts, ds2);
+ if (op == RPMRICHOP_WITH) {
+ dbiIndexSetFilterSet(set1, set2, 0);
+ } else if (op == RPMRICHOP_WITHOUT) {
+ dbiIndexSetPruneSet(set1, set2, 0);
+ } else if (op == RPMRICHOP_OR) {
+ dbiIndexSetAppendSet(set1, set2, 0);
+ }
+exit_rich:
+ ds1 = rpmdsFree(ds1);
+ ds2 = rpmdsFree(ds2);
+ goto exit;
+ }
+
+ /* match database entries */
+ rpmdbProvides(ts, NULL, dep, &set1);
+
+ /* Pretrans dependencies can't be satisfied by added packages. */
+ if (!(dsflags & RPMSENSE_PRETRANS)) {
+ rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
+ if (matches) {
+ for (rpmte *p = matches; *p; p++)
+ dbiIndexSetAppendOne(set1, rpmalLookupTE(tsmem->addedPackages, *p), 1, 0);
+ }
+ _free(matches);
+ }
+
+exit:
+ set2 = dbiIndexSetFree(set2);
+ return set1 ? set1 : dbiIndexSetNew(0);
+}
+
/**
* Check dep for an unsatisfied dependency.
* @param ts transaction set
+ * @param dcache dependency cache
* @param dep dependency
* @return 0 if satisfied, 1 if not satisfied
*/
@@ -584,29 +728,78 @@ retry:
if (!adding && isInstallPreReq(dsflags) && !isErasePreReq(dsflags))
goto exit;
+ /* Handle rich dependencies */
+ if (rpmdsIsRich(dep)) {
+ rpmds ds1, ds2;
+ rpmrichOp op;
+ char *emsg = 0;
+ if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {
+ rc = rpmdsTagN(dep) == RPMTAG_CONFLICTNAME ? 0 : 1;
+ if (rpmdsInstance(dep) != 0)
+ rc = !rc; /* ignore errors for installed packages */
+ rpmdsNotify(dep, emsg ? emsg : "(parse error)", rc);
+ _free(emsg);
+ goto exit;
+ }
+ if (op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) {
+ /* switch to set mode processing */
+ dbiIndexSet set = unsatisfiedDependSet(ts, dep);
+ rc = dbiIndexSetCount(set) ? 0 : 1;
+ dbiIndexSetFree(set);
+ ds1 = rpmdsFree(ds1);
+ ds2 = rpmdsFree(ds2);
+ rpmdsNotify(dep, "(rich)", rc);
+ goto exit;
+ }
+ if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS) {
+ /* A IF B -> A OR NOT(B) */
+ /* A UNLESS B -> A AND NOT(B) */
+ if (rpmdsIsRich(ds2)) {
+ /* check if this has an ELSE clause */
+ rpmds ds21 = NULL, ds22 = NULL;
+ rpmrichOp op2;
+ if (rpmdsParseRichDep(ds2, &ds21, &ds22, &op2, NULL) == RPMRC_OK && op2 == RPMRICHOP_ELSE) {
+ /* A IF B ELSE C -> (A OR NOT(B)) AND (C OR B) */
+ /* A UNLESS B ELSE C -> (A AND NOT(B)) OR (C AND B) */
+ rc = !unsatisfiedDepend(ts, dcache, ds21); /* NOT(B) */
+ if ((rc && op == RPMRICHOP_IF) || (!rc && op == RPMRICHOP_UNLESS)) {
+ rc = unsatisfiedDepend(ts, dcache, ds1); /* A */
+ } else {
+ rc = unsatisfiedDepend(ts, dcache, ds22); /* C */
+ }
+ rpmdsFree(ds21);
+ rpmdsFree(ds22);
+ goto exitrich;
+ }
+ rpmdsFree(ds21);
+ rpmdsFree(ds22);
+ }
+ rc = !unsatisfiedDepend(ts, dcache, ds2); /* NOT(B) */
+ if ((rc && op == RPMRICHOP_IF) || (!rc && op == RPMRICHOP_UNLESS))
+ rc = unsatisfiedDepend(ts, dcache, ds1);
+ } else {
+ rc = unsatisfiedDepend(ts, dcache, ds1);
+ if ((rc && op == RPMRICHOP_OR) || (!rc && op == RPMRICHOP_AND))
+ rc = unsatisfiedDepend(ts, dcache, ds2);
+ }
+exitrich:
+ ds1 = rpmdsFree(ds1);
+ ds2 = rpmdsFree(ds2);
+ rpmdsNotify(dep, "(rich)", rc);
+ goto exit;
+ }
+
/* Pretrans dependencies can't be satisfied by added packages. */
if (!(dsflags & RPMSENSE_PRETRANS)) {
- rpmte match = rpmalSatisfiesDepend(tsmem->addedPackages, dep);
-
- /*
- * Handle definitive matches within the added package set.
- * Self-obsoletes and -conflicts fall through here as we need to
- * check for possible other matches in the rpmdb.
- */
- if (match) {
- rpmTagVal dtag = rpmdsTagN(dep);
- /* Requires match, look no further */
- if (dtag == RPMTAG_REQUIRENAME)
- goto exit;
-
- /* Conflicts/obsoletes match on another package, look no further */
- if (rpmteDS(match, dtag) != dep)
- goto exit;
- }
+ rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
+ int match = matches && *matches;
+ _free(matches);
+ if (match)
+ goto exit;
}
/* See if the rpmdb provides it */
- if (rpmdbProvides(ts, dcache, dep) == 0)
+ if (rpmdbProvides(ts, dcache, dep, NULL) == 0)
goto exit;
/* Search for an unsatisfied dependency. */
@@ -637,7 +830,7 @@ exit:
/* Check a dependency set for problems */
static void checkDS(rpmts ts, depCache dcache, rpmte te,
const char * pkgNEVRA, rpmds ds,
- const char * depName, rpm_color_t tscolor)
+ rpm_color_t tscolor)
{
rpm_color_t dscolor;
/* require-problems are unsatisfied, others appear "satisfied" */
@@ -645,10 +838,6 @@ static void checkDS(rpmts ts, depCache dcache, rpmte te,
ds = rpmdsInit(ds);
while (rpmdsNext(ds) >= 0) {
- /* Filter out dependencies that came along for the ride. */
- if (depName != NULL && !rstreq(depName, rpmdsN(ds)))
- continue;
-
/* Ignore colored dependencies not in our rainbow. */
dscolor = rpmdsColor(ds);
if (tscolor && dscolor && !(tscolor & dscolor))
@@ -659,19 +848,33 @@ static void checkDS(rpmts ts, depCache dcache, rpmte te,
}
}
-/* Check a given dependency type against installed packages */
+/* Check a given dependency against installed packages */
static void checkInstDeps(rpmts ts, depCache dcache, rpmte te,
rpmTag depTag, const char *dep)
{
Header h;
rpmdbMatchIterator mi = rpmtsPrunedIterator(ts, depTag, dep, 1);
rpmstrPool pool = rpmtsPool(ts);
+ /* require-problems are unsatisfied, others appear "satisfied" */
+ int is_problem = (depTag == RPMTAG_REQUIRENAME);
while ((h = rpmdbNextIterator(mi)) != NULL) {
- char * pkgNEVRA = headerGetAsString(h, RPMTAG_NEVRA);
- rpmds ds = rpmdsNewPool(pool, h, depTag, 0);
+ char * pkgNEVRA;
+ rpmds ds;
- checkDS(ts, dcache, te, pkgNEVRA, ds, dep, 0);
+ /* Ignore self-obsoletes and self-conflicts */
+ if (depTag == RPMTAG_OBSOLETENAME || depTag == RPMTAG_CONFLICTNAME) {
+ unsigned int instance = headerGetInstance(h);
+ if (instance && instance == rpmteDBInstance(te))
+ continue;
+ }
+
+ pkgNEVRA = headerGetAsString(h, RPMTAG_NEVRA);
+ ds = rpmdsNewPool(pool, h, depTag, 0);
+ rpmdsSetIx(ds, rpmdbGetIteratorFileNum(mi));
+
+ if (unsatisfiedDepend(ts, dcache, ds) == is_problem)
+ rpmteAddDepProblem(te, pkgNEVRA, ds, NULL);
rpmdsFree(ds);
free(pkgNEVRA);
@@ -679,6 +882,116 @@ static void checkInstDeps(rpmts ts, depCache dcache, rpmte te,
rpmdbFreeIterator(mi);
}
+static void checkNotInstDeps(rpmts ts, depCache dcache, rpmte te,
+ rpmTag depTag, const char *dep)
+{
+ char *ndep = rmalloc(strlen(dep) + 2);
+ ndep[0] = '!';
+ strcpy(ndep + 1, dep);
+ checkInstDeps(ts, dcache, te, depTag, ndep);
+ free(ndep);
+}
+
+static void checkInstFileDeps(rpmts ts, depCache dcache, rpmte te,
+ rpmTag depTag, rpmfi fi, int is_not,
+ filedepHash cache, fingerPrintCache *fpcp)
+{
+ fingerPrintCache fpc = *fpcp;
+ fingerPrint * fp = NULL;
+ const char *basename = rpmfiBN(fi);
+ const char *dirname;
+ const char **dirnames = 0;
+ int ndirnames = 0;
+ int i;
+
+ filedepHashGetEntry(cache, basename, &dirnames, &ndirnames, NULL);
+ if (!ndirnames)
+ return;
+ if (!fpc)
+ *fpcp = fpc = fpCacheCreate(1001, NULL);
+ dirname = rpmfiDN(fi);
+ fpLookup(fpc, dirname, basename, &fp);
+ for (i = 0; i < ndirnames; i++) {
+ char *fpdep = 0;
+ const char *dep;
+ if (!strcmp(dirnames[i], dirname)) {
+ dep = rpmfiFN(fi);
+ } else if (fpLookupEquals(fpc, fp, dirnames[i], basename)) {
+ fpdep = rmalloc(strlen(dirnames[i]) + strlen(basename) + 1);
+ strcpy(fpdep, dirnames[i]);
+ strcat(fpdep, basename);
+ dep = fpdep;
+ } else {
+ continue;
+ }
+ if (!is_not)
+ checkInstDeps(ts, dcache, te, depTag, dep);
+ else
+ checkNotInstDeps(ts, dcache, te, depTag, dep);
+ _free(fpdep);
+ }
+ _free(fp);
+}
+
+static void addFileDepToHash(filedepHash hash, char *key, size_t keylen)
+{
+ int i;
+ char *basename, *dirname;
+ if (!keylen || key[0] != '/')
+ return;
+ for (i = keylen - 1; key[i] != '/'; i--)
+ ;
+ dirname = rmalloc(i + 2);
+ memcpy(dirname, key, i + 1);
+ dirname[i + 1] = 0;
+ basename = rmalloc(keylen - i);
+ memcpy(basename, key + i + 1, keylen - i - 1);
+ basename[keylen - i - 1] = 0;
+ filedepHashAddEntry(hash, basename, dirname);
+}
+
+static void addDepToHash(depexistsHash hash, char *key, size_t keylen)
+{
+ char *keystr;
+ if (!keylen)
+ return;
+ keystr = rmalloc(keylen + 1);
+ strncpy(keystr, key, keylen);
+ keystr[keylen] = 0;
+ depexistsHashAddEntry(hash, keystr);
+}
+
+static void addIndexToDepHashes(rpmts ts, rpmDbiTag tag,
+ depexistsHash dephash, filedepHash filehash,
+ depexistsHash depnothash, filedepHash filenothash)
+{
+ char *key;
+ size_t keylen;
+ rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), tag);
+
+ if (!ii)
+ return;
+ while ((rpmdbIndexIteratorNext(ii, (const void**)&key, &keylen)) == 0) {
+ if (!key || !keylen)
+ continue;
+ if (*key == '!' && keylen > 1) {
+ key++;
+ keylen--;
+ if (*key == '/' && filenothash)
+ addFileDepToHash(filenothash, key, keylen);
+ if (depnothash)
+ addDepToHash(depnothash, key, keylen);
+ } else {
+ if (*key == '/' && filehash)
+ addFileDepToHash(filehash, key, keylen);
+ if (dephash)
+ addDepToHash(dephash, key, keylen);
+ }
+ }
+ rpmdbIndexIteratorFree(ii);
+}
+
+
int rpmtsCheck(rpmts ts)
{
rpm_color_t tscolor = rpmtsColor(ts);
@@ -686,20 +999,67 @@ int rpmtsCheck(rpmts ts)
int closeatexit = 0;
int rc = 0;
depCache dcache = NULL;
+ filedepHash confilehash = NULL; /* file conflicts of installed packages */
+ filedepHash connotfilehash = NULL; /* file conflicts of installed packages */
+ depexistsHash connothash = NULL;
+ filedepHash reqfilehash = NULL; /* file requires of installed packages */
+ filedepHash reqnotfilehash = NULL; /* file requires of installed packages */
+ depexistsHash reqnothash = NULL;
+ fingerPrintCache fpc = NULL;
+ rpmdb rdb = NULL;
(void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
/* Do lazy, readonly, open of rpm database. */
- if (rpmtsGetRdb(ts) == NULL && rpmtsGetDBMode(ts) != -1) {
+ rdb = rpmtsGetRdb(ts);
+ if (rdb == NULL && rpmtsGetDBMode(ts) != -1) {
if ((rc = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0)
goto exit;
+ rdb = rpmtsGetRdb(ts);
closeatexit = 1;
}
+ if (rdb)
+ rpmdbCtrl(rdb, RPMDB_CTRL_LOCK_RO);
+
/* XXX FIXME: figure some kind of heuristic for the cache size */
dcache = depCacheCreate(5001, rstrhash, strcmp,
(depCacheFreeKey)rfree, NULL);
+ /* build hashes of all confilict sdependencies */
+ confilehash = filedepHashCreate(257, rstrhash, strcmp,
+ (filedepHashFreeKey)rfree,
+ (filedepHashFreeData)rfree);
+ connothash = depexistsHashCreate(257, rstrhash, strcmp,
+ (filedepHashFreeKey)rfree);
+ connotfilehash = filedepHashCreate(257, rstrhash, strcmp,
+ (filedepHashFreeKey)rfree,
+ (filedepHashFreeData)rfree);
+ addIndexToDepHashes(ts, RPMTAG_CONFLICTNAME, NULL, confilehash, connothash, connotfilehash);
+ if (!filedepHashNumKeys(confilehash))
+ confilehash = filedepHashFree(confilehash);
+ if (!depexistsHashNumKeys(connothash))
+ connothash= depexistsHashFree(connothash);
+ if (!filedepHashNumKeys(connotfilehash))
+ connotfilehash = filedepHashFree(connotfilehash);
+
+ /* build hashes of all requires dependencies */
+ reqfilehash = filedepHashCreate(8191, rstrhash, strcmp,
+ (filedepHashFreeKey)rfree,
+ (filedepHashFreeData)rfree);
+ reqnothash = depexistsHashCreate(257, rstrhash, strcmp,
+ (filedepHashFreeKey)rfree);
+ reqnotfilehash = filedepHashCreate(257, rstrhash, strcmp,
+ (filedepHashFreeKey)rfree,
+ (filedepHashFreeData)rfree);
+ addIndexToDepHashes(ts, RPMTAG_REQUIRENAME, NULL, reqfilehash, reqnothash, reqnotfilehash);
+ if (!filedepHashNumKeys(reqfilehash))
+ reqfilehash = filedepHashFree(reqfilehash);
+ if (!depexistsHashNumKeys(reqnothash))
+ reqnothash= depexistsHashFree(reqnothash);
+ if (!filedepHashNumKeys(reqnotfilehash))
+ reqnotfilehash = filedepHashFree(reqnotfilehash);
+
/*
* Look at all of the added packages and make sure their dependencies
* are satisfied.
@@ -712,15 +1072,18 @@ int rpmtsCheck(rpmts ts)
rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_REQUIRENAME),
- NULL, tscolor);
+ tscolor);
checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_CONFLICTNAME),
- NULL, tscolor);
+ tscolor);
checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_OBSOLETENAME),
- NULL, tscolor);
+ tscolor);
/* Check provides against conflicts in installed packages. */
while (rpmdsNext(provides) >= 0) {
- checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, rpmdsN(provides));
+ const char *dep = rpmdsN(provides);
+ checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep);
+ if (reqnothash && depexistsHashHasEntry(reqnothash, dep))
+ checkNotInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep);
}
/* Skip obsoletion checks for source packages (ie build) */
@@ -729,6 +1092,20 @@ int rpmtsCheck(rpmts ts)
/* Check package name (not provides!) against installed obsoletes */
checkInstDeps(ts, dcache, p, RPMTAG_OBSOLETENAME, rpmteN(p));
+
+ /* Check filenames against installed conflicts */
+ if (confilehash || reqnotfilehash) {
+ rpmfiles files = rpmteFiles(p);
+ rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);
+ while (rpmfiNext(fi) >= 0) {
+ if (confilehash)
+ checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 0, confilehash, &fpc);
+ if (reqnotfilehash)
+ checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 1, reqnotfilehash, &fpc);
+ }
+ rpmfiFree(fi);
+ rpmfilesFree(files);
+ }
}
rpmtsiFree(pi);
@@ -738,25 +1115,47 @@ int rpmtsCheck(rpmts ts)
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME));
- rpmfi fi = rpmfiInit(rpmteFI(p), 0);
rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n",
rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
/* Check provides and filenames against installed dependencies. */
while (rpmdsNext(provides) >= 0) {
- checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, rpmdsN(provides));
+ const char *dep = rpmdsN(provides);
+ checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep);
+ if (connothash && depexistsHashHasEntry(connothash, dep))
+ checkNotInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep);
}
- while (rpmfiNext(fi) >= 0) {
- if (RPMFILE_IS_INSTALLED(rpmfiFState(fi)))
- checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, rpmfiFN(fi));
+ if (reqfilehash || connotfilehash) {
+ rpmfiles files = rpmteFiles(p);
+ rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);;
+ while (rpmfiNext(fi) >= 0) {
+ if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) {
+ if (reqfilehash)
+ checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 0, reqfilehash, &fpc);
+ if (connotfilehash)
+ checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 1, connotfilehash, &fpc);
+ }
+ }
+ rpmfiFree(fi);
+ rpmfilesFree(files);
}
}
rpmtsiFree(pi);
+ if (rdb)
+ rpmdbCtrl(rdb, RPMDB_CTRL_UNLOCK_RO);
+
exit:
depCacheFree(dcache);
+ filedepHashFree(confilehash);
+ filedepHashFree(connotfilehash);
+ depexistsHashFree(connothash);
+ filedepHashFree(reqfilehash);
+ filedepHashFree(reqnotfilehash);
+ depexistsHashFree(reqnothash);
+ fpCacheFree(fpc);
(void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
diff --git a/lib/formats.c b/lib/formats.c
index 23f40277f..cd69073ea 100644
--- a/lib/formats.c
+++ b/lib/formats.c
@@ -21,22 +21,34 @@
#include "debug.h"
+#define RPM_ANY_CLASS 255
+
+typedef char * (*headerTagFormatFunction) (rpmtd td, char **emsg);
+
/** \ingroup header
* Define header tag output formats.
*/
-struct headerFormatFunc_s {
+struct headerFmt_s {
rpmtdFormats fmt; /*!< Value of extension */
const char *name; /*!< Name of extension. */
+ rpmTagClass class; /*!< Class of source data (RPM_ANY_CLASS for any) */
headerTagFormatFunction func; /*!< Pointer to formatter function. */
};
-/**
- * barebones string representation with no extra formatting
- * @param td tag data container
- * @return formatted string
- */
-static char * stringFormat(rpmtd td)
+static const char *classEr(rpmTagClass class)
+{
+ switch (class) {
+ case RPM_BINARY_CLASS: return _("(not a blob)");
+ case RPM_NUMERIC_CLASS: return _("(not a number)");
+ case RPM_STRING_CLASS: return _("(not a string)");
+ default: break;
+ }
+ return _("(invalid type)");
+}
+
+/* barebones string representation with no extra formatting */
+static char * stringFormat(rpmtd td, char **emsg)
{
char *val = NULL;
@@ -44,109 +56,80 @@ static char * stringFormat(rpmtd td)
case RPM_NUMERIC_CLASS:
rasprintf(&val, "%" PRIu64, rpmtdGetNumber(td));
break;
- case RPM_STRING_CLASS:
- val = xstrdup(rpmtdGetString(td));
+ case RPM_STRING_CLASS: {
+ const char *str = rpmtdGetString(td);
+ if (str)
+ val = xstrdup(str);
break;
+ }
case RPM_BINARY_CLASS:
val = pgpHexStr(td->data, td->count);
break;
default:
- val = xstrdup("(unknown type)");
+ *emsg = xstrdup("(unknown type)");
break;
}
return val;
}
+/* arbitrary number format as per format arg */
static char * numFormat(rpmtd td, const char *format)
{
char * val = NULL;
-
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- rasprintf(&val, format, rpmtdGetNumber(td));
- }
-
+ rasprintf(&val, format, rpmtdGetNumber(td));
return val;
}
-/**
- * octalFormat.
- * @param td tag data container
- * @return formatted string
- */
-static char * octalFormat(rpmtd td)
+
+/* octal number formatting */
+static char * octalFormat(rpmtd td, char **emsg)
{
return numFormat(td, "%o");
}
-/**
- * hexFormat.
- * @param td tag data container
- * @return formatted string
- */
-static char * hexFormat(rpmtd td)
+/* hexadecimal format */
+static char * hexFormat(rpmtd td, char **emsg)
{
return numFormat(td, "%x");
}
-/**
- * @param td tag data container
- * @return formatted string
- */
-static char * realDateFormat(rpmtd td, const char * strftimeFormat)
+/* arbitrary date formatting as per strftimeFormat arg */
+static char * realDateFormat(rpmtd td, const char * strftimeFormat, char **emsg)
{
char * val = NULL;
+ struct tm * tstruct;
+ char buf[1024];
+ time_t dateint = rpmtdGetNumber(td);
+ tstruct = localtime(&dateint);
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- struct tm * tstruct;
- char buf[50];
- time_t dateint = rpmtdGetNumber(td);
- tstruct = localtime(&dateint);
-
- /* XXX TODO: deal with non-fitting date string correctly */
- buf[0] = '\0';
- if (tstruct)
- (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
- val = xstrdup(buf);
- }
+ buf[0] = '\0';
+ if (tstruct)
+ if (strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct) == 0)
+ *emsg = xstrdup("date output too long");
+ val = xstrdup(buf);
return val;
}
-/**
- * Format a date.
- * @param td tag data container
- * @return formatted string
- */
-static char * dateFormat(rpmtd td)
+/* date formatting */
+static char * dateFormat(rpmtd td, char **emsg)
{
- return realDateFormat(td, _("%c"));
+ return realDateFormat(td, _("%c"), emsg);
}
-/**
- * Format a day.
- * @param td tag data container
- * @return formatted string
- */
-static char * dayFormat(rpmtd td)
+/* day formatting */
+static char * dayFormat(rpmtd td, char **emsg)
{
- return realDateFormat(td, _("%a %b %d %Y"));
+ return realDateFormat(td, _("%a %b %d %Y"), emsg);
}
-/**
- * Return shell escape formatted data.
- * @param td tag data container
- * @return formatted string
- */
-static char * shescapeFormat(rpmtd td)
+/* shell escape formatting */
+static char * shescapeFormat(rpmtd td, char **emsg)
{
char * result = NULL, * dst, * src;
if (rpmtdClass(td) == RPM_NUMERIC_CLASS) {
rasprintf(&result, "%" PRIu64, rpmtdGetNumber(td));
- } else {
+ } else if (rpmtdClass(td) == RPM_STRING_CLASS) {
char *buf = xstrdup(rpmtdGetString(td));;
result = dst = xmalloc(strlen(buf) * 4 + 3);
@@ -164,139 +147,95 @@ static char * shescapeFormat(rpmtd td)
*dst++ = '\'';
*dst = '\0';
free(buf);
+ } else {
+ *emsg = xstrdup(_("(invalid type)"));
}
return result;
}
-/**
- * Identify type of trigger.
- * @param td tag data container
- * @return formatted string
- */
-static char * triggertypeFormat(rpmtd td)
+/* trigger type formatting (from rpmsense flags) */
+static char * triggertypeFormat(rpmtd td, char **emsg)
{
char * val;
-
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- uint64_t item = rpmtdGetNumber(td);
- if (item & RPMSENSE_TRIGGERPREIN)
- val = xstrdup("prein");
- else if (item & RPMSENSE_TRIGGERIN)
- val = xstrdup("in");
- else if (item & RPMSENSE_TRIGGERUN)
- val = xstrdup("un");
- else if (item & RPMSENSE_TRIGGERPOSTUN)
- val = xstrdup("postun");
- else
- val = xstrdup("");
- }
+ uint64_t item = rpmtdGetNumber(td);
+ if (item & RPMSENSE_TRIGGERPREIN)
+ val = xstrdup("prein");
+ else if (item & RPMSENSE_TRIGGERIN)
+ val = xstrdup("in");
+ else if (item & RPMSENSE_TRIGGERUN)
+ val = xstrdup("un");
+ else if (item & RPMSENSE_TRIGGERPOSTUN)
+ val = xstrdup("postun");
+ else
+ val = xstrdup("");
return val;
}
-/**
- * Identify type of dependency.
- * @param td tag data container
- * @return formatted string
- */
-static char * deptypeFormat(rpmtd td)
+/* dependency type formatting (from rpmsense flags) */
+static char * deptypeFormat(rpmtd td, char **emsg)
{
char *val = NULL;
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
+ ARGV_t sdeps = NULL;
+ uint64_t item = rpmtdGetNumber(td);
+
+ if (item & RPMSENSE_SCRIPT_PRE)
+ argvAdd(&sdeps, "pre");
+ if (item & RPMSENSE_SCRIPT_POST)
+ argvAdd(&sdeps, "post");
+ if (item & RPMSENSE_SCRIPT_PREUN)
+ argvAdd(&sdeps, "preun");
+ if (item & RPMSENSE_SCRIPT_POSTUN)
+ argvAdd(&sdeps, "postun");
+ if (item & RPMSENSE_SCRIPT_VERIFY)
+ argvAdd(&sdeps, "verify");
+ if (item & RPMSENSE_INTERP)
+ argvAdd(&sdeps, "interp");
+ if (item & RPMSENSE_RPMLIB)
+ argvAdd(&sdeps, "rpmlib");
+ if ((item & RPMSENSE_FIND_REQUIRES) || (item & RPMSENSE_FIND_PROVIDES))
+ argvAdd(&sdeps, "auto");
+ if (item & RPMSENSE_PREREQ)
+ argvAdd(&sdeps, "prereq");
+ if (item & RPMSENSE_PRETRANS)
+ argvAdd(&sdeps, "pretrans");
+ if (item & RPMSENSE_POSTTRANS)
+ argvAdd(&sdeps, "posttrans");
+ if (item & RPMSENSE_CONFIG)
+ argvAdd(&sdeps, "config");
+ if (item & RPMSENSE_MISSINGOK)
+ argvAdd(&sdeps, "missingok");
+
+ if (sdeps) {
+ val = argvJoin(sdeps, ",");
} else {
- ARGV_t sdeps = NULL;
- uint64_t item = rpmtdGetNumber(td);
-
- if (item & RPMSENSE_SCRIPT_PRE)
- argvAdd(&sdeps, "pre");
- if (item & RPMSENSE_SCRIPT_POST)
- argvAdd(&sdeps, "post");
- if (item & RPMSENSE_SCRIPT_PREUN)
- argvAdd(&sdeps, "preun");
- if (item & RPMSENSE_SCRIPT_POSTUN)
- argvAdd(&sdeps, "postun");
- if (item & RPMSENSE_SCRIPT_VERIFY)
- argvAdd(&sdeps, "verify");
- if (item & RPMSENSE_INTERP)
- argvAdd(&sdeps, "interp");
- if (item & RPMSENSE_RPMLIB)
- argvAdd(&sdeps, "rpmlib");
- if ((item & RPMSENSE_FIND_REQUIRES) || (item & RPMSENSE_FIND_PROVIDES))
- argvAdd(&sdeps, "auto");
- if (item & RPMSENSE_PREREQ)
- argvAdd(&sdeps, "prereq");
- if (item & RPMSENSE_PRETRANS)
- argvAdd(&sdeps, "pretrans");
- if (item & RPMSENSE_POSTTRANS)
- argvAdd(&sdeps, "posttrans");
- if (item & RPMSENSE_CONFIG)
- argvAdd(&sdeps, "config");
- if (item & RPMSENSE_MISSINGOK)
- argvAdd(&sdeps, "missingok");
-
- if (sdeps) {
- val = argvJoin(sdeps, ",");
- } else {
- val = xstrdup("manual");
- }
-
- argvFree(sdeps);
+ val = xstrdup("manual");
}
+
+ argvFree(sdeps);
return val;
}
-/**
- * Format file permissions for display.
- * @param td tag data container
- * @return formatted string
- */
-static char * permsFormat(rpmtd td)
+/* file permissions formatting */
+static char * permsFormat(rpmtd td, char **emsg)
{
- char * val = NULL;
-
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- val = rpmPermsString(rpmtdGetNumber(td));
- }
-
- return val;
+ return rpmPermsString(rpmtdGetNumber(td));
}
-/**
- * Format file flags for display.
- * @param td tag data container
- * @return formatted string
- */
-static char * fflagsFormat(rpmtd td)
+/* file flags formatting */
+static char * fflagsFormat(rpmtd td, char **emsg)
{
- char * val = NULL;
-
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- val = rpmFFlagsString(rpmtdGetNumber(td), "");
- }
-
- return val;
+ return rpmFFlagsString(rpmtdGetNumber(td), "");
}
-/**
- * Wrap a pubkey in ascii armor for display.
- * @todo Permit selectable display formats (i.e. binary).
- * @param td tag data container
- * @return formatted string
- */
-static char * armorFormat(rpmtd td)
+/* pubkey ascii armor formatting */
+static char * armorFormat(rpmtd td, char **emsg)
{
const char * enc;
const unsigned char * s;
unsigned char * bs = NULL;
- char *val;
+ char *val = NULL;
size_t ns;
int atype;
@@ -310,8 +249,10 @@ static char * armorFormat(rpmtd td)
case RPM_STRING_TYPE:
case RPM_STRING_ARRAY_TYPE:
enc = rpmtdGetString(td);
- if (rpmBase64Decode(enc, (void **)&bs, &ns))
- return xstrdup(_("(not base64)"));
+ if (rpmBase64Decode(enc, (void **)&bs, &ns)) {
+ *emsg = xstrdup(_("(not base64)"));
+ goto exit;
+ }
s = bs;
atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
break;
@@ -323,7 +264,8 @@ static char * armorFormat(rpmtd td)
case RPM_INT64_TYPE:
case RPM_I18NSTRING_TYPE:
default:
- return xstrdup(_("(invalid type)"));
+ *emsg = xstrdup(_("(invalid type)"));
+ goto exit;
break;
}
@@ -332,48 +274,35 @@ static char * armorFormat(rpmtd td)
if (atype == PGPARMOR_PUBKEY) {
free(bs);
}
+
+exit:
return val;
}
-/**
- * Encode binary data in base64 for display.
- * @todo Permit selectable display formats (i.e. binary).
- * @param td tag data container
- * @return formatted string
- */
-static char * base64Format(rpmtd td)
+/* base64 encoding formatting */
+static char * base64Format(rpmtd td, char **emsg)
{
- char * val = NULL;
-
- if (rpmtdType(td) != RPM_BIN_TYPE) {
- val = xstrdup(_("(not a blob)"));
- } else {
- val = rpmBase64Encode(td->data, td->count, -1);
- if (val == NULL)
- val = xstrdup("");
- }
+ char * val = rpmBase64Encode(td->data, td->count, -1);
+ if (val == NULL)
+ val = xstrdup("");
return val;
}
-/**
- * Wrap tag data in simple header xml markup.
- * @param td tag data container
- * @return formatted string
- */
-static char * xmlFormat(rpmtd td)
+/* xml formatting */
+static char * xmlFormat(rpmtd td, char **emsg)
{
const char *xtag = NULL;
char *val = NULL;
char *s = NULL;
- rpmtdFormats fmt = RPMTD_FORMAT_STRING;
+ headerTagFormatFunction fmt = stringFormat;
switch (rpmtdClass(td)) {
case RPM_STRING_CLASS:
xtag = "string";
break;
case RPM_BINARY_CLASS:
- fmt = RPMTD_FORMAT_BASE64;
+ fmt = base64Format;
xtag = "base64";
break;
case RPM_NUMERIC_CLASS:
@@ -381,12 +310,14 @@ static char * xmlFormat(rpmtd td)
break;
case RPM_NULL_TYPE:
default:
- return xstrdup(_("(invalid xml type)"));
+ *emsg = xstrdup(_("(invalid xml type)"));
+ goto exit;
break;
}
- /* XXX TODO: handle errors */
- s = rpmtdFormat(td, fmt, NULL);
+ s = fmt(td, emsg);
+ if (s == NULL)
+ goto exit;
if (s[0] == '\0') {
val = rstrscat(NULL, "\t<", xtag, "/>", NULL);
@@ -413,226 +344,204 @@ static char * xmlFormat(rpmtd td)
}
free(s);
+exit:
return val;
}
-/**
- * Display signature fingerprint and time.
- * @param td tag data container
- * @return formatted string
- */
-static char * pgpsigFormat(rpmtd td)
+/* signature fingerprint and time formatting */
+static char * pgpsigFormat(rpmtd td, char **emsg)
{
char * val = NULL;
+ pgpDigParams sigp = NULL;
- if (rpmtdType(td) != RPM_BIN_TYPE) {
- val = xstrdup(_("(not a blob)"));
+ if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) {
+ *emsg = xstrdup(_("(not an OpenPGP signature)"));
} else {
- pgpDigParams sigp = NULL;
-
- if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) {
- val = xstrdup(_("(not an OpenPGP signature)"));
+ char dbuf[BUFSIZ];
+ char *keyid = pgpHexStr(sigp->signid, sizeof(sigp->signid));
+ unsigned int dateint = sigp->time;
+ time_t date = dateint;
+ struct tm * tms = localtime(&date);
+ unsigned int key_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO);
+ unsigned int hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO);
+
+ if (!(tms && strftime(dbuf, sizeof(dbuf), "%c", tms) > 0)) {
+ rasprintf(emsg, _("Invalid date %u"), dateint);
} else {
- char dbuf[BUFSIZ];
- char *keyid = pgpHexStr(sigp->signid, sizeof(sigp->signid));
- unsigned int dateint = pgpGrab(sigp->time, sizeof(sigp->time));
- time_t date = dateint;
- struct tm * tms = localtime(&date);
- unsigned int key_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO);
- unsigned int hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO);
-
- if (!(tms && strftime(dbuf, sizeof(dbuf), "%c", tms) > 0)) {
- snprintf(dbuf, sizeof(dbuf),
- _("Invalid date %u"), dateint);
- dbuf[sizeof(dbuf)-1] = '\0';
- }
-
rasprintf(&val, "%s/%s, %s, Key ID %s",
- pgpValString(PGPVAL_PUBKEYALGO, key_algo),
- pgpValString(PGPVAL_HASHALGO, hash_algo),
- dbuf, keyid);
-
- free(keyid);
- pgpDigParamsFree(sigp);
+ pgpValString(PGPVAL_PUBKEYALGO, key_algo),
+ pgpValString(PGPVAL_HASHALGO, hash_algo),
+ dbuf, keyid);
}
- }
-
- return val;
-}
-/**
- * Format dependency flags for display.
- * @param td tag data container
- * @return formatted string
- */
-static char * depflagsFormat(rpmtd td)
-{
- char * val = NULL;
-
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- uint64_t anint = rpmtdGetNumber(td);
- val = xcalloc(4, 1);
-
- if (anint & RPMSENSE_LESS)
- strcat(val, "<");
- if (anint & RPMSENSE_GREATER)
- strcat(val, ">");
- if (anint & RPMSENSE_EQUAL)
- strcat(val, "=");
+ free(keyid);
+ pgpDigParamsFree(sigp);
}
return val;
}
-static char * depflag_strongFormat(rpmtd td)
+/* dependency flags formatting */
+static char * depflagsFormat(rpmtd td, char **emsg)
{
char * val = NULL;
+ uint64_t anint = rpmtdGetNumber(td);
+ val = xcalloc(4, 1);
+
+ if (anint & RPMSENSE_LESS)
+ strcat(val, "<");
+ if (anint & RPMSENSE_GREATER)
+ strcat(val, ">");
+ if (anint & RPMSENSE_EQUAL)
+ strcat(val, "=");
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- uint64_t anint = rpmtdGetNumber(td);
- val = xstrdup(anint & RPMSENSE_STRONG ? "strong" : "");
- }
return val;
}
-
-/**
- * Return tag container array size.
- * @param td tag data container
- * @return formatted string
- */
-static char * arraysizeFormat(rpmtd td)
+/* tag container array size */
+static char * arraysizeFormat(rpmtd td, char **emsg)
{
char *val = NULL;
rasprintf(&val, "%u", rpmtdCount(td));
return val;
}
-static char * fstateFormat(rpmtd td)
+/* file state formatting */
+static char * fstateFormat(rpmtd td, char **emsg)
{
char * val = NULL;
-
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- const char * str;
- rpmfileState fstate = rpmtdGetNumber(td);
- switch (fstate) {
- case RPMFILE_STATE_NORMAL:
- str = _("normal");
- break;
- case RPMFILE_STATE_REPLACED:
- str = _("replaced");
- break;
- case RPMFILE_STATE_NOTINSTALLED:
- str = _("not installed");
- break;
- case RPMFILE_STATE_NETSHARED:
- str = _("net shared");
- break;
- case RPMFILE_STATE_WRONGCOLOR:
- str = _("wrong color");
- break;
- case RPMFILE_STATE_MISSING:
- str = _("missing");
- break;
- default:
- str = _("(unknown)");
- break;
- }
-
- val = xstrdup(str);
+ const char * str;
+ rpmfileState fstate = rpmtdGetNumber(td);
+ switch (fstate) {
+ case RPMFILE_STATE_NORMAL:
+ str = _("normal");
+ break;
+ case RPMFILE_STATE_REPLACED:
+ str = _("replaced");
+ break;
+ case RPMFILE_STATE_NOTINSTALLED:
+ str = _("not installed");
+ break;
+ case RPMFILE_STATE_NETSHARED:
+ str = _("net shared");
+ break;
+ case RPMFILE_STATE_WRONGCOLOR:
+ str = _("wrong color");
+ break;
+ case RPMFILE_STATE_MISSING:
+ str = _("missing");
+ break;
+ default:
+ str = _("(unknown)");
+ break;
}
+
+ val = xstrdup(str);
return val;
}
+/* file verification flags formatting with optional padding */
static char * verifyFlags(rpmtd td, const char *pad)
{
- char * val = NULL;
-
- if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
- val = xstrdup(_("(not a number)"));
- } else {
- val = rpmVerifyString(rpmtdGetNumber(td), pad);
- }
- return val;
+ return rpmVerifyString(rpmtdGetNumber(td), pad);
}
-static char * vflagsFormat(rpmtd td)
+static char * vflagsFormat(rpmtd td, char **emsg)
{
return verifyFlags(td, "");
}
-static char * fstatusFormat(rpmtd td)
+static char * fstatusFormat(rpmtd td, char **emsg)
{
return verifyFlags(td, ".");
}
-static char * expandFormat(rpmtd td)
+/* macro expansion formatting */
+static char * expandFormat(rpmtd td, char **emsg)
{
- char *val = NULL;
- if (rpmtdClass(td) != RPM_STRING_CLASS) {
- val = xstrdup(_("(not a string)"));
- } else {
- val = rpmExpand(td->data, NULL);
- }
- return val;
+ return rpmExpand(rpmtdGetString(td), NULL);
}
-static const struct headerFormatFunc_s rpmHeaderFormats[] = {
- { RPMTD_FORMAT_STRING, "string", stringFormat },
- { RPMTD_FORMAT_ARMOR, "armor", armorFormat },
- { RPMTD_FORMAT_BASE64, "base64", base64Format },
- { RPMTD_FORMAT_PGPSIG, "pgpsig", pgpsigFormat },
- { RPMTD_FORMAT_DEPFLAGS, "depflags", depflagsFormat },
- { RPMTD_FORMAT_DEPTYPE, "deptype", deptypeFormat },
- { RPMTD_FORMAT_FFLAGS, "fflags", fflagsFormat },
- { RPMTD_FORMAT_PERMS, "perms", permsFormat },
- { RPMTD_FORMAT_PERMS, "permissions", permsFormat },
- { RPMTD_FORMAT_TRIGGERTYPE, "triggertype", triggertypeFormat },
- { RPMTD_FORMAT_XML, "xml", xmlFormat },
- { RPMTD_FORMAT_OCTAL, "octal", octalFormat },
- { RPMTD_FORMAT_HEX, "hex", hexFormat },
- { RPMTD_FORMAT_DATE, "date", dateFormat },
- { RPMTD_FORMAT_DAY, "day", dayFormat },
- { RPMTD_FORMAT_SHESCAPE, "shescape", shescapeFormat },
- { RPMTD_FORMAT_ARRAYSIZE, "arraysize", arraysizeFormat },
- { RPMTD_FORMAT_FSTATE, "fstate", fstateFormat },
- { RPMTD_FORMAT_VFLAGS, "vflags", vflagsFormat },
- { RPMTD_FORMAT_EXPAND, "expand", expandFormat },
- { RPMTD_FORMAT_FSTATUS, "fstatus", fstatusFormat },
- { RPMTD_FORMAT_DEPFLAG_STRONG, "depflag_strong", depflag_strongFormat },
- { -1, NULL, NULL }
+static const struct headerFmt_s rpmHeaderFormats[] = {
+ { RPMTD_FORMAT_STRING, "string",
+ RPM_ANY_CLASS, stringFormat },
+ { RPMTD_FORMAT_ARMOR, "armor",
+ RPM_ANY_CLASS, armorFormat },
+ { RPMTD_FORMAT_BASE64, "base64",
+ RPM_BINARY_CLASS, base64Format },
+ { RPMTD_FORMAT_PGPSIG, "pgpsig",
+ RPM_BINARY_CLASS, pgpsigFormat },
+ { RPMTD_FORMAT_DEPFLAGS, "depflags",
+ RPM_NUMERIC_CLASS, depflagsFormat },
+ { RPMTD_FORMAT_DEPTYPE, "deptype",
+ RPM_NUMERIC_CLASS, deptypeFormat },
+ { RPMTD_FORMAT_FFLAGS, "fflags",
+ RPM_NUMERIC_CLASS, fflagsFormat },
+ { RPMTD_FORMAT_PERMS, "perms",
+ RPM_NUMERIC_CLASS, permsFormat },
+ { RPMTD_FORMAT_PERMS, "permissions",
+ RPM_NUMERIC_CLASS, permsFormat },
+ { RPMTD_FORMAT_TRIGGERTYPE, "triggertype",
+ RPM_NUMERIC_CLASS, triggertypeFormat },
+ { RPMTD_FORMAT_XML, "xml",
+ RPM_ANY_CLASS, xmlFormat },
+ { RPMTD_FORMAT_OCTAL, "octal",
+ RPM_NUMERIC_CLASS, octalFormat },
+ { RPMTD_FORMAT_HEX, "hex",
+ RPM_NUMERIC_CLASS, hexFormat },
+ { RPMTD_FORMAT_DATE, "date",
+ RPM_NUMERIC_CLASS, dateFormat },
+ { RPMTD_FORMAT_DAY, "day",
+ RPM_NUMERIC_CLASS, dayFormat },
+ { RPMTD_FORMAT_SHESCAPE, "shescape",
+ RPM_ANY_CLASS, shescapeFormat },
+ { RPMTD_FORMAT_ARRAYSIZE, "arraysize",
+ RPM_ANY_CLASS, arraysizeFormat },
+ { RPMTD_FORMAT_FSTATE, "fstate",
+ RPM_NUMERIC_CLASS, fstateFormat },
+ { RPMTD_FORMAT_VFLAGS, "vflags",
+ RPM_NUMERIC_CLASS, vflagsFormat },
+ { RPMTD_FORMAT_EXPAND, "expand",
+ RPM_STRING_CLASS, expandFormat },
+ { RPMTD_FORMAT_FSTATUS, "fstatus",
+ RPM_NUMERIC_CLASS, fstatusFormat },
+ { -1, NULL, 0, NULL }
};
-headerTagFormatFunction rpmHeaderFormatFuncByName(const char *fmt)
+headerFmt rpmHeaderFormatByName(const char *fmt)
{
- const struct headerFormatFunc_s * ext;
- headerTagFormatFunction func = NULL;
+ const struct headerFmt_s * ext;
for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
- if (rstreq(ext->name, fmt)) {
- func = ext->func;
- break;
- }
+ if (rstreq(ext->name, fmt))
+ return ext;
}
- return func;
+ return NULL;
}
-headerTagFormatFunction rpmHeaderFormatFuncByValue(rpmtdFormats fmt)
+headerFmt rpmHeaderFormatByValue(rpmtdFormats fmt)
{
- const struct headerFormatFunc_s * ext;
- headerTagFormatFunction func = NULL;
+ const struct headerFmt_s * ext;
for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
- if (fmt == ext->fmt) {
- func = ext->func;
- break;
- }
+ if (fmt == ext->fmt)
+ return ext;
}
- return func;
+ return NULL;
}
+char *rpmHeaderFormatCall(headerFmt fmt, rpmtd td)
+{
+ char *ret = NULL;
+ char *err = NULL;
+
+ if (fmt->class != RPM_ANY_CLASS && rpmtdClass(td) != fmt->class)
+ err = xstrdup(classEr(fmt->class));
+ else
+ ret = fmt->func(td, &err);
+
+ if (err) {
+ free(ret);
+ ret = err;
+ }
+ return ret;
+}
diff --git a/lib/fprint.c b/lib/fprint.c
index 6f6172cf2..b810e4d2b 100644
--- a/lib/fprint.c
+++ b/lib/fprint.c
@@ -6,7 +6,7 @@
#include <rpm/rpmfileutil.h> /* for rpmCleanPath */
#include <rpm/rpmts.h>
-#include <rpm/rpmdb.h>
+#include <rpm/rpmsq.h>
#include "lib/rpmdb_internal.h"
#include "lib/rpmfi_internal.h"
@@ -251,7 +251,7 @@ int fpLookup(fingerPrintCache cache,
/**
* Return hash value for a finger print.
* Hash based on dev and inode only!
- * @param key pointer to finger print entry
+ * @param fp pointer to finger print entry
* @return hash value
*/
static unsigned int fpHashFunction(const fingerPrint * fp)
@@ -335,7 +335,7 @@ fingerPrint * fpLookupList(fingerPrintCache cache, rpmstrPool pool,
/* Check file for to be installed symlinks in their path and correct their fp */
static void fpLookupSubdir(rpmFpHash symlinks, fingerPrintCache fpc, rpmte p, int filenr)
{
- rpmfi fi = rpmteFI(p);
+ rpmfiles fi = rpmteFiles(p);
struct fingerPrint_s current_fp;
const char *currentsubdir;
size_t lensubDir, bnStart, bnEnd;
@@ -343,13 +343,13 @@ static void fpLookupSubdir(rpmFpHash symlinks, fingerPrintCache fpc, rpmte p, in
struct rpmffi_s * recs;
int numRecs;
int i;
- fingerPrint *fp = rpmfiFps(fi) + filenr;
+ fingerPrint *fp = rpmfilesFps(fi) + filenr;
int symlinkcount = 0;
struct rpmffi_s ffi = { p, filenr};
if (fp->subDirId == 0) {
- rpmFpHashAddEntry(fpc->fp, fp, ffi);
- return;
+ rpmFpHashAddEntry(fpc->fp, fp, ffi);
+ goto exit;
}
currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId);
@@ -364,88 +364,98 @@ static void fpLookupSubdir(rpmFpHash symlinks, fingerPrintCache fpc, rpmte p, in
current_fp.subDirId = 0;
while (bnEnd < lensubDir) {
- char found = 0;
+ char found = 0;
- current_fp.baseNameId = rpmstrPoolIdn(fpc->pool,
+ current_fp.baseNameId = rpmstrPoolIdn(fpc->pool,
currentsubdir + bnStart,
bnEnd - bnStart, 1);
- rpmFpHashGetEntry(symlinks, &current_fp, &recs, &numRecs, NULL);
-
- for (i=0; i<numRecs; i++) {
- rpmfi foundfi = rpmteFI(recs[i].p);
- char const *linktarget = rpmfiFLinkIndex(foundfi, recs[i].fileno);
- char *link;
-
- if (linktarget && *linktarget != '\0') {
- const char *bn;
- /* this "directory" is a symlink */
- link = NULL;
- if (*linktarget != '/') {
- const char *dn, *subDir = NULL;
- dn = rpmstrPoolStr(fpc->pool, current_fp.entry->dirId);
- if (current_fp.subDirId) {
- subDir = rpmstrPoolStr(fpc->pool,
- current_fp.subDirId);
- }
- rstrscat(&link, dn,
- subDir ? subDir : "",
- "/", NULL);
- }
- rstrscat(&link, linktarget, "/", NULL);
- if (strlen(currentsubdir + bnEnd)) {
- rstrscat(&link, currentsubdir + bnEnd, NULL);
- }
-
- bn = rpmstrPoolStr(fpc->pool, fp->baseNameId);
- doLookup(fpc, link, bn, fp);
-
- free(link);
- symlinkcount++;
-
- /* setup current_fp for the new path */
- found = 1;
- current_fp = *fp;
- if (fp->subDirId == 0) {
- /* directory exists - no need to look for symlinks */
- rpmFpHashAddEntry(fpc->fp, fp, ffi);
- return;
- }
- currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId);
- lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId);
- /* no subDir for now */
- current_fp.subDirId = 0;
-
- /* Set baseName to the upper most dir */
- bnStart = bnEnd = 1;
- while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/')
- bnEnd++;
- break;
-
- }
- }
- if (symlinkcount>50) {
- // found too many symlinks in the path
- // most likley a symlink cicle
- // giving up
- // TODO warning/error
- break;
- }
- if (found) {
- continue; // restart loop after symlink
- }
-
- /* Set former baseName as subDir */
- bnEnd++;
- current_fp.subDirId = rpmstrPoolIdn(fpc->pool, currentsubdir, bnEnd, 1);
-
- /* set baseName to the next lower dir */
- bnStart = bnEnd;
- while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/')
+ rpmFpHashGetEntry(symlinks, &current_fp, &recs, &numRecs, NULL);
+
+ for (i = 0; i < numRecs; i++) {
+ rpmfiles foundfi = rpmteFiles(recs[i].p);
+ char const *linktarget = rpmfilesFLink(foundfi, recs[i].fileno);
+ char *link;
+
+ /* Ignore already removed (by eg %pretrans) links */
+ if (linktarget && rpmteType(recs[i].p) == TR_REMOVED) {
+ char *path = rpmfilesFN(foundfi, recs[i].fileno);
+ struct stat sb;
+ if (lstat(path, &sb) == -1)
+ linktarget = NULL;
+ free(path);
+ }
+
+ foundfi = rpmfilesFree(foundfi);
+
+ if (linktarget && *linktarget != '\0') {
+ const char *bn;
+ /* this "directory" is a symlink */
+ link = NULL;
+ if (*linktarget != '/') {
+ const char *dn, *subDir = NULL;
+ dn = rpmstrPoolStr(fpc->pool, current_fp.entry->dirId);
+ if (current_fp.subDirId) {
+ subDir = rpmstrPoolStr(fpc->pool, current_fp.subDirId);
+ }
+ rstrscat(&link, dn, subDir ? subDir : "", "/", NULL);
+ }
+ rstrscat(&link, linktarget, "/", NULL);
+ if (strlen(currentsubdir + bnEnd)) {
+ rstrscat(&link, currentsubdir + bnEnd, NULL);
+ }
+
+ bn = rpmstrPoolStr(fpc->pool, fp->baseNameId);
+ doLookup(fpc, link, bn, fp);
+
+ free(link);
+ symlinkcount++;
+
+ /* setup current_fp for the new path */
+ found = 1;
+ current_fp = *fp;
+ if (fp->subDirId == 0) {
+ /* directory exists - no need to look for symlinks */
+ rpmFpHashAddEntry(fpc->fp, fp, ffi);
+ goto exit;
+ }
+ currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId);
+ lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId);
+ /* no subDir for now */
+ current_fp.subDirId = 0;
+
+ /* Set baseName to the upper most dir */
+ bnStart = bnEnd = 1;
+ while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/')
+ bnEnd++;
+ break;
+
+ }
+ }
+ if (symlinkcount > 50) {
+ // found too many symlinks in the path
+ // most likley a symlink cicle
+ // giving up
+ // TODO warning/error
+ break;
+ }
+ if (found) {
+ continue; // restart loop after symlink
+ }
+
+ /* Set former baseName as subDir */
+ bnEnd++;
+ current_fp.subDirId = rpmstrPoolIdn(fpc->pool, currentsubdir, bnEnd, 1);
+
+ /* set baseName to the next lower dir */
+ bnStart = bnEnd;
+ while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/')
bnEnd++;
}
rpmFpHashAddEntry(fpc->fp, fp, ffi);
+exit:
+ rpmfilesFree(fi);
}
fingerPrint * fpCacheGetByFp(fingerPrintCache cache,
@@ -463,7 +473,7 @@ void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount)
rpmtsi pi;
rpmte p;
rpmfs fs;
- rpmfi fi;
+ rpmfiles fi;
int i, fc;
if (fpc->fp == NULL)
@@ -475,23 +485,23 @@ void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount)
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
fingerPrint *fpList;
- (void) rpmdbCheckSignals();
+ (void) rpmsqPoll();
- if ((fi = rpmteFI(p)) == NULL)
+ if ((fi = rpmteFiles(p)) == NULL)
continue; /* XXX can't happen */
(void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
- rpmfiFpLookup(fi, fpc);
+ rpmfilesFpLookup(fi, fpc);
fs = rpmteGetFileStates(p);
fc = rpmfsFC(fs);
- fpList = rpmfiFps(fi);
+ fpList = rpmfilesFps(fi);
/* collect symbolic links */
for (i = 0; i < fc; i++) {
struct rpmffi_s ffi;
char const *linktarget;
if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
continue;
- linktarget = rpmfiFLinkIndex(fi, i);
+ linktarget = rpmfilesFLink(fi, i);
if (!(linktarget && *linktarget != '\0'))
continue;
ffi.p = p;
@@ -499,7 +509,7 @@ void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount)
rpmFpHashAddEntry(symlinks, fpList + i, ffi);
}
(void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
-
+ rpmfilesFree(fi);
}
rpmtsiFree(pi);
@@ -510,7 +520,7 @@ void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount)
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
- (void) rpmdbCheckSignals();
+ (void) rpmsqPoll();
fs = rpmteGetFileStates(p);
fc = rpmfsFC(fs);
diff --git a/lib/fsm.c b/lib/fsm.c
index ab4e18034..839ce83c6 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -13,129 +13,23 @@
#include <rpm/rpmte.h>
#include <rpm/rpmts.h>
-#include <rpm/rpmsq.h>
#include <rpm/rpmlog.h>
+#include <rpm/rpmmacro.h>
#include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
-#include "lib/cpio.h"
#include "lib/fsm.h"
-#define fsmUNSAFE fsmStage
-#include "lib/rpmfi_internal.h" /* XXX fi->apath, ... */
#include "lib/rpmte_internal.h" /* XXX rpmfs */
-#include "lib/rpmts_internal.h" /* rpmtsSELabelFoo() only */
-#include "lib/rpmplugins.h" /* rpm plugins hooks */
+#include "lib/rpmplugins.h" /* rpm plugins hooks */
#include "lib/rpmug.h"
-#include "lib/cpio.h"
#include "debug.h"
#define _FSM_DEBUG 0
int _fsm_debug = _FSM_DEBUG;
-extern int _fsm_debug;
-
-/** \ingroup payload
- */
-enum cpioMapFlags_e {
- CPIO_MAP_PATH = (1 << 0),
- CPIO_MAP_MODE = (1 << 1),
- CPIO_MAP_UID = (1 << 2),
- CPIO_MAP_GID = (1 << 3),
- CPIO_FOLLOW_SYMLINKS= (1 << 4), /*!< only for building. */
- CPIO_MAP_ABSOLUTE = (1 << 5),
- CPIO_MAP_ADDDOT = (1 << 6),
- CPIO_MAP_TYPE = (1 << 8), /*!< only for building. */
- CPIO_SBIT_CHECK = (1 << 9)
-};
-typedef rpmFlags cpioMapFlags;
-
-typedef struct fsmIterator_s * FSMI_t;
-typedef struct fsm_s * FSM_t;
-
-typedef struct hardLink_s * hardLink_t;
-
-typedef enum fileStage_e {
- FSM_PKGINSTALL,
- FSM_PKGERASE,
- FSM_PKGBUILD,
-} fileStage;
-
/* XXX Failure to remove is not (yet) cause for failure. */
static int strict_erasures = 0;
-/** \ingroup payload
- * Keeps track of the set of all hard links to a file in an archive.
- */
-struct hardLink_s {
- hardLink_t next;
- const char ** nsuffix;
- int * filex;
- struct stat sb;
- nlink_t nlink;
- nlink_t linksLeft;
- int linkIndex;
- int createdPath;
-};
-
-/** \ingroup payload
- * Iterator across package file info, forward on install, backward on erase.
- */
-struct fsmIterator_s {
- rpmfs fs; /*!< file state info. */
- rpmfi fi; /*!< transaction element file info. */
- int reverse; /*!< reversed traversal? */
- int isave; /*!< last returned iterator index. */
- int i; /*!< iterator index. */
-};
-
-/** \ingroup payload
- * File name and stat information.
- */
-struct fsm_s {
- char * path; /*!< Current file name. */
- char * buf; /*!< read: Buffer. */
- size_t bufsize; /*!< read: Buffer allocated size. */
- FSMI_t iter; /*!< File iterator. */
- int ix; /*!< Current file iterator index. */
- hardLink_t links; /*!< Pending hard linked file(s). */
- char ** failedFile; /*!< First file name that failed. */
- const char * osuffix; /*!< Old, preserved, file suffix. */
- const char * nsuffix; /*!< New, created, file suffix. */
- char * suffix; /*!< Current file suffix. */
- int postpone; /*!< Skip remaining stages? */
- int diskchecked; /*!< Has stat(2) been performed? */
- int exists; /*!< Does current file exist on disk? */
- cpioMapFlags mapFlags; /*!< Bit(s) to control mapping. */
- const char * dirName; /*!< File directory name. */
- const char * baseName; /*!< File base name. */
- struct selabel_handle *sehandle; /*!< SELinux label handle (if any). */
- rpmPlugins plugins; /*!< Rpm plugins handle */
-
- unsigned fflags; /*!< File flags. */
- rpmFileAction action; /*!< File disposition. */
- fileStage goal; /*!< Package state machine goal. */
- struct stat sb; /*!< Current file stat(2) info. */
- struct stat osb; /*!< Original file stat(2) info. */
-};
-
-
-/**
- * Retrieve transaction element file info from file state machine iterator.
- * @param fsm file state machine
- * @return transaction element file info
- */
-static rpmfi fsmGetFi(const FSM_t fsm)
-{
- const FSMI_t iter = fsm->iter;
- return (iter ? iter->fi : NULL);
-}
-
-static rpmfs fsmGetFs(const FSM_t fsm)
-{
- const FSMI_t iter = fsm->iter;
- return (iter ? iter->fs : NULL);
-}
-
#define SUFFIX_RPMORIG ".rpmorig"
#define SUFFIX_RPMSAVE ".rpmsave"
#define SUFFIX_RPMNEW ".rpmnew"
@@ -152,126 +46,20 @@ static const char * fileActionString(rpmFileAction a);
/** \ingroup payload
* Build path to file from file info, optionally ornamented with suffix.
- * @param fsm file state machine data
- * @param isDir directory or regular path?
+ * @param fi file info iterator
* @param suffix suffix to use (NULL disables)
* @retval path to file (malloced)
*/
-static char * fsmFsPath(const FSM_t fsm, int isDir,
- const char * suffix)
-{
- return rstrscat(NULL,
- fsm->dirName, fsm->baseName,
- (!isDir && suffix) ? suffix : "",
- NULL);
-}
-
-/** \ingroup payload
- * Destroy file info iterator.
- * @param p file info iterator
- * @retval NULL always
- */
-static FSMI_t mapFreeIterator(FSMI_t iter)
+static char * fsmFsPath(rpmfi fi, const char * suffix)
{
- if (iter) {
- iter->fs = NULL; /* rpmfs is not refcounted */
- iter->fi = rpmfiFree(iter->fi);
- free(iter);
- }
- return NULL;
-}
-
-/** \ingroup payload
- * Create file info iterator.
- * @param fi transaction element file info
- * @return file info iterator
- */
-static FSMI_t
-mapInitIterator(rpmfs fs, rpmfi fi, int reverse)
-{
- FSMI_t iter = NULL;
-
- iter = xcalloc(1, sizeof(*iter));
- iter->fs = fs; /* rpmfs is not refcounted */
- iter->fi = rpmfiLink(fi);
- iter->reverse = reverse;
- iter->i = (iter->reverse ? (rpmfiFC(fi) - 1) : 0);
- iter->isave = iter->i;
- return iter;
-}
-
-/** \ingroup payload
- * Return next index into file info.
- * @param a file info iterator
- * @return next index, -1 on termination
- */
-static int mapNextIterator(FSMI_t iter)
-{
- int i = -1;
-
- if (iter) {
- const rpmfi fi = iter->fi;
- if (iter->reverse) {
- if (iter->i >= 0) i = iter->i--;
- } else {
- if (iter->i < rpmfiFC(fi)) i = iter->i++;
- }
- iter->isave = i;
- }
- return i;
-}
-
-/** \ingroup payload
- */
-static int cpioStrCmp(const void * a, const void * b)
-{
- const char * afn = *(const char **)a;
- const char * bfn = *(const char **)b;
-
- /* Match rpm-4.0 payloads with ./ prefixes. */
- if (afn[0] == '.' && afn[1] == '/') afn += 2;
- if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
-
- /* If either path is absolute, make it relative. */
- if (afn[0] == '/') afn += 1;
- if (bfn[0] == '/') bfn += 1;
-
- return strcmp(afn, bfn);
-}
-
-/** \ingroup payload
- * Locate archive path in file info.
- * @param iter file info iterator
- * @param fsmPath archive path
- * @return index into file info, -1 if archive path was not found
- */
-static int mapFind(FSMI_t iter, const char * fsmPath)
-{
- int ix = -1;
-
- if (iter) {
- const rpmfi fi = iter->fi;
- int fc = rpmfiFC(fi);
- if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) {
- char ** p = NULL;
-
- if (fi->apath != NULL)
- p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath),
- cpioStrCmp);
- if (p) {
- iter->i = p - fi->apath;
- ix = mapNextIterator(iter);
- }
- }
- }
- return ix;
+ return rstrscat(NULL, rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL);
}
/** \ingroup payload
* Directory name iterator.
*/
typedef struct dnli_s {
- rpmfi fi;
+ rpmfiles fi;
char * active;
int reverse;
int isave;
@@ -280,7 +68,7 @@ typedef struct dnli_s {
/** \ingroup payload
* Destroy directory name iterator.
- * @param a directory name iterator
+ * @param dnli directory name iterator
* @retval NULL always
*/
static DNLI_t dnlFreeIterator(DNLI_t dnli)
@@ -299,7 +87,7 @@ static DNLI_t dnlFreeIterator(DNLI_t dnli)
* @param reverse traverse directory names in reverse order?
* @return directory name iterator
*/
-static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse)
+static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse)
{
DNLI_t dnli;
int i, j;
@@ -307,7 +95,7 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse)
if (fi == NULL)
return NULL;
- dc = rpmfiDC(fi);
+ dc = rpmfilesDC(fi);
dnli = xcalloc(1, sizeof(*dnli));
dnli->fi = fi;
dnli->reverse = reverse;
@@ -315,24 +103,24 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse)
if (dc) {
dnli->active = xcalloc(dc, sizeof(*dnli->active));
- int fc = rpmfiFC(fi);
+ int fc = rpmfilesFC(fi);
/* Identify parent directories not skipped. */
for (i = 0; i < fc; i++)
if (!XFA_SKIPPING(rpmfsGetAction(fs, i)))
- dnli->active[rpmfiDIIndex(fi, i)] = 1;
+ dnli->active[rpmfilesDI(fi, i)] = 1;
/* Exclude parent directories that are explicitly included. */
for (i = 0; i < fc; i++) {
int dil;
size_t dnlen, bnlen;
- if (!S_ISDIR(rpmfiFModeIndex(fi, i)))
+ if (!S_ISDIR(rpmfilesFMode(fi, i)))
continue;
- dil = rpmfiDIIndex(fi, i);
- dnlen = strlen(rpmfiDNIndex(fi, dil));
- bnlen = strlen(rpmfiBNIndex(fi, i));
+ dil = rpmfilesDI(fi, i);
+ dnlen = strlen(rpmfilesDN(fi, dil));
+ bnlen = strlen(rpmfilesBN(fi, i));
for (j = 0; j < dc; j++) {
const char * dnl;
@@ -340,13 +128,13 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse)
if (!dnli->active[j] || j == dil)
continue;
- dnl = rpmfiDNIndex(fi, j);
+ dnl = rpmfilesDN(fi, j);
jlen = strlen(dnl);
if (jlen != (dnlen+bnlen+1))
continue;
- if (!rstreqn(dnl, rpmfiDNIndex(fi, dil), dnlen))
+ if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen))
continue;
- if (!rstreqn(dnl+dnlen, rpmfiBNIndex(fi, i), bnlen))
+ if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen))
continue;
if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
continue;
@@ -366,7 +154,7 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse)
rpmlog(RPMLOG_DEBUG,
"========== Directories not explicitly included in package:\n");
}
- rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfiDNIndex(fi, i));
+ rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i));
}
if (j)
rpmlog(RPMLOG_DEBUG, "==========\n");
@@ -386,8 +174,8 @@ const char * dnlNextIterator(DNLI_t dnli)
const char * dn = NULL;
if (dnli) {
- rpmfi fi = dnli->fi;
- int dc = rpmfiDC(fi);
+ rpmfiles fi = dnli->fi;
+ int dc = rpmfilesDC(fi);
int i = -1;
if (dnli->active)
@@ -396,7 +184,7 @@ const char * dnlNextIterator(DNLI_t dnli)
} while (i >= 0 && i < dc && !dnli->active[i]);
if (i >= 0 && i < dc)
- dn = rpmfiDNIndex(fi, i);
+ dn = rpmfilesDN(fi, i);
else
i = -1;
dnli->isave = i;
@@ -404,251 +192,6 @@ const char * dnlNextIterator(DNLI_t dnli)
return dn;
}
-/**
- * Map next file path and action.
- * @param fsm file state machine
- * @param i file index
- */
-static int fsmMapPath(FSM_t fsm, int i)
-{
- rpmfi fi = fsmGetFi(fsm); /* XXX const except for fstates */
- int rc = 0;
-
- fsm->osuffix = NULL;
- fsm->nsuffix = NULL;
- fsm->action = FA_UNKNOWN;
-
- if (fi && i >= 0 && i < rpmfiFC(fi)) {
- rpmfs fs = fsmGetFs(fsm);
- /* XXX these should use rpmfiFFlags() etc */
- fsm->action = rpmfsGetAction(fs, i);
- fsm->fflags = rpmfiFFlagsIndex(fi, i);
-
- /* src rpms have simple base name in payload. */
- fsm->dirName = rpmfiDNIndex(fi, rpmfiDIIndex(fi, i));
- fsm->baseName = rpmfiBNIndex(fi, i);
-
- /* Never create backup for %ghost files. */
- if (fsm->goal != FSM_PKGBUILD && !(fsm->fflags & RPMFILE_GHOST)) {
- switch (fsm->action) {
- case FA_ALTNAME:
- fsm->nsuffix = SUFFIX_RPMNEW;
- break;
- case FA_SAVE:
- fsm->osuffix = SUFFIX_RPMSAVE;
- break;
- case FA_BACKUP:
- fsm->osuffix = (fsm->goal == FSM_PKGINSTALL) ?
- SUFFIX_RPMORIG : SUFFIX_RPMSAVE;
- break;
- default:
- break;
- }
- }
-
- if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
- fsm->path = _free(fsm->path);
- fsm->path = fsmFsPath(fsm, S_ISDIR(fsm->sb.st_mode),
- (fsm->suffix ? fsm->suffix : fsm->nsuffix));
- }
- }
- return rc;
-}
-
-/** \ingroup payload
- * Save hard link in chain.
- * @param fsm file state machine data
- * @retval linkSet hard link set when complete
- * @return Is chain only partially filled?
- */
-static int saveHardLink(FSM_t fsm, hardLink_t * linkSet)
-{
- struct stat * st = &fsm->sb;
- int rc = 0;
- int ix = -1;
- int j;
- hardLink_t *tailp, li;
-
- /* Find hard link set. */
- for (tailp = &fsm->links; (li = *tailp) != NULL; tailp = &li->next) {
- if (li->sb.st_ino == st->st_ino && li->sb.st_dev == st->st_dev)
- break;
- }
-
- /* New hard link encountered, add new link to set. */
- if (li == NULL) {
- li = xcalloc(1, sizeof(*li));
- li->next = NULL;
- li->sb = *st; /* structure assignment */
- li->nlink = st->st_nlink;
- li->linkIndex = fsm->ix;
- li->createdPath = -1;
-
- li->filex = xcalloc(st->st_nlink, sizeof(li->filex[0]));
- memset(li->filex, -1, (st->st_nlink * sizeof(li->filex[0])));
- li->nsuffix = xcalloc(st->st_nlink, sizeof(*li->nsuffix));
-
- if (fsm->goal == FSM_PKGBUILD)
- li->linksLeft = st->st_nlink;
- if (fsm->goal == FSM_PKGINSTALL)
- li->linksLeft = 0;
-
- *tailp = li; /* append to tail of linked list */
- }
-
- if (fsm->goal == FSM_PKGBUILD) --li->linksLeft;
- li->filex[li->linksLeft] = fsm->ix;
- li->nsuffix[li->linksLeft] = fsm->nsuffix;
- if (fsm->goal == FSM_PKGINSTALL) li->linksLeft++;
-
- if (fsm->goal == FSM_PKGBUILD)
- return (li->linksLeft > 0);
-
- if (fsm->goal != FSM_PKGINSTALL)
- return 0;
-
- if (!(st->st_size || li->linksLeft == st->st_nlink))
- return 1;
-
- /* Here come the bits, time to choose a non-skipped file name. */
- { rpmfs fs = fsmGetFs(fsm);
-
- for (j = li->linksLeft - 1; j >= 0; j--) {
- ix = li->filex[j];
- if (ix < 0 || XFA_SKIPPING(rpmfsGetAction(fs, ix)))
- continue;
- break;
- }
- }
-
- /* Are all links skipped or not encountered yet? */
- if (ix < 0 || j < 0)
- return 1; /* XXX W2DO? */
-
- /* Save the non-skipped file name and map index. */
- li->linkIndex = j;
- if (linkSet)
- *linkSet = li;
- fsm->path = _free(fsm->path);
- fsm->ix = ix;
- rc = fsmMapPath(fsm, fsm->ix);
- return rc;
-}
-
-/** \ingroup payload
- * Destroy set of hard links.
- * @param li set of hard links
- * @return NULL always
- */
-static hardLink_t freeHardLink(hardLink_t li)
-{
- if (li) {
- li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */
- li->filex = _free(li->filex);
- _free(li);
- }
- return NULL;
-}
-
-/* Check for hard links missing from payload */
-static int checkHardLinks(FSM_t fsm)
-{
- int rc = 0;
- rpmfs fs = fsmGetFs(fsm);
-
- for (hardLink_t li = fsm->links; li != NULL; li = li->next) {
- if (li->linksLeft) {
- for (nlink_t i = 0 ; i < li->linksLeft; i++) {
- int ix = li->filex[i];
- if (ix < 0 || XFA_SKIPPING(rpmfsGetAction(fs, ix)))
- continue;
- rc = CPIOERR_MISSING_HARDLINK;
- if (fsm->failedFile && *fsm->failedFile == NULL) {
- if (!fsmMapPath(fsm, ix)) {
- /* Out-of-sync hardlinks handled as sub-state */
- *fsm->failedFile = fsm->path;
- fsm->path = NULL;
- }
- }
- break;
- }
- }
- }
- return rc;
-}
-
-static FSM_t fsmNew(fileStage goal, rpmfs fs, rpmfi fi, char ** failedFile)
-{
- FSM_t fsm = xcalloc(1, sizeof(*fsm));
-
- fsm->ix = -1;
- fsm->goal = goal;
- fsm->iter = mapInitIterator(fs, fi, (goal == FSM_PKGERASE));
-
- /* common flags for all modes */
- fsm->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
-
- if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
- fsm->bufsize = 8 * BUFSIZ;
- fsm->buf = xmalloc(fsm->bufsize);
- }
-
- fsm->failedFile = failedFile;
- if (fsm->failedFile)
- *fsm->failedFile = NULL;
-
- return fsm;
-}
-
-static FSM_t fsmFree(FSM_t fsm)
-{
- hardLink_t li;
- fsm->buf = _free(fsm->buf);
- fsm->bufsize = 0;
-
- fsm->iter = mapFreeIterator(fsm->iter);
- fsm->failedFile = NULL;
-
- fsm->path = _free(fsm->path);
- fsm->suffix = _free(fsm->suffix);
-
- while ((li = fsm->links) != NULL) {
- fsm->links = li->next;
- li->next = NULL;
- freeHardLink(li);
- }
- free(fsm);
- return NULL;
-}
-
-/* Find and set file security context */
-static int fsmSetSELabel(struct selabel_handle *sehandle,
- const char *path, mode_t mode)
-{
- int rc = 0;
-#if WITH_SELINUX
- if (sehandle) {
- security_context_t scon = NULL;
-
- if (selabel_lookup_raw(sehandle, &scon, path, mode) == 0) {
- rc = lsetfilecon(path, scon);
-
- if (_fsm_debug) {
- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n",
- __func__, path, scon,
- (rc < 0 ? strerror(errno) : ""));
- }
-
- if (rc < 0 && errno == EOPNOTSUPP)
- rc = 0;
- }
-
- freecon(scon);
- }
-#endif
- return rc ? CPIOERR_LSETFCON_FAILED : 0;
-}
-
static int fsmSetFCaps(const char *path, const char *captxt)
{
int rc = 0;
@@ -656,7 +199,7 @@ static int fsmSetFCaps(const char *path, const char *captxt)
if (captxt && *captxt != '\0') {
cap_t fcaps = cap_from_text(captxt);
if (fcaps == NULL || cap_set_file(path, fcaps) != 0) {
- rc = CPIOERR_SETCAP_FAILED;
+ rc = RPMERR_SETCAP_FAILED;
}
cap_free(fcaps);
}
@@ -664,132 +207,102 @@ static int fsmSetFCaps(const char *path, const char *captxt)
return rc;
}
-/**
- * Map file stat(2) info.
- * @param fsm file state machine
- */
-static int fsmMapAttrs(FSM_t fsm)
+static void wfd_close(FD_t *wfdp)
{
- struct stat * st = &fsm->sb;
- rpmfi fi = fsmGetFi(fsm);
- int i = fsm->ix;
-
- /* this check is pretty moot, rpmfi accessors check array bounds etc */
- if (fi && i >= 0 && i < rpmfiFC(fi)) {
- ino_t finalInode = rpmfiFInodeIndex(fi, i);
- mode_t finalMode = rpmfiFModeIndex(fi, i);
- dev_t finalRdev = rpmfiFRdevIndex(fi, i);
- time_t finalMtime = rpmfiFMtimeIndex(fi, i);
- const char *user = rpmfiFUserIndex(fi, i);
- const char *group = rpmfiFGroupIndex(fi, i);
- uid_t uid = 0;
- gid_t gid = 0;
-
- if (user && rpmugUid(user, &uid)) {
- if (fsm->goal == FSM_PKGINSTALL)
- rpmlog(RPMLOG_WARNING,
- _("user %s does not exist - using root\n"), user);
- finalMode &= ~S_ISUID; /* turn off suid bit */
+ if (wfdp && *wfdp) {
+ int myerrno = errno;
+ static int oneshot = 0;
+ static int flush_io = 0;
+ if (!oneshot) {
+ flush_io = rpmExpandNumeric("%{?_flush_io}");
+ oneshot = 1;
}
-
- if (group && rpmugGid(group, &gid)) {
- if (fsm->goal == FSM_PKGINSTALL)
- rpmlog(RPMLOG_WARNING,
- _("group %s does not exist - using root\n"), group);
- finalMode &= ~S_ISGID; /* turn off sgid bit */
+ if (flush_io) {
+ int fdno = Fileno(*wfdp);
+ fsync(fdno);
}
+ Fclose(*wfdp);
+ *wfdp = NULL;
+ errno = myerrno;
+ }
+}
- if (fsm->mapFlags & CPIO_MAP_MODE)
- st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
- if (fsm->mapFlags & CPIO_MAP_TYPE) {
- st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
- if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
- && st->st_nlink == 0)
- st->st_nlink = 1;
- st->st_ino = finalInode;
- st->st_rdev = finalRdev;
- st->st_mtime = finalMtime;
- }
- if (fsm->mapFlags & CPIO_MAP_UID)
- st->st_uid = uid;
- if (fsm->mapFlags & CPIO_MAP_GID)
- st->st_gid = gid;
+static int wfd_open(FD_t *wfdp, const char *dest)
+{
+ int rc = 0;
+ /* Create the file with 0200 permissions (write by owner). */
+ {
+ mode_t old_umask = umask(0577);
+ *wfdp = Fopen(dest, "wx.ufdio");
+ umask(old_umask);
}
+ if (Ferror(*wfdp)) {
+ rc = RPMERR_OPEN_FAILED;
+ goto exit;
+ }
+
return 0;
+
+exit:
+ wfd_close(wfdp);
+ return rc;
}
/** \ingroup payload
* Create file from payload stream.
- * @param fsm file state machine data
- * @param archive payload archive
* @return 0 on success
*/
-static int expandRegular(FSM_t fsm, rpmpsm psm, rpmcpio_t archive, int nodigest)
+static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest)
{
FD_t wfd = NULL;
- const struct stat * st = &fsm->sb;
- rpm_loff_t left = st->st_size;
- const unsigned char * fidigest = NULL;
- pgpHashAlgo digestalgo = 0;
- int rc = 0;
-
- wfd = Fopen(fsm->path, "w.ufdio");
- if (Ferror(wfd)) {
- rc = CPIOERR_OPEN_FAILED;
- goto exit;
- }
-
- if (!nodigest) {
- rpmfi fi = fsmGetFi(fsm);
- digestalgo = rpmfiDigestAlgo(fi);
- fidigest = rpmfiFDigestIndex(fi, fsm->ix, NULL, NULL);
- }
-
- if (st->st_size > 0 && fidigest)
- fdInitDigest(wfd, digestalgo, 0);
-
- while (left) {
- size_t len;
- len = (left > fsm->bufsize ? fsm->bufsize : left);
- if (rpmcpioRead(archive, fsm->buf, len) != len) {
- rc = CPIOERR_READ_FAILED;
- goto exit;
- }
- if ((Fwrite(fsm->buf, sizeof(*fsm->buf), len, wfd) != len) || Ferror(wfd)) {
- rc = CPIOERR_WRITE_FAILED;
- goto exit;
- }
+ int rc;
- left -= len;
+ rc = wfd_open(&wfd, dest);
+ if (rc != 0)
+ goto exit;
- /* don't call this with fileSize == fileComplete */
- if (!rc && left)
- rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmcpioTell(archive));
- }
-
- if (st->st_size > 0 && fidigest) {
- void * digest = NULL;
+ rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm);
+ wfd_close(&wfd);
+exit:
+ return rc;
+}
- (void) Fflush(wfd);
- fdFiniDigest(wfd, digestalgo, &digest, NULL, 0);
+static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
+ rpmpsm psm, int nodigest, int *setmeta,
+ int * firsthardlink, FD_t *firstlinkfile)
+{
+ int rc = 0;
+ int numHardlinks = rpmfiFNlink(fi);
- if (digest != NULL && fidigest != NULL) {
- size_t diglen = rpmDigestLength(digestalgo);
- if (memcmp(digest, fidigest, diglen)) {
- rc = CPIOERR_DIGEST_MISMATCH;
- }
+ if (numHardlinks > 1) {
+ /* Create first hardlinked file empty */
+ if (*firsthardlink < 0) {
+ *firsthardlink = rpmfiFX(fi);
+ rc = wfd_open(firstlinkfile, dest);
} else {
- rc = CPIOERR_DIGEST_MISMATCH;
+ /* Create hard links for others */
+ char *fn = rpmfilesFN(files, *firsthardlink);
+ rc = link(fn, dest);
+ if (rc < 0) {
+ rc = RPMERR_LINK_FAILED;
+ }
+ free(fn);
}
- free(digest);
}
-
-exit:
- if (wfd) {
- int myerrno = errno;
- Fclose(wfd);
- errno = myerrno;
+ /* Write normal files or fill the last hardlinked (already
+ existing) file with content */
+ if (numHardlinks<=1) {
+ if (!rc)
+ rc = expandRegular(fi, dest, psm, nodigest);
+ } else if (rpmfiArchiveHasContent(fi)) {
+ if (!rc)
+ rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
+ wfd_close(firstlinkfile);
+ *firsthardlink = -1;
+ } else {
+ *setmeta = 0;
}
+
return rc;
}
@@ -797,7 +310,7 @@ static int fsmReadLink(const char *path,
char *buf, size_t bufsize, size_t *linklen)
{
ssize_t llen = readlink(path, buf, bufsize - 1);
- int rc = CPIOERR_READLINK_FAILED;
+ int rc = RPMERR_READLINK_FAILED;
if (_fsm_debug) {
rpmlog(RPMLOG_DEBUG, " %8s (%s, buf, %d) %s\n",
@@ -813,168 +326,6 @@ static int fsmReadLink(const char *path,
return rc;
}
-/** \ingroup payload
- * Write next item to payload stream.
- * @param fsm file state machine data
- * @param writeData should data be written?
- * @param archive payload archive
- * @param ix file index
- * @return 0 on success
- */
-static int writeFile(FSM_t fsm, int writeData, rpmcpio_t archive, int ix)
-{
- FD_t rfd = NULL;
- char * path = fsm->path;
- struct stat * st = &fsm->sb;
- struct stat * ost = &fsm->osb;
- char * symbuf = NULL;
- rpm_loff_t left;
- int rc = 0;
-
- st->st_size = (writeData ? ost->st_size : 0);
-
- if (S_ISDIR(st->st_mode)) {
- st->st_size = 0;
- } else if (S_ISLNK(st->st_mode)) {
- /*
- * While linux puts the size of a symlink in the st_size field,
- * I don't think that's a specified standard.
- */
- size_t linklen;
- rc = fsmReadLink(fsm->path, fsm->buf, fsm->bufsize, &linklen);
- if (rc) goto exit;
- st->st_size = linklen;
- rstrcat(&symbuf, fsm->buf); /* XXX save readlink return. */
- }
-
- if (fsm->mapFlags & CPIO_MAP_ABSOLUTE) {
- fsm->path = rstrscat(NULL, (fsm->mapFlags & CPIO_MAP_ADDDOT) ? "." : "",
- fsm->dirName, fsm->baseName, NULL);
- } else if (fsm->mapFlags & CPIO_MAP_PATH) {
- rpmfi fi = fsmGetFi(fsm);
- fsm->path = xstrdup((fi->apath ? fi->apath[ix] :
- rpmfiBNIndex(fi, ix)));
- }
-
- rc = rpmcpioHeaderWrite(archive, fsm->path, st);
- _free(fsm->path);
- fsm->path = path;
-
- if (rc) goto exit;
-
-
- if (writeData && S_ISREG(st->st_mode)) {
- size_t len;
-
- rfd = Fopen(fsm->path, "r.ufdio");
- if (Ferror(rfd)) {
- rc = CPIOERR_OPEN_FAILED;
- goto exit;
- }
-
- left = st->st_size;
-
- while (left) {
- len = (left > fsm->bufsize ? fsm->bufsize : left);
- if (Fread(fsm->buf, sizeof(*fsm->buf), len, rfd) != len || Ferror(rfd)) {
- rc = CPIOERR_READ_FAILED;
- goto exit;
- }
-
- if (rpmcpioWrite(archive, fsm->buf, len) != len) {
- rc = CPIOERR_WRITE_FAILED;
- goto exit;
- }
- left -= len;
- }
- } else if (writeData && S_ISLNK(st->st_mode)) {
- size_t len = strlen(symbuf);
- if (rpmcpioWrite(archive, symbuf, len) != len) {
- rc = CPIOERR_WRITE_FAILED;
- goto exit;
- }
- }
-
-exit:
- if (rfd) {
- /* preserve any prior errno across close */
- int myerrno = errno;
- Fclose(rfd);
- errno = myerrno;
- }
- fsm->path = path;
- free(symbuf);
- return rc;
-}
-
-/** \ingroup payload
- * Write set of linked files to payload stream.
- * @param fsm file state machine data
- * @param archive payload archive
- * @param li link to write
- * @return 0 on success
- */
-static int writeLinkedFile(FSM_t fsm, rpmcpio_t archive, hardLink_t li)
-{
- char * path = fsm->path;
- const char * nsuffix = fsm->nsuffix;
- int ec = 0;
- int rc;
- int i;
-
- fsm->path = NULL;
- fsm->nsuffix = NULL;
-
- for (i = li->nlink - 1; i >= 0; i--) {
-
- if (li->filex[i] < 0) continue;
-
- rc = fsmMapPath(fsm, li->filex[i]);
-
- /* Write data after last link. */
- rc = writeFile(fsm, (i == 0), archive, li->filex[i]);
- if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
- ec = rc;
- *fsm->failedFile = xstrdup(fsm->path);
- }
-
- fsm->path = _free(fsm->path);
- li->filex[i] = -1;
- }
-
- fsm->nsuffix = nsuffix;
- fsm->path = path;
- return ec;
-}
-
-static int writeLinks(FSM_t fsm, rpmcpio_t archive)
-{
- int j, rc = 0;
- nlink_t i, nlink;
-
- for (hardLink_t li = fsm->links; li; li = li->next) {
- /* Re-calculate link count for archive header. */
- for (j = -1, nlink = 0, i = 0; i < li->nlink; i++) {
- if (li->filex[i] < 0)
- continue;
- nlink++;
- if (j == -1) j = i;
- }
- /* XXX force the contents out as well. */
- if (j != 0) {
- li->filex[0] = li->filex[j];
- li->filex[j] = -1;
- }
- li->sb.st_nlink = nlink;
-
- fsm->sb = li->sb; /* structure assignment */
- fsm->osb = fsm->sb; /* structure assignment */
-
- if (!rc) rc = writeLinkedFile(fsm, archive, li);
- }
- return rc;
-}
-
static int fsmStat(const char *path, int dolstat, struct stat *sb)
{
int rc;
@@ -988,105 +339,10 @@ static int fsmStat(const char *path, int dolstat, struct stat *sb)
__func__,
path, (rc < 0 ? strerror(errno) : ""));
if (rc < 0) {
- rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_LSTAT_FAILED);
- /* WTH is this, and is it really needed, still? */
- memset(sb, 0, sizeof(*sb)); /* XXX s390x hackery */
- }
- return rc;
-}
-
-static int fsmVerify(FSM_t fsm);
-
-/** \ingroup payload
- * Create pending hard links to existing file.
- * @param fsm file state machine data
- * @param li hard link
- * @return 0 on success
- */
-static int fsmMakeLinks(FSM_t fsm, hardLink_t li)
-{
- char * path = fsm->path;
- char * opath = NULL;
- const char * nsuffix = fsm->nsuffix;
- int ec = 0;
- int rc;
- int i;
-
- fsm->path = NULL;
- fsm->nsuffix = NULL;
-
- rc = fsmMapPath(fsm, li->filex[li->createdPath]);
- opath = fsm->path;
- fsm->path = NULL;
- for (i = 0; i < li->nlink; i++) {
- if (li->filex[i] < 0) continue;
- if (li->createdPath == i) continue;
-
- fsm->path = _free(fsm->path);
- rc = fsmMapPath(fsm, li->filex[i]);
- if (XFA_SKIPPING(fsm->action)) continue;
-
- rc = fsmVerify(fsm);
- if (!rc) continue;
- if (!(rc == CPIOERR_ENOENT)) break;
-
- /* XXX link(opath, fsm->path) */
- rc = link(opath, fsm->path);
- if (_fsm_debug)
- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
- opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_LINK_FAILED;
-
- if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
- ec = rc;
- *fsm->failedFile = xstrdup(fsm->path);
- }
-
- li->linksLeft--;
+ rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_LSTAT_FAILED);
+ /* Ensure consistent struct content on failure */
+ memset(sb, 0, sizeof(*sb));
}
- fsm->path = _free(fsm->path);
- free(opath);
-
- fsm->nsuffix = nsuffix;
- fsm->path = path;
- return ec;
-}
-
-static int fsmCommit(FSM_t fsm, int ix);
-
-/** \ingroup payload
- * Commit hard linked file set atomically.
- * @param fsm file state machine data
- * @return 0 on success
- */
-static int fsmCommitLinks(FSM_t fsm)
-{
- char * path = fsm->path;
- const char * nsuffix = fsm->nsuffix;
- struct stat * st = &fsm->sb;
- int rc = 0;
- nlink_t i;
- hardLink_t li;
-
- fsm->path = NULL;
- fsm->nsuffix = NULL;
-
- for (li = fsm->links; li != NULL; li = li->next) {
- if (li->sb.st_ino == st->st_ino && li->sb.st_dev == st->st_dev)
- break;
- }
-
- for (i = 0; i < li->nlink; i++) {
- if (li->filex[i] < 0) continue;
- rc = fsmMapPath(fsm, li->filex[i]);
- if (!XFA_SKIPPING(fsm->action))
- rc = fsmCommit(fsm, li->filex[i]);
- fsm->path = _free(fsm->path);
- li->filex[i] = -1;
- }
-
- fsm->nsuffix = nsuffix;
- fsm->path = path;
return rc;
}
@@ -1098,9 +354,9 @@ static int fsmRmdir(const char *path)
path, (rc < 0 ? strerror(errno) : ""));
if (rc < 0)
switch (errno) {
- case ENOENT: rc = CPIOERR_ENOENT; break;
- case ENOTEMPTY: rc = CPIOERR_ENOTEMPTY; break;
- default: rc = CPIOERR_RMDIR_FAILED; break;
+ case ENOENT: rc = RPMERR_ENOENT; break;
+ case ENOTEMPTY: rc = RPMERR_ENOTEMPTY; break;
+ default: rc = RPMERR_RMDIR_FAILED; break;
}
return rc;
}
@@ -1112,7 +368,7 @@ static int fsmMkdir(const char *path, mode_t mode)
rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
path, (unsigned)(mode & 07777),
(rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_MKDIR_FAILED;
+ if (rc < 0) rc = RPMERR_MKDIR_FAILED;
return rc;
}
@@ -1127,7 +383,7 @@ static int fsmMkfifo(const char *path, mode_t mode)
}
if (rc < 0)
- rc = CPIOERR_MKFIFO_FAILED;
+ rc = RPMERR_MKFIFO_FAILED;
return rc;
}
@@ -1144,24 +400,24 @@ static int fsmMknod(const char *path, mode_t mode, dev_t dev)
}
if (rc < 0)
- rc = CPIOERR_MKNOD_FAILED;
+ rc = RPMERR_MKNOD_FAILED;
return rc;
}
/**
* Create (if necessary) directories not explicitly included in package.
- * @param dnli file state machine data
- * @param sehandle selinux label handle (bah)
+ * @param files file data
+ * @param fs file states
* @param plugins rpm plugins handle
* @return 0 on success
*/
-static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle, rpmPlugins plugins)
+static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins)
{
- DNLI_t dnli = dnlInitIterator(fi, fs, 0);
+ DNLI_t dnli = dnlInitIterator(files, fs, 0);
struct stat sb;
const char *dpath;
- int dc = rpmfiDC(fi);
+ int dc = rpmfilesDC(files);
int rc = 0;
int i;
int ldnlen = 0;
@@ -1213,21 +469,35 @@ static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle, rpmPlu
if (rc == 0 && S_ISDIR(sb.st_mode)) {
/* Move pre-existing path marker forward. */
dnlx[dc] = (te - dn);
- } else if (rc == CPIOERR_ENOENT) {
+ } else if (rc == RPMERR_ENOENT) {
*te = '\0';
mode_t mode = S_IFDIR | (_dirPerms & 07777);
- rc = fsmMkdir(dn, mode);
+ rpmFsmOp op = (FA_CREATE|FAF_UNOWNED);
+
+ /* Run fsm file pre hook for all plugins */
+ rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op);
+
+ if (!rc)
+ rc = fsmMkdir(dn, mode);
+
if (!rc) {
- rc = fsmSetSELabel(sehandle, dn, mode);
+ rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn,
+ mode, op);
+ }
+ /* Run fsm file post hook for all plugins */
+ rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc);
+
+ if (!rc) {
rpmlog(RPMLOG_DEBUG,
"%s directory created with perms %04o\n",
dn, (unsigned)(mode & 07777));
}
+
if (!rc) {
- /* Run file closed hook for all plugins */
- rc = rpmpluginsCallFsmCommit(plugins, dn, mode, DIR_TYPE_UNOWNED);
- }
+ /* Run file closed hook for all plugins */
+ rc = rpmpluginsCallFsmCommit(plugins, dn, mode, DIR_TYPE_UNOWNED);
+ }
*te = '/';
}
if (rc)
@@ -1267,72 +537,14 @@ static void removeSBITS(const char *path)
}
}
-/********************************************************************/
-
-static void fsmReset(FSM_t fsm)
-{
- fsm->path = _free(fsm->path);
- fsm->postpone = 0;
- fsm->diskchecked = fsm->exists = 0;
- fsm->action = FA_UNKNOWN;
- fsm->osuffix = NULL;
- fsm->nsuffix = NULL;
- memset(&(fsm->sb), 0, sizeof(fsm->sb));
- memset(&(fsm->osb), 0, sizeof(fsm->sb));
-}
-
-static int fsmInit(FSM_t fsm)
+static void fsmDebug(const char *fpath, rpmFileAction action,
+ const struct stat *st)
{
- int rc = 0;
-
- /* On non-install, mode must be known so that dirs don't get suffix. */
- if (fsm->goal != FSM_PKGINSTALL) {
- rpmfi fi = fsmGetFi(fsm);
- fsm->sb.st_mode = rpmfiFModeIndex(fi, fsm->ix);
- }
-
- /* Generate file path. */
- rc = fsmMapPath(fsm, fsm->ix);
- if (rc) return rc;
-
- /* Perform lstat/stat for disk file. */
- if (fsm->path != NULL &&
- !(fsm->goal == FSM_PKGINSTALL && S_ISREG(fsm->sb.st_mode)))
- {
- int dolstat = !(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS);
- rc = fsmStat(fsm->path, dolstat, &fsm->osb);
- if (rc == CPIOERR_ENOENT) {
- // errno = saveerrno; XXX temporary commented out
- rc = 0;
- fsm->exists = 0;
- } else if (rc == 0) {
- fsm->exists = 1;
- }
- } else {
- /* Skip %ghost files on build. */
- fsm->exists = 0;
- }
- fsm->diskchecked = 1;
- if (rc) return rc;
-
- /* On non-install, the disk file stat is what's remapped. */
- if (fsm->goal != FSM_PKGINSTALL)
- fsm->sb = fsm->osb; /* structure assignment */
-
- /* Remap file perms, owner, and group. */
- rc = fsmMapAttrs(fsm);
- if (rc) return rc;
-
- fsm->postpone = XFA_SKIPPING(fsm->action);
-
rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s\n",
- fileActionString(fsm->action), (int)fsm->sb.st_mode,
- (int)fsm->sb.st_nlink, (int)fsm->sb.st_uid,
- (int)fsm->sb.st_gid, (int)fsm->sb.st_size,
- (fsm->path ? fsm->path : ""));
-
- return rc;
-
+ fileActionString(action), (int)st->st_mode,
+ (int)st->st_nlink, (int)st->st_uid,
+ (int)st->st_gid, (int)st->st_size,
+ (fpath ? fpath : ""));
}
static int fsmSymlink(const char *opath, const char *path)
@@ -1345,29 +557,26 @@ static int fsmSymlink(const char *opath, const char *path)
}
if (rc < 0)
- rc = CPIOERR_SYMLINK_FAILED;
+ rc = RPMERR_SYMLINK_FAILED;
return rc;
}
-static int fsmUnlink(const char *path, cpioMapFlags mapFlags)
+static int fsmUnlink(const char *path)
{
int rc = 0;
- if (mapFlags & CPIO_SBIT_CHECK)
- removeSBITS(path);
+ removeSBITS(path);
rc = unlink(path);
if (_fsm_debug)
rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__,
path, (rc < 0 ? strerror(errno) : ""));
if (rc < 0)
- rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_UNLINK_FAILED);
+ rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_UNLINK_FAILED);
return rc;
}
-static int fsmRename(const char *opath, const char *path,
- cpioMapFlags mapFlags)
+static int fsmRename(const char *opath, const char *path)
{
- if (mapFlags & CPIO_SBIT_CHECK)
- removeSBITS(path);
+ removeSBITS(path);
int rc = rename(opath, path);
#if defined(ETXTBSY) && defined(__HPUX__)
/* XXX HP-UX (and other os'es) don't permit rename to busy files. */
@@ -1382,30 +591,19 @@ static int fsmRename(const char *opath, const char *path,
if (_fsm_debug)
rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
opath, path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_RENAME_FAILED;
+ if (rc < 0)
+ rc = (errno == EISDIR ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED);
return rc;
}
-
-static int fsmChown(const char *path, uid_t uid, gid_t gid)
+static int fsmRemove(const char *path, mode_t mode)
{
- int rc = chown(path, uid, gid);
- if (rc < 0) {
- struct stat st;
- if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
- rc = 0;
- }
- if (_fsm_debug)
- rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__,
- path, (int)uid, (int)gid,
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
- return rc;
+ return S_ISDIR(mode) ? fsmRmdir(path) : fsmUnlink(path);
}
-static int fsmLChown(const char *path, uid_t uid, gid_t gid)
+static int fsmChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
{
- int rc = lchown(path, uid, gid);
+ int rc = S_ISLNK(mode) ? lchown(path, uid, gid) : chown(path, uid, gid);
if (rc < 0) {
struct stat st;
if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
@@ -1415,7 +613,7 @@ static int fsmLChown(const char *path, uid_t uid, gid_t gid)
rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__,
path, (int)uid, (int)gid,
(rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
+ if (rc < 0) rc = RPMERR_CHOWN_FAILED;
return rc;
}
@@ -1431,76 +629,90 @@ static int fsmChmod(const char *path, mode_t mode)
rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
path, (unsigned)(mode & 07777),
(rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_CHMOD_FAILED;
+ if (rc < 0) rc = RPMERR_CHMOD_FAILED;
return rc;
}
-static int fsmUtime(const char *path, time_t mtime)
+static int fsmUtime(const char *path, mode_t mode, time_t mtime)
{
int rc = 0;
- struct utimbuf stamp;
- stamp.actime = mtime;
- stamp.modtime = mtime;
- rc = utime(path, &stamp);
+ struct timeval stamps[2] = {
+ { .tv_sec = mtime, .tv_usec = 0 },
+ { .tv_sec = mtime, .tv_usec = 0 },
+ };
+
+#if HAVE_LUTIMES
+ rc = lutimes(path, stamps);
+#else
+ if (!S_ISLNK(mode))
+ rc = utimes(path, stamps);
+#endif
+
if (_fsm_debug)
rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__,
path, (unsigned)mtime, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_UTIME_FAILED;
+ if (rc < 0) rc = RPMERR_UTIME_FAILED;
+ /* ...but utime error is not critical for directories */
+ if (rc && S_ISDIR(mode))
+ rc = 0;
return rc;
}
-static int fsmVerify(FSM_t fsm)
+static int fsmVerify(const char *path, rpmfi fi, const struct stat *fsb)
{
int rc;
- struct stat * st = &fsm->sb;
- struct stat * ost = &fsm->osb;
int saveerrno = errno;
+ struct stat dsb;
+ mode_t mode = rpmfiFMode(fi);
- if (fsm->diskchecked && !fsm->exists) {
- return CPIOERR_ENOENT;
- }
- if (S_ISREG(st->st_mode)) {
+ rc = fsmStat(path, 1, &dsb);
+ if (rc)
+ return rc;
+
+ if (S_ISREG(mode)) {
/* HP-UX (and other os'es) don't permit unlink on busy files. */
- char *rmpath = rstrscat(NULL, fsm->path, "-RPMDELETE", NULL);
- rc = fsmRename(fsm->path, rmpath, fsm->mapFlags);
+ char *rmpath = rstrscat(NULL, path, "-RPMDELETE", NULL);
+ rc = fsmRename(path, rmpath);
/* XXX shouldn't we take unlink return code here? */
if (!rc)
- (void) fsmUnlink(rmpath, fsm->mapFlags);
+ (void) fsmUnlink(rmpath);
else
- rc = CPIOERR_UNLINK_FAILED;
+ rc = RPMERR_UNLINK_FAILED;
free(rmpath);
- return (rc ? rc : CPIOERR_ENOENT); /* XXX HACK */
- } else if (S_ISDIR(st->st_mode)) {
- if (S_ISDIR(ost->st_mode)) return 0;
- if (S_ISLNK(ost->st_mode)) {
- rc = fsmStat(fsm->path, 0, &fsm->osb);
- if (rc == CPIOERR_ENOENT) rc = 0;
+ return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */
+ } else if (S_ISDIR(mode)) {
+ if (S_ISDIR(dsb.st_mode)) return 0;
+ if (S_ISLNK(dsb.st_mode)) {
+ uid_t luid = dsb.st_uid;
+ rc = fsmStat(path, 0, &dsb);
+ if (rc == RPMERR_ENOENT) rc = 0;
if (rc) return rc;
errno = saveerrno;
- if (S_ISDIR(ost->st_mode)) return 0;
+ /* Only permit directory symlinks by target owner and root */
+ if (S_ISDIR(dsb.st_mode) && (luid == 0 || luid == fsb->st_uid))
+ return 0;
}
- } else if (S_ISLNK(st->st_mode)) {
- if (S_ISLNK(ost->st_mode)) {
+ } else if (S_ISLNK(mode)) {
+ if (S_ISLNK(dsb.st_mode)) {
char buf[8 * BUFSIZ];
size_t len;
- rc = fsmReadLink(fsm->path, buf, 8 * BUFSIZ, &len);
+ rc = fsmReadLink(path, buf, 8 * BUFSIZ, &len);
errno = saveerrno;
if (rc) return rc;
- /* FSM_PROCESS puts link target to fsm->buf. */
- if (rstreq(fsm->buf, buf)) return 0;
+ if (rstreq(rpmfiFLink(fi), buf)) return 0;
}
- } else if (S_ISFIFO(st->st_mode)) {
- if (S_ISFIFO(ost->st_mode)) return 0;
- } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
- if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
- (ost->st_rdev == st->st_rdev)) return 0;
- } else if (S_ISSOCK(st->st_mode)) {
- if (S_ISSOCK(ost->st_mode)) return 0;
+ } else if (S_ISFIFO(mode)) {
+ if (S_ISFIFO(dsb.st_mode)) return 0;
+ } else if (S_ISCHR(mode) || S_ISBLK(mode)) {
+ if ((S_ISCHR(dsb.st_mode) || S_ISBLK(dsb.st_mode)) &&
+ (dsb.st_rdev == rpmfiFRdev(fi))) return 0;
+ } else if (S_ISSOCK(mode)) {
+ if (S_ISSOCK(dsb.st_mode)) return 0;
}
/* XXX shouldn't do this with commit/undo. */
- rc = fsmUnlink(fsm->path, fsm->mapFlags);
- if (rc == 0) rc = CPIOERR_ENOENT;
- return (rc ? rc : CPIOERR_ENOENT); /* XXX HACK */
+ rc = fsmUnlink(path);
+ if (rc == 0) rc = RPMERR_ENOENT;
+ return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */
}
#define IS_DEV_LOG(_x) \
@@ -1512,88 +724,101 @@ static int fsmVerify(FSM_t fsm)
/* Rename pre-existing modified or unmanaged file. */
-static int fsmBackup(FSM_t fsm)
+static int fsmBackup(rpmfi fi, rpmFileAction action)
{
int rc = 0;
+ const char *suffix = NULL;
- /* FIXME: %ghost can have backup action but no suffix */
- if ((fsm->action == FA_SAVE || fsm->action == FA_BACKUP) && fsm->osuffix) {
- char * opath = fsmFsPath(fsm, S_ISDIR(fsm->sb.st_mode), NULL);
- char * path = fsmFsPath(fsm, 0, fsm->osuffix);
- rc = fsmRename(opath, path, fsm->mapFlags);
- if (!rc) {
- rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path);
- fsm->exists = 0; /* it doesn't exist anymore... */
- }
- free(path);
- free(opath);
+ if (!(rpmfiFFlags(fi) & RPMFILE_GHOST)) {
+ switch (action) {
+ case FA_SAVE:
+ suffix = SUFFIX_RPMSAVE;
+ break;
+ case FA_BACKUP:
+ suffix = SUFFIX_RPMORIG;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (suffix) {
+ char * opath = fsmFsPath(fi, NULL);
+ char * path = fsmFsPath(fi, suffix);
+ rc = fsmRename(opath, path);
+ if (!rc) {
+ rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path);
+ }
+ free(path);
+ free(opath);
}
return rc;
}
-static int fsmCommit(FSM_t fsm, int ix)
+static int fsmSetmeta(const char *path, rpmfi fi, rpmPlugins plugins,
+ rpmFileAction action, const struct stat * st,
+ int nofcaps)
+{
+ int rc = 0;
+ const char *dest = rpmfiFN(fi);
+
+ if (!rc && !getuid()) {
+ rc = fsmChown(path, st->st_mode, st->st_uid, st->st_gid);
+ }
+ if (!rc && !S_ISLNK(st->st_mode)) {
+ rc = fsmChmod(path, st->st_mode);
+ }
+ /* Set file capabilities (if enabled) */
+ if (!rc && !nofcaps && S_ISREG(st->st_mode) && !getuid()) {
+ rc = fsmSetFCaps(path, rpmfiFCaps(fi));
+ }
+ if (!rc) {
+ rc = fsmUtime(path, st->st_mode, rpmfiFMtime(fi));
+ }
+ if (!rc) {
+ rc = rpmpluginsCallFsmFilePrepare(plugins, fi,
+ path, dest, st->st_mode, action);
+ }
+
+ return rc;
+}
+
+static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *suffix, rpmPlugins plugins)
{
int rc = 0;
- struct stat * st = &fsm->sb;
/* XXX Special case /dev/log, which shouldn't be packaged anyways */
- if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) {
- /* Backup on-disk file if needed. Directories are handled earlier */
- if (!S_ISDIR(st->st_mode))
- rc = fsmBackup(fsm);
- /* Rename temporary to final file name. */
- if (!S_ISDIR(st->st_mode) && (fsm->suffix || fsm->nsuffix)) {
- char *npath = fsmFsPath(fsm, 0, fsm->nsuffix);
- rc = fsmRename(fsm->path, npath, fsm->mapFlags);
- if (!rc && fsm->nsuffix) {
- char * opath = fsmFsPath(fsm, 0, NULL);
- rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
- opath, npath);
- free(opath);
- }
- free(fsm->path);
- fsm->path = npath;
- }
- /* Set file security context (if enabled) */
- if (!rc && !getuid()) {
- rc = fsmSetSELabel(fsm->sehandle, fsm->path, fsm->sb.st_mode);
- }
+ if (!(S_ISSOCK(rpmfiFMode(fi)) && IS_DEV_LOG(*path))) {
+ const char *nsuffix = (action == FA_ALTNAME) ? SUFFIX_RPMNEW : NULL;
+ char *dest = *path;
+ /* Construct final destination path (nsuffix is usually NULL) */
+ if (suffix)
+ dest = fsmFsPath(fi, nsuffix);
+
+ /* Rename temporary to final file name if needed. */
+ if (dest != *path) {
+ rc = fsmRename(*path, dest);
+ if (!rc && nsuffix) {
+ char * opath = fsmFsPath(fi, NULL);
+ rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
+ opath, dest);
+ free(opath);
+ }
+ free(*path);
+ *path = dest;
+ }
/* Call fsm commit hook for all plugins */
if (!rc) {
- rc = rpmpluginsCallFsmCommit(fsm->plugins, fsm->path, fsm->sb.st_mode, DIR_TYPE_NORMAL);
- }
- if (S_ISLNK(st->st_mode)) {
- if (!rc && !getuid())
- rc = fsmLChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
- } else {
- rpmfi fi = fsmGetFi(fsm);
- if (!rc && !getuid())
- rc = fsmChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
- if (!rc)
- rc = fsmChmod(fsm->path, fsm->sb.st_mode);
- if (!rc) {
- rc = fsmUtime(fsm->path, rpmfiFMtimeIndex(fi, ix));
- /* utime error is not critical for directories */
- if (rc && S_ISDIR(st->st_mode))
- rc = 0;
- }
- /* Set file capabilities (if enabled) */
- if (!rc && !S_ISDIR(st->st_mode) && !getuid()) {
- rc = fsmSetFCaps(fsm->path, rpmfiFCapsIndex(fi, ix));
- }
+ rc = rpmpluginsCallFsmCommit(plugins, *path, rpmfiFMode(fi), DIR_TYPE_NORMAL);
}
}
- if (rc && fsm->failedFile && *fsm->failedFile == NULL) {
- *fsm->failedFile = fsm->path;
- fsm->path = NULL;
- }
return rc;
}
/**
* Return formatted string representation of file disposition.
- * @param a file dispostion
+ * @param a file disposition
* @return formatted string
*/
static const char * fileActionString(rpmFileAction a)
@@ -1601,8 +826,6 @@ static const char * fileActionString(rpmFileAction a)
switch (a) {
case FA_UNKNOWN: return "unknown";
case FA_CREATE: return "create";
- case FA_COPYOUT: return "copyout";
- case FA_COPYIN: return "copyin";
case FA_BACKUP: return "backup";
case FA_SAVE: return "save";
case FA_SKIP: return "skip";
@@ -1611,14 +834,15 @@ static const char * fileActionString(rpmFileAction a)
case FA_SKIPNSTATE: return "skipnstate";
case FA_SKIPNETSHARED: return "skipnetshared";
case FA_SKIPCOLOR: return "skipcolor";
+ case FA_TOUCH: return "touch";
default: return "???";
}
}
/* Remember any non-regular file state for recording in the rpmdb */
-static void setFileState(rpmfs fs, int i, rpmFileAction action)
+static void setFileState(rpmfs fs, int i)
{
- switch (action) {
+ switch (rpmfsGetAction(fs, i)) {
case FA_SKIPNSTATE:
rpmfsSetState(fs, i, RPMFILE_STATE_NOTINSTALLED);
break;
@@ -1628,219 +852,223 @@ static void setFileState(rpmfs fs, int i, rpmFileAction action)
case FA_SKIPCOLOR:
rpmfsSetState(fs, i, RPMFILE_STATE_WRONGCOLOR);
break;
+ case FA_TOUCH:
+ rpmfsSetState(fs, i, RPMFILE_STATE_NORMAL);
+ break;
default:
break;
}
}
-int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi fi, FD_t cfd,
+int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rpmpsm psm, char ** failedFile)
{
+ FD_t payload = rpmtePayload(te);
+ rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
rpmfs fs = rpmteGetFileStates(te);
- FSM_t fsm = fsmNew(FSM_PKGINSTALL, fs, fi, failedFile);
- rpmcpio_t archive = rpmcpioOpen(cfd, O_RDONLY);
- struct stat * st = &fsm->sb;
+ rpmPlugins plugins = rpmtsPlugins(ts);
+ struct stat sb;
int saveerrno = errno;
int rc = 0;
- int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST);
-
- if (!rpmteIsSource(te))
- fsm->mapFlags |= CPIO_SBIT_CHECK;
-
- if (archive == NULL)
- rc = CPIOERR_INTERNAL;
+ int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
+ int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
+ int firsthardlink = -1;
+ FD_t firstlinkfile = NULL;
+ int skip;
+ rpmFileAction action;
+ char *tid = NULL;
+ const char *suffix;
+ char *fpath = NULL;
+
+ if (fi == NULL) {
+ rc = RPMERR_BAD_MAGIC;
+ goto exit;
+ }
- fsm->sehandle = rpmtsSELabelHandle(ts);
- fsm->plugins = rpmtsPlugins(ts);
-
/* transaction id used for temporary path suffix while installing */
- rasprintf(&fsm->suffix, ";%08x", (unsigned)rpmtsGetTid(ts));
+ rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
/* Detect and create directories not explicitly in package. */
- if (!rc) {
- rc = fsmMkdirs(fi, rpmteGetFileStates(te), fsm->sehandle, fsm->plugins);
- }
+ rc = fsmMkdirs(files, fs, plugins);
while (!rc) {
- hardLink_t li = NULL;
-
- /* Clean fsm, free'ing memory. */
- fsmReset(fsm);
-
/* Read next payload header. */
- rc = rpmcpioHeaderRead(archive, &(fsm->path), &(fsm->sb));
+ rc = rpmfiNext(fi);
- /* Detect and exit on end-of-payload. */
- if (rc == CPIOERR_HDR_TRAILER) {
- rc = 0;
+ if (rc < 0) {
+ if (rc == RPMERR_ITER_END)
+ rc = 0;
break;
}
- if (rc) break;
-
- /* Identify mapping index. */
- fsm->ix = mapFind(fsm->iter, fsm->path);
-
- /* Mapping error */
- if (fsm->ix < 0) {
- if (fsm->failedFile && *fsm->failedFile == NULL)
- *fsm->failedFile = xstrdup(fsm->path);
- rc = CPIOERR_UNMAPPED_FILE;
- break;
+ action = rpmfsGetAction(fs, rpmfiFX(fi));
+ skip = XFA_SKIPPING(action);
+ suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
+ if (action != FA_TOUCH) {
+ fpath = fsmFsPath(fi, suffix);
+ } else {
+ fpath = fsmFsPath(fi, "");
}
- rc = fsmInit(fsm);
+ /* Remap file perms, owner, and group. */
+ rc = rpmfiStat(fi, 1, &sb);
- /* Exit on error. */
- if (rc) {
- fsm->postpone = 1;
- break;
- }
+ fsmDebug(fpath, action, &sb);
- /* Run fsm init hook for all plugins */
- rc = rpmpluginsCallFsmInit(fsm->plugins, fsm->path, fsm->sb.st_mode);
-
/* Exit on error. */
- if (rc) {
- fsm->postpone = 1;
+ if (rc)
break;
- }
-
- if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)
- fsm->postpone = saveHardLink(fsm, &li);
-
- setFileState(rpmteGetFileStates(te), fsm->ix, fsm->action);
-
- if (!fsm->postpone) {
- if (S_ISREG(st->st_mode)) {
- rc = fsmVerify(fsm);
- if (!(rc == CPIOERR_ENOENT)) return rc;
- rc = expandRegular(fsm, psm, archive, nodigest);
- } else if (S_ISDIR(st->st_mode)) {
- /* Directories replacing something need early backup */
- rc = fsmBackup(fsm);
- rc = fsmVerify(fsm);
- if (rc == CPIOERR_ENOENT) {
- mode_t mode = st->st_mode;
+
+ /* Run fsm init hook for all plugins */
+ //FIXME. functions related with msm.
+ rc = rpmpluginsCallFsmInit(plugins, fpath, sb.st_mode);
+
+ /* Run fsm file pre hook for all plugins */
+ rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
+ sb.st_mode, action);
+ if (rc) {
+ skip = 1;
+ } else {
+ setFileState(fs, rpmfiFX(fi));
+ }
+
+ if (!skip) {
+ int setmeta = 1;
+
+ /* Directories replacing something need early backup */
+ if (!suffix) {
+ rc = fsmBackup(fi, action);
+ }
+ /* Assume file does't exist when tmp suffix is in use */
+ if (!suffix) {
+ rc = fsmVerify(fpath, fi, &sb);
+ } else {
+ rc = (action == FA_TOUCH) ? 0 : RPMERR_ENOENT;
+ }
+
+ if (S_ISREG(sb.st_mode)) {
+ if (rc == RPMERR_ENOENT) {
+ rc = fsmMkfile(fi, fpath, files, psm, nodigest,
+ &setmeta, &firsthardlink, &firstlinkfile);
+ }
+ } else if (S_ISDIR(sb.st_mode)) {
+ if (rc == RPMERR_ENOENT) {
+ mode_t mode = sb.st_mode;
mode &= ~07777;
mode |= 00700;
- rc = fsmMkdir(fsm->path, mode);
+ rc = fsmMkdir(fpath, mode);
}
- } else if (S_ISLNK(st->st_mode)) {
- if ((st->st_size + 1) > fsm->bufsize) {
- rc = CPIOERR_HDR_SIZE;
- } else if (rpmcpioRead(archive, fsm->buf, st->st_size) != st->st_size) {
- rc = CPIOERR_READ_FAILED;
- } else {
-
- fsm->buf[st->st_size] = '\0';
- /* fsmVerify() assumes link target in fsm->buf */
- rc = fsmVerify(fsm);
- if (rc == CPIOERR_ENOENT) {
- rc = fsmSymlink(fsm->buf, fsm->path);
- }
- }
- } else if (S_ISFIFO(st->st_mode)) {
- /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
- rc = fsmVerify(fsm);
- if (rc == CPIOERR_ENOENT) {
- rc = fsmMkfifo(fsm->path, 0000);
+ } else if (S_ISLNK(sb.st_mode)) {
+ if (rc == RPMERR_ENOENT) {
+ rc = fsmSymlink(rpmfiFLink(fi), fpath);
+ }
+ } else if (S_ISFIFO(sb.st_mode)) {
+ /* This mimics cpio S_ISSOCK() behavior but probably isn't right */
+ if (rc == RPMERR_ENOENT) {
+ rc = fsmMkfifo(fpath, 0000);
}
- } else if (S_ISCHR(st->st_mode) ||
- S_ISBLK(st->st_mode) ||
- S_ISSOCK(st->st_mode))
+ } else if (S_ISCHR(sb.st_mode) ||
+ S_ISBLK(sb.st_mode) ||
+ S_ISSOCK(sb.st_mode))
{
- rc = fsmVerify(fsm);
- if (rc == CPIOERR_ENOENT) {
- rc = fsmMknod(fsm->path, fsm->sb.st_mode, fsm->sb.st_rdev);
+ if (rc == RPMERR_ENOENT) {
+ rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev);
}
} else {
/* XXX Special case /dev/log, which shouldn't be packaged anyways */
- if (!IS_DEV_LOG(fsm->path))
- rc = CPIOERR_UNKNOWN_FILETYPE;
+ if (!IS_DEV_LOG(fpath))
+ rc = RPMERR_UNKNOWN_FILETYPE;
}
- if (li != NULL) {
- li->createdPath = li->linkIndex;
- rc = fsmMakeLinks(fsm, li);
- }
- }
+ /* Set permissions, timestamps etc for non-hardlink entries */
+ if (!rc && setmeta) {
+ rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps);
+ }
+ } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
+ /* we skip the hard linked file containing the content */
+ /* write the content to the first used instead */
+ char *fn = rpmfilesFN(files, firsthardlink);
+ rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm);
+ wfd_close(&firstlinkfile);
+ firsthardlink = -1;
+ free(fn);
+ }
if (rc) {
- if (!fsm->postpone) {
+ if (!skip) {
/* XXX only erase if temp fn w suffix is in use */
- if (fsm->suffix) {
- if (S_ISDIR(st->st_mode)) {
- (void) fsmRmdir(fsm->path);
- } else {
- (void) fsmUnlink(fsm->path, fsm->mapFlags);
- }
+ if (suffix && (action != FA_TOUCH)) {
+ (void) fsmRemove(fpath, sb.st_mode);
}
errno = saveerrno;
- if (fsm->failedFile && *fsm->failedFile == NULL)
- *fsm->failedFile = xstrdup(fsm->path);
}
+ } else {
+ /* Notify on success. */
+ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
- break;
- }
+ if (!skip) {
+ /* Backup file if needed. Directories are handled earlier */
+ if (suffix)
+ rc = fsmBackup(fi, action);
- /* Notify on success. */
- rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmcpioTell(archive));
+ if (!rc)
+ rc = fsmCommit(&fpath, fi, action, suffix, plugins);
+ }
+ }
- if (!fsm->postpone) {
- rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
- ? fsmCommitLinks(fsm) : fsmCommit(fsm, fsm->ix));
- }
- if (rc) {
- break;
- }
+ if (rc)
+ *failedFile = xstrdup(fpath);
+
+ /* Run fsm file post hook for all plugins */
+ rpmpluginsCallFsmFilePost(plugins, fi, fpath,
+ sb.st_mode, action, rc);
+ fpath = _free(fpath);
}
- if (!rc)
- rc = checkHardLinks(fsm);
+ rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ));
+ rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
+
+exit:
/* No need to bother with close errors on read */
- rpmcpioFree(archive);
- fsmFree(fsm);
+ rpmfiArchiveClose(fi);
+ rpmfiFree(fi);
+ Fclose(payload);
+ free(tid);
+ free(fpath);
return rc;
}
-int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi,
+int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
rpmpsm psm, char ** failedFile)
{
+ rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK);
rpmfs fs = rpmteGetFileStates(te);
- FSM_t fsm = fsmNew(FSM_PKGERASE, fs, fi, failedFile);
+ rpmPlugins plugins = rpmtsPlugins(ts);
+ struct stat sb;
int rc = 0;
+ char *fpath = NULL;
- if (!rpmteIsSource(te))
- fsm->mapFlags |= CPIO_SBIT_CHECK;
+ while (!rc && rpmfiNext(fi) >= 0) {
+ rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi));
+ fpath = fsmFsPath(fi, NULL);
+ rc = fsmStat(fpath, 1, &sb);
- while (!rc) {
- /* Clean fsm, free'ing memory. */
- fsmReset(fsm);
-
- /* Identify mapping index. */
- fsm->ix = mapNextIterator(fsm->iter);
+ fsmDebug(fpath, action, &sb);
- /* Exit on end-of-payload. */
- if (fsm->ix < 0)
- break;
+ /* Run fsm file pre hook for all plugins */
+ rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
+ sb.st_mode, action);
- rc = fsmInit(fsm);
-
- if (!fsm->postpone)
- rc = fsmBackup(fsm);
+ if (!XFA_SKIPPING(action))
+ rc = fsmBackup(fi, action);
/* Remove erased files. */
- if (!fsm->postpone && fsm->action == FA_ERASE) {
- int missingok = (fsm->fflags & (RPMFILE_MISSINGOK | RPMFILE_GHOST));
+ if (action == FA_ERASE) {
+ int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST));
- if (S_ISDIR(fsm->sb.st_mode)) {
- rc = fsmRmdir(fsm->path);
- } else {
- rc = fsmUnlink(fsm->path, fsm->mapFlags);
- }
+ rc = fsmRemove(fpath, sb.st_mode);
/*
* Missing %ghost or %missingok entries are not errors.
@@ -1849,7 +1077,7 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi,
* and complaining about job already done seems like kinderkarten
* level "But it was MY turn!" whining...
*/
- if (rc == CPIOERR_ENOENT && missingok) {
+ if (rc == RPMERR_ENOENT && missingok) {
rc = 0;
}
@@ -1858,112 +1086,41 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi,
* to track at least some of the expected failures though,
* such as when we knowingly left config file backups etc behind.
*/
- if (rc == CPIOERR_ENOTEMPTY) {
+ if (rc == RPMERR_ENOTEMPTY) {
rc = 0;
}
if (rc) {
int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;
rpmlog(lvl, _("%s %s: remove failed: %s\n"),
- S_ISDIR(fsm->sb.st_mode) ? _("directory") : _("file"),
- fsm->path, strerror(errno));
+ S_ISDIR(sb.st_mode) ? _("directory") : _("file"),
+ fpath, strerror(errno));
}
}
+
+ /* Run fsm file post hook for all plugins */
+ rpmpluginsCallFsmFilePost(plugins, fi, fpath,
+ sb.st_mode, action, rc);
+
/* XXX Failure to remove is not (yet) cause for failure. */
if (!strict_erasures) rc = 0;
- if (rc) break;
+ if (rc)
+ *failedFile = xstrdup(fpath);
- /* Notify on success. */
- /* On erase we're iterating backwards, fixup for progress */
- rpm_loff_t amount = (fsm->ix >= 0) ?
- rpmfiFC(fsmGetFi(fsm)) - fsm->ix : 0;
- rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount);
+ if (rc == 0) {
+ /* Notify on success. */
+ /* On erase we're iterating backwards, fixup for progress */
+ rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi);
+ rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount);
+ }
+ fpath = _free(fpath);
}
- fsmFree(fsm);
+ free(fpath);
+ rpmfiFree(fi);
return rc;
}
-int rpmPackageFilesArchive(rpmfi fi, int isSrc, FD_t cfd,
- rpm_loff_t * archiveSize, char ** failedFile)
-{
- rpmfs fs = rpmfsNew(rpmfiFC(fi), 0);;
- FSM_t fsm = fsmNew(FSM_PKGBUILD, fs, fi, failedFile);;
- rpmcpio_t archive = rpmcpioOpen(cfd, O_WRONLY);
- int rc = 0;
-
- fsm->mapFlags |= CPIO_MAP_TYPE;
- if (isSrc)
- fsm->mapFlags |= CPIO_FOLLOW_SYMLINKS;
-
- if (archive == NULL) {
- rc = CPIOERR_INTERNAL;
- } else {
- int ghost, i, fc = rpmfiFC(fi);
-
- /* XXX Is this actually still needed? */
- for (i = 0; i < fc; i++) {
- ghost = (rpmfiFFlagsIndex(fi, i) & RPMFILE_GHOST);
- rpmfsSetAction(fs, i, ghost ? FA_SKIP : FA_COPYOUT);
- }
- }
-
- while (!rc) {
- fsmReset(fsm);
-
- /* Identify mapping index. */
- fsm->ix = mapNextIterator(fsm->iter);
-
- /* Exit on end-of-payload. */
- if (fsm->ix < 0)
- break;
-
- rc = fsmInit(fsm);
-
- /* Exit on error. */
- if (rc) {
- fsm->postpone = 1;
- break;
- }
-
- if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)
- fsm->postpone = saveHardLink(fsm, NULL);
-
- if (fsm->postpone || fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
- continue;
- /* Hardlinks are handled later */
- if (!(S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)) {
- /* Copy file into archive. */
- rc = writeFile(fsm, 1, archive, fsm->ix);
- }
-
- if (rc) {
- if (!fsm->postpone) {
- if (fsm->failedFile && *fsm->failedFile == NULL)
- *fsm->failedFile = xstrdup(fsm->path);
- }
-
- break;
- }
- }
-
- /* Flush partial sets of hard linked files. */
- if (!rc)
- rc = writeLinks(fsm, archive);
-
- /* Finish the payload stream */
- if (!rc)
- rc = rpmcpioClose(archive);
-
- if (archiveSize)
- *archiveSize = (rc == 0) ? rpmcpioTell(archive) : 0;
-
- rpmcpioFree(archive);
- rpmfsFree(fs);
- fsmFree(fsm);
-
- return rc;
-}
diff --git a/lib/fsm.h b/lib/fsm.h
index 7f1911406..7a75caf5a 100644
--- a/lib/fsm.h
+++ b/lib/fsm.h
@@ -17,22 +17,21 @@ typedef struct rpmpsm_s * rpmpsm;
/**
* Execute a file actions for package
* @param ts transaction set
- * @param fi transaction element file info
- * @param cfd
+ * @param te transaction set element
+ * @param files transaction element file info
* @param psm owner psm (or NULL)
- * @retval archiveSize pointer to archive size
* @retval failedFile pointer to first file name that failed (malloced)
* @return 0 on success
*/
-int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi fi, FD_t cfd,
+int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rpmpsm psm, char ** failedFile);
-int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi,
+int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
rpmpsm psm, char ** failedFile);
-int rpmPackageFilesArchive(rpmfi fi, int isSrc, FD_t cfd,
- rpm_loff_t * archiveSize, char ** failedFile);
+RPM_GNUC_INTERNAL
+int rpmfiArchiveReadToFilePsm(rpmfi fi, FD_t fd, int nodigest, rpmpsm psm);
RPM_GNUC_INTERNAL
void rpmpsmNotify(rpmpsm psm, int what, rpm_loff_t amount);
diff --git a/lib/header.c b/lib/header.c
index 90079f307..0d50f0daf 100644
--- a/lib/header.c
+++ b/lib/header.c
@@ -11,6 +11,7 @@
#include "system.h"
#include <netdb.h>
#include <errno.h>
+#include <inttypes.h>
#include <rpm/rpmtypes.h>
#include <rpm/rpmstring.h>
#include "lib/header_internal.h"
@@ -69,8 +70,13 @@ static const int typeSizes[16] = {
0
};
+enum headerSorted_e {
+ HEADERSORT_NONE = 0, /* Not sorted */
+ HEADERSORT_OFFSET = 1, /* Sorted by offset (on-disk format) */
+ HEADERSORT_INDEX = 2, /* Sorted by index */
+};
+
enum headerFlags_e {
- HEADERFLAG_SORTED = (1 << 0), /*!< Are header entries sorted? */
HEADERFLAG_ALLOCATED = (1 << 1), /*!< Is 1st header region allocated? */
HEADERFLAG_LEGACY = (1 << 2), /*!< Header came from legacy source? */
HEADERFLAG_DEBUG = (1 << 3), /*!< Debug this header? */
@@ -79,6 +85,17 @@ enum headerFlags_e {
typedef rpmFlags headerFlags;
/** \ingroup header
+ * A single tag from a Header.
+ */
+typedef struct indexEntry_s * indexEntry;
+struct indexEntry_s {
+ struct entryInfo_s info; /*!< Description of tag data. */
+ rpm_data_t data; /*!< Location of tag data. */
+ int length; /*!< No. bytes of data. */
+ int rdlen; /*!< No. bytes of data in region. */
+};
+
+/** \ingroup header
* The Header data structure.
*/
struct headerToken_s {
@@ -88,13 +105,14 @@ struct headerToken_s {
int indexAlloced; /*!< Allocated size of tag array. */
unsigned int instance; /*!< Rpmdb instance (offset) */
headerFlags flags;
+ int sorted; /*!< Current sort method */
int nrefs; /*!< Reference count. */
};
/** \ingroup header
* Maximum no. of bytes permitted in a header.
*/
-static const size_t headerMaxbytes = (32*1024*1024);
+static const size_t headerMaxbytes = (256*1024*1024);
#define INDEX_MALLOC_SIZE 8
@@ -102,16 +120,62 @@ static const size_t headerMaxbytes = (32*1024*1024);
(((_e)->info.tag >= RPMTAG_HEADERIMAGE) && ((_e)->info.tag < RPMTAG_HEADERREGIONS))
#define ENTRY_IN_REGION(_e) ((_e)->info.offset < 0)
+#define REGION_TAG_TYPE RPM_BIN_TYPE
+#define REGION_TAG_COUNT sizeof(struct entryInfo_s)
+
+/**
+ * Sanity check on no. of tags.
+ * This check imposes a limit of 65K tags, more than enough.
+ */
+#define HEADER_TAGS_MAX 0x0000ffff
+#define hdrchkTags(_ntags) ((_ntags) & (~HEADER_TAGS_MAX))
+
+/**
+ * Sanity check on tag values.
+ * Catches out nasties like negative values and multiple regions.
+ **/
+#define hdrchkTag(_tag) ((_tag) < HEADER_I18NTABLE)
+
+/**
+ * Sanity check on type values.
+ */
+#define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
+
+/**
+ * Sanity check on data size and/or offset and/or count.
+ * This check imposes a limit of 256 MB -- file signatures
+ * may require a lot of space in the header.
+ */
+#define HEADER_DATA_MAX 0x0fffffff
+#define hdrchkData(_nbytes) ((_nbytes) & (~HEADER_DATA_MAX))
+
+/**
+ * Sanity check on data alignment for data type.
+ */
+#define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
+
+/**
+ * Sanity check on range of data offset.
+ */
+#define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
+
+static int dataLength(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t count,
+ int onDisk, rpm_constdata_t pend);
+
+#ifndef htonll
/* Convert a 64bit value to network byte order. */
RPM_GNUC_CONST
static uint64_t htonll(uint64_t n)
{
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
uint32_t *i = (uint32_t*)&n;
uint32_t b = i[0];
i[0] = htonl(i[1]);
i[1] = htonl(b);
+#endif
return n;
}
+#endif
Header headerLink(Header h)
{
@@ -156,11 +220,11 @@ Header headerFree(Header h)
return NULL;
}
-static Header headerCreate(void *blob, unsigned int pvlen, int32_t indexLen)
+static Header headerCreate(void *blob, int32_t indexLen)
{
Header h = xcalloc(1, sizeof(*h));
if (blob) {
- h->blob = (pvlen > 0) ? memcpy(xmalloc(pvlen), blob, pvlen) : blob;
+ h->blob = blob;
h->indexAlloced = indexLen + 1;
h->indexUsed = indexLen;
} else {
@@ -168,7 +232,7 @@ static Header headerCreate(void *blob, unsigned int pvlen, int32_t indexLen)
h->indexUsed = 0;
}
h->instance = 0;
- h->flags |= HEADERFLAG_SORTED;
+ h->sorted = HEADERSORT_NONE;
h->index = (h->indexAlloced
? xcalloc(h->indexAlloced, sizeof(*h->index))
@@ -180,34 +244,50 @@ static Header headerCreate(void *blob, unsigned int pvlen, int32_t indexLen)
Header headerNew(void)
{
- return headerCreate(NULL, 0, 0);
+ return headerCreate(NULL, 0);
}
-int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
+static rpmRC hdrblobVerifyInfo(hdrblob blob, char **emsg)
{
- entryInfo pe = (entryInfo) pev;
- entryInfo info = iv;
- int i;
+ struct entryInfo_s info;
+ int i, len = 0;
+ int32_t end = 0;
+ const char *ds = (const char *) blob->dataStart;
+ int32_t il = (blob->regionTag) ? blob->il-1 : blob->il;
+ entryInfo pe = (blob->regionTag) ? blob->pe+1 : blob->pe;
for (i = 0; i < il; i++) {
- info->tag = ntohl(pe[i].tag);
- info->type = ntohl(pe[i].type);
- info->offset = ntohl(pe[i].offset);
- if (negate)
- info->offset = -info->offset;
- info->count = ntohl(pe[i].count);
-
- if (hdrchkType(info->type))
- return i;
- if (hdrchkAlign(info->type, info->offset))
- return i;
- if (hdrchkRange(dl, info->offset))
- return i;
- if (hdrchkData(info->count))
- return i;
+ ei2h(&pe[i], &info);
+
+ /* Previous data must not overlap */
+ if (end > info.offset)
+ goto err;
+
+ if (hdrchkTag(info.tag))
+ goto err;
+ if (hdrchkType(info.type))
+ goto err;
+ if (hdrchkAlign(info.type, info.offset))
+ goto err;
+ if (hdrchkRange(blob->dl, info.offset))
+ goto err;
+
+ /* Verify the data actually fits */
+ len = dataLength(info.type, ds + info.offset,
+ info.count, 1, ds + blob->dl);
+ end = info.offset + len;
+ if (hdrchkRange(blob->dl, end) || len <= 0)
+ goto err;
+ }
+ return 0; /* Everything ok */
+err:
+ if (emsg) {
+ rasprintf(emsg,
+ _("tag[%d]: BAD, tag %d type %d offset %d count %d len %d"),
+ i, info.tag, info.type, info.offset, info.count, len);
}
- return -1;
+ return i + 1;
}
static int indexCmp(const void * avp, const void * bvp)
@@ -216,11 +296,11 @@ static int indexCmp(const void * avp, const void * bvp)
return (ap->info.tag - bp->info.tag);
}
-void headerSort(Header h)
+static void headerSort(Header h)
{
- if (!(h->flags & HEADERFLAG_SORTED)) {
+ if (h->sorted != HEADERSORT_INDEX) {
qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
- h->flags |= HEADERFLAG_SORTED;
+ h->sorted = HEADERSORT_INDEX;
}
}
@@ -239,11 +319,11 @@ static int offsetCmp(const void * avp, const void * bvp)
return rc;
}
-void headerUnsort(Header h)
+static void headerUnsort(Header h)
{
- if (h->flags & HEADERFLAG_SORTED) {
+ if (h->sorted != HEADERSORT_OFFSET) {
qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
- h->flags &= ~HEADERFLAG_SORTED;
+ h->sorted = HEADERSORT_OFFSET;
}
}
@@ -270,13 +350,8 @@ unsigned headerSizeof(Header h, int magicp)
headerSort(h);
- switch (magicp) {
- case HEADER_MAGIC_YES:
+ if (magicp == HEADER_MAGIC_YES)
size += sizeof(rpm_header_magic);
- break;
- case HEADER_MAGIC_NO:
- break;
- }
size += 2 * sizeof(int32_t); /* count of index entries */
@@ -284,7 +359,7 @@ unsigned headerSizeof(Header h, int magicp)
/* Regions go in as is ... */
if (ENTRY_IS_REGION(entry)) {
size += entry->length;
- /* XXX Legacy regions do not include the region tag and data. */
+ /* Reserve space for legacy region tag + data */
if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
size += sizeof(struct entryInfo_s) + entry->info.count;
continue;
@@ -313,6 +388,8 @@ static inline int strtaglen(const char *str, rpm_count_t c, const char *end)
const char *s;
if (end) {
+ if (str >= end)
+ return -1;
while ((s = memchr(start, '\0', end-start))) {
if (--c == 0 || s > end)
break;
@@ -407,10 +484,7 @@ static int regionSwab(indexEntry entry, int il, int dl,
for (; il > 0; il--, pe++) {
struct indexEntry_s ie;
- ie.info.tag = ntohl(pe->tag);
- ie.info.type = ntohl(pe->type);
- ie.info.count = ntohl(pe->count);
- ie.info.offset = ntohl(pe->offset);
+ ei2h(pe, &ie.info);
if (hdrchkType(ie.info.type))
return -1;
@@ -507,7 +581,7 @@ void * headerExport(Header h, unsigned int *bsize)
il += ril;
dl += entry->rdlen + entry->info.count;
- /* XXX Legacy regions do not include the region tag and data. */
+ /* Reserve space for legacy region tag */
if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
il += 1;
@@ -580,7 +654,7 @@ void * headerExport(Header h, unsigned int *bsize)
src = (char *)entry->data;
rdlen = entry->rdlen;
- /* XXX Legacy regions do not include the region tag and data. */
+ /* Legacy headers don't have regions originally, create one */
if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
int32_t stei[4];
@@ -720,7 +794,8 @@ indexEntry findEntry(Header h, rpmTagVal tag, rpm_tagtype_t type)
struct indexEntry_s key;
if (h == NULL) return NULL;
- if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
+ if (h->sorted != HEADERSORT_INDEX)
+ headerSort(h);
key.info.tag = tag;
@@ -750,7 +825,7 @@ int headerDel(Header h, rpmTagVal tag)
entry = findEntry(h, tag, RPM_NULL_TYPE);
if (!entry) return 1;
- /* Make sure entry points to the first occurence of this tag. */
+ /* Make sure entry points to the first occurrence of this tag. */
while (entry > h->index && (entry - 1)->info.tag == tag)
entry--;
@@ -778,92 +853,46 @@ int headerDel(Header h, rpmTagVal tag)
return 0;
}
-Header headerImport(void * blob, unsigned int bsize, headerImportFlags flags)
+rpmRC hdrblobImport(hdrblob blob, int fast, Header *hdrp, char **emsg)
{
- const int32_t * ei = (int32_t *) blob;
- int32_t il = ntohl(ei[0]); /* index length */
- int32_t dl = ntohl(ei[1]); /* data length */
- unsigned int pvlen = sizeof(il) + sizeof(dl) +
- (il * sizeof(struct entryInfo_s)) + dl;;
Header h = NULL;
- entryInfo pe;
- unsigned char * dataStart;
- unsigned char * dataEnd;
indexEntry entry;
int rdlen;
- int fast = (flags & HEADERIMPORT_FAST);
-
- /* Sanity checks on header intro. */
- if (bsize && bsize != pvlen)
- goto errxit;
- if (hdrchkTags(il) || hdrchkData(dl) || pvlen >= headerMaxbytes)
- goto errxit;
-
- h = headerCreate(blob, (flags & HEADERIMPORT_COPY) ? pvlen : 0, il);
- ei = h->blob; /* In case we had to copy */
- pe = (entryInfo) &ei[2];
- dataStart = (unsigned char *) (pe + il);
- dataEnd = dataStart + dl;
+ h = headerCreate(blob->ei, blob->il);
entry = h->index;
- if (!(htonl(pe->tag) < RPMTAG_HEADERI18NTABLE)) {
+ if (!(htonl(blob->pe->tag) < RPMTAG_HEADERI18NTABLE)) {
+ /* An original v3 header, create a legacy region entry for it */
h->flags |= HEADERFLAG_LEGACY;
entry->info.type = REGION_TAG_TYPE;
entry->info.tag = RPMTAG_HEADERIMAGE;
entry->info.count = REGION_TAG_COUNT;
- entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
-
- entry->data = pe;
- entry->length = pvlen - sizeof(il) - sizeof(dl);
- rdlen = regionSwab(entry+1, il, 0, pe,
- dataStart, dataEnd, entry->info.offset, fast);
- if (rdlen != dl)
+ entry->info.offset = ((unsigned char *)blob->pe - blob->dataStart); /* negative offset */
+
+ entry->data = blob->pe;
+ entry->length = blob->pvlen - sizeof(blob->il) - sizeof(blob->dl);
+ rdlen = regionSwab(entry+1, blob->il, 0, blob->pe,
+ blob->dataStart, blob->dataEnd,
+ entry->info.offset, fast);
+ if (rdlen != blob->dl)
goto errxit;
entry->rdlen = rdlen;
h->indexUsed++;
} else {
- int32_t rdl;
+ /* Either a v4 header or an "upgraded" v3 header with a legacy region */
int32_t ril;
h->flags &= ~HEADERFLAG_LEGACY;
-
- entry->info.type = htonl(pe->type);
- entry->info.count = htonl(pe->count);
- entry->info.tag = htonl(pe->tag);
-
- if (!ENTRY_IS_REGION(entry))
- goto errxit;
- if (entry->info.type != REGION_TAG_TYPE)
- goto errxit;
- if (entry->info.count != REGION_TAG_COUNT)
- goto errxit;
-
- { int off = ntohl(pe->offset);
-
- if (off) {
- size_t nb = REGION_TAG_COUNT;
- int32_t stei[nb];
- if (hdrchkRange(dl, (off + nb)))
- goto errxit;
- /* XXX Hmm, why the copy? */
- memcpy(&stei, dataStart + off, nb);
- rdl = -ntohl(stei[2]); /* negative offset */
- ril = rdl/sizeof(*pe);
- if (hdrchkTags(ril) || hdrchkData(rdl))
- goto errxit;
- } else {
- ril = il;
- rdl = (ril * sizeof(struct entryInfo_s));
- entry->info.tag = RPMTAG_HEADERIMAGE;
- }
- }
- entry->info.offset = -rdl; /* negative offset */
-
- entry->data = pe;
- entry->length = pvlen - sizeof(il) - sizeof(dl);
- rdlen = regionSwab(entry+1, ril-1, 0, pe+1,
- dataStart, dataEnd, entry->info.offset, fast);
+ ei2h(blob->pe, &entry->info);
+ ril = (entry->info.offset != 0) ? blob->ril : blob->il;
+
+ entry->info.offset = -(ril * sizeof(*blob->pe)); /* negative offset */
+ entry->data = blob->pe;
+ entry->length = blob->pvlen - sizeof(blob->il) - sizeof(blob->dl);
+ rdlen = regionSwab(entry+1, ril-1, 0, blob->pe+1,
+ blob->dataStart, blob->dataEnd,
+ entry->info.offset, fast);
if (rdlen < 0)
goto errxit;
entry->rdlen = rdlen;
@@ -874,8 +903,8 @@ Header headerImport(void * blob, unsigned int bsize, headerImportFlags flags)
int rid = entry->info.offset+1;
/* Load dribble entries from region. */
- rdlen = regionSwab(newEntry, ne, rdlen, pe+ril,
- dataStart, dataEnd, rid, fast);
+ rdlen = regionSwab(newEntry, ne, rdlen, blob->pe+ril,
+ blob->dataStart, blob->dataEnd, rid, fast);
if (rdlen < 0)
goto errxit;
@@ -902,24 +931,29 @@ Header headerImport(void * blob, unsigned int bsize, headerImportFlags flags)
rdlen += REGION_TAG_COUNT;
- if (rdlen != dl)
+ if (rdlen != blob->dl)
goto errxit;
}
- h->flags &= ~HEADERFLAG_SORTED;
+ /* Force sorting, dribble lookups can cause early sort on partial header */
+ h->sorted = HEADERSORT_NONE;
headerSort(h);
h->flags |= HEADERFLAG_ALLOCATED;
+ if (hdrp)
+ *hdrp = h;
- return h;
+ /* We own the memory now, avoid double-frees */
+ blob->ei = NULL;
+
+ return RPMRC_OK;
errxit:
if (h) {
- if (flags & HEADERIMPORT_COPY)
- free(h->blob);
free(h->index);
free(h);
+ rasprintf(emsg, _("hdr load: BAD"));
}
- return NULL;
+ return RPMRC_FAIL;
}
Header headerReload(Header h, rpmTagVal tag)
@@ -956,54 +990,14 @@ Header headerCopyLoad(const void * uh)
Header headerRead(FD_t fd, int magicp)
{
- int32_t block[4];
- int32_t * ei = NULL;
- int32_t il;
- int32_t dl;
Header h = NULL;
- unsigned int len, blen;
-
- if (magicp == HEADER_MAGIC_YES) {
- int32_t magic;
-
- if (Freadall(fd, block, 4*sizeof(*block)) != 4*sizeof(*block))
- goto exit;
-
- magic = block[0];
+ struct hdrblob_s blob;
+ char *buf = NULL;
- if (memcmp(&magic, rpm_header_magic, sizeof(magic)))
- goto exit;
+ if (hdrblobRead(fd, magicp, 0, 0, &blob, &buf) == RPMRC_OK)
+ hdrblobImport(&blob, 0, &h, &buf);
- il = ntohl(block[2]);
- dl = ntohl(block[3]);
- } else {
- if (Freadall(fd, block, 2*sizeof(*block)) != 2*sizeof(*block))
- goto exit;
-
- il = ntohl(block[0]);
- dl = ntohl(block[1]);
- }
-
- blen = (il * sizeof(struct entryInfo_s)) + dl;
- len = sizeof(il) + sizeof(dl) + blen;
-
- /* Sanity checks on header intro. */
- if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
- goto exit;
-
- ei = xmalloc(len);
- ei[0] = htonl(il);
- ei[1] = htonl(dl);
-
- if (Freadall(fd, (char *)&ei[2], blen) != blen)
- goto exit;
-
- h = headerImport(ei, len, 0);
-
-exit:
- if (h == NULL && ei != NULL) {
- free(ei);
- }
+ free(buf);
return h;
}
@@ -1011,19 +1005,15 @@ int headerWrite(FD_t fd, Header h, int magicp)
{
ssize_t nb;
unsigned int length;
- void * uh;
+ void * uh = headerExport(h, &length);
- uh = headerExport(h, &length);
if (uh == NULL)
return 1;
- switch (magicp) {
- case HEADER_MAGIC_YES:
- nb = Fwrite(rpm_header_magic, sizeof(uint8_t), sizeof(rpm_header_magic), fd);
+
+ if (magicp == HEADER_MAGIC_YES) {
+ nb = Fwrite(rpm_header_magic, sizeof(rpm_header_magic), 1, fd);
if (nb != sizeof(rpm_header_magic))
goto exit;
- break;
- case HEADER_MAGIC_NO:
- break;
}
nb = Fwrite(uh, sizeof(char), length, fd);
@@ -1040,6 +1030,16 @@ int headerIsEntry(Header h, rpmTagVal tag)
}
+/* simple heuristic to find out if the header is from * a source rpm
+ * or not: source rpms contain at least the spec file and have all
+ * files in one directory with an empty name.
+ */
+int headerIsSourceHeuristic(Header h)
+{
+ indexEntry entry = findEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE);
+ return entry && entry->info.count == 1 && entry->data && !*(const char *)entry->data;
+}
+
/** \ingroup header
* Retrieve data from header entry.
* Relevant flags (others are ignored), if neither is set allocation
@@ -1050,7 +1050,6 @@ int headerIsEntry(Header h, rpmTagVal tag)
* @todo Permit retrieval of regions other than HEADER_IMUTABLE.
* @param entry header entry
* @param td tag data container
- * @param minMem string pointers refer to header memory?
* @param flags flags to control memory allocation
* @return 1 on success, otherwise error.
*/
@@ -1167,6 +1166,7 @@ static int copyTdEntry(const indexEntry entry, rpmtd td, headerGetFlags flags)
}
td->type = entry->info.type;
td->count = count;
+ td->size = entry->length;
if (td->data && entry->data != td->data) {
td->flags |= RPMTD_ALLOCED;
@@ -1311,18 +1311,10 @@ static int intGetTdEntry(Header h, rpmtd td, headerGetFlags flags)
return 0;
}
- if (flags & HEADERGET_RAW) {
+ if (entry->info.type == RPM_I18NSTRING_TYPE && !(flags & HEADERGET_RAW))
+ rc = copyI18NEntry(h, entry, td, flags);
+ else
rc = copyTdEntry(entry, td, flags);
- } else {
- switch (entry->info.type) {
- case RPM_I18NSTRING_TYPE:
- rc = copyI18NEntry(h, entry, td, flags);
- break;
- default:
- rc = copyTdEntry(entry, td, flags);
- break;
- }
- }
if (rc == 0)
td->flags |= RPMTD_INVALID;
@@ -1438,7 +1430,7 @@ static int intAddEntry(Header h, rpmtd td)
entry->length = length;
if (h->indexUsed > 0 && td->tag < h->index[h->indexUsed-1].info.tag)
- h->flags &= ~HEADERFLAG_SORTED;
+ h->sorted = HEADERSORT_NONE;
h->indexUsed++;
return 1;
@@ -1650,7 +1642,7 @@ int headerMod(Header h, rpmtd td)
if (data == NULL)
return 0;
- /* make sure entry points to the first occurence of this tag */
+ /* make sure entry points to the first occurrence of this tag */
while (entry > h->index && (entry - 1)->info.tag == td->tag)
entry--;
@@ -1773,3 +1765,277 @@ ssize_t Freadall(FD_t fd, void * buf, ssize_t size)
return total;
}
+static rpmRC hdrblobVerifyRegion(rpmTagVal regionTag, int exact_size,
+ hdrblob blob, char **buf)
+{
+ rpmRC rc = RPMRC_FAIL;
+ struct entryInfo_s trailer, einfo;
+ unsigned char * regionEnd = NULL;
+
+ /* Check that we have at least on tag */
+ if (blob->il < 1) {
+ rasprintf(buf, _("region: no tags"));
+ goto exit;
+ }
+
+ /* Convert the 1st tag element. */
+ ei2h(blob->pe, &einfo);
+
+ if (!regionTag && (einfo.tag == RPMTAG_HEADERSIGNATURES ||
+ einfo.tag == RPMTAG_HEADERIMMUTABLE ||
+ einfo.tag == RPMTAG_HEADERIMAGE)) {
+ regionTag = einfo.tag;
+ }
+
+ /* Is there an immutable header region tag? */
+ if (!(einfo.tag == regionTag)) {
+ rc = RPMRC_NOTFOUND;
+ goto exit;
+ }
+
+ /* Is the region tag sane? */
+ if (!(einfo.type == REGION_TAG_TYPE && einfo.count == REGION_TAG_COUNT)) {
+ rasprintf(buf,
+ _("region tag: BAD, tag %d type %d offset %d count %d"),
+ einfo.tag, einfo.type, einfo.offset, einfo.count);
+ goto exit;
+ }
+
+ /* Is the trailer within the data area? */
+ if (hdrchkRange(blob->dl, einfo.offset + REGION_TAG_COUNT)) {
+ rasprintf(buf,
+ _("region offset: BAD, tag %d type %d offset %d count %d"),
+ einfo.tag, einfo.type, einfo.offset, einfo.count);
+ goto exit;
+ }
+
+ /* Is there an immutable header region tag trailer? */
+ memset(&trailer, 0, sizeof(trailer));
+ regionEnd = blob->dataStart + einfo.offset;
+ (void) memcpy(&trailer, regionEnd, REGION_TAG_COUNT);
+ regionEnd += REGION_TAG_COUNT;
+ blob->rdl = regionEnd - blob->dataStart;
+
+ ei2h(&trailer, &einfo);
+ /* Trailer offset is negative and has a special meaning */
+ einfo.offset = -einfo.offset;
+ if (!(einfo.tag == regionTag &&
+ einfo.type == REGION_TAG_TYPE && einfo.count == REGION_TAG_COUNT))
+ {
+ rasprintf(buf,
+ _("region trailer: BAD, tag %d type %d offset %d count %d"),
+ einfo.tag, einfo.type, einfo.offset, einfo.count);
+ goto exit;
+ }
+
+ /* Does the region actually fit within the header? */
+ blob->ril = einfo.offset/sizeof(*blob->pe);
+ if ((einfo.offset % sizeof(*blob->pe)) || hdrchkRange(blob->il, blob->ril) ||
+ hdrchkRange(blob->dl, blob->rdl)) {
+ rasprintf(buf, _("region %d size: BAD, ril %d il %d rdl %d dl %d"),
+ regionTag, blob->ril, blob->il, blob->rdl, blob->dl);
+ goto exit;
+ }
+
+ /* In package files region size is expected to match header size. */
+ if (exact_size && !(blob->il == blob->ril && blob->dl == blob->rdl)) {
+ rasprintf(buf,
+ _("region %d: tag number mismatch il %d ril %d dl %d rdl %d\n"),
+ regionTag, blob->il, blob->ril, blob->dl, blob->rdl);
+ goto exit;
+ }
+
+ blob->regionTag = regionTag;
+ rc = RPMRC_OK;
+
+exit:
+ return rc;
+}
+
+
+static rpmRC hdrblobVerifyLengths(rpmTagVal regionTag, uint32_t il, uint32_t dl,
+ char **emsg) {
+ uint32_t il_max = HEADER_TAGS_MAX;
+ uint32_t dl_max = HEADER_DATA_MAX;
+ if (regionTag == RPMTAG_HEADERSIGNATURES) {
+ il_max = 32;
+ dl_max = 64 * 1024 * 1024;
+ }
+ if (hdrchkRange(il_max, il)) {
+ rasprintf(emsg, _("hdr tags: BAD, no. of tags(%" PRIu32 ") out of range"), il);
+ return RPMRC_FAIL;
+ }
+ if (hdrchkRange(dl_max, dl)) {
+ rasprintf(emsg, _("hdr data: BAD, no. of bytes(%" PRIu32 ") out of range"), dl);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg)
+{
+ int32_t block[4];
+ int32_t *bs = (magic != 0) ? &block[0] : &block[2];
+ int blen = (magic != 0) ? sizeof(block) : sizeof(block) / 2;
+ int32_t il;
+ int32_t dl;
+ int32_t * ei = NULL;
+ size_t uc;
+ size_t nb;
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ int xx;
+
+ memset(block, 0, sizeof(block));
+ if ((xx = Freadall(fd, bs, blen)) != blen) {
+ rasprintf(emsg,
+ _("hdr size(%d): BAD, read returned %d"), blen, xx);
+ goto exit;
+ }
+ if (magic && memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) {
+ rasprintf(emsg, _("hdr magic: BAD"));
+ goto exit;
+ }
+ il = ntohl(block[2]);
+ dl = ntohl(block[3]);
+ if (hdrblobVerifyLengths(regionTag, il, dl, emsg))
+ goto exit;
+
+ nb = (il * sizeof(struct entryInfo_s)) + dl;
+ uc = sizeof(il) + sizeof(dl) + nb;
+ ei = xmalloc(uc);
+ ei[0] = block[2];
+ ei[1] = block[3];
+ if ((xx = Freadall(fd, (char *)&ei[2], nb)) != nb) {
+ rasprintf(emsg, _("hdr blob(%zd): BAD, read returned %d"), nb, xx);
+ goto exit;
+ }
+
+ if (regionTag == RPMTAG_HEADERSIGNATURES) {
+ size_t sigSize = uc + sizeof(rpm_header_magic);
+ size_t pad = (8 - (sigSize % 8)) % 8;
+ size_t trc;
+ if (pad && (trc = Freadall(fd, block, pad)) != pad) {
+ rasprintf(emsg, _("sigh pad(%zd): BAD, read %zd bytes"), pad, trc);
+ goto exit;
+ }
+ }
+
+ rc = hdrblobInit(ei, uc, regionTag, exact_size, blob, emsg);
+
+exit:
+ if (rc != RPMRC_OK) {
+ free(ei);
+ blob->ei = NULL;
+ if (emsg && *emsg && regionTag == RPMTAG_HEADERSIGNATURES) {
+ /* rstrscat() cannot handle overlap even if it claims so */
+ char *tmp = rstrscat(NULL, _("signature "), *emsg, NULL);
+ free(*emsg);
+ *emsg = tmp;
+ }
+ }
+
+ return rc;
+}
+
+rpmRC hdrblobInit(const void *uh, size_t uc,
+ rpmTagVal regionTag, int exact_size,
+ struct hdrblob_s *blob, char **emsg)
+{
+ rpmRC rc = RPMRC_FAIL;
+ memset(blob, 0, sizeof(*blob));
+ if (uc && uc < 8) {
+ rasprintf(emsg, _("hdr length: BAD"));
+ goto exit;
+ }
+
+ blob->ei = (int32_t *) uh; /* discards const */
+ blob->il = ntohl((uint32_t)(blob->ei[0]));
+ blob->dl = ntohl((uint32_t)(blob->ei[1]));
+ if (hdrblobVerifyLengths(regionTag, blob->il, blob->dl, emsg) != RPMRC_OK)
+ goto exit;
+
+ blob->pe = (entryInfo) &(blob->ei[2]);
+ blob->pvlen = sizeof(blob->il) + sizeof(blob->dl) +
+ (blob->il * sizeof(*blob->pe)) + blob->dl;
+ blob->dataStart = (uint8_t *) (blob->pe + blob->il);
+ blob->dataEnd = blob->dataStart + blob->dl;
+
+ /* Is the blob the right size? */
+ if (blob->pvlen >= headerMaxbytes || (uc && blob->pvlen != uc)) {
+ rasprintf(emsg, _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)"),
+ blob->pvlen, blob->il, blob->dl);
+ goto exit;
+ }
+
+ if (hdrblobVerifyRegion(regionTag, exact_size, blob, emsg) == RPMRC_FAIL)
+ goto exit;
+
+ /* Sanity check the rest of the header structure. */
+ if (hdrblobVerifyInfo(blob, emsg))
+ goto exit;
+
+ rc = RPMRC_OK;
+
+exit:
+ return rc;
+}
+
+rpmRC hdrblobGet(hdrblob blob, uint32_t tag, rpmtd td)
+{
+ rpmRC rc = RPMRC_NOTFOUND;
+ struct indexEntry_s entry;
+ struct entryInfo_s einfo;
+ const struct entryInfo_s *pe = blob->pe;
+ uint32_t ntag = htonl(tag);
+ int tsize;
+
+ memset(&einfo, 0, sizeof(einfo));
+ rpmtdReset(td);
+
+ for (int i = 1; i < blob->il; i++, pe++) {
+ if (pe->tag != ntag)
+ continue;
+ ei2h(pe, &einfo);
+
+ /* We can only handle non-byteswappable data */
+ tsize = typeSizes[einfo.type];
+ if (tsize != 1 && tsize != -1)
+ return RPMRC_FAIL;
+
+ entry.info = einfo; /* struct assignment */
+ entry.data = blob->dataStart + einfo.offset;
+ entry.length = dataLength(einfo.type, blob->dataStart + einfo.offset,
+ einfo.count, 1, blob->dataEnd);
+ entry.rdlen = 0;
+ td->tag = einfo.tag;
+ rc = copyTdEntry(&entry, td, HEADERGET_MINMEM) ? RPMRC_OK : RPMRC_FAIL;
+ break;
+ }
+ return rc;
+}
+
+Header headerImport(void * blob, unsigned int bsize, headerImportFlags flags)
+{
+ Header h = NULL;
+ struct hdrblob_s hblob;
+ char *buf = NULL;
+ void * b = blob;
+
+ if (flags & HEADERIMPORT_COPY) {
+ if (bsize == 0 && hdrblobInit(b, 0, 0, 0, &hblob, &buf) == RPMRC_OK)
+ bsize = hblob.pvlen;
+ if (bsize == 0)
+ goto exit;
+ b = memcpy(xmalloc(bsize), b, bsize);
+ }
+
+ /* Sanity checks on header intro. */
+ if (hdrblobInit(b, bsize, 0, 0, &hblob, &buf) == RPMRC_OK)
+ hdrblobImport(&hblob, (flags & HEADERIMPORT_FAST), &h, &buf);
+
+exit:
+ if (h == NULL && b != blob)
+ free(b);
+ free(buf);
+
+ return h;
+}
diff --git a/lib/header.h b/lib/header.h
index ddaba4f68..a616deefc 100644
--- a/lib/header.h
+++ b/lib/header.h
@@ -55,18 +55,6 @@ Header headerFree( Header h);
Header headerLink(Header h);
/** \ingroup header
- * Sort tags in header.
- * @param h header
- */
-void headerSort(Header h);
-
-/** \ingroup header
- * Restore tags in header to original ordering.
- * @param h header
- */
-void headerUnsort(Header h);
-
-/** \ingroup header
* Return size of on-disk header representation in bytes.
* @param h header
* @param magicp include size of 8 bytes for (magic, 0)?
@@ -75,17 +63,6 @@ void headerUnsort(Header h);
unsigned int headerSizeof(Header h, int magicp);
/** \ingroup header
- * Perform simple sanity and range checks on header tag(s).
- * @param il no. of tags in header
- * @param dl no. of bytes in header data.
- * @param pev 1st element in tag array, big-endian
- * @param iv failing (or last) tag element, host-endian
- * @param negate negative offset expected?
- * @return -1 on success, otherwise failing tag element index
- */
-int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate);
-
-/** \ingroup header
* Convert header to on-disk representation.
* @deprecated Use headerExport() instead
* @param h header (with pointers)
@@ -245,9 +222,9 @@ int headerPut(Header h, rpmtd td, headerPutFlags flags);
* @return 1 on success, 0 on failure
*
*/
+int headerPutBin(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size);
int headerPutString(Header h, rpmTagVal tag, const char *val);
int headerPutStringArray(Header h, rpmTagVal tag, const char **val, rpm_count_t size);
-int headerPutBin(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size);
int headerPutChar(Header h, rpmTagVal tag, const char *val, rpm_count_t size);
int headerPutUint8(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size);
int headerPutUint16(Header h, rpmTagVal tag, const uint16_t *val, rpm_count_t size);
@@ -348,65 +325,6 @@ int headerNext(HeaderIterator hi, rpmtd td);
rpmTagVal headerNextTag(HeaderIterator hi);
/** \ingroup header
- * Return name, version, release strings from header.
- * @param h header
- * @retval *np name pointer (or NULL)
- * @retval *vp version pointer (or NULL)
- * @retval *rp release pointer (or NULL)
- * @return 0 always
- */
-RPM_GNUC_DEPRECATED
-int headerNVR(Header h,
- const char ** np,
- const char ** vp,
- const char ** rp);
-
-/** \ingroup header
- * Return name, epoch, version, release, arch strings from header.
- * @param h header
- * @retval *np name pointer (or NULL)
- * @retval *ep epoch pointer (or NULL)
- * @retval *vp version pointer (or NULL)
- * @retval *rp release pointer (or NULL)
- * @retval *ap arch pointer (or NULL)
- * @return 0 always
- */
-RPM_GNUC_DEPRECATED
-int headerNEVRA(Header h,
- const char ** np,
- uint32_t ** ep,
- const char ** vp,
- const char ** rp,
- const char ** ap);
-
-/** \ingroup header
- * Return (malloc'd) header name-version-release string.
- * @param h header
- * @retval np name tag value
- * @return name-version-release string
- */
-RPM_GNUC_DEPRECATED
-char * headerGetNEVR(Header h, const char ** np );
-
-/** \ingroup header
- * Return (malloc'd) header name-version-release.arch string.
- * @param h header
- * @retval np name tag value
- * @return name-version-release string
- */
-RPM_GNUC_DEPRECATED
-char * headerGetNEVRA(Header h, const char ** np );
-
-/* \ingroup header
- * Return (malloc'd) header (epoch:)version-release string.
- * @param h header
- * @retval np name tag value (or NULL)
- * @return (epoch:)version-release string
- */
-RPM_GNUC_DEPRECATED
-char * headerGetEVR(Header h, const char **np);
-
-/** \ingroup header
* Return any non-array tag from header, converted to string
* @param h header
* @param tag tag to retrieve
@@ -431,14 +349,6 @@ const char * headerGetString(Header h, rpmTagVal tag);
uint64_t headerGetNumber(Header h, rpmTagVal tag);
/** \ingroup header
- * Return header color.
- * @param h header
- * @return header color
- */
-RPM_GNUC_DEPRECATED
-rpm_color_t headerGetColor(Header h);
-
-/** \ingroup header
* Check if header is a source or binary package header
* @param h header
* @return 0 == binary, 1 == source
diff --git a/lib/header_internal.h b/lib/header_internal.h
index f51435fee..76b7ed5a7 100644
--- a/lib/header_internal.h
+++ b/lib/header_internal.h
@@ -6,6 +6,7 @@
*/
#include <rpm/header.h>
+#include <netinet/in.h>
/** \ingroup header
* Description of tag data.
@@ -18,51 +19,60 @@ struct entryInfo_s {
rpm_count_t count; /*!< Number of tag elements. */
};
-#define REGION_TAG_TYPE RPM_BIN_TYPE
-#define REGION_TAG_COUNT sizeof(struct entryInfo_s)
+typedef struct hdrblob_s * hdrblob;
+struct hdrblob_s {
+ int32_t *ei;
+ int32_t il;
+ int32_t dl;
+ entryInfo pe;
+ int32_t pvlen;
+ uint8_t *dataStart;
+ uint8_t *dataEnd;
-/** \ingroup header
- * A single tag from a Header.
- */
-typedef struct indexEntry_s * indexEntry;
-struct indexEntry_s {
- struct entryInfo_s info; /*!< Description of tag data. */
- rpm_data_t data; /*!< Location of tag data. */
- int length; /*!< No. bytes of data. */
- int rdlen; /*!< No. bytes of data in region. */
+ rpmTagVal regionTag;
+ int32_t ril;
+ int32_t rdl;
};
-/**
- * Sanity check on no. of tags.
- * This check imposes a limit of 65K tags, more than enough.
- */
-#define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
+#ifdef __cplusplus
+extern "C" {
+#endif
-/**
- * Sanity check on type values.
- */
-#define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
+/* convert entry info to host endianess */
+static inline void ei2h(const struct entryInfo_s *pe, struct entryInfo_s *info)
+{
+ info->tag = ntohl(pe->tag);
+ info->type = ntohl(pe->type);
+ info->offset = ntohl(pe->offset);
+ info->count = ntohl(pe->count);
+}
-/**
- * Sanity check on data size and/or offset and/or count.
- * This check imposes a limit of 16 MB, more than enough.
- */
-#define HEADER_DATA_MAX 0x00ffffff
-#define hdrchkData(_nbytes) ((_nbytes) & (~HEADER_DATA_MAX))
+static inline void ei2td(const struct entryInfo_s *info,
+ unsigned char * dataStart, size_t len,
+ struct rpmtd_s *td)
+{
+ td->tag = info->tag;
+ td->type = info->type;
+ td->count = info->count;
+ td->size = len;
+ td->data = dataStart + info->offset;
+ td->ix = -1;
+ td->flags = RPMTD_IMMUTABLE;
+}
-/**
- * Sanity check on data alignment for data type.
- */
-#define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
+RPM_GNUC_INTERNAL
+rpmRC hdrblobInit(const void *uh, size_t uc,
+ rpmTagVal regionTag, int exact_size,
+ struct hdrblob_s *blob, char **emsg);
-/**
- * Sanity check on range of data offset.
- */
-#define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
+RPM_GNUC_INTERNAL
+rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg);
-#ifdef __cplusplus
-extern "C" {
-#endif
+RPM_GNUC_INTERNAL
+rpmRC hdrblobImport(hdrblob blob, int fast, Header *hdrp, char **emsg);
+
+RPM_GNUC_INTERNAL
+rpmRC hdrblobGet(hdrblob blob, uint32_t tag, rpmtd td);
/** \ingroup header
* Set header instance (rpmdb record number)
@@ -75,6 +85,14 @@ void headerSetInstance(Header h, unsigned int instance);
/* Package IO helper to consolidate partial read and error handling */
RPM_GNUC_INTERNAL
ssize_t Freadall(FD_t fd, void * buf, ssize_t size);
+
+/* XXX here only temporarily */
+RPM_GNUC_INTERNAL
+rpmTagVal headerMergeLegacySigs(Header h, Header sigh, char **msg);
+RPM_GNUC_INTERNAL
+void applyRetrofits(Header h, int leadtype);
+RPM_GNUC_INTERNAL
+int headerIsSourceHeuristic(Header h);
#ifdef __cplusplus
}
#endif
diff --git a/lib/headerfmt.c b/lib/headerfmt.c
index a865ee7a8..fdb3aadb7 100644
--- a/lib/headerfmt.c
+++ b/lib/headerfmt.c
@@ -4,6 +4,7 @@
#include "system.h"
+#include <stdarg.h>
#include <rpm/header.h>
#include <rpm/rpmtag.h>
#include <rpm/rpmstring.h>
@@ -20,7 +21,7 @@
*/
typedef struct sprintfTag_s * sprintfTag;
struct sprintfTag_s {
- headerTagFormatFunction fmt;
+ headerFmt fmt;
rpmTagVal tag;
int justOne;
char * format;
@@ -217,6 +218,25 @@ static char * hsaReserve(headerSprintfArgs hsa, size_t need)
return hsa->val + hsa->vallen;
}
+RPM_GNUC_PRINTF(2, 3)
+static void hsaError(headerSprintfArgs hsa, const char *fmt, ...)
+{
+ /* Use thread local static buffer as headerFormat() errmsg arg is const */
+ static __thread char errbuf[BUFSIZ];
+
+ if (fmt == NULL) {
+ hsa->errmsg = NULL;
+ } else {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
+ va_end(ap);
+
+ hsa->errmsg = errbuf;
+ }
+}
+
/**
* Search tags for a name.
* @param hsa headerSprintf args
@@ -246,7 +266,7 @@ static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
/* Search extensions for specific format. */
if (stag->type != NULL)
- stag->fmt = rpmHeaderFormatFuncByName(stag->type);
+ stag->fmt = rpmHeaderFormatByName(stag->type);
return stag->fmt ? 0 : 1;
}
@@ -333,13 +353,13 @@ static int parseFormat(headerSprintfArgs hsa, char * str,
chptr = start;
while (*chptr && *chptr != '{' && *chptr != '%') {
if (!risdigit(*chptr) && *chptr != '-') {
- hsa->errmsg = _("invalid field width");
+ hsaError(hsa, _("invalid field width"));
goto errxit;
}
chptr++;
}
if (!*chptr || *chptr == '%') {
- hsa->errmsg = _("missing { after %");
+ hsaError(hsa, _("missing { after %%"));
goto errxit;
}
@@ -361,7 +381,7 @@ static int parseFormat(headerSprintfArgs hsa, char * str,
dst = next = start;
while (*next && *next != '}') next++;
if (!*next) {
- hsa->errmsg = _("missing } after %{");
+ hsaError(hsa, _("missing } after %%{"));
goto errxit;
}
*next++ = '\0';
@@ -372,7 +392,7 @@ static int parseFormat(headerSprintfArgs hsa, char * str,
if (*chptr != '\0') {
*chptr++ = '\0';
if (!*chptr) {
- hsa->errmsg = _("empty tag format");
+ hsaError(hsa, _("empty tag format"));
goto errxit;
}
token->u.tag.type = chptr;
@@ -383,14 +403,14 @@ static int parseFormat(headerSprintfArgs hsa, char * str,
}
if (!*start) {
- hsa->errmsg = _("empty tag name");
+ hsaError(hsa, _("empty tag name"));
goto errxit;
}
token->type = PTOK_TAG;
if (findTag(hsa, token, start)) {
- hsa->errmsg = _("unknown tag");
+ hsaError(hsa, _("unknown tag: \"%s\""), start);
goto errxit;
}
@@ -410,7 +430,7 @@ static int parseFormat(headerSprintfArgs hsa, char * str,
}
if (!start) {
- hsa->errmsg = _("] expected at end of array");
+ hsaError(hsa, _("] expected at end of array"));
goto errxit;
}
@@ -422,7 +442,7 @@ static int parseFormat(headerSprintfArgs hsa, char * str,
case ']':
if (state != PARSER_IN_ARRAY) {
- hsa->errmsg = _("unexpected ]");
+ hsaError(hsa, _("unexpected ]"));
goto errxit;
}
*start++ = '\0';
@@ -432,7 +452,7 @@ static int parseFormat(headerSprintfArgs hsa, char * str,
case '}':
if (state != PARSER_IN_EXPR) {
- hsa->errmsg = _("unexpected }");
+ hsaError(hsa, _("unexpected }"));
goto errxit;
}
*start++ = '\0';
@@ -483,19 +503,19 @@ static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
char * chptr;
char * end;
- hsa->errmsg = NULL;
+ hsaError(hsa, NULL);
chptr = str;
while (*chptr && *chptr != '?') chptr++;
if (*chptr != '?') {
- hsa->errmsg = _("? expected in expression");
+ hsaError(hsa, _("? expected in expression"));
return 1;
}
*chptr++ = '\0';;
if (*chptr != '{') {
- hsa->errmsg = _("{ expected after ? in expression");
+ hsaError(hsa, _("{ expected after ? in expression"));
return 1;
}
@@ -507,7 +527,7 @@ static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
/* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
if (!(end && *end)) {
- hsa->errmsg = _("} expected in expression");
+ hsaError(hsa, _("} expected in expression"));
token->u.cond.ifFormat =
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
return 1;
@@ -515,7 +535,7 @@ static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
chptr = end;
if (*chptr != ':' && *chptr != '|') {
- hsa->errmsg = _(": expected following ? subexpression");
+ hsaError(hsa, _(": expected following ? subexpression"));
token->u.cond.ifFormat =
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
return 1;
@@ -533,7 +553,7 @@ static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
chptr++;
if (*chptr != '{') {
- hsa->errmsg = _("{ expected after : in expression");
+ hsaError(hsa, _("{ expected after : in expression"));
token->u.cond.ifFormat =
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
return 1;
@@ -547,7 +567,7 @@ static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
/* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
if (!(end && *end)) {
- hsa->errmsg = _("} expected in expression");
+ hsaError(hsa, _("} expected in expression"));
token->u.cond.ifFormat =
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
return 1;
@@ -555,7 +575,7 @@ static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
chptr = end;
if (*chptr != '|') {
- hsa->errmsg = _("| expected at end of expression");
+ hsaError(hsa, _("| expected at end of expression"));
token->u.cond.ifFormat =
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
token->u.cond.elseFormat =
@@ -624,9 +644,9 @@ static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
char * t, * te;
rpmtd td;
- if ((td = getData(hsa, tag->tag))) {
+ if ((td = getData(hsa, tag->tag)) && td->count > element) {
td->ix = element; /* Ick, use iterators instead */
- val = tag->fmt(td);
+ val = rpmHeaderFormatCall(tag->fmt, td);
} else {
val = xstrdup("(none)");
}
@@ -748,16 +768,10 @@ static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
found = 1;
count = rpmtdCount(td);
- if (numElements > 1 && count != numElements)
- switch (td->type) {
- default:
- hsa->errmsg =
- _("array iterator used with different sized arrays");
+ if (numElements > 0 && count != numElements) {
+ hsaError(hsa,
+ _("array iterator used with different sized arrays"));
return NULL;
- break;
- case RPM_BIN_TYPE:
- case RPM_STRING_TYPE:
- break;
}
if (count > numElements)
numElements = count;
@@ -821,13 +835,6 @@ static unsigned int tagId(rpmTagVal tag)
return tag;
}
-static rpmtd tagFree(rpmtd td)
-{
- rpmtdFreeData(td);
- rpmtdFree(td);
- return NULL;
-}
-
char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg)
{
struct headerSprintfArgs_s hsa;
@@ -845,7 +852,7 @@ char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg)
if (parseFormat(&hsa, hsa.fmt, &hsa.format, &hsa.numTokens, NULL, PARSER_BEGIN))
goto exit;
- hsa.cache = tagCacheCreate(128, tagId, tagCmp, NULL, tagFree);
+ hsa.cache = tagCacheCreate(128, tagId, tagCmp, NULL, rpmtdFree);
hsa.val = xstrdup("");
tag =
diff --git a/lib/headerutil.c b/lib/headerutil.c
index a9f1221eb..2003219b6 100644
--- a/lib/headerutil.c
+++ b/lib/headerutil.c
@@ -1,5 +1,5 @@
/** \ingroup rpmdb
- * \file lib/hdrNVR.c
+ * \file lib/headerutil.c
*/
#include "system.h"
@@ -7,63 +7,10 @@
#include <rpm/rpmtypes.h>
#include <rpm/header.h>
#include <rpm/rpmstring.h>
+#include <rpm/rpmds.h>
#include "debug.h"
-static int NEVRA(Header h, const char **np,
- uint32_t **ep, const char **vp, const char **rp,
- const char **ap)
-{
- if (np) *np = headerGetString(h, RPMTAG_NAME);
- if (vp) *vp = headerGetString(h, RPMTAG_VERSION);
- if (rp) *rp = headerGetString(h, RPMTAG_RELEASE);
- if (ap) *ap = headerGetString(h, RPMTAG_ARCH);
- if (ep) {
- struct rpmtd_s td;
- headerGet(h, RPMTAG_EPOCH, &td, HEADERGET_DEFAULT);
- *ep = rpmtdGetUint32(&td);
- }
- return 0;
-}
-
-int headerNVR(Header h, const char **np, const char **vp, const char **rp)
-{
- return NEVRA(h, np, NULL, vp, rp, NULL);
-}
-
-int headerNEVRA(Header h, const char **np,
- uint32_t **ep, const char **vp, const char **rp,
- const char **ap)
-{
- return NEVRA(h, np, ep, vp, rp, ap);
-}
-
-static char *getNEVRA(Header h, rpmTag tag, const char **np)
-{
- if (np) *np = headerGetString(h, RPMTAG_NAME);
- return headerGetAsString(h, tag);
-}
-
-char * headerGetNEVR(Header h, const char ** np)
-{
- return getNEVRA(h, RPMTAG_NEVR, np);
-}
-
-char * headerGetNEVRA(Header h, const char ** np)
-{
- return getNEVRA(h, RPMTAG_NEVRA, np);
-}
-
-char * headerGetEVR(Header h, const char ** np)
-{
- return getNEVRA(h, RPMTAG_EVR, np);
-}
-
-rpm_color_t headerGetColor(Header h)
-{
- return headerGetNumber(h, RPMTAG_HEADERCOLOR);
-}
-
int headerIsSource(Header h)
{
return (!headerIsEntry(h, RPMTAG_SOURCERPM));
@@ -84,7 +31,7 @@ Header headerCopy(Header h)
}
headerFreeIterator(hi);
- return headerReload(nh, RPMTAG_HEADERIMAGE);
+ return nh;
}
void headerCopyTags(Header headerFrom, Header headerTo,
@@ -243,3 +190,229 @@ int headerPutBin(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size)
return headerPutType(h, tag, RPM_BIN_TYPE, val, size);
}
+static int dncmp(const void * a, const void * b)
+{
+ const char *const * first = a;
+ const char *const * second = b;
+ return strcmp(*first, *second);
+}
+
+static void compressFilelist(Header h)
+{
+ struct rpmtd_s fileNames;
+ char ** dirNames;
+ const char ** baseNames;
+ uint32_t * dirIndexes;
+ rpm_count_t count, realCount = 0;
+ int i;
+ int dirIndex = -1;
+
+ /*
+ * This assumes the file list is already sorted, and begins with a
+ * single '/'. That assumption isn't critical, but it makes things go
+ * a bit faster.
+ */
+
+ if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
+ headerDel(h, RPMTAG_OLDFILENAMES);
+ return; /* Already converted. */
+ }
+
+ if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM))
+ return;
+ count = rpmtdCount(&fileNames);
+ if (count < 1)
+ return;
+
+ dirNames = xmalloc(sizeof(*dirNames) * count); /* worst case */
+ baseNames = xmalloc(sizeof(*dirNames) * count);
+ dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
+
+ /* HACK. Source RPM, so just do things differently */
+ { const char *fn = rpmtdGetString(&fileNames);
+ if (fn && *fn != '/') {
+ dirIndex = 0;
+ dirNames[dirIndex] = xstrdup("");
+ while ((i = rpmtdNext(&fileNames)) >= 0) {
+ dirIndexes[i] = dirIndex;
+ baseNames[i] = rpmtdGetString(&fileNames);
+ realCount++;
+ }
+ goto exit;
+ }
+ }
+
+ /*
+ * XXX EVIL HACK, FIXME:
+ * This modifies (and then restores) a const string from rpmtd
+ * through basename retrieved from strrchr() which silently
+ * casts away const on return.
+ */
+ while ((i = rpmtdNext(&fileNames)) >= 0) {
+ char ** needle;
+ char savechar;
+ char * baseName;
+ size_t len;
+ char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */
+
+ if (filename == NULL) /* XXX can't happen */
+ continue;
+ baseName = strrchr(filename, '/');
+ if (baseName == NULL) {
+ baseName = filename;
+ } else {
+ baseName += 1;
+ }
+ len = baseName - filename;
+ needle = dirNames;
+ savechar = *baseName;
+ *baseName = '\0';
+ if (dirIndex < 0 ||
+ (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
+ char *s = xmalloc(len + 1);
+ rstrlcpy(s, filename, len + 1);
+ dirIndexes[realCount] = ++dirIndex;
+ dirNames[dirIndex] = s;
+ } else
+ dirIndexes[realCount] = needle - dirNames;
+
+ *baseName = savechar;
+ baseNames[realCount] = baseName;
+ realCount++;
+ }
+
+exit:
+ if (count > 0) {
+ headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, realCount);
+ headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, realCount);
+ headerPutStringArray(h, RPMTAG_DIRNAMES,
+ (const char **) dirNames, dirIndex + 1);
+ }
+
+ rpmtdFreeData(&fileNames);
+ for (i = 0; i <= dirIndex; i++) {
+ free(dirNames[i]);
+ }
+ free(dirNames);
+ free(baseNames);
+ free(dirIndexes);
+
+ headerDel(h, RPMTAG_OLDFILENAMES);
+}
+
+static void expandFilelist(Header h)
+{
+ struct rpmtd_s filenames;
+
+ if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
+ (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
+ if (rpmtdCount(&filenames) < 1)
+ return;
+ rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
+ headerPut(h, &filenames, HEADERPUT_DEFAULT);
+ rpmtdFreeData(&filenames);
+ }
+
+ (void) headerDel(h, RPMTAG_DIRNAMES);
+ (void) headerDel(h, RPMTAG_BASENAMES);
+ (void) headerDel(h, RPMTAG_DIRINDEXES);
+}
+
+/*
+ * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
+ * Retrofit an explicit "Provides: name = epoch:version-release.
+ */
+static void providePackageNVR(Header h)
+{
+ const char *name = headerGetString(h, RPMTAG_NAME);
+ char *pEVR = headerGetAsString(h, RPMTAG_EVR);
+ rpmsenseFlags pFlags = RPMSENSE_EQUAL;
+ int bingo = 1;
+ struct rpmtd_s pnames;
+ rpmds hds, nvrds;
+
+ /* Generate provides for this package name-version-release. */
+ if (!(name && pEVR))
+ return;
+
+ /*
+ * Rpm prior to 3.0.3 does not have versioned provides.
+ * If no provides at all are available, we can just add.
+ */
+ if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
+ goto exit;
+ }
+
+ /*
+ * Otherwise, fill in entries on legacy packages.
+ */
+ if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
+ while (rpmtdNext(&pnames) >= 0) {
+ rpmsenseFlags fdummy = RPMSENSE_ANY;
+
+ headerPutString(h, RPMTAG_PROVIDEVERSION, "");
+ headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
+ }
+ goto exit;
+ }
+
+ /* see if we already have this provide */
+ hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
+ nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
+ if (rpmdsFind(hds, nvrds) >= 0) {
+ bingo = 0;
+ }
+ rpmdsFree(hds);
+ rpmdsFree(nvrds);
+
+
+exit:
+ if (bingo) {
+ headerPutString(h, RPMTAG_PROVIDENAME, name);
+ headerPutString(h, RPMTAG_PROVIDEVERSION, pEVR);
+ headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pFlags, 1);
+ }
+ rpmtdFreeData(&pnames);
+ free(pEVR);
+}
+
+static void legacyRetrofit(Header h)
+{
+ /*
+ * The file list was moved to a more compressed format which not
+ * only saves memory (nice), but gives fingerprinting a nice, fat
+ * speed boost (very nice). Go ahead and convert old headers to
+ * the new style (this is a noop for new headers).
+ */
+ compressFilelist(h);
+
+ /* Retrofit "Provide: name = EVR" for binary packages. */
+ if (!headerIsSource(h)) {
+ providePackageNVR(h);
+ }
+}
+
+int headerConvert(Header h, int op)
+{
+ int rc = 1;
+
+ if (h == NULL)
+ return 0;
+
+ switch (op) {
+ case HEADERCONV_EXPANDFILELIST:
+ expandFilelist(h);
+ break;
+ case HEADERCONV_COMPRESSFILELIST:
+ compressFilelist(h);
+ break;
+ case HEADERCONV_RETROFIT_V3:
+ legacyRetrofit(h);
+ break;
+ default:
+ rc = 0;
+ break;
+ }
+ return rc;
+};
+
diff --git a/lib/legacy.c b/lib/legacy.c
deleted file mode 100644
index 422c2b0e8..000000000
--- a/lib/legacy.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/**
- * \file lib/legacy.c
- */
-
-#include "system.h"
-
-#include <rpm/header.h>
-#include <rpm/rpmmacro.h>
-#include <rpm/rpmstring.h>
-#include <rpm/rpmfi.h>
-#include <rpm/rpmds.h>
-
-#include "debug.h"
-
-static int dncmp(const void * a, const void * b)
-{
- const char *const * first = a;
- const char *const * second = b;
- return strcmp(*first, *second);
-}
-
-static void compressFilelist(Header h)
-{
- struct rpmtd_s fileNames;
- char ** dirNames;
- const char ** baseNames;
- uint32_t * dirIndexes;
- rpm_count_t count;
- int i;
- int dirIndex = -1;
-
- /*
- * This assumes the file list is already sorted, and begins with a
- * single '/'. That assumption isn't critical, but it makes things go
- * a bit faster.
- */
-
- if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
- headerDel(h, RPMTAG_OLDFILENAMES);
- return; /* Already converted. */
- }
-
- if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM))
- return;
- count = rpmtdCount(&fileNames);
- if (count < 1)
- return;
-
- dirNames = xmalloc(sizeof(*dirNames) * count); /* worst case */
- baseNames = xmalloc(sizeof(*dirNames) * count);
- dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
-
- /* HACK. Source RPM, so just do things differently */
- { const char *fn = rpmtdGetString(&fileNames);
- if (fn && *fn != '/') {
- dirIndex = 0;
- dirNames[dirIndex] = xstrdup("");
- while ((i = rpmtdNext(&fileNames)) >= 0) {
- dirIndexes[i] = dirIndex;
- baseNames[i] = rpmtdGetString(&fileNames);
- }
- goto exit;
- }
- }
-
- /*
- * XXX EVIL HACK, FIXME:
- * This modifies (and then restores) a const string from rpmtd
- * through basename retrieved from strrchr() which silently
- * casts away const on return.
- */
- while ((i = rpmtdNext(&fileNames)) >= 0) {
- char ** needle;
- char savechar;
- char * baseName;
- size_t len;
- char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */
-
- if (filename == NULL) /* XXX can't happen */
- continue;
- baseName = strrchr(filename, '/') + 1;
- len = baseName - filename;
- needle = dirNames;
- savechar = *baseName;
- *baseName = '\0';
- if (dirIndex < 0 ||
- (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
- char *s = xmalloc(len + 1);
- rstrlcpy(s, filename, len + 1);
- dirIndexes[i] = ++dirIndex;
- dirNames[dirIndex] = s;
- } else
- dirIndexes[i] = needle - dirNames;
-
- *baseName = savechar;
- baseNames[i] = baseName;
- }
-
-exit:
- if (count > 0) {
- headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, count);
- headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, count);
- headerPutStringArray(h, RPMTAG_DIRNAMES,
- (const char **) dirNames, dirIndex + 1);
- }
-
- rpmtdFreeData(&fileNames);
- for (i = 0; i <= dirIndex; i++) {
- free(dirNames[i]);
- }
- free(dirNames);
- free(baseNames);
- free(dirIndexes);
-
- headerDel(h, RPMTAG_OLDFILENAMES);
-}
-
-static void expandFilelist(Header h)
-{
- struct rpmtd_s filenames;
-
- if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
- (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
- if (rpmtdCount(&filenames) < 1)
- return;
- rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
- headerPut(h, &filenames, HEADERPUT_DEFAULT);
- rpmtdFreeData(&filenames);
- }
-
- (void) headerDel(h, RPMTAG_DIRNAMES);
- (void) headerDel(h, RPMTAG_BASENAMES);
- (void) headerDel(h, RPMTAG_DIRINDEXES);
-}
-
-/*
- * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
- * Retrofit an explicit "Provides: name = epoch:version-release.
- */
-static void providePackageNVR(Header h)
-{
- const char *name = headerGetString(h, RPMTAG_NAME);
- char *pEVR = headerGetAsString(h, RPMTAG_EVR);
- rpmsenseFlags pFlags = RPMSENSE_EQUAL;
- int bingo = 1;
- struct rpmtd_s pnames;
- rpmds hds, nvrds;
-
- /* Generate provides for this package name-version-release. */
- if (!(name && pEVR))
- return;
-
- /*
- * Rpm prior to 3.0.3 does not have versioned provides.
- * If no provides at all are available, we can just add.
- */
- if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
- goto exit;
- }
-
- /*
- * Otherwise, fill in entries on legacy packages.
- */
- if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
- while (rpmtdNext(&pnames) >= 0) {
- rpmsenseFlags fdummy = RPMSENSE_ANY;
-
- headerPutString(h, RPMTAG_PROVIDEVERSION, "");
- headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
- }
- goto exit;
- }
-
- /* see if we already have this provide */
- hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
- nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
- if (rpmdsFind(hds, nvrds) >= 0) {
- bingo = 0;
- }
- rpmdsFree(hds);
- rpmdsFree(nvrds);
-
-
-exit:
- if (bingo) {
- headerPutString(h, RPMTAG_PROVIDENAME, name);
- headerPutString(h, RPMTAG_PROVIDEVERSION, pEVR);
- headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pFlags, 1);
- }
- rpmtdFreeData(&pnames);
- free(pEVR);
-}
-
-static void legacyRetrofit(Header h)
-{
- /*
- * The file list was moved to a more compressed format which not
- * only saves memory (nice), but gives fingerprinting a nice, fat
- * speed boost (very nice). Go ahead and convert old headers to
- * the new style (this is a noop for new headers).
- */
- compressFilelist(h);
-
- /* Retrofit "Provide: name = EVR" for binary packages. */
- if (!headerIsSource(h)) {
- providePackageNVR(h);
- }
-}
-
-int headerConvert(Header h, int op)
-{
- int rc = 1;
-
- if (h == NULL)
- return 0;
-
- switch (op) {
- case HEADERCONV_EXPANDFILELIST:
- expandFilelist(h);
- break;
- case HEADERCONV_COMPRESSFILELIST:
- compressFilelist(h);
- break;
- case HEADERCONV_RETROFIT_V3:
- legacyRetrofit(h);
- break;
- default:
- rc = 0;
- break;
- }
- return rc;
-};
-
-/*
- * Backwards compatibility wrappers for legacy interfaces.
- * Remove these some day...
- */
-#define _RPM_4_4_COMPAT
-#include <rpm/rpmlegacy.h>
-
-/* dumb macro to avoid 50 copies of this code while converting... */
-#define TDWRAP() \
- if (type) \
- *type = td.type; \
- if (p) \
- *p = td.data; \
- else \
- rpmtdFreeData(&td); \
- if (c) \
- *c = td.count
-
-int headerRemoveEntry(Header h, rpm_tag_t tag)
-{
- return headerDel(h, tag);
-}
-
-static void *_headerFreeData(rpm_data_t data, rpm_tagtype_t type)
-{
- if (data) {
- if (type == RPM_FORCEFREE_TYPE ||
- type == RPM_STRING_ARRAY_TYPE ||
- type == RPM_I18NSTRING_TYPE ||
- type == RPM_BIN_TYPE)
- free(data);
- }
- return NULL;
-}
-
-void * headerFreeData(rpm_data_t data, rpm_tagtype_t type)
-{
- return _headerFreeData(data, type);
-}
-
-void * headerFreeTag(Header h, rpm_data_t data, rpm_tagtype_t type)
-{
- return _headerFreeData(data, type);
-}
-
-static int headerGetWrap(Header h, rpm_tag_t tag,
- rpm_tagtype_t * type,
- rpm_data_t * p,
- rpm_count_t * c,
- headerGetFlags flags)
-{
- struct rpmtd_s td;
- int rc;
-
- rc = headerGet(h, tag, &td, flags);
- TDWRAP();
- return rc;
-}
-
-int headerGetEntry(Header h, rpm_tag_t tag,
- rpm_tagtype_t * type,
- rpm_data_t * p,
- rpm_count_t * c)
-{
- return headerGetWrap(h, tag, type, p, c, HEADERGET_DEFAULT);
-}
-
-int headerGetEntryMinMemory(Header h, rpm_tag_t tag,
- rpm_tagtype_t * type,
- rpm_data_t * p,
- rpm_count_t * c)
-{
- return headerGetWrap(h, tag, type, (rpm_data_t) p, c, HEADERGET_MINMEM);
-}
-
-/* XXX shut up compiler warning from missing prototype */
-int headerGetRawEntry(Header h, rpm_tag_t tag, rpm_tagtype_t * type, rpm_data_t * p,
- rpm_count_t * c);
-
-int headerGetRawEntry(Header h, rpm_tag_t tag, rpm_tagtype_t * type, rpm_data_t * p,
- rpm_count_t * c)
-{
- if (p == NULL)
- return headerIsEntry(h, tag);
-
- return headerGetWrap(h, tag, type, p, c, HEADERGET_RAW);
-}
-
-int headerNextIterator(HeaderIterator hi,
- rpm_tag_t * tag,
- rpm_tagtype_t * type,
- rpm_data_t * p,
- rpm_count_t * c)
-{
- struct rpmtd_s td;
- int rc;
-
- rc = headerNext(hi, &td);
- if (tag)
- *tag = td.tag;
- TDWRAP();
- return rc;
-}
-
-int headerModifyEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
- rpm_constdata_t p, rpm_count_t c)
-{
- struct rpmtd_s td = {
- .tag = tag,
- .type = type,
- .data = (void *) p,
- .count = c,
- };
- return headerMod(h, &td);
-}
-
-static int headerPutWrap(Header h, rpm_tag_t tag, rpm_tagtype_t type,
- rpm_constdata_t p, rpm_count_t c, headerPutFlags flags)
-{
- struct rpmtd_s td = {
- .tag = tag,
- .type = type,
- .data = (void *) p,
- .count = c,
- };
- return headerPut(h, &td, flags);
-}
-
-int headerAddOrAppendEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
- rpm_constdata_t p, rpm_count_t c)
-{
- return headerPutWrap(h, tag, type, p, c, HEADERPUT_APPEND);
-}
-
-int headerAppendEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
- rpm_constdata_t p, rpm_count_t c)
-{
- return headerPutWrap(h, tag, type, p, c, HEADERPUT_APPEND);
-}
-
-int headerAddEntry(Header h, rpm_tag_t tag, rpm_tagtype_t type,
- rpm_constdata_t p, rpm_count_t c)
-{
- return headerPutWrap(h, tag, type, p, c, HEADERPUT_DEFAULT);
-}
-#undef _RPM_4_4_COMPAT
diff --git a/lib/manifest.c b/lib/manifest.c
index 5d71f3f25..71c4c912c 100644
--- a/lib/manifest.c
+++ b/lib/manifest.c
@@ -94,8 +94,8 @@ rpmRC rpmReadPackageManifest(FD_t fd, int * argcPtr, char *** argvPtr)
s++;
if (*s == '\0') continue;
- /* Sanity checks: skip obviously binary lines and dash (for stdin) */
- if (*s < 32 || rstreq(s, "-")) {
+ /* Sanity checks: skip obviously binary lines */
+ if (*s < 32) {
s = NULL;
rpmrc = RPMRC_NOTFOUND;
goto exit;
@@ -117,6 +117,14 @@ rpmRC rpmReadPackageManifest(FD_t fd, int * argcPtr, char *** argvPtr)
rpmrc = (rpmGlob(s, &ac, &av) == 0 ? RPMRC_OK : RPMRC_FAIL);
if (rpmrc != RPMRC_OK) goto exit;
+ /* Sanity check: skip dash (for stdin) */
+ for (i = 0; i < ac; i++) {
+ if (rstreq(av[i], "-")) {
+ rpmrc = RPMRC_NOTFOUND;
+ goto exit;
+ }
+ }
+
rpmlog(RPMLOG_DEBUG, "adding %d args from manifest.\n", ac);
/* Count non-NULL args, keeping track of 1st arg after last NULL. */
diff --git a/lib/merge.c b/lib/merge.c
deleted file mode 100644
index 738ad7a68..000000000
--- a/lib/merge.c
+++ /dev/null
@@ -1,347 +0,0 @@
-#ifndef __APPLE__
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Peter McIlroy.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94";
-#endif /* LIBC_SCCS and not lint */
-
-/*
- * Hybrid exponential search/linear search merge sort with hybrid
- * natural/pairwise first pass. Requires about .3% more comparisons
- * for random data than LSMS with pairwise first pass alone.
- * It works for objects as small as two bytes.
- */
-
-#define NATURAL
-#define THRESHOLD 16 /* Best choice for natural merge cut-off. */
-
-/* #define NATURAL to get hybrid natural merge.
- * (The default is pairwise merging.)
- */
-
-#include "system.h"
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include "lib/rpmdb_internal.h" /* XXX for mergesort */
-
-#define ISIZE sizeof(int)
-#define PSIZE sizeof(unsigned char *)
-#define ICOPY_LIST(src, dst, last) \
- do \
- *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \
- while(src < last)
-#define ICOPY_ELT(src, dst, i) \
- do \
- *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \
- while (i -= ISIZE)
-
-#define CCOPY_LIST(src, dst, last) \
- do \
- *dst++ = *src++; \
- while (src < last)
-#define CCOPY_ELT(src, dst, i) \
- do \
- *dst++ = *src++; \
- while (i -= 1)
-
-/*
- * Find the next possible pointer head. (Trickery for forcing an array
- * to do double duty as a linked list when objects do not align with word
- * boundaries.
- */
-/* Assumption: PSIZE is a power of 2. */
-#define EVAL(p) (unsigned char **) \
- ((unsigned char *)0 + \
- (((unsigned char *)p + PSIZE - 1 - (unsigned char *) 0) & ~(PSIZE - 1)))
-
-#define swap(a, b) { \
- s = b; \
- i = size; \
- do { \
- tmp = *a; *a++ = *s; *s++ = tmp; \
- } while (--i); \
- a -= size; \
- }
-#define reverse(bot, top) { \
- s = top; \
- do { \
- i = size; \
- do { \
- tmp = *bot; *bot++ = *s; *s++ = tmp; \
- } while (--i); \
- s -= size2; \
- } while(bot < s); \
-}
-
-/*
- * This is to avoid out-of-bounds addresses in sorting the
- * last 4 elements.
- */
-static void
-insertionsort(unsigned char *a, size_t n, size_t size,
- int (*cmp) (const void *, const void *))
-{
- unsigned char *ai, *s, *t, *u, tmp;
- int i;
-
- for (ai = a+size; --n >= 1; ai += size)
- for (t = ai; t > a; t -= size) {
- u = t - size;
- if (cmp(u, t) <= 0)
- break;
- swap(u, t);
- }
-}
-
-/*
- * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of
- * increasing order, list2 in a corresponding linked list. Checks for runs
- * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL
- * is defined. Otherwise simple pairwise merging is used.)
- */
-static void
-setup(unsigned char *list1, unsigned char *list2,
- size_t n, size_t size, int (*cmp) (const void *, const void *))
-{
- int i, length, size2, tmp, sense;
- unsigned char *f1, *f2, *s, *l2, *last, *p2;
-
- size2 = size*2;
- if (n <= 5) {
- insertionsort(list1, n, size, cmp);
- *EVAL(list2) = (unsigned char*) list2 + n*size;
- return;
- }
- /*
- * Avoid running pointers out of bounds; limit n to evens
- * for simplicity.
- */
- i = 4 + (n & 1);
- insertionsort(list1 + (n - i) * size, i, size, cmp);
- last = list1 + size * (n - i);
- *EVAL(list2 + (last - list1)) = list2 + n * size;
-
-#ifdef NATURAL
- p2 = list2;
- f1 = list1;
- sense = (cmp(f1, f1 + size) > 0);
- for (; f1 < last; sense = !sense) {
- length = 2;
- /* Find pairs with same sense. */
- for (f2 = f1 + size2; f2 < last; f2 += size2) {
- if ((cmp(f2, f2+ size) > 0) != sense)
- break;
- length += 2;
- }
- if (length < THRESHOLD) { /* Pairwise merge */
- do {
- p2 = *EVAL(p2) = f1 + size2 - list1 + list2;
- if (sense > 0)
- swap (f1, f1 + size);
- } while ((f1 += size2) < f2);
- } else { /* Natural merge */
- l2 = f2;
- for (f2 = f1 + size2; f2 < l2; f2 += size2) {
- if ((cmp(f2-size, f2) > 0) != sense) {
- p2 = *EVAL(p2) = f2 - list1 + list2;
- if (sense > 0)
- reverse(f1, f2-size);
- f1 = f2;
- }
- }
- if (sense > 0)
- reverse (f1, f2-size);
- f1 = f2;
- if (f2 < last || cmp(f2 - size, f2) > 0)
- p2 = *EVAL(p2) = f2 - list1 + list2;
- else
- p2 = *EVAL(p2) = list2 + n*size;
- }
- }
-#else /* pairwise merge only. */
- for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
- p2 = *EVAL(p2) = p2 + size2;
- if (cmp (f1, f1 + size) > 0)
- swap(f1, f1 + size);
- }
-#endif /* NATURAL */
-}
-
-/*
- * Arguments are as for qsort.
- */
-int
-mergesort(void *base, size_t nmemb, size_t size,
- int (*cmp) (const void *, const void *))
-{
- register int i, sense;
- int big, iflag;
- register unsigned char *f1, *f2, *t, *b, *q, *l1, *l2;
- register unsigned char *tp2;
- unsigned char *list2;
- unsigned char *list1;
- unsigned char *p2, *p, *last, **p1;
-
- if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */
- errno = EINVAL;
- return (-1);
- }
-
- if (nmemb == 0)
- return (0);
-
- /*
- * XXX
- * Stupid subtraction for the Cray.
- */
- iflag = 0;
- if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE))
- iflag = 1;
-
- if ((list2 = malloc(nmemb * size + PSIZE)) == NULL)
- return (-1);
-
- list1 = base;
- setup(list1, list2, nmemb, size, cmp);
- last = list2 + nmemb * size;
- i = big = 0;
- while (*EVAL(list2) != last) {
- l2 = list1;
- p1 = EVAL(list1);
- for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) {
- p2 = *EVAL(p2);
- f1 = l2;
- f2 = l1 = list1 + (p2 - list2);
- if (p2 != last)
- p2 = *EVAL(p2);
- l2 = list1 + (p2 - list2);
- while (f1 < l1 && f2 < l2) {
- if ((*cmp)(f1, f2) <= 0) {
- q = f2;
- b = f1, t = l1;
- sense = -1;
- } else {
- q = f1;
- b = f2, t = l2;
- sense = 0;
- }
- if (!big) { /* here i = 0 */
- while ((b += size) < t && cmp(q, b) >sense)
- if (++i == 6) {
- big = 1;
- goto EXPONENTIAL;
- }
- } else {
-EXPONENTIAL: for (i = size; ; i <<= 1)
- if ((p = (b + i)) >= t) {
- if ((p = t - size) > b &&
- (*cmp)(q, p) <= sense)
- t = p;
- else
- b = p;
- break;
- } else if ((*cmp)(q, p) <= sense) {
- t = p;
- if (i == size)
- big = 0;
- goto FASTCASE;
- } else
- b = p;
- while (t > b+size) {
- i = (((t - b) / size) >> 1) * size;
- if ((*cmp)(q, p = b + i) <= sense)
- t = p;
- else
- b = p;
- }
- goto COPY;
-FASTCASE: while (i > size)
- if ((*cmp)(q,
- p = b + (i >>= 1)) <= sense)
- t = p;
- else
- b = p;
-COPY: b = t;
- }
- i = size;
- if (q == f1) {
- if (iflag) {
- ICOPY_LIST(f2, tp2, b);
- ICOPY_ELT(f1, tp2, i);
- } else {
- CCOPY_LIST(f2, tp2, b);
- CCOPY_ELT(f1, tp2, i);
- }
- } else {
- if (iflag) {
- ICOPY_LIST(f1, tp2, b);
- ICOPY_ELT(f2, tp2, i);
- } else {
- CCOPY_LIST(f1, tp2, b);
- CCOPY_ELT(f2, tp2, i);
- }
- }
- }
- if (f2 < l2) {
- if (iflag)
- ICOPY_LIST(f2, tp2, l2);
- else
- CCOPY_LIST(f2, tp2, l2);
- } else if (f1 < l1) {
- if (iflag)
- ICOPY_LIST(f1, tp2, l1);
- else
- CCOPY_LIST(f1, tp2, l1);
- }
- *p1 = l2;
- }
- tp2 = list1; /* swap list1, list2 */
- list1 = list2;
- list2 = tp2;
- last = list2 + nmemb*size;
- }
- if (base == list2) {
- memmove(list2, list1, nmemb*size);
- list2 = list1;
- }
- free(list2);
- return (0);
-}
-#else
-/* mergesort is implemented in System on Mac OS X */
-#endif /* __APPLE__ */
diff --git a/lib/misc.h b/lib/misc.h
index 15c9e3111..74e94a2e7 100644
--- a/lib/misc.h
+++ b/lib/misc.h
@@ -9,6 +9,9 @@
#include <string.h>
#include <rpm/rpmtypes.h>
#include <rpm/header.h> /* for headerGetFlags typedef, duh.. */
+#include "lib/rpmfs.h"
+
+typedef const struct headerFmt_s * headerFmt;
#ifdef __cplusplus
extern "C" {
@@ -24,18 +27,43 @@ char * rpmVerifyString(uint32_t verifyResult, const char *pad);
RPM_GNUC_INTERNAL
char * rpmFFlagsString(uint32_t fflags, const char *pad);
-typedef char * (*headerTagFormatFunction) (rpmtd td);
typedef int (*headerTagTagFunction) (Header h, rpmtd td, headerGetFlags hgflags);
RPM_GNUC_INTERNAL
headerTagTagFunction rpmHeaderTagFunc(rpmTagVal tag);
RPM_GNUC_INTERNAL
-headerTagFormatFunction rpmHeaderFormatFuncByName(const char *fmt);
+headerFmt rpmHeaderFormatByName(const char *fmt);
+
+RPM_GNUC_INTERNAL
+headerFmt rpmHeaderFormatByValue(rpmtdFormats fmt);
+
+RPM_GNUC_INTERNAL
+char * rpmHeaderFormatCall(headerFmt fmt, rpmtd td);
+
+RPM_GNUC_INTERNAL
+int headerFindSpec(Header h);
+
+/**
+ * Relocate files in header.
+ * @todo multilib file dispositions need to be checked.
+ * @param relocs relocations
+ * @param numRelocations number of relocations
+ * @param fs file state set
+ * @param h package header to relocate
+ */
+RPM_GNUC_INTERNAL
+void rpmRelocateFileList(rpmRelocation *relocs, int numRelocations, rpmfs fs, Header h);
RPM_GNUC_INTERNAL
-headerTagFormatFunction rpmHeaderFormatFuncByValue(rpmtdFormats fmt);
+int rpmRelocateSrpmFileList(Header h, const char *rootDir);
+RPM_GNUC_INTERNAL
+void rpmRelocationBuild(Header h, rpmRelocation *rawrelocs,
+ int *rnrelocs, rpmRelocation **rrelocs, uint8_t **rbadrelocs);
+
+RPM_GNUC_INTERNAL
+void rpmAtExit(void);
#ifdef __cplusplus
}
#endif
diff --git a/lib/order.c b/lib/order.c
index c0ef5470a..7a1dd10fd 100644
--- a/lib/order.c
+++ b/lib/order.c
@@ -67,7 +67,8 @@ static void rpmTSIFree(tsortInfo tsi)
static inline int addSingleRelation(rpmte p,
rpmte q,
- rpmsenseFlags dsflags)
+ rpmsenseFlags dsflags,
+ int reversed)
{
struct tsortInfo_s *tsi_p, *tsi_q;
relation rel;
@@ -80,9 +81,7 @@ static inline int addSingleRelation(rpmte p,
/* Erasures are reversed installs. */
if (teType == TR_REMOVED) {
- rpmte r = p;
- p = q;
- q = r;
+ reversed = ! reversed;
flags = isErasePreReq(dsflags);
} else {
flags = isInstallPreReq(dsflags);
@@ -94,32 +93,62 @@ static inline int addSingleRelation(rpmte p,
RPMSENSE_SCRIPT_PRE : RPMSENSE_SCRIPT_PREUN;
}
+ if (reversed) {
+ rpmte r = p;
+ p = q;
+ q = r;
+ }
+
tsi_p = rpmteTSI(p);
tsi_q = rpmteTSI(q);
/* if relation got already added just update the flags */
- if (tsi_q->tsi_relations && tsi_q->tsi_relations->rel_suc == tsi_p) {
+ if (!reversed &&
+ tsi_q->tsi_relations && tsi_q->tsi_relations->rel_suc == tsi_p) {
+ /* must be latest one added to q as we add all rels to p at once */
tsi_q->tsi_relations->rel_flags |= flags;
- tsi_p->tsi_forward_relations->rel_flags |= flags;
- return 0;
+ /* search entry in p */
+ for (struct relation_s * tsi = tsi_p->tsi_forward_relations;
+ tsi; tsi = tsi->rel_next) {
+ if (tsi->rel_suc == tsi_q) {
+ tsi->rel_flags |= flags;
+ return 0;
+ }
+ }
+ assert(0);
}
- /* Record next "q <- p" relation (i.e. "p" requires "q"). */
- if (p != q) {
- /* bump p predecessor count */
- tsi_p->tsi_count++;
+ /* if relation got already added just update the flags */
+ if (reversed && tsi_q->tsi_forward_relations &&
+ tsi_q->tsi_forward_relations->rel_suc == tsi_p) {
+ /* must be latest one added to q as we add all rels to p at once */
+ tsi_q->tsi_forward_relations->rel_flags |= flags;
+ /* search entry in p */
+ for (struct relation_s * tsi = tsi_p->tsi_relations;
+ tsi; tsi = tsi->rel_next) {
+ if (tsi->rel_suc == tsi_q) {
+ tsi->rel_flags |= flags;
+ return 0;
+ }
+ }
+ assert(0);
}
+ /* Record next "q <- p" relation (i.e. "p" requires "q"). */
+
+ /* bump p predecessor count */
+ tsi_p->tsi_count++;
+
rel = xcalloc(1, sizeof(*rel));
rel->rel_suc = tsi_p;
rel->rel_flags = flags;
rel->rel_next = tsi_q->tsi_relations;
tsi_q->tsi_relations = rel;
- if (p != q) {
- /* bump q successor count */
- tsi_q->tsi_qcnt++;
- }
+
+
+ /* bump q successor count */
+ tsi_q->tsi_qcnt++;
rel = xcalloc(1, sizeof(*rel));
rel->rel_suc = tsi_q;
@@ -134,6 +163,7 @@ static inline int addSingleRelation(rpmte p,
/**
* Record next "q <- p" relation (i.e. "p" requires "q").
* @param ts transaction set
+ * @param al packages list
* @param p predecessor (i.e. package that "Requires: q")
* @param requires relation
* @return 0 always
@@ -141,7 +171,8 @@ static inline int addSingleRelation(rpmte p,
static inline int addRelation(rpmts ts,
rpmal al,
rpmte p,
- rpmds requires)
+ rpmds requires,
+ int reversed)
{
rpmte q;
rpmsenseFlags dsflags;
@@ -152,47 +183,35 @@ static inline int addRelation(rpmts ts,
if (dsflags & (RPMSENSE_RPMLIB|RPMSENSE_CONFIG|RPMSENSE_PRETRANS|RPMSENSE_POSTTRANS))
return 0;
- q = rpmalSatisfiesDepend(al, requires);
+ if (rpmdsIsRich(requires)) {
+ rpmds ds1, ds2;
+ rpmrichOp op;
+ if (rpmdsParseRichDep(requires, &ds1, &ds2, &op, NULL) == RPMRC_OK) {
+ if (op != RPMRICHOP_ELSE)
+ addRelation(ts, al, p, ds1, reversed);
+ if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS) {
+ rpmds ds21, ds22;
+ rpmrichOp op2;
+ if (rpmdsParseRichDep(requires, &ds21, &ds22, &op2, NULL) == RPMRC_OK && op2 == RPMRICHOP_ELSE) {
+ addRelation(ts, al, p, ds22, reversed);
+ }
+ ds21 = rpmdsFree(ds21);
+ ds22 = rpmdsFree(ds22);
+ }
+ if (op == RPMRICHOP_AND || op == RPMRICHOP_OR)
+ addRelation(ts, al, p, ds2, reversed);
+ ds1 = rpmdsFree(ds1);
+ ds2 = rpmdsFree(ds2);
+ }
+ return 0;
+ }
+ q = rpmalSatisfiesDepend(al, p, requires);
/* Avoid deps outside this transaction and self dependencies */
if (q == NULL || q == p)
return 0;
- addSingleRelation(p, q, dsflags);
-
- return 0;
-}
-
-/*
- * Collections might have special ordering requirements. Notably
- * sepolicy collection requires having all the bits in the collection
- * close to each other. We try to ensure this by creating a strongly
- * connected component of such "grouped" collections, by introducing
- * an artificial relation loop across the all its members.
- */
-static int addCollRelations(rpmal al, rpmte p, ARGV_t *seenColls)
-{
- ARGV_const_t qcolls;
-
- for (qcolls = rpmteCollections(p); qcolls && *qcolls; qcolls++) {
- char * flags;
- if (argvSearch(*seenColls, *qcolls, NULL))
- continue;
-
- flags = rstrscat(NULL, "%{__collection_", *qcolls, "_flags}", NULL);
- if (rpmExpandNumeric(flags) & 0x1) {
- rpmte *tes = rpmalAllInCollection(al, *qcolls);
- for (rpmte *te = tes; te && *te; te++) {
- rpmte next = (*(te + 1) != NULL) ? *(te + 1) : *tes;
- addSingleRelation(*te, next, RPMSENSE_ANY);
- }
- _free(tes);
- }
- free(flags);
-
- argvAdd(seenColls, *qcolls);
- argvSort(*seenColls, NULL);
- }
+ addSingleRelation(p, q, dsflags, reversed);
return 0;
}
@@ -552,7 +571,6 @@ int rpmtsOrder(rpmts ts)
scc SCCs;
int nelem = rpmtsNElements(ts);
tsortInfo sortInfo = xcalloc(nelem, sizeof(struct tsortInfo_s));
- ARGV_t seenColls = NULL;
(void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
@@ -571,22 +589,43 @@ int rpmtsOrder(rpmts ts)
rpmal al = (rpmteType(p) == TR_REMOVED) ?
erasedPackages : tsmem->addedPackages;
rpmds requires = rpmdsInit(rpmteDS(p, RPMTAG_REQUIRENAME));
+ rpmds recommends = rpmdsInit(rpmteDS(p, RPMTAG_RECOMMENDNAME));
+ rpmds suggests = rpmdsInit(rpmteDS(p, RPMTAG_SUGGESTNAME));
+ rpmds supplements = rpmdsInit(rpmteDS(p, RPMTAG_SUPPLEMENTNAME));
+ rpmds enhances = rpmdsInit(rpmteDS(p, RPMTAG_ENHANCENAME));
rpmds order = rpmdsInit(rpmteDS(p, RPMTAG_ORDERNAME));
while (rpmdsNext(requires) >= 0) {
/* Record next "q <- p" relation (i.e. "p" requires "q"). */
- (void) addRelation(ts, al, p, requires);
+ (void) addRelation(ts, al, p, requires, 0);
+ }
+
+ while (rpmdsNext(recommends) >= 0) {
+ /* Record next "q <- p" relation (i.e. "p" recommends "q"). */
+ (void) addRelation(ts, al, p, recommends, 0);
+ }
+
+ while (rpmdsNext(suggests) >= 0) {
+ /* Record next "q <- p" relation (i.e. "p" suggests "q"). */
+ (void) addRelation(ts, al, p, suggests, 0);
}
while (rpmdsNext(order) >= 0) {
/* Record next "q <- p" ordering request */
- (void) addRelation(ts, al, p, order);
+ (void) addRelation(ts, al, p, order, 0);
}
- addCollRelations(al, p, &seenColls);
+ while (rpmdsNext(supplements) >= 0) {
+ /* Record next "p -> q" relation (i.e. "q" supplemented by "p"). */
+ (void) addRelation(ts, al, p, supplements, 1);
+ }
+
+ while (rpmdsNext(enhances) >= 0) {
+ /* Record next "p <- q" relation (i.e. "q" is enhanced by "p"). */
+ (void) addRelation(ts, al, p, enhances, 1);
+ }
}
- seenColls = argvFree(seenColls);
rpmtsiFree(pi);
newOrder = xcalloc(tsmem->orderCount, sizeof(*newOrder));
diff --git a/lib/package.c b/lib/package.c
index 157c96900..74cd9f479 100644
--- a/lib/package.c
+++ b/lib/package.c
@@ -5,6 +5,7 @@
#include "system.h"
#include <netinet/in.h>
+#include <pthread.h>
#include <rpm/rpmlib.h> /* XXX RPMSIGTAG, other sig stuff */
#include <rpm/rpmts.h>
@@ -13,116 +14,105 @@
#include <rpm/rpmkeyring.h>
#include "lib/rpmlead.h"
-#include "lib/signature.h"
-#include "rpmio/digest.h"
#include "rpmio/rpmio_internal.h" /* fd digest bits */
#include "lib/header_internal.h" /* XXX headerCheck */
+#include "lib/rpmvs.h"
#include "lib/rpmplugins.h" /* rpm plugins hooks */
#include "debug.h"
-static const unsigned int nkeyids_max = 256;
-static unsigned int nkeyids = 0;
-static unsigned int nextkeyid = 0;
-static unsigned int * keyids;
+struct taglate_s {
+ rpmTagVal stag;
+ rpmTagVal xtag;
+ rpm_count_t count;
+} const xlateTags[] = {
+ { RPMSIGTAG_SIZE, RPMTAG_SIGSIZE, 1 },
+ { RPMSIGTAG_PGP, RPMTAG_SIGPGP, 0 },
+ { RPMSIGTAG_MD5, RPMTAG_SIGMD5, 16 },
+ { RPMSIGTAG_GPG, RPMTAG_SIGGPG, 0 },
+ /* { RPMSIGTAG_PGP5, RPMTAG_SIGPGP5, 0 }, */ /* long obsolete, dont use */
+ { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1 },
+ { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1 },
+ { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1 },
+ { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0 },
+ { RPMSIGTAG_RSA, RPMTAG_RSAHEADER, 0 },
+ { RPMSIGTAG_LONGSIZE, RPMTAG_LONGSIGSIZE, 1 },
+ { RPMSIGTAG_LONGARCHIVESIZE, RPMTAG_LONGARCHIVESIZE, 1 },
+ { 0 }
+};
/** \ingroup header
* Translate and merge legacy signature tags into header.
* @param h header (dest)
* @param sigh signature header (src)
*/
-static void headerMergeLegacySigs(Header h, Header sigh)
+rpmTagVal headerMergeLegacySigs(Header h, Header sigh, char **msg)
{
- HeaderIterator hi;
+ const struct taglate_s *xl;
struct rpmtd_s td;
- hi = headerInitIterator(sigh);
- for (; headerNext(hi, &td); rpmtdFreeData(&td))
- {
- switch (td.tag) {
- /* XXX Translate legacy signature tag values. */
- case RPMSIGTAG_SIZE:
- td.tag = RPMTAG_SIGSIZE;
+ rpmtdReset(&td);
+ for (xl = xlateTags; xl->stag; xl++) {
+ /* There mustn't be one in the main header */
+ if (headerIsEntry(h, xl->xtag))
break;
- case RPMSIGTAG_PGP:
- td.tag = RPMTAG_SIGPGP;
- break;
- case RPMSIGTAG_MD5:
- td.tag = RPMTAG_SIGMD5;
- break;
- case RPMSIGTAG_GPG:
- td.tag = RPMTAG_SIGGPG;
- break;
- case RPMSIGTAG_PGP5:
- td.tag = RPMTAG_SIGPGP5;
- break;
- case RPMSIGTAG_PAYLOADSIZE:
- td.tag = RPMTAG_ARCHIVESIZE;
- break;
- case RPMSIGTAG_SHA1:
- case RPMSIGTAG_DSA:
- case RPMSIGTAG_RSA:
- default:
- if (!(td.tag >= HEADER_SIGBASE && td.tag < HEADER_TAGBASE))
- continue;
- break;
- }
- if (td.data == NULL) continue; /* XXX can't happen */
- if (!headerIsEntry(h, td.tag)) {
- if (hdrchkType(td.type))
- continue;
- if (td.count < 0 || hdrchkData(td.count))
- continue;
- switch(td.type) {
- case RPM_NULL_TYPE:
- continue;
+ if (headerGet(sigh, xl->stag, &td, HEADERGET_RAW|HEADERGET_MINMEM)) {
+ /* Translate legacy tags */
+ if (xl->stag != xl->xtag)
+ td.tag = xl->xtag;
+ /* Ensure type and tag size match expectations */
+ if (td.type != rpmTagGetTagType(td.tag))
break;
- case RPM_CHAR_TYPE:
- case RPM_INT8_TYPE:
- case RPM_INT16_TYPE:
- case RPM_INT32_TYPE:
- case RPM_INT64_TYPE:
- if (td.count != 1)
- continue;
+ if (td.count < 1 || td.count > 16*1024*1024)
break;
- case RPM_STRING_TYPE:
- case RPM_BIN_TYPE:
- if (td.count >= 16*1024)
- continue;
+ if (xl->count && td.count != xl->count)
break;
- case RPM_STRING_ARRAY_TYPE:
- case RPM_I18NSTRING_TYPE:
- continue;
+ if (!headerPut(h, &td, HEADERPUT_DEFAULT))
break;
- }
- (void) headerPut(h, &td, HEADERPUT_DEFAULT);
+ rpmtdFreeData(&td);
}
}
- headerFreeIterator(hi);
+ rpmtdFreeData(&td);
+
+ if (xl->stag) {
+ rasprintf(msg, "invalid signature tag %s (%d)",
+ rpmTagGetName(xl->xtag), xl->xtag);
+ }
+
+ return xl->stag;
}
/**
* Remember current key id.
- * @param dig OpenPGP packet containter
+ * XXX: This s*** needs to die. Hook it into keyring or sumthin...
+ * @param keyid signature keyid
* @return 0 if new keyid, otherwise 1
*/
-static int stashKeyid(pgpDigParams sigp)
+static int stashKeyid(unsigned int keyid)
{
- unsigned int keyid;
+ static pthread_mutex_t keyid_lock = PTHREAD_MUTEX_INITIALIZER;
+ static const unsigned int nkeyids_max = 256;
+ static unsigned int nkeyids = 0;
+ static unsigned int nextkeyid = 0;
+ static unsigned int * keyids;
+
int i;
+ int seen = 0;
- if (sigp == NULL)
+ if (keyid == 0)
return 0;
- keyid = pgpGrab(sigp->signid+4, 4);
- if (keyid == 0)
+ /* Just pretend we didn't see the keyid if we fail to lock */
+ if (pthread_mutex_lock(&keyid_lock))
return 0;
if (keyids != NULL)
for (i = 0; i < nkeyids; i++) {
- if (keyid == keyids[i])
- return 1;
+ if (keyid == keyids[i]) {
+ seen = 1;
+ goto exit;
+ }
}
if (nkeyids < nkeyids_max) {
@@ -134,346 +124,86 @@ static int stashKeyid(pgpDigParams sigp)
nextkeyid++;
nextkeyid %= nkeyids_max;
- return 0;
+exit:
+ pthread_mutex_unlock(&keyid_lock);
+ return seen;
}
-int parsePGPSig(rpmtd sigtd, const char *type, const char *fn,
- pgpDigParams *sig)
+static rpmRC handleHdrVS(struct rpmsinfo_s *sinfo, rpmRC rc, const char *msg, void *cbdata)
{
- int rc = pgpPrtParams(sigtd->data, sigtd->count, PGPTAG_SIGNATURE, sig);
-
- if (rc != 0) {
- if (type && fn) {
- rpmlog(RPMLOG_ERR,
- _("skipping %s %s with unverifiable signature\n"), type, fn);
- } else if (type) {
- rpmlog(RPMLOG_ERR,
- _("skipping %s with unverifiable signature\n"), type);
- }
+ char **buf = cbdata;
+ if (buf) {
+ char *vsmsg = rpmsinfoMsg(sinfo, rc, msg);
+ *buf = rstrscat(buf, "\n", vsmsg, NULL);
+ free(vsmsg);
}
return rc;
}
-/*
- * Argument monster to verify header-only signature/digest if there is
- * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check.
- */
-static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags,
- int il, int dl, int ril, int rdl,
- entryInfo pe, unsigned char * dataStart,
- char **buf)
+static void updateHdrDigests(rpmDigestBundle bundle, struct hdrblob_s *blob)
{
- size_t siglen = 0;
- rpmRC rc = RPMRC_FAIL;
- pgpDigParams sig = NULL;
- struct rpmtd_s sigtd;
- struct entryInfo_s info, einfo;
- unsigned int hashalgo = 0;
-
- rpmtdReset(&sigtd);
- memset(&info, 0, sizeof(info));
- memset(&einfo, 0, sizeof(einfo));
-
- /* Find a header-only digest/signature tag. */
- for (int i = ril; i < il; i++) {
- if (headerVerifyInfo(1, dl, pe+i, &einfo, 0) != -1) {
- rasprintf(buf,
- _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
- i, einfo.tag, einfo.type,
- einfo.offset, einfo.count);
- goto exit;
- }
-
- switch (einfo.tag) {
- case RPMTAG_SHA1HEADER: {
- size_t blen = 0;
- unsigned const char * b;
- if (vsflags & RPMVSF_NOSHA1HEADER)
- break;
- for (b = dataStart + einfo.offset; *b != '\0'; b++) {
- if (strchr("0123456789abcdefABCDEF", *b) == NULL)
- break;
- blen++;
- }
- if (einfo.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
- {
- rasprintf(buf, _("hdr SHA1: BAD, not hex\n"));
- goto exit;
- }
- if (info.tag == 0) {
- info = einfo; /* structure assignment */
- siglen = blen + 1;
- }
- } break;
- case RPMTAG_RSAHEADER:
- if (vsflags & RPMVSF_NORSAHEADER)
- break;
- if (einfo.type != RPM_BIN_TYPE) {
- rasprintf(buf, _("hdr RSA: BAD, not binary\n"));
- goto exit;
- }
- info = einfo; /* structure assignment */
- siglen = info.count;
- break;
- case RPMTAG_DSAHEADER:
- if (vsflags & RPMVSF_NODSAHEADER)
- break;
- if (einfo.type != RPM_BIN_TYPE) {
- rasprintf(buf, _("hdr DSA: BAD, not binary\n"));
- goto exit;
- }
- info = einfo; /* structure assignment */
- siglen = info.count;
- break;
- default:
- break;
- }
- }
-
- /* No header-only digest/signature found, get outta here */
- if (info.tag == 0) {
- rc = RPMRC_NOTFOUND;
- goto exit;
- }
-
- sigtd.tag = info.tag;
- sigtd.type = info.type;
- sigtd.count = info.count;
- sigtd.data = memcpy(xmalloc(siglen), dataStart + info.offset, siglen);
- sigtd.flags = RPMTD_ALLOCED;
-
- switch (info.tag) {
- case RPMTAG_RSAHEADER:
- case RPMTAG_DSAHEADER:
- if (parsePGPSig(&sigtd, "header", NULL, &sig))
- goto exit;
- hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO);
- break;
- case RPMTAG_SHA1HEADER:
- hashalgo = PGPHASHALGO_SHA1;
- break;
- default:
- break;
- }
-
- if (hashalgo) {
- DIGEST_CTX ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);
- int32_t ildl[2] = { htonl(ril), htonl(rdl) };
-
- rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
- rpmDigestUpdate(ctx, ildl, sizeof(ildl));
- rpmDigestUpdate(ctx, pe, (ril * sizeof(*pe)));
- rpmDigestUpdate(ctx, dataStart, rdl);
+ int32_t ildl[2] = { htonl(blob->ril), htonl(blob->rdl) };
- rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf);
-
- rpmDigestFinal(ctx, NULL, NULL, 0);
- }
-
-exit:
- rpmtdFreeData(&sigtd);
- pgpDigParamsFree(sig);
-
- return rc;
+ rpmDigestBundleUpdate(bundle, rpm_header_magic, sizeof(rpm_header_magic));
+ rpmDigestBundleUpdate(bundle, ildl, sizeof(ildl));
+ rpmDigestBundleUpdate(bundle, blob->pe, (blob->ril * sizeof(*blob->pe)));
+ rpmDigestBundleUpdate(bundle, blob->dataStart, blob->rdl);
}
-static rpmRC headerVerify(rpmKeyring keyring, rpmVSFlags vsflags,
- const void * uh, size_t uc, char ** msg)
+rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, char ** msg)
{
- char *buf = NULL;
- int32_t * ei = (int32_t *) uh;
- int32_t il = ntohl(ei[0]);
- int32_t dl = ntohl(ei[1]);
- entryInfo pe = (entryInfo) &ei[2];
- int32_t pvlen = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
- unsigned char * dataStart = (unsigned char *) (pe + il);
- struct indexEntry_s entry;
- struct entryInfo_s info;
- int32_t ril = 0;
- unsigned char * regionEnd = NULL;
- rpmRC rc = RPMRC_FAIL; /* assume failure */
-
- /* Is the blob the right size? */
- if (uc > 0 && pvlen != uc) {
- rasprintf(&buf, _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"),
- (int)uc, (int)il, (int)dl);
- goto exit;
- }
-
- memset(&entry, 0, sizeof(entry));
- memset(&info, 0, sizeof(info));
-
- /* Check (and convert) the 1st tag element. */
- if (headerVerifyInfo(1, dl, pe, &entry.info, 0) != -1) {
- rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
- 0, entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
+ rpmRC rc = RPMRC_FAIL;
+ rpmVSFlags vsflags = rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD;
+ rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
+ struct hdrblob_s blob;
- /* Is there an immutable header region tag? */
- if (!(entry.info.tag == RPMTAG_HEADERIMMUTABLE)) {
- rc = RPMRC_NOTFOUND;
- goto exit;
- }
+ if (hdrblobInit(uh, uc, 0, 0, &blob, msg) == RPMRC_OK) {
+ struct rpmvs_s *vs = rpmvsCreate(&blob, vsflags);
+ rpmDigestBundle bundle = rpmDigestBundleNew();
- /* Is the region tag sane? */
- if (!(entry.info.type == REGION_TAG_TYPE &&
- entry.info.count == REGION_TAG_COUNT)) {
- rasprintf(&buf,
- _("region tag: BAD, tag %d type %d offset %d count %d\n"),
- entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
+ rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
- /* Is the trailer within the data area? */
- if (entry.info.offset + REGION_TAG_COUNT > dl) {
- rasprintf(&buf,
- _("region offset: BAD, tag %d type %d offset %d count %d\n"),
- entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
+ rpmvsInitDigests(vs, RPMSIG_HEADER, bundle);
+ updateHdrDigests(bundle, &blob);
- /* Is there an immutable header region tag trailer? */
- regionEnd = dataStart + entry.info.offset;
- (void) memcpy(&info, regionEnd, REGION_TAG_COUNT);
- regionEnd += REGION_TAG_COUNT;
-
- if (headerVerifyInfo(1, il * sizeof(*pe), &info, &entry.info, 1) != -1 ||
- !(entry.info.tag == RPMTAG_HEADERIMMUTABLE
- && entry.info.type == REGION_TAG_TYPE
- && entry.info.count == REGION_TAG_COUNT))
- {
- rasprintf(&buf,
- _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
- entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
- memset(&info, 0, sizeof(info));
+ rc = rpmvsVerifyItems(rpmtsPlugins(ts), vs, RPMSIG_HEADER, bundle, keyring,
+ handleHdrVS, msg);
- /* Is the no. of tags in the region less than the total no. of tags? */
- ril = entry.info.offset/sizeof(*pe);
- if ((entry.info.offset % sizeof(*pe)) || ril > il) {
- rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
- goto exit;
- }
+ rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), uc);
- /* Verify header-only digest/signature if there is one we can use. */
- rc = headerSigVerify(keyring, vsflags,
- il, dl, ril, (regionEnd - dataStart),
- pe, dataStart, &buf);
+ if (rc == RPMRC_OK && msg != NULL && *msg == NULL)
+ rasprintf(msg, "Header sanity check: OK");
-exit:
- /* If no header-only digest/signature, then do simple sanity check. */
- if (rc == RPMRC_NOTFOUND) {
- int xx = headerVerifyInfo(ril-1, dl, pe+1, &entry.info, 0);
- if (xx != -1) {
- rasprintf(&buf,
- _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
- xx+1, entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- rc = RPMRC_FAIL;
- } else {
- rasprintf(&buf, "Header sanity check: OK\n");
- rc = RPMRC_OK;
- }
+ rpmDigestBundleFree(bundle);
+ rpmvsFree(vs);
}
- if (msg)
- *msg = buf;
- else
- free(buf);
-
- return rc;
-}
-
-rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, char ** msg)
-{
- rpmRC rc;
- rpmVSFlags vsflags = rpmtsVSFlags(ts);
- rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
-
- rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
- rc = headerVerify(keyring, vsflags, uh, uc, msg);
- rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), uc);
rpmKeyringFree(keyring);
return rc;
}
-static rpmRC rpmpkgReadHeader(rpmKeyring keyring, rpmVSFlags vsflags,
- FD_t fd, Header *hdrp, char ** msg)
+rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg)
{
char *buf = NULL;
- int32_t block[4];
- int32_t il;
- int32_t dl;
- int32_t * ei = NULL;
- size_t uc;
- size_t nb;
+ struct hdrblob_s blob;
Header h = NULL;
rpmRC rc = RPMRC_FAIL; /* assume failure */
- int xx;
if (hdrp)
*hdrp = NULL;
if (msg)
*msg = NULL;
- memset(block, 0, sizeof(block));
- if ((xx = Freadall(fd, block, sizeof(block))) != sizeof(block)) {
- rasprintf(&buf,
- _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
- goto exit;
- }
- if (memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) {
- rasprintf(&buf, _("hdr magic: BAD\n"));
- goto exit;
- }
- il = ntohl(block[2]);
- if (hdrchkTags(il)) {
- rasprintf(&buf, _("hdr tags: BAD, no. of tags(%d) out of range\n"), il);
- goto exit;
- }
- dl = ntohl(block[3]);
- if (hdrchkData(dl)) {
- rasprintf(&buf,
- _("hdr data: BAD, no. of bytes(%d) out of range\n"), dl);
- goto exit;
- }
-
- nb = (il * sizeof(struct entryInfo_s)) + dl;
- uc = sizeof(il) + sizeof(dl) + nb;
- ei = xmalloc(uc);
- ei[0] = block[2];
- ei[1] = block[3];
- if ((xx = Freadall(fd, (char *)&ei[2], nb)) != nb) {
- rasprintf(&buf, _("hdr blob(%zd): BAD, read returned %d\n"), nb, xx);
- goto exit;
- }
-
- /* Sanity check header tags */
- rc = headerVerify(keyring, vsflags, ei, uc, &buf);
- if (rc != RPMRC_OK)
+ if (hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, &blob, &buf) != RPMRC_OK)
goto exit;
/* OK, blob looks sane, load the header. */
- h = headerImport(ei, uc, 0);
- if (h == NULL) {
- free(buf);
- rasprintf(&buf, _("hdr load: BAD\n"));
- rc = RPMRC_FAIL;
- goto exit;
- }
- ei = NULL; /* XXX will be freed with header */
+ rc = hdrblobImport(&blob, 0, &h, &buf);
exit:
if (hdrp && h && rc == RPMRC_OK)
*hdrp = headerLink(h);
- free(ei);
headerFree(h);
if (msg != NULL && *msg == NULL && buf != NULL) {
@@ -485,241 +215,100 @@ exit:
return rc;
}
-rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg)
-{
- rpmRC rc;
- rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
- rpmVSFlags vsflags = rpmtsVSFlags(ts);
-
- rc = rpmpkgReadHeader(keyring, vsflags, fd, hdrp, msg);
-
- rpmKeyringFree(keyring);
- return rc;
-}
-
-static rpmRC rpmpkgRead(rpmPlugins plugins, rpmKeyring keyring, rpmVSFlags vsflags,
- FD_t fd, const char * fn, Header * hdrp)
+void applyRetrofits(Header h, int leadtype)
{
- pgpDigParams sig = NULL;
- char buf[8*BUFSIZ];
- ssize_t count;
- Header sigh = NULL;
- rpmTagVal sigtag;
- struct rpmtd_s sigtd;
- Header h = NULL;
- char * msg = NULL;
- rpmRC rc = RPMRC_FAIL; /* assume failure */
- int leadtype = -1;
- headerGetFlags hgeflags = HEADERGET_DEFAULT;
- DIGEST_CTX ctx = NULL;
-
- if (hdrp) *hdrp = NULL;
- if (fn == NULL)
- fn = Fdescr(fd);
-
- rpmtdReset(&sigtd);
-
- if ((rc = rpmLeadRead(fd, NULL, &leadtype, &msg)) != RPMRC_OK) {
- /* Avoid message spew on manifests */
- if (rc != RPMRC_NOTFOUND)
- rpmlog(RPMLOG_ERR, "%s: %s\n", fn, msg);
- free(msg);
- goto exit;
- }
-
- /* Read the signature header. */
- rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
- switch (rc) {
- default:
- rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
- (msg && *msg ? msg : "\n"));
- msg = _free(msg);
- goto exit;
- break;
- case RPMRC_OK:
- if (sigh == NULL) {
- rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
- rc = RPMRC_FAIL;
- goto exit;
+ /*
+ * Make sure that either RPMTAG_SOURCERPM or RPMTAG_SOURCEPACKAGE
+ * is set. Use a simple heuristic to find the type if both are unset.
+ */
+ if (!headerIsEntry(h, RPMTAG_SOURCERPM) && !headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) {
+ /* the heuristic needs the compressed file list */
+ if (headerIsEntry(h, RPMTAG_OLDFILENAMES))
+ headerConvert(h, HEADERCONV_COMPRESSFILELIST);
+ if (headerIsSourceHeuristic(h)) {
+ /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */
+ uint32_t one = 1;
+ headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1);
+ } else {
+ /*
+ * Make sure binary rpms have RPMTAG_SOURCERPM set as that's
+ * what we use for differentiating binary vs source elsewhere.
+ */
+ headerPutString(h, RPMTAG_SOURCERPM, "(none)");
}
- break;
}
- msg = _free(msg);
-
-#define _chk(_mask, _tag) \
- (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag)))
/*
- * Figger the most effective available signature.
- * Prefer signatures over digests, then header-only over header+payload.
- * DSA will be preferred over RSA if both exist because tested first.
- * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
+ * Convert legacy headers on the fly. Not having immutable region
+ * equals a truly ancient package, do full retrofit. OTOH newer
+ * packages might have been built with --nodirtokens, test and handle
+ * the non-compressed filelist case separately.
*/
- sigtag = 0;
- if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) {
- sigtag = RPMSIGTAG_DSA;
- } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) {
- sigtag = RPMSIGTAG_RSA;
- } else if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_GPG)) {
- sigtag = RPMSIGTAG_GPG;
- fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
- } else if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_PGP)) {
- sigtag = RPMSIGTAG_PGP;
- fdInitDigest(fd, PGPHASHALGO_MD5, 0);
- } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) {
- sigtag = RPMSIGTAG_SHA1;
- } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_MD5)) {
- sigtag = RPMSIGTAG_MD5;
- fdInitDigest(fd, PGPHASHALGO_MD5, 0);
- }
-
- /* Read the metadata, computing digest(s) on the fly. */
- h = NULL;
- msg = NULL;
-
- rc = rpmpkgReadHeader(keyring, vsflags, fd, &h, &msg);
-
- if (rc != RPMRC_OK || h == NULL) {
- rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s"), fn,
- (msg && *msg ? msg : "\n"));
- msg = _free(msg);
- goto exit;
- }
- msg = _free(msg);
-
- /* Any digests or signatures to check? */
- if (sigtag == 0) {
- rc = RPMRC_OK;
- goto exit;
- }
-
- /* Retrieve the tag parameters from the signature header. */
- if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) {
- rc = RPMRC_FAIL;
- goto exit;
- }
-
- switch (sigtag) {
- case RPMSIGTAG_RSA:
- case RPMSIGTAG_DSA:
- if (parsePGPSig(&sigtd, "package", fn, &sig)) {
- rc = RPMRC_FAIL;
- goto exit;
- }
- /* fallthrough */
- case RPMSIGTAG_SHA1:
- { struct rpmtd_s utd;
- unsigned int hashalgo = (sigtag == RPMSIGTAG_SHA1) ?
- PGPHASHALGO_SHA1 :
- pgpDigParamsAlgo(sig, PGPVAL_HASHALGO);
-
- if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags))
- break;
- ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);
- (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
- (void) rpmDigestUpdate(ctx, utd.data, utd.count);
- rpmtdFreeData(&utd);
- } break;
- case RPMSIGTAG_GPG:
- case RPMSIGTAG_PGP5: /* XXX legacy */
- case RPMSIGTAG_PGP:
- if (parsePGPSig(&sigtd, "package", fn, &sig)) {
- rc = RPMRC_FAIL;
- goto exit;
- }
- /* fallthrough */
- case RPMSIGTAG_MD5:
- /* Legacy signatures need the compressed payload in the digest too. */
- while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
- if (count < 0) {
- rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
- fn, Fstrerror(fd));
- rc = RPMRC_FAIL;
- goto exit;
- }
+ if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE))
+ headerConvert(h, HEADERCONV_RETROFIT_V3);
+ else if (headerIsEntry(h, RPMTAG_OLDFILENAMES))
+ headerConvert(h, HEADERCONV_COMPRESSFILELIST);
+}
- ctx = rpmDigestBundleDupCtx(fdGetBundle(fd),(sigtag == RPMSIGTAG_MD5) ?
- PGPHASHALGO_MD5 :
- pgpDigParamsAlgo(sig, PGPVAL_HASHALGO));
- break;
- default:
- break;
- }
+struct pkgdata_s {
+ const char *fn;
+ rpmRC rc;
+};
- /** @todo Implement disable/enable/warn/error/anal policy. */
- rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, &msg);
-
- /* Run verify hook for all plugins */
- rc = rpmpluginsCallVerify(plugins, keyring, &sigtd, sig, ctx, rc);
-
+static rpmRC handlePkgVS(struct rpmsinfo_s *sinfo, rpmRC rc, const char *msg, void *cbdata)
+{
+ struct pkgdata_s *pkgdata = cbdata;
+ int lvl = RPMLOG_DEBUG;
+ char *vsmsg = rpmsinfoMsg(sinfo, rc, msg);
switch (rc) {
case RPMRC_OK: /* Signature is OK. */
- rpmlog(RPMLOG_DEBUG, "%s: %s", fn, msg);
break;
case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */
case RPMRC_NOKEY: /* Public key is unavailable. */
/* XXX Print NOKEY/NOTTRUSTED warning only once. */
- { int lvl = (stashKeyid(sig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
- rpmlog(lvl, "%s: %s", fn, msg);
- } break;
- case RPMRC_NOTFOUND: /* Signature is unknown type. */
- rpmlog(RPMLOG_WARNING, "%s: %s", fn, msg);
+ if (stashKeyid(sinfo->keyid) == 0)
+ lvl = RPMLOG_WARNING;
+ break;
+ case RPMRC_NOTFOUND: /* Signature/digest not present. */
+ lvl = RPMLOG_WARNING;
break;
default:
case RPMRC_FAIL: /* Signature does not verify. */
- rpmlog(RPMLOG_ERR, "%s: %s", fn, msg);
+ lvl = RPMLOG_ERR;
break;
}
- free(msg);
-exit:
- if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
- /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */
- if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) {
- if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) {
- uint32_t one = 1;
- headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1);
- }
- }
- /*
- * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's
- * what we use for differentiating binary vs source elsewhere.
- */
- if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) {
- headerPutString(h, RPMTAG_SOURCERPM, "(none)");
- }
- /*
- * Convert legacy headers on the fly. Not having immutable region
- * equals a truly ancient package, do full retrofit. OTOH newer
- * packages might have been built with --nodirtokens, test and handle
- * the non-compressed filelist case separately.
- */
- if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE))
- headerConvert(h, HEADERCONV_RETROFIT_V3);
- else if (headerIsEntry(h, RPMTAG_OLDFILENAMES))
- headerConvert(h, HEADERCONV_COMPRESSFILELIST);
-
- /* Append (and remap) signature tags to the metadata. */
- headerMergeLegacySigs(h, sigh);
+ rpmlog(lvl, "%s: %s\n", pkgdata->fn, vsmsg);
- /* Bump reference count for return. */
- *hdrp = headerLink(h);
- }
- rpmtdFreeData(&sigtd);
- rpmDigestFinal(ctx, NULL, NULL, 0);
- h = headerFree(h);
- pgpDigParamsFree(sig);
- sigh = rpmFreeSignature(sigh);
+ /* Remember actual return code, but don't override a previous failure */
+ if (rc && pkgdata->rc != RPMRC_FAIL)
+ pkgdata->rc = rc;
+
+ /* Preserve traditional behavior for now: only failure prevents read */
+ if (rc != RPMRC_FAIL)
+ rc = RPMRC_OK;
+
+ free(vsmsg);
return rc;
}
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
{
- rpmRC rc;
- rpmVSFlags vsflags = rpmtsVSFlags(ts);
+ rpmVSFlags vsflags = rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD;
rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
+ struct pkgdata_s pkgdata = {
+ .fn = fn ? fn : Fdescr(fd),
+ .rc = RPMRC_OK,
+ };
+
+ /* XXX: lots of 3rd party software relies on the behavior */
+ if (hdrp)
+ *hdrp = NULL;
- rc = rpmpkgRead(rpmtsPlugins(ts), keyring, vsflags, fd, fn, hdrp);
+ rpmRC rc = rpmpkgRead(rpmtsPlugins(ts), keyring, vsflags, fd, handlePkgVS, &pkgdata, hdrp);
+ /* If there was a "substatus" (NOKEY in practise), return that instead */
+ if (rc == RPMRC_OK && pkgdata.rc)
+ rc = pkgdata.rc;
rpmKeyringFree(keyring);
diff --git a/lib/poptALL.c b/lib/poptALL.c
index 541e8c4ab..b7f48da36 100644
--- a/lib/poptALL.c
+++ b/lib/poptALL.c
@@ -4,7 +4,6 @@
*/
#include "system.h"
-const char *__progname;
#include <rpm/rpmcli.h>
#include <rpm/rpmlib.h> /* rpmEVR, rpmReadConfigFiles etc */
@@ -20,6 +19,7 @@ const char *__progname;
#define POPT_PREDEFINE -996
#define POPT_DBPATH -995
#define POPT_UNDEFINE -994
+#define POPT_PIPE -993
static int _debug = 0;
@@ -69,6 +69,27 @@ void rpmcliConfigured(void)
exit(EXIT_FAILURE);
}
+static int cliDefine(const char *arg, int predefine)
+{
+ int rc;
+ char *s, *t;
+ /* XXX Convert '-' in macro name to underscore, skip leading %. */
+ s = t = xstrdup(arg);
+ while (*t && !risspace(*t)) {
+ if (*t == '-') *t = '_';
+ t++;
+ }
+ t = s;
+ if (*t == '%') t++;
+
+ rc = rpmDefineMacro(NULL, t, RMIL_CMDLINE);
+ if (!predefine && rc == 0)
+ (void) rpmDefineMacro(rpmCLIMacroContext, t, RMIL_CMDLINE);
+
+ free(s);
+ return rc;
+}
+
/**
*/
static void rpmcliAllArgCallback( poptContext con,
@@ -87,43 +108,32 @@ static void rpmcliAllArgCallback( poptContext con,
rpmIncreaseVerbosity();
break;
case POPT_PREDEFINE:
- (void) rpmDefineMacro(NULL, arg, RMIL_CMDLINE);
+ if (cliDefine(arg, 1))
+ exit(EXIT_FAILURE);
break;
case 'D':
- { char *s, *t;
- /* XXX Convert '-' in macro name to underscore, skip leading %. */
- s = t = xstrdup(arg);
- while (*t && !risspace(*t)) {
- if (*t == '-') *t = '_';
- t++;
- }
- t = s;
- if (*t == '%') t++;
- /* XXX Predefine macro if not initialized yet. */
- if (rpmcliInitialized < 0)
- (void) rpmDefineMacro(NULL, t, RMIL_CMDLINE);
rpmcliConfigured();
- (void) rpmDefineMacro(NULL, t, RMIL_CMDLINE);
- (void) rpmDefineMacro(rpmCLIMacroContext, t, RMIL_CMDLINE);
- free(s);
+ if (cliDefine(arg, 0))
+ exit(EXIT_FAILURE);
break;
- }
case POPT_UNDEFINE:
rpmcliConfigured();
if (*arg == '%')
arg++;
- delMacro(NULL, arg);
+ rpmPopMacro(NULL, arg);
break;
case 'E':
rpmcliConfigured();
- { char *val = rpmExpand(arg, NULL);
+ { char *val = NULL;
+ if (rpmExpandMacros(NULL, arg, &val, 0) < 0)
+ exit(EXIT_FAILURE);
fprintf(stdout, "%s\n", val);
free(val);
}
break;
case POPT_DBPATH:
rpmcliConfigured();
- addMacro(NULL, "_dbpath", NULL, arg, RMIL_CMDLINE);
+ rpmPushMacro(NULL, "_dbpath", NULL, arg, RMIL_CMDLINE);
break;
case POPT_SHOWVERSION:
printVersion(stdout);
@@ -138,6 +148,16 @@ static void rpmcliAllArgCallback( poptContext con,
rpmDisplayQueryTags(stdout);
exit(EXIT_SUCCESS);
break;
+ case POPT_PIPE:
+ if (rpmcliPipeOutput) {
+ fprintf(stderr,
+ _("%s: error: more than one --pipe specified "
+ "(incompatible popt aliases?)\n"), xgetprogname());
+ exit(EXIT_FAILURE);
+ }
+ rpmcliPipeOutput = xstrdup(arg);
+ break;
+
case RPMCLI_POPT_NODIGEST:
rpmcliQueryFlags |= VERIFY_DIGEST;
break;
@@ -149,6 +169,10 @@ static void rpmcliAllArgCallback( poptContext con,
case RPMCLI_POPT_NOHDRCHK:
rpmcliQueryFlags |= VERIFY_HDRCHK;
break;
+
+ case RPMCLI_POPT_TARGETPLATFORM:
+ rpmcliInitialized = rpmReadConfigFiles(rpmcliRcfile, arg);
+ break;
}
}
@@ -172,10 +196,17 @@ struct poptOption rpmcliAllPoptTable[] = {
{ "eval", 'E', POPT_ARG_STRING, 0, 'E',
N_("print macro expansion of EXPR"),
N_("'EXPR'") },
+ { "target", '\0', POPT_ARG_STRING, NULL, RPMCLI_POPT_TARGETPLATFORM,
+ N_("Specify target platform"), N_("CPU-VENDOR-OS") },
{ "macros", '\0', POPT_ARG_STRING, &macrofiles, 0,
N_("read <FILE:...> instead of default file(s)"),
N_("<FILE:...>") },
+ /* XXX this is a bit out of place here but kinda unavoidable... */
+ { "noplugins", '\0', POPT_BIT_SET,
+ &rpmIArgs.transFlags, RPMTRANS_FLAG_NOPLUGINS,
+ N_("don't enable any plugins"), NULL },
+
{ "nodigest", '\0', 0, 0, RPMCLI_POPT_NODIGEST,
N_("don't verify package digest(s)"), NULL },
{ "nohdrchk", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0, RPMCLI_POPT_NOHDRCHK,
@@ -183,7 +214,7 @@ struct poptOption rpmcliAllPoptTable[] = {
{ "nosignature", '\0', 0, 0, RPMCLI_POPT_NOSIGNATURE,
N_("don't verify package signature(s)"), NULL },
- { "pipe", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &rpmcliPipeOutput, 0,
+ { "pipe", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, 0, POPT_PIPE,
N_("send stdout to CMD"),
N_("CMD") },
{ "rcfile", '\0', POPT_ARG_STRING, &rpmcliRcfile, 0,
@@ -244,14 +275,6 @@ rpmcliInit(int argc, char *const argv[], struct poptOption * optionsTable)
int rc;
const char *ctx, *execPath;
- setprogname(argv[0]); /* Retrofit glibc __progname */
-
- /* XXX glibc churn sanity */
- if (__progname == NULL) {
- if ((__progname = strrchr(argv[0], '/')) != NULL) __progname++;
- else __progname = argv[0];
- }
-
#if defined(ENABLE_NLS)
(void) setlocale(LC_ALL, "" );
@@ -268,7 +291,7 @@ rpmcliInit(int argc, char *const argv[], struct poptOption * optionsTable)
}
/* XXX hack to get popt working from build tree wrt lt-foo names */
- ctx = rstreqn(__progname, "lt-", 3) ? __progname + 3 : __progname;
+ ctx = rstreqn(xgetprogname(), "lt-", 3) ? xgetprogname() + 3 : xgetprogname();
optCon = poptGetContext(ctx, argc, (const char **)argv, optionsTable, 0);
{
@@ -285,12 +308,12 @@ rpmcliInit(int argc, char *const argv[], struct poptOption * optionsTable)
/* Process all options, whine if unknown. */
while ((rc = poptGetNextOpt(optCon)) > 0) {
fprintf(stderr, _("%s: option table misconfigured (%d)\n"),
- __progname, rc);
+ xgetprogname(), rc);
exit(EXIT_FAILURE);
}
if (rc < -1) {
- fprintf(stderr, "%s: %s: %s\n", __progname,
+ fprintf(stderr, "%s: %s: %s\n", xgetprogname(),
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
exit(EXIT_FAILURE);
diff --git a/lib/poptI.c b/lib/poptI.c
index 8c1ff6edb..8272fa80f 100644
--- a/lib/poptI.c
+++ b/lib/poptI.c
@@ -26,7 +26,7 @@ struct rpmInstallArguments_s rpmIArgs = {
RPM_GNUC_NORETURN
static void argerror(const char * desc)
{
- fprintf(stderr, _("%s: %s\n"), __progname, desc);
+ fprintf(stderr, _("%s: %s\n"), xgetprogname(), desc);
exit(EXIT_FAILURE);
}
@@ -87,6 +87,10 @@ static void installArgCallback( poptContext con,
ia->transFlags |= RPMTRANS_FLAG_NOCONTEXTS;
break;
+ case RPMCLI_POPT_NOCAPS:
+ ia->transFlags |= RPMTRANS_FLAG_NOCAPS;
+ break;
+
case RPMCLI_POPT_FORCE:
ia->probFilter |=
( RPMPROB_FILTER_REPLACEPKG
@@ -181,6 +185,8 @@ struct poptOption rpmInstallPoptTable[] = {
N_("don't verify digest of files (obsolete)"), NULL },
{ "nocontexts", '\0',0, NULL, RPMCLI_POPT_NOCONTEXTS,
N_("don't install file security contexts"), NULL},
+ { "nocaps", '\0',0, NULL, RPMCLI_POPT_NOCAPS,
+ N_("don't install file capabilities"), NULL},
{ "noorder", '\0', POPT_BIT_SET,
&rpmIArgs.installInterfaceFlags, INSTALL_NOORDER,
@@ -202,6 +208,12 @@ struct poptOption rpmInstallPoptTable[] = {
{ "nopostun", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &rpmIArgs.transFlags,
RPMTRANS_FLAG_NOPOSTUN,
N_("do not execute %%postun scriptlet (if any)"), NULL },
+ { "nopretrans", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &rpmIArgs.transFlags,
+ RPMTRANS_FLAG_NOPRETRANS,
+ N_("do not execute %%pretrans scriptlet (if any)"), NULL },
+ { "noposttrans", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &rpmIArgs.transFlags,
+ RPMTRANS_FLAG_NOPOSTTRANS,
+ N_("do not execute %%posttrans scriptlet (if any)"), NULL },
{ "notriggers", '\0', POPT_BIT_SET, &rpmIArgs.transFlags, _noTransTriggers,
N_("do not execute any scriptlet(s) triggered by this package"), NULL},
@@ -218,10 +230,6 @@ struct poptOption rpmInstallPoptTable[] = {
&rpmIArgs.transFlags, RPMTRANS_FLAG_NOTRIGGERPOSTUN,
N_("do not execute any %%triggerpostun scriptlet(s)"), NULL},
- { "nocollections", '\0', POPT_BIT_SET,
- &rpmIArgs.transFlags, RPMTRANS_FLAG_NOCOLLECTIONS,
- N_("do not perform any collection actions"), NULL},
-
{ "oldpackage", '\0', POPT_BIT_SET,
&rpmIArgs.probFilter, RPMPROB_FILTER_OLDPACKAGE,
N_("upgrade to an old version of the package (--force on upgrades does this automatically)"),
@@ -247,6 +255,10 @@ struct poptOption rpmInstallPoptTable[] = {
&rpmIArgs.installInterfaceFlags, (INSTALL_UPGRADE|INSTALL_INSTALL),
N_("upgrade package(s)"),
N_("<packagefile>+") },
+ { "reinstall", '\0', POPT_BIT_SET,
+ &rpmIArgs.installInterfaceFlags, (INSTALL_REINSTALL|INSTALL_INSTALL),
+ N_("reinstall package(s)"),
+ N_("<packagefile>+") },
POPT_TABLEEND
};
diff --git a/lib/poptQV.c b/lib/poptQV.c
index 3db17b0ab..e3ea2d7bc 100644
--- a/lib/poptQV.c
+++ b/lib/poptQV.c
@@ -21,6 +21,10 @@ struct rpmQVKArguments_s rpmQVKArgs;
#define POPT_QUERYBYPKGID -1007
#define POPT_QUERYBYHDRID -1008
#define POPT_QUERYBYTID -1010
+#define POPT_WHATRECOMMENDS -1011
+#define POPT_WHATSUGGESTS -1012
+#define POPT_WHATSUPPLEMENTS -1013
+#define POPT_WHATENHANCES -1014
/* ========== Query/Verify/Signature source args */
static void rpmQVSourceArgCallback( poptContext con,
@@ -45,6 +49,10 @@ static void rpmQVSourceArgCallback( poptContext con,
case 'p': qva->qva_source |= RPMQV_RPM; break;
case POPT_WHATPROVIDES: qva->qva_source |= RPMQV_WHATPROVIDES; break;
case POPT_WHATREQUIRES: qva->qva_source |= RPMQV_WHATREQUIRES; break;
+ case POPT_WHATRECOMMENDS: qva->qva_source |= RPMQV_WHATRECOMMENDS; break;
+ case POPT_WHATSUGGESTS: qva->qva_source |= RPMQV_WHATSUGGESTS; break;
+ case POPT_WHATSUPPLEMENTS: qva->qva_source |= RPMQV_WHATSUPPLEMENTS; break;
+ case POPT_WHATENHANCES: qva->qva_source |= RPMQV_WHATENHANCES; break;
case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY; break;
case POPT_QUERYBYPKGID: qva->qva_source |= RPMQV_PKGID; break;
case POPT_QUERYBYHDRID: qva->qva_source |= RPMQV_HDRID; break;
@@ -93,6 +101,14 @@ struct poptOption rpmQVSourcePoptTable[] = {
N_("query/verify the package(s) which require a dependency"), "CAPABILITY" },
{ "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES,
N_("query/verify the package(s) which provide a dependency"), "CAPABILITY" },
+ { "whatrecommends", '\0', 0, 0, POPT_WHATRECOMMENDS,
+ N_("query/verify the package(s) which recommends a dependency"), "CAPABILITY" },
+ { "whatsuggests", '\0', 0, 0, POPT_WHATSUGGESTS,
+ N_("query/verify the package(s) which suggests a dependency"), "CAPABILITY" },
+ { "whatsupplements", '\0', 0, 0, POPT_WHATSUPPLEMENTS,
+ N_("query/verify the package(s) which supplements a dependency"), "CAPABILITY" },
+ { "whatenhances", '\0', 0, 0, POPT_WHATENHANCES,
+ N_("query/verify the package(s) which enhances a dependency"), "CAPABILITY" },
{ "noglob", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &giFlags, RPMGI_NOGLOB,
N_("do not glob arguments"), NULL},
@@ -115,6 +131,7 @@ static void queryArgCallback(poptContext con,
case 'c': qva->qva_flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
case 'd': qva->qva_flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
case 'L': qva->qva_flags |= QUERY_FOR_LICENSE | QUERY_FOR_LIST; break;
+ case 'A': qva->qva_flags |= QUERY_FOR_ARTIFACT | QUERY_FOR_LIST; break;
case 'l': qva->qva_flags |= QUERY_FOR_LIST; break;
case 's': qva->qva_flags |= QUERY_FOR_STATE | QUERY_FOR_LIST;
break;
@@ -144,6 +161,10 @@ static void queryArgCallback(poptContext con,
qva->qva_flags |= VERIFY_CONTEXTS;
break;
+ case RPMCLI_POPT_NOCAPS:
+ qva->qva_flags |= VERIFY_CAPS;
+ break;
+
#ifdef NOTYET
case RPMCLI_POPT_FORCE:
ia->probFilter |=
@@ -174,6 +195,8 @@ struct poptOption rpmQueryPoptTable[] = {
N_("list all documentation files"), NULL },
{ "licensefiles", 'L', 0, 0, 'L',
N_("list all license files"), NULL },
+ { "artifactfiles", 'A', 0, 0, 'A',
+ N_("list all artifact files"), NULL },
{ "dump", '\0', 0, 0, POPT_DUMP,
N_("dump basic file information"), NULL },
{ NULL, 'i', POPT_ARGFLAG_DOC_HIDDEN, 0, 'i',
@@ -182,9 +205,15 @@ struct poptOption rpmQueryPoptTable[] = {
N_("list files in package"), NULL },
/* Duplicate file attr flags from packages into command line options. */
- { "noghost", '\0', POPT_BIT_CLR|POPT_ARGFLAG_DOC_HIDDEN,
+ { "noghost", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
&rpmQVKArgs.qva_fflags, RPMFILE_GHOST,
N_("skip %%ghost files"), NULL },
+ { "noconfig", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
+ &rpmQVKArgs.qva_fflags, RPMFILE_CONFIG,
+ N_("skip %%config files"), NULL },
+ { "noartifact", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
+ &rpmQVKArgs.qva_fflags, RPMFILE_ARTIFACT,
+ N_("skip %%artifact files"), NULL },
{ "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
POPT_QUERYFORMAT, NULL, NULL },
@@ -228,12 +257,11 @@ struct poptOption rpmVerifyPoptTable[] = {
{ "nordev", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
&rpmQVKArgs.qva_flags, VERIFY_RDEV,
N_("don't verify mode of files"), NULL },
- { "nocaps", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
- &rpmQVKArgs.qva_flags, VERIFY_CAPS,
- N_("don't verify capabilities of files"), NULL },
{ "nocontexts", '\0', POPT_ARGFLAG_DOC_HIDDEN, NULL, RPMCLI_POPT_NOCONTEXTS,
N_("don't verify file security contexts"), NULL },
+ { "nocaps", '\0', POPT_ARGFLAG_DOC_HIDDEN, NULL, RPMCLI_POPT_NOCAPS,
+ N_("don't verify capabilities of files"), NULL },
{ "nofiles", '\0', POPT_BIT_SET, &rpmQVKArgs.qva_flags, VERIFY_FILES,
N_("don't verify files in package"), NULL},
{ "nodeps", '\0', 0, NULL, RPMCLI_POPT_NODEPS,
diff --git a/lib/psm.c b/lib/psm.c
index fcc6749cc..2c6c9c550 100644
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -17,107 +17,38 @@
#include <rpm/rpmstring.h>
#include <rpm/argv.h>
-#include "lib/cpio.h"
#include "lib/fsm.h" /* XXX CPIO_FOO/FSM_FOO constants */
#include "lib/rpmchroot.h"
#include "lib/rpmfi_internal.h" /* XXX replaced/states... */
#include "lib/rpmte_internal.h" /* XXX internal apis */
#include "lib/rpmdb_internal.h" /* rpmdbAdd/Remove */
-#include "lib/rpmts_internal.h" /* ts->plugins */
+#include "lib/rpmts_internal.h" /* rpmtsPlugins() etc */
+#include "lib/rpmds_internal.h" /* rpmdsFilterTi() */
#include "lib/rpmscript.h"
+#include "lib/misc.h"
+#include "lib/rpmtriggers.h"
#include "lib/rpmplugins.h"
#include "debug.h"
-typedef enum pkgStage_e {
- PSM_UNKNOWN = 0,
- PSM_INIT = 1,
- PSM_PRE = 2,
- PSM_PROCESS = 3,
- PSM_POST = 4,
- PSM_UNDO = 5,
- PSM_FINI = 6,
-
- PSM_CREATE = 17,
- PSM_DESTROY = 23,
-
- PSM_SCRIPT = 53,
- PSM_TRIGGERS = 54,
- PSM_IMMED_TRIGGERS = 55,
-
- PSM_RPMDB_ADD = 98,
- PSM_RPMDB_REMOVE = 99
-
-} pkgStage;
-
struct rpmpsm_s {
rpmts ts; /*!< transaction set */
rpmte te; /*!< current transaction element */
- rpmfi fi; /*!< transaction element file info */
- const char * goalName;
- char * failedFile;
- rpmTagVal scriptTag; /*!< Scriptlet data tag. */
- int npkgs_installed; /*!< No. of installed instances. */
+ rpmfiles files; /*!< transaction element file info */
int scriptArg; /*!< Scriptlet package arg. */
- rpmsenseFlags sense; /*!< One of RPMSENSE_TRIGGER{PREIN,IN,UN,POSTUN}. */
int countCorrection; /*!< 0 if installing, -1 if removing. */
rpmCallbackType what; /*!< Callback type. */
rpm_loff_t amount; /*!< Callback amount. */
rpm_loff_t total; /*!< Callback total. */
- pkgGoal goal;
- pkgStage stage; /*!< Current psm stage. */
- pkgStage nstage; /*!< Next psm stage. */
int nrefs; /*!< Reference count. */
};
-static rpmpsm rpmpsmNew(rpmts ts, rpmte te);
+static rpmpsm rpmpsmNew(rpmts ts, rpmte te, pkgGoal goal);
+static rpmRC rpmpsmUnpack(rpmpsm psm);
static rpmpsm rpmpsmFree(rpmpsm psm);
-static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage);
-
-/**
- * Macros to be defined from per-header tag values.
- * @todo Should other macros be added from header when installing a package?
- */
-static struct tagMacro {
- const char *macroname; /*!< Macro name to define. */
- rpmTag tag; /*!< Header tag to use for value. */
-} const tagMacros[] = {
- { "name", RPMTAG_NAME },
- { "version", RPMTAG_VERSION },
- { "release", RPMTAG_RELEASE },
- { "epoch", RPMTAG_EPOCH },
- { NULL, 0 }
-};
-
-/**
- * Define per-header macros.
- * @param h header
- * @return 0 always
- */
-static void rpmInstallLoadMacros(Header h)
-{
- const struct tagMacro * tagm;
-
- for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
- struct rpmtd_s td;
- char *body;
- if (!headerGet(h, tagm->tag, &td, HEADERGET_DEFAULT))
- continue;
-
- switch (rpmtdType(&td)) {
- default:
- body = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL);
- addMacro(NULL, tagm->macroname, NULL, body, -1);
- free(body);
- break;
- case RPM_NULL_TYPE:
- break;
- }
- rpmtdFreeData(&td);
- }
-}
+static const char * pkgGoalString(pkgGoal goal);
/**
* Adjust file states in database for files shared with this package:
@@ -133,9 +64,9 @@ static rpmRC markReplacedFiles(const rpmpsm psm)
sharedFileInfo sfi;
rpmdbMatchIterator mi;
Header h;
- int * offsets;
+ unsigned int * offsets;
unsigned int prev;
- int num;
+ unsigned int num;
if (!replaced)
return RPMRC_OK;
@@ -227,17 +158,12 @@ static int rpmlibDeps(Header h)
rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd,
char ** specFilePtr, char ** cookie)
{
- rpmfi fi = NULL;
- char * specFile = NULL;
- const char *rootdir = rpmtsRootDir(ts);
Header h = NULL;
rpmpsm psm = NULL;
rpmte te = NULL;
rpmRC rpmrc;
int specix = -1;
- struct rpmtd_s filenames;
- rpmtdReset(&filenames);
rpmrc = rpmReadPackageFile(ts, fd, NULL, &h);
switch (rpmrc) {
case RPMRC_NOTTRUSTED:
@@ -262,51 +188,9 @@ rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd,
if (!rpmlibDeps(h))
goto exit;
- if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_ALLOC)) {
- struct rpmtd_s td;
- const char *str;
- const char *_cookie = headerGetString(h, RPMTAG_COOKIE);
- if (cookie && _cookie) *cookie = xstrdup(_cookie);
-
- /* Try to find spec by file flags */
- if (_cookie && headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) {
- rpmfileAttrs *flags;
- while (specix < 0 && (flags = rpmtdNextUint32(&td))) {
- if (*flags & RPMFILE_SPECFILE)
- specix = rpmtdGetIndex(&td);
- }
- }
- /* Still no spec? Look by filename. */
- while (specix < 0 && (str = rpmtdNextString(&filenames))) {
- if (rpmFileHasSuffix(str, ".spec"))
- specix = rpmtdGetIndex(&filenames);
- }
- }
-
- if (rootdir && rstreq(rootdir, "/"))
- rootdir = NULL;
-
- /* Macros need to be added before trying to create directories */
- rpmInstallLoadMacros(h);
+ specix = headerFindSpec(h);
- if (specix >= 0) {
- const char *bn;
-
- headerDel(h, RPMTAG_BASENAMES);
- headerDel(h, RPMTAG_DIRNAMES);
- headerDel(h, RPMTAG_DIRINDEXES);
-
- rpmtdInit(&filenames);
- for (int i = 0; (bn = rpmtdNextString(&filenames)); i++) {
- int spec = (i == specix);
- char *fn = rpmGenPath(rpmtsRootDir(ts),
- spec ? "%{_specdir}" : "%{_sourcedir}", bn);
- headerPutString(h, RPMTAG_OLDFILENAMES, fn);
- if (spec) specFile = xstrdup(fn);
- free(fn);
- }
- headerConvert(h, HEADERCONV_COMPRESSFILELIST);
- } else {
+ if (specix < 0) {
rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n"));
goto exit;
};
@@ -322,142 +206,50 @@ rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd,
rpmteSetFd(te, fd);
rpmteSetHeader(te, h);
- fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
- h = headerFree(h);
-
- if (fi == NULL) {
- goto exit;
- }
- fi->apath = filenames.data; /* Ick */
- rpmteSetFI(te, fi);
- fi = rpmfiFree(fi);
-
- if (rpmMkdirs(rpmtsRootDir(ts), "%{_topdir}:%{_sourcedir}:%{_specdir}")) {
- goto exit;
- }
{
/* set all files to be installed */
rpmfs fs = rpmteGetFileStates(te);
- int i;
- unsigned int fc = rpmfiFC(fi);
- for (i=0; i<fc; i++) rpmfsSetAction(fs, i, FA_CREATE);
+ int fc = rpmfsFC(fs);
+ for (int i = 0; i < fc; i++)
+ rpmfsSetAction(fs, i, FA_CREATE);
}
- psm = rpmpsmNew(ts, te);
- psm->goal = PKG_INSTALL;
+ psm = rpmpsmNew(ts, te, PKG_INSTALL);
- /* FIX: psm->fi->dnl should be owned. */
- if (rpmpsmStage(psm, PSM_PROCESS) == RPMRC_OK)
+ if (rpmpsmUnpack(psm) == RPMRC_OK)
rpmrc = RPMRC_OK;
- (void) rpmpsmStage(psm, PSM_FINI);
rpmpsmFree(psm);
exit:
- if (specFilePtr && specFile && rpmrc == RPMRC_OK)
- *specFilePtr = specFile;
- else
- free(specFile);
-
- headerFree(h);
- rpmfiFree(fi);
+ if (rpmrc == RPMRC_OK && specix >= 0) {
+ if (cookie)
+ *cookie = headerGetAsString(h, RPMTAG_COOKIE);
+ if (specFilePtr) {
+ rpmfiles files = rpmteFiles(te);
+ *specFilePtr = rpmfilesFN(files, specix);
+ rpmfilesFree(files);
+ }
+ }
/* XXX nuke the added package(s). */
- rpmtsClean(ts);
+ headerFree(h);
+ rpmtsEmpty(ts);
return rpmrc;
}
-static rpmTagVal triggertag(rpmsenseFlags sense)
-{
- rpmTagVal tag = RPMTAG_NOT_FOUND;
- switch (sense) {
- case RPMSENSE_TRIGGERIN:
- tag = RPMTAG_TRIGGERIN;
- break;
- case RPMSENSE_TRIGGERUN:
- tag = RPMTAG_TRIGGERUN;
- break;
- case RPMSENSE_TRIGGERPOSTUN:
- tag = RPMTAG_TRIGGERPOSTUN;
- break;
- case RPMSENSE_TRIGGERPREIN:
- tag = RPMTAG_TRIGGERPREIN;
- break;
- default:
- break;
- }
- return tag;
-}
-
-/**
- * Run a scriptlet with args.
- *
- * Run a script with an interpreter. If the interpreter is not specified,
- * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
- * the header will be ignored, passing instead arg1 and arg2.
- *
- * @param psm package state machine data
- * @param prefixes install prefixes
- * @param script scriptlet from header
- * @param arg1 no. instances of package installed after scriptlet exec
- * (-1 is no arg)
- * @param arg2 ditto, but for the target package
- * @return 0 on success
- */
-static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes,
- rpmScript script, int arg1, int arg2)
-{
- rpmRC stoprc, rc = RPMRC_OK;
- rpmTagVal stag = rpmScriptTag(script);
- FD_t sfd = NULL;
- int warn_only = (stag != RPMTAG_PREIN &&
- stag != RPMTAG_PREUN &&
- stag != RPMTAG_PRETRANS &&
- stag != RPMTAG_VERIFYSCRIPT);
- int selinux = !(rpmtsFlags(psm->ts) & RPMTRANS_FLAG_NOCONTEXTS);
-
- sfd = rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_START, stag, 0);
- if (sfd == NULL)
- sfd = rpmtsScriptFd(psm->ts);
-
- rpmtsSuspendResumeDBLock(psm->ts, 0);
- rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
- rc = rpmScriptRun(script, arg1, arg2, sfd,
- prefixes, warn_only, selinux, psm->ts->plugins);
- rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
- rpmtsSuspendResumeDBLock(psm->ts, 1);
-
- /* Map warn-only errors to "notfound" for script stop callback */
- stoprc = (rc != RPMRC_OK && warn_only) ? RPMRC_NOTFOUND : rc;
- rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_STOP, stag, stoprc);
-
- /*
- * Notify callback for all errors. "total" abused for warning/error,
- * rc only reflects whether the condition prevented install/erase
- * (which is only happens with %prein and %preun scriptlets) or not.
- */
- if (rc != RPMRC_OK) {
- if (warn_only) {
- rc = RPMRC_OK;
- }
- rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR, stag, rc);
- }
-
- return rc;
-}
-
-static rpmRC runInstScript(rpmpsm psm)
+static rpmRC runInstScript(rpmpsm psm, rpmTagVal scriptTag)
{
rpmRC rc = RPMRC_OK;
struct rpmtd_s pfx;
Header h = rpmteHeader(psm->te);
- rpmScript script = rpmScriptFromTag(h, psm->scriptTag);
+ rpmScript script = rpmScriptFromTag(h, scriptTag);
if (script) {
headerGet(h, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
- rc = runScript(psm, pfx.data, script, psm->scriptArg, -1);
+ rc = runScript(psm->ts, psm->te, h, pfx.data, script, psm->scriptArg, -1);
rpmtdFreeData(&pfx);
}
@@ -470,18 +262,19 @@ static rpmRC runInstScript(rpmpsm psm)
/**
* Execute triggers.
* @todo Trigger on any provides, not just package NVR.
- * @param psm package state machine data
+ * @param ts transaction set
+ * @param te transaction element
+ * @param sense trigger type
* @param sourceH header of trigger source
* @param trigH header of triggered package
* @param arg2
* @param triggersAlreadyRun
* @return
*/
-static rpmRC handleOneTrigger(const rpmpsm psm,
- Header sourceH, Header trigH,
+static rpmRC handleOneTrigger(rpmts ts, rpmte te, rpmsenseFlags sense,
+ Header sourceH, Header trigH, int countCorrection,
int arg2, unsigned char * triggersAlreadyRun)
{
- const rpmts ts = psm->ts;
rpmds trigger = rpmdsInit(rpmdsNew(trigH, RPMTAG_TRIGGERNAME, 0));
struct rpmtd_s pfx;
const char * sourceName = headerGetString(sourceH, RPMTAG_NAME);
@@ -496,10 +289,9 @@ static rpmRC handleOneTrigger(const rpmpsm psm,
(void) rpmdsSetNoPromote(trigger, 1);
while ((i = rpmdsNext(trigger)) >= 0) {
- struct rpmtd_s tindexes;
uint32_t tix;
- if (!(rpmdsFlags(trigger) & psm->sense))
+ if (!(rpmdsFlags(trigger) & sense))
continue;
if (!rstreq(rpmdsN(trigger), sourceName))
@@ -509,15 +301,7 @@ static rpmRC handleOneTrigger(const rpmpsm psm,
if (!rpmdsAnyMatchesDep(sourceH, trigger, 1))
continue;
- if (!headerGet(trigH, RPMTAG_TRIGGERINDEX, &tindexes, HEADERGET_MINMEM))
- continue;
-
- if (rpmtdSetIndex(&tindexes, i) < 0) {
- rpmtdFreeData(&tindexes);
- continue;
- }
-
- tix = rpmtdGetNumber(&tindexes);
+ tix = rpmdsTi(trigger);
if (triggersAlreadyRun == NULL || triggersAlreadyRun[tix] == 0) {
int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
@@ -526,10 +310,9 @@ static rpmRC handleOneTrigger(const rpmpsm psm,
rc = RPMRC_FAIL;
} else {
rpmScript script = rpmScriptFromTriggerTag(trigH,
- triggertag(psm->sense), tix);
- arg1 += psm->countCorrection;
- rc = runScript(psm, pfx.data, script, arg1, arg2);
-
+ triggertag(sense), RPMSCRIPT_NORMALTRIGGER, tix);
+ arg1 += countCorrection;
+ rc = runScript(ts, te, trigH, pfx.data, script, arg1, arg2);
if (triggersAlreadyRun != NULL)
triggersAlreadyRun[tix] = 1;
@@ -537,8 +320,6 @@ static rpmRC handleOneTrigger(const rpmpsm psm,
}
}
- rpmtdFreeData(&tindexes);
-
/*
* Each target/source header pair can only result in a single
* script being run.
@@ -555,9 +336,10 @@ static rpmRC handleOneTrigger(const rpmpsm psm,
/**
* Run trigger scripts in the database that are fired by this header.
* @param psm package state machine data
+ * @param sense trigger type
* @return 0 on success
*/
-static rpmRC runTriggers(rpmpsm psm)
+static rpmRC runTriggers(rpmpsm psm, rpmsenseFlags sense)
{
const rpmts ts = psm->ts;
int numPackage = -1;
@@ -575,14 +357,13 @@ static rpmRC runTriggers(rpmpsm psm)
{ Header triggeredH;
Header h = rpmteHeader(psm->te);
rpmdbMatchIterator mi;
- int countCorrection = psm->countCorrection;
- psm->countCorrection = 0;
mi = rpmtsInitIterator(ts, RPMDBI_TRIGGERNAME, N, 0);
- while((triggeredH = rpmdbNextIterator(mi)) != NULL)
- nerrors += handleOneTrigger(psm, h, triggeredH, numPackage, NULL);
+ while ((triggeredH = rpmdbNextIterator(mi)) != NULL) {
+ nerrors += handleOneTrigger(ts, NULL, sense, h, triggeredH,
+ 0, numPackage, NULL);
+ }
rpmdbFreeIterator(mi);
- psm->countCorrection = countCorrection;
headerFree(h);
}
@@ -592,9 +373,10 @@ static rpmRC runTriggers(rpmpsm psm)
/**
* Run triggers from this header that are fired by headers in the database.
* @param psm package state machine data
+ * @param sense trigger type
* @return 0 on success
*/
-static rpmRC runImmedTriggers(rpmpsm psm)
+static rpmRC runImmedTriggers(rpmpsm psm, rpmsenseFlags sense)
{
const rpmts ts = psm->ts;
unsigned char * triggersRun;
@@ -620,8 +402,10 @@ static rpmRC runImmedTriggers(rpmpsm psm)
mi = rpmtsInitIterator(ts, RPMDBI_NAME, trigName, 0);
- while((sourceH = rpmdbNextIterator(mi)) != NULL) {
- nerrors += handleOneTrigger(psm, sourceH, h,
+ while ((sourceH = rpmdbNextIterator(mi)) != NULL) {
+ nerrors += handleOneTrigger(psm->ts, psm->te,
+ sense, sourceH, h,
+ psm->countCorrection,
rpmdbGetIteratorCount(mi),
triggersRun);
}
@@ -641,7 +425,7 @@ exit:
static rpmpsm rpmpsmFree(rpmpsm psm)
{
if (psm) {
- rpmfiFree(psm->fi);
+ rpmfilesFree(psm->files);
rpmtsFree(psm->ts),
/* XXX rpmte not refcounted yet */
memset(psm, 0, sizeof(*psm)); /* XXX trash and burn */
@@ -650,12 +434,55 @@ static rpmpsm rpmpsmFree(rpmpsm psm)
return NULL;
}
-static rpmpsm rpmpsmNew(rpmts ts, rpmte te)
+static rpmpsm rpmpsmNew(rpmts ts, rpmte te, pkgGoal goal)
{
rpmpsm psm = xcalloc(1, sizeof(*psm));
psm->ts = rpmtsLink(ts);
- psm->fi = rpmfiLink(rpmteFI(te));
+ psm->files = rpmteFiles(te);
psm->te = te; /* XXX rpmte not refcounted yet */
+ if (!rpmteIsSource(te)) {
+ /*
+ * When we run scripts, we pass an argument which is the number of
+ * versions of this package that will be installed when we are
+ * finished.
+ */
+ int npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(te));
+ switch (goal) {
+ case PKG_INSTALL:
+ case PKG_PRETRANS:
+ psm->scriptArg = npkgs_installed + 1;
+ psm->countCorrection = 0;
+ break;
+ case PKG_ERASE:
+ psm->scriptArg = npkgs_installed - 1;
+ psm->countCorrection = -1;
+ break;
+ case PKG_VERIFY:
+ case PKG_POSTTRANS:
+ psm->scriptArg = npkgs_installed;
+ psm->countCorrection = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (goal == PKG_INSTALL) {
+ Header h = rpmteHeader(te);
+ psm->total = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE);
+ headerFree(h);
+ } else if (goal == PKG_ERASE) {
+ psm->total = rpmfilesFC(psm->files);
+ }
+ /* Fake up something for packages with no files */
+ if (psm->total == 0)
+ psm->total = 100;
+
+ if (goal == PKG_INSTALL || goal == PKG_ERASE) {
+ rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n", pkgGoalString(goal),
+ rpmteNEVRA(psm->te), rpmfilesFC(psm->files));
+ }
+
return psm;
}
@@ -685,14 +512,13 @@ void rpmpsmNotify(rpmpsm psm, int what, rpm_loff_t amount)
*/
static void markReplacedInstance(rpmts ts, rpmte te)
{
- /* this must match rpmNameVersionCompare in depends.c */
rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(te), 0);
rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(te));
rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(te));
rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(te));
- rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(te));
/* XXX shouldn't we also do this on colorless transactions? */
if (rpmtsColor(ts)) {
+ rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(te));
rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP, rpmteO(te));
}
@@ -703,323 +529,293 @@ static void markReplacedInstance(rpmts ts, rpmte te)
rpmdbFreeIterator(mi);
}
-static rpmRC rpmpsmNext(rpmpsm psm, pkgStage nstage)
+static rpmRC dbAdd(rpmts ts, rpmte te)
{
- psm->nstage = nstage;
- return rpmpsmStage(psm, psm->nstage);
+ Header h = rpmteHeader(te);
+ rpm_time_t installTime = (rpm_time_t) time(NULL);
+ rpmfs fs = rpmteGetFileStates(te);
+ rpm_count_t fc = rpmfsFC(fs);
+ rpm_fstate_t * fileStates = rpmfsGetStates(fs);
+ rpm_color_t tscolor = rpmtsColor(ts);
+ rpm_tid_t tid = rpmtsGetTid(ts);
+ rpmRC rc;
+
+ if (fileStates != NULL && fc > 0) {
+ headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc);
+ }
+
+ headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
+ headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1);
+ headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1);
+
+ (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
+ rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL;
+ (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
+
+ if (rc == RPMRC_OK) {
+ rpmteSetDBInstance(te, headerGetInstance(h));
+ packageHashAddEntry(ts->members->installedPackages,
+ headerGetInstance(h), te);
+ }
+ headerFree(h);
+ return rc;
}
-static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
+static rpmRC dbRemove(rpmts ts, rpmte te)
{
- const rpmts ts = psm->ts;
- rpmfi fi = psm->fi;
+ rpmRC rc;
+
+ (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
+ rc = (rpmdbRemove(rpmtsGetRdb(ts), rpmteDBInstance(te)) == 0) ?
+ RPMRC_OK : RPMRC_FAIL;
+ (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
+
+ if (rc == RPMRC_OK)
+ rpmteSetDBInstance(te, 0);
+ return rc;
+}
+
+static rpmRC rpmpsmUnpack(rpmpsm psm)
+{
+ char *failedFile = NULL;
+ int fsmrc = 0;
+ int saved_errno = 0;
rpmRC rc = RPMRC_OK;
- switch (stage) {
- case PSM_UNKNOWN:
- break;
- case PSM_INIT:
- rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n",
- psm->goalName, rpmteNEVR(psm->te), rpmfiFC(fi));
+ rpmpsmNotify(psm, RPMCALLBACK_INST_START, 0);
+ /* make sure first progress call gets made */
+ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, 0);
- /*
- * When we run scripts, we pass an argument which is the number of
- * versions of this package that will be installed when we are
- * finished.
- */
- psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
- if (psm->npkgs_installed < 0) {
- rc = RPMRC_FAIL;
- break;
+ if (!(rpmtsFlags(psm->ts) & RPMTRANS_FLAG_JUSTDB)) {
+ if (rpmfilesFC(psm->files) > 0) {
+ fsmrc = rpmPackageFilesInstall(psm->ts, psm->te, psm->files,
+ psm, &failedFile);
+ saved_errno = errno;
}
+ }
- if (psm->goal == PKG_INSTALL) {
- Header h = rpmteHeader(psm->te);
- psm->scriptArg = psm->npkgs_installed + 1;
+ /* XXX make sure progress reaches 100% */
+ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, psm->total);
+ rpmpsmNotify(psm, RPMCALLBACK_INST_STOP, psm->total);
+
+ if (fsmrc) {
+ char *emsg;
+ errno = saved_errno;
+ emsg = rpmfileStrerror(fsmrc);
+ rpmlog(RPMLOG_ERR,
+ _("unpacking of archive failed%s%s: %s\n"),
+ (failedFile != NULL ? _(" on file ") : ""),
+ (failedFile != NULL ? failedFile : ""),
+ emsg);
+ free(emsg);
+ rc = RPMRC_FAIL;
+
+ /* XXX notify callback on error. */
+ rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_UNPACK_ERROR, 0, 0);
+ }
+ free(failedFile);
+ return rc;
+}
- psm->amount = 0;
- psm->total = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE);
- /* fake up something for packages with no files */
- if (psm->total == 0)
- psm->total = 100;
+static rpmRC rpmpsmRemove(rpmpsm psm)
+{
+ char *failedFile = NULL;
+ int fsmrc = 0;
+
+ rpmpsmNotify(psm, RPMCALLBACK_UNINST_START, 0);
+ /* make sure first progress call gets made */
+ rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, 0);
+
+ /* XXX should't we log errors from here? */
+ if (!(rpmtsFlags(psm->ts) & RPMTRANS_FLAG_JUSTDB)) {
+ if (rpmfilesFC(psm->files) > 0) {
+ fsmrc = rpmPackageFilesRemove(psm->ts, psm->te, psm->files,
+ psm, &failedFile);
+ }
+ }
+ /* XXX make sure progress reaches 100% */
+ rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, psm->total);
+ rpmpsmNotify(psm, RPMCALLBACK_UNINST_STOP, psm->total);
- /* HACK: reinstall abuses te instance to remove old header */
- if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)
- markReplacedInstance(ts, psm->te);
+ free(failedFile);
+ return (fsmrc == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
- if (rpmfiFC(fi) > 0) {
- struct rpmtd_s filenames;
- rpmTag ftag = RPMTAG_FILENAMES;
-
- if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
- ftag = RPMTAG_ORIGFILENAMES;
- }
- headerGet(h, ftag, &filenames, HEADERGET_EXT);
- fi->apath = filenames.data; /* Ick.. */
- }
- headerFree(h);
- }
- if (psm->goal == PKG_ERASE) {
- psm->scriptArg = psm->npkgs_installed - 1;
+static rpmRC rpmPackageInstall(rpmts ts, rpmpsm psm)
+{
+ rpmRC rc = RPMRC_OK;
+ int once = 1;
- psm->amount = 0;
- psm->total = rpmfiFC(fi) ? rpmfiFC(fi) : 100;
- }
- break;
- case PSM_PRE:
- if (psm->goal == PKG_INSTALL) {
- psm->scriptTag = RPMTAG_PREIN;
- psm->sense = RPMSENSE_TRIGGERPREIN;
- psm->countCorrection = 0; /* XXX is this correct?!? */
-
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
- /* Run triggers in other package(s) this package sets off. */
- rc = rpmpsmNext(psm, PSM_TRIGGERS);
- if (rc) break;
-
- /* Run triggers in this package other package(s) set off. */
- rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
- if (rc) break;
- }
+ rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_INSTALL), 0);
+ while (once--) {
+ /* HACK: replacepkgs abuses te instance to remove old header */
+ if (rpmtsFilterFlags(psm->ts) & RPMPROB_FILTER_REPLACEPKG)
+ markReplacedInstance(ts, psm->te);
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
- rc = rpmpsmNext(psm, PSM_SCRIPT);
- if (rc) break;
- }
- }
- if (psm->goal == PKG_ERASE) {
- psm->scriptTag = RPMTAG_PREUN;
- psm->sense = RPMSENSE_TRIGGERUN;
- psm->countCorrection = -1;
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
+ /* Run triggers in other package(s) this package sets off. */
+ rc = runTriggers(psm, RPMSENSE_TRIGGERPREIN);
+ if (rc) break;
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
- /* Run triggers in this package other package(s) set off. */
- rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
- if (rc) break;
+ /* Run triggers in this package other package(s) set off. */
+ rc = runImmedTriggers(psm, RPMSENSE_TRIGGERPREIN);
+ if (rc) break;
+ }
- /* Run triggers in other package(s) this package sets off. */
- rc = rpmpsmNext(psm, PSM_TRIGGERS);
- if (rc) break;
- }
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
+ rc = runInstScript(psm, RPMTAG_PREIN);
+ if (rc) break;
+ }
+
+ rc = rpmpsmUnpack(psm);
+ if (rc) break;
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
- rc = rpmpsmNext(psm, PSM_SCRIPT);
+ /*
+ * If this package has already been installed, remove it from
+ * the database before adding the new one.
+ */
+ if (rpmteDBInstance(psm->te)) {
+ rc = dbRemove(ts, psm->te);
+ if (rc) break;
}
- break;
- case PSM_PROCESS:
- if (psm->goal == PKG_INSTALL) {
- int fsmrc = 0;
-
- rpmpsmNotify(psm, RPMCALLBACK_INST_START, 0);
- /* make sure first progress call gets made */
- rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, 0);
-
- if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) {
- rpmtransFlags oldtsflags;
- FD_t payload = rpmtePayload(psm->te);
- if (payload == NULL) {
- rc = RPMRC_FAIL;
- break;
- }
- oldtsflags = rpmtsFlags(ts);
- if (headerIsEntry(fi->h, RPMTAG_REMOVETID))
- (void) rpmtsSetFlags(ts, oldtsflags | RPMTRANS_FLAG_NOMD5);
+ rc = dbAdd(ts, psm->te);
+ if (rc) break;
- fsmrc = rpmPackageFilesInstall(psm->ts, psm->te, psm->fi,
- payload, psm, &psm->failedFile);
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
+ /* Run upper file triggers i. e. with higher priorities */
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_FILETRIGGER, 1);
+ if (rc) break;
- rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_UNCOMPRESS),
- fdOp(payload, FDSTAT_READ));
- rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_DIGEST),
- fdOp(payload, FDSTAT_DIGEST));
+ /* Run file triggers in this package other package(s) set off. */
+ rc = runImmedFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_FILETRIGGER, 1);
+ if (rc) break;
+ }
- if (headerIsEntry(fi->h, RPMTAG_REMOVETID))
- (void) rpmtsSetFlags(ts, oldtsflags);
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
+ rc = runInstScript(psm, RPMTAG_POSTIN);
+ if (rc) break;
+ }
- Fclose(payload);
- }
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
+ /* Run triggers in other package(s) this package sets off. */
+ rc = runTriggers(psm, RPMSENSE_TRIGGERIN);
+ if (rc) break;
- /* XXX make sure progress reaches 100% */
- rpmpsmNotify(psm, 0, psm->total);
- rpmpsmNotify(psm, RPMCALLBACK_INST_STOP, psm->total);
+ /* Run triggers in this package other package(s) set off. */
+ rc = runImmedTriggers(psm, RPMSENSE_TRIGGERIN);
+ if (rc) break;
- if (fsmrc) {
- rpmlog(RPMLOG_ERR,
- _("unpacking of archive failed%s%s: %s\n"),
- (psm->failedFile != NULL ? _(" on file ") : ""),
- (psm->failedFile != NULL ? psm->failedFile : ""),
- rpmcpioStrerror(fsmrc));
- rc = RPMRC_FAIL;
+ /* Run lower file triggers i. e. with lower priorities */
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_FILETRIGGER, 2);
+ if (rc) break;
- /* XXX notify callback on error. */
- rpmtsNotify(ts, psm->te, RPMCALLBACK_UNPACK_ERROR, 0, 0);
- break;
- }
+ /* Run file triggers in this package other package(s) set off. */
+ rc = runImmedFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_FILETRIGGER, 2);
+ if (rc) break;
}
- if (psm->goal == PKG_ERASE) {
- if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
- rpmpsmNotify(psm, RPMCALLBACK_UNINST_START, 0);
- /* make sure first progress call gets made */
- rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, 0);
+ rc = markReplacedFiles(psm);
+ }
- /* XXX should't we log errors from here? */
- if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) {
- rc = rpmPackageFilesRemove(psm->ts, psm->te, psm->fi,
- psm, &psm->failedFile);
- }
+ rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_INSTALL), 0);
- /* XXX make sure progress reaches 100% */
- rpmpsmNotify(psm, 0, psm->total);
- rpmpsmNotify(psm, RPMCALLBACK_UNINST_STOP, psm->total);
- }
- break;
- case PSM_POST:
- if (psm->goal == PKG_INSTALL) {
- rpm_time_t installTime = (rpm_time_t) time(NULL);
- rpmfs fs = rpmteGetFileStates(psm->te);
- rpm_count_t fc = rpmfsFC(fs);
- rpm_fstate_t * fileStates = rpmfsGetStates(fs);
- Header h = rpmteHeader(psm->te);
- rpm_color_t tscolor = rpmtsColor(ts);
-
- if (fileStates != NULL && fc > 0) {
- headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc);
- }
+ return rc;
+}
- headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1);
- headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1);
- headerFree(h);
-
- /*
- * If this package has already been installed, remove it from
- * the database before adding the new one.
- */
- if (rpmteDBInstance(psm->te)) {
- rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
- if (rc) break;
- }
+static rpmRC rpmPackageErase(rpmts ts, rpmpsm psm)
+{
+ rpmRC rc = RPMRC_OK;
+ int once = 1;
+
+ rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_ERASE), 0);
+ while (once--) {
- rc = rpmpsmNext(psm, PSM_RPMDB_ADD);
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
+ /* Run file triggers in this package other package(s) set off. */
+ rc = runImmedFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_FILETRIGGER, 1);
if (rc) break;
- psm->scriptTag = RPMTAG_POSTIN;
- psm->sense = RPMSENSE_TRIGGERIN;
- psm->countCorrection = 0;
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_FILETRIGGER, 1);
+ if (rc) break;
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
- rc = rpmpsmNext(psm, PSM_SCRIPT);
- if (rc) break;
- }
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
- /* Run triggers in other package(s) this package sets off. */
- rc = rpmpsmNext(psm, PSM_TRIGGERS);
- if (rc) break;
-
- /* Run triggers in this package other package(s) set off. */
- rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
- if (rc) break;
- }
+ /* Run triggers in this package other package(s) set off. */
+ rc = runImmedTriggers(psm, RPMSENSE_TRIGGERUN);
+ if (rc) break;
- rc = markReplacedFiles(psm);
+ /* Run triggers in other package(s) this package sets off. */
+ rc = runTriggers(psm, RPMSENSE_TRIGGERUN);
+ if (rc) break;
+ }
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN)) {
+ rc = runInstScript(psm, RPMTAG_PREUN);
+ if (rc) break;
}
- if (psm->goal == PKG_ERASE) {
- psm->scriptTag = RPMTAG_POSTUN;
- psm->sense = RPMSENSE_TRIGGERPOSTUN;
- psm->countCorrection = -1;
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
+ /* Run file triggers in this package other package(s) set off. */
+ rc = runImmedFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_FILETRIGGER, 2);
+ if (rc) break;
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
- rc = rpmpsmNext(psm, PSM_SCRIPT);
- if (rc) break;
- }
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_FILETRIGGER, 2);
+ if (rc) break;
+ }
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
- /* Run triggers in other package(s) this package sets off. */
- rc = rpmpsmNext(psm, PSM_TRIGGERS);
- if (rc) break;
- }
+ rc = rpmpsmRemove(psm);
+ if (rc) break;
- rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
- }
- break;
- case PSM_UNDO:
- break;
- case PSM_FINI:
- if (rc) {
- if (psm->failedFile)
- rpmlog(RPMLOG_ERR,
- _("%s failed on file %s: %s\n"),
- psm->goalName, psm->failedFile, rpmcpioStrerror(rc));
- else
- rpmlog(RPMLOG_ERR, _("%s failed: %s\n"),
- psm->goalName, rpmcpioStrerror(rc));
-
- /* XXX notify callback on error. */
- rpmtsNotify(ts, psm->te, RPMCALLBACK_CPIO_ERROR, 0, 0);
+ /* Run file triggers in other package(s) this package sets off. */
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERPOSTUN,
+ RPMSCRIPT_FILETRIGGER, 1);
}
- psm->failedFile = _free(psm->failedFile);
-
- fi->apath = _free(fi->apath);
- break;
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
+ rc = runInstScript(psm, RPMTAG_POSTUN);
+ if (rc) break;
+ }
- case PSM_CREATE:
- break;
- case PSM_DESTROY:
- break;
- case PSM_SCRIPT: /* Run current package scriptlets. */
- rc = runInstScript(psm);
- break;
- case PSM_TRIGGERS:
- /* Run triggers in other package(s) this package sets off. */
- rc = runTriggers(psm);
- break;
- case PSM_IMMED_TRIGGERS:
- /* Run triggers in this package other package(s) set off. */
- rc = runImmedTriggers(psm);
- break;
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
+ /* Run triggers in other package(s) this package sets off. */
+ rc = runTriggers(psm, RPMSENSE_TRIGGERPOSTUN);
+ if (rc) break;
- case PSM_RPMDB_ADD: {
- Header h = rpmteHeader(psm->te);
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERPOSTUN,
+ RPMSCRIPT_FILETRIGGER, 2);
+ }
+ if (rc) break;
- if (!headerIsEntry(h, RPMTAG_INSTALLTID)) {
- rpm_tid_t tid = rpmtsGetTid(ts);
- if (tid != 0 && tid != (rpm_tid_t)-1)
- headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) {
+ /* Prepare post transaction uninstall triggers */
+ rpmtriggersPrepPostUnTransFileTrigs(psm->ts, psm->te);
}
-
- (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
- rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL;
- (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
- if (rc == RPMRC_OK)
- rpmteSetDBInstance(psm->te, headerGetInstance(h));
- headerFree(h);
- } break;
-
- case PSM_RPMDB_REMOVE:
- (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
- rc = (rpmdbRemove(rpmtsGetRdb(ts), rpmteDBInstance(psm->te)) == 0) ?
- RPMRC_OK : RPMRC_FAIL;
- (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
- if (rc == RPMRC_OK)
- rpmteSetDBInstance(psm->te, 0);
- break;
+ rc = dbRemove(ts, psm->te);
+ }
- default:
- break;
- }
+ rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_ERASE), 0);
return rc;
}
static const char * pkgGoalString(pkgGoal goal)
{
- switch(goal) {
+ switch (goal) {
case PKG_INSTALL: return " install";
case PKG_ERASE: return " erase";
case PKG_VERIFY: return " verify";
@@ -1038,42 +834,39 @@ rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal)
if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
return RPMRC_OK;
- psm = rpmpsmNew(ts, te);
+ psm = rpmpsmNew(ts, te, goal);
if (rpmChrootIn() == 0) {
- rpmtsOpX op;
- psm->goal = goal;
- psm->goalName = pkgGoalString(goal);
+ /* Run pre transaction element hook for all plugins */
+ rc = rpmpluginsCallPsmPre(rpmtsPlugins(ts), te);
- switch (goal) {
- case PKG_INSTALL:
- case PKG_ERASE:
- /* Run pre transaction element hook for all plugins */
- if (rpmpluginsCallPsmPre(ts->plugins, te) != RPMRC_FAIL) {
-
- op = (goal == PKG_INSTALL) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
- rpmswEnter(rpmtsOp(psm->ts, op), 0);
-
- rc = rpmpsmNext(psm, PSM_INIT);
- if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
- if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
- if (!rc) rc = rpmpsmNext(psm, PSM_POST);
- (void) rpmpsmNext(psm, PSM_FINI);
-
- rpmswExit(rpmtsOp(psm->ts, op), 0);
+ if (!rc) {
+ switch (goal) {
+ case PKG_INSTALL:
+ rc = rpmPackageInstall(ts, psm);
+ break;
+ case PKG_ERASE:
+ rc = rpmPackageErase(ts, psm);
+ break;
+ case PKG_PRETRANS:
+ case PKG_POSTTRANS:
+ case PKG_VERIFY:
+ rc = runInstScript(psm, goal);
+ break;
+ case PKG_TRANSFILETRIGGERIN:
+ rc = runImmedFileTriggers(ts, te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_TRANSFILETRIGGER, 0);
+ break;
+ case PKG_TRANSFILETRIGGERUN:
+ rc = runImmedFileTriggers(ts, te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_TRANSFILETRIGGER, 0);
+ break;
+ default:
+ break;
}
-
- /* Run post transaction element hook for all plugins */
- rpmpluginsCallPsmPost(ts->plugins, te, rc);
- break;
- case PKG_PRETRANS:
- case PKG_POSTTRANS:
- case PKG_VERIFY:
- psm->scriptTag = goal;
- rc = rpmpsmStage(psm, PSM_SCRIPT);
- break;
- default:
- break;
}
+ /* Run post transaction element hook for all plugins */
+ rpmpluginsCallPsmPost(rpmtsPlugins(ts), te, rc);
+
/* XXX an error here would require a full abort */
(void) rpmChrootOut();
}
diff --git a/lib/query.c b/lib/query.c
index 6f2d593a7..d857ae5bc 100644
--- a/lib/query.c
+++ b/lib/query.c
@@ -14,6 +14,7 @@
#include <rpm/rpmdb.h>
#include <rpm/rpmfi.h>
#include <rpm/rpmts.h>
+#include <rpm/rpmsq.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmfileutil.h> /* rpmCleanPath */
@@ -30,21 +31,16 @@ static void printFileInfo(const char * name,
unsigned int mtime,
unsigned short rdev, unsigned int nlink,
const char * owner, const char * group,
- const char * linkto)
+ const char * linkto, time_t now)
{
char sizefield[21];
char ownerfield[8+1], groupfield[8+1];
char timefield[100];
time_t when = mtime; /* important if sizeof(int32_t) ! sizeof(time_t) */
struct tm * tm;
- static time_t now;
char * perms = rpmPermsString(mode);
char *link = NULL;
- /* On first call, grab snapshot of now */
- if (now == 0)
- now = time(NULL);
-
rstrlcpy(ownerfield, owner, sizeof(ownerfield));
rstrlcpy(groupfield, group, sizeof(groupfield));
@@ -99,6 +95,7 @@ int showQueryPackage(QVA_t qva, rpmts ts, Header h)
rpmfi fi = NULL;
rpmfiFlags fiflags = (RPMFI_NOHEADER | RPMFI_FLAGS_QUERY);
int rc = 0; /* XXX FIXME: need real return code */
+ time_t now = 0;
if (qva->qva_queryFormat != NULL) {
const char *errstr;
@@ -150,8 +147,12 @@ int showQueryPackage(QVA_t qva, rpmts ts, Header h)
if ((qva->qva_flags & QUERY_FOR_LICENSE) && !(fflags & RPMFILE_LICENSE))
continue;
- /* If not querying %ghost, skip ghost files. */
- if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
+ /* If querying only ... yes we know the drill, and this is dumb. */
+ if ((qva->qva_flags & QUERY_FOR_ARTIFACT) && !(fflags & RPMFILE_ARTIFACT))
+ continue;
+
+ /* Skip on attributes (eg from --noghost) */
+ if (fflags & qva->qva_fflags)
continue;
if (qva->qva_flags & QUERY_FOR_STATE) {
@@ -219,11 +220,14 @@ int showQueryPackage(QVA_t qva, rpmts ts, Header h)
}
if (fuser && fgroup) {
+ /* On first call, grab snapshot of now */
+ if (now == 0)
+ now = time(NULL);
if (buf) {
rpmlog(RPMLOG_NOTICE, "%s", buf);
}
printFileInfo(fn, fsize, fmode, fmtime, frdev, fnlink,
- fuser, fgroup, flink);
+ fuser, fgroup, flink, now);
} else {
rpmlog(RPMLOG_ERR,
_("package has neither file owner or id lists\n"));
@@ -262,7 +266,6 @@ void rpmDisplayQueryTags(FILE * fp)
}
fprintf(fp, "\n");
}
- rpmtdFreeData(names);
rpmtdFree(names);
}
@@ -274,7 +277,7 @@ static int rpmgiShowMatches(QVA_t qva, rpmts ts, rpmgi gi)
while ((h = rpmgiNext(gi)) != NULL) {
int rc;
- rpmdbCheckSignals();
+ rpmsqPoll();
if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
ec = rc;
headerFree(h);
@@ -292,7 +295,7 @@ static int rpmcliShowMatches(QVA_t qva, rpmts ts, rpmdbMatchIterator mi)
while ((h = rpmdbNextIterator(mi)) != NULL) {
int rc;
- rpmdbCheckSignals();
+ rpmsqPoll();
if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
ec = rc;
}
@@ -305,7 +308,7 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar
int i;
rpmdbMatchIterator mi = NULL;
- (void) rpmdbCheckSignals();
+ (void) rpmsqPoll();
if (qva->qva_showPackage == NULL)
goto exit;
@@ -385,6 +388,34 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar
}
break;
+ case RPMQV_WHATRECOMMENDS:
+ mi = rpmtsInitIterator(ts, RPMDBI_RECOMMENDNAME, arg, 0);
+ if (mi == NULL) {
+ rpmlog(RPMLOG_NOTICE, _("no package recommends %s\n"), arg);
+ }
+ break;
+
+ case RPMQV_WHATSUGGESTS:
+ mi = rpmtsInitIterator(ts, RPMDBI_SUGGESTNAME, arg, 0);
+ if (mi == NULL) {
+ rpmlog(RPMLOG_NOTICE, _("no package suggests %s\n"), arg);
+ }
+ break;
+
+ case RPMQV_WHATSUPPLEMENTS:
+ mi = rpmtsInitIterator(ts, RPMDBI_SUPPLEMENTNAME, arg, 0);
+ if (mi == NULL) {
+ rpmlog(RPMLOG_NOTICE, _("no package supplements %s\n"), arg);
+ }
+ break;
+
+ case RPMQV_WHATENHANCES:
+ mi = rpmtsInitIterator(ts, RPMDBI_ENHANCENAME, arg, 0);
+ if (mi == NULL) {
+ rpmlog(RPMLOG_NOTICE, _("no package enhances %s\n"), arg);
+ }
+ break;
+
case RPMQV_WHATPROVIDES:
if (arg[0] != '/' && arg[0] != '.') {
mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, arg, 0);
@@ -455,7 +486,9 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar
}
mi = rpmdbFreeIterator(mi);
if (! matches) {
- rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
+ size_t l = strlen(arg);
+ if (!(l > 4 && !strcmp(arg + l - 4, ".rpm")))
+ rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
} else {
mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
}
@@ -520,6 +553,7 @@ int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv)
break;
}
case RPMQV_SPECRPMS:
+ case RPMQV_SPECBUILTRPMS:
case RPMQV_SPECSRPM:
for (ARGV_const_t arg = argv; arg && *arg; arg++) {
ec += ((qva->qva_specQuery != NULL)
@@ -530,6 +564,14 @@ int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv)
for (ARGV_const_t arg = argv; arg && *arg; arg++) {
rpmdbMatchIterator mi = initQueryIterator(qva, ts, *arg);
ec += rpmcliShowMatches(qva, ts, mi);
+ if (mi == NULL && qva->qva_source == RPMQV_PACKAGE) {
+ size_t l = strlen(*arg);
+ if (l > 4 && !strcmp(*arg + l - 4, ".rpm")) {
+ rpmgi gi = rpmgiNew(ts, giFlags, argv);
+ ec += rpmgiShowMatches(qva, ts, gi);
+ rpmgiFree(gi);
+ }
+ }
rpmdbFreeIterator(mi);
}
break;
diff --git a/lib/relocation.c b/lib/relocation.c
new file mode 100644
index 000000000..3ba4cfeab
--- /dev/null
+++ b/lib/relocation.c
@@ -0,0 +1,560 @@
+#include "system.h"
+
+#include <rpm/rpmtypes.h>
+#include <rpm/header.h>
+#include <rpm/rpmfi.h>
+#include <rpm/rpmfileutil.h>
+#include <rpm/rpmmacro.h>
+#include <rpm/rpmlog.h>
+
+#include "lib/rpmfs.h"
+#include "lib/misc.h"
+
+#include "debug.h"
+
+/**
+ * Identify a file type.
+ * @param ft file type
+ * @return string to identify a file type
+ */
+static
+const char * ftstring (rpmFileTypes ft)
+{
+ switch (ft) {
+ case XDIR: return "directory";
+ case CDEV: return "char dev";
+ case BDEV: return "block dev";
+ case LINK: return "link";
+ case SOCK: return "sock";
+ case PIPE: return "fifo/pipe";
+ case REG: return "file";
+ default: return "unknown file type";
+ }
+}
+
+static char **duparray(char ** src, int size)
+{
+ char **dest = xmalloc((size+1) * sizeof(*dest));
+ for (int i = 0; i < size; i++) {
+ dest[i] = xstrdup(src[i]);
+ }
+ free(src);
+ return dest;
+}
+
+static int addPrefixes(Header h, rpmRelocation *relocations, int numRelocations)
+{
+ struct rpmtd_s validRelocs;
+ const char *validprefix;
+ const char ** actualRelocations;
+ int numActual = 0;
+
+ headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM);
+ /*
+ * If no relocations are specified (usually the case), then return the
+ * original header. If there are prefixes, however, then INSTPREFIXES
+ * should be added for RPM_INSTALL_PREFIX environ variables in scriptlets,
+ * but, since relocateFileList() can be called more than once for
+ * the same header, don't bother if already present.
+ */
+ if (relocations == NULL || numRelocations == 0) {
+ if (rpmtdCount(&validRelocs) > 0) {
+ if (!headerIsEntry(h, RPMTAG_INSTPREFIXES)) {
+ rpmtdSetTag(&validRelocs, RPMTAG_INSTPREFIXES);
+ headerPut(h, &validRelocs, HEADERPUT_DEFAULT);
+ }
+ rpmtdFreeData(&validRelocs);
+ }
+ return 0;
+ }
+
+ actualRelocations = xmalloc(rpmtdCount(&validRelocs) * sizeof(*actualRelocations));
+ rpmtdInit(&validRelocs);
+ while ((validprefix = rpmtdNextString(&validRelocs))) {
+ int j;
+ for (j = 0; j < numRelocations; j++) {
+ if (relocations[j].oldPath == NULL || /* XXX can't happen */
+ !rstreq(validprefix, relocations[j].oldPath))
+ continue;
+ /* On install, a relocate to NULL means skip the path. */
+ if (relocations[j].newPath) {
+ actualRelocations[numActual] = relocations[j].newPath;
+ numActual++;
+ }
+ break;
+ }
+ if (j == numRelocations) {
+ actualRelocations[numActual] = validprefix;
+ numActual++;
+ }
+ }
+ rpmtdFreeData(&validRelocs);
+
+ if (numActual) {
+ headerPutStringArray(h, RPMTAG_INSTPREFIXES, actualRelocations, numActual);
+ }
+ free(actualRelocations);
+ /* When any relocations are present there'll be more work to do */
+ return 1;
+}
+
+static void saveOrig(Header h)
+{
+ struct rpmtd_s td;
+ headerGet(h, RPMTAG_BASENAMES, &td, HEADERGET_MINMEM);
+ rpmtdSetTag(&td, RPMTAG_ORIGBASENAMES);
+ headerPut(h, &td, HEADERPUT_DEFAULT);
+ rpmtdFreeData(&td);
+
+ headerGet(h, RPMTAG_DIRNAMES, &td, HEADERGET_MINMEM);
+ rpmtdSetTag(&td, RPMTAG_ORIGDIRNAMES);
+ headerPut(h, &td, HEADERPUT_DEFAULT);
+ rpmtdFreeData(&td);
+
+ headerGet(h, RPMTAG_DIRINDEXES, &td, HEADERGET_MINMEM);
+ rpmtdSetTag(&td, RPMTAG_ORIGDIRINDEXES);
+ headerPut(h, &td, HEADERPUT_DEFAULT);
+ rpmtdFreeData(&td);
+}
+
+void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations,
+ rpmfs fs, Header h)
+{
+ char ** baseNames;
+ char ** dirNames;
+ uint32_t * dirIndexes;
+ rpm_count_t fileCount, dirCount;
+ int nrelocated = 0;
+ int fileAlloced = 0;
+ char * fn = NULL;
+ int haveRelocatedBase = 0;
+ size_t maxlen = 0;
+ int i, j;
+ struct rpmtd_s bnames, dnames, dindexes, fmodes;
+
+ if (!addPrefixes(h, relocations, numRelocations))
+ return;
+
+ if (rpmIsDebug()) {
+ rpmlog(RPMLOG_DEBUG, "========== relocations\n");
+ for (i = 0; i < numRelocations; i++) {
+ if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
+ if (relocations[i].newPath == NULL)
+ rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n",
+ i, relocations[i].oldPath);
+ else
+ rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
+ i, relocations[i].oldPath, relocations[i].newPath);
+ }
+ }
+
+ for (i = 0; i < numRelocations; i++) {
+ if (relocations[i].newPath == NULL) continue;
+ size_t len = strlen(relocations[i].newPath);
+ if (len > maxlen) maxlen = len;
+ }
+
+ headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM);
+ headerGet(h, RPMTAG_DIRINDEXES, &dindexes, HEADERGET_ALLOC);
+ headerGet(h, RPMTAG_DIRNAMES, &dnames, HEADERGET_MINMEM);
+ headerGet(h, RPMTAG_FILEMODES, &fmodes, HEADERGET_MINMEM);
+ /* TODO XXX ugh.. use rpmtd iterators & friends instead */
+ baseNames = bnames.data;
+ dirIndexes = dindexes.data;
+ fileCount = rpmtdCount(&bnames);
+ dirCount = rpmtdCount(&dnames);
+ /* XXX TODO: use rpmtdDup() instead */
+ dirNames = dnames.data = duparray(dnames.data, dirCount);
+ dnames.flags |= RPMTD_PTR_ALLOCED;
+
+ /*
+ * For all relocations, we go through sorted file/relocation lists
+ * backwards so that /usr/local relocations take precedence over /usr
+ * ones.
+ */
+
+ /* Relocate individual paths. */
+
+ for (i = fileCount - 1; i >= 0; i--) {
+ rpmFileTypes ft;
+ int fnlen;
+
+ size_t len = maxlen +
+ strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
+ if (len >= fileAlloced) {
+ fileAlloced = len * 2;
+ fn = xrealloc(fn, fileAlloced);
+ }
+
+assert(fn != NULL); /* XXX can't happen */
+ *fn = '\0';
+ fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
+
+ /*
+ * See if this file path needs relocating.
+ */
+ /*
+ * XXX FIXME: Would a bsearch of the (already sorted)
+ * relocation list be a good idea?
+ */
+ for (j = numRelocations - 1; j >= 0; j--) {
+ if (relocations[j].oldPath == NULL) /* XXX can't happen */
+ continue;
+ len = !rstreq(relocations[j].oldPath, "/")
+ ? strlen(relocations[j].oldPath)
+ : 0;
+
+ if (fnlen < len)
+ continue;
+ /*
+ * Only subdirectories or complete file paths may be relocated. We
+ * don't check for '\0' as our directory names all end in '/'.
+ */
+ if (!(fn[len] == '/' || fnlen == len))
+ continue;
+
+ if (!rstreqn(relocations[j].oldPath, fn, len))
+ continue;
+ break;
+ }
+ if (j < 0) continue;
+
+ rpmtdSetIndex(&fmodes, i);
+ ft = rpmfiWhatis(rpmtdGetNumber(&fmodes));
+
+ /* On install, a relocate to NULL means skip the path. */
+ if (relocations[j].newPath == NULL) {
+ if (ft == XDIR) {
+ /* Start with the parent, looking for directory to exclude. */
+ for (j = dirIndexes[i]; j < dirCount; j++) {
+ len = strlen(dirNames[j]) - 1;
+ while (len > 0 && dirNames[j][len-1] == '/') len--;
+ if (fnlen != len)
+ continue;
+ if (!rstreqn(fn, dirNames[j], fnlen))
+ continue;
+ break;
+ }
+ }
+ rpmfsSetAction(fs, i, FA_SKIPNSTATE);
+ rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
+ ftstring(ft), fn);
+ continue;
+ }
+
+ /* Relocation on full paths only, please. */
+ if (fnlen != len) continue;
+
+ rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
+ fn, relocations[j].newPath);
+ nrelocated++;
+
+ strcpy(fn, relocations[j].newPath);
+ { char * te = strrchr(fn, '/');
+ if (te) {
+ if (te > fn) te++; /* root is special */
+ fnlen = te - fn;
+ } else
+ te = fn + strlen(fn);
+ if (!rstreq(baseNames[i], te)) { /* basename changed too? */
+ if (!haveRelocatedBase) {
+ /* XXX TODO: use rpmtdDup() instead */
+ bnames.data = baseNames = duparray(baseNames, fileCount);
+ bnames.flags |= RPMTD_PTR_ALLOCED;
+ haveRelocatedBase = 1;
+ }
+ free(baseNames[i]);
+ baseNames[i] = xstrdup(te);
+ }
+ *te = '\0'; /* terminate new directory name */
+ }
+
+ /* Does this directory already exist in the directory list? */
+ for (j = 0; j < dirCount; j++) {
+ if (fnlen != strlen(dirNames[j]))
+ continue;
+ if (!rstreqn(fn, dirNames[j], fnlen))
+ continue;
+ break;
+ }
+
+ if (j < dirCount) {
+ dirIndexes[i] = j;
+ continue;
+ }
+
+ /* Creating new paths is a pita */
+ dirNames = dnames.data = xrealloc(dnames.data,
+ sizeof(*dirNames) * (dirCount + 1));
+
+ dirNames[dirCount] = xstrdup(fn);
+ dirIndexes[i] = dirCount;
+ dirCount++;
+ dnames.count++;
+ }
+
+ /* Finish off by relocating directories. */
+ for (i = dirCount - 1; i >= 0; i--) {
+ for (j = numRelocations - 1; j >= 0; j--) {
+
+ if (relocations[j].oldPath == NULL) /* XXX can't happen */
+ continue;
+ size_t len = !rstreq(relocations[j].oldPath, "/")
+ ? strlen(relocations[j].oldPath)
+ : 0;
+
+ if (len && !rstreqn(relocations[j].oldPath, dirNames[i], len))
+ continue;
+
+ /*
+ * Only subdirectories or complete file paths may be relocated. We
+ * don't check for '\0' as our directory names all end in '/'.
+ */
+ if (dirNames[i][len] != '/')
+ continue;
+
+ if (relocations[j].newPath) { /* Relocate the path */
+ char *t = NULL;
+ rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
+ /* Unfortunately rpmCleanPath strips the trailing slash.. */
+ (void) rpmCleanPath(t);
+ rstrcat(&t, "/");
+
+ rpmlog(RPMLOG_DEBUG,
+ "relocating directory %s to %s\n", dirNames[i], t);
+ free(dirNames[i]);
+ dirNames[i] = t;
+ nrelocated++;
+ }
+ }
+ }
+
+ /* Save original filenames in header and replace (relocated) filenames. */
+ if (nrelocated) {
+ saveOrig(h);
+ headerMod(h, &bnames);
+ headerMod(h, &dnames);
+ headerMod(h, &dindexes);
+ }
+
+ rpmtdFreeData(&bnames);
+ rpmtdFreeData(&dnames);
+ rpmtdFreeData(&dindexes);
+ rpmtdFreeData(&fmodes);
+ free(fn);
+}
+
+/**
+ * Macros to be defined from per-header tag values.
+ * @todo Should other macros be added from header when installing a package?
+ */
+static struct tagMacro {
+ const char *macroname; /*!< Macro name to define. */
+ rpmTag tag; /*!< Header tag to use for value. */
+} const tagMacros[] = {
+ { "name", RPMTAG_NAME },
+ { "version", RPMTAG_VERSION },
+ { "release", RPMTAG_RELEASE },
+ { "epoch", RPMTAG_EPOCH },
+ { NULL, 0 }
+};
+
+/**
+ * Define or undefine per-header macros.
+ * @param h header
+ * @param define define/undefine?
+ * @return 0 always
+ */
+static void rpmInstallLoadMacros(Header h, int define)
+{
+ const struct tagMacro * tagm;
+
+ for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
+ struct rpmtd_s td;
+ char *body;
+ if (!headerGet(h, tagm->tag, &td, HEADERGET_DEFAULT))
+ continue;
+
+ /*
+ * Undefine doesn't need the actual data for anything, but
+ * this way ensures we only undefine what was defined earlier.
+ */
+ if (define) {
+ body = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL);
+ rpmPushMacro(NULL, tagm->macroname, NULL, body, -1);
+ free(body);
+ } else {
+ rpmPopMacro(NULL, tagm->macroname);
+ }
+ rpmtdFreeData(&td);
+ }
+}
+
+int headerFindSpec(Header h)
+{
+ struct rpmtd_s filenames;
+ int specix = -1;
+
+ if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_MINMEM)) {
+ struct rpmtd_s td;
+ const char *str;
+
+ /* Try to find spec by file flags */
+ if (headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) {
+ rpmfileAttrs *flags;
+ while (specix < 0 && (flags = rpmtdNextUint32(&td))) {
+ if (*flags & RPMFILE_SPECFILE)
+ specix = rpmtdGetIndex(&td);
+ }
+ rpmtdFreeData(&td);
+ }
+ /* Still no spec? Look by filename. */
+ while (specix < 0 && (str = rpmtdNextString(&filenames))) {
+ if (rpmFileHasSuffix(str, ".spec"))
+ specix = rpmtdGetIndex(&filenames);
+ }
+ rpmtdFreeData(&filenames);
+ }
+ return specix;
+}
+
+/*
+ * Source rpms only contain basenames, on install the full paths are
+ * constructed with %{_specdir} and %{_sourcedir} macros. Because
+ * of that regular relocation wont work, we need to do it the hard
+ * way. Return spec file index on success, -1 on errors.
+ */
+int rpmRelocateSrpmFileList(Header h, const char *rootDir)
+{
+ int specix = headerFindSpec(h);
+
+ if (specix >= 0) {
+ const char *bn;
+ struct rpmtd_s filenames;
+ /* save original file names */
+ saveOrig(h);
+
+ headerDel(h, RPMTAG_BASENAMES);
+ headerDel(h, RPMTAG_DIRNAMES);
+ headerDel(h, RPMTAG_DIRINDEXES);
+
+ /* Macros need to be added before trying to create directories */
+ rpmInstallLoadMacros(h, 1);
+
+ /* ALLOC is needed as we modify the header */
+ headerGet(h, RPMTAG_ORIGBASENAMES, &filenames, HEADERGET_ALLOC);
+ for (int i = 0; (bn = rpmtdNextString(&filenames)); i++) {
+ int spec = (i == specix);
+ char *fn = rpmGenPath(rootDir,
+ spec ? "%{_specdir}" : "%{_sourcedir}", bn);
+ headerPutString(h, RPMTAG_OLDFILENAMES, fn);
+ free(fn);
+ }
+ rpmtdFreeData(&filenames);
+ headerConvert(h, HEADERCONV_COMPRESSFILELIST);
+ rpmInstallLoadMacros(h, 0);
+ }
+
+ return specix;
+}
+
+/* stupid bubble sort, but it's probably faster here */
+static void sortRelocs(rpmRelocation *relocations, int numRelocations)
+{
+ for (int i = 0; i < numRelocations; i++) {
+ int madeSwap = 0;
+ for (int j = 1; j < numRelocations; j++) {
+ rpmRelocation tmpReloc;
+ if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
+ relocations[j ].oldPath == NULL || /* XXX can't happen */
+ strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
+ continue;
+ tmpReloc = relocations[j - 1];
+ relocations[j - 1] = relocations[j];
+ relocations[j] = tmpReloc;
+ madeSwap = 1;
+ }
+ if (!madeSwap) break;
+ }
+}
+
+static char * stripTrailingChar(char * s, char c)
+{
+ char * t;
+ for (t = s + strlen(s) - 1; *t == c && t >= s; t--)
+ *t = '\0';
+ return s;
+}
+
+void rpmRelocationBuild(Header h, rpmRelocation *rawrelocs,
+ int *rnrelocs, rpmRelocation **rrelocs, uint8_t **rbadrelocs)
+{
+ int i;
+ struct rpmtd_s validRelocs;
+ rpmRelocation * relocs = NULL;
+ uint8_t *badrelocs = NULL;
+ int nrelocs = 0;
+
+ for (rpmRelocation *r = rawrelocs; r->oldPath || r->newPath; r++)
+ nrelocs++;
+
+ headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM);
+ relocs = xmalloc(sizeof(*relocs) * (nrelocs+1));
+
+ /* Build sorted relocation list from raw relocations. */
+ for (i = 0; i < nrelocs; i++) {
+ char * t;
+
+ /*
+ * Default relocations (oldPath == NULL) are handled in the UI,
+ * not rpmlib.
+ */
+ if (rawrelocs[i].oldPath == NULL) continue; /* XXX can't happen */
+
+ /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
+ too, but those are more trouble to fix up. :-( */
+ t = xstrdup(rawrelocs[i].oldPath);
+ relocs[i].oldPath = (t[0] == '/' && t[1] == '\0')
+ ? t
+ : stripTrailingChar(t, '/');
+
+ /* An old path w/o a new path is valid, and indicates exclusion */
+ if (rawrelocs[i].newPath) {
+ int valid = 0;
+ const char *validprefix;
+
+ t = xstrdup(rawrelocs[i].newPath);
+ relocs[i].newPath = (t[0] == '/' && t[1] == '\0')
+ ? t
+ : stripTrailingChar(t, '/');
+
+ /* FIX: relocations[i].oldPath == NULL */
+ /* Verify that the relocation's old path is in the header. */
+ rpmtdInit(&validRelocs);
+ while ((validprefix = rpmtdNextString(&validRelocs))) {
+ if (rstreq(validprefix, relocs[i].oldPath)) {
+ valid = 1;
+ break;
+ }
+ }
+
+ if (!valid) {
+ if (badrelocs == NULL)
+ badrelocs = xcalloc(nrelocs, sizeof(*badrelocs));
+ badrelocs[i] = 1;
+ }
+ } else {
+ relocs[i].newPath = NULL;
+ }
+ }
+ relocs[i].oldPath = NULL;
+ relocs[i].newPath = NULL;
+ sortRelocs(relocs, nrelocs);
+
+ rpmtdFreeData(&validRelocs);
+
+ *rrelocs = relocs;
+ *rnrelocs = nrelocs;
+ *rbadrelocs = badrelocs;
+}
+
diff --git a/lib/rpmal.c b/lib/rpmal.c
index 71f25916a..ca7ab053e 100644
--- a/lib/rpmal.c
+++ b/lib/rpmal.c
@@ -27,7 +27,7 @@ struct availablePackage_s {
rpmte p; /*!< transaction member */
rpmds provides; /*!< Provides: dependencies. */
rpmds obsoletes; /*!< Obsoletes: dependencies. */
- rpmfi fi; /*!< File info set. */
+ rpmfiles fi; /*!< File info set. */
};
/** \ingroup rpmdep
@@ -38,11 +38,6 @@ typedef struct availableIndexEntry_s {
unsigned int entryIx; /*!< Dependency index. */
} * availableIndexEntry;
-struct fileNameEntry_s {
- rpmsid dirName;
- rpmsid baseName;
-};
-
#undef HASHTYPE
#undef HTKEYTYPE
#undef HTDATATYPE
@@ -52,12 +47,18 @@ struct fileNameEntry_s {
#include "lib/rpmhash.H"
#include "lib/rpmhash.C"
+typedef struct availableIndexFileEntry_s {
+ rpmsid dirName;
+ rpmalNum pkgNum; /*!< Containing package index. */
+ unsigned int entryIx; /*!< Dependency index. */
+} * availableIndexFileEntry;
+
#undef HASHTYPE
#undef HTKEYTYPE
#undef HTDATATYPE
#define HASHTYPE rpmalFileHash
-#define HTKEYTYPE struct fileNameEntry_s
-#define HTDATATYPE struct availableIndexEntry_s
+#define HTKEYTYPE rpmsid
+#define HTDATATYPE struct availableIndexFileEntry_s
#include "lib/rpmhash.H"
#include "lib/rpmhash.C"
@@ -76,6 +77,7 @@ struct rpmal_s {
rpmtransFlags tsflags; /*!< Transaction control flags. */
rpm_color_t tscolor; /*!< Transaction color. */
rpm_color_t prefcolor; /*!< Transaction preferred color. */
+ fingerPrintCache fpc;
};
/**
@@ -87,6 +89,7 @@ static void rpmalFreeIndex(rpmal al)
al->providesHash = rpmalDepHashFree(al->providesHash);
al->obsoletesHash = rpmalDepHashFree(al->obsoletesHash);
al->fileHash = rpmalFileHashFree(al->fileHash);
+ al->fpc = fpCacheFree(al->fpc);
}
rpmal rpmalCreate(rpmstrPool pool, int delta, rpmtransFlags tsflags,
@@ -125,7 +128,7 @@ rpmal rpmalFree(rpmal al)
for (i = 0; i < al->size; i++, alp++) {
alp->obsoletes = rpmdsFree(alp->obsoletes);
alp->provides = rpmdsFree(alp->provides);
- alp->fi = rpmfiFree(alp->fi);
+ alp->fi = rpmfilesFree(alp->fi);
}
al->pool = rpmstrPoolFree(al->pool);
al->list = _free(al->list);
@@ -146,19 +149,6 @@ static int sidCmp(rpmsid a, rpmsid b)
return (a != b);
}
-static unsigned int fileHash(struct fileNameEntry_s file)
-{
- return file.dirName ^ file.baseName;
-}
-
-static int fileCompare(struct fileNameEntry_s one, struct fileNameEntry_s two)
-{
- int rc = (one.dirName != two.dirName);;
- if (!rc)
- rc = (one.baseName != two.baseName);
- return rc;
-}
-
void rpmalDel(rpmal al, rpmte p)
{
availablePackage alp;
@@ -181,11 +171,10 @@ void rpmalDel(rpmal al, rpmte p)
alp->p = NULL;
}
-static void rpmalAddFiles(rpmal al, rpmalNum pkgNum, rpmfi fi)
+static void rpmalAddFiles(rpmal al, rpmalNum pkgNum, rpmfiles fi)
{
- struct fileNameEntry_s fileName;
- struct availableIndexEntry_s fileEntry;
- int fc = rpmfiFC(fi);
+ struct availableIndexFileEntry_s fileEntry;
+ int fc = rpmfilesFC(fi);
rpm_color_t ficolor;
int skipdoc = (al->tsflags & RPMTRANS_FLAG_NODOCS);
int skipconf = (al->tsflags & RPMTRANS_FLAG_NOCONFIGS);
@@ -194,22 +183,20 @@ static void rpmalAddFiles(rpmal al, rpmalNum pkgNum, rpmfi fi)
for (int i = 0; i < fc; i++) {
/* Ignore colored provides not in our rainbow. */
- ficolor = rpmfiFColorIndex(fi, i);
+ ficolor = rpmfilesFColor(fi, i);
if (al->tscolor && ficolor && !(al->tscolor & ficolor))
continue;
/* Ignore files that wont be installed */
- if (skipdoc && (rpmfiFFlagsIndex(fi, i) & RPMFILE_DOC))
+ if (skipdoc && (rpmfilesFFlags(fi, i) & RPMFILE_DOC))
continue;
- if (skipconf && (rpmfiFFlagsIndex(fi, i) & RPMFILE_CONFIG))
+ if (skipconf && (rpmfilesFFlags(fi, i) & RPMFILE_CONFIG))
continue;
- fileName.dirName = rpmfiDNIdIndex(fi, rpmfiDIIndex(fi, i));
- fileName.baseName = rpmfiBNIdIndex(fi, i);
-
+ fileEntry.dirName = rpmfilesDNId(fi, rpmfilesDI(fi, i));
fileEntry.entryIx = i;
- rpmalFileHashAddEntry(al->fileHash, fileName, fileEntry);
+ rpmalFileHashAddEntry(al->fileHash, rpmfilesBNId(fi, i), fileEntry);
}
}
@@ -275,7 +262,7 @@ void rpmalAdd(rpmal al, rpmte p)
alp->provides = rpmdsLink(rpmteDS(p, RPMTAG_PROVIDENAME));
alp->obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME));
- alp->fi = rpmfiLink(rpmteFI(p));
+ alp->fi = rpmteFiles(p);
/*
* Transition-time safe-guard to catch private-pool uses.
@@ -286,7 +273,7 @@ void rpmalAdd(rpmal al, rpmte p)
* NULL pool from NULL alp->provides in numerous cases?
*/
{
- rpmstrPool fipool = rpmfiPool(alp->fi);
+ rpmstrPool fipool = rpmfilesPool(alp->fi);
rpmstrPool dspool = rpmdsPool(alp->provides);
assert(fipool == NULL || fipool == al->pool);
@@ -312,10 +299,10 @@ static void rpmalMakeFileIndex(rpmal al)
for (i = 0; i < al->size; i++) {
alp = al->list + i;
if (alp->fi != NULL)
- fileCnt += rpmfiFC(alp->fi);
+ fileCnt += rpmfilesFC(alp->fi);
}
al->fileHash = rpmalFileHashCreate(fileCnt/4+128,
- fileHash, fileCompare, NULL, NULL);
+ sidHash, sidCmp, NULL, NULL);
for (i = 0; i < al->size; i++) {
alp = al->list + i;
rpmalAddFiles(al, i, alp->fi);
@@ -403,7 +390,7 @@ rpmte * rpmalAllObsoletes(rpmal al, rpmds ds)
return ret;
}
-static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const char *fileName)
+static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const char *fileName, const rpmds filterds)
{
const char *slash;
rpmte * ret = NULL;
@@ -413,31 +400,45 @@ static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const char *fileName)
/* Split path into dirname and basename components for lookup */
if ((slash = strrchr(fileName, '/')) != NULL) {
- availableIndexEntry result;
+ availableIndexFileEntry result;
int resultCnt = 0;
size_t bnStart = (slash - fileName) + 1;
- struct fileNameEntry_s fne;
-
- fne.baseName = rpmstrPoolId(al->pool, fileName + bnStart, 0);
- fne.dirName = rpmstrPoolIdn(al->pool, fileName, bnStart, 0);
+ rpmsid baseName;
if (al->fileHash == NULL)
rpmalMakeFileIndex(al);
- rpmalFileHashGetEntry(al->fileHash, fne, &result, &resultCnt, NULL);
+ baseName = rpmstrPoolId(al->pool, fileName + bnStart, 0);
+ if (!baseName)
+ return NULL; /* no match possible */
+
+ rpmalFileHashGetEntry(al->fileHash, baseName, &result, &resultCnt, NULL);
if (resultCnt > 0) {
int i, found;
ret = xmalloc((resultCnt+1) * sizeof(*ret));
+ fingerPrint * fp = NULL;
+ rpmsid dirName = rpmstrPoolIdn(al->pool, fileName, bnStart, 1);
+
+ if (!al->fpc)
+ al->fpc = fpCacheCreate(1001, NULL);
+ fpLookup(al->fpc, rpmstrPoolStr(al->pool, dirName), fileName + bnStart, &fp);
for (found = i = 0; i < resultCnt; i++) {
availablePackage alp = al->list + result[i].pkgNum;
- if (alp->p == NULL) // deleted
+ if (alp->p == NULL) /* deleted */
+ continue;
+ /* ignore self-conflicts/obsoletes */
+ if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds)
+ continue;
+ if (result[i].dirName != dirName &&
+ !fpLookupEquals(al->fpc, fp, rpmstrPoolStr(al->pool, result[i].dirName), fileName + bnStart))
continue;
ret[found] = alp->p;
found++;
}
+ _free(fp);
ret[found] = NULL;
}
}
@@ -454,6 +455,8 @@ rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
availableIndexEntry result;
int resultCnt;
int obsolete;
+ rpmTagVal dtag;
+ rpmds filterds = NULL;
availablePackage alp;
int rc;
@@ -461,11 +464,14 @@ rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
if (al == NULL || ds == NULL || (nameId = rpmdsNId(ds)) == 0)
return ret;
- obsolete = (rpmdsTagN(ds) == RPMTAG_OBSOLETENAME);
+ dtag = rpmdsTagN(ds);
+ obsolete = (dtag == RPMTAG_OBSOLETENAME);
+ if (dtag == RPMTAG_OBSOLETENAME || dtag == RPMTAG_CONFLICTNAME)
+ filterds = ds;
name = rpmstrPoolStr(al->pool, nameId);
if (!obsolete && *name == '/') {
/* First, look for files "contained" in package ... */
- ret = rpmalAllFileSatisfiesDepend(al, name);
+ ret = rpmalAllFileSatisfiesDepend(al, name, filterds);
if (ret != NULL && *ret != NULL) {
rpmdsNotify(ds, "(added files)", 0);
return ret;
@@ -486,52 +492,70 @@ rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
for (found=i=0; i<resultCnt; i++) {
alp = al->list + result[i].pkgNum;
- if (alp->p == NULL) // deleted
+ if (alp->p == NULL) /* deleted */
continue;
- ix = result[i].entryIx;
-
- /* Obsoletes are on package name, filter out other provide matches */
- if (obsolete && !rstreq(rpmdsNIndex(alp->provides, ix), rpmteN(alp->p)))
+ /* ignore self-conflicts/obsoletes */
+ if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds)
continue;
+ ix = result[i].entryIx;
- rc = rpmdsCompareIndex(alp->provides, ix, ds, rpmdsIx(ds));
-
- if (rc) {
- rpmdsNotify(ds, "(added provide)", 0);
- ret[found] = alp->p;
- found++;
+ if (obsolete) {
+ /* Obsoletes are on package NEVR only */
+ rpmds thisds;
+ if (!rstreq(rpmdsNIndex(alp->provides, ix), rpmteN(alp->p)))
+ continue;
+ thisds = rpmteDS(alp->p, RPMTAG_NAME);
+ rc = rpmdsCompareIndex(thisds, rpmdsIx(thisds), ds, rpmdsIx(ds));
+ } else {
+ rc = rpmdsCompareIndex(alp->provides, ix, ds, rpmdsIx(ds));
}
+
+ if (rc)
+ ret[found++] = alp->p;
}
- if (found)
+ if (found) {
+ rpmdsNotify(ds, "(added provide)", 0);
ret[found] = NULL;
- else
+ } else {
ret = _free(ret);
+ }
return ret;
}
rpmte
-rpmalSatisfiesDepend(const rpmal al, const rpmds ds)
+rpmalSatisfiesDepend(const rpmal al, const rpmte te, const rpmds ds)
{
rpmte *providers = rpmalAllSatisfiesDepend(al, ds);
rpmte best = NULL;
+ int bestscore = 0;
if (providers) {
- if (al->tscolor) {
+ rpm_color_t dscolor = rpmdsColor(ds);
+ for (rpmte *p = providers; *p; p++) {
+ int score = 0;
+
/*
- * For colored dependencies, try to find a matching provider.
+ * For colored dependencies, prefer a matching colored provider.
* Otherwise prefer provider of ts preferred color.
*/
- rpm_color_t dscolor = rpmdsColor(ds);
- for (rpmte *p = providers; *p; p++) {
+ if (al->tscolor) {
rpm_color_t tecolor = rpmteColor(*p);
if (dscolor) {
- if (dscolor == tecolor) best = *p;
+ if (dscolor == tecolor) score += 2;
} else if (al->prefcolor) {
- if (al->prefcolor == tecolor) best = *p;
+ if (al->prefcolor == tecolor) score += 2;
}
- if (best) break;
+ }
+
+ /* Being self-provided is a bonus */
+ if (*p == te)
+ score += 1;
+
+ if (score > bestscore) {
+ bestscore = score;
+ best = *p;
}
}
/* if not decided by now, just pick first match */
@@ -541,27 +565,13 @@ rpmalSatisfiesDepend(const rpmal al, const rpmds ds)
return best;
}
-rpmte *
-rpmalAllInCollection(const rpmal al, const char *collname)
+unsigned int
+rpmalLookupTE(const rpmal al, const rpmte te)
{
- rpmte *ret = NULL;
- int found = 0;
rpmalNum pkgNum;
-
- if (!al || !al->list || !collname)
- return NULL;
-
- for (pkgNum = 0; pkgNum < al->size; pkgNum++) {
- rpmte p = al->list[pkgNum].p;
- if (rpmteHasCollection(p, collname)) {
- ret = xrealloc(ret, sizeof(*ret) * (found + 1 + 1));
- ret[found] = p;
- found++;
- }
- }
- if (ret) {
- ret[found] = NULL;
- }
-
- return ret;
+ for (pkgNum=0; pkgNum < al->size; pkgNum++)
+ if (al->list[pkgNum].p == te)
+ break;
+ return pkgNum < al->size ? pkgNum : (unsigned int)-1;
}
+
diff --git a/lib/rpmal.h b/lib/rpmal.h
index 6f1327bdb..10fe756d4 100644
--- a/lib/rpmal.h
+++ b/lib/rpmal.h
@@ -73,22 +73,21 @@ rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds);
/**
* Lookup best provider for a dependency in the available list
* @param al available list
+ * @param te transaction element
* @param ds dependency set
* @return best provider for the dependency, NULL if none
*/
RPM_GNUC_INTERNAL
-rpmte rpmalSatisfiesDepend(const rpmal al, const rpmds ds);
+rpmte rpmalSatisfiesDepend(const rpmal al, const rpmte te, const rpmds ds);
/**
- * Get a list of transaction elements that are memebers of a collection in the
- * available list
- * @param al available list
- * @param collname collection name to search for
- * @return NULL-terminated list of transaction elements that are
- * members of the specified collection
+ * Return index of a transaction element in the available list
+ * @param al available list
+ * @param te transaction element
+ * @return index, (unsigned int)-1 if not found
*/
RPM_GNUC_INTERNAL
-rpmte * rpmalAllInCollection(const rpmal al, const char * collname);
+unsigned int rpmalLookupTE(const rpmal al, const rpmte te);
#ifdef __cplusplus
}
diff --git a/lib/rpmarchive.h b/lib/rpmarchive.h
new file mode 100644
index 000000000..c864e5b56
--- /dev/null
+++ b/lib/rpmarchive.h
@@ -0,0 +1,149 @@
+#ifndef H_ARCHIVE
+#define H_ARCHIVE
+
+/** \ingroup payload
+ * \file lib/rpmarchive.h
+ * File archive (aka payload) API.
+ */
+
+#define RPMERR_CHECK_ERRNO -32768
+
+/** \ingroup payload
+ * Error codes for archive and file handling
+ */
+enum rpmfilesErrorCodes {
+ RPMERR_ITER_END = -1,
+ RPMERR_BAD_MAGIC = -2,
+ RPMERR_BAD_HEADER = -3,
+ RPMERR_HDR_SIZE = -4,
+ RPMERR_UNKNOWN_FILETYPE= -5,
+ RPMERR_MISSING_FILE = -6,
+ RPMERR_DIGEST_MISMATCH = -7,
+ RPMERR_INTERNAL = -8,
+ RPMERR_UNMAPPED_FILE = -9,
+ RPMERR_ENOENT = -10,
+ RPMERR_ENOTEMPTY = -11,
+ RPMERR_FILE_SIZE = -12,
+ RPMERR_ITER_SKIP = -13,
+ RPMERR_EXIST_AS_DIR = -14,
+
+ RPMERR_OPEN_FAILED = -32768,
+ RPMERR_CHMOD_FAILED = -32769,
+ RPMERR_CHOWN_FAILED = -32770,
+ RPMERR_WRITE_FAILED = -32771,
+ RPMERR_UTIME_FAILED = -32772,
+ RPMERR_UNLINK_FAILED = -32773,
+ RPMERR_RENAME_FAILED = -32774,
+ RPMERR_SYMLINK_FAILED = -32775,
+ RPMERR_STAT_FAILED = -32776,
+ RPMERR_LSTAT_FAILED = -32777,
+ RPMERR_MKDIR_FAILED = -32778,
+ RPMERR_RMDIR_FAILED = -32779,
+ RPMERR_MKNOD_FAILED = -32780,
+ RPMERR_MKFIFO_FAILED = -32781,
+ RPMERR_LINK_FAILED = -32782,
+ RPMERR_READLINK_FAILED = -32783,
+ RPMERR_READ_FAILED = -32784,
+ RPMERR_COPY_FAILED = -32785,
+ RPMERR_LSETFCON_FAILED = -32786,
+ RPMERR_SETCAP_FAILED = -32787,
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \ingroup payload
+ * Return formatted error message on payload handling failure.
+ * @param rc error code
+ * @return formatted error string (malloced)
+ */
+char * rpmfileStrerror(int rc);
+
+/** \ingroup payload
+ * Get new file iterator for writing the archive content.
+ * The returned rpmfi will only visit the files needing some content.
+ * You need to provide the content using rpmfiArchiveWrite() or
+ * rpmfiArchiveWriteFile(). Make sure to close the rpmfi with
+ * rpmfiArchiveClose() to get the trailer written.
+ * rpmfiSetFX() is not supported for this type of iterator.
+ * @param fd file
+ * @param files file info
+ * @return new rpmfi
+ */
+rpmfi rpmfiNewArchiveWriter(FD_t fd, rpmfiles files);
+
+/** \ingroup payload
+ * Get new file iterator for looping over the archive content.
+ * Returned rpmfi visites files in the order they are read from the payload.
+ * Content of the regular files can be retrieved with rpmfiArchiveRead() or
+ * rpmfiArchiveReadToFile() when they are visited with rpmfiNext().
+ * rpmfiSetFX() is not supported for this type of iterator.
+ * @param fd file
+ * @param files file info
+ * @param itype how to handle hard links. See rpmFileIter.
+ * @return new rpmfi
+ */
+ rpmfi rpmfiNewArchiveReader(FD_t fd, rpmfiles files, int itype);
+
+/** \ingroup payload
+ * Close payload archive
+ * @param fi file info
+ * @return > 0 on error
+ */
+int rpmfiArchiveClose(rpmfi fi);
+
+/** \ingroup payload
+ * Return current position in payload archive
+ * @param fi file info
+ * @return position
+ */
+rpm_loff_t rpmfiArchiveTell(rpmfi fi);
+
+/** \ingroup payload
+ * Write content into current file in archive
+ * @param fi file info
+ * @param buf pointer to content
+ * @param size number of bytes to write
+ * @return bytes actually written
+ */
+size_t rpmfiArchiveWrite(rpmfi fi, const void * buf, size_t size);
+
+/** \ingroup payload
+ * Write content from given file into current file in archive
+ * @param fi file info
+ * @param fd file descriptor of file to read
+ * @return > 0 on error
+ */
+int rpmfiArchiveWriteFile(rpmfi fi, FD_t fd);
+
+/** \ingroup payload
+ * Read content from current file in archive
+ * @param fi file info
+ * @param buf pointer to buffer
+ * @param size number of bytes to read
+ * @return bytes actually read
+ */
+size_t rpmfiArchiveRead(rpmfi fi, void * buf, size_t size);
+
+/** \ingroup payload
+ * Has current file content stored in the archive
+ * @param fi file info
+ * @ return 1 for regular files but 0 for hardlinks without content
+ */
+int rpmfiArchiveHasContent(rpmfi fi);
+
+/** \ingroup payload
+ * Write content from current file in archive to a file
+ * @param fi file info
+ * @param fd file descriptor of file to write to
+ * @param nodigest omit checksum check if 1
+ * @return > 0 on error
+ */
+int rpmfiArchiveReadToFile(rpmfi fi, FD_t fd, int nodigest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_ARCHIVE */
diff --git a/lib/rpmcallback.h b/lib/rpmcallback.h
index b3b05c6c1..f07892d0a 100644
--- a/lib/rpmcallback.h
+++ b/lib/rpmcallback.h
@@ -1,6 +1,12 @@
#ifndef _RPMCALLBACK_H
#define _RPMCALLBACK_H
+/** \ingroup rpmcallback
+ * \file lib/rpmcallback.h
+ *
+ * (un)install callbacks
+ */
+
#include <rpm/rpmtypes.h>
#ifdef __cplusplus
@@ -31,9 +37,22 @@ typedef enum rpmCallbackType_e {
RPMCALLBACK_SCRIPT_START = (1 << 16),
RPMCALLBACK_SCRIPT_STOP = (1 << 17),
RPMCALLBACK_INST_STOP = (1 << 18),
+ RPMCALLBACK_ELEM_PROGRESS = (1 << 19),
} rpmCallbackType;
-/**
+/** \ingroup rpmts
+ * Function pointer type for rpmtsSetNotifyCallback() triggered by
+ * rpmtsNotify()
+ *
+ * @param h related header or NULL
+ * @param what kind of notification (See RPMCALLBACK_ constants above)
+ * @param amount number of bytes/packages already processed or
+ * tag of the scriptlet involved
+ * or 0 or some other number
+ * @param total total number of bytes/packages to be processed or
+ * return code of the scriptlet or 0
+ * @param key result of rpmteKey() of related rpmte or 0
+ * @param data user data as passed to rpmtsSetNotifyCallback()
*/
typedef void * (*rpmCallbackFunction)
(const void * h,
diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c
index 0d3e95ad7..26a81efab 100644
--- a/lib/rpmchecksig.c
+++ b/lib/rpmchecksig.c
@@ -11,7 +11,7 @@
#include <rpm/rpmpgp.h>
#include <rpm/rpmcli.h>
#include <rpm/rpmfileutil.h> /* rpmMkTemp() */
-#include <rpm/rpmdb.h>
+#include <rpm/rpmsq.h>
#include <rpm/rpmts.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmstring.h>
@@ -19,7 +19,8 @@
#include "rpmio/rpmio_internal.h" /* fdSetBundle() */
#include "lib/rpmlead.h"
-#include "lib/signature.h"
+#include "lib/header_internal.h"
+#include "lib/rpmvs.h"
#include "debug.h"
@@ -35,14 +36,31 @@ static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen)
do {
uint8_t *pkt = NULL;
+ uint8_t *pkti = NULL;
size_t pktlen = 0;
+ size_t certlen;
/* Read pgp packet. */
if (pgpParsePkts(start, &pkt, &pktlen) == PGPARMOR_PUBKEY) {
- /* Import pubkey packet(s). */
- if (rpmtsImportPubkey(ts, pkt, pktlen) != RPMRC_OK) {
- rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn, keyno);
- res++;
+ pkti = pkt;
+
+ /* Iterate over certificates in pkt */
+ while (pktlen > 0) {
+ if (pgpPubKeyCertLen(pkti, pktlen, &certlen)) {
+ rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
+ keyno);
+ res++;
+ break;
+ }
+
+ /* Import pubkey certificate. */
+ if (rpmtsImportPubkey(ts, pkti, certlen) != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
+ keyno);
+ res++;
+ }
+ pkti += certlen;
+ pktlen -= certlen;
}
} else {
rpmlog(RPMLOG_ERR, _("%s: key %d not an armored public key.\n"),
@@ -102,308 +120,156 @@ int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv)
return res;
}
-/**
- * @todo If the GPG key was known available, the md5 digest could be skipped.
- */
-static int readFile(FD_t fd, const char * fn,
- rpmDigestBundle plbundle, rpmDigestBundle hdrbundle)
+static int readFile(FD_t fd, char **msg)
{
unsigned char buf[4*BUFSIZ];
ssize_t count;
- int rc = 1;
- Header h = NULL;
- char *msg = NULL;
-
- /* Read the header from the package. */
- if (rpmReadHeader(NULL, fd, &h, &msg) != RPMRC_OK) {
- rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n"), fn, msg);
- goto exit;
- }
-
- if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
- struct rpmtd_s utd;
-
- if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)){
- rpmlog(RPMLOG_ERR,
- _("%s: Immutable header region could not be read. "
- "Corrupted package?\n"), fn);
- goto exit;
- }
- rpmDigestBundleUpdate(hdrbundle, rpm_header_magic, sizeof(rpm_header_magic));
- rpmDigestBundleUpdate(hdrbundle, utd.data, utd.count);
- rpmtdFreeData(&utd);
- }
/* Read the payload from the package. */
while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
- if (count < 0) {
- rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
- goto exit;
- }
+ if (count < 0)
+ rasprintf(msg, _("Fread failed: %s"), Fstrerror(fd));
- rc = 0;
-
-exit:
- free(msg);
- headerFree(h);
- return rc;
+ return (count != 0);
}
-/*
- * Figure best available signature.
- * XXX TODO: Similar detection in rpmReadPackageFile(), unify these.
- */
-static rpmTagVal bestSig(Header sigh, int nosignatures, int nodigests)
-{
- rpmTagVal sigtag = 0;
- if (sigtag == 0 && !nosignatures) {
- if (headerIsEntry(sigh, RPMSIGTAG_DSA))
- sigtag = RPMSIGTAG_DSA;
- else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
- sigtag = RPMSIGTAG_RSA;
- else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
- sigtag = RPMSIGTAG_GPG;
- else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
- sigtag = RPMSIGTAG_PGP;
- }
- if (sigtag == 0 && !nodigests) {
- if (headerIsEntry(sigh, RPMSIGTAG_MD5))
- sigtag = RPMSIGTAG_MD5;
- else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
- sigtag = RPMSIGTAG_SHA1; /* XXX never happens */
- }
- return sigtag;
-}
+struct vfydata_s {
+ int seen;
+ int bad;
+};
-static const char *sigtagname(rpmTagVal sigtag, int upper)
+static rpmRC formatVerbose(struct rpmsinfo_s *sinfo, rpmRC sigres, const char *result, void *cbdata)
{
- const char *n = NULL;
-
- switch (sigtag) {
- case RPMSIGTAG_SIZE:
- n = (upper ? "SIZE" : "size");
- break;
- case RPMSIGTAG_SHA1:
- n = (upper ? "SHA1" : "sha1");
- break;
- case RPMSIGTAG_MD5:
- n = (upper ? "MD5" : "md5");
- break;
- case RPMSIGTAG_RSA:
- n = (upper ? "RSA" : "rsa");
- break;
- case RPMSIGTAG_PGP5: /* XXX legacy */
- case RPMSIGTAG_PGP:
- n = (upper ? "(MD5) PGP" : "(md5) pgp");
- break;
- case RPMSIGTAG_DSA:
- n = (upper ? "(SHA1) DSA" : "(sha1) dsa");
- break;
- case RPMSIGTAG_GPG:
- n = (upper ? "GPG" : "gpg");
- break;
- default:
- n = (upper ? "?UnknownSigatureType?" : "???");
- break;
- }
- return n;
+ char *vsmsg = rpmsinfoMsg(sinfo, sigres, result);
+ rpmlog(RPMLOG_NOTICE, " %s\n", vsmsg);
+ free(vsmsg);
+ return sigres;
}
-/*
- * Format sigcheck result for output, appending the message spew to buf and
- * bad/missing keyids to keyprob.
- *
- * In verbose mode, just dump it all. Otherwise ok signatures
- * are dumped lowercase, bad sigs uppercase and for PGP/GPG
- * if misssing/untrusted key it's uppercase in parenthesis
- * and stash the key id as <SIGTYPE>#<keyid>. Pfft.
- */
-static void formatResult(rpmTagVal sigtag, rpmRC sigres, const char *result,
- int havekey, char **keyprob, char **buf)
+/* Failures are uppercase, in parenthesis if NOKEY. Otherwise lowercase. */
+static rpmRC formatDefault(struct rpmsinfo_s *sinfo, rpmRC sigres, const char *result, void *cbdata)
{
- char *msg = NULL;
- if (rpmIsVerbose()) {
- rasprintf(&msg, " %s", result);
- } else {
- /* Check for missing / untrusted keys in result. */
- const char *signame = sigtagname(sigtag, (sigres != RPMRC_OK));
-
- if (havekey && (sigres == RPMRC_NOKEY || sigres == RPMRC_NOTTRUSTED)) {
- const char *tempKey = strstr(result, "ey ID");
- if (tempKey) {
- char keyid[sizeof(pgpKeyID_t) + 1];
- rstrlcpy(keyid, tempKey + 6, sizeof(keyid));
- rstrscat(keyprob, " ", signame, "#", keyid, NULL);
- }
- }
- rasprintf(&msg, (*keyprob ? "(%s) " : "%s "), signame);
- }
- rstrcat(buf, msg);
- free(msg);
+ struct vfydata_s *vd = cbdata;
+ vd->seen |= sinfo->type;
+ if (sigres != RPMRC_OK)
+ vd->bad |= sinfo->type;
+ return sigres;
}
-static int rpmpkgVerifySigs(rpmKeyring keyring, rpmQueryFlags flags,
- FD_t fd, const char *fn)
+rpmRC rpmpkgRead(rpmPlugins plugins, rpmKeyring keyring, rpmVSFlags flags, FD_t fd,
+ rpmsinfoCb cb, void *cbdata, Header *hdrp)
{
- char *buf = NULL;
- char *missingKeys = NULL;
- char *untrustedKeys = NULL;
- struct rpmtd_s sigtd;
- rpmTagVal sigtag;
- pgpDigParams sig = NULL;
- Header sigh = NULL;
- HeaderIterator hi = NULL;
char * msg = NULL;
- int res = 1; /* assume failure */
- rpmRC rc;
+ rpmRC xx, rc = RPMRC_FAIL; /* assume failure */
int failed = 0;
- int nodigests = !(flags & VERIFY_DIGEST);
- int nosignatures = !(flags & VERIFY_SIGNATURE);
- rpmDigestBundle plbundle = rpmDigestBundleNew();
- rpmDigestBundle hdrbundle = rpmDigestBundleNew();
-
- if ((rc = rpmLeadRead(fd, NULL, NULL, &msg)) != RPMRC_OK) {
- rpmlog(RPMLOG_ERR, "%s: %s\n", fn, msg);
- free(msg);
+ int leadtype = -1;
+ struct hdrblob_s sigblob, blob;
+ struct rpmvs_s *sigset = NULL;
+ Header h = NULL;
+ Header sigh = NULL;
+ rpmDigestBundle bundle = fdGetBundle(fd, 1); /* freed with fd */
+
+ memset(&blob, 0, sizeof(blob));
+ memset(&sigblob, 0, sizeof(sigblob));
+
+ if ((xx = rpmLeadRead(fd, &leadtype, &msg)) != RPMRC_OK) {
+ /* Avoid message spew on manifests */
+ if (xx == RPMRC_NOTFOUND)
+ msg = _free(msg);
+ rc = xx;
goto exit;
}
- rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
- switch (rc) {
- default:
- rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
- (msg && *msg ? msg : "\n"));
- msg = _free(msg);
+ /* Read the signature header. Might not be in a contiguous region. */
+ if (hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, &sigblob, &msg))
goto exit;
- break;
- case RPMRC_OK:
- if (sigh == NULL) {
- rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
- goto exit;
- }
- break;
- }
- msg = _free(msg);
-
- /* Grab a hint of what needs doing to avoid duplication. */
- sigtag = bestSig(sigh, nosignatures, nodigests);
-
- /* XXX RSA needs the hash_algo, so decode early. */
- if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP ||
- sigtag == RPMSIGTAG_DSA || sigtag == RPMSIGTAG_GPG) {
- unsigned int hashalgo;
- if (headerGet(sigh, sigtag, &sigtd, HEADERGET_DEFAULT)) {
- parsePGPSig(&sigtd, "package", fn, &sig);
- rpmtdFreeData(&sigtd);
- }
- if (sig == NULL) goto exit;
-
- /* XXX assume same hash_algo in header-only and header+payload */
- hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO);
- rpmDigestBundleAdd(plbundle, hashalgo, RPMDIGEST_NONE);
- rpmDigestBundleAdd(hdrbundle, hashalgo, RPMDIGEST_NONE);
- }
- if (headerIsEntry(sigh, RPMSIGTAG_PGP) ||
- headerIsEntry(sigh, RPMSIGTAG_PGP5) ||
- headerIsEntry(sigh, RPMSIGTAG_MD5)) {
- rpmDigestBundleAdd(plbundle, PGPHASHALGO_MD5, RPMDIGEST_NONE);
- }
- if (headerIsEntry(sigh, RPMSIGTAG_GPG)) {
- rpmDigestBundleAdd(plbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
- }
+ sigset = rpmvsCreate(&sigblob, flags);
- /* always do sha1 hash of header */
- rpmDigestBundleAdd(hdrbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
+ /* Initialize digests ranging over the header */
+ rpmvsInitDigests(sigset, RPMSIG_HEADER, bundle);
- /* Read the file, generating digest(s) on the fly. */
- fdSetBundle(fd, plbundle);
- if (readFile(fd, fn, plbundle, hdrbundle)) {
+ /* Read the header from the package. */
+ if (hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, &blob, &msg))
goto exit;
+
+ /* Fish interesting tags from the main header. This is a bit hacky... */
+ if (!(flags & (RPMVSF_NOPAYLOAD|RPMVSF_NEEDPAYLOAD)))
+ rpmvsAppend(sigset, &blob, RPMTAG_PAYLOADDIGEST);
+
+ /* Initialize digests ranging over the payload only */
+ rpmvsInitDigests(sigset, RPMSIG_PAYLOAD, bundle);
+
+
+ /* Verify header signatures and digests */
+ failed += rpmvsVerifyItems(plugins, sigset, (RPMSIG_HEADER), bundle, keyring, cb, cbdata);
+
+ /* Unless disabled, read the file, generating digest(s) on the fly. */
+ if (!(flags & RPMVSF_NEEDPAYLOAD)) {
+ if (readFile(fd, &msg))
+ goto exit;
}
- rasprintf(&buf, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
-
- hi = headerInitIterator(sigh);
- for (; headerNext(hi, &sigtd) != 0; rpmtdFreeData(&sigtd)) {
- char *result = NULL;
- int havekey = 0;
- DIGEST_CTX ctx = NULL;
- if (sigtd.data == NULL) /* XXX can't happen */
- continue;
-
- /* Clean up parameters from previous sigtag. */
- sig = pgpDigParamsFree(sig);
-
- switch (sigtd.tag) {
- case RPMSIGTAG_GPG:
- case RPMSIGTAG_PGP5: /* XXX legacy */
- case RPMSIGTAG_PGP:
- havekey = 1;
- case RPMSIGTAG_RSA:
- case RPMSIGTAG_DSA:
- if (nosignatures)
- continue;
- if (parsePGPSig(&sigtd, "package", fn, &sig))
- goto exit;
- ctx = rpmDigestBundleDupCtx(havekey ? plbundle : hdrbundle,
- pgpDigParamsAlgo(sig, PGPVAL_HASHALGO));
- break;
- case RPMSIGTAG_SHA1:
- if (nodigests)
- continue;
- ctx = rpmDigestBundleDupCtx(hdrbundle, PGPHASHALGO_SHA1);
- break;
- case RPMSIGTAG_MD5:
- if (nodigests)
- continue;
- ctx = rpmDigestBundleDupCtx(plbundle, PGPHASHALGO_MD5);
- break;
- default:
- continue;
- break;
- }
+ /* Verify signatures and digests ranging over the payload */
+ failed += rpmvsVerifyItems(plugins, sigset, (RPMSIG_PAYLOAD), bundle,
+ keyring, cb, cbdata);
+ failed += rpmvsVerifyItems(plugins, sigset, (RPMSIG_HEADER|RPMSIG_PAYLOAD), bundle,
+ keyring, cb, cbdata);
- rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, &result);
- rpmDigestFinal(ctx, NULL, NULL, 0);
+ if (failed == 0) {
+ /* Finally import the headers and do whatever required retrofits etc */
+ if (hdrp) {
+ if (hdrblobImport(&sigblob, 0, &sigh, &msg))
+ goto exit;
+ if (hdrblobImport(&blob, 0, &h, &msg))
+ goto exit;
- formatResult(sigtd.tag, rc, result, havekey,
- (rc == RPMRC_NOKEY ? &missingKeys : &untrustedKeys),
- &buf);
- free(result);
+ /* Append (and remap) signature tags to the metadata. */
+ if (headerMergeLegacySigs(h, sigh, &msg))
+ goto exit;
+ applyRetrofits(h, leadtype);
- if (rc != RPMRC_OK) {
- failed = 1;
+ /* Bump reference count for return. */
+ *hdrp = headerLink(h);
}
-
+ rc = RPMRC_OK;
}
- res = failed;
+exit:
+ if (rc && msg != NULL)
+ rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg);
+ free(msg);
+ free(sigblob.ei);
+ free(blob.ei);
+ headerFree(h);
+ headerFree(sigh);
+ rpmvsFree(sigset);
+ return rc;
+}
+
+static int rpmpkgVerifySigs(rpmPlugins plugins, rpmKeyring keyring, rpmVSFlags flags,
+ FD_t fd, const char *fn)
+{
+ int rc;
if (rpmIsVerbose()) {
- rpmlog(RPMLOG_NOTICE, "%s", buf);
+ rpmlog(RPMLOG_NOTICE, "%s:\n", fn);
+ rc = rpmpkgRead(plugins, keyring, flags, fd, formatVerbose, NULL, NULL);
} else {
- const char *ok = (failed ? _("NOT OK") : _("OK"));
- rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf, ok,
- missingKeys ? _(" (MISSING KEYS:") : "",
- missingKeys ? missingKeys : "",
- missingKeys ? _(") ") : "",
- untrustedKeys ? _(" (UNTRUSTED KEYS:") : "",
- untrustedKeys ? untrustedKeys : "",
- untrustedKeys ? _(")") : "");
+ struct vfydata_s vd = { 0, 0 };
+ rpmlog(RPMLOG_NOTICE, "%s:", fn);
+ rc = rpmpkgRead(plugins, keyring, flags, fd, formatDefault, &vd, NULL);
+ if (vd.seen & RPMSIG_DIGEST_TYPE) {
+ rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_DIGEST_TYPE) ?
+ _("DIGESTS") : _("digests"));
+ }
+ if (vd.seen & RPMSIG_SIGNATURE_TYPE) {
+ rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ?
+ _("SIGNATURES") : _("signatures"));
+ }
+ rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));
}
- free(missingKeys);
- free(untrustedKeys);
-
-exit:
- free(buf);
- rpmDigestBundleFree(hdrbundle);
- rpmDigestBundleFree(plbundle);
- fdSetBundle(fd, NULL); /* XXX avoid double-free from fd close */
- sigh = rpmFreeSignature(sigh);
- hi = headerFreeIterator(hi);
- pgpDigParamsFree(sig);
- return res;
+ return rc;
}
/* Wrapper around rpmkVerifySigs to preserve API */
@@ -412,7 +278,7 @@ int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
int rc = 1; /* assume failure */
if (ts && qva && fd && fn) {
rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
- rc = rpmpkgVerifySigs(keyring, qva->qva_flags, fd, fn);
+ rc = rpmpkgVerifySigs(rpmtsPlugins(ts), keyring, qva->qva_flags, fd, fn);
rpmKeyringFree(keyring);
}
return rc;
@@ -423,9 +289,12 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
const char * arg;
int res = 0;
rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
- rpmVerifyFlags verifyFlags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
-
- verifyFlags &= ~rpmcliQueryFlags;
+ rpmVSFlags vsflags = 0;
+
+ if (rpmcliQueryFlags & QUERY_DIGEST)
+ vsflags |= _RPMVSF_NODIGESTS;
+ if (rpmcliQueryFlags & QUERY_SIGNATURE)
+ vsflags |= _RPMVSF_NOSIGNATURES;
while ((arg = *argv++) != NULL) {
FD_t fd = Fopen(arg, "r.ufdio");
@@ -433,12 +302,12 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
arg, Fstrerror(fd));
res++;
- } else if (rpmpkgVerifySigs(keyring, verifyFlags, fd, arg)) {
+ } else if (rpmpkgVerifySigs(rpmtsPlugins(ts), keyring, vsflags, fd, arg)) {
res++;
}
Fclose(fd);
- rpmdbCheckSignals();
+ rpmsqPoll();
}
rpmKeyringFree(keyring);
return res;
diff --git a/lib/rpmcli.h b/lib/rpmcli.h
index cdb1f8ab4..7a88f8791 100644
--- a/lib/rpmcli.h
+++ b/lib/rpmcli.h
@@ -3,6 +3,8 @@
/** \ingroup rpmcli rpmbuild
* \file lib/rpmcli.h
+ *
+ * Parsing RPM command line arguments
*/
#include <popt.h>
@@ -67,6 +69,8 @@ rpmcliFini(poptContext optCon);
#define RPMCLI_POPT_NODIGEST -1030
#define RPMCLI_POPT_NOHDRCHK -1031
#define RPMCLI_POPT_NOCONTEXTS -1032
+#define RPMCLI_POPT_NOCAPS -1033
+#define RPMCLI_POPT_TARGETPLATFORM -1034
/* ==================================================================== */
/** \name RPMQV */
@@ -91,6 +95,11 @@ enum rpmQVSources_e {
RPMQV_HDRID, /*!< ... from header id (immutable header SHA1). */
RPMQV_TID, /*!< ... from install transaction id (time stamp). */
RPMQV_SPECSRPM, /*!< ... from spec file source (query only). */
+ RPMQV_WHATRECOMMENDS, /*!< ... from recommends db search. */
+ RPMQV_WHATSUGGESTS, /*!< ... from suggests db search. */
+ RPMQV_WHATSUPPLEMENTS, /*!< ... from supplements db search. */
+ RPMQV_WHATENHANCES, /*!< ... from enhances db search. */
+ RPMQV_SPECBUILTRPMS, /*!< ... from pkgs which would be built from spec */
};
typedef rpmFlags rpmQVSources;
@@ -124,7 +133,8 @@ enum rpmQueryFlags_e {
QUERY_FOR_DOCS = (1 << 25), /*!< query: from --docfiles */
QUERY_FOR_CONFIG = (1 << 26), /*!< query: from --configfiles */
QUERY_FOR_DUMPFILES = (1 << 27), /*!< query: from --dump */
- QUERY_FOR_LICENSE = (1 << 28) /*!< query: from --licensefiles */
+ QUERY_FOR_LICENSE = (1 << 28), /*!< query: from --licensefiles */
+ QUERY_FOR_ARTIFACT = (1 << 29), /*!< query: from --artifacts */
};
typedef rpmFlags rpmQueryFlags;
@@ -282,7 +292,8 @@ enum rpmInstallFlags_e {
INSTALL_FRESHEN = (1 << 6), /*!< from --freshen */
INSTALL_INSTALL = (1 << 7), /*!< from --install */
INSTALL_ERASE = (1 << 8), /*!< from --erase */
- INSTALL_ALLMATCHES = (1 << 9) /*!< from --allmatches */
+ INSTALL_ALLMATCHES = (1 << 9), /*!< from --allmatches */
+ INSTALL_REINSTALL = (1 << 10), /*!< from --reinstall */
};
typedef rpmFlags rpmInstallFlags;
@@ -343,7 +354,7 @@ struct rpmInstallArguments_s {
};
/** \ingroup rpmcli
- * Install/upgrade/freshen binary rpm package.
+ * Install/upgrade/freshen/reinstall binary rpm package.
* @param ts transaction set
* @param ia mode flags and parameters
* @param fileArgv array of package file names (NULL terminated)
diff --git a/lib/rpmdb.c b/lib/rpmdb.c
index 76425b4ca..4af21f69c 100644
--- a/lib/rpmdb.c
+++ b/lib/rpmdb.c
@@ -4,8 +4,6 @@
#include "system.h"
-#define _USE_COPY_LOAD /* XXX don't use DB_DBT_MALLOC (yet) */
-
#include <sys/file.h>
#include <utime.h>
#include <errno.h>
@@ -34,6 +32,8 @@
#include "lib/rpmdb_internal.h"
#include "lib/fprint.h"
#include "lib/header_internal.h" /* XXX for headerSetInstance() */
+#include "lib/backend/dbiset.h"
+#include "lib/misc.h"
#include "debug.h"
#undef HASHTYPE
@@ -48,39 +48,14 @@
#undef HTKEYTYPE
#undef HTDATATYPE
-static rpmDbiTag const dbiTags[] = {
- RPMDBI_PACKAGES,
- RPMDBI_NAME,
- RPMDBI_BASENAMES,
- RPMDBI_GROUP,
- RPMDBI_REQUIRENAME,
- RPMDBI_PROVIDENAME,
- RPMDBI_CONFLICTNAME,
- RPMDBI_OBSOLETENAME,
- RPMDBI_TRIGGERNAME,
- RPMDBI_DIRNAMES,
- RPMDBI_INSTALLTID,
- RPMDBI_SIGMD5,
- RPMDBI_SHA1HEADER,
-};
-
-#define dbiTagsMax (sizeof(dbiTags) / sizeof(rpmDbiTag))
-
-/* A single item from an index database (i.e. the "data returned"). */
-struct dbiIndexItem {
- unsigned int hdrNum; /*!< header instance in db */
- unsigned int tagNum; /*!< tag index in header */
-};
+typedef rpmRC (*idxfunc)(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
+ dbiIndexItem rec);
-/* Items retrieved from the index database.*/
-typedef struct _dbiIndexSet {
- struct dbiIndexItem * recs; /*!< array of records */
- unsigned int count; /*!< number of records */
- size_t alloced; /*!< alloced size */
-} * dbiIndexSet;
+static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag,
+ unsigned int hdrNum, Header h,
+ idxfunc idxupdate);
-static int addToIndex(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h);
-static unsigned int pkgInstance(dbiIndex dbi, int alloc);
+static rpmRC indexPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h);
static rpmdb rpmdbUnlink(rpmdb db);
static int buildIndexes(rpmdb db)
@@ -92,7 +67,7 @@ static int buildIndexes(rpmdb db)
rc += rpmdbOpenAll(db);
/* If the main db was just created, this is expected - dont whine */
- if (!(dbiFlags(db->_dbi[0]) & DBI_CREATED)) {
+ if (!(dbiFlags(db->db_pkgs) & DBI_CREATED)) {
rpmlog(RPMLOG_WARNING,
_("Generating %d missing index(es), please wait...\n"),
db->db_buildindex);
@@ -101,21 +76,27 @@ static int buildIndexes(rpmdb db)
/* Don't call us again */
db->db_buildindex = 0;
- dbSetFSync(db->db_dbenv, 0);
+ dbSetFSync(db, 0);
+
+ dbCtrl(db, RPMDB_CTRL_LOCK_RW);
mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
while ((h = rpmdbNextIterator(mi))) {
unsigned int hdrNum = headerGetInstance(h);
/* Build all secondary indexes which were created on open */
- for (int dbix = 1; dbix < dbiTagsMax; dbix++) {
- dbiIndex dbi = db->_dbi[dbix];
+ for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
+ dbiIndex dbi = db->db_indexes[dbix];
if (dbi && (dbiFlags(dbi) & DBI_CREATED)) {
- rc += addToIndex(dbi, dbiTags[dbix], hdrNum, h);
+ rc += indexPut(dbi, db->db_tags[dbix], hdrNum, h);
}
}
}
rpmdbFreeIterator(mi);
- dbSetFSync(db->db_dbenv, !db->cfg.db_no_fsync);
+
+ dbCtrl(db, DB_CTRL_INDEXSYNC);
+ dbCtrl(db, DB_CTRL_UNLOCK_RW);
+
+ dbSetFSync(db, !db->cfg.db_no_fsync);
return rc;
}
@@ -154,395 +135,135 @@ static int64_t splitEpoch(const char *s, const char **version)
return e;
}
-/** \ingroup dbi
- * Return handle for an index database.
- * @param db rpm database
- * @param rpmtag rpm tag
- * @param flags
- * @return index database handle
- */
-static dbiIndex rpmdbOpenIndex(rpmdb db, rpmDbiTagVal rpmtag, int flags)
+static int pkgdbOpen(rpmdb db, int flags, dbiIndex *dbip)
{
- int dbix;
- dbiIndex dbi = NULL;
int rc = 0;
+ dbiIndex dbi = NULL;
if (db == NULL)
- return NULL;
-
- for (dbix = 0; dbix < dbiTagsMax; dbix++) {
- if (rpmtag == dbiTags[dbix])
- break;
- }
- if (dbix >= dbiTagsMax)
- return NULL;
-
- /* Is this index already open ? */
- if ((dbi = db->_dbi[dbix]) != NULL)
- return dbi;
-
- errno = 0;
- dbi = NULL;
- rc = dbiOpen(db, rpmtag, &dbi, flags);
-
- if (rc) {
- static int _printed[32];
- if (!_printed[dbix & 0x1f]++)
- rpmlog(RPMLOG_ERR, _("cannot open %s index using db%d - %s (%d)\n"),
- rpmTagGetName(rpmtag), db->db_ver,
- (rc > 0 ? strerror(rc) : ""), rc);
- } else {
- db->_dbi[dbix] = dbi;
- int verifyonly = (flags & RPMDB_FLAG_VERIFYONLY);
- int rebuild = (db->db_flags & RPMDB_FLAG_REBUILD);
- if (dbiType(dbi) == DBI_PRIMARY) {
- /* Allocate based on max header instance number + some reserve */
- if (!verifyonly && (db->db_checked == NULL)) {
- db->db_checked = dbChkCreate(1024 + pkgInstance(dbi, 0) / 4,
- uintId, uintCmp, NULL, NULL);
- }
- /* If primary got created, we can safely run without fsync */
- if ((!verifyonly && (dbiFlags(dbi) & DBI_CREATED)) || db->cfg.db_no_fsync) {
- rpmlog(RPMLOG_DEBUG, "disabling fsync on database\n");
- db->cfg.db_no_fsync = 1;
- dbSetFSync(db->db_dbenv, 0);
- }
- } else { /* secondary index */
- if (!rebuild && !verifyonly && (dbiFlags(dbi) & DBI_CREATED)) {
- rpmlog(RPMLOG_DEBUG, "index %s needs creating\n", dbiName(dbi));
- db->db_buildindex++;
- if (db->db_buildindex == 1) {
- buildIndexes(db);
- }
- }
- }
- }
-
- return dbi;
-}
-
-union _dbswap {
- unsigned int ui;
- unsigned char uc[4];
-};
-
-#define _DBSWAP(_a) \
-\
- { unsigned char _b, *_c = (_a).uc; \
- _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
- _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
-\
- }
-
-/*
- * Ensure sufficient memory for nrecs of new records in dbiIndexSet.
- * Allocate in power of two sizes to avoid memory fragmentation, so
- * realloc is not always needed.
- */
-static inline void dbiGrowSet(dbiIndexSet set, unsigned int nrecs)
-{
- size_t need = (set->count + nrecs) * sizeof(*(set->recs));
- size_t alloced = set->alloced ? set->alloced : 1 << 4;
-
- while (alloced < need)
- alloced <<= 1;
-
- if (alloced != set->alloced) {
- set->recs = xrealloc(set->recs, alloced);
- set->alloced = alloced;
- }
-}
-
-/**
- * Convert retrieved data to index set.
- * @param dbi index database handle
- * @param data retrieved data
- * @retval setp (malloc'ed) index set
- * @return 0 on success
- */
-static int dbt2set(dbiIndex dbi, DBT * data, dbiIndexSet * setp)
-{
- int _dbbyteswapped = dbiByteSwapped(dbi);
- const char * sdbir;
- dbiIndexSet set;
- unsigned int i;
- dbiIndexType itype = dbiType(dbi);
-
- if (dbi == NULL || data == NULL || setp == NULL)
return -1;
+ /* Is this it already open ? */
+ if ((dbi = db->db_pkgs) != NULL)
+ goto exit;
- if ((sdbir = data->data) == NULL) {
- *setp = NULL;
- return 0;
- }
-
- set = xcalloc(1, sizeof(*set));
- dbiGrowSet(set, data->size / itype);
- set->count = data->size / itype;
-
- switch (itype) {
- default:
- case DBI_SECONDARY:
- for (i = 0; i < set->count; i++) {
- union _dbswap hdrNum, tagNum;
-
- memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
- sdbir += sizeof(hdrNum.ui);
- memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
- sdbir += sizeof(tagNum.ui);
- if (_dbbyteswapped) {
- _DBSWAP(hdrNum);
- _DBSWAP(tagNum);
- }
- /* remove tagged directory info */
- if (tagNum.ui & 0x80000000)
- tagNum.ui &= 0x0000ffff;
- set->recs[i].hdrNum = hdrNum.ui;
- set->recs[i].tagNum = tagNum.ui;
- }
- break;
- case DBI_PRIMARY:
- for (i = 0; i < set->count; i++) {
- union _dbswap hdrNum;
-
- memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
- sdbir += sizeof(hdrNum.ui);
- if (_dbbyteswapped) {
- _DBSWAP(hdrNum);
- }
- set->recs[i].hdrNum = hdrNum.ui;
- set->recs[i].tagNum = 0;
- }
- break;
- }
- *setp = set;
- return 0;
-}
-
-/**
- * Convert index set to database representation.
- * @param dbi index database handle
- * @param data retrieved data
- * @param set index set
- * @return 0 on success
- */
-static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
-{
- int _dbbyteswapped = dbiByteSwapped(dbi);
- char * tdbir;
- unsigned int i;
- dbiIndexType itype = dbiType(dbi);
-
- if (dbi == NULL || data == NULL || set == NULL)
- return -1;
+ rc = dbiOpen(db, RPMDBI_PACKAGES, &dbi, flags);
- data->size = set->count * itype;
- if (data->size == 0) {
- data->data = NULL;
- return 0;
- }
- tdbir = data->data = xmalloc(data->size);
+ if (rc == 0) {
+ int verifyonly = (flags & RPMDB_FLAG_VERIFYONLY);
- switch (itype) {
- default:
- case DBI_SECONDARY:
- for (i = 0; i < set->count; i++) {
- union _dbswap hdrNum, tagNum;
-
- memset(&hdrNum, 0, sizeof(hdrNum));
- memset(&tagNum, 0, sizeof(tagNum));
- hdrNum.ui = set->recs[i].hdrNum;
- tagNum.ui = set->recs[i].tagNum;
- if (_dbbyteswapped) {
- _DBSWAP(hdrNum);
- _DBSWAP(tagNum);
- }
- memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
- tdbir += sizeof(hdrNum.ui);
- memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
- tdbir += sizeof(tagNum.ui);
+ db->db_pkgs = dbi;
+ /* Allocate header checking cache .. based on some random number */
+ if (!verifyonly && (db->db_checked == NULL)) {
+ db->db_checked = dbChkCreate(567, uintId, uintCmp, NULL, NULL);
}
- break;
- case DBI_PRIMARY:
- for (i = 0; i < set->count; i++) {
- union _dbswap hdrNum;
-
- memset(&hdrNum, 0, sizeof(hdrNum));
- hdrNum.ui = set->recs[i].hdrNum;
- if (_dbbyteswapped) {
- _DBSWAP(hdrNum);
- }
- memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
- tdbir += sizeof(hdrNum.ui);
+ /* If primary got created, we can safely run without fsync */
+ if ((!verifyonly && (dbiFlags(dbi) & DBI_CREATED)) || db->cfg.db_no_fsync) {
+ rpmlog(RPMLOG_DEBUG, "disabling fsync on database\n");
+ db->cfg.db_no_fsync = 1;
+ dbSetFSync(db, 0);
}
- break;
+ } else {
+ rpmlog(RPMLOG_ERR, _("cannot open %s index using %s - %s (%d)\n"),
+ rpmTagGetName(RPMDBI_PACKAGES), db->db_descr,
+ (rc > 0 ? strerror(rc) : ""), rc);
}
- return 0;
-}
+exit:
+ if (rc == 0 && dbip)
+ *dbip = dbi;
-/* XXX assumes hdrNum is first int in dbiIndexItem */
-static int hdrNumCmp(const void * one, const void * two)
-{
- const unsigned int * a = one, * b = two;
- return (*a - *b);
+ return rc;
}
-/**
- * Append element(s) to set of index database items.
- * @param set set of index database items
- * @param recs array of items to append to set
- * @param nrecs number of items
- * @param recsize size of an array item
- * @param sortset should resulting set be sorted?
- * @return 0 success, 1 failure (bad args)
- */
-static int dbiAppendSet(dbiIndexSet set, const void * recs,
- int nrecs, size_t recsize, int sortset)
+static int indexOpen(rpmdb db, rpmDbiTagVal rpmtag, int flags, dbiIndex *dbip)
{
- const char * rptr = recs;
- size_t rlen = (recsize < sizeof(*(set->recs)))
- ? recsize : sizeof(*(set->recs));
-
- if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
- return 1;
+ int dbix, rc = 0;
+ dbiIndex dbi = NULL;
- dbiGrowSet(set, nrecs);
- memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
+ if (db == NULL)
+ return -1;
- while (nrecs-- > 0) {
- memcpy(set->recs + set->count, rptr, rlen);
- rptr += recsize;
- set->count++;
+ for (dbix = 0; dbix < db->db_ndbi; dbix++) {
+ if (rpmtag == db->db_tags[dbix])
+ break;
}
+ if (dbix >= db->db_ndbi)
+ return -1;
- if (sortset && set->count > 1)
- qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
-
- return 0;
-}
+ /* Is this index already open ? */
+ if ((dbi = db->db_indexes[dbix]) != NULL)
+ goto exit;
-/**
- * Remove element(s) from set of index database items.
- * @param set set of index database items
- * @param recs array of items to remove from set
- * @param nrecs number of items
- * @param recsize size of an array item
- * @param sorted array is already sorted?
- * @return 0 success, 1 failure (no items found)
- */
-static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
- size_t recsize, int sorted)
-{
- unsigned int from;
- unsigned int to = 0;
- unsigned int num = set->count;
- unsigned int numCopied = 0;
+ rc = dbiOpen(db, rpmtag, &dbi, flags);
- assert(set->count > 0);
- if (nrecs > 1 && !sorted)
- qsort(recs, nrecs, recsize, hdrNumCmp);
+ if (rc == 0) {
+ int verifyonly = (flags & RPMDB_FLAG_VERIFYONLY);
+ int rebuild = (db->db_flags & RPMDB_FLAG_REBUILD);
- for (from = 0; from < num; from++) {
- if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
- set->count--;
- continue;
+ db->db_indexes[dbix] = dbi;
+ if (!rebuild && !verifyonly && (dbiFlags(dbi) & DBI_CREATED)) {
+ rpmlog(RPMLOG_DEBUG, "index %s needs creating\n", dbiName(dbi));
+ db->db_buildindex++;
+ if (db->db_buildindex == 1) {
+ buildIndexes(db);
+ }
}
- if (from != to)
- set->recs[to] = set->recs[from]; /* structure assignment */
- to++;
- numCopied++;
+ } else {
+ rpmlog(RPMLOG_ERR, _("cannot open %s index using %s - %s (%d)\n"),
+ rpmTagGetName(rpmtag), db->db_descr,
+ (rc > 0 ? strerror(rc) : ""), rc);
}
- return (numCopied == num);
-}
-
-/* Count items in index database set. */
-static unsigned int dbiIndexSetCount(dbiIndexSet set)
-{
- return set->count;
-}
-
-/* Return record offset of header from element in index database set. */
-static unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno)
-{
- return set->recs[recno].hdrNum;
-}
-/* Return file index from element in index database set. */
-static unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno)
-{
- return set->recs[recno].tagNum;
-}
-
-/* Destroy set of index database items */
-static dbiIndexSet dbiIndexSetFree(dbiIndexSet set)
-{
- if (set) {
- free(set->recs);
- memset(set, 0, sizeof(*set)); /* trash and burn */
- free(set);
- }
- return NULL;
+exit:
+ if (rc == 0 && dbip)
+ *dbip = dbi;
+ return rc;
}
-static int dbiCursorGetToSet(dbiCursor dbc, const char *keyp, size_t keylen,
- dbiIndexSet *set)
+static rpmRC indexGet(dbiIndex dbi, const char *keyp, size_t keylen,
+ dbiIndexSet *set)
{
- int rc = EINVAL;
- if (dbc != NULL && set != NULL) {
- dbiIndex dbi = dbiCursorIndex(dbc);
- int cflags = DB_NEXT;
- DBT data, key;
- memset(&data, 0, sizeof(data));
- memset(&key, 0, sizeof(key));
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ if (dbi != NULL) {
+ dbiCursor dbc = dbiCursorInit(dbi, DBC_READ);
if (keyp) {
- key.data = (void *) keyp; /* discards const */
- key.size = keylen;
- cflags = DB_SET;
- }
-
- rc = dbiCursorGet(dbc, &key, &data, cflags);
+ if (keylen == 0)
+ keylen = strlen(keyp);
+ rc = idxdbGet(dbi, dbc, keyp, keylen, set, DBC_NORMAL_SEARCH);
+ } else {
+ do {
+ rc = idxdbGet(dbi, dbc, NULL, 0, set, DBC_NORMAL_SEARCH);
+ } while (rc == RPMRC_OK);
- if (rc == 0) {
- dbiIndexSet newset = NULL;
- dbt2set(dbi, &data, &newset);
- if (*set == NULL) {
- *set = newset;
- } else {
- dbiAppendSet(*set, newset->recs, newset->count,
- sizeof(*(newset->recs)), 0);
- dbiIndexSetFree(newset);
- }
- } else if (rc != DB_NOTFOUND) {
- rpmlog(RPMLOG_ERR,
- _("error(%d) getting \"%s\" records from %s index: %s\n"),
- rc, keyp ? keyp : "???", dbiName(dbi), db_strerror(rc));
+ /* If we got some results, not found is not an error */
+ if (rc == RPMRC_NOTFOUND && set != NULL)
+ rc = RPMRC_OK;
}
+
+ dbiCursorFree(dbi, dbc);
}
return rc;
}
-static int dbiGetToSet(dbiIndex dbi, const char *keyp, size_t keylen,
- dbiIndexSet *set)
+static rpmRC indexPrefixGet(dbiIndex dbi, const char *pfx, size_t plen,
+ dbiIndexSet *set)
{
- int rc = EINVAL;
- if (dbi != NULL && keyp != NULL) {
- dbiCursor dbc = dbiCursorInit(dbi, 0);
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
- if (keylen == 0) {
- keylen = strlen(keyp);
- if (keylen == 0)
- keylen++; /* XXX "/" fixup */
- }
+ if (dbi != NULL && pfx) {
+ dbiCursor dbc = dbiCursorInit(dbi, DBC_READ);
- rc = dbiCursorGetToSet(dbc, keyp, keylen, set);
+ if (plen == 0)
+ plen = strlen(pfx);
+ rc = idxdbGet(dbi, dbc, pfx, plen, set, DBC_PREFIX_SEARCH);
- dbiCursorFree(dbc);
+ dbiCursorFree(dbi, dbc);
}
return rc;
}
+
typedef struct miRE_s {
rpmTagVal tag; /*!< header tag */
rpmMireMode mode; /*!< pattern match mode */
@@ -556,8 +277,6 @@ typedef struct miRE_s {
struct rpmdbMatchIterator_s {
rpmdbMatchIterator mi_next;
- void * mi_keyp;
- size_t mi_keylen;
rpmdb mi_db;
rpmDbiTagVal mi_rpmtag;
dbiIndexSet mi_set;
@@ -583,92 +302,28 @@ struct rpmdbIndexIterator_s {
dbiIndex ii_dbi;
rpmDbiTag ii_rpmtag;
dbiCursor ii_dbc;
- DBT ii_key;
dbiIndexSet ii_set;
+ unsigned int *ii_hdrNums;
};
static rpmdb rpmdbRock;
static rpmdbMatchIterator rpmmiRock;
static rpmdbIndexIterator rpmiiRock;
-int rpmdbCheckTerminate(int terminate)
+void rpmAtExit(void)
{
- sigset_t newMask, oldMask;
- static int terminating = 0;
-
- if (terminating) return 0;
-
- (void) sigfillset(&newMask); /* block all signals */
- (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-
- if (rpmsqIsCaught(SIGINT) > 0
- || rpmsqIsCaught(SIGQUIT) > 0
- || rpmsqIsCaught(SIGHUP) > 0
- || rpmsqIsCaught(SIGTERM) > 0
- || rpmsqIsCaught(SIGPIPE) > 0
- || terminate)
- terminating = 1;
-
- if (terminating) {
- rpmdb db;
- rpmdbMatchIterator mi;
- rpmdbIndexIterator ii;
-
- while ((mi = rpmmiRock) != NULL) {
- rpmmiRock = mi->mi_next;
- mi->mi_next = NULL;
- rpmdbFreeIterator(mi);
- }
-
- while ((ii = rpmiiRock) != NULL) {
- rpmiiRock = ii->ii_next;
- ii->ii_next = NULL;
- rpmdbIndexIteratorFree(ii);
- }
-
- while ((db = rpmdbRock) != NULL) {
- rpmdbRock = db->db_next;
- db->db_next = NULL;
- (void) rpmdbClose(db);
- }
- }
- sigprocmask(SIG_SETMASK, &oldMask, NULL);
- return terminating;
-}
-
-int rpmdbCheckSignals(void)
-{
- if (rpmdbCheckTerminate(0)) {
- rpmlog(RPMLOG_DEBUG, "Exiting on signal...\n");
- exit(EXIT_FAILURE);
- }
- return 0;
-}
+ rpmdb db;
+ rpmdbMatchIterator mi;
+ rpmdbIndexIterator ii;
-/**
- * Block all signals, returning previous signal mask.
- */
-static int blockSignals(sigset_t * oldMask)
-{
- sigset_t newMask;
+ while ((mi = rpmmiRock) != NULL)
+ rpmdbFreeIterator(mi);
- (void) sigfillset(&newMask); /* block all signals */
- (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
- (void) sigdelset(&newMask, SIGINT);
- (void) sigdelset(&newMask, SIGQUIT);
- (void) sigdelset(&newMask, SIGHUP);
- (void) sigdelset(&newMask, SIGTERM);
- (void) sigdelset(&newMask, SIGPIPE);
- return sigprocmask(SIG_BLOCK, &newMask, NULL);
-}
+ while ((ii = rpmiiRock) != NULL)
+ rpmdbIndexIteratorFree(ii);
-/**
- * Restore signal mask.
- */
-static int unblockSignals(sigset_t * oldMask)
-{
- (void) rpmdbCheckSignals();
- return sigprocmask(SIG_SETMASK, oldMask, NULL);
+ while ((db = rpmdbRock) != NULL)
+ (void) rpmdbClose(db);
}
rpmop rpmdbOp(rpmdb rpmdb, rpmdbOpX opx)
@@ -705,20 +360,18 @@ int rpmdbOpenAll(rpmdb db)
if (db == NULL) return -2;
- for (int dbix = 0; dbix < dbiTagsMax; dbix++) {
- dbiIndex dbi = db->_dbi[dbix];
- if (dbi == NULL) {
- rc += (rpmdbOpenIndex(db, dbiTags[dbix], db->db_flags) == NULL);
- }
+ rc = pkgdbOpen(db, db->db_flags, NULL);
+ for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
+ rc += indexOpen(db, db->db_tags[dbix], db->db_flags, NULL);
}
return rc;
}
-static int dbiForeach(dbiIndex *dbis,
+static int dbiForeach(dbiIndex *dbis, int ndbi,
int (*func) (dbiIndex, unsigned int), int del)
{
int xx, rc = 0;
- for (int dbix = dbiTagsMax; --dbix >= 0; ) {
+ for (int dbix = ndbi; --dbix >= 0; ) {
if (dbis[dbix] == NULL)
continue;
xx = func(dbis[dbix], 0);
@@ -733,12 +386,16 @@ int rpmdbClose(rpmdb db)
{
rpmdb * prev, next;
int rc = 0;
- int dbmode;
if (db == NULL)
goto exit;
- dbmode = db->db_mode;
+ prev = &rpmdbRock;
+ while ((next = *prev) != NULL && next != db)
+ prev = &next->db_next;
+ if (!next)
+ goto exit;
+
(void) rpmdbUnlink(db);
if (db->nrefs > 0)
@@ -746,19 +403,19 @@ int rpmdbClose(rpmdb db)
/* Always re-enable fsync on close of rw-database */
if ((db->db_mode & O_ACCMODE) != O_RDONLY)
- dbSetFSync(db->db_dbenv, 1);
+ dbSetFSync(db, 1);
- rc = dbiForeach(db->_dbi, dbiClose, 1);
+ if (db->db_pkgs)
+ rc = dbiClose(db->db_pkgs, 0);
+ rc += dbiForeach(db->db_indexes, db->db_ndbi, dbiClose, 1);
db->db_root = _free(db->db_root);
db->db_home = _free(db->db_home);
db->db_fullpath = _free(db->db_fullpath);
db->db_checked = dbChkFree(db->db_checked);
- db->_dbi = _free(db->_dbi);
+ db->db_indexes = _free(db->db_indexes);
+ db->db_descr = _free(db->db_descr);
- prev = &rpmdbRock;
- while ((next = *prev) != NULL && next != db)
- prev = &next->db_next;
if (next) {
*prev = next->db_next;
next->db_next = NULL;
@@ -766,36 +423,39 @@ int rpmdbClose(rpmdb db)
db = _free(db);
- if (rpmdbRock == NULL && (dbmode & (O_RDWR|O_WRONLY)) != 0) {
- (void) rpmsqEnable(-SIGHUP, NULL);
- (void) rpmsqEnable(-SIGINT, NULL);
- (void) rpmsqEnable(-SIGTERM, NULL);
- (void) rpmsqEnable(-SIGQUIT, NULL);
- (void) rpmsqEnable(-SIGPIPE, NULL);
+ if (rpmdbRock == NULL) {
+ rpmsqActivate(0);
}
exit:
return rc;
}
-
-int rpmdbSync(rpmdb db)
-{
- if (db == NULL) return 0;
-
- return dbiForeach(db->_dbi, dbiSync, 0);
-}
-
-int rpmdbSuspendResumeDBLock(rpmdb db, int mode)
-{
- if (db == NULL) return 0;
- return dbiForeach(db->_dbi, mode ? dbiResumeDBLock : dbiSuspendDBLock, 0);
-}
-
static rpmdb newRpmdb(const char * root, const char * home,
int mode, int perms, int flags)
{
rpmdb db = NULL;
char * db_home = rpmGetPath((home && *home) ? home : "%{_dbpath}", NULL);
+ static rpmDbiTag const dbiTags[] = {
+ RPMDBI_NAME,
+ RPMDBI_BASENAMES,
+ RPMDBI_GROUP,
+ RPMDBI_REQUIRENAME,
+ RPMDBI_PROVIDENAME,
+ RPMDBI_CONFLICTNAME,
+ RPMDBI_OBSOLETENAME,
+ RPMDBI_TRIGGERNAME,
+ RPMDBI_DIRNAMES,
+ RPMDBI_INSTALLTID,
+ RPMDBI_SIGMD5,
+ RPMDBI_SHA1HEADER,
+ RPMDBI_FILETRIGGERNAME,
+ RPMDBI_TRANSFILETRIGGERNAME,
+ RPMDBI_RECOMMENDNAME,
+ RPMDBI_SUGGESTNAME,
+ RPMDBI_SUPPLEMENTNAME,
+ RPMDBI_ENHANCENAME,
+ };
+
if (!(db_home && db_home[0] != '%')) {
rpmlog(RPMLOG_ERR, _("no dbpath has been set\n"));
free(db_home);
@@ -815,8 +475,10 @@ static rpmdb newRpmdb(const char * root, const char * home,
db->db_fullpath = rpmGenPath(db->db_root, db->db_home, NULL);
/* XXX remove environment after chrooted operations, for now... */
db->db_remove_env = (!rstreq(db->db_root, "/") ? 1 : 0);
- db->_dbi = xcalloc(dbiTagsMax, sizeof(*db->_dbi));
- db->db_ver = DB_VERSION_MAJOR; /* XXX just to put something in messages */
+ db->db_tags = dbiTags;
+ db->db_ndbi = sizeof(dbiTags) / sizeof(rpmDbiTag);
+ db->db_indexes = xcalloc(db->db_ndbi, sizeof(*db->db_indexes));
+ db->db_descr = xstrdup("unknown db");
db->nrefs = 0;
return rpmdbLink(db);
}
@@ -838,19 +500,15 @@ static int openDatabase(const char * prefix,
if (db == NULL)
return 1;
- /* Try to ensure db home exists, error out if we cant even create */
+ /* Try to ensure db home exists, error out if we can't even create */
rc = rpmioMkpath(rpmdbHome(db), 0755, getuid(), getgid());
if (rc == 0) {
- if (rpmdbRock == NULL && (db->db_mode & (O_RDWR|O_WRONLY)) != 0) {
- (void) rpmsqEnable(SIGHUP, NULL);
- (void) rpmsqEnable(SIGINT, NULL);
- (void) rpmsqEnable(SIGTERM, NULL);
- (void) rpmsqEnable(SIGQUIT, NULL);
- (void) rpmsqEnable(SIGPIPE, NULL);
+ if (rpmdbRock == NULL) {
+ rpmsqActivate(1);
}
/* Just the primary Packages database opened here */
- rc = (rpmdbOpenIndex(db, RPMDBI_PACKAGES, db->db_flags) != NULL) ? 0 : -2;
+ rc = pkgdbOpen(db, db->db_flags, NULL);
}
if (rc || justCheck || dbp == NULL)
@@ -911,7 +569,10 @@ int rpmdbVerify(const char * prefix)
int xx;
rc = rpmdbOpenAll(db);
- rc = dbiForeach(db->_dbi, dbiVerify, 0);
+
+ if (db->db_pkgs)
+ rc += dbiVerify(db->db_pkgs, 0);
+ rc += dbiForeach(db->db_indexes, db->db_ndbi, dbiVerify, 0);
xx = rpmdbClose(db);
if (xx && rc == 0) rc = xx;
@@ -920,7 +581,7 @@ int rpmdbVerify(const char * prefix)
return rc;
}
-static Header rpmdbGetHeaderAt(rpmdb db, unsigned int offset)
+Header rpmdbGetHeaderAt(rpmdb db, unsigned int offset)
{
rpmdbMatchIterator mi = rpmdbInitIterator(db, RPMDBI_PACKAGES,
&offset, sizeof(offset));
@@ -936,9 +597,9 @@ static Header rpmdbGetHeaderAt(rpmdb db, unsigned int offset)
* @param filespec
* @param usestate take file state into account?
* @retval matches
- * @return 0 on success, 1 on not found, -2 on error
+ * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
*/
-static int rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
+static rpmRC rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
int usestate, dbiIndexSet * matches)
{
char * dirName = NULL;
@@ -947,7 +608,7 @@ static int rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
fingerPrint * fp1 = NULL;
dbiIndexSet allMatches = NULL;
unsigned int i;
- int rc = -2; /* assume error */
+ rpmRC rc = RPMRC_FAIL; /* assume error */
*matches = NULL;
if (filespec == NULL) return rc; /* nothing alloced yet */
@@ -964,11 +625,11 @@ static int rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
if (baseName == NULL)
goto exit;
- rc = dbiGetToSet(dbi, baseName, 0, &allMatches);
+ rc = indexGet(dbi, baseName, 0, &allMatches);
if (rc || allMatches == NULL) goto exit;
- *matches = xcalloc(1, sizeof(**matches));
+ *matches = dbiIndexSetNew(0);
fpc = fpCacheCreate(allMatches->count, NULL);
fpLookup(fpc, dirName, baseName, &fp1);
@@ -996,7 +657,7 @@ static int rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
headerGet(h, RPMTAG_FILESTATES, &fs, HEADERGET_MINMEM);
do {
- int num = dbiIndexRecordFileNumber(allMatches, i);
+ unsigned int num = dbiIndexRecordFileNumber(allMatches, i);
int skip = 0;
if (usestate) {
@@ -1009,11 +670,8 @@ static int rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
if (!skip) {
const char *dirName = dirNames[dirIndexes[num]];
if (fpLookupEquals(fpc, fp1, dirName, baseNames[num])) {
- struct dbiIndexItem rec = {
- .hdrNum = dbiIndexRecordOffset(allMatches, i),
- .tagNum = dbiIndexRecordFileNumber(allMatches, i),
- };
- dbiAppendSet(*matches, &rec, 1, sizeof(rec), 0);
+ dbiIndexSetAppendOne(*matches, dbiIndexRecordOffset(allMatches, i),
+ dbiIndexRecordFileNumber(allMatches, i), 0);
}
}
@@ -1036,9 +694,9 @@ static int rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
if ((*matches)->count == 0) {
*matches = dbiIndexSetFree(*matches);
- rc = 1;
+ rc = RPMRC_NOTFOUND;
} else {
- rc = 0;
+ rc = RPMRC_OK;
}
exit:
@@ -1049,29 +707,29 @@ exit:
int rpmdbCountPackages(rpmdb db, const char * name)
{
- int rc = -1;
- dbiIndex dbi = rpmdbOpenIndex(db, RPMDBI_NAME, 0);
+ int count = -1;
+ dbiIndex dbi = NULL;
- if (dbi != NULL && name != NULL) {
+ if (name != NULL && indexOpen(db, RPMDBI_NAME, 0, &dbi) == 0) {
dbiIndexSet matches = NULL;
- rc = dbiGetToSet(dbi, name, strlen(name), &matches);
+ rpmRC rc = indexGet(dbi, name, strlen(name), &matches);
- if (rc == 0) {
- rc = dbiIndexSetCount(matches);
+ if (rc == RPMRC_OK) {
+ count = dbiIndexSetCount(matches);
} else {
- rc = (rc == DB_NOTFOUND) ? 0 : -1;
+ count = (rc == RPMRC_NOTFOUND) ? 0 : -1;
}
dbiIndexSetFree(matches);
}
- return rc;
+ return count;
}
/**
* Attempt partial matches on name[-version[-release]][.arch] strings.
* @param db rpmdb handle
- * @param dbc index database cursor
+ * @param dbi index database
* @param name package name
* @param epoch package epoch (-1 for any epoch)
* @param version package version (can be a pattern)
@@ -1080,7 +738,7 @@ int rpmdbCountPackages(rpmdb db, const char * name)
* @retval matches set of header instances that match
* @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
*/
-static rpmRC dbiFindMatches(rpmdb db, dbiCursor dbc,
+static rpmRC dbiFindMatches(rpmdb db, dbiIndex dbi,
const char * name,
int64_t epoch,
const char * version,
@@ -1089,16 +747,18 @@ static rpmRC dbiFindMatches(rpmdb db, dbiCursor dbc,
dbiIndexSet * matches)
{
unsigned int gotMatches = 0;
- int rc;
+ rpmRC rc;
unsigned int i;
- rc = dbiCursorGetToSet(dbc, name, strlen(name), matches);
+ rc = indexGet(dbi, name, strlen(name), matches);
- if (rc != 0) {
- return (rc == DB_NOTFOUND) ? RPMRC_NOTFOUND : RPMRC_FAIL;
- } else if (epoch < 0 && version == NULL && release == NULL && arch == NULL) {
- return RPMRC_OK;
- }
+ /* No matches on the name, anything else wont match either */
+ if (rc != RPMRC_OK)
+ goto exit;
+
+ /* If we got matches on name and nothing else was specified, we're done */
+ if (epoch < 0 && version == NULL && release == NULL && arch == NULL)
+ goto exit;
/* Make sure the version and release match. */
for (i = 0; i < dbiIndexSetCount(*matches); i++) {
@@ -1184,16 +844,14 @@ static rpmRC dbiFindByLabelArch(rpmdb db, dbiIndex dbi,
char c;
int brackets;
rpmRC rc;
- dbiCursor dbc;
if (arglen == 0) return RPMRC_NOTFOUND;
strncpy(localarg, arg, arglen);
localarg[arglen] = '\0';
- dbc = dbiCursorInit(dbi, 0);
/* did they give us just a name? */
- rc = dbiFindMatches(db, dbc, localarg, -1, NULL, NULL, arch, matches);
+ rc = dbiFindMatches(db, dbi, localarg, -1, NULL, NULL, arch, matches);
if (rc != RPMRC_NOTFOUND)
goto exit;
@@ -1228,7 +886,7 @@ static rpmRC dbiFindByLabelArch(rpmdb db, dbiIndex dbi,
*s = '\0';
epoch = splitEpoch(s + 1, &version);
- rc = dbiFindMatches(db, dbc, localarg, epoch, version, NULL, arch, matches);
+ rc = dbiFindMatches(db, dbi, localarg, epoch, version, NULL, arch, matches);
if (rc != RPMRC_NOTFOUND) goto exit;
/* FIX: double indirection */
@@ -1262,9 +920,8 @@ static rpmRC dbiFindByLabelArch(rpmdb db, dbiIndex dbi,
*s = '\0';
/* FIX: *matches may be NULL. */
epoch = splitEpoch(s + 1, &version);
- rc = dbiFindMatches(db, dbc, localarg, epoch, version, release, arch, matches);
+ rc = dbiFindMatches(db, dbi, localarg, epoch, version, release, arch, matches);
exit:
- dbiCursorFree(dbc);
return rc;
}
@@ -1298,22 +955,16 @@ static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
return 0;
if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
- DBT key, data;
- sigset_t signalMask;
rpmRC rpmrc = RPMRC_NOTFOUND;
-
- memset(&key, 0, sizeof(key));
- memset(&data, 0, sizeof(data));
- key.data = (void *) &mi->mi_prevoffset;
- key.size = sizeof(mi->mi_prevoffset);
- data.data = headerExport(mi->mi_h, &data.size);
+ unsigned int hdrLen = 0;
+ unsigned char *hdrBlob = headerExport(mi->mi_h, &hdrLen);
/* Check header digest/signature on blob export (if requested). */
if (mi->mi_hdrchk && mi->mi_ts) {
char * msg = NULL;
int lvl;
- rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, data.data, data.size, &msg);
+ rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, hdrBlob, hdrLen, &msg);
lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
rpmlog(lvl, "%s h#%8u %s",
(rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping") : "write"),
@@ -1321,19 +972,22 @@ static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
msg = _free(msg);
}
- if (data.data != NULL && rpmrc != RPMRC_FAIL) {
- (void) blockSignals(&signalMask);
- rc = dbiCursorPut(mi->mi_dbc, &key, &data, DB_KEYLAST);
+ if (hdrBlob != NULL && rpmrc != RPMRC_FAIL) {
+ rpmsqBlock(SIG_BLOCK);
+ dbCtrl(mi->mi_db, DB_CTRL_LOCK_RW);
+ rc = pkgdbPut(dbi, mi->mi_dbc, mi->mi_prevoffset,
+ hdrBlob, hdrLen);
+ dbCtrl(mi->mi_db, DB_CTRL_INDEXSYNC);
+ dbCtrl(mi->mi_db, DB_CTRL_UNLOCK_RW);
+ rpmsqBlock(SIG_UNBLOCK);
+
if (rc) {
rpmlog(RPMLOG_ERR,
_("error(%d) storing record #%d into %s\n"),
rc, mi->mi_prevoffset, dbiName(dbi));
}
- dbiSync(dbi, 0);
- (void) unblockSignals(&signalMask);
}
- data.data = _free(data.data);
- data.size = 0;
+ free(hdrBlob);
}
mi->mi_h = headerFree(mi->mi_h);
@@ -1344,7 +998,7 @@ static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
{
rpmdbMatchIterator * prev, next;
- dbiIndex dbi;
+ dbiIndex dbi = NULL;
int i;
if (mi == NULL)
@@ -1356,13 +1010,14 @@ rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
if (next) {
*prev = next->mi_next;
next->mi_next = NULL;
- }
+ } else
+ return NULL;
- dbi = rpmdbOpenIndex(mi->mi_db, RPMDBI_PACKAGES, 0);
+ pkgdbOpen(mi->mi_db, 0, &dbi);
miFreeHeader(mi, dbi);
- mi->mi_dbc = dbiCursorFree(mi->mi_dbc);
+ mi->mi_dbc = dbiCursorFree(dbi, mi->mi_dbc);
if (mi->mi_re != NULL)
for (i = 0; i < mi->mi_nre; i++) {
@@ -1376,13 +1031,12 @@ rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
mi->mi_re = _free(mi->mi_re);
mi->mi_set = dbiIndexSetFree(mi->mi_set);
- mi->mi_keyp = _free(mi->mi_keyp);
rpmdbClose(mi->mi_db);
mi->mi_ts = rpmtsFree(mi->mi_ts);
mi = _free(mi);
- (void) rpmdbCheckSignals();
+ (void) rpmsqPoll();
return NULL;
}
@@ -1402,6 +1056,24 @@ int rpmdbGetIteratorCount(rpmdbMatchIterator mi)
return (mi && mi->mi_set ? mi->mi_set->count : 0);
}
+int rpmdbGetIteratorIndex(rpmdbMatchIterator mi)
+{
+ return (mi ? mi->mi_setx : 0);
+}
+
+void rpmdbSetIteratorIndex(rpmdbMatchIterator mi, unsigned int ix)
+{
+ if (mi)
+ mi->mi_setx = ix;
+}
+
+unsigned int rpmdbGetIteratorOffsetFor(rpmdbMatchIterator mi, unsigned int ix)
+{
+ if (mi && mi->mi_set && ix < mi->mi_set->count)
+ return mi->mi_set->recs[ix].hdrNum;
+ return 0;
+}
+
/**
* Return pattern match.
* @param mire match iterator regex
@@ -1714,11 +1386,11 @@ int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite)
int rc;
if (mi == NULL)
return 0;
- rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
+ rc = (mi->mi_cflags & DBC_WRITE) ? 1 : 0;
if (rewrite)
- mi->mi_cflags |= DB_WRITECURSOR;
+ mi->mi_cflags |= DBC_WRITE;
else
- mi->mi_cflags &= ~DB_WRITECURSOR;
+ mi->mi_cflags &= ~DBC_WRITE;
return rc;
}
@@ -1766,9 +1438,9 @@ static rpmRC miVerifyHeader(rpmdbMatchIterator mi, const void *uh, size_t uhlen)
rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg);
lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
- rpmlog(lvl, "%s h#%8u %s",
+ rpmlog(lvl, "%s h#%8u %s\n",
(rpmrc == RPMRC_FAIL ? _("rpmdbNextIterator: skipping") : " read"),
- mi->mi_offset, (msg ? msg : "\n"));
+ mi->mi_offset, (msg ? msg : ""));
msg = _free(msg);
/* Mark header checked. */
@@ -1782,20 +1454,16 @@ static rpmRC miVerifyHeader(rpmdbMatchIterator mi, const void *uh, size_t uhlen)
/* FIX: mi->mi_key.data may be NULL */
Header rpmdbNextIterator(rpmdbMatchIterator mi)
{
- dbiIndex dbi;
- void * uh;
+ dbiIndex dbi = NULL;
+ unsigned char * uh;
unsigned int uhlen;
- DBT key, data;
- void * keyp;
- size_t keylen;
int rc;
headerImportFlags importFlags = HEADERIMPORT_FAST;
if (mi == NULL)
return NULL;
- dbi = rpmdbOpenIndex(mi->mi_db, RPMDBI_PACKAGES, 0);
- if (dbi == NULL)
+ if (pkgdbOpen(mi->mi_db, 0, &dbi))
return NULL;
#if defined(_USE_COPY_LOAD)
@@ -1803,63 +1471,26 @@ Header rpmdbNextIterator(rpmdbMatchIterator mi)
#endif
/*
* Cursors are per-iterator, not per-dbi, so get a cursor for the
- * iterator on 1st call. If the iteration is to rewrite headers, and the
- * CDB model is used for the database, then the cursor needs to
- * marked with DB_WRITECURSOR as well.
+ * iterator on 1st call. If the iteration is to rewrite headers,
+ * then the cursor needs to marked with DBC_WRITE as well.
*/
if (mi->mi_dbc == NULL)
mi->mi_dbc = dbiCursorInit(dbi, mi->mi_cflags);
- memset(&key, 0, sizeof(key));
- memset(&data, 0, sizeof(data));
-
top:
uh = NULL;
uhlen = 0;
do {
- union _dbswap mi_offset;
-
if (mi->mi_set) {
if (!(mi->mi_setx < mi->mi_set->count))
return NULL;
mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
- mi_offset.ui = mi->mi_offset;
- if (dbiByteSwapped(dbi) == 1)
- _DBSWAP(mi_offset);
- keyp = &mi_offset;
- keylen = sizeof(mi_offset.ui);
} else {
-
- key.data = keyp = (void *)mi->mi_keyp;
- key.size = keylen = mi->mi_keylen;
- data.data = uh;
- data.size = uhlen;
-#if !defined(_USE_COPY_LOAD)
- data.flags |= DB_DBT_MALLOC;
-#endif
- rc = dbiCursorGet(mi->mi_dbc, &key, &data,
- (key.data == NULL ? DB_NEXT : DB_SET));
- data.flags = 0;
- keyp = key.data;
- keylen = key.size;
- uh = data.data;
- uhlen = data.size;
-
- /*
- * If we got the next key, save the header instance number.
- *
- * Instance 0 (i.e. mi->mi_setx == 0) is the
- * largest header instance in the database, and should be
- * skipped.
- */
- if (keyp && mi->mi_setx && rc == 0) {
- memcpy(&mi_offset, keyp, sizeof(mi_offset.ui));
- if (dbiByteSwapped(dbi) == 1)
- _DBSWAP(mi_offset);
- mi->mi_offset = mi_offset.ui;
- }
+ rc = pkgdbGet(dbi, mi->mi_dbc, 0, &uh, &uhlen);
+ if (rc == 0)
+ mi->mi_offset = pkgdbKey(dbi, mi->mi_dbc);
/* Terminate on error or end of keys */
if (rc || (mi->mi_setx && mi->mi_offset == 0))
@@ -1869,22 +1500,12 @@ top:
} while (mi->mi_offset == 0);
/* If next header is identical, return it now. */
- if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset) {
- /* ...but rpmdb record numbers are unique, avoid endless loop */
- return (mi->mi_rpmtag == RPMDBI_PACKAGES) ? NULL : mi->mi_h;
- }
+ if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
+ return mi->mi_h;
/* Retrieve next header blob for index iterator. */
if (uh == NULL) {
- key.data = keyp;
- key.size = keylen;
-#if !defined(_USE_COPY_LOAD)
- data.flags |= DB_DBT_MALLOC;
-#endif
- rc = dbiCursorGet(mi->mi_dbc, &key, &data, DB_SET);
- data.flags = 0;
- uh = data.data;
- uhlen = data.size;
+ rc = pkgdbGet(dbi, mi->mi_dbc, mi->mi_offset, &uh, &uhlen);
if (rc)
return NULL;
}
@@ -1914,10 +1535,7 @@ top:
* Skip this header if iterator selector (if any) doesn't match.
*/
if (mireSkip(mi)) {
- /* XXX hack, can't restart with Packages locked on single instance. */
- if (mi->mi_set || mi->mi_keyp == NULL)
- goto top;
- return NULL;
+ goto top;
}
headerSetInstance(mi->mi_h, mi->mi_offset);
@@ -1934,22 +1552,19 @@ top:
*/
void rpmdbSortIterator(rpmdbMatchIterator mi)
{
- if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
- /*
- * mergesort is much (~10x with lots of identical basenames) faster
- * than pure quicksort, but glibc uses msort_with_tmp() on stack.
- */
-#if defined(__GLIBC__)
- qsort(mi->mi_set->recs, mi->mi_set->count,
- sizeof(*mi->mi_set->recs), hdrNumCmp);
-#else
- mergesort(mi->mi_set->recs, mi->mi_set->count,
- sizeof(*mi->mi_set->recs), hdrNumCmp);
-#endif
+ if (mi && mi->mi_set) {
+ dbiIndexSetSort(mi->mi_set);
mi->mi_sorted = 1;
}
}
+void rpmdbUniqIterator(rpmdbMatchIterator mi)
+{
+ if (mi && mi->mi_set) {
+ dbiIndexSetUniq(mi->mi_set, mi->mi_sorted);
+ }
+}
+
int rpmdbExtendIterator(rpmdbMatchIterator mi,
const void * keyp, size_t keylen)
{
@@ -1960,16 +1575,13 @@ int rpmdbExtendIterator(rpmdbMatchIterator mi,
if (mi == NULL || keyp == NULL)
return rc;
- dbi = rpmdbOpenIndex(mi->mi_db, mi->mi_rpmtag, 0);
+ rc = indexOpen(mi->mi_db, mi->mi_rpmtag, 0, &dbi);
- if (dbiGetToSet(dbi, keyp, keylen, &set) == 0) {
+ if (rc == 0 && indexGet(dbi, keyp, keylen, &set) == RPMRC_OK) {
if (mi->mi_set == NULL) {
mi->mi_set = set;
} else {
- dbiGrowSet(mi->mi_set, set->count);
- memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
- set->count * sizeof(*(mi->mi_set->recs)));
- mi->mi_set->count += set->count;
+ dbiIndexSetAppendSet(mi->mi_set, set, 0);
dbiIndexSetFree(set);
}
rc = 0;
@@ -1978,22 +1590,31 @@ int rpmdbExtendIterator(rpmdbMatchIterator mi,
return rc;
}
-int rpmdbPruneIterator(rpmdbMatchIterator mi, removedHash hdrNums)
+int rpmdbFilterIterator(rpmdbMatchIterator mi, packageHash hdrNums, int neg)
{
- if (mi == NULL || hdrNums == NULL || removedHashNumKeys(hdrNums) <= 0)
+ if (mi == NULL || hdrNums == NULL)
return 1;
if (!mi->mi_set)
- return 0;
+ return 0;
+
+ if (packageHashNumKeys(hdrNums) == 0) {
+ if (!neg)
+ mi->mi_set->count = 0;
+ return 0;
+ }
unsigned int from;
unsigned int to = 0;
unsigned int num = mi->mi_set->count;
+ int cond;
assert(mi->mi_set->count > 0);
for (from = 0; from < num; from++) {
- if (removedHashHasEntry(hdrNums, mi->mi_set->recs[from].hdrNum)) {
+ cond = !packageHashHasEntry(hdrNums, mi->mi_set->recs[from].hdrNum);
+ cond = neg ? !cond : cond;
+ if (cond) {
mi->mi_set->count--;
continue;
}
@@ -2004,14 +1625,26 @@ int rpmdbPruneIterator(rpmdbMatchIterator mi, removedHash hdrNums)
return 0;
}
-int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
+int rpmdbPruneIterator(rpmdbMatchIterator mi, packageHash hdrNums)
+{
+ if (packageHashNumKeys(hdrNums) <= 0)
+ return 1;
+
+ return rpmdbFilterIterator(mi, hdrNums, 1);
+}
+
+
+int rpmdbAppendIterator(rpmdbMatchIterator mi,
+ const unsigned int * hdrNums, unsigned int nHdrNums)
{
- if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
+ if (mi == NULL || hdrNums == NULL || nHdrNums == 0)
return 1;
if (mi->mi_set == NULL)
- mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
- (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
+ mi->mi_set = dbiIndexSetNew(nHdrNums);
+
+ for (unsigned int i = 0; i < nHdrNums; i++)
+ dbiIndexSetAppendOne(mi->mi_set, hdrNums[i], 0, 0);
return 0;
}
@@ -2019,12 +1652,15 @@ rpmdbMatchIterator rpmdbNewIterator(rpmdb db, rpmDbiTagVal dbitag)
{
rpmdbMatchIterator mi = NULL;
- if (rpmdbOpenIndex(db, dbitag, 0) == NULL)
- return NULL;
+ if (dbitag == RPMDBI_PACKAGES) {
+ if (pkgdbOpen(db, 0, NULL))
+ return NULL;
+ } else {
+ if (indexOpen(db, dbitag, 0, NULL))
+ return NULL;
+ }
mi = xcalloc(1, sizeof(*mi));
- mi->mi_keyp = NULL;
- mi->mi_keylen = 0;
mi->mi_set = NULL;
mi->mi_db = rpmdbLink(db);
mi->mi_rpmtag = dbitag;
@@ -2051,19 +1687,32 @@ rpmdbMatchIterator rpmdbNewIterator(rpmdb db, rpmDbiTagVal dbitag)
return mi;
};
-rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmDbiTagVal rpmtag,
- const void * keyp, size_t keylen)
+static rpmdbMatchIterator pkgdbIterInit(rpmdb db,
+ const unsigned int * keyp, size_t keylen)
{
rpmdbMatchIterator mi = NULL;
- dbiIndexSet set = NULL;
- dbiIndex dbi;
- void * mi_keyp = NULL;
- rpmDbiTagVal dbtag = rpmtag;
+ rpmDbiTagVal dbtag = RPMDBI_PACKAGES;
+ dbiIndex pkgs = NULL;
- if (db == NULL)
+ /* Require a sane keylen if one is specified */
+ if (keyp && keylen != sizeof(*keyp))
return NULL;
- (void) rpmdbCheckSignals();
+ if (pkgdbOpen(db, 0, &pkgs) == 0) {
+ mi = rpmdbNewIterator(db, dbtag);
+ if (keyp)
+ rpmdbAppendIterator(mi, keyp, 1);
+ }
+ return mi;
+}
+
+static rpmdbMatchIterator indexIterInit(rpmdb db, rpmDbiTagVal rpmtag,
+ const void * keyp, size_t keylen)
+{
+ rpmdbMatchIterator mi = NULL;
+ rpmDbiTagVal dbtag = rpmtag;
+ dbiIndex dbi = NULL;
+ dbiIndexSet set = NULL;
/* Fixup the physical index for our pseudo indexes */
if (rpmtag == RPMDBI_LABEL) {
@@ -2072,19 +1721,10 @@ rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmDbiTagVal rpmtag,
dbtag = RPMDBI_BASENAMES;
}
- dbi = rpmdbOpenIndex(db, dbtag, 0);
- if (dbi == NULL)
- return NULL;
-
- /*
- * Handle label and file name special cases.
- * Otherwise, retrieve join keys for secondary lookup.
- */
- if (rpmtag != RPMDBI_PACKAGES) {
+ if (indexOpen(db, dbtag, 0, &dbi) == 0) {
int rc = 0;
if (keyp) {
-
if (rpmtag == RPMDBI_LABEL) {
rc = dbiFindByLabel(db, dbi, keyp, &set);
} else if (rpmtag == RPMDBI_BASENAMES) {
@@ -2092,117 +1732,130 @@ rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmDbiTagVal rpmtag,
} else if (rpmtag == RPMDBI_INSTFILENAMES) {
rc = rpmdbFindByFile(db, dbi, keyp, 1, &set);
} else {
- rc = dbiGetToSet(dbi, keyp, keylen, &set);
+ rc = indexGet(dbi, keyp, keylen, &set);
}
} else {
/* get all entries from index */
- dbiCursor dbc = dbiCursorInit(dbi, 0);
-
- do {
- rc = dbiCursorGetToSet(dbc, NULL, 0, &set);
- } while (rc == 0);
-
- /* If we got some results, not found is not an error */
- if (rc == DB_NOTFOUND && set != NULL)
- rc = 0;
-
- dbiCursorFree(dbc);
+ rc = indexGet(dbi, NULL, 0, &set);
}
if (rc) { /* error/not found */
set = dbiIndexSetFree(set);
- goto exit;
+ } else {
+ mi = rpmdbNewIterator(db, dbtag);
+ mi->mi_set = set;
+
+ if (keyp) {
+ rpmdbSortIterator(mi);
+ }
}
}
+
+ return mi;
+}
- /* Copy the retrieval key, byte swapping header instance if necessary. */
- if (keyp) {
- switch (dbtag) {
- case RPMDBI_PACKAGES:
- { union _dbswap *k;
+rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmDbiTagVal rpmtag,
+ const void * keyp, size_t keylen)
+{
+ rpmdbMatchIterator mi = NULL;
- assert(keylen == sizeof(k->ui)); /* xxx programmer error */
- k = xmalloc(sizeof(*k));
- memcpy(k, keyp, keylen);
- if (dbiByteSwapped(dbi) == 1)
- _DBSWAP(*k);
- mi_keyp = k;
- } break;
- default:
- { char * k;
- if (keylen == 0)
- keylen = strlen(keyp);
- k = xmalloc(keylen + 1);
- memcpy(k, keyp, keylen);
- k[keylen] = '\0'; /* XXX assumes strings */
- mi_keyp = k;
- } break;
- }
+ if (db != NULL) {
+ (void) rpmsqPoll();
+
+ if (rpmtag == RPMDBI_PACKAGES)
+ mi = pkgdbIterInit(db, keyp, keylen);
+ else
+ mi = indexIterInit(db, rpmtag, keyp, keylen);
}
- mi = rpmdbNewIterator(db, dbtag);
- mi->mi_keyp = mi_keyp;
- mi->mi_keylen = keylen;
- mi->mi_set = set;
+ return mi;
+}
+
+rpmdbMatchIterator rpmdbInitPrefixIterator(rpmdb db, rpmDbiTagVal rpmtag,
+ const void * pfx, size_t plen)
+{
+ rpmdbMatchIterator mi = NULL;
+ dbiIndexSet set = NULL;
+ dbiIndex dbi = NULL;
+ rpmDbiTagVal dbtag = rpmtag;
+
+ if (!pfx)
+ return NULL;
+
+ if (db != NULL && rpmtag != RPMDBI_PACKAGES) {
+ (void) rpmsqPoll();
+
+
+ if (indexOpen(db, dbtag, 0, &dbi) == 0) {
+ int rc = 0;
+
+ rc = indexPrefixGet(dbi, pfx, plen, &set);
+
+ if (rc) {
+ set = dbiIndexSetFree(set);
+ } else {
+ mi = rpmdbNewIterator(db, dbtag);
+ mi->mi_set = set;
+ rpmdbSortIterator(mi);
+ }
+ }
- if (dbtag != RPMDBI_PACKAGES && keyp == NULL) {
- rpmdbSortIterator(mi);
}
-exit:
return mi;
}
/*
* Convert current tag data to db key
* @param tagdata Tag data container
- * @retval key DB key struct
- * @retval freedata Should key.data be freed afterwards
- * Return 0 to signal this item should be discarded (ie continue)
+ * @retval keylen Length of key
+ * @return Pointer to key value or NULL to signal skip
*/
-static int td2key(rpmtd tagdata, DBT *key, int *freedata)
+static const void * td2key(rpmtd tagdata, unsigned int *keylen)
{
+ const void * data = NULL;
+ unsigned int size = 0;
const char *str = NULL;
- *freedata = 0;
switch (rpmtdType(tagdata)) {
case RPM_CHAR_TYPE:
case RPM_INT8_TYPE:
- key->size = sizeof(uint8_t);
- key->data = rpmtdGetChar(tagdata);
+ size = sizeof(uint8_t);
+ data = rpmtdGetChar(tagdata);
break;
case RPM_INT16_TYPE:
- key->size = sizeof(uint16_t);
- key->data = rpmtdGetUint16(tagdata);
+ size = sizeof(uint16_t);
+ data = rpmtdGetUint16(tagdata);
break;
case RPM_INT32_TYPE:
- key->size = sizeof(uint32_t);
- key->data = rpmtdGetUint32(tagdata);
+ size = sizeof(uint32_t);
+ data = rpmtdGetUint32(tagdata);
break;
case RPM_INT64_TYPE:
- key->size = sizeof(uint64_t);
- key->data = rpmtdGetUint64(tagdata);
+ size = sizeof(uint64_t);
+ data = rpmtdGetUint64(tagdata);
break;
case RPM_BIN_TYPE:
- key->size = tagdata->count;
- key->data = tagdata->data;
+ size = tagdata->count;
+ data = tagdata->data;
break;
case RPM_STRING_TYPE:
case RPM_I18NSTRING_TYPE:
case RPM_STRING_ARRAY_TYPE:
- default:
str = rpmtdGetString(tagdata);
- key->data = (char *) str; /* XXX discards const */
- key->size = strlen(str);
+ if (str) {
+ size = strlen(str);
+ data = str;
+ }
+ break;
+ default:
break;
}
- if (key->size == 0)
- key->size = strlen((char *)key->data);
- if (key->size == 0)
- key->size++; /* XXX "/" fixup. */
+ if (data && keylen)
+ *keylen = size;
- return 1;
+ return data;
}
/*
* rpmdbIndexIterator
@@ -2216,10 +1869,9 @@ rpmdbIndexIterator rpmdbIndexIteratorInit(rpmdb db, rpmDbiTag rpmtag)
if (db == NULL)
return NULL;
- (void) rpmdbCheckSignals();
+ (void) rpmsqPoll();
- dbi = rpmdbOpenIndex(db, rpmtag, 0);
- if (dbi == NULL)
+ if (indexOpen(db, rpmtag, 0, &dbi))
return NULL;
/* Chain cursors for teardown on abnormal exit. */
@@ -2238,37 +1890,69 @@ rpmdbIndexIterator rpmdbIndexIteratorInit(rpmdb db, rpmDbiTag rpmtag)
int rpmdbIndexIteratorNext(rpmdbIndexIterator ii, const void ** key, size_t * keylen)
{
int rc;
- DBT data;
+ unsigned int iikeylen = 0; /* argh, size_t vs uint pointer... */
if (ii == NULL)
return -1;
if (ii->ii_dbc == NULL)
- ii->ii_dbc = dbiCursorInit(ii->ii_dbi, 0);
+ ii->ii_dbc = dbiCursorInit(ii->ii_dbi, DBC_READ);
/* free old data */
ii->ii_set = dbiIndexSetFree(ii->ii_set);
- memset(&data, 0, sizeof(data));
- rc = dbiCursorGet(ii->ii_dbc, &ii->ii_key, &data, DB_NEXT);
+ rc = idxdbGet(ii->ii_dbi, ii->ii_dbc, NULL, 0, &ii->ii_set, DBC_NORMAL_SEARCH);
- if (rc != 0) {
- *key = NULL;
- *keylen = 0;
+ *key = idxdbKey(ii->ii_dbi, ii->ii_dbc, &iikeylen);
+ *keylen = iikeylen;
- if (rc != DB_NOTFOUND) {
- rpmlog(RPMLOG_ERR,
- _("error(%d:%s) getting next key from %s index\n"),
- rc, db_strerror(rc), rpmTagGetName(ii->ii_rpmtag));
- }
- return -1;
- }
+ return (rc == RPMRC_OK) ? 0 : -1;
+}
- (void) dbt2set(ii->ii_dbi, &data, &ii->ii_set);
- *key = ii->ii_key.data;
- *keylen = ii->ii_key.size;
+int rpmdbIndexIteratorNextTd(rpmdbIndexIterator ii, rpmtd keytd)
+{
+ size_t keylen = 0;
+ const void * keyp = NULL;
- return 0;
+ int rc = rpmdbIndexIteratorNext(ii, &keyp, &keylen);
+
+ if (rc == 0) {
+ rpmTagVal tag = ii->ii_rpmtag;
+ rpmTagClass tagclass = rpmTagGetClass(tag);
+
+ /* Set the common values, overridden below as necessary */
+ keytd->type = rpmTagGetTagType(tag);
+ keytd->tag = tag;
+ keytd->flags = RPMTD_ALLOCED;
+ keytd->count = 1;
+
+ switch (tagclass) {
+ case RPM_STRING_CLASS: {
+ /*
+ * XXX: We never return arrays here, so everything is a
+ * "simple" string. However this can disagree with the
+ * type of the index tag, eg requires are string arrays.
+ */
+ char *key = memcpy(xmalloc(keylen + 1), keyp, keylen);
+ key[keylen] = '\0';
+ keytd->data = key;
+ keytd->type = RPM_STRING_TYPE;
+ } break;
+ case RPM_BINARY_CLASS:
+ /* Binary types abuse count for data length */
+ keytd->count = keylen;
+ /* fallthrough */
+ case RPM_NUMERIC_CLASS:
+ keytd->data = memcpy(xmalloc(keylen), keyp, keylen);
+ break;
+ default:
+ rpmtdReset(keytd);
+ rc = -1;
+ break;
+ }
+ }
+
+ return rc;
}
unsigned int rpmdbIndexIteratorNumPkgs(rpmdbIndexIterator ii)
@@ -2285,6 +1969,24 @@ unsigned int rpmdbIndexIteratorPkgOffset(rpmdbIndexIterator ii, unsigned int nr)
return dbiIndexRecordOffset(ii->ii_set, nr);
}
+unsigned int *rpmdbIndexIteratorPkgOffsets(rpmdbIndexIterator ii)
+{
+ int i;
+
+ if (!ii || !ii->ii_set)
+ return NULL;
+
+ if (ii->ii_hdrNums)
+ ii->ii_hdrNums = _free(ii->ii_hdrNums);
+
+ ii->ii_hdrNums = xmalloc(sizeof(*ii->ii_hdrNums) * ii->ii_set->count);
+ for (i = 0; i < ii->ii_set->count; i++) {
+ ii->ii_hdrNums[i] = ii->ii_set->recs[i].hdrNum;
+ }
+
+ return ii->ii_hdrNums;
+}
+
unsigned int rpmdbIndexIteratorTagNum(rpmdbIndexIterator ii, unsigned int nr)
{
if (!ii || !ii->ii_set)
@@ -2307,13 +2009,17 @@ rpmdbIndexIterator rpmdbIndexIteratorFree(rpmdbIndexIterator ii)
if (next) {
*prev = next->ii_next;
next->ii_next = NULL;
- }
+ } else
+ return NULL;
- ii->ii_dbc = dbiCursorFree(ii->ii_dbc);
+ ii->ii_dbc = dbiCursorFree(ii->ii_dbi, ii->ii_dbc);
ii->ii_dbi = NULL;
rpmdbClose(ii->ii_db);
ii->ii_set = dbiIndexSetFree(ii->ii_set);
+ if (ii->ii_hdrNums)
+ ii->ii_hdrNums = _free(ii->ii_hdrNums);
+
ii = _free(ii);
return NULL;
}
@@ -2332,56 +2038,16 @@ static void logAddRemove(const char *dbiname, int removing, rpmtd tagdata)
}
}
-/* Update primary Packages index. NULL hdr means remove */
-static int updatePackages(dbiIndex dbi, unsigned int hdrNum, DBT *hdr)
+static rpmRC indexDel(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
{
- union _dbswap mi_offset;
- int rc = 0;
- dbiCursor dbc;
- DBT key;
-
- if (dbi == NULL || hdrNum == 0)
- return 1;
-
- memset(&key, 0, sizeof(key));
-
- dbc = dbiCursorInit(dbi, DB_WRITECURSOR);
-
- mi_offset.ui = hdrNum;
- if (dbiByteSwapped(dbi) == 1)
- _DBSWAP(mi_offset);
- key.data = (void *) &mi_offset;
- key.size = sizeof(mi_offset.ui);
-
- if (hdr) {
- rc = dbiCursorPut(dbc, &key, hdr, DB_KEYLAST);
- if (rc) {
- rpmlog(RPMLOG_ERR,
- _("error(%d) adding header #%d record\n"), rc, hdrNum);
- }
- } else {
- DBT data;
-
- memset(&data, 0, sizeof(data));
- rc = dbiCursorGet(dbc, &key, &data, DB_SET);
- if (rc) {
- rpmlog(RPMLOG_ERR,
- _("error(%d) removing header #%d record\n"), rc, hdrNum);
- } else
- rc = dbiCursorDel(dbc, &key, &data, 0);
- }
-
- dbiCursorFree(dbc);
- dbiSync(dbi, 0);
-
- return rc;
+ return tag2index(dbi, rpmtag, hdrNum, h, idxdbDel);
}
int rpmdbRemove(rpmdb db, unsigned int hdrNum)
{
- dbiIndex dbi;
+ dbiIndex dbi = NULL;
+ dbiCursor dbc = NULL;
Header h;
- sigset_t signalMask;
int ret = 0;
if (db == NULL)
@@ -2399,112 +2065,32 @@ int rpmdbRemove(rpmdb db, unsigned int hdrNum)
free(nevra);
}
- (void) blockSignals(&signalMask);
+ if (pkgdbOpen(db, 0, &dbi))
+ return 1;
+
+ rpmsqBlock(SIG_BLOCK);
+ dbCtrl(db, DB_CTRL_LOCK_RW);
- dbi = rpmdbOpenIndex(db, RPMDBI_PACKAGES, 0);
/* Remove header from primary index */
- ret = updatePackages(dbi, hdrNum, NULL);
+ dbc = dbiCursorInit(dbi, DBC_WRITE);
+ ret = pkgdbDel(dbi, dbc, hdrNum);
+ dbiCursorFree(dbi, dbc);
/* Remove associated data from secondary indexes */
if (ret == 0) {
- struct dbiIndexItem rec = { .hdrNum = hdrNum, .tagNum = 0 };
- int rc = 0;
- dbiCursor dbc = NULL;
- DBT key, data;
-
- memset(&key, 0, sizeof(key));
- memset(&data, 0, sizeof(data));
+ for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
+ rpmDbiTag rpmtag = db->db_tags[dbix];
- for (int dbix = 1; dbix < dbiTagsMax; dbix++) {
- rpmDbiTag rpmtag = dbiTags[dbix];
- struct rpmtd_s tagdata;
-
- if (!(dbi = rpmdbOpenIndex(db, rpmtag, 0)))
- continue;
-
- if (!headerGet(h, rpmtag, &tagdata, HEADERGET_MINMEM))
+ if (indexOpen(db, rpmtag, 0, &dbi))
continue;
- dbc = dbiCursorInit(dbi, DB_WRITECURSOR);
-
- logAddRemove(dbiName(dbi), 1, &tagdata);
- while (rpmtdNext(&tagdata) >= 0) {
- dbiIndexSet set;
- int freedata = 0;
-
- if (!td2key(&tagdata, &key, &freedata)) {
- continue;
- }
-
- /* XXX
- * This is almost right, but, if there are duplicate tag
- * values, there will be duplicate attempts to remove
- * the header instance. It's faster to just ignore errors
- * than to do things correctly.
- */
-
- /*
- * XXX with duplicates, an accurate data value and
- * DB_GET_BOTH is needed.
- * */
- set = NULL;
-
- rc = dbiCursorGet(dbc, &key, &data, DB_SET);
- if (rc == 0) { /* success */
- (void) dbt2set(dbi, &data, &set);
- } else if (rc == DB_NOTFOUND) { /* not found */
- goto cont;
- } else { /* error */
- rpmlog(RPMLOG_ERR,
- _("error(%d) setting \"%s\" records from %s index\n"),
- rc, (char*)key.data, dbiName(dbi));
- ret += 1;
- goto cont;
- }
-
- rc = dbiPruneSet(set, &rec, 1, sizeof(rec), 1);
-
- /* If nothing was pruned, then don't bother updating. */
- if (rc) {
- set = dbiIndexSetFree(set);
- goto cont;
- }
-
- if (set->count > 0) {
- (void) set2dbt(dbi, &data, set);
- rc = dbiCursorPut(dbc, &key, &data, DB_KEYLAST);
- if (rc) {
- rpmlog(RPMLOG_ERR,
- _("error(%d) storing record \"%s\" into %s\n"),
- rc, (char*)key.data, dbiName(dbi));
- ret += 1;
- }
- data.data = _free(data.data);
- data.size = 0;
- } else {
- rc = dbiCursorDel(dbc, &key, &data, 0);
- if (rc) {
- rpmlog(RPMLOG_ERR,
- _("error(%d) removing record \"%s\" from %s\n"),
- rc, (char*)key.data, dbiName(dbi));
- ret += 1;
- }
- }
- set = dbiIndexSetFree(set);
-cont:
- if (freedata) {
- free(key.data);
- }
- }
-
- dbc = dbiCursorFree(dbc);
- dbiSync(dbi, 0);
-
- rpmtdFreeData(&tagdata);
+ ret += indexDel(dbi, rpmtag, hdrNum, h);
}
}
- (void) unblockSignals(&signalMask);
+ dbCtrl(db, DB_CTRL_INDEXSYNC);
+ dbCtrl(db, DB_CTRL_UNLOCK_RW);
+ rpmsqBlock(SIG_UNBLOCK);
headerFree(h);
@@ -2512,79 +2098,109 @@ cont:
return 0;
}
-/* Get current header instance number or try to allocate a new one */
-static unsigned int pkgInstance(dbiIndex dbi, int alloc)
-{
- unsigned int hdrNum = 0;
-
- if (dbi != NULL && dbiType(dbi) == DBI_PRIMARY) {
- dbiCursor dbc;
- DBT key, data;
- unsigned int firstkey = 0;
- union _dbswap mi_offset;
- int ret;
-
- memset(&key, 0, sizeof(key));
- memset(&data, 0, sizeof(data));
-
- dbc = dbiCursorInit(dbi, alloc ? DB_WRITECURSOR : 0);
-
- /* Key 0 holds the current largest instance, fetch it */
- key.data = &firstkey;
- key.size = sizeof(firstkey);
- ret = dbiCursorGet(dbc, &key, &data, DB_SET);
+struct updateRichDepData {
+ ARGV_t argv;
+ int nargv;
+ int neg;
+ int level;
+ int *nargv_level;
+};
- if (ret == 0 && data.data) {
- memcpy(&mi_offset, data.data, sizeof(mi_offset.ui));
- if (dbiByteSwapped(dbi) == 1)
- _DBSWAP(mi_offset);
- hdrNum = mi_offset.ui;
+static rpmRC updateRichDepCB(void *cbdata, rpmrichParseType type,
+ const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
+ rpmrichOp op, char **emsg) {
+ struct updateRichDepData *data = cbdata;
+ if (type == RPMRICH_PARSE_ENTER) {
+ data->level++;
+ data->nargv_level = xrealloc(data->nargv_level, data->level * (sizeof(int)));
+ data->nargv_level[data->level - 1] = data->nargv;
+ }
+ if (type == RPMRICH_PARSE_LEAVE) {
+ data->level--;
+ }
+ if (type == RPMRICH_PARSE_SIMPLE && nl && !(nl > 7 && !strncmp(n, "rpmlib(", 7))) {
+ char *name = xmalloc(nl + 2);
+ *name = data->neg ? '!' : ' ';
+ strncpy(name + 1, n, nl);
+ name[1 + nl] = 0;
+ argvAdd(&data->argv, name);
+ data->nargv++;
+ _free(name);
+ }
+ if (type == RPMRICH_PARSE_OP && (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS)) {
+ /* save nargv in case of ELSE */
+ data->nargv_level[data->level - 1] = data->nargv;
+ data->neg ^= 1;
+ }
+ if (type == RPMRICH_PARSE_OP && op == RPMRICHOP_ELSE) {
+ int i, nargv = data->nargv;
+ /* copy and invert condition block */
+ for (i = data->nargv_level[data->level - 1]; i < nargv; i++) {
+ char *name = data->argv[i];
+ *name ^= ' ' ^ '!';
+ argvAdd(&data->argv, name);
+ *name ^= ' ' ^ '!';
+ data->nargv++;
}
-
- if (alloc) {
- /* Rather complicated "increment by one", bswapping as needed */
- ++hdrNum;
- mi_offset.ui = hdrNum;
- if (dbiByteSwapped(dbi) == 1)
- _DBSWAP(mi_offset);
- if (ret == 0 && data.data) {
- memcpy(data.data, &mi_offset, sizeof(mi_offset.ui));
- } else {
- data.data = &mi_offset;
- data.size = sizeof(mi_offset.ui);
- }
-
- /* Unless we manage to insert the new instance number, we failed */
- ret = dbiCursorPut(dbc, &key, &data, DB_KEYLAST);
- if (ret) {
- hdrNum = 0;
- rpmlog(RPMLOG_ERR,
- _("error(%d) allocating new package instance\n"), ret);
+ data->neg ^= 1;
+ }
+ if (type == RPMRICH_PARSE_LEAVE && (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS)) {
+ data->neg ^= 1;
+ }
+ return RPMRC_OK;
+}
+
+static rpmRC updateRichDep(dbiIndex dbi, dbiCursor dbc, const char *str,
+ struct dbiIndexItem_s *rec,
+ idxfunc idxupdate)
+{
+ int n, i, rc = 0;
+ struct updateRichDepData data;
+
+ data.argv = argvNew();
+ data.neg = 0;
+ data.nargv = 0;
+ data.level = 0;
+ data.nargv_level = xcalloc(1, sizeof(int));
+ if (rpmrichParse(&str, NULL, updateRichDepCB, &data) == RPMRC_OK) {
+ n = argvCount(data.argv);
+ if (n) {
+ argvSort(data.argv, NULL);
+ for (i = 0; i < n; i++) {
+ char *name = data.argv[i];
+ if (i && !strcmp(data.argv[i - 1], name))
+ continue; /* ignore dups */
+ if (*name == ' ')
+ name++;
+ rc += idxupdate(dbi, dbc, name, strlen(name), rec);
}
-
- dbiSync(dbi, 0);
}
- dbiCursorFree(dbc);
}
-
- return hdrNum;
+ _free(data.nargv_level);
+ argvFree(data.argv);
+ return rc;
}
-/* Add data to secondary index */
-static int addToIndex(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
+static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag,
+ unsigned int hdrNum, Header h,
+ idxfunc idxupdate)
{
int i, rc = 0;
- struct rpmtd_s tagdata, reqflags;
+ struct rpmtd_s tagdata, reqflags, trig_index;
dbiCursor dbc = NULL;
switch (rpmtag) {
case RPMTAG_REQUIRENAME:
headerGet(h, RPMTAG_REQUIREFLAGS, &reqflags, HEADERGET_MINMEM);
- /* fallthrough */
- default:
- headerGet(h, rpmtag, &tagdata, HEADERGET_MINMEM);
+ break;
+ case RPMTAG_FILETRIGGERNAME:
+ headerGet(h, RPMTAG_FILETRIGGERINDEX, &trig_index, HEADERGET_MINMEM);
+ break;
+ case RPMTAG_TRANSFILETRIGGERNAME:
+ headerGet(h, RPMTAG_TRANSFILETRIGGERINDEX, &trig_index, HEADERGET_MINMEM);
break;
}
+ headerGet(h, rpmtag, &tagdata, HEADERGET_MINMEM);
if (rpmtdCount(&tagdata) == 0) {
if (rpmtag != RPMTAG_GROUP)
@@ -2596,15 +2212,29 @@ static int addToIndex(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Heade
tagdata.count = 1;
}
- dbc = dbiCursorInit(dbi, DB_WRITECURSOR);
+ dbc = dbiCursorInit(dbi, DBC_WRITE);
logAddRemove(dbiName(dbi), 0, &tagdata);
while ((i = rpmtdNext(&tagdata)) >= 0) {
- dbiIndexSet set;
- int freedata = 0, j;
- DBT key, data;
- /* Include the tagNum in all indices (only files use though) */
- struct dbiIndexItem rec = { .hdrNum = hdrNum, .tagNum = i };
+ const void * key = NULL;
+ unsigned int keylen = 0;
+ int j;
+ struct dbiIndexItem_s rec;
+
+ switch (rpmtag) {
+ /* Include trigger index in db index for triggers */
+ case RPMTAG_FILETRIGGERNAME:
+ case RPMTAG_TRANSFILETRIGGERNAME:
+ rec.hdrNum = hdrNum;
+ rec.tagNum = *rpmtdNextUint32(&trig_index);
+ break;
+
+ /* Include the tagNum in the others indices (only files use though) */
+ default:
+ rec.hdrNum = hdrNum;
+ rec.tagNum = i;
+ break;
+ }
switch (rpmtag) {
case RPMTAG_REQUIRENAME: {
@@ -2631,107 +2261,90 @@ static int addToIndex(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Heade
break;
}
- memset(&key, 0, sizeof(key));
- memset(&data, 0, sizeof(data));
-
- if (!td2key(&tagdata, &key, &freedata)) {
+ if ((key = td2key(&tagdata, &keylen)) == NULL)
continue;
- }
-
- /*
- * XXX with duplicates, an accurate data value and
- * DB_GET_BOTH is needed.
- */
-
- set = NULL;
-
- rc = dbiCursorGet(dbc, &key, &data, DB_SET);
- if (rc == 0) { /* success */
- /* With duplicates, cursor is positioned, discard the record. */
- if (!dbi->dbi_permit_dups)
- (void) dbt2set(dbi, &data, &set);
- } else if (rc != DB_NOTFOUND) { /* error */
- rpmlog(RPMLOG_ERR,
- _("error(%d) getting \"%s\" records from %s index\n"),
- rc, (char*)key.data, dbiName(dbi));
- rc += 1;
- goto cont;
- }
-
- if (set == NULL) /* not found or duplicate */
- set = xcalloc(1, sizeof(*set));
- (void) dbiAppendSet(set, &rec, 1, sizeof(rec), 0);
-
- (void) set2dbt(dbi, &data, set);
- rc = dbiCursorPut(dbc, &key, &data, DB_KEYLAST);
-
- if (rc) {
- rpmlog(RPMLOG_ERR,
- _("error(%d) storing record %s into %s\n"),
- rc, (char*)key.data, dbiName(dbi));
- rc += 1;
- }
- data.data = _free(data.data);
- data.size = 0;
- set = dbiIndexSetFree(set);
-cont:
- if (freedata) {
- free(key.data);
+ rc += idxupdate(dbi, dbc, key, keylen, &rec);
+
+ if (*(char *)key == '(') {
+ switch (rpmtag) {
+ case RPMTAG_REQUIRENAME:
+ case RPMTAG_CONFLICTNAME:
+ case RPMTAG_SUGGESTNAME:
+ case RPMTAG_SUPPLEMENTNAME:
+ case RPMTAG_RECOMMENDNAME:
+ case RPMTAG_ENHANCENAME:
+ if (rpmtdType(&tagdata) == RPM_STRING_ARRAY_TYPE) {
+ rc += updateRichDep(dbi, dbc, rpmtdGetString(&tagdata),
+ &rec, idxupdate);
+ }
+ default:
+ break;
+ }
}
}
- dbiCursorFree(dbc);
- dbiSync(dbi, 0);
+ dbiCursorFree(dbi, dbc);
exit:
rpmtdFreeData(&tagdata);
- return rc;
+ return (rc == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
+
+static rpmRC indexPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
+{
+ return tag2index(dbi, rpmtag, hdrNum, h, idxdbPut);
}
int rpmdbAdd(rpmdb db, Header h)
{
- DBT hdr;
- sigset_t signalMask;
- dbiIndex dbi;
+ dbiIndex dbi = NULL;
+ dbiCursor dbc = NULL;
unsigned int hdrNum = 0;
+ unsigned int hdrLen = 0;
+ unsigned char *hdrBlob = NULL;
int ret = 0;
- int hdrOk;
if (db == NULL)
return 0;
- memset(&hdr, 0, sizeof(hdr));
-
- hdr.data = headerExport(h, &hdr.size);
- hdrOk = (hdr.data != NULL && hdr.size > 0);
-
- if (!hdrOk) {
+ hdrBlob = headerExport(h, &hdrLen);
+ if (hdrBlob == NULL || hdrLen == 0) {
ret = -1;
goto exit;
}
- (void) blockSignals(&signalMask);
-
- dbi = rpmdbOpenIndex(db, RPMDBI_PACKAGES, 0);
- hdrNum = pkgInstance(dbi, 1);
+ ret = pkgdbOpen(db, 0, &dbi);
+ if (ret)
+ goto exit;
+
+ rpmsqBlock(SIG_BLOCK);
+ dbCtrl(db, DB_CTRL_LOCK_RW);
/* Add header to primary index */
- ret = updatePackages(dbi, hdrNum, &hdr);
+ dbc = dbiCursorInit(dbi, DBC_WRITE);
+ ret = pkgdbNew(dbi, dbc, &hdrNum);
+ if (ret == 0)
+ ret = pkgdbPut(dbi, dbc, hdrNum, hdrBlob, hdrLen);
+ dbiCursorFree(dbi, dbc);
/* Add associated data to secondary indexes */
if (ret == 0) {
- for (int dbix = 1; dbix < dbiTagsMax; dbix++) {
- rpmDbiTag rpmtag = dbiTags[dbix];
+ for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
+ rpmDbiTag rpmtag = db->db_tags[dbix];
- if (!(dbi = rpmdbOpenIndex(db, rpmtag, 0)))
+ if (indexOpen(db, rpmtag, 0, &dbi))
continue;
- ret += addToIndex(dbi, rpmtag, hdrNum, h);
+ ret += indexPut(dbi, rpmtag, hdrNum, h);
}
}
- /* If everthing ok, mark header as installed now */
+ dbCtrl(db, DB_CTRL_INDEXSYNC);
+ dbCtrl(db, DB_CTRL_UNLOCK_RW);
+ rpmsqBlock(SIG_UNBLOCK);
+
+ /* If everything ok, mark header as installed now */
if (ret == 0) {
headerSetInstance(h, hdrNum);
/* Purge our verification cache on added public keys */
@@ -2741,24 +2354,15 @@ int rpmdbAdd(rpmdb db, Header h)
}
exit:
- free(hdr.data);
- (void) unblockSignals(&signalMask);
+ free(hdrBlob);
return ret;
}
-/*
- * Remove DB4 environment (and lock), ie the equivalent of
- * rm -f <prefix>/<dbpath>/__db.???
- * Environment files not existing is not an error, failure to unlink is,
- * return zero on success.
- * TODO/FIX: push this down to db3.c where it belongs
- */
-static int cleanDbenv(const char *prefix, const char *dbpath)
+static int rpmdbRemoveFiles(char * pattern)
{
+ int rc = 0;
ARGV_t paths = NULL, p;
- int rc = 0;
- char *pattern = rpmGetPath(prefix, "/", dbpath, "/__db.???", NULL);
if (rpmGlob(pattern, NULL, &paths) == 0) {
for (p = paths; *p; p++) {
@@ -2766,86 +2370,114 @@ static int cleanDbenv(const char *prefix, const char *dbpath)
}
argvFree(paths);
}
+ return rc;
+}
+
+static int rpmdbRemoveDatabase(const char *dbpath)
+{
+ int rc = 0;
+ char *pattern;
+
+ pattern = rpmGetPath(dbpath, "/*", NULL);
+ rc += rpmdbRemoveFiles(pattern);
+ free(pattern);
+ pattern = rpmGetPath(dbpath, "/.??*", NULL);
+ rc += rpmdbRemoveFiles(pattern);
free(pattern);
+
+ rc += rmdir(dbpath);
return rc;
}
-static int rpmdbRemoveDatabase(const char * prefix, const char * dbpath)
-{
- char *path;
- int xx = 0;
+static int rpmdbMoveDatabase(const char * prefix, const char * srcdbpath,
+ const char * dbpath, const char * tmppath)
+{
+ int rc = -1;
+ int xx;
+ char *src = rpmGetPath(prefix, "/", srcdbpath, NULL);
+ char *old = rpmGetPath(prefix, "/", tmppath, NULL);
+ char *dest = rpmGetPath(prefix, "/", dbpath, NULL);
+
+ char * oldkeys = rpmGetPath(old, "/", "pubkeys", NULL);
+ char * destkeys = rpmGetPath(dest, "/", "pubkeys", NULL);
- for (int i = 0; i < dbiTagsMax; i++) {
- const char * base = rpmTagGetName(dbiTags[i]);
- path = rpmGetPath(prefix, "/", dbpath, "/", base, NULL);
- if (access(path, F_OK) == 0)
- xx += unlink(path);
- free(path);
+ xx = rename(dest, old);
+ if (xx) {
+ goto exit;
+ }
+ xx = rename(src, dest);
+ if (xx) {
+ rpmlog(RPMLOG_ERR, _("could not move new database in place\n"));
+ xx = rename(old, dest);
+ if (xx) {
+ rpmlog(RPMLOG_ERR, _("could also not restore old database from %s\n"),
+ old);
+ rpmlog(RPMLOG_ERR, _("replace files in %s with files from %s "
+ "to recover\n"), dest, old);
+ }
+ goto exit;
+ }
+
+ if (access(oldkeys, F_OK ) != -1) {
+ xx = rename(oldkeys, destkeys);
+ if (xx) {
+ rpmlog(RPMLOG_ERR, _("Could not get public keys from %s\n"), oldkeys);
+ goto exit;
+ }
+ }
+
+ xx = rpmdbRemoveDatabase(old);
+ if (xx) {
+ rpmlog(RPMLOG_ERR, _("could not delete old database at %s\n"), old);
}
- cleanDbenv(prefix, dbpath);
- path = rpmGetPath(prefix, "/", dbpath, NULL);
- xx += rmdir(path);
- free(path);
+ rc = 0;
- return (xx != 0);
+ exit:
+ _free(src);
+ _free(old);
+ _free(dest);
+ _free(oldkeys);
+ _free(destkeys);
+ return rc;
}
-static int rpmdbMoveDatabase(const char * prefix,
- const char * olddbpath, const char * newdbpath)
+static int rpmdbSetPermissions(char * src, char * dest)
{
- int i;
+ struct dirent *dp;
+ DIR *dfd;
+
struct stat st;
- int rc = 0;
- int xx;
- int selinux = is_selinux_enabled() && (matchpathcon_init(NULL) != -1);
- sigset_t sigMask;
-
- blockSignals(&sigMask);
- for (i = 0; i < dbiTagsMax; i++) {
- rpmDbiTag rpmtag = dbiTags[i];
- const char *base = rpmTagGetName(rpmtag);
- char *src = rpmGetPath(prefix, "/", olddbpath, "/", base, NULL);
- char *dest = rpmGetPath(prefix, "/", newdbpath, "/", base, NULL);
-
- if (access(src, F_OK) != 0)
- goto cont;
-
- /*
- * Restore uid/gid/mode/security context if possible.
- */
- if (stat(dest, &st) < 0)
- if (stat(src, &st) < 0)
- goto cont;
-
- if ((xx = rename(src, dest)) != 0) {
- rc = 1;
- goto cont;
+ int xx, rc = -1;
+ char * filepath;
+
+ if (stat(dest, &st) < 0)
+ goto exit;
+ if (stat(src, &st) < 0)
+ goto exit;
+
+ if ((dfd = opendir(dest)) == NULL) {
+ goto exit;
+ }
+
+ rc = 0;
+ while ((dp = readdir(dfd)) != NULL) {
+ if (!strcmp(dp->d_name, "..")) {
+ continue;
}
- xx = chown(dest, st.st_uid, st.st_gid);
- xx = chmod(dest, (st.st_mode & 07777));
-
- if (selinux) {
- security_context_t scon = NULL;
- if (matchpathcon(dest, st.st_mode, &scon) != -1) {
- (void) setfilecon(dest, scon);
- freecon(scon);
- }
+ filepath = rpmGetPath(dest, "/", dp->d_name, NULL);
+ xx = chown(filepath, st.st_uid, st.st_gid);
+ rc += xx;
+ if (!strcmp(dp->d_name, ".")) {
+ xx = chmod(filepath, (st.st_mode & 07777));
+ } else {
+ xx = chmod(filepath, (st.st_mode & 07666));
}
-
-cont:
- free(src);
- free(dest);
+ rc += xx;
+ _free(filepath);
}
- cleanDbenv(prefix, olddbpath);
- cleanDbenv(prefix, newdbpath);
-
- unblockSignals(&sigMask);
-
- if (selinux) {
- (void) matchpathcon_fini();
- }
+ exit:
return rc;
}
@@ -2855,12 +2487,12 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
rpmdb olddb;
char * dbpath = NULL;
char * rootdbpath = NULL;
+ char * tmppath = NULL;
rpmdb newdb;
char * newdbpath = NULL;
char * newrootdbpath = NULL;
int nocleanup = 1;
int failed = 0;
- int removedir = 0;
int rc = 0;
dbpath = rpmGetPath("%{?_dbpath}", NULL);
@@ -2888,7 +2520,6 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
rc = 1;
goto exit;
}
- removedir = 1;
if (openDatabase(prefix, dbpath, &olddb,
O_RDONLY, 0644, RPMDB_FLAG_REBUILD)) {
@@ -2900,10 +2531,13 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
rc = 1;
goto exit;
}
+ if (rpmdbOpenAll(newdb)) {
+ rc = 1;
+ goto exit;
+ }
{ Header h = NULL;
rpmdbMatchIterator mi;
-#define _RECNUM rpmdbGetIteratorOffset(mi)
mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
if (ts && hdrchk)
@@ -2919,20 +2553,22 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
{
rpmlog(RPMLOG_ERR,
_("header #%u in the database is bad -- skipping.\n"),
- _RECNUM);
+ rpmdbGetIteratorOffset(mi));
continue;
}
/* Deleted entries are eliminated in legacy headers by copy. */
- { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
- ? headerCopy(h) : NULL);
- rc = rpmdbAdd(newdb, (nh ? nh : h));
+ if (headerIsEntry(h, RPMTAG_HEADERIMAGE)) {
+ Header nh = headerReload(headerCopy(h), RPMTAG_HEADERIMAGE);
+ rc = rpmdbAdd(newdb, h);
headerFree(nh);
+ } else {
+ rc = rpmdbAdd(newdb, h);
}
if (rc) {
- rpmlog(RPMLOG_ERR,
- _("cannot add record originally at %u\n"), _RECNUM);
+ rpmlog(RPMLOG_ERR, _("cannot add record originally at %u\n"),
+ rpmdbGetIteratorOffset(mi));
failed = 1;
break;
}
@@ -2950,15 +2586,20 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
_("failed to rebuild database: original database "
"remains in place\n"));
- rpmdbRemoveDatabase(prefix, newdbpath);
+ rpmdbRemoveDatabase(newrootdbpath);
rc = 1;
goto exit;
- } else if (!nocleanup) {
- if (rpmdbMoveDatabase(prefix, newdbpath, dbpath)) {
+ } else {
+ rpmdbSetPermissions(dbpath, newdbpath);
+ }
+
+ if (!nocleanup) {
+ rasprintf(&tmppath, "%sold.%d", dbpath, (int) getpid());
+ if (rpmdbMoveDatabase(prefix, newdbpath, dbpath, tmppath)) {
rpmlog(RPMLOG_ERR, _("failed to replace old database with new "
"database!\n"));
rpmlog(RPMLOG_ERR, _("replace files in %s with files from %s "
- "to recover"), dbpath, newdbpath);
+ "to recover\n"), dbpath, newdbpath);
rc = 1;
goto exit;
}
@@ -2966,15 +2607,35 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
rc = 0;
exit:
- if (removedir && !(rc == 0 && nocleanup)) {
- if (rmdir(newrootdbpath))
- rpmlog(RPMLOG_ERR, _("failed to remove directory %s: %s\n"),
- newrootdbpath, strerror(errno));
- }
free(newdbpath);
free(dbpath);
+ free(tmppath);
free(newrootdbpath);
free(rootdbpath);
return rc;
}
+
+int rpmdbCtrl(rpmdb db, rpmdbCtrlOp ctrl)
+{
+ dbCtrlOp dbctrl = 0;
+ switch (ctrl) {
+ case RPMDB_CTRL_LOCK_RO:
+ dbctrl = DB_CTRL_LOCK_RO;
+ break;
+ case RPMDB_CTRL_UNLOCK_RO:
+ dbctrl = DB_CTRL_UNLOCK_RO;
+ break;
+ case RPMDB_CTRL_LOCK_RW:
+ dbctrl = DB_CTRL_LOCK_RW;
+ break;
+ case RPMDB_CTRL_UNLOCK_RW:
+ dbctrl = DB_CTRL_UNLOCK_RW;
+ break;
+ case RPMDB_CTRL_INDEXSYNC:
+ dbctrl = DB_CTRL_INDEXSYNC;
+ break;
+ }
+ return dbctrl ? dbCtrl(db, dbctrl) : 1;
+}
+
diff --git a/lib/rpmdb.h b/lib/rpmdb.h
index 3c7aac2c8..78765bb15 100644
--- a/lib/rpmdb.h
+++ b/lib/rpmdb.h
@@ -3,7 +3,7 @@
/** \ingroup rpmdb dbi
* \file lib/rpmdb.h
- * Access RPM indices using Berkeley DB interface(s).
+ * RPM database API.
*/
#include <rpm/rpmtypes.h>
@@ -30,6 +30,14 @@ typedef enum rpmdbOpX_e {
RPMDB_OP_MAX = 4
} rpmdbOpX;
+typedef enum rpmdbCtrlOp_e {
+ RPMDB_CTRL_LOCK_RO = 1,
+ RPMDB_CTRL_UNLOCK_RO = 2,
+ RPMDB_CTRL_LOCK_RW = 3,
+ RPMDB_CTRL_UNLOCK_RW = 4,
+ RPMDB_CTRL_INDEXSYNC = 5
+} rpmdbCtrlOp;
+
/** \ingroup rpmdb
* Retrieve operation timestamp from rpm database.
* @param db rpm database
@@ -79,7 +87,7 @@ unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi);
* @return 0 on success, 1 on failure (bad args)
*/
int rpmdbAppendIterator(rpmdbMatchIterator mi,
- const int * hdrNums, int nHdrNums);
+ const unsigned int * hdrNums, unsigned int nHdrNums);
/** \ingroup rpmdb
* Add pattern to iterator selector.
@@ -138,21 +146,6 @@ rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmDbiTagVal rpmtag,
Header rpmdbNextIterator(rpmdbMatchIterator mi);
/** \ingroup rpmdb
- * Check for and exit on termination signals.
- */
-int rpmdbCheckSignals(void);
-
-/** \ingroup rpmdb
- * Check rpmdb signal handler for trapped signal and/or requested exit,
- * clean up any open iterators and databases on termination condition.
- * On non-zero exit any open references to rpmdb are invalid and cannot
- * be accessed anymore, calling process should terminate immediately.
- * @param terminate 0 to only check for signals, 1 to terminate anyway
- * @return 0 to continue, 1 if termination cleanup was done.
- */
-int rpmdbCheckTerminate(int terminate);
-
-/** \ingroup rpmdb
* Destroy rpm database iterator.
* @param mi rpm database iterator
* @return NULL always
@@ -171,13 +164,23 @@ rpmdbIndexIterator rpmdbIndexIteratorInit(rpmdb db, rpmDbiTag rpmtag);
* Get the next key - Warning! Keys are not zero terminated!
* Binary tags may even contain zero bytes
* @param ii index iterator
- * @param key adress to save the pointer to the key
- * @param keylen adress to save the length of the key to
+ * @param key address to save the pointer to the key
+ * @param keylen address to save the length of the key to
* @return 0 on success; != 0 on error or end of index
*/
int rpmdbIndexIteratorNext(rpmdbIndexIterator ii, const void ** key, size_t * keylen);
/** \ingroup rpmdb
+ * Get the next key into a tag data container.
+ * Caller is responsible for calling rpmtdFreeData() to freeing the
+ * data returned in keytd once done with it.
+ * @param ii index iterator
+ * @param keytd tag container to store the key in
+ * @return 0 on success; != 0 on error or end of index
+ */
+int rpmdbIndexIteratorNextTd(rpmdbIndexIterator ii, rpmtd keytd);
+
+/** \ingroup rpmdb
* Get number of entries for current key
* @param ii index iterator
* @return number of entries. 0 on error.
@@ -207,6 +210,13 @@ unsigned int rpmdbIndexIteratorTagNum(rpmdbIndexIterator ii, unsigned int nr);
*/
rpmdbIndexIterator rpmdbIndexIteratorFree(rpmdbIndexIterator ii);
+/** \ingroup rpmdb
+ * manipulate the rpm database
+ * @param db rpm database
+ * @param ctrl operation
+ * @return 0 on success; != 0 on error
+ */
+int rpmdbCtrl(rpmdb db, rpmdbCtrlOp ctrl);
#ifdef __cplusplus
}
diff --git a/lib/rpmdb_internal.h b/lib/rpmdb_internal.h
index ce95ce1b4..92848ab37 100644
--- a/lib/rpmdb_internal.h
+++ b/lib/rpmdb_internal.h
@@ -2,7 +2,6 @@
#define H_RPMDB_INTERNAL
#include <assert.h>
-#include <db.h>
#include <rpm/rpmsw.h>
#include <rpm/rpmtypes.h>
@@ -16,7 +15,7 @@ extern "C" {
#undef HASHTYPE
#undef HTKEYTYPE
#undef HTDATATYPE
-#define HASHTYPE removedHash
+#define HASHTYPE packageHash
#define HTKEYTYPE unsigned int
#define HTDATATYPE struct rpmte_s *
#include "rpmhash.H"
@@ -60,14 +59,6 @@ RPM_GNUC_INTERNAL
int rpmdbClose (rpmdb db);
/** \ingroup rpmdb
- * Sync all database indices.
- * @param db rpm database
- * @return 0 on success
- */
-RPM_GNUC_INTERNAL
-int rpmdbSync (rpmdb db);
-
-/** \ingroup rpmdb
* Rebuild database indices from package headers.
* @param prefix path to top of install tree
* @param ts transaction set (or NULL)
@@ -130,13 +121,31 @@ int rpmdbExtendIterator(rpmdbMatchIterator mi,
void rpmdbSortIterator(rpmdbMatchIterator mi);
/** \ingroup rpmdb
+ * uniq the iterator by recnum
+ * Return database iterator.
+ * @param mi rpm database iterator
+ */
+void rpmdbUniqIterator(rpmdbMatchIterator mi);
+
+/** \ingroup rpmdb
+ * If neg equals to zero then it leaves in iterator only packages that
+ * header numbers are in hdrNums. If neg is not zero then removes from iterator
+ * all packages that header numbers are in hdrNums.
+ * @param mi rpm database iterator
+ * @param hdrNums hash of package numbers
+ * @param neg mode
+ * return 0 on success, 1 on failure (bad args)
+ */
+int rpmdbFilterIterator(rpmdbMatchIterator mi, packageHash hdrNums, int neg);
+
+/** \ingroup rpmdb
* Remove items from set of package instances to iterate.
* @note Sorted hdrNums are always passed in rpmlib.
* @param mi rpm database iterator
* @param hdrNums hash of package instances
* @return 0 on success, 1 on failure (bad args)
*/
-int rpmdbPruneIterator(rpmdbMatchIterator mi, removedHash hdrNums);
+int rpmdbPruneIterator(rpmdbMatchIterator mi, packageHash hdrNums);
/** \ingroup rpmdb
* Create a new, empty match iterator (for purposes of extending it
@@ -148,16 +157,59 @@ int rpmdbPruneIterator(rpmdbMatchIterator mi, removedHash hdrNums);
RPM_GNUC_INTERNAL
rpmdbMatchIterator rpmdbNewIterator(rpmdb db, rpmDbiTagVal dbitag);
-#ifndef __APPLE__
-/**
- * * Mergesort, same arguments as qsort(2).
- * */
+/** \ingroup rpmdb
+ * Return database iterator that iterates over database items
+ * starting with pfx.
+ * @param db rpm database
+ * @param rpmtag database index tag
+ * @param pfx prefix data
+ * @param plen prefix data length (0 will use strlen(keyp))
+ * @return NULL on failure
+ */
+RPM_GNUC_INTERNAL
+rpmdbMatchIterator rpmdbInitPrefixIterator(rpmdb db, rpmDbiTagVal rpmtag,
+ const void * pfx, size_t plen);
+/** \ingroup rpmdb
+ * Get package offsets of entries
+ * @param ii index iterator
+ * @return db offsets of pkgs
+ */
+RPM_GNUC_INTERNAL
+unsigned int *rpmdbIndexIteratorPkgOffsets(rpmdbIndexIterator ii);
+
+/** \ingroup rpmdb
+ * Return current index (position) in iterator.
+ * @param mi rpm database iterator
+ * @return current index
+ */
+RPM_GNUC_INTERNAL
+int rpmdbGetIteratorIndex(rpmdbMatchIterator mi);
+
+/** \ingroup rpmdb
+ * Set iterator index.
+ * @param mi rpm database iterator
+ * @param ix index
+ */
+RPM_GNUC_INTERNAL
+void rpmdbSetIteratorIndex(rpmdbMatchIterator mi, unsigned int ix);
+
+/** \ingroup rpmdb
+ * Return offset of package with given index.
+ * @param mi rpm database iterator
+ * @param ix index
+ * @return package offset
+ */
+RPM_GNUC_INTERNAL
+unsigned int rpmdbGetIteratorOffsetFor(rpmdbMatchIterator mi, unsigned int ix);
+
+/** \ingroup rpmdb
+ * Return header located in rpmdb at given offset.
+ * @param db rpm database
+ * @param offset database offset
+ * @return header at given offset
+ */
RPM_GNUC_INTERNAL
-int mergesort(void *base, size_t nmemb, size_t size,
- int (*cmp) (const void *, const void *));
-#else
-/* mergesort is defined in stdlib.h on Mac OS X */
-#endif /* __APPLE__ */
+Header rpmdbGetHeaderAt(rpmdb db, unsigned int offset);
#ifdef __cplusplus
}
diff --git a/lib/rpmds.c b/lib/rpmds.c
index 1e6798648..823c722e8 100644
--- a/lib/rpmds.c
+++ b/lib/rpmds.c
@@ -32,19 +32,20 @@ struct rpmds_s {
int32_t Count; /*!< No. of elements */
unsigned int instance; /*!< From rpmdb instance? */
int i; /*!< Element index. */
- unsigned l; /*!< Low element (bsearch). */
- unsigned u; /*!< High element (bsearch). */
int nopromote; /*!< Don't promote Epoch: in rpmdsCompare()? */
int nrefs; /*!< Reference count. */
+ int *ti; /*!< Trigger index. */
};
static int dsType(rpmTagVal tag,
- const char ** Type, rpmTagVal * tagEVR, rpmTagVal * tagF)
+ const char ** Type, rpmTagVal * tagEVR, rpmTagVal * tagF,
+ rpmTagVal * tagTi)
{
int rc = 0;
const char *t = NULL;
rpmTagVal evr = RPMTAG_NOT_FOUND;
rpmTagVal f = RPMTAG_NOT_FOUND;
+ rpmTagVal ti = RPMTAG_NOT_FOUND;
if (tag == RPMTAG_PROVIDENAME) {
t = "Provides";
@@ -54,6 +55,22 @@ static int dsType(rpmTagVal tag,
t = "Requires";
evr = RPMTAG_REQUIREVERSION;
f = RPMTAG_REQUIREFLAGS;
+ } else if (tag == RPMTAG_SUPPLEMENTNAME) {
+ t = "Supplements";
+ evr = RPMTAG_SUPPLEMENTVERSION;
+ f = RPMTAG_SUPPLEMENTFLAGS;
+ } else if (tag == RPMTAG_ENHANCENAME) {
+ t = "Enhances";
+ evr = RPMTAG_ENHANCEVERSION;
+ f = RPMTAG_ENHANCEFLAGS;
+ } else if (tag == RPMTAG_RECOMMENDNAME) {
+ t = "Recommends";
+ evr = RPMTAG_RECOMMENDVERSION;
+ f = RPMTAG_RECOMMENDFLAGS;
+ } else if (tag == RPMTAG_SUGGESTNAME) {
+ t = "Suggests";
+ evr = RPMTAG_SUGGESTVERSION;
+ f = RPMTAG_SUGGESTFLAGS;
} else if (tag == RPMTAG_CONFLICTNAME) {
t = "Conflicts";
evr = RPMTAG_CONFLICTVERSION;
@@ -70,19 +87,103 @@ static int dsType(rpmTagVal tag,
t = "Trigger";
evr = RPMTAG_TRIGGERVERSION;
f = RPMTAG_TRIGGERFLAGS;
- } else if (tag == RPMTAG_ENHANCESNAME) {
- t = "Enhances";
- evr = RPMTAG_ENHANCESVERSION;
- f = RPMTAG_ENHANCESFLAGS;
+ ti = RPMTAG_TRIGGERINDEX;
+ } else if (tag == RPMTAG_OLDSUGGESTSNAME) {
+ t = "Oldsuggests";
+ evr = RPMTAG_OLDSUGGESTSVERSION;
+ f = RPMTAG_OLDSUGGESTSFLAGS;
+ } else if (tag == RPMTAG_OLDENHANCESNAME) {
+ t = "Oldenhances";
+ evr = RPMTAG_OLDENHANCESVERSION;
+ f = RPMTAG_OLDENHANCESFLAGS;
+ } else if (tag == RPMTAG_FILETRIGGERNAME) {
+ t = "FileTrigger";
+ evr = RPMTAG_FILETRIGGERVERSION;
+ f = RPMTAG_FILETRIGGERFLAGS;
+ ti = RPMTAG_FILETRIGGERINDEX;
+ } else if (tag == RPMTAG_TRANSFILETRIGGERNAME) {
+ t = "TransFileTrigger";
+ evr = RPMTAG_TRANSFILETRIGGERVERSION;
+ f = RPMTAG_TRANSFILETRIGGERFLAGS;
+ ti = RPMTAG_TRANSFILETRIGGERINDEX;
} else {
rc = 1;
}
if (Type) *Type = t;
if (tagEVR) *tagEVR = evr;
if (tagF) *tagF = f;
+ if (tagTi) *tagTi = ti;
return rc;
}
+static char tagNToChar(rpmTagVal tagN)
+{
+ switch (tagN) {
+ default:
+ return 'R';
+ break;
+ case RPMTAG_REQUIRENAME:
+ return 'R';
+ break;
+ case RPMTAG_PROVIDENAME:
+ return 'P';
+ break;
+ case RPMTAG_RECOMMENDNAME:
+ return 'r';
+ break;
+ case RPMTAG_SUGGESTNAME:
+ return 's';
+ break;
+ case RPMTAG_SUPPLEMENTNAME:
+ return 'S';
+ break;
+ case RPMTAG_ENHANCENAME:
+ return 'e';
+ break;
+ case RPMTAG_CONFLICTNAME:
+ return 'C';
+ break;
+ case RPMTAG_OBSOLETENAME:
+ return 'O';
+ break;
+ }
+}
+
+rpmTagVal rpmdsDToTagN(char deptype)
+{
+ rpmTagVal tagN = RPMTAG_REQUIRENAME;
+ switch (deptype) {
+ default:
+ tagN = RPMTAG_NOT_FOUND;
+ break;
+ case 'P':
+ tagN = RPMTAG_PROVIDENAME;
+ break;
+ case 'R':
+ tagN = RPMTAG_REQUIRENAME;
+ break;
+ case 'r':
+ tagN = RPMTAG_RECOMMENDNAME;
+ break;
+ case 's':
+ tagN = RPMTAG_SUGGESTNAME;
+ break;
+ case 'S':
+ tagN = RPMTAG_SUPPLEMENTNAME;
+ break;
+ case 'e':
+ tagN = RPMTAG_ENHANCENAME;
+ break;
+ case 'C':
+ tagN = RPMTAG_CONFLICTNAME;
+ break;
+ case 'O':
+ tagN = RPMTAG_OBSOLETENAME;
+ break;
+ }
+ return tagN;
+}
+
rpmsid rpmdsNIdIndex(rpmds ds, int i)
{
rpmsid id = 0;
@@ -122,6 +223,14 @@ rpmsenseFlags rpmdsFlagsIndex(rpmds ds, int i)
return Flags;
}
+int rpmdsTiIndex(rpmds ds, int i)
+{
+ int ti = -1;
+ if (ds != NULL && i >= 0 && i < ds->Count && ds->ti != NULL)
+ ti = ds->ti[i];
+ return ti;
+}
+
rpm_color_t rpmdsColorIndex(rpmds ds, int i)
{
rpm_color_t Color = 0;
@@ -145,7 +254,7 @@ rpmds rpmdsLink(rpmds ds)
rpmds rpmdsFree(rpmds ds)
{
- rpmTagVal tagEVR, tagF;
+ rpmTagVal tagEVR, tagF, tagTi;
if (ds == NULL)
return NULL;
@@ -153,13 +262,14 @@ rpmds rpmdsFree(rpmds ds)
if (ds->nrefs > 1)
return rpmdsUnlink(ds);
- if (dsType(ds->tagN, NULL, &tagEVR, &tagF))
+ if (dsType(ds->tagN, NULL, &tagEVR, &tagF, &tagTi))
return NULL;
if (ds->Count > 0) {
ds->N = _free(ds->N);
ds->EVR = _free(ds->EVR);
ds->Flags = _free(ds->Flags);
+ ds->ti = _free(ds->ti);
}
ds->pool = rpmstrPoolFree(ds->pool);
@@ -191,24 +301,46 @@ static rpmds rpmdsCreate(rpmstrPool pool,
rpmds rpmdsNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, int flags)
{
- rpmTagVal tagEVR, tagF;
+ rpmTagVal tagEVR, tagF, tagTi;
rpmds ds = NULL;
const char * Type;
struct rpmtd_s names;
- if (dsType(tagN, &Type, &tagEVR, &tagF))
+ if (dsType(tagN, &Type, &tagEVR, &tagF, &tagTi))
goto exit;
if (headerGet(h, tagN, &names, HEADERGET_MINMEM)) {
- struct rpmtd_s evr, flags;
+ struct rpmtd_s evr, flags, tindices;
+ rpm_count_t count = rpmtdCount(&names);
- ds = rpmdsCreate(pool, tagN, Type,
- rpmtdCount(&names), headerGetInstance(h));
-
- ds->N = rpmtdToPool(&names, ds->pool);
headerGet(h, tagEVR, &evr, HEADERGET_MINMEM);
- ds->EVR = rpmtdToPool(&evr, ds->pool);
+ if (evr.count && evr.count != count) {
+ rpmtdFreeData(&evr);
+ return NULL;
+ }
+
headerGet(h, tagF, &flags, HEADERGET_ALLOC);
+ if (flags.count && flags.count != count) {
+ rpmtdFreeData(&flags);
+ return NULL;
+ }
+
+ if (tagTi != RPMTAG_NOT_FOUND) {
+ headerGet(h, tagTi, &tindices, HEADERGET_ALLOC);
+ if (tindices.count && tindices.count != count) {
+ rpmtdFreeData(&tindices);
+ return NULL;
+ }
+ }
+
+ ds = rpmdsCreate(pool, tagN, Type, count, headerGetInstance(h));
+
+ ds->N = names.count ? rpmtdToPool(&names, ds->pool) : NULL;
+ ds->EVR = evr.count ? rpmtdToPool(&evr, ds->pool): NULL;
ds->Flags = flags.data;
+ if (tagTi != RPMTAG_NOT_FOUND) {
+ ds->ti = tindices.data;
+ }
+
/* ensure rpmlib() requires always have RPMSENSE_RPMLIB flag set */
if (tagN == RPMTAG_REQUIRENAME && ds->Flags) {
for (int i = 0; i < ds->Count; i++) {
@@ -285,12 +417,14 @@ char * rpmdsNewDNEVR(const char * dspfx, const rpmds ds)
static rpmds singleDSPool(rpmstrPool pool, rpmTagVal tagN,
rpmsid N, rpmsid EVR, rpmsenseFlags Flags,
- unsigned int instance, rpm_color_t Color)
+ unsigned int instance, rpm_color_t Color,
+ int triggerIndex)
{
rpmds ds = NULL;
const char * Type;
+ rpmTagVal tagTi;
- if (dsType(tagN, &Type, NULL, NULL))
+ if (dsType(tagN, &Type, NULL, NULL, &tagTi))
goto exit;
ds = rpmdsCreate(pool, tagN, Type, 1, instance);
@@ -301,6 +435,10 @@ static rpmds singleDSPool(rpmstrPool pool, rpmTagVal tagN,
ds->EVR[0] = EVR;
ds->Flags = xmalloc(sizeof(*ds->Flags));
ds->Flags[0] = Flags;
+ if (tagTi != RPMTAG_NOT_FOUND) {
+ ds->ti = xmalloc(sizeof(*ds->ti));
+ ds->ti[0] = triggerIndex;
+ }
ds->i = 0;
if (Color)
rpmdsSetColor(ds, Color);
@@ -312,9 +450,10 @@ exit:
static rpmds singleDS(rpmstrPool pool, rpmTagVal tagN,
const char * N, const char * EVR,
rpmsenseFlags Flags, unsigned int instance,
- rpm_color_t Color)
+ rpm_color_t Color, int triggerIndex)
{
- rpmds ds = singleDSPool(pool, tagN, 0, 0, Flags, instance, Color);
+ rpmds ds = singleDSPool(pool, tagN, 0, 0, Flags, instance, Color,
+ triggerIndex);
if (ds) {
/* now that we have a pool, we can insert our N & EVR strings */
ds->N[0] = rpmstrPoolId(ds->pool, N ? N : "", 1);
@@ -331,7 +470,7 @@ rpmds rpmdsThisPool(rpmstrPool pool,
{
char *evr = headerGetAsString(h, RPMTAG_EVR);
rpmds ds = singleDS(pool, tagN, headerGetString(h, RPMTAG_NAME),
- evr, Flags, headerGetInstance(h), 0);
+ evr, Flags, headerGetInstance(h), 0, 0);
free(evr);
return ds;
}
@@ -344,7 +483,14 @@ rpmds rpmdsThis(Header h, rpmTagVal tagN, rpmsenseFlags Flags)
rpmds rpmdsSinglePool(rpmstrPool pool,rpmTagVal tagN,
const char * N, const char * EVR, rpmsenseFlags Flags)
{
- return singleDS(pool, tagN, N, EVR, Flags, 0, 0);
+ return singleDS(pool, tagN, N, EVR, Flags, 0, 0, 0);
+}
+
+rpmds rpmdsSinglePoolTix(rpmstrPool pool,rpmTagVal tagN,
+ const char * N, const char * EVR,
+ rpmsenseFlags Flags, int triggerIndex)
+{
+ return singleDS(pool, tagN, N, EVR, Flags, 0, 0, triggerIndex);
}
rpmds rpmdsSingle(rpmTagVal tagN, const char * N, const char * EVR, rpmsenseFlags Flags)
@@ -355,14 +501,78 @@ rpmds rpmdsSingle(rpmTagVal tagN, const char * N, const char * EVR, rpmsenseFlag
rpmds rpmdsCurrent(rpmds ds)
{
rpmds cds = NULL;
+ int ti = -1;
if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ if (ds->ti)
+ ti = ds->ti[ds->i];
/* Using parent's pool so we can just use the same id's */
cds = singleDSPool(ds->pool, ds->tagN, ds->N[ds->i], ds->EVR[ds->i],
- rpmdsFlags(ds), ds->instance, rpmdsColor(ds));
+ rpmdsFlags(ds), ds->instance, rpmdsColor(ds), ti);
}
return cds;
}
+rpmds rpmdsFilterTi(rpmds ds, int ti)
+{
+ int i, i2, tiCount = 0;
+ rpmds fds;
+
+ if (ds == NULL || !ds->ti || !ds->Count)
+ return NULL;
+
+ for (i = 0; i < ds->Count; i++) {
+ if (ds->ti[i] == ti)
+ tiCount++;
+ }
+
+ if (!tiCount)
+ return NULL;
+
+ fds = rpmdsCreate(ds->pool, ds->tagN, ds->Type, tiCount, ds->instance);
+
+ fds->N = xmalloc(tiCount * sizeof(*fds->N));
+ fds->EVR = xmalloc(tiCount * sizeof(*fds->EVR));
+ fds->Flags = xmalloc(tiCount * sizeof(*fds->Flags));
+ fds->ti = xmalloc(tiCount * sizeof(*fds->ti));
+ fds->i = -1;
+
+ i2 = 0;
+ for (i = 0; i < ds->Count; i++) {
+ if (ds->ti[i] == ti) {
+ fds->N[i2] = ds->N[i];
+ fds->EVR[i2] = ds->EVR[i];
+ fds->Flags[i2] = ds->Flags[i];
+ fds->ti[i2] = ds->ti[i];
+ i2++;
+ }
+ }
+
+ return fds;
+}
+
+int rpmdsPutToHeader(rpmds ds, Header h)
+{
+ rpmTagVal tagN = rpmdsTagN(ds);
+ rpmTagVal tagEVR = rpmdsTagEVR(ds);
+ rpmTagVal tagF = rpmdsTagF(ds);
+ rpmTagVal tagTi = rpmdsTagTi(ds);
+ if (!tagN)
+ return -1;
+
+ rpmds pi = rpmdsInit(ds);
+ while (rpmdsNext(pi) >= 0) {
+ rpmsenseFlags flags = rpmdsFlags(pi);
+ uint32_t index = rpmdsTi(pi);
+ headerPutString(h, tagN, rpmdsN(pi));
+ headerPutString(h, tagEVR, rpmdsEVR(pi));
+ headerPutUint32(h, tagF, &flags, 1);
+ if (tagTi != RPMTAG_NOT_FOUND) {
+ headerPutUint32(h, tagTi, &index, 1);
+ }
+ }
+ return 0;
+}
+
int rpmdsCount(const rpmds ds)
{
return (ds != NULL ? ds->Count : 0);
@@ -385,13 +595,22 @@ int rpmdsSetIx(rpmds ds, int ix)
return i;
}
+char rpmdsD(const rpmds ds)
+{
+ if (ds != NULL) {
+ return tagNToChar(ds->tagN);
+ } else {
+ return '\0';
+ }
+}
+
const char * rpmdsDNEVR(const rpmds ds)
{
const char * DNEVR = NULL;
if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
if (ds->DNEVR == NULL) {
- char t[2] = { ds->Type[0], '\0' };
+ char t[2] = { tagNToChar(ds->tagN), '\0' };
ds->DNEVR = rpmdsNewDNEVR(t, ds);
}
DNEVR = ds->DNEVR;
@@ -424,6 +643,11 @@ rpmsenseFlags rpmdsFlags(const rpmds ds)
return (ds != NULL) ? rpmdsFlagsIndex(ds, ds->i) : 0;
}
+int rpmdsTi(const rpmds ds)
+{
+ return (ds != NULL) ? rpmdsTiIndex(ds, ds->i) : 0;
+}
+
rpmTagVal rpmdsTagN(const rpmds ds)
{
rpmTagVal tagN = RPMTAG_NOT_FOUND;
@@ -433,6 +657,33 @@ rpmTagVal rpmdsTagN(const rpmds ds)
return tagN;
}
+rpmTagVal rpmdsTagEVR(const rpmds ds)
+{
+ rpmTagVal tagEVR = RPMTAG_NOT_FOUND;
+
+ if (ds != NULL)
+ dsType(ds->tagN, NULL, &tagEVR, NULL, NULL);
+ return tagEVR;
+}
+
+rpmTagVal rpmdsTagF(const rpmds ds)
+{
+ rpmTagVal tagF = RPMTAG_NOT_FOUND;
+
+ if (ds != NULL)
+ dsType(ds->tagN, NULL, NULL, &tagF, NULL);
+ return tagF;
+}
+
+rpmTagVal rpmdsTagTi(const rpmds ds)
+{
+ rpmTagVal tagTi = RPMTAG_NOT_FOUND;
+
+ if (ds != NULL)
+ dsType(ds->tagN, NULL, NULL, NULL, &tagTi);
+ return tagTi;
+}
+
unsigned int rpmdsInstance(rpmds ds)
{
return (ds != NULL) ? ds->instance : 0;
@@ -529,8 +780,6 @@ static rpmds rpmdsDup(const rpmds ods)
size_t nb;
ds->i = ods->i;
- ds->l = ods->l;
- ds->u = ods->u;
ds->nopromote = ods->nopromote;
nb = ds->Count * sizeof(*ds->N);
@@ -547,58 +796,77 @@ static rpmds rpmdsDup(const rpmds ods)
ds->Flags = memcpy(xmalloc(nb), ods->Flags, nb);
}
+ if (ods->ti) {
+ nb = ds->Count * sizeof(*ds->ti);
+ ds->ti = memcpy(xmalloc(nb), ods->ti, nb);
+ }
+
return ds;
}
-int rpmdsFind(rpmds ds, const rpmds ods)
+static int doFind(rpmds ds, const rpmds ods, unsigned int *he)
{
int comparison;
const char *N, *ON = rpmdsN(ods);
const char *EVR, *OEVR = rpmdsEVR(ods);
rpmsenseFlags Flags, OFlags = rpmdsFlags(ods);
+ int index, Oindex = rpmdsTi(ods);
int rc = -1; /* assume not found */
if (ds == NULL || ods == NULL)
return -1;
- ds->l = 0;
- ds->u = ds->Count;
- while (ds->l < ds->u) {
- ds->i = (ds->l + ds->u) / 2;
+ unsigned int l = 0;
+ unsigned int u = ds->Count;
+ while (l < u) {
+ ds->i = (l + u) / 2;
N = rpmdsN(ds);
EVR = rpmdsEVR(ds);
Flags = rpmdsFlags(ds);
+ index = rpmdsTi(ds);
comparison = strcmp(ON, N);
/* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
if (comparison == 0 && OEVR && EVR)
comparison = strcmp(OEVR, EVR);
- if (comparison == 0 && OFlags && Flags)
+ if (comparison == 0)
comparison = OFlags - Flags;
+ if (comparison == 0)
+ comparison = Oindex - index;
if (comparison < 0)
- ds->u = ds->i;
+ u = ds->i;
else if (comparison > 0)
- ds->l = ds->i + 1;
+ l = ds->i + 1;
else {
rc = ds->i;
break;
}
}
+ if (he)
+ *he = u;
return rc;
}
+int rpmdsFind(rpmds ds, const rpmds ods)
+{
+ return doFind(ds, ods, NULL);
+}
+
int rpmdsMerge(rpmds * dsp, rpmds ods)
{
rpmds ds;
int save;
+ int ocount;
if (dsp == NULL || ods == NULL)
return -1;
+ ocount = rpmdsCount(*dsp);
+
/* If not initialized yet, dup the 1st entry. */
if (*dsp == NULL) {
save = ods->Count;
@@ -615,6 +883,12 @@ int rpmdsMerge(rpmds * dsp, rpmds ods)
ds->EVR = xcalloc(ds->Count, sizeof(*ds->EVR));
if (ds->Flags == NULL)
ds->Flags = xcalloc(ds->Count, sizeof(*ds->Flags));
+ if (ds->ti == NULL && ods->ti) {
+ int i;
+ ds->ti = xcalloc(ds->Count, sizeof(*ds->ti));
+ for (i = 0; i < ds->Count; i++)
+ ds->ti[i] = -1;
+ }
/*
* Add new entries.
@@ -623,10 +897,11 @@ int rpmdsMerge(rpmds * dsp, rpmds ods)
ods = rpmdsInit(ods);
while (rpmdsNext(ods) >= 0) {
const char *OEVR;
+ unsigned int u;
/*
* If this entry is already present, don't bother.
*/
- if (rpmdsFind(ds, ods) >= 0)
+ if (doFind(ds, ods, &u) >= 0)
continue;
/*
@@ -634,33 +909,42 @@ int rpmdsMerge(rpmds * dsp, rpmds ods)
*/
rpmstrPoolUnfreeze(ds->pool);
ds->N = xrealloc(ds->N, (ds->Count+1) * sizeof(*ds->N));
- if (ds->u < ds->Count) {
- memmove(ds->N + ds->u + 1, ds->N + ds->u,
- (ds->Count - ds->u) * sizeof(*ds->N));
+ if (u < ds->Count) {
+ memmove(ds->N + u + 1, ds->N + u,
+ (ds->Count - u) * sizeof(*ds->N));
}
- ds->N[ds->u] = rpmstrPoolId(ds->pool, rpmdsN(ods), 1);
+ ds->N[u] = rpmstrPoolId(ds->pool, rpmdsN(ods), 1);
ds->EVR = xrealloc(ds->EVR, (ds->Count+1) * sizeof(*ds->EVR));
- if (ds->u < ds->Count) {
- memmove(ds->EVR + ds->u + 1, ds->EVR + ds->u,
- (ds->Count - ds->u) * sizeof(*ds->EVR));
+ if (u < ds->Count) {
+ memmove(ds->EVR + u + 1, ds->EVR + u,
+ (ds->Count - u) * sizeof(*ds->EVR));
}
OEVR = rpmdsEVR(ods);
- ds->EVR[ds->u] = rpmstrPoolId(ds->pool, OEVR ? OEVR : "", 1);
+ ds->EVR[u] = rpmstrPoolId(ds->pool, OEVR ? OEVR : "", 1);
ds->Flags = xrealloc(ds->Flags, (ds->Count+1) * sizeof(*ds->Flags));
- if (ds->u < ds->Count) {
- memmove(ds->Flags + ds->u + 1, ds->Flags + ds->u,
- (ds->Count - ds->u) * sizeof(*ds->Flags));
+ if (u < ds->Count) {
+ memmove(ds->Flags + u + 1, ds->Flags + u,
+ (ds->Count - u) * sizeof(*ds->Flags));
+ }
+ ds->Flags[u] = rpmdsFlags(ods);
+
+ if (ds->ti || ods->ti) {
+ ds->ti = xrealloc(ds->ti, (ds->Count+1) * sizeof(*ds->ti));
+ if (u < ds->Count) {
+ memmove(ds->ti + u + 1, ds->ti + u,
+ (ds->Count - u) * sizeof(*ds->ti));
+ }
+ ds->ti[u] = rpmdsTi(ods);
}
- ds->Flags[ds->u] = rpmdsFlags(ods);
ds->i = ds->Count;
ds->Count++;
}
ods->i = save;
- return 0;
+ return (ds->Count - ocount);
}
@@ -988,6 +1272,17 @@ static const struct rpmlibProvides_s rpmlibProvides[] = {
{ "rpmlib(TildeInVersions)", "4.10.0-1",
( RPMSENSE_EQUAL),
N_("dependency comparison supports versions with tilde.") },
+ { "rpmlib(LargeFiles)", "4.12.0-1",
+ ( RPMSENSE_EQUAL),
+ N_("support files larger than 4GB") },
+ { "rpmlib(RichDependencies)", "4.12.0-1",
+ ( RPMSENSE_EQUAL),
+ N_("support for rich dependencies.") },
+#ifdef HAVE_ZSTD
+ { "rpmlib(PayloadIsZstd)", "5.4.18-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("package payload can be compressed using zstd.") },
+#endif
{ NULL, NULL, 0, NULL }
};
@@ -1001,7 +1296,7 @@ int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp)
if (rltblp == NULL)
rltblp = rpmlibProvides;
- for (rlp = rltblp; rlp->featureName != NULL && rc == 0; rlp++) {
+ for (rlp = rltblp; rlp->featureName != NULL && rc >= 0; rlp++) {
rpmds ds = rpmdsSinglePool(pool, RPMTAG_PROVIDENAME, rlp->featureName,
rlp->featureEVR, rlp->featureFlags);
rc = rpmdsMerge(dsp, ds);
@@ -1010,7 +1305,7 @@ int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp)
/* freeze the pool to save memory, but only if private pool */
if (*dsp && (*dsp)->pool != pool)
rpmstrPoolFreeze((*dsp)->pool, 0);
- return rc;
+ return (rc < 0) ? -1 : 0;
}
int rpmdsRpmlib(rpmds * dsp, const void * tblp)
@@ -1022,3 +1317,392 @@ rpmstrPool rpmdsPool(rpmds ds)
{
return (ds != NULL) ? ds->pool : NULL;
}
+
+rpmsenseFlags rpmSanitizeDSFlags(rpmTagVal tagN, rpmsenseFlags Flags)
+{
+ rpmsenseFlags extra = RPMSENSE_ANY;
+ switch (tagN) {
+ case RPMTAG_PROVIDENAME:
+ extra = Flags & RPMSENSE_FIND_PROVIDES;
+ break;
+ case RPMTAG_TRIGGERNAME:
+ case RPMTAG_FILETRIGGERNAME:
+ case RPMTAG_TRANSFILETRIGGERNAME:
+ extra = Flags & RPMSENSE_TRIGGER;
+ break;
+ case RPMTAG_RECOMMENDNAME:
+ case RPMTAG_SUGGESTNAME:
+ case RPMTAG_SUPPLEMENTNAME:
+ case RPMTAG_ENHANCENAME:
+ case RPMTAG_REQUIRENAME:
+ extra = Flags & (_ALL_REQUIRES_MASK);
+ break;
+ case RPMTAG_CONFLICTNAME:
+ extra = Flags;
+ break;
+ default:
+ break;
+ }
+ return (Flags & RPMSENSE_SENSEMASK) | extra;
+}
+
+static struct ReqComp {
+const char * token;
+ rpmsenseFlags sense;
+} const ReqComparisons[] = {
+ { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL},
+ { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL},
+ { "<", RPMSENSE_LESS},
+
+ { "==", RPMSENSE_EQUAL},
+ { "=", RPMSENSE_EQUAL},
+
+ { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL},
+ { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL},
+ { ">", RPMSENSE_GREATER},
+
+ { NULL, 0 },
+};
+
+rpmsenseFlags rpmParseDSFlags(const char *str, size_t len)
+{
+ const struct ReqComp *rc;
+ for (rc = ReqComparisons; rc->token != NULL; rc++)
+ if (len == strlen(rc->token) && rstreqn(str, rc->token, len))
+ return rc->sense;
+ return 0;
+}
+
+static struct RichOpComp {
+ const char * token;
+ rpmrichOp op;
+} const RichOps[] = {
+ { "and", RPMRICHOP_AND},
+ { "or", RPMRICHOP_OR},
+ { "if", RPMRICHOP_IF},
+ { "unless", RPMRICHOP_UNLESS},
+ { "else", RPMRICHOP_ELSE},
+ { "with", RPMRICHOP_WITH},
+ { "without", RPMRICHOP_WITHOUT},
+ { NULL, 0 },
+};
+
+int rpmdsIsRich(rpmds dep)
+{
+ const char * n = rpmdsN(dep);
+ return (n && n[0] == '(');
+}
+
+static rpmRC parseRichDepOp(const char **dstrp, rpmrichOp *opp, char **emsg)
+{
+ const char *p = *dstrp, *pe = p;
+ const struct RichOpComp *ro;
+
+ while (*pe && !risspace(*pe) && *pe != ')')
+ pe++;
+ for (ro = RichOps; ro->token != NULL; ro++)
+ if (pe - p == strlen(ro->token) && rstreqn(p, ro->token, pe - p)) {
+ *opp = ro->op;
+ *dstrp = pe;
+ return RPMRC_OK;
+ }
+ if (emsg)
+ rasprintf(emsg, _("Unknown rich dependency op '%.*s'"), (int)(pe - p), p);
+ return RPMRC_FAIL;
+}
+
+const char *rpmrichOpStr(rpmrichOp op)
+{
+ if (op == RPMRICHOP_SINGLE)
+ return "SINGLE";
+ if (op == RPMRICHOP_AND)
+ return "and";
+ if (op == RPMRICHOP_OR)
+ return "or";
+ if (op == RPMRICHOP_IF)
+ return "if";
+ if (op == RPMRICHOP_UNLESS)
+ return "unless";
+ if (op == RPMRICHOP_ELSE)
+ return "else";
+ if (op == RPMRICHOP_WITH)
+ return "with";
+ if (op == RPMRICHOP_WITHOUT)
+ return "without";
+ return NULL;
+}
+
+
+#define SKIPWHITE(_x) {while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
+#define SKIPNONWHITEX(_x){int bl = 0; while (*(_x) &&!(risspace(*_x) || *(_x) == ',' || (*(_x) == ')' && bl-- <= 0))) if (*(_x)++ == '(') bl++;}
+
+static rpmRC parseSimpleDep(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
+{
+ const char *p = *dstrp;
+ const char *n, *e = 0;
+ int nl, el = 0;
+ rpmsenseFlags sense = 0;
+
+ n = p;
+ SKIPNONWHITEX(p);
+ nl = p - n;
+ if (nl == 0) {
+ if (emsg)
+ rasprintf(emsg, _("Name required"));
+ return RPMRC_FAIL;
+ }
+ SKIPWHITE(p);
+ if (*p) {
+ const char *pe = p;
+
+ SKIPNONWHITEX(pe);
+ sense = rpmParseDSFlags(p, pe - p);
+ if (sense) {
+ p = pe;
+ SKIPWHITE(p);
+ e = p;
+ SKIPNONWHITEX(p);
+ el = p - e;
+ }
+ }
+ if (e && el == 0) {
+ if (emsg)
+ rasprintf(emsg, _("Version required"));
+ return RPMRC_FAIL;
+ }
+ if (cb && cb(cbdata, RPMRICH_PARSE_SIMPLE, n, nl, e, el, sense, RPMRICHOP_SINGLE, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ *dstrp = p;
+ return RPMRC_OK;
+}
+
+#define RICHPARSE_CHECK (1 << 0)
+#define RICHPARSE_NO_WITH (1 << 1)
+#define RICHPARSE_NO_AND (1 << 2)
+#define RICHPARSE_NO_OR (1 << 3)
+
+static rpmRC rpmrichParseCheck(rpmrichOp op, int check, char **emsg)
+{
+ if ((op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) && (check & RICHPARSE_NO_WITH) != 0) {
+ if (emsg)
+ rasprintf(emsg, _("Illegal ops in with/without"));
+ return RPMRC_FAIL;
+ }
+ if ((check & RICHPARSE_CHECK) == 0)
+ return RPMRC_OK;
+ if ((op == RPMRICHOP_AND || op == RPMRICHOP_IF) && (check & RICHPARSE_NO_AND) != 0) {
+ if (emsg)
+ rasprintf(emsg, _("Illegal context for 'unless', please use 'or' instead"));
+ return RPMRC_FAIL;
+ }
+ if ((op == RPMRICHOP_OR || op == RPMRICHOP_UNLESS) && (check & RICHPARSE_NO_OR) != 0) {
+ if (emsg)
+ rasprintf(emsg, _("Illegal context for 'if', please use 'and' instead"));
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, int *checkp)
+{
+ const char *p = *dstrp, *pe;
+ rpmrichOp op = RPMRICHOP_SINGLE, firstop = RPMRICHOP_SINGLE, chainop = 0;
+ int check = checkp ? *checkp : 0;
+
+ if (cb && cb(cbdata, RPMRICH_PARSE_ENTER, p, 0, 0, 0, 0, op, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ if (*p++ != '(') {
+ if (emsg)
+ rasprintf(emsg, _("Rich dependency does not start with '('"));
+ return RPMRC_FAIL;
+ }
+ for (;;) {
+ SKIPWHITE(p);
+ if (*p == ')') {
+ if (emsg) {
+ if (chainop)
+ rasprintf(emsg, _("Missing argument to rich dependency op"));
+ else
+ rasprintf(emsg, _("Empty rich dependency"));
+ }
+ return RPMRC_FAIL;
+ }
+ if (*p == '(') {
+ int subcheck = check & RICHPARSE_CHECK;
+ if (rpmrichParseInternal(&p, emsg, cb, cbdata, &subcheck) != RPMRC_OK)
+ return RPMRC_FAIL;
+ if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS)
+ subcheck &= ~(RICHPARSE_NO_AND | RICHPARSE_NO_OR);
+ check |= subcheck;
+ } else {
+ if (parseSimpleDep(&p, emsg, cb, cbdata) != RPMRC_OK)
+ return RPMRC_FAIL;
+ }
+ SKIPWHITE(p);
+ if (!*p) {
+ if (emsg)
+ rasprintf(emsg, _("Unterminated rich dependency: %s"), *dstrp);
+ return RPMRC_FAIL;
+ }
+ if (*p == ')')
+ break;
+ pe = p;
+ if (parseRichDepOp(&pe, &op, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ if (firstop == RPMRICHOP_SINGLE)
+ firstop = op;
+
+ if (op == RPMRICHOP_ELSE && (chainop == RPMRICHOP_IF || chainop == RPMRICHOP_UNLESS))
+ chainop = 0;
+ if (chainop && op != chainop) {
+ if (emsg)
+ rasprintf(emsg, _("Cannot chain different ops"));
+ return RPMRC_FAIL;
+ }
+ if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR && op != RPMRICHOP_WITH) {
+ if (emsg)
+ rasprintf(emsg, _("Can only chain and/or/with ops"));
+ return RPMRC_FAIL;
+ }
+ if (cb && cb(cbdata, RPMRICH_PARSE_OP, p, pe - p, 0, 0, 0, op, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ chainop = op;
+ p = pe;
+ }
+
+ /* check for illegal combinations */
+ if (rpmrichParseCheck(firstop, check, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+
+ /* update check data */
+ if (firstop == RPMRICHOP_IF)
+ check |= RICHPARSE_NO_OR;
+ if (firstop == RPMRICHOP_UNLESS)
+ check |= RICHPARSE_NO_AND;
+ if (op == RPMRICHOP_AND || op == RPMRICHOP_OR)
+ check &= ~(RICHPARSE_NO_AND | RICHPARSE_NO_OR);
+ if (op != RPMRICHOP_SINGLE && op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT && op != RPMRICHOP_OR)
+ check |= RICHPARSE_NO_WITH;
+
+ p++;
+ if (cb && cb(cbdata, RPMRICH_PARSE_LEAVE, *dstrp, p - *dstrp , 0, 0, 0, op, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ *dstrp = p;
+ if (checkp)
+ *checkp |= check;
+ return RPMRC_OK;
+}
+
+rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
+{
+ return rpmrichParseInternal(dstrp, emsg, cb, cbdata, NULL);
+}
+
+rpmRC rpmrichParseForTag(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, rpmTagVal tagN)
+{
+ int check = RICHPARSE_CHECK;
+ if (rpmrichParseInternal(dstrp, emsg, cb, cbdata, &check) != RPMRC_OK)
+ return RPMRC_FAIL;
+ switch (tagN) {
+ case RPMTAG_CONFLICTNAME:
+ case RPMTAG_SUPPLEMENTNAME:
+ case RPMTAG_ENHANCENAME:
+ if (rpmrichParseCheck(RPMRICHOP_OR, check, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ break;
+ default:
+ if (rpmrichParseCheck(RPMRICHOP_AND, check, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ break;
+ }
+ return RPMRC_OK;
+}
+
+struct rpmdsParseRichDepData {
+ rpmds dep;
+ rpmsenseFlags depflags;
+
+ rpmds leftds;
+ rpmds rightds;
+ rpmrichOp op;
+
+ int depth;
+ const char *rightstart;
+ int dochain;
+};
+
+static rpmRC rpmdsParseRichDepCB(void *cbdata, rpmrichParseType type,
+ const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
+ rpmrichOp op, char **emsg) {
+ struct rpmdsParseRichDepData *data = cbdata;
+ rpmds ds = 0;
+
+ if (type == RPMRICH_PARSE_ENTER)
+ data->depth++;
+ else if (type == RPMRICH_PARSE_LEAVE) {
+ if (--data->depth == 0 && data->dochain && data->rightstart) {
+ /* chain op hack, construct a sub-ds from the right side of the chain */
+ char *right = xmalloc(n + nl - data->rightstart + 2);
+ right[0] = '(';
+ strncpy(right + 1, data->rightstart, n + nl - data->rightstart);
+ right[n + nl - data->rightstart + 1] = 0;
+ data->rightds = rpmdsFree(data->rightds);
+ ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, data->depflags, 0, 0, 0);
+ ds->N[0] = rpmstrPoolId(ds->pool, right, 1);
+ ds->EVR[0] = rpmstrPoolId(ds->pool, "", 1);
+ data->rightds = ds;
+ free(right);
+ }
+ }
+ if (data->depth != 1)
+ return RPMRC_OK; /* we're only interested in top-level parsing */
+ if ((type == RPMRICH_PARSE_SIMPLE || type == RPMRICH_PARSE_LEAVE) && !data->dochain) {
+ if (type == RPMRICH_PARSE_SIMPLE && data->dep->tagN == RPMTAG_REQUIRENAME && nl > 7 &&
+ rstreqn(n, "rpmlib(", sizeof("rpmlib(")-1))
+ sense |= RPMSENSE_RPMLIB;
+ ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, sense | data->depflags, 0, 0, 0);
+ ds->N[0] = rpmstrPoolIdn(ds->pool, n, nl, 1);
+ ds->EVR[0] = rpmstrPoolIdn(ds->pool, e ? e : "", el, 1);
+ if (!data->leftds)
+ data->leftds = ds;
+ else {
+ data->rightds = ds;
+ data->rightstart = n;
+ }
+ }
+ if (type == RPMRICH_PARSE_OP) {
+ if (data->op != RPMRICHOP_SINGLE)
+ data->dochain = 1; /* this is a chained op */
+ else
+ data->op = op;
+ }
+ return RPMRC_OK;
+}
+
+
+rpmRC rpmdsParseRichDep(rpmds dep, rpmds *leftds, rpmds *rightds, rpmrichOp *op, char **emsg)
+{
+ rpmRC rc;
+ struct rpmdsParseRichDepData data;
+ const char *depstr = rpmdsN(dep);
+ memset(&data, 0, sizeof(data));
+ data.dep = dep;
+ data.op = RPMRICHOP_SINGLE;
+ data.depflags = rpmdsFlags(dep) & ~(RPMSENSE_SENSEMASK | RPMSENSE_MISSINGOK);
+ rc = rpmrichParse(&depstr, emsg, rpmdsParseRichDepCB, &data);
+ if (rc == RPMRC_OK && *depstr) {
+ if (emsg)
+ rasprintf(emsg, _("Junk after rich dependency"));
+ rc = RPMRC_FAIL;
+ }
+ if (rc != RPMRC_OK) {
+ rpmdsFree(data.leftds);
+ rpmdsFree(data.rightds);
+ } else {
+ *leftds = data.leftds;
+ *rightds = data.rightds;
+ *op = data.op;
+ }
+ return rc;
+}
+
diff --git a/lib/rpmds.h b/lib/rpmds.h
index bceed0081..463a82a96 100644
--- a/lib/rpmds.h
+++ b/lib/rpmds.h
@@ -86,6 +86,24 @@ typedef rpmFlags rpmsenseFlags;
#define isInstallPreReq(_x) ((_x) & _INSTALL_ONLY_MASK)
#define isErasePreReq(_x) ((_x) & _ERASE_ONLY_MASK)
+
+
+/** \ingroup rpmds
+ * Return only those flags allowed for given type of dependencies
+ * @param tagN type of dependency
+ * @param Flags flags
+ * @return flags filtered to allowed bits
+ */
+rpmsenseFlags rpmSanitizeDSFlags(rpmTagVal tagN, rpmsenseFlags Flags);
+
+/** \ingroup rpmds
+ * Convert a string to the sense flags
+ * @param str the string
+ * @param len length of the string
+ * @return flags, zero for unknown relations
+ */
+rpmsenseFlags rpmParseDSFlags(const char *str, size_t len);
+
/** \ingroup rpmds
* Reference a dependency set instance.
* @param ds dependency set
@@ -144,6 +162,14 @@ rpmds rpmdsSingle(rpmTagVal tagN, const char * N, const char * EVR, rpmsenseFlag
rpmds rpmdsCurrent(rpmds ds);
/** \ingroup rpmds
+ * Write content of the dependency set to the header
+ * @param ds dependency set
+ * @param h header
+ * @return 0 on success
+ */
+int rpmdsPutToHeader(rpmds ds, Header h);
+
+/** \ingroup rpmds
* Return dependency set count.
* @param ds dependency set
* @return current count
@@ -173,6 +199,20 @@ int rpmdsSetIx(rpmds ds, int ix);
const char * rpmdsDNEVR(const rpmds ds);
/** \ingroup rpmds
+ * Return one char indicating the type of the dependency.
+ * @param ds dependency set
+ * @return character
+ */
+char rpmdsD(const rpmds ds);
+
+/** \ingroup rpmds
+ * Return matching tagN for one char dependency type description.
+ * @param deptype character
+ * @return type of dependency
+ */
+rpmTagVal rpmdsDToTagN(char deptype);
+
+/** \ingroup rpmds
* Return current dependency name.
* @param ds dependency set
* @return current dependency name, NULL on invalid
@@ -187,6 +227,13 @@ const char * rpmdsN(const rpmds ds);
const char * rpmdsEVR(const rpmds ds);
/** \ingroup rpmds
+ * Return current dependency triggerindex.
+ * @param ds dependency set
+ * @return current dependency trigger index, 0 on invalid
+ */
+int rpmdsTi(const rpmds ds);
+
+/** \ingroup rpmds
* Return current dependency flags.
* @param ds dependency set
* @return current dependency flags, 0 on invalid
@@ -201,6 +248,27 @@ rpmsenseFlags rpmdsFlags(const rpmds ds);
rpmTagVal rpmdsTagN(const rpmds ds);
/** \ingroup rpmds
+ * Return current dependency type.
+ * @param ds dependency set
+ * @return current dependency type version tag, 0 on invalid
+ */
+rpmTagVal rpmdsTagEVR(const rpmds ds);
+
+/** \ingroup rpmds
+ * Return current dependency type.
+ * @param ds dependency set
+ * @return current dependency type flags tag, 0 on invalid
+ */
+rpmTagVal rpmdsTagF(const rpmds ds);
+
+/** \ingroup rpmds
+ * Return current dependency type.
+ * @param ds dependency set
+ * @return current dependency type trigger index tag, 0 on invalid
+ */
+rpmTagVal rpmdsTagTi(const rpmds ds);
+
+/** \ingroup rpmds
* Return dependency header instance, ie whether the dependency comes from
* an installed header or not.
* @param ds dependency set
@@ -247,15 +315,6 @@ rpm_color_t rpmdsColor(const rpmds ds);
rpm_color_t rpmdsSetColor(const rpmds ds, rpm_color_t color);
/** \ingroup rpmds
- * Notify of results of dependency match.
- * @param ds dependency set
- * @param where where dependency was resolved (or NULL)
- * @param rc 0 == YES, otherwise NO
- */
-/* FIX: rpmMessage annotation is a lie */
-void rpmdsNotify(rpmds ds, const char * where, int rc);
-
-/** \ingroup rpmds
* Return next dependency set iterator index.
* @param ds dependency set
* @return dependency set iterator index, -1 on termination
@@ -281,7 +340,7 @@ int rpmdsFind(rpmds ds, const rpmds ods);
* Merge a dependency set maintaining (N,EVR,Flags) sorted order.
* @retval *dsp (merged) dependency set
* @param ods dependency set to merge
- * @return (merged) dependency index
+ * @return number of merged dependencies, -1 on error
*/
int rpmdsMerge(rpmds * dsp, rpmds ods);
@@ -333,12 +392,138 @@ int rpmdsNVRMatchesDep(const Header h, const rpmds req, int nopromote);
/**
* Load rpmlib provides into a dependency set.
- * @retval *dsp (loaded) depedency set
+ * @retval *dsp (loaded) dependency set
* @param tblp rpmlib provides table (NULL uses internal table)
* @return 0 on success
*/
int rpmdsRpmlib(rpmds * dsp, const void * tblp);
+/** \ingroup rpmds
+ * Create and load a dependency set.
+ * @param pool shared string pool (or NULL for private pool)
+ * @param h header
+ * @param tagN type of dependency
+ * @param flags unused
+ * @return new dependency set
+ */
+rpmds rpmdsNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, int flags);
+
+/** \ingroup rpmds
+ * Create, load and initialize a dependency for this header.
+ * @param pool string pool (or NULL for private pool)
+ * @param h header
+ * @param tagN type of dependency
+ * @param Flags comparison flags
+ * @return new dependency set
+ */
+rpmds rpmdsThisPool(rpmstrPool pool,
+ Header h, rpmTagVal tagN, rpmsenseFlags Flags);
+
+/** \ingroup rpmds
+ * Create, load and initialize a dependency set of size 1.
+ * @param pool string pool (or NULL for private pool)
+ * @param tagN type of dependency
+ * @param N name
+ * @param EVR epoch:version-release
+ * @param Flags comparison flags
+ * @return new dependency set
+ */
+rpmds rpmdsSinglePool(rpmstrPool pool, rpmTagVal tagN,
+ const char * N, const char * EVR, rpmsenseFlags Flags);
+
+/** \ingroup rpmds
+ * Create, load and initialize a trigger dependency set of size 1.
+ * @param pool string pool (or NULL for private pool)
+ * @param tagN type of dependency
+ * @param N name
+ * @param EVR epoch:version-release
+ * @param Flags comparison flags
+ * @param triggerIndex trigger index
+ * @return new dependency set
+ */
+rpmds rpmdsSinglePoolTix(rpmstrPool pool, rpmTagVal tagN,
+ const char * N, const char * EVR,
+ rpmsenseFlags Flags, int triggerIndex);
+
+/**
+ * Load rpmlib provides into a dependency set.
+ * @param pool shared string pool (or NULL for private pool)
+ * @retval *dsp (loaded) dependency set
+ * @param tblp rpmlib provides table (NULL uses internal table)
+ * @return 0 on success
+ */
+int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp);
+
+
+typedef enum rpmrichOp_e {
+ RPMRICHOP_SINGLE = 1,
+ RPMRICHOP_AND = 2,
+ RPMRICHOP_OR = 3,
+ RPMRICHOP_IF = 4,
+ RPMRICHOP_ELSE = 5,
+ RPMRICHOP_WITH = 6,
+ RPMRICHOP_WITHOUT = 7,
+ RPMRICHOP_UNLESS = 8
+} rpmrichOp;
+
+typedef enum rpmrichParseType_e {
+ RPMRICH_PARSE_SIMPLE = 1, /* standard N <=> EVR dep */
+ RPMRICH_PARSE_ENTER = 2, /* entering sub-dependency */
+ RPMRICH_PARSE_LEAVE = 3, /* leaving sub-dependency */
+ RPMRICH_PARSE_OP = 4 /* parsed a rich dependency op */
+} rpmrichParseType;
+
+typedef rpmRC (*rpmrichParseFunction) (void *cbdata, rpmrichParseType type,
+ const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
+ rpmrichOp op, char **emsg);
+
+/**
+ * Parse a rich dependency string
+ * @param dstrp pointer to sting, will be updated
+ * @param emsg returns the error string, can be NULL
+ * @param cb callback function
+ * @param cbdata callback function data
+ * @return RPMRC_OK on success
+ */
+rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata);
+
+/**
+ * Parse a rich dependency string for a specific tag
+ * @param dstrp pointer to sting, will be updated
+ * @param emsg returns the error string, can be NULL
+ * @param cb callback function
+ * @param cbdata callback function data
+ * @param tagN type of dependency
+ * @return RPMRC_OK on success
+ */
+rpmRC rpmrichParseForTag(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, rpmTagVal tagN);
+
+
+/**
+ * Return if current depenency is rich
+ * @param dep the dependency
+ * @return 1 is dependency is a rich 0 otherwise
+ */
+int rpmdsIsRich(rpmds dep);
+
+/**
+ * Return a string representation of the rich dependency op
+ * @param op the dependency op
+ * @return constant string, do not free
+ */
+const char *rpmrichOpStr(rpmrichOp op);
+
+/**
+ * Parse a rich dependency string
+ * @param dep the dependency
+ * @param leftds returns the left dependency
+ * @param rightds returns the right dependency
+ * @param op returns the rich dep op
+ * @param emsg returns the error string
+ * @return RPMRC_OK on success
+ */
+rpmRC rpmdsParseRichDep(rpmds dep, rpmds *leftds, rpmds *rightds, rpmrichOp *op, char **emsg);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/rpmds_internal.h b/lib/rpmds_internal.h
index edd5a0268..6861fba0f 100644
--- a/lib/rpmds_internal.h
+++ b/lib/rpmds_internal.h
@@ -8,52 +8,6 @@ extern "C" {
#endif
/** \ingroup rpmds
- * Create and load a dependency set.
- * @param pool shared string pool (or NULL for private pool)
- * @param h header
- * @param tagN type of dependency
- * @param flags unused
- * @return new dependency set
- */
-RPM_GNUC_INTERNAL
-rpmds rpmdsNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, int flags);
-
-/** \ingroup rpmds
- * Create, load and initialize a dependency for this header.
- * @param pool string pool (or NULL for private pool)
- * @param h header
- * @param tagN type of dependency
- * @param Flags comparison flags
- * @return new dependency set
- */
-RPM_GNUC_INTERNAL
-rpmds rpmdsThisPool(rpmstrPool pool,
- Header h, rpmTagVal tagN, rpmsenseFlags Flags);
-
-/** \ingroup rpmds
- * Create, load and initialize a dependency set of size 1.
- * @param pool string pool (or NULL for private pool)
- * @param tagN type of dependency
- * @param N name
- * @param EVR epoch:version-release
- * @param Flags comparison flags
- * @return new dependency set
- */
-RPM_GNUC_INTERNAL
-rpmds rpmdsSinglePool(rpmstrPool pool, rpmTagVal tagN,
- const char * N, const char * EVR, rpmsenseFlags Flags);
-
-/**
- * Load rpmlib provides into a dependency set.
- * @param pool shared string pool (or NULL for private pool)
- * @retval *dsp (loaded) depedency set
- * @param tblp rpmlib provides table (NULL uses internal table)
- * @return 0 on success
- */
-RPM_GNUC_INTERNAL
-int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp);
-
-/** \ingroup rpmds
* Swiss army knife dependency matching function.
* @param pool string pool (or NULL for private pool)
* @param h header
@@ -68,6 +22,15 @@ int rpmdsMatches(rpmstrPool pool, Header h, int prix,
rpmds req, int selfevr, int nopromote);
/** \ingroup rpmds
+ * Notify of results of dependency match.
+ * @param ds dependency set
+ * @param where where dependency was resolved (or NULL)
+ * @param rc 0 == YES, otherwise NO
+ */
+RPM_GNUC_INTERNAL
+void rpmdsNotify(rpmds ds, const char * where, int rc);
+
+/** \ingroup rpmds
* Return current dependency name pool id.
* @param ds dependency set
* @return current dependency name id, 0 on invalid
@@ -107,11 +70,23 @@ RPM_GNUC_INTERNAL
rpmsenseFlags rpmdsFlagsIndex(rpmds ds, int i);
RPM_GNUC_INTERNAL
+int rpmdsTiIndex(rpmds ds, int i);
+
+RPM_GNUC_INTERNAL
rpm_color_t rpmdsColorIndex(rpmds ds, int i);
RPM_GNUC_INTERNAL
int rpmdsCompareIndex(rpmds A, int aix, rpmds B, int bix);
+/** \ingroup rpmds
+ * Filter dependency set and return new dependency set containing only items
+ * with given trigger index.
+ * @param ds dependency set
+ * @param ti trigger index
+ * @return new filtered dependency set
+ */
+RPM_GNUC_INTERNAL
+rpmds rpmdsFilterTi(rpmds ds, int ti);
#ifdef __cplusplus
}
#endif
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index 7f7ef2a7f..beb2ae72b 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -11,13 +11,137 @@
#include <rpm/rpmstring.h>
#include <rpm/rpmmacro.h> /* XXX rpmCleanPath */
#include <rpm/rpmds.h>
+#include <errno.h>
#include "lib/rpmfi_internal.h"
#include "lib/rpmte_internal.h" /* relocations */
#include "lib/cpio.h" /* XXX CPIO_FOO */
+#include "lib/fsm.h" /* rpmpsm stuff for now */
+#include "lib/rpmug.h"
+#include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
#include "debug.h"
+struct hardlinks_s {
+ int nlink;
+ int files[];
+};
+
+typedef struct hardlinks_s * hardlinks_t;
+
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+#define HASHTYPE nlinkHash
+#define HTKEYTYPE int
+#define HTDATATYPE struct hardlinks_s *
+#include "lib/rpmhash.H"
+#include "lib/rpmhash.C"
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+
+typedef int (*iterfunc)(rpmfi fi);
+
+struct rpmfi_s {
+ int i; /*!< Current file index. */
+ int j; /*!< Current directory index. */
+ iterfunc next; /*!< Iterator function. */
+ char * fn; /*!< File name buffer. */
+ char * ofn; /*!< Original file name buffer. */
+
+ int intervalStart; /*!< Start of iterating interval. */
+ int intervalEnd; /*!< End of iterating interval. */
+
+ rpmfiles files; /*!< File info set */
+ rpmcpio_t archive; /*!< Archive with payload */
+ unsigned char * found; /*!< Bit field of files found in the archive */
+ int nrefs; /*!< Reference count */
+};
+
+struct rpmfn_s {
+ rpm_count_t dc; /*!< No. of directories. */
+ rpm_count_t fc; /*!< No. of files. */
+
+ rpmsid * bnid; /*!< Index to base name(s) (pool) */
+ rpmsid * dnid; /*!< Index to directory name(s) (pool) */
+ uint32_t * dil; /*!< Directory indice(s) (from header) */
+};
+
+typedef struct rpmfn_s * rpmfn;
+
+/**
+ * A package filename set.
+ */
+struct rpmfiles_s {
+ Header h; /*!< Header for file info set (or NULL) */
+ rpmstrPool pool; /*!< String pool of this file info set */
+
+ struct rpmfn_s fndata; /*!< File name data */
+ struct rpmfn_s *ofndata; /*!< Original file name data */
+
+ rpmsid * flinks; /*!< Index to file link(s) (pool) */
+
+ rpm_flag_t * fflags; /*!< File flag(s) (from header) */
+ rpm_off_t * fsizes; /*!< File size(s) (from header) */
+ rpm_loff_t * lfsizes; /*!< File size(s) (from header) */
+ rpm_time_t * fmtimes; /*!< File modification time(s) (from header) */
+ rpm_mode_t * fmodes; /*!< File mode(s) (from header) */
+ rpm_rdev_t * frdevs; /*!< File rdev(s) (from header) */
+ rpm_ino_t * finodes; /*!< File inodes(s) (from header) */
+
+ rpmsid * fuser; /*!< Index to file owner(s) (misc pool) */
+ rpmsid * fgroup; /*!< Index to file group(s) (misc pool) */
+ rpmsid * flangs; /*!< Index to file lang(s) (misc pool) */
+
+ char * fstates; /*!< File state(s) (from header) */
+
+ rpm_color_t * fcolors; /*!< File color bits (header) */
+ char ** fcaps; /*!< File capability strings (header) */
+
+ char ** cdict; /*!< File class dictionary (header) */
+ rpm_count_t ncdict; /*!< No. of class entries. */
+ uint32_t * fcdictx; /*!< File class dictionary index (header) */
+
+ uint32_t * ddict; /*!< File depends dictionary (header) */
+ rpm_count_t nddict; /*!< No. of depends entries. */
+ uint32_t * fddictx; /*!< File depends dictionary start (header) */
+ uint32_t * fddictn; /*!< File depends dictionary count (header) */
+ rpm_flag_t * vflags; /*!< File verify flag(s) (from header) */
+
+ rpmfiFlags fiflags; /*!< file info set control flags */
+
+ struct fingerPrint_s * fps; /*!< File fingerprint(s). */
+
+ int digestalgo; /*!< File digest algorithm */
+ int signaturelength; /*!< File signature length */
+ unsigned char * digests; /*!< File digests in binary. */
+ unsigned char * signatures; /*!< File signatures in binary. */
+
+ struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */
+ rpm_off_t * replacedSizes; /*!< (TR_ADDED) */
+ rpm_loff_t * replacedLSizes;/*!< (TR_ADDED) */
+ int magic;
+ int nrefs; /*!< Reference count. */
+};
+
+static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd);
+static int cmpPoolFn(rpmstrPool pool, rpmfn files, int ix, const char * fn);
+
+static rpmfiles rpmfilesUnlink(rpmfiles fi)
+{
+ if (fi)
+ fi->nrefs--;
+ return NULL;
+}
+
+rpmfiles rpmfilesLink(rpmfiles fi)
+{
+ if (fi)
+ fi->nrefs++;
+ return fi;
+}
+
static rpmfi rpmfiUnlink(rpmfi fi)
{
if (fi)
@@ -32,14 +156,146 @@ rpmfi rpmfiLink(rpmfi fi)
return fi;
}
+/*
+ * Collect and validate file path data from header.
+ * Return the number of files found (could be none) or -1 on error.
+ */
+static int rpmfnInit(rpmfn fndata, rpmTagVal bntag, Header h, rpmstrPool pool)
+{
+ struct rpmtd_s bn, dn, dx;
+ rpmTagVal dntag, ditag;
+ int rc = 0;
+
+ if (bntag == RPMTAG_BASENAMES) {
+ dntag = RPMTAG_DIRNAMES;
+ ditag = RPMTAG_DIRINDEXES;
+ } else if (bntag == RPMTAG_ORIGBASENAMES) {
+ dntag = RPMTAG_ORIGDIRNAMES;
+ ditag = RPMTAG_ORIGDIRINDEXES;
+ } else {
+ return -1;
+ }
+
+ /* Grab and validate file triplet data (if there is any) */
+ if (headerGet(h, bntag, &bn, HEADERGET_MINMEM)) {
+ headerGet(h, dntag, &dn, HEADERGET_MINMEM);
+ headerGet(h, ditag, &dx, HEADERGET_ALLOC);
+
+ if (indexSane(&bn, &dn, &dx)) {
+ /* Init the file triplet data */
+ fndata->fc = rpmtdCount(&bn);
+ fndata->dc = rpmtdCount(&dn);
+ fndata->bnid = rpmtdToPool(&bn, pool);
+ fndata->dnid = rpmtdToPool(&dn, pool);
+ /* Steal index data from the td (pooh...) */
+ fndata->dil = dx.data;
+ dx.data = NULL;
+ rc = fndata->fc;
+ } else {
+ memset(fndata, 0, sizeof(*fndata));
+ rc = -1;
+ }
+ rpmtdFreeData(&bn);
+ rpmtdFreeData(&dn);
+ rpmtdFreeData(&dx);
+ }
+
+ return rc;
+}
+
+static void rpmfnClear(rpmfn fndata)
+{
+ if (fndata) {
+ free(fndata->bnid);
+ free(fndata->dnid);
+ free(fndata->dil);
+ memset(fndata, 0, sizeof(*fndata));
+ }
+}
+
+static rpm_count_t rpmfnFC(rpmfn fndata)
+{
+ return (fndata != NULL) ? fndata->fc :0;
+}
+
+static rpm_count_t rpmfnDC(rpmfn fndata)
+{
+ return (fndata != NULL) ? fndata->dc : 0;
+}
+
+static int rpmfnDI(rpmfn fndata, int ix)
+{
+ int j = -1;
+ if (ix >= 0 && ix < rpmfnFC(fndata)) {
+ if (fndata->dil != NULL)
+ j = fndata->dil[ix];
+ }
+ return j;
+}
+
+static rpmsid rpmfnBNId(rpmfn fndata, int ix)
+{
+ rpmsid id = 0;
+ if (ix >= 0 && ix < rpmfnFC(fndata)) {
+ if (fndata->bnid != NULL)
+ id = fndata->bnid[ix];
+ }
+ return id;
+}
+
+static rpmsid rpmfnDNId(rpmfn fndata, int ix)
+{
+ rpmsid id = 0;
+ if (ix >= 0 && ix < rpmfnDC(fndata)) {
+ if (fndata->dnid != NULL)
+ id = fndata->dnid[ix];
+ }
+ return id;
+}
+
+static const char * rpmfnBN(rpmstrPool pool, rpmfn fndata, int ix)
+{
+ return rpmstrPoolStr(pool, rpmfnBNId(fndata, ix));
+}
+
+static const char * rpmfnDN(rpmstrPool pool, rpmfn fndata, int ix)
+{
+ return rpmstrPoolStr(pool, rpmfnDNId(fndata, ix));
+}
+
+static char * rpmfnFN(rpmstrPool pool, rpmfn fndata, int ix)
+{
+ char *fn = NULL;
+ if (ix >= 0 && ix < rpmfnFC(fndata)) {
+ fn = rstrscat(NULL, rpmfnDN(pool, fndata, rpmfnDI(fndata, ix)),
+ rpmfnBN(pool, fndata, ix), NULL);
+ }
+ return fn;
+}
+
+rpm_count_t rpmfilesFC(rpmfiles fi)
+{
+ return (fi != NULL ? rpmfnFC(&fi->fndata) : 0);
+}
+
+rpm_count_t rpmfilesDC(rpmfiles fi)
+{
+ return (fi != NULL ? rpmfnDC(&fi->fndata) : 0);
+}
+
+int rpmfilesDigestAlgo(rpmfiles fi)
+{
+ return (fi != NULL) ? fi->digestalgo : 0;
+}
+
rpm_count_t rpmfiFC(rpmfi fi)
{
- return (fi != NULL ? fi->fc : 0);
+ return (fi != NULL ? rpmfilesFC(fi->files) : 0);
}
rpm_count_t rpmfiDC(rpmfi fi)
{
- return (fi != NULL ? fi->dc : 0);
+ return (fi != NULL ? rpmfilesDC(fi->files) : 0);
}
#ifdef NOTYET
@@ -57,10 +313,10 @@ int rpmfiSetFX(rpmfi fi, int fx)
{
int i = -1;
- if (fi != NULL && fx >= 0 && fx < fi->fc) {
+ if (fi != NULL && fx >= 0 && fx < rpmfilesFC(fi->files)) {
i = fi->i;
fi->i = fx;
- fi->j = fi->dil[fi->i];
+ fi->j = rpmfilesDI(fi->files, fi->i);
}
return i;
}
@@ -74,138 +330,222 @@ int rpmfiSetDX(rpmfi fi, int dx)
{
int j = -1;
- if (fi != NULL && dx >= 0 && dx < fi->dc) {
+ if (fi != NULL && dx >= 0 && dx < rpmfiDC(fi)) {
j = fi->j;
fi->j = dx;
}
return j;
}
-int rpmfiDIIndex(rpmfi fi, int dx)
+int rpmfilesDI(rpmfiles fi, int ix)
{
- int j = -1;
- if (fi != NULL && dx >= 0 && dx < fi->fc) {
- if (fi->dil != NULL)
- j = fi->dil[dx];
- }
- return j;
+ return (fi != NULL) ? rpmfnDI(&fi->fndata, ix) : -1;
}
-rpmsid rpmfiBNIdIndex(rpmfi fi, int ix)
+int rpmfilesODI(rpmfiles fi, int ix)
{
- rpmsid id = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
- if (fi->bnid != NULL)
- id = fi->bnid[ix];
- }
- return id;
+ return (fi != NULL) ? rpmfnDI(fi->ofndata, ix) : -1;
}
-rpmsid rpmfiDNIdIndex(rpmfi fi, int jx)
+rpmsid rpmfilesBNId(rpmfiles fi, int ix)
{
- rpmsid id = 0;
- if (fi != NULL && jx >= 0 && jx < fi->fc) {
- if (fi->dnid != NULL)
- id = fi->dnid[jx];
- }
- return id;
+ return (fi != NULL) ? rpmfnBNId(&fi->fndata, ix) : 0;
+}
+
+rpmsid rpmfilesOBNId(rpmfiles fi, int ix)
+{
+ return (fi != NULL) ? rpmfnBNId(fi->ofndata, ix) : 0;
+}
+
+rpmsid rpmfilesDNId(rpmfiles fi, int jx)
+{
+ return (fi != NULL) ? rpmfnDNId(&fi->fndata, jx) : 0;
+}
+
+rpmsid rpmfilesODNId(rpmfiles fi, int jx)
+{
+ return (fi != NULL) ? rpmfnDNId(fi->ofndata, jx) : 0;
+}
+
+const char * rpmfilesBN(rpmfiles fi, int ix)
+{
+ return (fi != NULL) ? rpmfnBN(fi->pool, &fi->fndata, ix) : NULL;
+}
+
+const char * rpmfilesOBN(rpmfiles fi, int ix)
+{
+ return (fi != NULL) ? rpmstrPoolStr(fi->pool, rpmfilesOBNId(fi, ix)) : NULL;
+}
+
+const char * rpmfilesDN(rpmfiles fi, int jx)
+{
+ return (fi != NULL) ? rpmfnDN(fi->pool, &fi->fndata, jx) : NULL;
+}
+
+const char * rpmfilesODN(rpmfiles fi, int jx)
+{
+ return (fi != NULL) ? rpmstrPoolStr(fi->pool, rpmfilesODNId(fi, jx)) : NULL;
+}
+
+char * rpmfilesFN(rpmfiles fi, int ix)
+{
+ return (fi != NULL) ? rpmfnFN(fi->pool, &fi->fndata, ix) : NULL;
+}
+
+char * rpmfilesOFN(rpmfiles fi, int ix)
+{
+ return (fi != NULL) ? rpmfnFN(fi->pool, fi->ofndata, ix) : NULL;
+}
+
+/* Fn is expected to be relative path, convert directory to relative too */
+static int cmpPoolFn(rpmstrPool pool, rpmfn files, int ix, const char * fn)
+{
+ rpmsid dnid = rpmfnDNId(files, rpmfnDI(files, ix));
+ const char *dn = rpmstrPoolStr(pool, dnid);
+ const char *reldn = (dn[0] == '/') ? dn + 1 : dn;
+ size_t l = strlen(reldn);
+ int cmp = strncmp(reldn, fn, l);
+ if (cmp == 0)
+ cmp = strcmp(rpmfnBN(pool, files, ix), fn + l);
+ return cmp;
}
-const char * rpmfiBNIndex(rpmfi fi, int ix)
+static int rpmfnFindFN(rpmstrPool pool, rpmfn files, const char * fn)
{
- const char * BN = NULL;
+ int fc = rpmfnFC(files);
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
- if (fi->bnid != NULL)
- BN = rpmstrPoolStr(fi->pool, fi->bnid[ix]);
+ /*
+ * Skip payload prefix, turn absolute paths into relative. This
+ * allows handling binary rpm payloads with and without ./ prefix and
+ * srpm payloads which only contain basenames.
+ */
+ if (fn[0] == '.' && fn[1] == '/')
+ fn += 2;
+ if (fn[0] == '/')
+ fn += 1;
+
+ /* try binary search */
+
+ int lo = 0;
+ int hi = fc;
+ int mid, cmp;
+
+ while (hi > lo) {
+ mid = (hi + lo) / 2 ;
+ cmp = cmpPoolFn(pool, files, mid, fn);
+ if (cmp < 0) {
+ lo = mid+1;
+ } else if (cmp > 0) {
+ hi = mid;
+ } else {
+ return mid;
+ }
+ }
+
+ /* not found: try linear search */
+ for (int i=0; i < fc; i++) {
+ if (cmpPoolFn(pool, files, i, fn) == 0)
+ return i;
}
- return BN;
+ return -1;
+}
+
+int rpmfilesFindFN(rpmfiles files, const char * fn)
+{
+ return (files && fn) ? rpmfnFindFN(files->pool, &files->fndata, fn) : -1;
+}
+
+int rpmfilesFindOFN(rpmfiles files, const char * fn)
+{
+ return (files && fn) ? rpmfnFindFN(files->pool, files->ofndata, fn) : -1;
}
-const char * rpmfiDNIndex(rpmfi fi, int jx)
+int rpmfiFindFN(rpmfi fi, const char * fn)
{
- const char * DN = NULL;
+ int ix = -1;
- if (fi != NULL && jx >= 0 && jx < fi->dc) {
- if (fi->dnid != NULL)
- DN = rpmstrPoolStr(fi->pool, fi->dnid[jx]);
+ if (fi != NULL) {
+ ix = rpmfilesFindFN(fi->files, fn);
}
- return DN;
+ return ix;
}
-char * rpmfiFNIndex(rpmfi fi, int ix)
+int rpmfiFindOFN(rpmfi fi, const char * fn)
{
- char *fn = NULL;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
- fn = rstrscat(NULL, rpmstrPoolStr(fi->pool, fi->dnid[fi->dil[ix]]),
- rpmstrPoolStr(fi->pool, fi->bnid[ix]), NULL);
+ int ix = -1;
+
+ if (fi != NULL) {
+ ix = rpmfilesFindOFN(fi->files, fn);
}
- return fn;
+ return ix;
}
-rpmfileAttrs rpmfiFFlagsIndex(rpmfi fi, int ix)
+/*
+ * Dirnames are not sorted when separated from basenames, we need to assemble
+ * the whole path for search (binary or otherwise) purposes.
+ */
+static int cmpPfx(rpmfiles files, int ix, const char *pfx, size_t plen)
+{
+ char *fn = rpmfilesFN(files, ix);
+ int rc = strncmp(pfx, fn, plen);
+ free(fn);
+ return rc;
+}
+
+rpmfileAttrs rpmfilesFFlags(rpmfiles fi, int ix)
{
rpmfileAttrs FFlags = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fflags != NULL)
FFlags = fi->fflags[ix];
}
return FFlags;
}
-rpmVerifyAttrs rpmfiVFlagsIndex(rpmfi fi, int ix)
+rpmVerifyAttrs rpmfilesVFlags(rpmfiles fi, int ix)
{
rpmVerifyAttrs VFlags = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->vflags != NULL)
VFlags = fi->vflags[ix];
}
return VFlags;
}
-rpm_mode_t rpmfiFModeIndex(rpmfi fi, int ix)
+rpm_mode_t rpmfilesFMode(rpmfiles fi, int ix)
{
rpm_mode_t fmode = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fmodes != NULL)
fmode = fi->fmodes[ix];
}
return fmode;
}
-rpmfileState rpmfiFStateIndex(rpmfi fi, int ix)
+rpmfileState rpmfilesFState(rpmfiles fi, int ix)
{
rpmfileState fstate = RPMFILE_STATE_MISSING;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fstates != NULL)
fstate = fi->fstates[ix];
}
return fstate;
}
-const unsigned char * rpmfiMD5(rpmfi fi)
-{
- const unsigned char *digest;
- int algo = 0;
-
- digest = rpmfiFDigest(fi, &algo, NULL);
- return (algo == PGPHASHALGO_MD5) ? digest : NULL;
-}
-
int rpmfiDigestAlgo(rpmfi fi)
{
- return fi ? fi->digestalgo : 0;
+ return fi ? rpmfilesDigestAlgo(fi->files) : 0;
}
-const unsigned char * rpmfiFDigestIndex(rpmfi fi, int ix, int *algo, size_t *len)
+const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *len)
{
const unsigned char *digest = NULL;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
size_t diglen = rpmDigestLength(fi->digestalgo);
if (fi->digests != NULL)
digest = fi->digests + (diglen * ix);
@@ -228,68 +568,89 @@ char * rpmfiFDigestHex(rpmfi fi, int *algo)
return fdigest;
}
-const char * rpmfiFLinkIndex(rpmfi fi, int ix)
+const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
+{
+ const unsigned char *signature = NULL;
+
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
+ if (fi->signatures != NULL)
+ signature = fi->signatures + (fi->signaturelength * ix);
+ if (len)
+ *len = fi->signaturelength;
+ }
+ return signature;
+}
+
+const char * rpmfilesFLink(rpmfiles fi, int ix)
{
const char * flink = NULL;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->flinks != NULL)
flink = rpmstrPoolStr(fi->pool, fi->flinks[ix]);
}
return flink;
}
-rpm_loff_t rpmfiFSizeIndex(rpmfi fi, int ix)
+rpm_loff_t rpmfilesFSize(rpmfiles fi, int ix)
{
rpm_loff_t fsize = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fsizes != NULL)
fsize = fi->fsizes[ix];
+ else if (fi->lfsizes != NULL)
+ fsize = fi->lfsizes[ix];
}
return fsize;
}
-rpm_rdev_t rpmfiFRdevIndex(rpmfi fi, int ix)
+rpm_rdev_t rpmfilesFRdev(rpmfiles fi, int ix)
{
rpm_rdev_t frdev = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->frdevs != NULL)
frdev = fi->frdevs[ix];
}
return frdev;
}
-rpm_ino_t rpmfiFInodeIndex(rpmfi fi, int ix)
+rpm_ino_t rpmfilesFInode(rpmfiles fi, int ix)
{
rpm_ino_t finode = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->finodes != NULL)
finode = fi->finodes[ix];
}
return finode;
}
-rpm_color_t rpmfiColor(rpmfi fi)
+rpm_color_t rpmfilesColor(rpmfiles files)
{
rpm_color_t color = 0;
- if (fi != NULL && fi->fcolors != NULL) {
- for (int i = 0; i < fi->fc; i++)
- color |= fi->fcolors[i];
+ if (files != NULL && files->fcolors != NULL) {
+ int fc = rpmfilesFC(files);
+ for (int i = 0; i < fc; i++)
+ color |= files->fcolors[i];
/* XXX ignore all but lsnibble for now. */
color &= 0xf;
}
return color;
}
-rpm_color_t rpmfiFColorIndex(rpmfi fi, int ix)
+rpm_color_t rpmfiColor(rpmfi fi)
+{
+ return (fi != NULL) ? rpmfilesColor(fi->files) : 0;
+}
+
+rpm_color_t rpmfilesFColor(rpmfiles fi, int ix)
{
rpm_color_t fcolor = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fcolors != NULL)
/* XXX ignore all but lsnibble for now. */
fcolor = (fi->fcolors[ix] & 0x0f);
@@ -297,12 +658,12 @@ rpm_color_t rpmfiFColorIndex(rpmfi fi, int ix)
return fcolor;
}
-const char * rpmfiFClassIndex(rpmfi fi, int ix)
+const char * rpmfilesFClass(rpmfiles fi, int ix)
{
const char * fclass = NULL;
int cdictx;
- if (fi != NULL && fi->fcdictx != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && fi->fcdictx != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
cdictx = fi->fcdictx[ix];
if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
fclass = fi->cdict[cdictx];
@@ -310,13 +671,13 @@ const char * rpmfiFClassIndex(rpmfi fi, int ix)
return fclass;
}
-uint32_t rpmfiFDependsIndex(rpmfi fi, int ix, const uint32_t ** fddictp)
+uint32_t rpmfilesFDepends(rpmfiles fi, int ix, const uint32_t ** fddictp)
{
int fddictx = -1;
int fddictn = 0;
const uint32_t * fddict = NULL;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fddictn != NULL)
fddictn = fi->fddictn[ix];
if (fddictn > 0 && fi->fddictx != NULL)
@@ -329,102 +690,189 @@ uint32_t rpmfiFDependsIndex(rpmfi fi, int ix, const uint32_t ** fddictp)
return fddictn;
}
-uint32_t rpmfiFNlinkIndex(rpmfi fi, int ix)
+uint32_t rpmfilesFLinks(rpmfiles fi, int ix, const int ** files)
{
uint32_t nlink = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
- /* XXX rpm-2.3.12 has not RPMTAG_FILEINODES */
- if (fi->finodes && fi->frdevs) {
- rpm_ino_t finode = fi->finodes[ix];
- rpm_rdev_t frdev = fi->frdevs[ix];
- int j;
-
- for (j = 0; j < fi->fc; j++) {
- if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
- nlink++;
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
+ nlink = 1;
+ if (fi->nlinks) {
+ struct hardlinks_s ** hardlinks = NULL;
+ nlinkHashGetEntry(fi->nlinks, ix, &hardlinks, NULL, NULL);
+ if (hardlinks) {
+ nlink = hardlinks[0]->nlink;
+ if (files) {
+ *files = hardlinks[0]->files;
+ }
+ } else if (files){
+ *files = NULL;
}
}
}
return nlink;
}
-rpm_time_t rpmfiFMtimeIndex(rpmfi fi, int ix)
+uint32_t rpmfiFLinks(rpmfi fi, const int ** files)
+{
+ return rpmfilesFLinks(fi->files, fi ? fi->i : -1, files);
+}
+
+uint32_t rpmfilesFNlink(rpmfiles fi, int ix)
+{
+ return rpmfilesFLinks(fi, ix, NULL);
+}
+
+rpm_time_t rpmfilesFMtime(rpmfiles fi, int ix)
{
rpm_time_t fmtime = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fmtimes != NULL)
fmtime = fi->fmtimes[ix];
}
return fmtime;
}
-const char * rpmfiFUserIndex(rpmfi fi, int ix)
+const char * rpmfilesFUser(rpmfiles fi, int ix)
{
const char * fuser = NULL;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fuser != NULL)
fuser = rpmstrPoolStr(fi->pool, fi->fuser[ix]);
}
return fuser;
}
-const char * rpmfiFGroupIndex(rpmfi fi, int ix)
+const char * rpmfilesFGroup(rpmfiles fi, int ix)
{
const char * fgroup = NULL;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->fgroup != NULL)
fgroup = rpmstrPoolStr(fi->pool, fi->fgroup[ix]);
}
return fgroup;
}
-const char * rpmfiFCapsIndex(rpmfi fi, int ix)
+const char * rpmfilesFCaps(rpmfiles fi, int ix)
{
const char *fcaps = NULL;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
fcaps = fi->fcaps ? fi->fcaps[ix] : "";
}
return fcaps;
}
-const char * rpmfiFLangsIndex(rpmfi fi, int ix)
+const char * rpmfilesFLangs(rpmfiles fi, int ix)
{
const char *flangs = NULL;
- if (fi != NULL && fi->flangs != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && fi->flangs != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
flangs = rpmstrPoolStr(fi->pool, fi->flangs[ix]);
}
return flangs;
}
-struct fingerPrint_s *rpmfiFps(rpmfi fi)
+int rpmfilesStat(rpmfiles fi, int ix, int flags, struct stat *sb)
+{
+ int rc = -1;
+ if (fi && sb) {
+ /* XXX FIXME define proper flags with sane semantics... */
+ int warn = flags & 0x1;
+ const char *user = rpmfilesFUser(fi, ix);
+ const char *group = rpmfilesFGroup(fi, ix);
+ const int * hardlinks = NULL;
+ uint32_t nlinks = rpmfilesFLinks(fi, ix, &hardlinks);
+
+ memset(sb, 0, sizeof(*sb));
+ sb->st_nlink = nlinks;
+ sb->st_ino = rpmfilesFInode(fi, ix);
+ sb->st_rdev = rpmfilesFRdev(fi, ix);
+ sb->st_mode = rpmfilesFMode(fi, ix);
+ sb->st_mtime = rpmfilesFMtime(fi, ix);
+
+ /* Only regular files and symlinks have a size */
+ if (S_ISREG(sb->st_mode)) {
+ /* Content and thus size comes with last hardlink */
+ if (!(nlinks > 1 && hardlinks[nlinks-1] != ix))
+ sb->st_size = rpmfilesFSize(fi, ix);
+ } else if (S_ISLNK(sb->st_mode)) {
+ /*
+ * Normally rpmfilesFSize() is correct for symlinks too, this is
+ * only needed for glob()'ed links from fakechroot environment.
+ */
+ sb->st_size = strlen(rpmfilesFLink(fi, ix));
+ }
+
+ if (user && rpmugUid(user, &sb->st_uid)) {
+ if (warn)
+ rpmlog(RPMLOG_WARNING,
+ _("user %s does not exist - using %s\n"), user, UID_0_USER);
+ sb->st_mode &= ~S_ISUID; /* turn off suid bit */
+ }
+
+ if (group && rpmugGid(group, &sb->st_gid)) {
+ if (warn)
+ rpmlog(RPMLOG_WARNING,
+ _("group %s does not exist - using %s\n"), group, GID_0_GROUP);
+ sb->st_mode &= ~S_ISGID; /* turn off sgid bit */
+ }
+
+ rc = 0;
+ }
+ return rc;
+}
+
+struct fingerPrint_s *rpmfilesFps(rpmfiles fi)
{
return (fi != NULL) ? fi->fps : NULL;
}
+static int iterFwd(rpmfi fi)
+{
+ return fi->i + 1;
+}
+
+static int iterBack(rpmfi fi)
+{
+ return fi->i - 1;
+}
+
+static int iterInterval(rpmfi fi)
+{
+ if (fi->i == -1)
+ return fi->intervalStart;
+ else if (fi->i + 1 < fi->intervalEnd)
+ return fi->i + 1;
+ else
+ return RPMERR_ITER_END;
+}
+
int rpmfiNext(rpmfi fi)
{
- int i = -1;
+ int next = -1;
+ if (fi != NULL) {
+ do {
+ next = fi->next(fi);
+ } while (next == RPMERR_ITER_SKIP);
- if (fi != NULL && ++fi->i >= 0) {
- if (fi->i < fi->fc) {
- i = fi->i;
- if (fi->dil != NULL)
- fi->j = fi->dil[fi->i];
- } else
+ if (next >= 0 && next < rpmfilesFC(fi->files)) {
+ fi->i = next;
+ fi->j = rpmfilesDI(fi->files, fi->i);
+ } else {
fi->i = -1;
+ if (next >= 0) {
+ next = -1;
+ }
+ }
}
-
- return i;
+ return next;
}
rpmfi rpmfiInit(rpmfi fi, int fx)
{
if (fi != NULL) {
- if (fx >= 0 && fx < fi->fc) {
+ if (fx >= 0 && fx < rpmfilesFC(fi->files)) {
fi->i = fx - 1;
fi->j = -1;
}
@@ -438,7 +886,7 @@ int rpmfiNextD(rpmfi fi)
int j = -1;
if (fi != NULL && ++fi->j >= 0) {
- if (fi->j < fi->dc)
+ if (fi->j < rpmfilesDC(fi->files))
j = fi->j;
else
fi->j = -1;
@@ -450,7 +898,7 @@ int rpmfiNextD(rpmfi fi)
rpmfi rpmfiInitD(rpmfi fi, int dx)
{
if (fi != NULL) {
- if (dx >= 0 && dx < fi->fc)
+ if (dx >= 0 && dx < rpmfilesFC(fi->files))
fi->j = dx - 1;
else
fi = NULL;
@@ -459,26 +907,6 @@ rpmfi rpmfiInitD(rpmfi fi, int dx)
return fi;
}
-/**
- * Identify a file type.
- * @param ft file type
- * @return string to identify a file type
- */
-static
-const char * ftstring (rpmFileTypes ft)
-{
- switch (ft) {
- case XDIR: return "directory";
- case CDEV: return "char dev";
- case BDEV: return "block dev";
- case LINK: return "link";
- case SOCK: return "sock";
- case PIPE: return "fifo/pipe";
- case REG: return "file";
- default: return "unknown file type";
- }
-}
-
rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
{
if (S_ISDIR(mode)) return XDIR;
@@ -490,30 +918,32 @@ rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
return REG;
}
-int rpmfiCompareIndex(rpmfi afi, int aix, rpmfi bfi, int bix)
+int rpmfilesCompare(rpmfiles afi, int aix, rpmfiles bfi, int bix)
{
- mode_t amode = rpmfiFModeIndex(afi, aix);
- mode_t bmode = rpmfiFModeIndex(bfi, bix);
+ mode_t amode = rpmfilesFMode(afi, aix);
+ mode_t bmode = rpmfilesFMode(bfi, bix);
rpmFileTypes awhat = rpmfiWhatis(amode);
- if ((rpmfiFFlagsIndex(afi, aix) & RPMFILE_GHOST) ||
- (rpmfiFFlagsIndex(bfi, bix) & RPMFILE_GHOST)) return 0;
+ if ((rpmfilesFFlags(afi, aix) & RPMFILE_GHOST) ||
+ (rpmfilesFFlags(bfi, bix) & RPMFILE_GHOST)) return 0;
- if (amode != bmode) return 1;
+ /* Mode difference is a conflict, except for symlinks */
+ if (!(awhat == LINK && rpmfiWhatis(bmode) == LINK) && amode != bmode)
+ return 1;
if (awhat == LINK || awhat == REG) {
- if (rpmfiFSizeIndex(afi, aix) != rpmfiFSizeIndex(bfi, bix))
+ if (rpmfilesFSize(afi, aix) != rpmfilesFSize(bfi, bix))
return 1;
}
- if (!rstreq(rpmfiFUserIndex(afi, aix), rpmfiFUserIndex(bfi, bix)))
+ if (!rstreq(rpmfilesFUser(afi, aix), rpmfilesFUser(bfi, bix)))
return 1;
- if (!rstreq(rpmfiFGroupIndex(afi, aix), rpmfiFGroupIndex(bfi, bix)))
+ if (!rstreq(rpmfilesFGroup(afi, aix), rpmfilesFGroup(bfi, bix)))
return 1;
if (awhat == LINK) {
- const char * alink = rpmfiFLinkIndex(afi, aix);
- const char * blink = rpmfiFLinkIndex(bfi, bix);
+ const char * alink = rpmfilesFLink(afi, aix);
+ const char * blink = rpmfilesFLink(bfi, bix);
if (alink == blink) return 0;
if (alink == NULL) return 1;
if (blink == NULL) return -1;
@@ -522,8 +952,8 @@ int rpmfiCompareIndex(rpmfi afi, int aix, rpmfi bfi, int bix)
size_t adiglen, bdiglen;
int aalgo, balgo;
const unsigned char * adigest, * bdigest;
- adigest = rpmfiFDigestIndex(afi, aix, &aalgo, &adiglen);
- bdigest = rpmfiFDigestIndex(bfi, bix, &balgo, &bdiglen);
+ adigest = rpmfilesFDigest(afi, aix, &aalgo, &adiglen);
+ bdigest = rpmfilesFDigest(bfi, bix, &balgo, &bdiglen);
if (adigest == bdigest) return 0;
if (adigest == NULL) return 1;
if (bdigest == NULL) return -1;
@@ -531,18 +961,88 @@ int rpmfiCompareIndex(rpmfi afi, int aix, rpmfi bfi, int bix)
if (aalgo != balgo || adiglen != bdiglen) return -1;
return memcmp(adigest, bdigest, adiglen);
} else if (awhat == CDEV || awhat == BDEV) {
- if (rpmfiFRdevIndex(afi, aix) != rpmfiFRdevIndex(bfi, bix))
+ if (rpmfilesFRdev(afi, aix) != rpmfilesFRdev(bfi, bix))
return 1;
}
return 0;
}
-rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix,
+int rpmfileContentsEqual(rpmfiles ofi, int oix, rpmfiles nfi, int nix)
+{
+ char * fn = rpmfilesFN(nfi, nix);
+ rpmFileTypes diskWhat, newWhat, oldWhat;
+ struct stat sb;
+ int equal = 0;
+
+ if (fn == NULL || (lstat(fn, &sb))) {
+ goto exit; /* The file doesn't exist on the disk */
+ }
+
+ if (rpmfilesFSize(nfi, nix) != sb.st_size) {
+ goto exit;
+ }
+
+ diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
+ newWhat = rpmfiWhatis(rpmfilesFMode(nfi, nix));
+ oldWhat = rpmfiWhatis(rpmfilesFMode(ofi, oix));
+ if ((diskWhat != newWhat) || (diskWhat != oldWhat)) {
+ goto exit;
+ }
+
+ if (diskWhat == REG) {
+ int oalgo, nalgo;
+ size_t odiglen, ndiglen;
+ const unsigned char * odigest, * ndigest;
+ char buffer[1024];
+
+ odigest = rpmfilesFDigest(ofi, oix, &oalgo, &odiglen);
+ ndigest = rpmfilesFDigest(nfi, nix, &nalgo, &ndiglen);
+ /* See if the file in old pkg is identical to the one in new pkg */
+ if ((oalgo != nalgo) || (odiglen != ndiglen) || (!ndigest) ||
+ (memcmp(odigest, ndigest, ndiglen) != 0)) {
+ goto exit;
+ }
+
+ if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL) != 0) {
+ goto exit; /* assume file has been removed */
+ }
+
+ /* See if the file on disk is identical to the one in new pkg */
+ if (memcmp(ndigest, buffer, ndiglen) == 0) {
+ equal = 1;
+ goto exit;
+ }
+ } else if (diskWhat == LINK) {
+ const char * nFLink;
+ char buffer[1024];
+ ssize_t link_len;
+
+ nFLink = rpmfilesFLink(nfi, nix);
+ link_len = readlink(fn, buffer, sizeof(buffer) - 1);
+ if (link_len == -1) {
+ goto exit; /* assume file has been removed */
+ }
+ buffer[link_len] = '\0';
+ /* See if the link on disk is identical to the one in new pkg */
+ if (nFLink && rstreq(nFLink, buffer)) {
+ equal = 1;
+ goto exit;
+ }
+ }
+
+exit:
+ free(fn);
+ return equal;
+}
+
+
+rpmFileAction rpmfilesDecideFate(rpmfiles ofi, int oix,
+ rpmfiles nfi, int nix,
int skipMissing)
{
- char * fn = rpmfiFNIndex(nfi, nix);
- rpmfileAttrs newFlags = rpmfiFFlagsIndex(nfi, nix);
+ char * fn = rpmfilesFN(nfi, nix);
+ rpmfileAttrs newFlags = rpmfilesFFlags(nfi, nix);
char buffer[1024];
rpmFileTypes dbWhat, newWhat, diskWhat;
struct stat sb;
@@ -571,39 +1071,47 @@ rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix,
}
diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
- dbWhat = rpmfiWhatis(rpmfiFModeIndex(ofi, oix));
- newWhat = rpmfiWhatis(rpmfiFModeIndex(nfi, nix));
+ dbWhat = rpmfiWhatis(rpmfilesFMode(ofi, oix));
+ newWhat = rpmfiWhatis(rpmfilesFMode(nfi, nix));
/*
- * This order matters - we'd prefer to CREATE the file if at all
+ * This order matters - we'd prefer to TOUCH the file if at all
* possible in case something else (like the timestamp) has changed.
* Only regular files and symlinks might need a backup, everything
* else falls through here with FA_CREATE.
*/
- memset(buffer, 0, sizeof(buffer));
if (dbWhat == REG) {
int oalgo, nalgo;
size_t odiglen, ndiglen;
const unsigned char * odigest, * ndigest;
+ /* See if the file on disk is identical to the one in new pkg */
+ ndigest = rpmfilesFDigest(nfi, nix, &nalgo, &ndiglen);
+ if (diskWhat == REG && newWhat == REG) {
+ if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL))
+ goto exit; /* assume file has been removed */
+ if (ndigest && memcmp(ndigest, buffer, ndiglen) == 0) {
+ action = FA_TOUCH;
+ goto exit; /* unmodified config file, touch it. */
+ }
+ }
+
/* See if the file on disk is identical to the one in old pkg */
- odigest = rpmfiFDigestIndex(ofi, oix, &oalgo, &odiglen);
+ odigest = rpmfilesFDigest(ofi, oix, &oalgo, &odiglen);
if (diskWhat == REG) {
- if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL))
- goto exit; /* assume file has been removed */
+ /* hash algo changed or digest was not computed, recalculate it */
+ if ((oalgo != nalgo) || (newWhat != REG)) {
+ if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL))
+ goto exit; /* assume file has been removed */
+ }
if (odigest && memcmp(odigest, buffer, odiglen) == 0)
goto exit; /* unmodified config file, replace. */
}
- /* See if the file on disk is identical to the one in new pkg */
- ndigest = rpmfiFDigestIndex(nfi, nix, &nalgo, &ndiglen);
- if (diskWhat == REG && newWhat == REG) {
- /* hash algo changed in new, recalculate digest */
- if (oalgo != nalgo)
- if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL))
- goto exit; /* assume file has been removed */
- if (ndigest && memcmp(ndigest, buffer, ndiglen) == 0)
- goto exit; /* file identical in new, replace. */
+ /* if new file is no longer config, backup it and replace it */
+ if (!(newFlags & RPMFILE_CONFIG)) {
+ action = FA_SAVE;
+ goto exit;
}
/* If file can be determined identical in old and new pkg, let it be */
@@ -619,24 +1127,36 @@ rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix,
} else if (dbWhat == LINK) {
const char * oFLink, * nFLink;
- /* See if the link on disk is identical to the one in old pkg */
- oFLink = rpmfiFLinkIndex(ofi, oix);
if (diskWhat == LINK) {
+ /* Read link from the disk */
ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
if (link_len == -1)
goto exit; /* assume file has been removed */
buffer[link_len] = '\0';
- if (oFLink && rstreq(oFLink, buffer))
- goto exit; /* unmodified config file, replace. */
}
/* See if the link on disk is identical to the one in new pkg */
- nFLink = rpmfiFLinkIndex(nfi, nix);
+ nFLink = rpmfilesFLink(nfi, nix);
if (diskWhat == LINK && newWhat == LINK) {
- if (nFLink && rstreq(nFLink, buffer))
+ if (nFLink && rstreq(nFLink, buffer)) {
+ action = FA_TOUCH;
+ goto exit; /* unmodified config file, touch it. */
+ }
+ }
+
+ /* See if the link on disk is identical to the one in old pkg */
+ oFLink = rpmfilesFLink(ofi, oix);
+ if (diskWhat == LINK) {
+ if (oFLink && rstreq(oFLink, buffer))
goto exit; /* unmodified config file, replace. */
}
+ /* if new file is no longer config, backup it and replace it */
+ if (!(newFlags & RPMFILE_CONFIG)) {
+ action = FA_SAVE;
+ goto exit;
+ }
+
/* If link is identical in old and new pkg, let it be */
if (newWhat == LINK && oFLink && nFLink && rstreq(oFLink, nFLink)) {
action = FA_SKIP; /* identical file, don't bother. */
@@ -652,10 +1172,10 @@ exit:
return action;
}
-int rpmfiConfigConflictIndex(rpmfi fi, int ix)
+int rpmfilesConfigConflict(rpmfiles fi, int ix)
{
char * fn = NULL;
- rpmfileAttrs flags = rpmfiFFlagsIndex(fi, ix);
+ rpmfileAttrs flags = rpmfilesFFlags(fi, ix);
char buffer[1024];
rpmFileTypes newWhat, diskWhat;
struct stat sb;
@@ -667,12 +1187,12 @@ int rpmfiConfigConflictIndex(rpmfi fi, int ix)
/* Only links and regular files can be %config, this is kinda moot */
/* XXX: Why are we returning 1 here? */
- newWhat = rpmfiWhatis(rpmfiFModeIndex(fi, ix));
+ newWhat = rpmfiWhatis(rpmfilesFMode(fi, ix));
if (newWhat != LINK && newWhat != REG)
return 1;
/* If it's not on disk, there's nothing to be saved */
- fn = rpmfiFNIndex(fi, ix);
+ fn = rpmfilesFN(fi, ix);
if (lstat(fn, &sb))
goto exit;
@@ -697,7 +1217,7 @@ int rpmfiConfigConflictIndex(rpmfi fi, int ix)
}
/* Files of different sizes obviously are not identical */
- if (rpmfiFSizeIndex(fi, ix) != sb.st_size) {
+ if (rpmfilesFSize(fi, ix) != sb.st_size) {
rc = 1;
goto exit;
}
@@ -706,7 +1226,7 @@ int rpmfiConfigConflictIndex(rpmfi fi, int ix)
if (newWhat == REG) {
int algo;
size_t diglen;
- const unsigned char *ndigest = rpmfiFDigestIndex(fi,ix, &algo, &diglen);
+ const unsigned char *ndigest = rpmfilesFDigest(fi,ix, &algo, &diglen);
if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL))
goto exit; /* assume file has been removed */
if (ndigest && memcmp(ndigest, buffer, diglen) == 0)
@@ -717,7 +1237,7 @@ int rpmfiConfigConflictIndex(rpmfi fi, int ix)
if (link_len == -1)
goto exit; /* assume file has been removed */
buffer[link_len] = '\0';
- nFLink = rpmfiFLinkIndex(fi, ix);
+ nFLink = rpmfilesFLink(fi, ix);
if (nFLink && rstreq(nFLink, buffer))
goto exit; /* unmodified config file */
}
@@ -729,334 +1249,24 @@ exit:
return rc;
}
-static char **duparray(char ** src, int size)
-{
- char **dest = xmalloc((size+1) * sizeof(*dest));
- for (int i = 0; i < size; i++) {
- dest[i] = xstrdup(src[i]);
- }
- free(src);
- return dest;
-}
-
-static int addPrefixes(Header h, rpmRelocation *relocations, int numRelocations)
-{
- struct rpmtd_s validRelocs;
- const char *validprefix;
- const char ** actualRelocations;
- int numActual = 0;
-
- headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM);
- /*
- * If no relocations are specified (usually the case), then return the
- * original header. If there are prefixes, however, then INSTPREFIXES
- * should be added for RPM_INSTALL_PREFIX environ variables in scriptlets,
- * but, since relocateFileList() can be called more than once for
- * the same header, don't bother if already present.
- */
- if (relocations == NULL || numRelocations == 0) {
- if (rpmtdCount(&validRelocs) > 0) {
- if (!headerIsEntry(h, RPMTAG_INSTPREFIXES)) {
- rpmtdSetTag(&validRelocs, RPMTAG_INSTPREFIXES);
- headerPut(h, &validRelocs, HEADERPUT_DEFAULT);
- }
- rpmtdFreeData(&validRelocs);
- }
- return 0;
- }
-
- actualRelocations = xmalloc(rpmtdCount(&validRelocs) * sizeof(*actualRelocations));
- rpmtdInit(&validRelocs);
- while ((validprefix = rpmtdNextString(&validRelocs))) {
- int j;
- for (j = 0; j < numRelocations; j++) {
- if (relocations[j].oldPath == NULL || /* XXX can't happen */
- !rstreq(validprefix, relocations[j].oldPath))
- continue;
- /* On install, a relocate to NULL means skip the path. */
- if (relocations[j].newPath) {
- actualRelocations[numActual] = relocations[j].newPath;
- numActual++;
- }
- break;
- }
- if (j == numRelocations) {
- actualRelocations[numActual] = validprefix;
- numActual++;
- }
- }
- rpmtdFreeData(&validRelocs);
-
- if (numActual) {
- headerPutStringArray(h, RPMTAG_INSTPREFIXES, actualRelocations, numActual);
- }
- free(actualRelocations);
- return numActual;
-}
-
-static void saveRelocs(Header h, rpmtd bnames, rpmtd dnames, rpmtd dindexes)
-{
- struct rpmtd_s td;
- headerGet(h, RPMTAG_BASENAMES, &td, HEADERGET_MINMEM);
- rpmtdSetTag(&td, RPMTAG_ORIGBASENAMES);
- headerPut(h, &td, HEADERPUT_DEFAULT);
- rpmtdFreeData(&td);
-
- headerGet(h, RPMTAG_DIRNAMES, &td, HEADERGET_MINMEM);
- rpmtdSetTag(&td, RPMTAG_ORIGDIRNAMES);
- headerPut(h, &td, HEADERPUT_DEFAULT);
- rpmtdFreeData(&td);
-
- headerGet(h, RPMTAG_DIRINDEXES, &td, HEADERGET_MINMEM);
- rpmtdSetTag(&td, RPMTAG_ORIGDIRINDEXES);
- headerPut(h, &td, HEADERPUT_DEFAULT);
- rpmtdFreeData(&td);
-
- headerMod(h, bnames);
- headerMod(h, dnames);
- headerMod(h, dindexes);
-}
-
-void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations,
- rpmfs fs, Header h)
-{
- static int _printed = 0;
- char ** baseNames;
- char ** dirNames;
- uint32_t * dirIndexes;
- rpm_count_t fileCount, dirCount;
- int nrelocated = 0;
- int fileAlloced = 0;
- char * fn = NULL;
- int haveRelocatedBase = 0;
- size_t maxlen = 0;
- int i, j;
- struct rpmtd_s bnames, dnames, dindexes, fmodes;
-
- addPrefixes(h, relocations, numRelocations);
-
- if (!_printed) {
- _printed = 1;
- rpmlog(RPMLOG_DEBUG, "========== relocations\n");
- for (i = 0; i < numRelocations; i++) {
- if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
- if (relocations[i].newPath == NULL)
- rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n",
- i, relocations[i].oldPath);
- else
- rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
- i, relocations[i].oldPath, relocations[i].newPath);
- }
- }
-
- for (i = 0; i < numRelocations; i++) {
- if (relocations[i].newPath == NULL) continue;
- size_t len = strlen(relocations[i].newPath);
- if (len > maxlen) maxlen = len;
- }
-
- headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM);
- headerGet(h, RPMTAG_DIRINDEXES, &dindexes, HEADERGET_ALLOC);
- headerGet(h, RPMTAG_DIRNAMES, &dnames, HEADERGET_MINMEM);
- headerGet(h, RPMTAG_FILEMODES, &fmodes, HEADERGET_MINMEM);
- /* TODO XXX ugh.. use rpmtd iterators & friends instead */
- baseNames = bnames.data;
- dirIndexes = dindexes.data;
- fileCount = rpmtdCount(&bnames);
- dirCount = rpmtdCount(&dnames);
- /* XXX TODO: use rpmtdDup() instead */
- dirNames = dnames.data = duparray(dnames.data, dirCount);
- dnames.flags |= RPMTD_PTR_ALLOCED;
-
- /*
- * For all relocations, we go through sorted file/relocation lists
- * backwards so that /usr/local relocations take precedence over /usr
- * ones.
- */
-
- /* Relocate individual paths. */
-
- for (i = fileCount - 1; i >= 0; i--) {
- rpmFileTypes ft;
- int fnlen;
-
- size_t len = maxlen +
- strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
- if (len >= fileAlloced) {
- fileAlloced = len * 2;
- fn = xrealloc(fn, fileAlloced);
- }
-
-assert(fn != NULL); /* XXX can't happen */
- *fn = '\0';
- fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
-
- /*
- * See if this file path needs relocating.
- */
- /*
- * XXX FIXME: Would a bsearch of the (already sorted)
- * relocation list be a good idea?
- */
- for (j = numRelocations - 1; j >= 0; j--) {
- if (relocations[j].oldPath == NULL) /* XXX can't happen */
- continue;
- len = !rstreq(relocations[j].oldPath, "/")
- ? strlen(relocations[j].oldPath)
- : 0;
-
- if (fnlen < len)
- continue;
- /*
- * Only subdirectories or complete file paths may be relocated. We
- * don't check for '\0' as our directory names all end in '/'.
- */
- if (!(fn[len] == '/' || fnlen == len))
- continue;
-
- if (!rstreqn(relocations[j].oldPath, fn, len))
- continue;
- break;
- }
- if (j < 0) continue;
-
- rpmtdSetIndex(&fmodes, i);
- ft = rpmfiWhatis(rpmtdGetNumber(&fmodes));
-
- /* On install, a relocate to NULL means skip the path. */
- if (relocations[j].newPath == NULL) {
- if (ft == XDIR) {
- /* Start with the parent, looking for directory to exclude. */
- for (j = dirIndexes[i]; j < dirCount; j++) {
- len = strlen(dirNames[j]) - 1;
- while (len > 0 && dirNames[j][len-1] == '/') len--;
- if (fnlen != len)
- continue;
- if (!rstreqn(fn, dirNames[j], fnlen))
- continue;
- break;
- }
- }
- rpmfsSetAction(fs, i, FA_SKIPNSTATE);
- rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
- ftstring(ft), fn);
- continue;
- }
-
- /* Relocation on full paths only, please. */
- if (fnlen != len) continue;
-
- rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
- fn, relocations[j].newPath);
- nrelocated++;
-
- strcpy(fn, relocations[j].newPath);
- { char * te = strrchr(fn, '/');
- if (te) {
- if (te > fn) te++; /* root is special */
- fnlen = te - fn;
- } else
- te = fn + strlen(fn);
- if (!rstreq(baseNames[i], te)) { /* basename changed too? */
- if (!haveRelocatedBase) {
- /* XXX TODO: use rpmtdDup() instead */
- bnames.data = baseNames = duparray(baseNames, fileCount);
- bnames.flags |= RPMTD_PTR_ALLOCED;
- haveRelocatedBase = 1;
- }
- free(baseNames[i]);
- baseNames[i] = xstrdup(te);
- }
- *te = '\0'; /* terminate new directory name */
- }
-
- /* Does this directory already exist in the directory list? */
- for (j = 0; j < dirCount; j++) {
- if (fnlen != strlen(dirNames[j]))
- continue;
- if (!rstreqn(fn, dirNames[j], fnlen))
- continue;
- break;
- }
-
- if (j < dirCount) {
- dirIndexes[i] = j;
- continue;
- }
-
- /* Creating new paths is a pita */
- dirNames = dnames.data = xrealloc(dnames.data,
- sizeof(*dirNames) * (dirCount + 1));
-
- dirNames[dirCount] = xstrdup(fn);
- dirIndexes[i] = dirCount;
- dirCount++;
- dnames.count++;
- }
-
- /* Finish off by relocating directories. */
- for (i = dirCount - 1; i >= 0; i--) {
- for (j = numRelocations - 1; j >= 0; j--) {
-
- if (relocations[j].oldPath == NULL) /* XXX can't happen */
- continue;
- size_t len = !rstreq(relocations[j].oldPath, "/")
- ? strlen(relocations[j].oldPath)
- : 0;
-
- if (len && !rstreqn(relocations[j].oldPath, dirNames[i], len))
- continue;
-
- /*
- * Only subdirectories or complete file paths may be relocated. We
- * don't check for '\0' as our directory names all end in '/'.
- */
- if (dirNames[i][len] != '/')
- continue;
-
- if (relocations[j].newPath) { /* Relocate the path */
- char *t = NULL;
- rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
- /* Unfortunatly rpmCleanPath strips the trailing slash.. */
- (void) rpmCleanPath(t);
- rstrcat(&t, "/");
-
- rpmlog(RPMLOG_DEBUG,
- "relocating directory %s to %s\n", dirNames[i], t);
- free(dirNames[i]);
- dirNames[i] = t;
- nrelocated++;
- }
- }
- }
-
- /* Save original filenames in header and replace (relocated) filenames. */
- if (nrelocated) {
- saveRelocs(h, &bnames, &dnames, &dindexes);
- }
-
- rpmtdFreeData(&bnames);
- rpmtdFreeData(&dnames);
- rpmtdFreeData(&dindexes);
- rpmtdFreeData(&fmodes);
- free(fn);
-}
-
-rpmfi rpmfiFree(rpmfi fi)
+rpmfiles rpmfilesFree(rpmfiles fi)
{
if (fi == NULL) return NULL;
if (fi->nrefs > 1)
- return rpmfiUnlink(fi);
+ return rpmfilesUnlink(fi);
- if (fi->fc > 0) {
- fi->bnid = _free(fi->bnid);
- fi->dnid = _free(fi->dnid);
- fi->dil = _free(fi->dil);
+ if (rpmfilesFC(fi) > 0) {
+ if (fi->ofndata != &fi->fndata) {
+ rpmfnClear(fi->ofndata);
+ free(fi->ofndata);
+ }
+ rpmfnClear(&fi->fndata);
fi->flinks = _free(fi->flinks);
fi->flangs = _free(fi->flangs);
fi->digests = _free(fi->digests);
+ fi->signatures = _free(fi->signatures);
fi->fcaps = _free(fi->fcaps);
fi->cdict = _free(fi->cdict);
@@ -1067,8 +1277,6 @@ rpmfi rpmfiFree(rpmfi fi)
fi->fstates = _free(fi->fstates);
fi->fps = _free(fi->fps);
- fi->pool = rpmstrPoolFree(fi->pool);
-
/* these point to header memory if KEEPHEADER is used, dont free */
if (!(fi->fiflags & RPMFI_KEEPHEADER) && fi->h == NULL) {
fi->fmtimes = _free(fi->fmtimes);
@@ -1076,6 +1284,7 @@ rpmfi rpmfiFree(rpmfi fi)
fi->fflags = _free(fi->fflags);
fi->vflags = _free(fi->vflags);
fi->fsizes = _free(fi->fsizes);
+ fi->lfsizes = _free(fi->lfsizes);
fi->frdevs = _free(fi->frdevs);
fi->finodes = _free(fi->finodes);
@@ -1088,26 +1297,46 @@ rpmfi rpmfiFree(rpmfi fi)
}
}
- fi->fn = _free(fi->fn);
- fi->apath = _free(fi->apath);
-
fi->replacedSizes = _free(fi->replacedSizes);
+ fi->replacedLSizes = _free(fi->replacedLSizes);
fi->h = headerFree(fi->h);
+ fi->pool = rpmstrPoolFree(fi->pool);
+
+ fi->nlinks = nlinkHashFree(fi->nlinks);
- (void) rpmfiUnlink(fi);
+ (void) rpmfilesUnlink(fi);
memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
fi = _free(fi);
return NULL;
}
-static rpmsid * tag2pool(rpmstrPool pool, Header h, rpmTag tag)
+rpmfi rpmfiFree(rpmfi fi)
+{
+ if (fi == NULL) return NULL;
+
+ if (fi->nrefs > 1)
+ return rpmfiUnlink(fi);
+
+ fi->files = rpmfilesFree(fi->files);
+ fi->fn = _free(fi->fn);
+ fi->ofn = _free(fi->ofn);
+ fi->found = _free(fi->found);
+ fi->archive = rpmcpioFree(fi->archive);
+
+ free(fi);
+ return NULL;
+}
+
+static rpmsid * tag2pool(rpmstrPool pool, Header h, rpmTag tag, rpm_count_t size)
{
rpmsid *sids = NULL;
struct rpmtd_s td;
if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
- sids = rpmtdToPool(&td, pool);
+ if ((size >= 0) && (rpmtdCount(&td) == size)) { /* ensure right size */
+ sids = rpmtdToPool(&td, pool);
+ }
rpmtdFreeData(&td);
}
return sids;
@@ -1122,30 +1351,182 @@ static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd)
uint32_t zc = rpmtdCount(zd);
/* check that the amount of data in each is sane */
- if (xc > 0 && yc > 0 && yc <= xc && zc == xc) {
- uint32_t * i;
+ /* normally yc <= xc but larger values are not fatal (RhBug:1001553) */
+ if (xc > 0 && yc > 0 && zc == xc) {
+ uint32_t * i, nvalid = 0;
/* ...and that the indexes are within bounds */
while ((i = rpmtdNextUint32(zd))) {
if (*i >= yc)
break;
+ nvalid++;
}
/* unless the loop runs to finish, the data is broken */
- sane = (i == NULL);
+ sane = (nvalid == zc);
}
return sane;
}
+/* Get file data from header */
+/* Requires totalfc to be set and label err: to goto on error */
#define _hgfi(_h, _tag, _td, _flags, _data) \
- if (headerGet((_h), (_tag), (_td), (_flags))) \
- _data = (td.data)
+ if (headerGet((_h), (_tag), (_td), (_flags))) { \
+ if (rpmtdCount(_td) != totalfc) { \
+ rpmlog(RPMLOG_ERR, _("Wrong number of entries for tag %s: %u found but %u expected.\n"), rpmTagGetName(_tag), rpmtdCount(_td), totalfc); \
+ goto err; \
+ } \
+ if (rpmTagGetTagType(_tag) != RPM_STRING_ARRAY_TYPE && rpmTagGetTagType(_tag) != RPM_I18NSTRING_TYPE && \
+ (_td)->size < totalfc * sizeof(*(_data))) { \
+ rpmlog(RPMLOG_ERR, _("Malformed data for tag %s: %u bytes found but %u expected.\n"), rpmTagGetName(_tag), (_td)->size, totalfc * sizeof(*(_data))); \
+ goto err; \
+ } \
+ _data = ((_td)->data); \
+ }
+/* Get file data from header without checking number of entries */
+#define _hgfinc(_h, _tag, _td, _flags, _data) \
+ if (headerGet((_h), (_tag), (_td), (_flags))) {\
+ _data = ((_td)->data); \
+ }
+
+/*** Hard link handling ***/
+
+struct fileid_s {
+ rpm_dev_t id_dev;
+ rpm_ino_t id_ino;
+};
+
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+#define HASHTYPE fileidHash
+#define HTKEYTYPE struct fileid_s
+#define HTDATATYPE int
+#include "lib/rpmhash.H"
+#include "lib/rpmhash.C"
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+
+static unsigned int fidHashFunc(struct fileid_s a)
+{
+ return a.id_ino + (a.id_dev<<16) + (a.id_dev>>16);
+}
+
+static int fidCmp(struct fileid_s a, struct fileid_s b)
+{
+ return !((a.id_dev == b.id_dev) && (a.id_ino == b.id_ino));
+}
+
+static unsigned int intHash(int a)
+{
+ return a < 0 ? UINT_MAX-a : a;
+}
+
+static int intCmp(int a, int b)
+{
+ return a != b;
+}
+
+static struct hardlinks_s * freeNLinks(struct hardlinks_s * nlinks)
+{
+ nlinks->nlink--;
+ if (!nlinks->nlink) {
+ nlinks = _free(nlinks);
+ }
+ return nlinks;
+}
-static int rpmfiPopulate(rpmfi fi, Header h, rpmfiFlags flags)
+static void rpmfilesBuildNLink(rpmfiles fi, Header h)
+{
+ struct fileid_s f_id;
+ fileidHash files;
+ rpm_dev_t * fdevs = NULL;
+ struct rpmtd_s td;
+ int fc = 0;
+ int totalfc = rpmfilesFC(fi);
+
+ if (!fi->finodes)
+ return;
+
+ _hgfi(h, RPMTAG_FILEDEVICES, &td, HEADERGET_ALLOC, fdevs);
+ if (!fdevs)
+ return;
+
+ files = fileidHashCreate(totalfc, fidHashFunc, fidCmp, NULL, NULL);
+ for (int i=0; i < totalfc; i++) {
+ if (!S_ISREG(rpmfilesFMode(fi, i)) ||
+ (rpmfilesFFlags(fi, i) & RPMFILE_GHOST) ||
+ fi->finodes[i] <= 0) {
+ continue;
+ }
+ fc++;
+ f_id.id_dev = fdevs[i];
+ f_id.id_ino = fi->finodes[i];
+ fileidHashAddEntry(files, f_id, i);
+ }
+ if (fileidHashNumKeys(files) != fc) {
+ /* Hard links */
+ fi->nlinks = nlinkHashCreate(2*(totalfc - fileidHashNumKeys(files)),
+ intHash, intCmp, NULL, freeNLinks);
+ for (int i=0; i < totalfc; i++) {
+ int fcnt;
+ int * data;
+ if (!S_ISREG(rpmfilesFMode(fi, i)) ||
+ (rpmfilesFFlags(fi, i) & RPMFILE_GHOST)) {
+ continue;
+ }
+ f_id.id_dev = fdevs[i];
+ f_id.id_ino = fi->finodes[i];
+ fileidHashGetEntry(files, f_id, &data, &fcnt, NULL);
+ if (fcnt > 1 && !nlinkHashHasEntry(fi->nlinks, i)) {
+ struct hardlinks_s * hlinks;
+ hlinks = xmalloc(sizeof(struct hardlinks_s)+
+ fcnt*sizeof(hlinks->files[0]));
+ hlinks->nlink = fcnt;
+ for (int j=0; j<fcnt; j++) {
+ hlinks->files[j] = data[j];
+ nlinkHashAddEntry(fi->nlinks, data[j], hlinks);
+ }
+ }
+ }
+ }
+ _free(fdevs);
+ files = fileidHashFree(files);
+err:
+ return;
+}
+
+/* Convert a tag of hex strings to binary presentation */
+static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
+{
+ struct rpmtd_s td;
+ uint8_t *bin = NULL;
+
+ if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {
+ uint8_t *t = bin = xmalloc(num * len);
+ const char *s;
+
+ while ((s = rpmtdNextString(&td))) {
+ if (*s == '\0') {
+ memset(t, 0, len);
+ t += len;
+ continue;
+ }
+ for (int j = 0; j < len; j++, t++, s += 2)
+ *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
+ }
+ }
+ rpmtdFreeData(&td);
+
+ return bin;
+}
+
+static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
{
headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ?
HEADERGET_MINMEM : HEADERGET_ALLOC;
headerGetFlags defFlags = HEADERGET_ALLOC;
- struct rpmtd_s fdigests, digalgo, td;
- unsigned char * t;
+ struct rpmtd_s digalgo, td;
+ rpm_count_t totalfc = rpmfilesFC(fi);
/* XXX TODO: all these should be sanity checked, ugh... */
if (!(flags & RPMFI_NOFILEMODES))
@@ -1154,22 +1535,23 @@ static int rpmfiPopulate(rpmfi fi, Header h, rpmfiFlags flags)
_hgfi(h, RPMTAG_FILEFLAGS, &td, scareFlags, fi->fflags);
if (!(flags & RPMFI_NOFILEVERIFYFLAGS))
_hgfi(h, RPMTAG_FILEVERIFYFLAGS, &td, scareFlags, fi->vflags);
- if (!(flags & RPMFI_NOFILESIZES))
+ if (!(flags & RPMFI_NOFILESIZES)) {
_hgfi(h, RPMTAG_FILESIZES, &td, scareFlags, fi->fsizes);
-
+ _hgfi(h, RPMTAG_LONGFILESIZES, &td, scareFlags, fi->lfsizes);
+ }
if (!(flags & RPMFI_NOFILECOLORS))
_hgfi(h, RPMTAG_FILECOLORS, &td, scareFlags, fi->fcolors);
if (!(flags & RPMFI_NOFILECLASS)) {
- _hgfi(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
+ _hgfinc(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
fi->ncdict = rpmtdCount(&td);
_hgfi(h, RPMTAG_FILECLASS, &td, scareFlags, fi->fcdictx);
}
if (!(flags & RPMFI_NOFILEDEPS)) {
- _hgfi(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
+ _hgfinc(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
fi->nddict = rpmtdCount(&td);
- _hgfi(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
- _hgfi(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
+ _hgfinc(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
+ _hgfinc(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
}
if (!(flags & RPMFI_NOFILESTATES))
@@ -1179,10 +1561,10 @@ static int rpmfiPopulate(rpmfi fi, Header h, rpmfiFlags flags)
_hgfi(h, RPMTAG_FILECAPS, &td, defFlags, fi->fcaps);
if (!(flags & RPMFI_NOFILELINKTOS))
- fi->flinks = tag2pool(fi->pool, h, RPMTAG_FILELINKTOS);
+ fi->flinks = tag2pool(fi->pool, h, RPMTAG_FILELINKTOS, totalfc);
/* FILELANGS are only interesting when installing */
if ((headerGetInstance(h) == 0) && !(flags & RPMFI_NOFILELANGS))
- fi->flangs = tag2pool(fi->pool, h, RPMTAG_FILELANGS);
+ fi->flangs = tag2pool(fi->pool, h, RPMTAG_FILELANGS, totalfc);
/* See if the package has non-md5 file digests */
fi->digestalgo = PGPHASHALGO_MD5;
@@ -1196,22 +1578,17 @@ static int rpmfiPopulate(rpmfi fi, Header h, rpmfiFlags flags)
fi->digests = NULL;
/* grab hex digests from header and store in binary format */
- if (!(flags & RPMFI_NOFILEDIGESTS) &&
- headerGet(h, RPMTAG_FILEDIGESTS, &fdigests, HEADERGET_MINMEM)) {
- const char *fdigest;
+ if (!(flags & RPMFI_NOFILEDIGESTS)) {
size_t diglen = rpmDigestLength(fi->digestalgo);
- fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
+ fi->digests = hex2bin(h, RPMTAG_FILEDIGESTS, totalfc, diglen);
+ }
- while ((fdigest = rpmtdNextString(&fdigests))) {
- if (!(fdigest && *fdigest != '\0')) {
- memset(t, 0, diglen);
- t += diglen;
- continue;
- }
- for (int j = 0; j < diglen; j++, t++, fdigest += 2)
- *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
- }
- rpmtdFreeData(&fdigests);
+ fi->signatures = NULL;
+ /* grab hex signatures from header and store in binary format */
+ if (!(flags & RPMFI_NOFILESIGNATURES)) {
+ fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);
+ fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,
+ totalfc, fi->signaturelength);
}
/* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
@@ -1219,67 +1596,170 @@ static int rpmfiPopulate(rpmfi fi, Header h, rpmfiFlags flags)
_hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
if (!(flags & RPMFI_NOFILERDEVS))
_hgfi(h, RPMTAG_FILERDEVS, &td, scareFlags, fi->frdevs);
- if (!(flags & RPMFI_NOFILEINODES))
+ if (!(flags & RPMFI_NOFILEINODES)) {
_hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
-
- if (!(flags & RPMFI_NOFILEUSER))
- fi->fuser = tag2pool(fi->pool, h, RPMTAG_FILEUSERNAME);
- if (!(flags & RPMFI_NOFILEGROUP))
- fi->fgroup = tag2pool(fi->pool, h, RPMTAG_FILEGROUPNAME);
-
+ rpmfilesBuildNLink(fi, h);
+ }
+ if (!(flags & RPMFI_NOFILEUSER)) {
+ fi->fuser = tag2pool(fi->pool, h, RPMTAG_FILEUSERNAME, totalfc);
+ if (!fi->fuser) goto err;
+ }
+ if (!(flags & RPMFI_NOFILEGROUP)) {
+ fi->fgroup = tag2pool(fi->pool, h, RPMTAG_FILEGROUPNAME, totalfc);
+ if (!fi->fgroup) goto err;
+ }
/* TODO: validate and return a real error */
return 0;
+ err:
+ return -1;
}
-rpmfi rpmfiNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
+rpmfiles rpmfilesNew(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
{
- rpmfi fi = xcalloc(1, sizeof(*fi));
- struct rpmtd_s bn, dn, dx;
+ rpmfiles fi = xcalloc(1, sizeof(*fi));
+ int fc;
fi->magic = RPMFIMAGIC;
- fi->i = -1;
fi->fiflags = flags;
+ /* private or shared pool? */
+ fi->pool = (pool != NULL) ? rpmstrPoolLink(pool) : rpmstrPoolCreate();
/*
* Grab and validate file triplet data. Headers with no files simply
* fall through here and an empty file set is returned.
*/
- if (headerGet(h, RPMTAG_BASENAMES, &bn, HEADERGET_MINMEM)) {
- headerGet(h, RPMTAG_DIRNAMES, &dn, HEADERGET_MINMEM);
- headerGet(h, RPMTAG_DIRINDEXES, &dx, HEADERGET_ALLOC);
+ fc = rpmfnInit(&fi->fndata, RPMTAG_BASENAMES, h, fi->pool);
+
+ /* Broken data, bail out */
+ if (fc < 0)
+ goto err;
+
+ /* populate the rest of the stuff if we have files */
+ if (fc > 0) {
+ if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
+ /* For relocated packages, grab the original paths too */
+ int ofc;
+ fi->ofndata = xmalloc(sizeof(*fi->ofndata));
+ ofc = rpmfnInit(fi->ofndata, RPMTAG_ORIGBASENAMES, h, fi->pool);
+
+ if (ofc != 0 && ofc != fc)
+ goto err;
+ } else {
+ /* In the normal case, orig is the same as actual path data */
+ fi->ofndata = &fi->fndata;
+ }
+
+ if (rpmfilesPopulate(fi, h, flags))
+ goto err;
+ }
- if (indexSane(&bn, &dn, &dx)) {
- /* private or shared pool? */
- fi->pool = (pool != NULL) ? rpmstrPoolLink(pool) :
- rpmstrPoolCreate();
-
- /* init the file triplet data */
- fi->fc = rpmtdCount(&bn);
- fi->dc = rpmtdCount(&dn);
- fi->bnid = rpmtdToPool(&bn, fi->pool);
- fi->dnid = rpmtdToPool(&dn, fi->pool);
- /* steal index data from the td (pooh...) */
- fi->dil = dx.data;
- dx.data = NULL;
+ /* freeze the pool to save memory, but only if private pool */
+ if (fi->pool != pool)
+ rpmstrPoolFreeze(fi->pool, 0);
- /* populate the rest of the stuff */
- rpmfiPopulate(fi, h, flags);
+ fi->h = (fi->fiflags & RPMFI_KEEPHEADER) ? headerLink(h) : NULL;
- /* freeze the pool to save memory, but only if private pool */
- if (fi->pool != pool)
- rpmstrPoolFreeze(fi->pool, 0);
+ return rpmfilesLink(fi);
- fi->h = (fi->fiflags & RPMFI_KEEPHEADER) ? headerLink(h) : NULL;
- } else {
- /* broken data, free and return NULL */
- fi = _free(fi);
+err:
+ rpmfilesFree(fi);
+ return NULL;
+}
+
+static int iterWriteArchiveNext(rpmfi fi);
+static int iterReadArchiveNext(rpmfi fi);
+static int iterReadArchiveNextContentFirst(rpmfi fi);
+static int iterReadArchiveNextOmitHardlinks(rpmfi fi);
+
+static int (*nextfuncs[])(rpmfi fi) = {
+ iterFwd,
+ iterBack,
+ iterWriteArchiveNext,
+ iterReadArchiveNext,
+ iterReadArchiveNextContentFirst,
+ iterReadArchiveNextOmitHardlinks,
+ iterInterval,
+};
+
+
+static rpmfi initIter(rpmfiles files, int itype, int link)
+{
+ rpmfi fi = NULL;
+
+ if (files && itype>=0 && itype<=RPMFILEITERMAX) {
+ fi = xcalloc(1, sizeof(*fi));
+ fi->i = -1;
+ fi->files = link ? rpmfilesLink(files) : files;
+ fi->next = nextfuncs[itype];
+ fi->i = -1;
+ if (itype == RPMFI_ITER_BACK) {
+ fi->i = rpmfilesFC(fi->files);
+ } else if (itype >=RPMFI_ITER_READ_ARCHIVE
+ && itype <= RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS) {
+
+ fi->found = xcalloc(1, (rpmfiFC(fi)>>3) + 1);
}
- rpmtdFreeData(&bn);
- rpmtdFreeData(&dn);
- rpmtdFreeData(&dx);
+ rpmfiLink(fi);
+ }
+ return fi;
+}
+
+rpmfi rpmfilesIter(rpmfiles files, int itype)
+{
+ /* standalone iterators need to bump our refcount */
+ return initIter(files, itype, 1);
+}
+
+rpmfi rpmfilesFindPrefix(rpmfiles fi, const char *pfx)
+{
+ int l, u, c, comparison;
+ rpmfi iterator = NULL;
+
+ if (!fi || !pfx)
+ return NULL;
+
+ size_t plen = strlen(pfx);
+ l = 0;
+ u = rpmfilesFC(fi);
+ while (l < u) {
+ c = (l + u) / 2;
+
+ comparison = cmpPfx(fi, c, pfx, plen);
+
+ if (comparison < 0)
+ u = c;
+ else if (comparison > 0)
+ l = c + 1;
+ else {
+ if (cmpPfx(fi, l, pfx, plen))
+ l = c;
+ while (l > 0 && !cmpPfx(fi, l - 1, pfx, plen))
+ l--;
+ if ( u >= rpmfilesFC(fi) || cmpPfx(fi, u, pfx, plen))
+ u = c;
+ while (++u < rpmfilesFC(fi)) {
+ if (cmpPfx(fi, u, pfx, plen))
+ break;
+ }
+ break;
+ }
+
+ }
+
+ if (l < u) {
+ iterator = initIter(fi, RPMFI_ITER_INTERVAL, 1);
+ iterator->intervalStart = l;
+ iterator->intervalEnd = u;
}
- return rpmfiLink(fi);
+ return iterator;
+}
+
+rpmfi rpmfiNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
+{
+ rpmfiles files = rpmfilesNew(pool, h, tagN, flags);
+ /* we already own rpmfiles, avoid extra refcount on it */
+ return initIter(files, RPMFI_ITER_FWD, 0);
}
rpmfi rpmfiNew(const rpmts ts, Header h, rpmTagVal tagN, rpmfiFlags flags)
@@ -1287,36 +1767,52 @@ rpmfi rpmfiNew(const rpmts ts, Header h, rpmTagVal tagN, rpmfiFlags flags)
return rpmfiNewPool(NULL, h, tagN, flags);
}
-void rpmfiSetFReplacedSizeIndex(rpmfi fi, int ix, rpm_loff_t newsize)
+void rpmfilesSetFReplacedSize(rpmfiles fi, int ix, rpm_loff_t newsize)
{
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
- if (fi->replacedSizes == NULL) {
- fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
+ /* Switch over to 64 bit variant */
+ int fc = rpmfilesFC(fi);
+ if (newsize > UINT32_MAX && fi->replacedLSizes == NULL) {
+ fi->replacedLSizes = xcalloc(fc, sizeof(*fi->replacedLSizes));
+ /* copy 32 bit data */
+ if (fi->replacedSizes) {
+ for (int i=0; i < fc; i++)
+ fi->replacedLSizes[i] = fi->replacedSizes[i];
+ fi->replacedSizes = _free(fi->replacedSizes);
+ }
+ }
+ if (fi->replacedLSizes != NULL) {
+ fi->replacedLSizes[ix] = newsize;
+ } else {
+ if (fi->replacedSizes == NULL)
+ fi->replacedSizes = xcalloc(fc, sizeof(*fi->replacedSizes));
+ fi->replacedSizes[ix] = (rpm_off_t) newsize;
}
- /* XXX watch out, replacedSizes is not rpm_loff_t (yet) */
- fi->replacedSizes[ix] = (rpm_off_t) newsize;
}
}
-rpm_loff_t rpmfiFReplacedSizeIndex(rpmfi fi, int ix)
+rpm_loff_t rpmfilesFReplacedSize(rpmfiles fi, int ix)
{
rpm_loff_t rsize = 0;
- if (fi != NULL && ix >= 0 && ix < fi->fc) {
+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->replacedSizes) {
rsize = fi->replacedSizes[ix];
+ } else if (fi->replacedLSizes) {
+ rsize = fi->replacedLSizes[ix];
}
}
return rsize;
}
-void rpmfiFpLookup(rpmfi fi, fingerPrintCache fpc)
+void rpmfilesFpLookup(rpmfiles fi, fingerPrintCache fpc)
{
/* This can get called twice (eg yum), scratch former results and redo */
- if (fi->fc > 0) {
+ if (rpmfilesFC(fi) > 0) {
+ rpmfn fn = &fi->fndata;
if (fi->fps)
free(fi->fps);
fi->fps = fpLookupList(fpc, fi->pool,
- fi->dnid, fi->bnid, fi->dil, fi->fc);
+ fn->dnid, fn->bnid, fn->dil, fn->fc);
}
}
@@ -1326,12 +1822,14 @@ void rpmfiFpLookup(rpmfi fi, fingerPrintCache fpc)
*/
#define RPMFI_ITERFUNC(TYPE, NAME, IXV) \
- TYPE rpmfi ## NAME(rpmfi fi) { return rpmfi ## NAME ## Index(fi, fi ? fi->IXV : -1); }
+ TYPE rpmfi ## NAME(rpmfi fi) { return rpmfiles ## NAME(fi ? fi->files : NULL, fi ? fi->IXV : -1); }
RPMFI_ITERFUNC(rpmsid, BNId, i)
RPMFI_ITERFUNC(rpmsid, DNId, j)
RPMFI_ITERFUNC(const char *, BN, i)
RPMFI_ITERFUNC(const char *, DN, j)
+RPMFI_ITERFUNC(const char *, OBN, i)
+RPMFI_ITERFUNC(const char *, ODN, j)
RPMFI_ITERFUNC(const char *, FLink, i)
RPMFI_ITERFUNC(const char *, FUser, i)
RPMFI_ITERFUNC(const char *, FGroup, i)
@@ -1354,41 +1852,545 @@ const char * rpmfiFN(rpmfi fi)
const char *fn = ""; /* preserve behavior on errors */
if (fi != NULL) {
free(fi->fn);
- fi->fn = rpmfiFNIndex(fi, fi->i);
+ fi->fn = rpmfilesFN(fi->files, fi->i);
if (fi->fn != NULL)
fn = fi->fn;
}
return fn;
}
+const char * rpmfiOFN(rpmfi fi)
+{
+ const char *fn = ""; /* preserve behavior on errors */
+ if (fi != NULL) {
+ free(fi->ofn);
+ fi->ofn = rpmfilesOFN(fi->files, fi->i);
+ if (fi->ofn != NULL)
+ fn = fi->ofn;
+ }
+ return fn;
+}
+
const unsigned char * rpmfiFDigest(rpmfi fi, int *algo, size_t *len)
{
- return rpmfiFDigestIndex(fi, fi ? fi->i : -1, algo, len);
+ return rpmfilesFDigest(fi->files, fi ? fi->i : -1, algo, len);
+}
+
+const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)
+{
+ return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);
}
uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
{
- return rpmfiFDependsIndex(fi, fi ? fi->i : -1, fddictp);
+ return rpmfilesFDepends(fi->files, fi ? fi->i : -1, fddictp);
}
-int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
+int rpmfiStat(rpmfi fi, int flags, struct stat *sb)
{
- return rpmfiCompareIndex(afi, afi ? afi->i : -1, bfi, bfi ? bfi->i : -1);
+ return rpmfilesStat(fi->files, fi->i, flags, sb);
}
-rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
+int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
{
- return rpmfiDecideFateIndex(ofi, ofi ? ofi->i : -1,
- nfi, nfi ? nfi->i : -1,
- skipMissing);
+ return rpmfilesCompare(afi->files, afi ? afi->i : -1, bfi->files, bfi ? bfi->i : -1);
}
-int rpmfiConfigConflict(const rpmfi fi)
+rpmVerifyAttrs rpmfiVerify(rpmfi fi, rpmVerifyAttrs omitMask)
{
- return rpmfiConfigConflictIndex(fi, fi ? fi->i : -1);
+ return rpmfilesVerify(fi->files, fi->i, omitMask);
}
-rpmstrPool rpmfiPool(rpmfi fi)
+rpmstrPool rpmfilesPool(rpmfiles fi)
{
return (fi != NULL) ? fi->pool : NULL;
}
+
+rpmfiles rpmfiFiles(rpmfi fi)
+{
+ return (fi != NULL) ? fi->files : NULL;
+}
+
+/******************************************************/
+/*** Archive handling *********************************/
+/******************************************************/
+
+rpmfi rpmfiNewArchiveReader(FD_t fd, rpmfiles files, int itype)
+{
+ rpmcpio_t archive = rpmcpioOpen(fd, O_RDONLY);
+ rpmfi fi = NULL;
+ if (archive && itype >= RPMFI_ITER_READ_ARCHIVE) {
+ fi = rpmfilesIter(files, itype);
+ }
+ if (fi) {
+ fi->archive = archive;
+ } else {
+ rpmcpioFree(archive);
+ }
+ return fi;
+}
+
+rpmfi rpmfiNewArchiveWriter(FD_t fd, rpmfiles files)
+{
+ rpmcpio_t archive = rpmcpioOpen(fd, O_WRONLY);
+ rpmfi fi = NULL;
+ if (archive) {
+ fi = rpmfilesIter(files, RPMFI_ITER_WRITE_ARCHIVE);
+ }
+ if (fi) {
+ fi->archive = archive;
+ } else {
+ rpmcpioFree(archive);
+ }
+ return fi;
+}
+
+int rpmfiArchiveClose(rpmfi fi)
+{
+ if (fi == NULL)
+ return -1;
+ int rc = rpmcpioClose(fi->archive);
+ return rc;
+}
+
+rpm_loff_t rpmfiArchiveTell(rpmfi fi)
+{
+ if (fi == NULL || fi->archive == NULL)
+ return 0;
+ return (rpm_loff_t) rpmcpioTell(fi->archive);
+}
+
+static int rpmfiArchiveWriteHeader(rpmfi fi)
+{
+ int rc;
+ struct stat st;
+
+ if (rpmfiStat(fi, 0, &st))
+ return -1;
+
+ rpmfiles files = fi->files;
+
+ if (files->lfsizes) {
+ return rpmcpioStrippedHeaderWrite(fi->archive, rpmfiFX(fi), st.st_size);
+ } else {
+ const char * dn = rpmfiDN(fi);
+ char * path = rstrscat(NULL, (dn[0] == '/' && !rpmExpandNumeric("%{_noPayloadPrefix}")) ? "." : "",
+ dn, rpmfiBN(fi), NULL);
+ rc = rpmcpioHeaderWrite(fi->archive, path, &st);
+ free(path);
+ }
+
+ return rc;
+}
+
+static int iterWriteArchiveNextFile(rpmfi fi)
+{
+ rpmfiles files = rpmfiFiles(fi);
+ int fx = rpmfiFX(fi);
+ int fc = rpmfiFC(fi);
+ const int * hardlinks;
+ int numHardlinks = 0;
+
+ /* already processing hard linked files */
+ if (rpmfiFNlink(fi) > 1) {
+ /* search next hard linked file */
+ fi->i = -1;
+ for (int i=fx+1; i<fc; i++) {
+ /* no ghosts */
+ if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
+ continue;
+ numHardlinks = rpmfilesFLinks(files, i, &hardlinks);
+ if (numHardlinks > 1 && hardlinks[0] == i) {
+ rpmfiSetFX(fi, i);
+ break;
+ }
+ }
+ } else {
+ fi->i = -1;
+ /* search next non hardlinked file */
+ for (int i=fx+1; i<fc; i++) {
+ /* no ghosts */
+ if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
+ continue;
+ if (rpmfilesFNlink(files, i) < 2) {
+ rpmfiSetFX(fi, i);
+ break;
+ }
+ }
+ if (rpmfiFX(fi) == -1) {
+ /* continue with first hard linked file */
+ for (int i=0; i<fc; i++) {
+ /* no ghosts */
+ if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
+ continue;
+ numHardlinks = rpmfilesFLinks(files, i, &hardlinks);
+ if (numHardlinks > 1) {
+ rpmfiSetFX(fi, i);
+ break;
+ }
+ }
+ }
+ }
+ if (rpmfiFX(fi) == -1)
+ return -1;
+
+ /* write header(s) */
+ if (numHardlinks>1) {
+ for (int i=0; i<numHardlinks; i++) {
+ rpmfiSetFX(fi, hardlinks[i]);
+ int rc = rpmfiArchiveWriteHeader(fi);
+ if (rc) {
+ return rc;
+ }
+ }
+ rpmfiSetFX(fi, hardlinks[0]);
+ } else {
+ int rc = rpmfiArchiveWriteHeader(fi);
+ if (rc) {
+ return rc;
+ }
+ }
+ return rpmfiFX(fi);
+}
+
+static int iterWriteArchiveNext(rpmfi fi)
+{
+ int fx;
+ /* loop over the files we can handle ourself */
+ do {
+ fx = iterWriteArchiveNextFile(fi);
+ if (S_ISLNK(rpmfiFMode(fi))) {
+ /* write symlink target */
+ const char *lnk = rpmfiFLink(fi);
+ size_t len = strlen(lnk);
+ if (rpmfiArchiveWrite(fi, lnk, len) != len) {
+ return RPMERR_WRITE_FAILED;
+ }
+ } else if (S_ISREG(rpmfiFMode(fi)) && rpmfiFSize(fi)) {
+ /* this file actually needs some content */
+ return fx;
+ }
+ /* go on for special files, directories and empty files */
+ } while (fx >= 0);
+ return fx;
+}
+
+size_t rpmfiArchiveWrite(rpmfi fi, const void * buf, size_t size)
+{
+ if (fi == NULL || fi->archive == NULL)
+ return -1;
+ return rpmcpioWrite(fi->archive, buf, size);
+}
+
+int rpmfiArchiveWriteFile(rpmfi fi, FD_t fd)
+{
+ rpm_loff_t left;
+ int rc = 0;
+ size_t len;
+ char buf[BUFSIZ*4];
+
+ if (fi == NULL || fi->archive == NULL || fd == NULL)
+ return -1;
+
+ left = rpmfiFSize(fi);
+
+ while (left) {
+ len = (left > sizeof(buf) ? sizeof(buf) : left);
+ if (Fread(buf, sizeof(*buf), len, fd) != len || Ferror(fd)) {
+ rc = RPMERR_READ_FAILED;
+ break;
+ }
+
+ if (rpmcpioWrite(fi->archive, buf, len) != len) {
+ rc = RPMERR_WRITE_FAILED;
+ break;
+ }
+ left -= len;
+ }
+ return rc;
+}
+
+static void rpmfiSetFound(rpmfi fi, int ix)
+{
+ fi->found[ix >> 3] |= (1 << (ix % 8));
+}
+
+static int rpmfiFound(rpmfi fi, int ix)
+{
+ return fi->found[ix >> 3] & (1 << (ix % 8));
+}
+
+static int iterReadArchiveNext(rpmfi fi)
+{
+ int rc;
+ int fx = -1;
+ int fc = rpmfilesFC(fi->files);
+ char * path = NULL;
+
+ if (fi->archive == NULL)
+ return -1;
+
+ /* Read next payload header. */
+ rc = rpmcpioHeaderRead(fi->archive, &path, &fx);
+
+ /* if archive ended, check if we found all files */
+ if (rc == RPMERR_ITER_END) {
+ for (int i=0; i<fc; i++) {
+ if (!rpmfiFound(fi, i) &&
+ !(rpmfilesFFlags(fi->files, i) & RPMFILE_GHOST)) {
+ rc = RPMERR_MISSING_FILE;
+ break;
+ }
+ }
+ }
+ if (rc) {
+ return rc;
+ }
+
+ if (path) {
+ /* Regular cpio archive, identify mapping index. */
+ fx = rpmfilesFindOFN(fi->files, path);
+ free(path);
+ }
+
+ if (fx >= 0 && fx < fc) {
+ rpm_loff_t fsize = 0;
+ rpm_mode_t mode = rpmfilesFMode(fi->files, fx);
+
+ /* %ghost in payload, should not be there but rpm < 4.11 sometimes did this */
+ if (rpmfilesFFlags(fi->files, fx) & RPMFILE_GHOST)
+ return RPMERR_ITER_SKIP;
+
+ if (S_ISREG(mode)) {
+ const int * links;
+ uint32_t numlinks = rpmfilesFLinks(fi->files, fx, &links);
+ if (!(numlinks > 1 && links[numlinks-1] != fx))
+ fsize = rpmfilesFSize(fi->files, fx);
+ } else if (S_ISLNK(mode)) {
+ /* Skip over symlink target data in payload */
+ rpm_loff_t lsize = rpmfilesFSize(fi->files, fx);
+ char *buf = xmalloc(lsize + 1);
+ if (rpmcpioRead(fi->archive, buf, lsize) != lsize)
+ rc = RPMERR_READ_FAILED;
+ /* XXX should we validate the payload matches? */
+ free(buf);
+ }
+ rpmcpioSetExpectedFileSize(fi->archive, fsize);
+ rpmfiSetFound(fi, fx);
+ } else {
+ /* Mapping error */
+ rc = RPMERR_UNMAPPED_FILE;
+ }
+ return (rc != 0) ? rc : fx;
+}
+
+
+static int iterReadArchiveNextOmitHardlinks(rpmfi fi)
+{
+ int fx;
+ const int * links;
+ int nlink;
+ do {
+ fx = iterReadArchiveNext(fi);
+ nlink = rpmfilesFLinks(fi->files, fx, &links);
+ } while (fx>=0 && nlink>1 && links[nlink-1]!=fx);
+ return fx;
+}
+
+static int iterReadArchiveNextContentFirst(rpmfi fi)
+{
+ int fx = rpmfiFX(fi);
+ const int * links;
+ int nlink;
+ /* decide what to do on the basis of the last entry */
+ nlink = rpmfilesFLinks(fi->files, fx, &links);
+ if (nlink > 1) {
+ /* currently reading through hard links */
+ if (fx == links[nlink-1]) {
+ /* arrived back at last entry, read on */
+ fx = iterReadArchiveNext(fi);
+ } else {
+ /* next hard link */
+ /* scales poorly but shouldn't matter */
+ for (int i=0; i<nlink; i++) {
+ if (links[i] == fx) {
+ fx = links[i+1];
+ return fx;
+ }
+ }
+ /* should never happen */
+ return -1;
+ }
+ } else {
+ fx = iterReadArchiveNext(fi);
+ }
+
+ /* look at the new entry */
+ nlink = rpmfilesFLinks(fi->files, fx, &links);
+ /* arrived at new set of hardlinks? */
+ if (nlink > 1) {
+ /* read over all entries to the last one (containing the content) */
+ do {
+ fx = iterReadArchiveNext(fi);
+ } while (fx >=0 && fx != links[nlink-1]);
+ /* rewind to the first entry */
+ if (fx >= 0) {
+ fx = links[0];
+ }
+ }
+ return fx;
+}
+
+int rpmfiArchiveHasContent(rpmfi fi)
+{
+ int res = 0;
+ if (fi && S_ISREG(rpmfiFMode(fi))) {
+ const int * links;
+ int nlink = rpmfiFLinks(fi, &links);
+ if (nlink > 1) {
+ if (fi->next == iterReadArchiveNext ||
+ fi->next == iterReadArchiveNextOmitHardlinks) {
+ res = rpmfiFX(fi) == links[nlink-1];
+ } else if (fi->next == iterReadArchiveNextContentFirst) {
+ res = rpmfiFX(fi) == links[0];
+ }
+ } else {
+ res = 1;
+ }
+ }
+ return res;
+}
+
+size_t rpmfiArchiveRead(rpmfi fi, void * buf, size_t size)
+{
+ if (fi == NULL || fi->archive == NULL)
+ return -1;
+ return rpmcpioRead(fi->archive, buf, size);
+}
+
+int rpmfiArchiveReadToFilePsm(rpmfi fi, FD_t fd, int nodigest, rpmpsm psm)
+{
+ if (fi == NULL || fi->archive == NULL || fd == NULL)
+ return -1;
+
+ rpm_loff_t left = rpmfiFSize(fi);
+ const unsigned char * fidigest = NULL;
+ pgpHashAlgo digestalgo = 0;
+ int rc = 0;
+ char buf[BUFSIZ*4];
+
+ if (!nodigest) {
+ digestalgo = rpmfiDigestAlgo(fi);
+ fidigest = rpmfilesFDigest(fi->files, rpmfiFX(fi), NULL, NULL);
+ fdInitDigest(fd, digestalgo, 0);
+ }
+
+ while (left) {
+ size_t len;
+ len = (left > sizeof(buf) ? sizeof(buf) : left);
+ if (rpmcpioRead(fi->archive, buf, len) != len) {
+ rc = RPMERR_READ_FAILED;
+ goto exit;
+ }
+ if ((Fwrite(buf, sizeof(*buf), len, fd) != len) || Ferror(fd)) {
+ rc = RPMERR_WRITE_FAILED;
+ goto exit;
+ }
+
+ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
+ left -= len;
+ }
+
+ if (!nodigest) {
+ void * digest = NULL;
+
+ (void) Fflush(fd);
+ fdFiniDigest(fd, digestalgo, &digest, NULL, 0);
+
+ if (digest != NULL && fidigest != NULL) {
+ size_t diglen = rpmDigestLength(digestalgo);
+ if (memcmp(digest, fidigest, diglen)) {
+ rc = RPMERR_DIGEST_MISMATCH;
+
+ /* ...but in old packages, empty files have zeros for digest */
+ if (rpmfiFSize(fi) == 0 && digestalgo == PGPHASHALGO_MD5) {
+ uint8_t zeros[diglen];
+ memset(&zeros, 0, diglen);
+ if (memcmp(zeros, fidigest, diglen) == 0)
+ rc = 0;
+ }
+ }
+ } else {
+ rc = RPMERR_DIGEST_MISMATCH;
+ }
+ free(digest);
+ }
+
+exit:
+ return rc;
+}
+
+int rpmfiArchiveReadToFile(rpmfi fi, FD_t fd, int nodigest)
+{
+ return rpmfiArchiveReadToFilePsm(fi, fd, nodigest, NULL);
+}
+
+char * rpmfileStrerror(int rc)
+{
+ char *msg = NULL;
+ const char *s = NULL;
+ const char *prefix = "cpio";
+ int myerrno = errno;
+
+ switch (rc) {
+ default:
+ break;
+ case RPMERR_BAD_MAGIC: s = _("Bad magic"); break;
+ case RPMERR_BAD_HEADER: s = _("Bad/unreadable header");break;
+
+ case RPMERR_OPEN_FAILED: s = "open"; break;
+ case RPMERR_CHMOD_FAILED: s = "chmod"; break;
+ case RPMERR_CHOWN_FAILED: s = "chown"; break;
+ case RPMERR_WRITE_FAILED: s = "write"; break;
+ case RPMERR_UTIME_FAILED: s = "utime"; break;
+ case RPMERR_UNLINK_FAILED: s = "unlink"; break;
+ case RPMERR_RENAME_FAILED: s = "rename"; break;
+ case RPMERR_SYMLINK_FAILED: s = "symlink"; break;
+ case RPMERR_STAT_FAILED: s = "stat"; break;
+ case RPMERR_LSTAT_FAILED: s = "lstat"; break;
+ case RPMERR_MKDIR_FAILED: s = "mkdir"; break;
+ case RPMERR_RMDIR_FAILED: s = "rmdir"; break;
+ case RPMERR_MKNOD_FAILED: s = "mknod"; break;
+ case RPMERR_MKFIFO_FAILED: s = "mkfifo"; break;
+ case RPMERR_LINK_FAILED: s = "link"; break;
+ case RPMERR_READLINK_FAILED: s = "readlink"; break;
+ case RPMERR_READ_FAILED: s = "read"; break;
+ case RPMERR_COPY_FAILED: s = "copy"; break;
+ case RPMERR_LSETFCON_FAILED: s = "lsetfilecon"; break;
+ case RPMERR_SETCAP_FAILED: s = "cap_set_file"; break;
+
+ case RPMERR_HDR_SIZE: s = _("Header size too big"); break;
+ case RPMERR_FILE_SIZE: s = _("File too large for archive"); break;
+ case RPMERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
+ case RPMERR_MISSING_FILE: s = _("Missing file(s)"); break;
+ case RPMERR_DIGEST_MISMATCH: s = _("Digest mismatch"); break;
+ case RPMERR_INTERNAL: s = _("Internal error"); break;
+ case RPMERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
+ case RPMERR_ENOENT: s = strerror(ENOENT); break;
+ case RPMERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break;
+ case RPMERR_EXIST_AS_DIR:
+ s = _("File from package already exists as a directory in system");
+ break;
+ }
+
+ if (s != NULL) {
+ rasprintf(&msg, "%s: %s", prefix, s);
+ if ((rc <= RPMERR_CHECK_ERRNO) && myerrno) {
+ rstrscat(&msg, _(" failed - "), strerror(myerrno), NULL);
+ }
+ } else {
+ rasprintf(&msg, _("%s: (error 0x%x)"), prefix, rc);
+ }
+
+ return msg;
+}
diff --git a/lib/rpmfi.h b/lib/rpmfi.h
index b77c82895..cb22acae7 100644
--- a/lib/rpmfi.h
+++ b/lib/rpmfi.h
@@ -1,289 +1,248 @@
#ifndef H_RPMFI
#define H_RPMFI
-/** \ingroup rpmdep rpmtrans
+/** \ingroup rpmfi
* \file lib/rpmfi.h
- * Structure(s) used for file info tag sets.
+ * File info set iterator API.
*/
#include <rpm/rpmtypes.h>
-#include <rpm/rpmvf.h>
-#include <rpm/rpmpgp.h>
+#include <rpm/rpmfiles.h>
+#include <rpm/rpmarchive.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \ingroup rpmfi
- * File types.
- * These are the file types used internally by rpm. The file
- * type is determined by applying stat(2) macros like S_ISDIR to
- * the file mode tag from a header. The values are arbitrary,
- * but are identical to the linux stat(2) file types.
- */
-typedef enum rpmFileTypes_e {
- PIPE = 1, /*!< pipe/fifo */
- CDEV = 2, /*!< character device */
- XDIR = 4, /*!< directory */
- BDEV = 6, /*!< block device */
- REG = 8, /*!< regular file */
- LINK = 10, /*!< hard link */
- SOCK = 12 /*!< socket */
-} rpmFileTypes;
-
-/**
- * File States (when installed).
- */
-typedef enum rpmfileState_e {
- RPMFILE_STATE_MISSING = -1, /* used for unavailable data */
- RPMFILE_STATE_NORMAL = 0,
- RPMFILE_STATE_REPLACED = 1,
- RPMFILE_STATE_NOTINSTALLED = 2,
- RPMFILE_STATE_NETSHARED = 3,
- RPMFILE_STATE_WRONGCOLOR = 4
-} rpmfileState;
-
-#define RPMFILE_IS_INSTALLED(_x) ((_x) == RPMFILE_STATE_NORMAL || (_x) == RPMFILE_STATE_NETSHARED)
-
-/**
- * Exported File Attributes (ie RPMTAG_FILEFLAGS)
- */
-enum rpmfileAttrs_e {
- RPMFILE_NONE = 0,
- RPMFILE_CONFIG = (1 << 0), /*!< from %%config */
- RPMFILE_DOC = (1 << 1), /*!< from %%doc */
- RPMFILE_ICON = (1 << 2), /*!< from %%donotuse. */
- RPMFILE_MISSINGOK = (1 << 3), /*!< from %%config(missingok) */
- RPMFILE_NOREPLACE = (1 << 4), /*!< from %%config(noreplace) */
- RPMFILE_SPECFILE = (1 << 5), /*!< @todo (unnecessary) marks 1st file in srpm. */
- RPMFILE_GHOST = (1 << 6), /*!< from %%ghost */
- RPMFILE_LICENSE = (1 << 7), /*!< from %%license */
- RPMFILE_README = (1 << 8), /*!< from %%readme */
- /* bits 9-10 unused */
- RPMFILE_PUBKEY = (1 << 11), /*!< from %%pubkey */
- RPMFILE_SECMANIFEST = (1 << 12), /*!< from %%manifest */
-};
-
-typedef rpmFlags rpmfileAttrs;
-
-#define RPMFILE_ALL ~(RPMFILE_NONE)
-
-/** \ingroup rpmfi
- * File disposition(s) during package install/erase transaction.
- */
-typedef enum rpmFileAction_e {
- FA_UNKNOWN = 0, /*!< initial action for file ... */
- FA_CREATE, /*!< ... copy in from payload. */
- FA_COPYIN, /*!< ... copy in from payload. */
- FA_COPYOUT, /*!< ... copy out to payload. */
- FA_BACKUP, /*!< ... renamed with ".rpmorig" extension. */
- FA_SAVE, /*!< ... renamed with ".rpmsave" extension. */
- FA_SKIP, /*!< ... already replaced, don't remove. */
- FA_ALTNAME, /*!< ... create with ".rpmnew" extension. */
- FA_ERASE, /*!< ... to be removed. */
- FA_SKIPNSTATE, /*!< ... untouched, state "not installed". */
- FA_SKIPNETSHARED, /*!< ... untouched, state "netshared". */
- FA_SKIPCOLOR /*!< ... untouched, state "wrong color". */
-} rpmFileAction;
-
-#define XFA_SKIPPING(_a) \
- ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR)
-
-/**
- * We pass these around as an array with a sentinel.
- */
-struct rpmRelocation_s {
- char * oldPath; /*!< NULL here evals to RPMTAG_DEFAULTPREFIX, */
- char * newPath; /*!< NULL means to omit the file completely! */
-};
-
-/** \ingroup rpmfi
- * Reference a file info set instance.
- * @param fi file info set
- * @return new file info set reference
+
+ * Reference a file info set iterator instance.
+ * @param fi file info set iterator
+ * @return new file info set iterator reference
*/
rpmfi rpmfiLink (rpmfi fi);
/** \ingroup rpmfi
- * Return file count from file info set.
- * @param fi file info set
+ * Return file count from file info set iterator.
+ * @param fi file info set iterator
* @return current file count
*/
rpm_count_t rpmfiFC(rpmfi fi);
/** \ingroup rpmfi
- * Return current file index from file info set.
- * @param fi file info set
+ * Return current file index from file info set iterator.
+ * @param fi file info set iterator
* @return current file index
*/
int rpmfiFX(rpmfi fi);
/** \ingroup rpmfi
- * Set current file index in file info set.
- * @param fi file info set
+ * Set current file index in file info set iterator.
+ * @param fi file info set iterator
* @param fx new file index
* @return current file index
*/
int rpmfiSetFX(rpmfi fi, int fx);
/** \ingroup rpmfi
- * Return directory count from file info set.
- * @param fi file info set
+ * Return directory count from file info set iterator.
+ * @param fi file info set iterator
* @return current directory count
*/
rpm_count_t rpmfiDC(rpmfi fi);
/** \ingroup rpmfi
- * Return current directory index from file info set.
- * @param fi file info set
+ * Return current directory index from file info set iterator.
+ * @param fi file info set iterator
* @return current directory index
*/
int rpmfiDX(rpmfi fi);
/** \ingroup rpmfi
- * Set current directory index in file info set.
- * @param fi file info set
+ * Set current directory index in file info set iterator.
+ * @param fi file info set iterator
* @param dx new directory index
* @return current directory index
*/
int rpmfiSetDX(rpmfi fi, int dx);
/** \ingroup rpmfi
- * Return current base name from file info set.
- * @param fi file info set
+ * Return current base name from file info set iterator.
+ * @param fi file info set iterator
* @return current base name, NULL on invalid
*/
const char * rpmfiBN(rpmfi fi);
/** \ingroup rpmfi
- * Return current directory name from file info set.
- * @param fi file info set
+ * Return current directory name from file info set iterator.
+ * @param fi file info set iterator
* @return current directory, NULL on invalid
*/
const char * rpmfiDN(rpmfi fi);
/** \ingroup rpmfi
- * Return current file name from file info set.
- * @param fi file info set
+ * Return current file name from file info set iterator.
+ * @param fi file info set iterator
* @return current file name
*/
const char * rpmfiFN(rpmfi fi);
/** \ingroup rpmfi
- * Return current file flags from file info set.
- * @param fi file info set
+ * Return file index of the given file name or -1 if file is not in the rpmfi.
+ * The file name may have "." prefixed but is then interpreted as a global
+ * path without the prefixing "."
+ * @param fi file info set iterator
+ * @param fn file name
+ * @return file index or -1
+ */
+int rpmfiFindFN(rpmfi fi, const char * fn);
+
+/** \ingroup rpmfi
+ * Return current original base name from file info set iterator.
+ * @param fi file info set iterator
+ * @return current base name, NULL on invalid
+ */
+const char * rpmfiOBN(rpmfi fi);
+
+/** \ingroup rpmfi
+ * Return current original directory name from file info set iterator.
+ * @param fi file info set iterator
+ * @return current directory, NULL on invalid
+ */
+const char * rpmfiODN(rpmfi fi);
+
+/** \ingroup rpmfi
+ * Return current original file name from file info set iterator.
+ * @param fi file info set iterator
+ * @return current file name
+ */
+const char * rpmfiOFN(rpmfi fi);
+
+/** \ingroup rpmfi
+ * Return file index of the given original file name or -1 if file is not
+ * in the rpmfi. The file name may have "." prefixed but is then interpreted
+ * as a global path without the prefixing "."
+ * @param fi file info set iterator
+ * @param fn file name
+ * @return file index or -1
+ */
+int rpmfiFindOFN(rpmfi fi, const char * fn);
+
+/** \ingroup rpmfi
+ * Return current file flags from file info set iterator.
+ * @param fi file info set iterator
* @return current file flags, 0 on invalid
*/
rpmfileAttrs rpmfiFFlags(rpmfi fi);
/** \ingroup rpmfi
- * Return current file verify flags from file info set.
- * @param fi file info set
+ * Return current file verify flags from file info set iterator.
+ * @param fi file info set iterator
* @return current file verify flags, 0 on invalid
*/
rpmVerifyAttrs rpmfiVFlags(rpmfi fi);
/** \ingroup rpmfi
- * Return current file mode from file info set.
- * @param fi file info set
+ * Return current file mode from file info set iterator.
+ * @param fi file info set iterator
* @return current file mode, 0 on invalid
*/
rpm_mode_t rpmfiFMode(rpmfi fi);
/** \ingroup rpmfi
- * Return current file state from file info set.
- * @param fi file info set
+ * Return current file state from file info set iterator.
+ * @param fi file info set iterator
* @return current file state, 0 on invalid
*/
rpmfileState rpmfiFState(rpmfi fi);
/** \ingroup rpmfi
- * Return digest algorithm of a file info set.
- * @param fi file info set
- * @return digest algorithm of file info set, 0 on invalid
+ * Return digest algorithm of a file info set iterator.
+ * @param fi file info set iterator
+ * @return digest algorithm of file info set iterator, 0 on invalid
*/
int rpmfiDigestAlgo(rpmfi fi);
/** \ingroup rpmfi
- * Return current file (binary) digest of file info set.
- * @param fi file info set
- * @retval algo digest hash algoritm used (pass NULL to ignore)
+ * Return current file (binary) digest of file info set iterator.
+ * @param fi file info set iterator
+ * @retval algo digest hash algorithm used (pass NULL to ignore)
* @retval diglen digest hash length (pass NULL to ignore)
* @return current file digest, NULL on invalid
*/
const unsigned char * rpmfiFDigest(rpmfi fi, int *algo, size_t *diglen);
/** \ingroup rpmfi
- * Return current file (hex) digest of file info set.
- * The file info set stores file digests in binary format to conserve
+ * Return current file (hex) digest of file info set iterator.
+ * The file info set iterator stores file digests in binary format to conserve
* memory, this converts the binary data back to hex presentation used in
* headers.
- * @param fi file info set
- * @retval algo digest hash algoritm used (pass NULL to ignore)
+ * @param fi file info set iterator
+ * @retval algo digest hash algorithm used (pass NULL to ignore)
* @return current file digest (malloc'ed), NULL on invalid
*/
char * rpmfiFDigestHex(rpmfi fi, int *algo);
/** \ingroup rpmfi
- * Return current file (binary) md5 digest from file info set.
- * @deprecated Use rpmfiFDigest() instead
- * @param fi file info set
- * @return current file md5 digest, NULL on invalid
+ * Return current file (binary) signature of file info set iterator.
+ * @param fi file info set iterator
+ * @retval siglen signature length (pass NULL to ignore)
+ * @return current file signature, NULL on invalid
*/
-const unsigned char * rpmfiMD5(rpmfi fi) RPM_GNUC_DEPRECATED;
+const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen);
/** \ingroup rpmfi
- * Return current file linkto (i.e. symlink(2) target) from file info set.
- * @param fi file info set
+ * Return current file linkto (i.e. symlink(2) target) from file info set iterator.
+ * @param fi file info set iterator
* @return current file linkto, NULL on invalid
*/
const char * rpmfiFLink(rpmfi fi);
/** \ingroup rpmfi
- * Return current file size from file info set.
- * @param fi file info set
+ * Return current file size from file info set iterator.
+ * @param fi file info set iterator
* @return current file size, 0 on invalid
*/
rpm_loff_t rpmfiFSize(rpmfi fi);
/** \ingroup rpmfi
- * Return current file rdev from file info set.
- * @param fi file info set
+ * Return current file rdev from file info set iterator.
+ * @param fi file info set iterator
* @return current file rdev, 0 on invalid
*/
rpm_rdev_t rpmfiFRdev(rpmfi fi);
/** \ingroup rpmfi
- * Return current file inode from file info set.
- * @param fi file info set
+ * Return current file inode from file info set iterator.
+ * @param fi file info set iterator
* @return current file inode, 0 on invalid
*/
rpm_ino_t rpmfiFInode(rpmfi fi);
/** \ingroup rpmfi
- * Return union of all file color bits from file info set.
- * @param fi file info set
+ * Return union of all file color bits from file info set iterator.
+ * @param fi file info set iterator
* @return current color
*/
rpm_color_t rpmfiColor(rpmfi fi);
/** \ingroup rpmfi
- * Return current file color bits from file info set.
- * @param fi file info set
+ * Return current file color bits from file info set iterator.
+ * @param fi file info set iterator
* @return current file color
*/
rpm_color_t rpmfiFColor(rpmfi fi);
/** \ingroup rpmfi
- * Return current file class from file info set.
- * @param fi file info set
+ * Return current file class from file info set iterator.
+ * @param fi file info set iterator
* @return current file class, 0 on invalid
*/
const char * rpmfiFClass(rpmfi fi);
/** \ingroup rpmfi
- * Return current file depends dictionary from file info set.
- * @param fi file info set
+ * Return current file depends dictionary from file info set iterator.
+ * @param fi file info set iterator
* @retval *fddictp file depends dictionary array (or NULL)
* @return no. of file depends entries, 0 on invalid
*/
@@ -291,133 +250,121 @@ uint32_t rpmfiFDepends(rpmfi fi,
const uint32_t ** fddictp);
/** \ingroup rpmfi
- * Return (calculated) current file nlink count from file info set.
- * @param fi file info set
+ * Return (calculated) current file nlink count from file info set iterator.
+ * @param fi file info set iterator
* @return current file nlink count, 0 on invalid
*/
uint32_t rpmfiFNlink(rpmfi fi);
+
+/** \ingroup rpmfi
+ * Return (calculated) current file nlink count from file info set iterator.
+ * @param fi file info set iterator
+ * @param files returns array of file ids hardlinked including ix,
+ NULL for nlink count == 1
+ * @return current file nlink count, 0 on invalid
+ */
+uint32_t rpmfiFLinks(rpmfi fi, const int ** files);
+
/** \ingroup rpmfi
- * Return current file modify time from file info set.
- * @param fi file info set
+ * Return current file modify time from file info set iterator.
+ * @param fi file info set iterator
* @return current file modify time, 0 on invalid
*/
rpm_time_t rpmfiFMtime(rpmfi fi);
/** \ingroup rpmfi
- * Return current file owner from file info set.
- * @param fi file info set
+ * Return current file owner from file info set iterator.
+ * @param fi file info set iterator
* @return current file owner, NULL on invalid
*/
const char * rpmfiFUser(rpmfi fi);
/** \ingroup rpmfi
- * Return current file group from file info set.
- * @param fi file info set
+ * Return current file group from file info set iterator.
+ * @param fi file info set iterator
* @return current file group, NULL on invalid
*/
const char * rpmfiFGroup(rpmfi fi);
/** \ingroup rpmfi
* Return textual representation of current file capabilities
- * from file info set. See cap_from_text(3) for details.
- * @param fi file info set
+ * from file info set iterator. See cap_from_text(3) for details.
+ * @param fi file info set iterator
* @return file capability description, "" for no capabilities
* and NULL on invalid
*/
const char * rpmfiFCaps(rpmfi fi);
/** \ingroup rpmfi
- * Return current file language(s) from file info set.
- * @param fi file info set
+ * Return current file language(s) from file info set iterator.
+ * @param fi file info set iterator
* @return current file language(s), NULL on invalid
*/
const char * rpmfiFLangs(rpmfi fi);
/** \ingroup rpmfi
+ * Map file stat(2) info.
+ * @param fi file info iterator
+ * @param flags flags
+ * @retval sb mapped stat(2) data
+ */
+int rpmfiStat(rpmfi fi, int flags, struct stat *sb);
+
+/** \ingroup rpmfi
* Return next file iterator index.
- * @param fi file info set
+ * @param fi file info set iterator
* @return file iterator index, -1 on termination
*/
int rpmfiNext(rpmfi fi);
/** \ingroup rpmfi
* Initialize file iterator index.
- * @param fi file info set
+ * @param fi file info set iterator
* @param fx file iterator index
- * @return file info set
+ * @return file info set iterator
*/
rpmfi rpmfiInit(rpmfi fi, int fx);
/** \ingroup rpmfi
* Return next directory iterator index.
- * @param fi file info set
+ * @param fi file info set iterator
* @return directory iterator index, -1 on termination
*/
int rpmfiNextD(rpmfi fi);
/** \ingroup rpmfi
* Initialize directory iterator index.
- * @param fi file info set
+ * @param fi file info set iterator
* @param dx directory iterator index
- * @return file info set, NULL if dx is out of range
+ * @return file info set iterator, NULL if dx is out of range
*/
rpmfi rpmfiInitD(rpmfi fi, int dx);
/** \ingroup rpmfi
- * Destroy a file info set.
- * @param fi file info set
+ * Destroy a file info set iterator.
+ * @param fi file info set iterator
* @return NULL always
*/
rpmfi rpmfiFree(rpmfi fi);
-enum rpmfiFlags_e {
- RPMFI_NOHEADER = 0,
- RPMFI_KEEPHEADER = (1 << 0),
- RPMFI_NOFILECLASS = (1 << 1),
- RPMFI_NOFILEDEPS = (1 << 2),
- RPMFI_NOFILELANGS = (1 << 3),
- RPMFI_NOFILEUSER = (1 << 4),
- RPMFI_NOFILEGROUP = (1 << 5),
- RPMFI_NOFILEMODES = (1 << 6),
- RPMFI_NOFILESIZES = (1 << 7),
- RPMFI_NOFILECAPS = (1 << 8),
- RPMFI_NOFILELINKTOS = (1 << 9),
- RPMFI_NOFILEDIGESTS = (1 << 10),
- RPMFI_NOFILEMTIMES = (1 << 11),
- RPMFI_NOFILERDEVS = (1 << 12),
- RPMFI_NOFILEINODES = (1 << 13),
- RPMFI_NOFILESTATES = (1 << 14),
- RPMFI_NOFILECOLORS = (1 << 15),
- RPMFI_NOFILEVERIFYFLAGS = (1 << 16),
- RPMFI_NOFILEFLAGS = (1 << 17),
-};
-
-typedef rpmFlags rpmfiFlags;
-
-#define RPMFI_FLAGS_ERASE \
- (RPMFI_NOFILECLASS | RPMFI_NOFILELANGS | \
- RPMFI_NOFILEMTIMES | RPMFI_NOFILERDEVS | RPMFI_NOFILEINODES | \
- RPMFI_NOFILEVERIFYFLAGS)
-
-#define RPMFI_FLAGS_INSTALL \
- (RPMFI_NOFILECLASS | RPMFI_NOFILEVERIFYFLAGS)
-
-#define RPMFI_FLAGS_VERIFY \
- (RPMFI_NOFILECLASS | RPMFI_NOFILEDEPS | RPMFI_NOFILELANGS | \
- RPMFI_NOFILECOLORS)
-
-#define RPMFI_FLAGS_QUERY \
- (RPMFI_NOFILECLASS | RPMFI_NOFILEDEPS | RPMFI_NOFILELANGS | \
- RPMFI_NOFILECOLORS | RPMFI_NOFILEVERIFYFLAGS)
-
-/** \ingroup rpmfi
- * Create and load a file info set.
+/** \ingroup rpmfi
+ * Create and load a file info set iterator.
+ * @param pool shared string pool (or NULL for private pool)
+ * @param h header
+ * @param tagN unused
+ * @param flags Flags to control what information is loaded.
+ * @return new file info set iterator
+ */
+rpmfi rpmfiNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags);
+
+/** \ingroup rpmfi
+ * Create and load a file info set iterator.
* @param ts unused
* @param h header
* @param tagN unused
* @param flags Flags to control what information is loaded.
- * @return new file info set
+ * @return new file info set iterator
*/
rpmfi rpmfiNew(const rpmts ts, Header h, rpmTagVal tagN, rpmfiFlags flags);
@@ -437,20 +384,12 @@ rpmFileTypes rpmfiWhatis(rpm_mode_t mode);
int rpmfiCompare(const rpmfi afi, const rpmfi bfi);
/** \ingroup rpmfi
- * Return file disposition.
- * @param ofi old file info
- * @param nfi new file info
- * @param skipMissing OK to skip missing files?
- * @return file dispostion
- */
-rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing);
-
-/** \ingroup rpmfi
- * Return whether file is conflicting config
- * @param fi file info
- * @return 1 if config file and file on disk conflicts
+ * Verify file attributes (including digest).
+ * @param fi file info iterator
+ * @param omitMask bit(s) to disable verify checks
+ * @return bit(s) to indicate failure (ie 0 for passed verify)
*/
-int rpmfiConfigConflict(const rpmfi fi);
+rpmVerifyAttrs rpmfiVerify(rpmfi fi, rpmVerifyAttrs omitMask);
#ifdef __cplusplus
}
diff --git a/lib/rpmfi_internal.h b/lib/rpmfi_internal.h
index 19484ec5a..dccc6ccbe 100644
--- a/lib/rpmfi_internal.h
+++ b/lib/rpmfi_internal.h
@@ -5,91 +5,21 @@
#include <rpm/rpmfi.h>
#include <rpm/rpmstrpool.h>
#include "lib/fprint.h"
+#include "lib/cpio.h"
#define RPMFIMAGIC 0x09697923
-/**
- * A package filename set.
- */
-struct rpmfi_s {
- int i; /*!< Current file index. */
- int j; /*!< Current directory index. */
-
- Header h; /*!< Header for file info set (or NULL) */
- rpmstrPool pool; /*!< String pool of this file info set */
-
- rpmsid * bnid; /*!< Index to base name(s) (pool) */
- rpmsid * dnid; /*!< Index to directory name(s) (pool) */
-
- rpmsid * flinks; /*!< Index to file link(s) (pool) */
-
- uint32_t * dil; /*!< Directory indice(s) (from header) */
- rpm_flag_t * fflags; /*!< File flag(s) (from header) */
- rpm_off_t * fsizes; /*!< File size(s) (from header) */
- rpm_time_t * fmtimes; /*!< File modification time(s) (from header) */
- rpm_mode_t * fmodes; /*!< File mode(s) (from header) */
- rpm_rdev_t * frdevs; /*!< File rdev(s) (from header) */
- rpm_ino_t * finodes; /*!< File inodes(s) (from header) */
-
- rpmsid * fuser; /*!< Index to file owner(s) (misc pool) */
- rpmsid * fgroup; /*!< Index to file group(s) (misc pool) */
- rpmsid * flangs; /*!< Index to file lang(s) (misc pool) */
-
- char * fstates; /*!< File state(s) (from header) */
-
- rpm_color_t * fcolors; /*!< File color bits (header) */
- char ** fcaps; /*!< File capability strings (header) */
-
- char ** cdict; /*!< File class dictionary (header) */
- rpm_count_t ncdict; /*!< No. of class entries. */
- uint32_t * fcdictx; /*!< File class dictionary index (header) */
-
- uint32_t * ddict; /*!< File depends dictionary (header) */
- rpm_count_t nddict; /*!< No. of depends entries. */
- uint32_t * fddictx; /*!< File depends dictionary start (header) */
- uint32_t * fddictn; /*!< File depends dictionary count (header) */
- rpm_flag_t * vflags; /*!< File verify flag(s) (from header) */
-
- rpm_count_t dc; /*!< No. of directories. */
- rpm_count_t fc; /*!< No. of files. */
-
- rpmfiFlags fiflags; /*!< file info set control flags */
-
- struct fingerPrint_s * fps; /*!< File fingerprint(s). */
-
- int digestalgo; /*!< File digest algorithm */
- unsigned char * digests; /*!< File digests in binary. */
-
- char * fn; /*!< File name buffer. */
-
- char ** apath;
- rpm_off_t * replacedSizes; /*!< (TR_ADDED) */
- int magic;
- int nrefs; /*!< Reference count. */
-};
-
#ifdef __cplusplus
extern "C" {
#endif
/** \ingroup rpmfi
- * Create and load a file info set.
- * @param pool shared string pool (or NULL for private pool)
- * @param h header
- * @param tagN unused
- * @param flags Flags to control what information is loaded.
- * @return new file info set
- */
-RPM_GNUC_INTERNAL
-rpmfi rpmfiNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags);
-
-/** \ingroup rpmfi
* Return file info set string pool handle
* @param fi file info
* @return string pool handle (weak reference)
*/
RPM_GNUC_INTERNAL
-rpmstrPool rpmfiPool(rpmfi fi);
+rpmstrPool rpmfilesPool(rpmfiles fi);
/** \ingroup rpmfi
* Return current base name pool id from file info set.
@@ -108,99 +38,75 @@ RPM_GNUC_INTERNAL
rpmsid rpmfiDNId(rpmfi fi);
RPM_GNUC_INTERNAL
-int rpmfiDIIndex(rpmfi fi, int dx);
-
-RPM_GNUC_INTERNAL
-rpmsid rpmfiBNIdIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-rpmsid rpmfiDNIdIndex(rpmfi fi, int jx);
-
-RPM_GNUC_INTERNAL
-const char * rpmfiBNIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-const char * rpmfiDNIndex(rpmfi fi, int jx);
-
-RPM_GNUC_INTERNAL
-char * rpmfiFNIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-rpmVerifyAttrs rpmfiVFlagsIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-rpmfileState rpmfiFStateIndex(rpmfi fi, int ix);
+rpmsid rpmfilesBNId(rpmfiles fi, int ix);
RPM_GNUC_INTERNAL
-const char * rpmfiFLinkIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-rpm_loff_t rpmfiFSizeIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-rpm_color_t rpmfiFColorIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-const char * rpmfiFClassIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-uint32_t rpmfiFDependsIndex(rpmfi fi, int ix, const uint32_t ** fddictp);
-
-RPM_GNUC_INTERNAL
-uint32_t rpmfiFNlinkIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-const char * rpmfiFLangsIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-rpmfileAttrs rpmfiFFlagsIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-rpm_mode_t rpmfiFModeIndex(rpmfi fi, int ix);
-
-RPM_GNUC_INTERNAL
-const unsigned char * rpmfiFDigestIndex(rpmfi fi, int ix, int *algo, size_t *len);
+rpmsid rpmfilesDNId(rpmfiles fi, int jx);
+/** \ingroup rpmfi
+ * Return current original base name pool id from file info set.
+ * @param fi file info set
+ * @return current base name id, 0 on invalid
+ */
RPM_GNUC_INTERNAL
-rpm_rdev_t rpmfiFRdevIndex(rpmfi fi, int ix);
+rpmsid rpmfiOBNId(rpmfi fi);
+/** \ingroup rpmfi
+ * Return current original directory name pool id from file info set.
+ * @param fi file info set
+ * @return current base name id, 0 on invalid
+ */
RPM_GNUC_INTERNAL
-rpm_ino_t rpmfiFInodeIndex(rpmfi fi, int ix);
+rpmsid rpmfiODNId(rpmfi fi);
RPM_GNUC_INTERNAL
-rpm_time_t rpmfiFMtimeIndex(rpmfi fi, int ix);
+rpmsid rpmfilesOBNId(rpmfiles fi, int ix);
RPM_GNUC_INTERNAL
-const char * rpmfiFUserIndex(rpmfi fi, int ix);
+rpmsid rpmfilesODNId(rpmfiles fi, int jx);
RPM_GNUC_INTERNAL
-const char * rpmfiFGroupIndex(rpmfi fi, int ix);
+struct fingerPrint_s *rpmfilesFps(rpmfiles fi);
+/** \ingroup rpmfi
+ * Check if the file in new package, in old package and on the disk have the same contents.
+ * @param new file info set
+ * @param new file index
+ * @param old file info set
+ * @param old file index
+ * @return 1 if the condition is satisfied, 0 otherwise
+ */
RPM_GNUC_INTERNAL
-const char * rpmfiFCapsIndex(rpmfi fi, int ix);
+int rpmfileContentsEqual(rpmfiles ofi, int oix, rpmfiles nfi, int nix);
-RPM_GNUC_INTERNAL
-struct fingerPrint_s *rpmfiFps(rpmfi fi);
RPM_GNUC_INTERNAL
-rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix,
+rpmFileAction rpmfilesDecideFate(rpmfiles ofi, int oix,
+ rpmfiles nfi, int nix,
int skipMissing);
RPM_GNUC_INTERNAL
-int rpmfiCompareIndex(rpmfi afi, int aix, rpmfi bfi, int bix);
+int rpmfilesConfigConflict(rpmfiles fi, int ix);
RPM_GNUC_INTERNAL
-int rpmfiConfigConflictIndex(rpmfi fi, int ix);
+void rpmfilesSetFReplacedSize(rpmfiles fi, int ix, rpm_loff_t newsize);
RPM_GNUC_INTERNAL
-void rpmfiSetFReplacedSizeIndex(rpmfi fi, int ix, rpm_loff_t newsize);
+rpm_loff_t rpmfilesFReplacedSize(rpmfiles fi, int ix);
RPM_GNUC_INTERNAL
-rpm_loff_t rpmfiFReplacedSizeIndex(rpmfi fi, int ix);
+void rpmfilesFpLookup(rpmfiles fi, fingerPrintCache fpc);
-RPM_GNUC_INTERNAL
-void rpmfiFpLookup(rpmfi fi, fingerPrintCache fpc);
+rpmfiles rpmfiFiles(rpmfi fi);
+/** \ingroup rpmfi
+ * Return file iterator through files starting with given prefix.
+ * @param fi file info set
+ * @param pfx prefix
+ * @return file iterator
+ */
+RPM_GNUC_INTERNAL
+rpmfi rpmfilesFindPrefix(rpmfiles fi, const char *pfx);
#ifdef __cplusplus
}
#endif
diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
new file mode 100644
index 000000000..4caef973b
--- /dev/null
+++ b/lib/rpmfiles.h
@@ -0,0 +1,519 @@
+#ifndef _RPMFILES_H
+#define _RPMFILES_H
+
+/** \ingroup rpmfilesles
+ * \file lib/rpmfiles.h
+ * File info set API.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmvf.h>
+#include <rpm/rpmpgp.h>
+
+/** \ingroup rpmfiles
+ * File types.
+ * These are the file types used internally by rpm. The file
+ * type is determined by applying stat(2) macros like S_ISDIR to
+ * the file mode tag from a header. The values are arbitrary,
+ * but are identical to the linux stat(2) file types.
+ */
+typedef enum rpmFileTypes_e {
+ PIPE = 1, /*!< pipe/fifo */
+ CDEV = 2, /*!< character device */
+ XDIR = 4, /*!< directory */
+ BDEV = 6, /*!< block device */
+ REG = 8, /*!< regular file */
+ LINK = 10, /*!< hard link */
+ SOCK = 12 /*!< socket */
+} rpmFileTypes;
+
+/**
+ * File States (when installed).
+ */
+typedef enum rpmfileState_e {
+ RPMFILE_STATE_MISSING = -1, /* used for unavailable data */
+ RPMFILE_STATE_NORMAL = 0,
+ RPMFILE_STATE_REPLACED = 1,
+ RPMFILE_STATE_NOTINSTALLED = 2,
+ RPMFILE_STATE_NETSHARED = 3,
+ RPMFILE_STATE_WRONGCOLOR = 4
+} rpmfileState;
+
+#define RPMFILE_IS_INSTALLED(_x) ((_x) == RPMFILE_STATE_NORMAL || (_x) == RPMFILE_STATE_NETSHARED)
+
+/**
+ * Exported File Attributes (ie RPMTAG_FILEFLAGS)
+ */
+enum rpmfileAttrs_e {
+ RPMFILE_NONE = 0,
+ RPMFILE_CONFIG = (1 << 0), /*!< from %%config */
+ RPMFILE_DOC = (1 << 1), /*!< from %%doc */
+ RPMFILE_ICON = (1 << 2), /*!< from %%donotuse. */
+ RPMFILE_MISSINGOK = (1 << 3), /*!< from %%config(missingok) */
+ RPMFILE_NOREPLACE = (1 << 4), /*!< from %%config(noreplace) */
+ RPMFILE_SPECFILE = (1 << 5), /*!< @todo (unnecessary) marks 1st file in srpm. */
+ RPMFILE_GHOST = (1 << 6), /*!< from %%ghost */
+ RPMFILE_LICENSE = (1 << 7), /*!< from %%license */
+ RPMFILE_README = (1 << 8), /*!< from %%readme */
+ /* bits 9-10 unused */
+ RPMFILE_PUBKEY = (1 << 11), /*!< from %%pubkey */
+ RPMFILE_ARTIFACT = (1 << 12), /*!< from %%artifact */
+ RPMFILE_SECMANIFEST = (1 << 13), /*!< from %%manifest */
+};
+
+typedef rpmFlags rpmfileAttrs;
+
+#define RPMFILE_ALL ~(RPMFILE_NONE)
+
+/** \ingroup rpmfiles
+ * File disposition(s) during package install/erase transaction.
+ */
+typedef enum rpmFileAction_e {
+ FA_UNKNOWN = 0, /*!< initial action for file ... */
+ FA_CREATE = 1, /*!< ... create from payload. */
+ FA_COPYIN = 2, /*!< obsolete, unused. */
+ FA_COPYOUT = 3, /*!< obsolete, unused. */
+ FA_BACKUP = 4, /*!< ... renamed with ".rpmorig" extension. */
+ FA_SAVE = 5, /*!< ... renamed with ".rpmsave" extension. */
+ FA_SKIP = 6, /*!< ... already replaced, don't remove. */
+ FA_ALTNAME = 7, /*!< ... create with ".rpmnew" extension. */
+ FA_ERASE = 8, /*!< ... to be removed. */
+ FA_SKIPNSTATE = 9, /*!< ... untouched, state "not installed". */
+ FA_SKIPNETSHARED = 10, /*!< ... untouched, state "netshared". */
+ FA_SKIPCOLOR = 11, /*!< ... untouched, state "wrong color". */
+ FA_TOUCH = 12, /*!< ... change metadata only. */
+ /* bits 16-31 reserved */
+} rpmFileAction;
+
+#define XFA_SKIPPING(_a) \
+ ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR)
+
+/**
+ * We pass these around as an array with a sentinel.
+ */
+struct rpmRelocation_s {
+ char * oldPath; /*!< NULL here evals to RPMTAG_DEFAULTPREFIX, */
+ char * newPath; /*!< NULL means to omit the file completely! */
+};
+
+enum rpmfiFlags_e {
+ RPMFI_NOHEADER = 0,
+ RPMFI_KEEPHEADER = (1 << 0),
+ RPMFI_NOFILECLASS = (1 << 1),
+ RPMFI_NOFILEDEPS = (1 << 2),
+ RPMFI_NOFILELANGS = (1 << 3),
+ RPMFI_NOFILEUSER = (1 << 4),
+ RPMFI_NOFILEGROUP = (1 << 5),
+ RPMFI_NOFILEMODES = (1 << 6),
+ RPMFI_NOFILESIZES = (1 << 7),
+ RPMFI_NOFILECAPS = (1 << 8),
+ RPMFI_NOFILELINKTOS = (1 << 9),
+ RPMFI_NOFILEDIGESTS = (1 << 10),
+ RPMFI_NOFILEMTIMES = (1 << 11),
+ RPMFI_NOFILERDEVS = (1 << 12),
+ RPMFI_NOFILEINODES = (1 << 13),
+ RPMFI_NOFILESTATES = (1 << 14),
+ RPMFI_NOFILECOLORS = (1 << 15),
+ RPMFI_NOFILEVERIFYFLAGS = (1 << 16),
+ RPMFI_NOFILEFLAGS = (1 << 17),
+ RPMFI_NOFILESIGNATURES = (1 << 18),
+};
+
+typedef rpmFlags rpmfiFlags;
+
+#define RPMFI_FLAGS_ERASE \
+ (RPMFI_NOFILECLASS | RPMFI_NOFILELANGS | \
+ RPMFI_NOFILEMTIMES | RPMFI_NOFILERDEVS | RPMFI_NOFILEINODES | \
+ RPMFI_NOFILEVERIFYFLAGS)
+
+#define RPMFI_FLAGS_INSTALL \
+ (RPMFI_NOFILECLASS | RPMFI_NOFILEVERIFYFLAGS)
+
+#define RPMFI_FLAGS_VERIFY \
+ (RPMFI_NOFILECLASS | RPMFI_NOFILEDEPS | RPMFI_NOFILELANGS | \
+ RPMFI_NOFILECOLORS)
+
+#define RPMFI_FLAGS_QUERY \
+ (RPMFI_NOFILECLASS | RPMFI_NOFILEDEPS | RPMFI_NOFILELANGS | \
+ RPMFI_NOFILECOLORS | RPMFI_NOFILEVERIFYFLAGS)
+
+#define RPMFI_FLAGS_FILETRIGGER \
+ (RPMFI_NOFILECLASS | RPMFI_NOFILEDEPS | RPMFI_NOFILELANGS | \
+ RPMFI_NOFILEUSER | RPMFI_NOFILEGROUP | RPMFI_NOFILEMODES | \
+ RPMFI_NOFILESIZES | RPMFI_NOFILECAPS | RPMFI_NOFILELINKTOS | \
+ RPMFI_NOFILEDIGESTS | RPMFI_NOFILEMTIMES | RPMFI_NOFILERDEVS | \
+ RPMFI_NOFILEINODES | RPMFI_NOFILECOLORS | \
+ RPMFI_NOFILEVERIFYFLAGS | RPMFI_NOFILEFLAGS)
+
+#define RPMFI_FLAGS_ONLY_FILENAMES \
+ (RPMFI_FLAGS_FILETRIGGER | RPMFI_NOFILESTATES)
+
+typedef enum rpmFileIter_e {
+ RPMFI_ITER_FWD = 0,
+ RPMFI_ITER_BACK = 1,
+ RPMFI_ITER_WRITE_ARCHIVE = 2,
+ RPMFI_ITER_READ_ARCHIVE = 3,
+ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST = 4,
+ RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS = 5,
+ RPMFI_ITER_INTERVAL = 6,
+} rpmFileIter;
+
+#define RPMFILEITERMAX 6
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \ingroup rpmfiles
+ * Create and load a file info set.
+ * @param pool shared string pool (or NULL for private pool)
+ * @param h header
+ * @param tagN unused
+ * @param flags Flags to control what information is loaded.
+ * @return new file info set
+ */
+rpmfiles rpmfilesNew(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags);
+
+/** \ingroup rpmfiles
+ * Reference a file info set instance.
+ * @param fi file info set
+ * @return new file info set reference
+ */
+rpmfiles rpmfilesLink(rpmfiles fi);
+
+/** \ingroup rpmfiles
+ * Destroy a file info set.
+ * @param fi file info set
+ * @return NULL always
+ */
+rpmfiles rpmfilesFree(rpmfiles fi);
+
+/** \ingroup rpmfiles
+ * Return file count from file info set.
+ * @param fi file info set
+ * @return file count
+ */
+rpm_count_t rpmfilesFC(rpmfiles fi);
+
+/** \ingroup rpmfiles
+ * Return directory count from file info set.
+ * @param fi file info set
+ * @return directory count
+ */
+rpm_count_t rpmfilesDC(rpmfiles fi);
+
+/** \ingroup rpmfiles
+ * Return file index of the given file name or -1 if file is not in the rpmfi.
+ * The file name may have "." prefixed but is then interpreted as a global
+ * path without the prefixing "."
+ * @param files file info set
+ * @param fn file name
+ * @return file index or -1
+ */
+int rpmfilesFindFN(rpmfiles files, const char * fn);
+
+/** \ingroup rpmfiles
+ * Return file index of the given original file name or -1 if file is not
+ * in the rpmfi. The file name may have "." prefixed but is then interpreted
+ * as a global path without the prefixing "."
+ * @param files file info set
+ * @param fn file name
+ * @return file index or -1
+ */
+int rpmfilesFindOFN(rpmfiles files, const char * fn);
+
+rpmfi rpmfilesIter(rpmfiles files, int itype);
+
+/** \ingroup rpmfiles
+ * Return digest algorithm of a file info set.
+ * @param fi file info set
+ * @return digest algorithm of file info set, 0 on invalid
+ */
+int rpmfilesDigestAlgo(rpmfiles fi);
+
+/** \ingroup rpmfiles
+ * Return union of all file color bits from file info set.
+ * @param files file info set
+ * @return color
+ */
+rpm_color_t rpmfilesColor(rpmfiles files);
+
+/** \ingroup rpmfiles
+ * Return file info comparison.
+ * @param afi 1st file info
+ * @param aix index of the 1st file
+ * @param bfi 2nd file info
+ * @param bix index of the 2nd file
+ * @return 0 if identical
+ */
+int rpmfilesCompare(rpmfiles afi, int aix, rpmfiles bfi, int bix);
+
+/** \ingroup rpmfiles
+ * Return base name from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return base name, NULL on invalid
+ */
+const char * rpmfilesBN(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return directory name from file info set. Note the index is on
+ * distinct directories within the file set, not a file index. The
+ * directory index associated with a given file index can be retrieved
+ * with rpmfilesDI(). Ie to constuct the full path of file index X
+ * you'd catenate the results of rpmfilesDN(f, rpmfilesDI(f, X)) and
+ * rpmfilesBN(f, X).
+ * @param fi file info set
+ * @param jx directory index
+ * @return directory, NULL on invalid
+ */
+const char * rpmfilesDN(rpmfiles fi, int jx);
+
+/** \ingroup rpmfiles
+ * Return directory index from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return directory index, -1 on invalid
+ */
+int rpmfilesDI(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file name from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file name (malloced)
+ */
+char * rpmfilesFN(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return original directory index from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return directory index, -1 on invalid
+ */
+int rpmfilesODI(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return original base name from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return base name, NULL on invalid
+ */
+const char * rpmfilesOBN(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return original directory name from file info set. Note the index is on
+ * distinct directories within the file set, not a file index. The
+ * directory index associated with a given file index can be retrieved
+ * with rpmfilesODI(). Ie to constuct the full path of file index X
+ * you'd catenate the results of rpmfilesODN(f, rpmfilesODI(f, X)) and
+ * rpmfilesOBN(f, X).
+ * @param fi file info set
+ * @param jx directory index
+ * @return directory, NULL on invalid
+ */
+const char * rpmfilesODN(rpmfiles fi, int jx);
+
+/** \ingroup rpmfiles
+ * Return original file name from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file name
+ */
+char * rpmfilesOFN(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file verify flags from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file verify flags, 0 on invalid
+ */
+rpmVerifyAttrs rpmfilesVFlags(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file state from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file state, 0 on invalid
+ */
+rpmfileState rpmfilesFState(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file linkto (i.e. symlink(2) target) from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file linkto, NULL on invalid
+ */
+const char * rpmfilesFLink(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file size from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file size, 0 on invalid
+ */
+rpm_loff_t rpmfilesFSize(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file color bits from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file color
+ */
+rpm_color_t rpmfilesFColor(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file class from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file class, 0 on invalid
+ */
+const char * rpmfilesFClass(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file depends dictionary from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @retval *fddictp file depends dictionary array (or NULL)
+ * @return no. of file depends entries, 0 on invalid
+ */
+uint32_t rpmfilesFDepends(rpmfiles fi, int ix, const uint32_t ** fddictp);
+
+/** \ingroup rpmfiles
+ * Return (calculated) file nlink count from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file nlink count, 0 on invalid
+ */
+uint32_t rpmfilesFNlink(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return (calculated) file nlink count from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @param files returns array of file ids hardlinked including ix,
+ NULL for nlink count == 1
+ * @return file nlink count, 0 on invalid
+ */
+uint32_t rpmfilesFLinks(rpmfiles fi, int ix, const int ** files);
+
+/** \ingroup rpmfiles
+ * Return file language(s) from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file language(s), NULL on invalid
+ */
+const char * rpmfilesFLangs(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file flags from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file flags, 0 on invalid
+ */
+rpmfileAttrs rpmfilesFFlags(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file mode from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file mode, 0 on invalid
+ */
+rpm_mode_t rpmfilesFMode(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file (binary) digest of file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @retval algo digest hash algorithm used (pass NULL to ignore)
+ * @retval len digest hash length (pass NULL to ignore)
+ * @return file digest, NULL on invalid
+ */
+const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *len);
+
+/** \ingroup rpmfiles
+ * Return file (binary) digest of file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @retval len signature length (pass NULL to ignore)
+ * @return file signature, NULL on invalid
+ */
+const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len);
+
+/** \ingroup rpmfiles
+ * Return file rdev from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file rdev, 0 on invalid
+ */
+rpm_rdev_t rpmfilesFRdev(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file inode from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file inode, 0 on invalid
+ */
+rpm_ino_t rpmfilesFInode(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file modify time from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file modify time, 0 on invalid
+ */
+rpm_time_t rpmfilesFMtime(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file owner from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file owner, NULL on invalid
+ */
+const char * rpmfilesFUser(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return file group from file info set.
+ * @param fi file info set
+ * @param ix file index
+ * @return file group, NULL on invalid
+ */
+const char * rpmfilesFGroup(rpmfiles fi, int ix);
+
+/** \ingroup rpmfiles
+ * Return textual representation of file capabilities
+ * from file info set. See cap_from_text(3) for details.
+ * @param fi file info set
+ * @param ix file index
+ * @return file capability description, "" for no capabilities
+ * and NULL on invalid
+ */
+const char * rpmfilesFCaps(rpmfiles fi, int ix);
+
+/** \ingroup rpmfi
+ * Map file stat(2) info.
+ * @param fi file info set
+ * @param ix file index
+ * @param flags flags
+ * @retval sb mapped stat(2) data
+ * @return 0 on success
+ */
+int rpmfilesStat(rpmfiles fi, int ix, int flags, struct stat *sb);
+
+/** \ingroup rpmfiles
+ * Verify file attributes (including digest).
+ * @param fi file info set
+ * @param ix file index
+ * @param omitMask bit(s) to disable verify checks
+ * @return bit(s) to indicate failure (ie 0 for passed verify)
+ */
+rpmVerifyAttrs rpmfilesVerify(rpmfiles fi, int ix, rpmVerifyAttrs omitMask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RPMFILES_H */
diff --git a/lib/rpmfs.c b/lib/rpmfs.c
index 764618d94..7d807e06b 100644
--- a/lib/rpmfs.c
+++ b/lib/rpmfs.c
@@ -18,7 +18,7 @@ rpmfs rpmfsNew(rpm_count_t fc, int initState)
rpmfs fs = xcalloc(1, sizeof(*fs));
fs->fc = fc;
fs->actions = xmalloc(fs->fc * sizeof(*fs->actions));
- memset(fs->actions, FA_UNKNOWN, fs->fc * sizeof(*fs->actions));
+ rpmfsResetActions(fs);
if (initState) {
fs->states = xmalloc(sizeof(*fs->states) * fs->fc);
memset(fs->states, RPMFILE_STATE_NORMAL, fs->fc);
@@ -101,7 +101,7 @@ rpm_fstate_t * rpmfsGetStates(rpmfs fs)
rpmFileAction rpmfsGetAction(rpmfs fs, unsigned int ix)
{
rpmFileAction action;
- if (fs->actions != NULL && ix < fs->fc) {
+ if (fs && fs->actions != NULL && ix < fs->fc) {
action = fs->actions[ix];
} else {
action = FA_UNKNOWN;
@@ -115,3 +115,10 @@ void rpmfsSetAction(rpmfs fs, unsigned int ix, rpmFileAction action)
fs->actions[ix] = action;
}
}
+
+void rpmfsResetActions(rpmfs fs)
+{
+ if (fs && fs->actions) {
+ memset(fs->actions, FA_UNKNOWN, fs->fc * sizeof(*fs->actions));
+ }
+}
diff --git a/lib/rpmfs.h b/lib/rpmfs.h
index 5f747533c..83f99d15a 100644
--- a/lib/rpmfs.h
+++ b/lib/rpmfs.h
@@ -57,6 +57,9 @@ rpmFileAction rpmfsGetAction(rpmfs fs, unsigned int ix);
RPM_GNUC_INTERNAL
void rpmfsSetAction(rpmfs fs, unsigned int ix, rpmFileAction action);
+RPM_GNUC_INTERNAL
+void rpmfsResetActions(rpmfs fs);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/rpmgi.c b/lib/rpmgi.c
index 89707df64..c6663fde1 100644
--- a/lib/rpmgi.c
+++ b/lib/rpmgi.c
@@ -17,6 +17,8 @@
#include "debug.h"
+#define MANIFEST_RECURSIONS 1000 /* Max. number of allowed manifest recursions */
+
RPM_GNUC_INTERNAL
rpmgiFlags giFlags = RPMGI_NONE;
@@ -31,6 +33,10 @@ struct rpmgi_s {
ARGV_t argv;
int argc;
+
+ int curLvl; /*!< Current recursion level */
+ int recLvls[MANIFEST_RECURSIONS]; /*!< Reversed end index for given level */
+
};
/**
@@ -123,11 +129,24 @@ static Header rpmgiLoadReadHeader(rpmgi gi)
if (gi->argv != NULL && gi->argv[gi->i] != NULL)
do {
char * fn = gi->argv[gi->i];
- int rc = rpmgiReadHeader(gi, fn, &h);
+ int rc;
+
+ while (gi->recLvls[gi->curLvl] > gi->argc - gi->i)
+ gi->curLvl--;
+
+ rc = rpmgiReadHeader(gi, fn, &h);
if (h != NULL || (gi->flags & RPMGI_NOMANIFEST) || rc == 0)
break;
+ if (gi->curLvl == MANIFEST_RECURSIONS - 1) {
+ rpmlog(RPMLOG_ERR,
+ _("Max level of manifest recursion exceeded: %s\n"), fn);
+ break;
+ }
+ gi->curLvl++;
+ gi->recLvls[gi->curLvl] = gi->argc - gi->i;
+
/* Not a header, so try for a manifest. */
gi->argv[gi->i] = NULL; /* Mark the insertion point */
if (rpmgiLoadManifest(gi, fn) != RPMRC_OK) {
@@ -195,11 +214,13 @@ rpmgi rpmgiNew(rpmts ts, rpmgiFlags flags, ARGV_const_t argv)
gi->i = -1;
gi->errors = 0;
- gi->flags = flags;
gi->argv = argvNew();
gi->argc = 0;
rpmgiGlobArgv(gi, argv);
+ gi->curLvl = 0;
+ gi->recLvls[gi->curLvl] = 1;
+
return gi;
}
diff --git a/lib/rpmhash.C b/lib/rpmhash.C
index 98203272d..6875397aa 100644
--- a/lib/rpmhash.C
+++ b/lib/rpmhash.C
@@ -69,8 +69,8 @@ HASHTYPE HASHPREFIX(Create)(int numBuckets,
HASHTYPE ht;
ht = xmalloc(sizeof(*ht));
- ht->numBuckets = numBuckets;
- ht->buckets = xcalloc(numBuckets, sizeof(*ht->buckets));
+ ht->numBuckets = numBuckets > 11 ? numBuckets : 11;
+ ht->buckets = xcalloc(ht->numBuckets, sizeof(*ht->buckets));
ht->freeKey = freeKey;
#ifdef HTDATATYPE
ht->freeData = freeData;
@@ -142,6 +142,8 @@ void HASHPREFIX(AddHEntry)(HASHTYPE ht, HTKEYTYPE key, unsigned int keyHash
}
#ifdef HTDATATYPE
else {
+ if (ht->freeKey)
+ ht->freeKey(key);
// resizing bucket TODO: increase exponentially
// Bucket_s already contains space for one dataset
b = *b_addr = xrealloc(
diff --git a/lib/rpminstall.c b/lib/rpminstall.c
index a3623fd3a..e10392e0f 100644
--- a/lib/rpminstall.c
+++ b/lib/rpminstall.c
@@ -10,6 +10,7 @@
#include <rpm/rpmdb.h>
#include <rpm/rpmds.h>
#include <rpm/rpmts.h>
+#include <rpm/rpmsq.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmfileutil.h>
@@ -22,6 +23,7 @@ static int rpmcliHashesCurrent = 0;
static int rpmcliHashesTotal = 0;
static int rpmcliProgressCurrent = 0;
static int rpmcliProgressTotal = 0;
+static int rpmcliProgressState = 0;
/**
* Print a CLI progress bar.
@@ -103,7 +105,6 @@ void * rpmShowProgress(const void * arg,
void * rc = NULL;
const char * filename = (const char *)key;
static FD_t fd = NULL;
- static int state = -1;
switch (what) {
case RPMCALLBACK_INST_OPEN_FILE:
@@ -134,8 +135,8 @@ void * rpmShowProgress(const void * arg,
case RPMCALLBACK_INST_START:
case RPMCALLBACK_UNINST_START:
- if (state != what) {
- state = what;
+ if (rpmcliProgressState != what) {
+ rpmcliProgressState = what;
if (flags & INSTALL_HASH) {
if (what == RPMCALLBACK_INST_START) {
fprintf(stdout, _("Updating / installing...\n"));
@@ -185,7 +186,7 @@ void * rpmShowProgress(const void * arg,
rpmcliProgressTotal = 1;
rpmcliProgressCurrent = 0;
rpmcliPackagesTotal = total;
- state = what;
+ rpmcliProgressState = what;
if (!(flags & INSTALL_LABEL))
break;
if (flags & INSTALL_HASH)
@@ -290,8 +291,8 @@ static int rpmcliTransaction(rpmts ts, struct rpmInstallArguments_s * ia,
ps = rpmtsProblems(ts);
- if ((rpmpsNumProblems(ps) > 0) && (eflags? 1 : (rc > 0)))
- rpmpsPrint((eflags? NULL : stderr), ps);
+ if (rpmpsNumProblems(ps) > 0 && (eflags || rc > 0))
+ rpmpsPrint(NULL, ps);
ps = rpmpsFree(ps);
}
@@ -311,7 +312,8 @@ static int tryReadManifest(struct rpmEIU * eiu)
Fclose(fd);
fd = NULL;
}
- eiu->numFailed++; *eiu->fnp = NULL;
+ eiu->numFailed++;
+ *eiu->fnp = NULL;
return RPMRC_FAIL;
}
@@ -323,8 +325,10 @@ static int tryReadManifest(struct rpmEIU * eiu)
Fclose(fd);
fd = NULL;
- if (rc != RPMRC_OK)
- eiu->numFailed++; *eiu->fnp = NULL;
+ if (rc != RPMRC_OK) {
+ eiu->numFailed++;
+ *eiu->fnp = NULL;
+ }
return rc;
}
@@ -340,7 +344,8 @@ static int tryReadHeader(rpmts ts, struct rpmEIU * eiu, Header * hdrp)
Fclose(fd);
fd = NULL;
}
- eiu->numFailed++; *eiu->fnp = NULL;
+ eiu->numFailed++;
+ *eiu->fnp = NULL;
return RPMRC_FAIL;
}
@@ -353,9 +358,10 @@ static int tryReadHeader(rpmts ts, struct rpmEIU * eiu, Header * hdrp)
if (eiu->rpmrc == RPMRC_NOTFOUND && (giFlags & RPMGI_NOMANIFEST))
eiu->rpmrc = RPMRC_FAIL;
- if(eiu->rpmrc == RPMRC_FAIL) {
+ if (eiu->rpmrc == RPMRC_FAIL) {
rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), *eiu->fnp);
- eiu->numFailed++; *eiu->fnp = NULL;
+ eiu->numFailed++;
+ *eiu->fnp = NULL;
}
return RPMRC_OK;
@@ -385,6 +391,19 @@ static int checkFreshenStatus(rpmts ts, Header h)
return (oldH != NULL);
}
+static int rpmNoGlob(const char *fn, int *argcPtr, ARGV_t * argvPtr)
+{
+ struct stat sb;
+ int rc = stat(fn, &sb);
+ if (rc == 0) {
+ argvAdd(argvPtr, fn);
+ *argcPtr = 1;
+ } else {
+ *argcPtr = 0;
+ }
+ return rc;
+}
+
/** @todo Generalize --freshen policies. */
int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv)
{
@@ -417,13 +436,20 @@ int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv)
for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) {
ARGV_t av = NULL;
int ac = 0;
- char * fn;
- fn = rpmEscapeSpaces(*eiu->fnp);
- rc = rpmGlob(fn, &ac, &av);
- fn = _free(fn);
+ if (giFlags & RPMGI_NOGLOB) {
+ rc = rpmNoGlob(*eiu->fnp, &ac, &av);
+ } else {
+ char * fn = rpmEscapeSpaces(*eiu->fnp);
+ rc = rpmGlob(fn, &ac, &av);
+ fn = _free(fn);
+ }
if (rc || ac == 0) {
- rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp);
+ if (giFlags & RPMGI_NOGLOB) {
+ rpmlog(RPMLOG_ERR, _("File not found: %s\n"), *eiu->fnp);
+ } else {
+ rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp);
+ }
eiu->numFailed++;
continue;
}
@@ -520,6 +546,10 @@ restart:
}
if (headerIsSource(h)) {
+ if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
+ headerFree(h);
+ continue;
+ }
rpmlog(RPMLOG_DEBUG, "\tadded source package [%d]\n",
eiu->numSRPMS);
eiu->sourceURL = xrealloc(eiu->sourceURL,
@@ -552,7 +582,10 @@ restart:
continue;
}
- rc = rpmtsAddInstallElement(ts, h, (fnpyKey)fileName,
+ if (ia->installInterfaceFlags & INSTALL_REINSTALL)
+ rc = rpmtsAddReinstallElement(ts, h, (fnpyKey)fileName);
+ else
+ rc = rpmtsAddInstallElement(ts, h, (fnpyKey)fileName,
(ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
relocations);
@@ -560,7 +593,7 @@ restart:
if (eiu->relocations)
eiu->relocations->oldPath = _free(eiu->relocations->oldPath);
- switch(rc) {
+ switch (rc) {
case 0:
rpmlog(RPMLOG_DEBUG, "\tadded binary package [%d]\n",
eiu->numRPMS);
@@ -594,8 +627,11 @@ restart:
}
if (eiu->numSRPMS && (eiu->sourceURL != NULL)) {
+ rpmcliProgressState = 0;
+ rpmcliProgressTotal = 0;
+ rpmcliProgressCurrent = 0;
for (i = 0; i < eiu->numSRPMS; i++) {
- rpmdbCheckSignals();
+ rpmsqPoll();
if (eiu->sourceURL[i] != NULL) {
rc = RPMRC_OK;
if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST))
diff --git a/lib/rpmlead.c b/lib/rpmlead.c
index 8e56bfc38..981bc8f60 100644
--- a/lib/rpmlead.c
+++ b/lib/rpmlead.c
@@ -17,6 +17,9 @@
#include "debug.h"
+/* A long time ago in a galaxy far far away, signatures were not in a header */
+#define RPMSIGTYPE_HEADERSIG 5
+
static unsigned char const lead_magic[] = {
RPMLEAD_MAGIC0, RPMLEAD_MAGIC1, RPMLEAD_MAGIC2, RPMLEAD_MAGIC3
};
@@ -39,10 +42,8 @@ struct rpmlead_s {
char reserved[16]; /*!< Pad to 96 bytes -- 8 byte aligned! */
};
-rpmlead rpmLeadFromHeader(Header h)
+static int rpmLeadFromHeader(Header h, struct rpmlead_s *l)
{
- rpmlead l = NULL;
-
if (h != NULL) {
int archnum, osnum;
char * nevr = headerGetAsString(h, RPMTAG_NEVR);
@@ -51,7 +52,7 @@ rpmlead rpmLeadFromHeader(Header h)
rpmGetArchInfo(NULL, &archnum);
rpmGetOsInfo(NULL, &osnum);
- l = xcalloc(1, sizeof(*l));
+ memset(l, 0, sizeof(*l));
l->major = 3;
l->minor = 0;
l->archnum = archnum;
@@ -65,36 +66,30 @@ rpmlead rpmLeadFromHeader(Header h)
free(nevr);
}
- return l;
-}
-
-rpmlead rpmLeadFree(rpmlead lead)
-{
- free(lead);
- return NULL;
+ return (h != NULL);
}
/* The lead needs to be 8 byte aligned */
-rpmRC rpmLeadWrite(FD_t fd, rpmlead lead)
+rpmRC rpmLeadWrite(FD_t fd, Header h)
{
rpmRC rc = RPMRC_FAIL;
+ struct rpmlead_s l;
- if (lead != NULL) {
- struct rpmlead_s l;
- memcpy(&l, lead, sizeof(l));
+ if (rpmLeadFromHeader(h, &l)) {
- l.type = htons(lead->type);
- l.archnum = htons(lead->archnum);
- l.osnum = htons(lead->osnum);
- l.signature_type = htons(lead->signature_type);
+ l.type = htons(l.type);
+ l.archnum = htons(l.archnum);
+ l.osnum = htons(l.osnum);
+ l.signature_type = htons(l.signature_type);
if (Fwrite(&l, 1, sizeof(l), fd) == sizeof(l))
rc = RPMRC_OK;
}
+
return rc;
}
-static rpmRC rpmLeadCheck(rpmlead lead, char **msg)
+static rpmRC rpmLeadCheck(struct rpmlead_s *lead, char **msg)
{
if (memcmp(lead->magic, lead_magic, sizeof(lead_magic))) {
*msg = xstrdup(_("not an rpm package"));
@@ -111,7 +106,7 @@ static rpmRC rpmLeadCheck(rpmlead lead, char **msg)
return RPMRC_OK;
}
-rpmRC rpmLeadRead(FD_t fd, rpmlead *lead, int *type, char **emsg)
+rpmRC rpmLeadRead(FD_t fd, int *type, char **emsg)
{
rpmRC rc = RPMRC_OK;
struct rpmlead_s l;
@@ -135,10 +130,6 @@ rpmRC rpmLeadRead(FD_t fd, rpmlead *lead, int *type, char **emsg)
}
if (rc == RPMRC_OK) {
- if (lead != NULL) {
- *lead = xmalloc(sizeof(l));
- memcpy(*lead, &l, sizeof(l));
- }
if (type != NULL)
*type = l.type;
} else {
diff --git a/lib/rpmlead.h b/lib/rpmlead.h
index a7f4730ad..48d4df287 100644
--- a/lib/rpmlead.h
+++ b/lib/rpmlead.h
@@ -19,39 +19,22 @@ extern "C" {
#define RPMLEAD_SIZE 96 /*!< Don't rely on sizeof(struct) */
-typedef struct rpmlead_s * rpmlead;
-
-/** \ingroup lead
- * Initialize a lead structure from header
- * param h Header
- * @return Pointer to populated lead structure (malloced)
- */
-rpmlead rpmLeadFromHeader(Header h);
-
-/** \ingroup lead
- * Free a lead structure
- * @param lead Pointer to lead structure
- * @return NULL always
- */
-rpmlead rpmLeadFree(rpmlead lead);
-
/** \ingroup lead
* Write lead to file handle.
* @param fd file handle
- * @param lead package lead
+ * @param h package header
* @return RPMRC_OK on success, RPMRC_FAIL on error
*/
-rpmRC rpmLeadWrite(FD_t fd, rpmlead lead);
+rpmRC rpmLeadWrite(FD_t fd, Header h);
/** \ingroup lead
* Read lead from file handle.
* @param fd file handle
- * @retval lead pointer to package lead (malloced)
* @retval type RPMLEAD_BINARY or RPMLEAD_SOURCE on success
* @retval emsg failure message on error (malloced)
* @return RPMRC_OK on success, RPMRC_FAIL/RPMRC_NOTFOUND on error
*/
-rpmRC rpmLeadRead(FD_t fd, rpmlead *lead, int *type, char **emsg);
+rpmRC rpmLeadRead(FD_t fd, int *type, char **emsg);
#ifdef __cplusplus
}
diff --git a/lib/rpmlib.h b/lib/rpmlib.h
index 41a285d04..2e1da831a 100644
--- a/lib/rpmlib.h
+++ b/lib/rpmlib.h
@@ -15,8 +15,9 @@
#include <rpm/rpmtag.h>
#include <rpm/rpmds.h> /* XXX move rpmlib provides to rpmds instead */
#include <rpm/rpmpgp.h>
+
#ifdef _RPM_4_4_COMPAT
-#include <rpm/rpmlegacy.h> /* legacy compat definitions if enabled */
+#warning RPM 4.4.x compatibility layer has been removed in RPM >= 4.14
#endif
#ifdef __cplusplus
@@ -137,7 +138,7 @@ rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, char ** msg);
/** \ingroup header
* Return checked and loaded header.
- * @param ts transaction set
+ * @param ts unused
* @param fd file handle
* @retval hdrp address of header (or NULL)
* @retval *msg verification error message (or NULL)
diff --git a/lib/rpmlock.c b/lib/rpmlock.c
index cf9947ea5..f27d8d9b3 100644
--- a/lib/rpmlock.c
+++ b/lib/rpmlock.c
@@ -12,18 +12,15 @@
/* Internal interface */
-enum {
- RPMLOCK_READ = 1 << 0,
- RPMLOCK_WRITE = 1 << 1,
- RPMLOCK_WAIT = 1 << 2,
-};
-
struct rpmlock_s {
int fd;
int openmode;
+ char *path;
+ char *descr;
+ int fdrefs;
};
-static rpmlock rpmlock_new(const char *lock_path)
+static rpmlock rpmlock_new(const char *lock_path, const char *descr)
{
rpmlock lock = (rpmlock) malloc(sizeof(*lock));
@@ -33,7 +30,8 @@ static rpmlock rpmlock_new(const char *lock_path)
(void) umask(oldmask);
if (lock->fd == -1) {
- lock->fd = open(lock_path, O_RDONLY);
+ if (errno == EACCES)
+ lock->fd = open(lock_path, O_RDONLY);
if (lock->fd == -1) {
free(lock);
lock = NULL;
@@ -43,13 +41,20 @@ static rpmlock rpmlock_new(const char *lock_path)
} else {
lock->openmode = RPMLOCK_WRITE | RPMLOCK_READ;
}
+ if (lock) {
+ lock->path = xstrdup(lock_path);
+ lock->descr = xstrdup(descr);
+ lock->fdrefs = 1;
+ }
}
return lock;
}
static void rpmlock_free(rpmlock lock)
{
- if (lock) {
+ if (--lock->fdrefs == 0) {
+ free(lock->path);
+ free(lock->descr);
(void) close(lock->fd);
free(lock);
}
@@ -58,7 +63,13 @@ static void rpmlock_free(rpmlock lock)
static int rpmlock_acquire(rpmlock lock, int mode)
{
int res = 0;
- if (lock && (mode & lock->openmode)) {
+
+ if (!(mode & lock->openmode))
+ return res;
+
+ if (lock->fdrefs > 1) {
+ res = 1;
+ } else {
struct flock info;
int cmd;
if (mode & RPMLOCK_WAIT)
@@ -76,12 +87,19 @@ static int rpmlock_acquire(rpmlock lock, int mode)
if (fcntl(lock->fd, cmd, &info) != -1)
res = 1;
}
+
+ lock->fdrefs += res;
+
return res;
}
static void rpmlock_release(rpmlock lock)
{
- if (lock) {
+ /* if not locked then we must not release */
+ if (lock->fdrefs <= 1)
+ return;
+
+ if (--lock->fdrefs == 1) {
struct flock info;
info.l_type = F_UNLCK;
info.l_whence = SEEK_SET;
@@ -94,31 +112,56 @@ static void rpmlock_release(rpmlock lock)
/* External interface */
-
-rpmlock rpmlockAcquire(const char *lock_path, const char *descr)
+rpmlock rpmlockNew(const char *lock_path, const char *descr)
{
- rpmlock lock = rpmlock_new(lock_path);
+ rpmlock lock = rpmlock_new(lock_path, descr);
if (!lock) {
rpmlog(RPMLOG_ERR, _("can't create %s lock on %s (%s)\n"),
descr, lock_path, strerror(errno));
- } else if (!rpmlock_acquire(lock, RPMLOCK_WRITE)) {
- if (lock->openmode & RPMLOCK_WRITE)
+ }
+ return lock;
+}
+
+int rpmlockAcquire(rpmlock lock)
+{
+ int locked = 0; /* assume failure */
+ int maywait = isatty(STDIN_FILENO); /* dont wait within scriptlets */
+
+ if (lock) {
+ locked = rpmlock_acquire(lock, RPMLOCK_WRITE);
+ if (!locked && (lock->openmode & RPMLOCK_WRITE) && maywait) {
rpmlog(RPMLOG_WARNING, _("waiting for %s lock on %s\n"),
- descr, lock_path);
- if (!rpmlock_acquire(lock, RPMLOCK_WRITE|RPMLOCK_WAIT)) {
+ lock->descr, lock->path);
+ locked = rpmlock_acquire(lock, (RPMLOCK_WRITE|RPMLOCK_WAIT));
+ }
+ if (!locked) {
rpmlog(RPMLOG_ERR, _("can't create %s lock on %s (%s)\n"),
- descr, lock_path, strerror(errno));
- rpmlock_free(lock);
- lock = NULL;
+ lock->descr, lock->path, strerror(errno));
}
}
+ return locked;
+}
+
+void rpmlockRelease(rpmlock lock)
+{
+ if (lock)
+ rpmlock_release(lock);
+}
+
+rpmlock rpmlockNewAcquire(const char *lock_path, const char *descr)
+{
+ rpmlock lock = rpmlockNew(lock_path, descr);
+ if (!rpmlockAcquire(lock))
+ lock = rpmlockFree(lock);
return lock;
}
rpmlock rpmlockFree(rpmlock lock)
{
- rpmlock_release(lock); /* Not really needed here. */
- rpmlock_free(lock);
+ if (lock) {
+ rpmlock_release(lock);
+ rpmlock_free(lock);
+ }
return NULL;
}
diff --git a/lib/rpmlock.h b/lib/rpmlock.h
index aa85451d6..308794fea 100644
--- a/lib/rpmlock.h
+++ b/lib/rpmlock.h
@@ -5,12 +5,27 @@
typedef struct rpmlock_s * rpmlock;
+enum {
+ RPMLOCK_READ = 1 << 0,
+ RPMLOCK_WRITE = 1 << 1,
+ RPMLOCK_WAIT = 1 << 2,
+};
+
#ifdef __cplusplus
extern "C" {
#endif
RPM_GNUC_INTERNAL
-rpmlock rpmlockAcquire(const char *lock_path, const char *descr);
+rpmlock rpmlockNew(const char *lock_path, const char *descr);
+
+RPM_GNUC_INTERNAL
+rpmlock rpmlockNewAcquire(const char *lock_path, const char *descr);
+
+RPM_GNUC_INTERNAL
+int rpmlockAcquire(rpmlock lock);
+
+RPM_GNUC_INTERNAL
+void rpmlockRelease(rpmlock lock);
RPM_GNUC_INTERNAL
rpmlock rpmlockFree(rpmlock lock);
diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h
new file mode 100644
index 000000000..d3cdecee2
--- /dev/null
+++ b/lib/rpmplugin.h
@@ -0,0 +1,145 @@
+#ifndef _RPMPLUGIN_H
+#define _RPMPLUGIN_H
+
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmfi.h>
+
+/** \ingroup rpmplugin
+ * Rpm plugin API
+ */
+
+/* indicates if a directory is part of rpm package or created by rpm itself */
+typedef enum rpmPluginDirType_e {
+ DIR_TYPE_NONE = 0,
+ DIR_TYPE_NORMAL = 1 << 0,
+ DIR_TYPE_UNOWNED = 1 << 1
+} rpmPluginDirType;
+
+
+/* indicates the way the scriptlet is executed */
+typedef enum rpmScriptletExecutionFlow_e {
+ RPMSCRIPTLET_NONE = 0,
+ RPMSCRIPTLET_FORK = 1 << 0,
+ RPMSCRIPTLET_EXEC = 1 << 1
+} rpmScriptletExecutionFlow;
+
+
+/** \ingroup rpmfi
+ * File disposition flags during package install/erase transaction.
+ * XXX: Move these to rpmfi.h once things stabilize.
+ */
+enum rpmFileActionFlags_e {
+ /* bits 0-15 reserved for actions */
+ FAF_UNOWNED = (1 << 31)
+};
+typedef rpmFlags rpmFileActionFlags;
+
+/** \ingroup rpmfi
+ * File action and associated flags on install/erase
+ */
+typedef rpmFlags rpmFsmOp;
+
+#define XFA_MASK 0x0000ffff
+#define XFAF_MASK ~(XFA_MASK)
+#define XFO_ACTION(_a) ((_a) & XFA_MASK) /*!< File op action part */
+#define XFO_FLAGS(_a) ((_a) & XFAF_MASK) /*!< File op flags part */
+
+/* plugin hook typedefs */
+typedef rpmRC (*plugin_init_func)(rpmPlugin plugin, rpmts ts);
+typedef void (*plugin_cleanup_func)(rpmPlugin plugin);
+typedef rpmRC (*plugin_tsm_pre_func)(rpmPlugin plugin, rpmts ts);
+typedef rpmRC (*plugin_tsm_post_func)(rpmPlugin plugin, rpmts ts, int res);
+typedef rpmRC (*plugin_psm_pre_func)(rpmPlugin plugin, rpmte te);
+typedef rpmRC (*plugin_psm_post_func)(rpmPlugin plugin, rpmte te, int res);
+typedef rpmRC (*plugin_psm_verify_func)(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, DIGEST_CTX ctx, int res);
+
+typedef rpmRC (*plugin_scriptlet_pre_func)(rpmPlugin plugin,
+ const char *s_name, int type);
+typedef rpmRC (*plugin_scriptlet_fork_post_func)(rpmPlugin plugin,
+ const char *path, int type);
+typedef rpmRC (*plugin_scriptlet_post_func)(rpmPlugin plugin,
+ const char *s_name, int type,
+ int res);
+typedef rpmRC (*plugin_fsm_file_pre_func)(rpmPlugin plugin, rpmfi fi,
+ const char* path, mode_t file_mode,
+ rpmFsmOp op);
+typedef rpmRC (*plugin_fsm_file_post_func)(rpmPlugin plugin, rpmfi fi,
+ const char* path, mode_t file_mode,
+ rpmFsmOp op, int res);
+typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,
+ const char* path,
+ const char *dest,
+ mode_t file_mode, rpmFsmOp op);
+typedef rpmRC (*plugin_fsm_file_init_func)(const char* path, mode_t mode);
+typedef rpmRC (*plugin_fsm_file_commit_func)(const char* path, mode_t mode, int type);
+typedef rpmRC (*plugin_fsm_file_conflict_func)(rpmts ts, char* path, Header oldHeader, rpmfi oldFi, int rpmrc);
+
+typedef struct rpmPluginHooks_s * rpmPluginHooks;
+struct rpmPluginHooks_s {
+ /* plugin constructor and destructor hooks */
+ plugin_init_func init;
+ plugin_cleanup_func cleanup;
+ /* per transaction plugin hooks */
+ plugin_tsm_pre_func tsm_pre;
+ plugin_tsm_post_func tsm_post;
+ /* per transaction element hooks */
+ plugin_psm_pre_func psm_pre;
+ plugin_psm_post_func psm_post;
+ plugin_psm_verify_func psm_verify;
+ /* per scriptlet hooks */
+ plugin_scriptlet_pre_func scriptlet_pre;
+ plugin_scriptlet_fork_post_func scriptlet_fork_post;
+ plugin_scriptlet_post_func scriptlet_post;
+ /* per file hooks */
+ plugin_fsm_file_pre_func fsm_file_pre;
+ plugin_fsm_file_post_func fsm_file_post;
+ plugin_fsm_file_prepare_func fsm_file_prepare;
+ plugin_fsm_file_init_func fsm_file_init;
+ plugin_fsm_file_commit_func fsm_file_commit;
+ plugin_fsm_file_conflict_func fsm_file_conflict;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \ingroup rpmplugin
+ * Return plugin name
+ * @param plugin plugin handle
+ * @return plugin name string
+ */
+const char *rpmPluginName(rpmPlugin plugin);
+
+/** \ingroup rpmplugin
+ * Return plugin options
+ * @param plugin plugin handle
+ * @return plugin options string (or NULL if none)
+ */
+const char *rpmPluginOpts(rpmPlugin plugin);
+
+/** \ingroup rpmplugin
+ * Set plugin private data
+ * @param plugin plugin handle
+ * @param data pointer to plugin private data
+ */
+void rpmPluginSetData(rpmPlugin plugin, void *data);
+
+/** \ingroup rpmplugin
+ * Get plugin private data
+ * @param plugin plugin handle
+ * @return pointer to plugin private data
+ */
+void * rpmPluginGetData(rpmPlugin plugin);
+
+/** \ingroup rpmplugin
+ * Get plugin count
+ * @param plugins plugins handle
+ * @return count of plugins in the plugins handle
+ */
+int rpmPluginsGetCount(rpmPlugins plugin);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _RPMPLUGIN_H */
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
index 2d4fb01cd..88d4f06ad 100644
--- a/lib/rpmplugins.c
+++ b/lib/rpmplugins.c
@@ -12,34 +12,37 @@
#define STR1(x) #x
#define STR(x) STR1(x)
+static rpmRC rpmpluginsCallInit(rpmPlugin plugin, rpmts ts);
+
+struct rpmPlugin_s {
+ char *name;
+ char *opts;
+ void *handle;
+ void *priv;
+ rpmPluginHooks hooks;
+};
+
struct rpmPlugins_s {
- void **handles;
- ARGV_t names;
+ rpmPlugin *plugins;
int count;
rpmts ts;
};
-static int rpmpluginsGetPluginIndex(rpmPlugins plugins, const char *name)
+static rpmPlugin rpmpluginsGetPlugin(rpmPlugins plugins, const char *name)
{
int i;
for (i = 0; i < plugins->count; i++) {
- if (rstreq(plugins->names[i], name)) {
- return i;
+ rpmPlugin plugin = plugins->plugins[i];
+ if (rstreq(plugin->name, name)) {
+ return plugin;
}
}
- return -1;
-}
-
-static int rpmpluginsHookIsSupported(void *handle, rpmPluginHook hook)
-{
- rpmPluginHook *supportedHooks =
- (rpmPluginHook *) dlsym(handle, STR(PLUGIN_HOOKS));
- return (*supportedHooks & hook);
+ return NULL;
}
int rpmpluginsPluginAdded(rpmPlugins plugins, const char *name)
{
- return (rpmpluginsGetPluginIndex(plugins, name) >= 0);
+ return (rpmpluginsGetPlugin(plugins, name) != NULL);
}
rpmPlugins rpmpluginsNew(rpmts ts)
@@ -49,31 +52,100 @@ rpmPlugins rpmpluginsNew(rpmts ts)
return plugins;
}
-rpmRC rpmpluginsAdd(rpmPlugins plugins, const char *name, const char *path,
- const char *opts)
+static rpmPlugin rpmPluginNew(const char *name, const char *path,
+ const char *opts)
{
+ rpmPlugin plugin = NULL;
+ rpmPluginHooks hooks = NULL;
char *error;
+ char *hooks_name = NULL;
void *handle = dlopen(path, RTLD_LAZY);
if (!handle) {
rpmlog(RPMLOG_ERR, _("Failed to dlopen %s %s\n"), path, dlerror());
- return RPMRC_FAIL;
+ return NULL;
}
/* make sure the plugin has the supported hooks flag */
- (void) dlsym(handle, STR(PLUGIN_HOOKS));
+ hooks_name = rstrscat(NULL, name, "_hooks", NULL);
+ hooks = dlsym(handle, hooks_name);
if ((error = dlerror()) != NULL) {
rpmlog(RPMLOG_ERR, _("Failed to resolve symbol %s: %s\n"),
- STR(PLUGIN_HOOKS), error);
- return RPMRC_FAIL;
+ hooks_name, error);
+ } else {
+ plugin = xcalloc(1, sizeof(*plugin));
+ plugin->name = xstrdup(name);
+ plugin->handle = handle;
+ plugin->hooks = hooks;
+ if (opts)
+ plugin->opts = xstrdup(opts);
+ }
+ free(hooks_name);
+
+ return plugin;
+}
+
+static rpmPlugin rpmPluginFree(rpmPlugin plugin)
+{
+ if (plugin) {
+ rpmPluginHooks hooks = plugin->hooks;
+ if (hooks->cleanup)
+ hooks->cleanup(plugin);
+ dlclose(plugin->handle);
+ free(plugin->name);
+ free(plugin->opts);
+ free(plugin);
}
+ return NULL;
+}
+
+const char *rpmPluginName(rpmPlugin plugin)
+{
+ return (plugin != NULL) ? plugin->name : NULL;
+}
+
+const char *rpmPluginOpts(rpmPlugin plugin)
+{
+ return (plugin != NULL) ? plugin->opts : NULL;
+}
+
+void * rpmPluginGetData(rpmPlugin plugin)
+{
+ return (plugin != NULL) ? plugin->priv : NULL;
+}
+
+int rpmPluginsGetCount(rpmPlugins plugins)
+{
+ return (plugins != NULL) ? plugins->count : 0;
+}
+
+void rpmPluginSetData(rpmPlugin plugin, void *data)
+{
+ if (plugin)
+ plugin->priv = data;
+}
+
+rpmRC rpmpluginsAdd(rpmPlugins plugins, const char *name, const char *path,
+ const char *opts)
+{
+ rpmRC rc;
+ rpmPlugin plugin = rpmPluginNew(name, path, opts);
- argvAdd(&plugins->names, name);
- plugins->handles = xrealloc(plugins->handles, (plugins->count + 1) * sizeof(*plugins->handles));
- plugins->handles[plugins->count] = handle;
- plugins->count++;
+ if (plugin == NULL)
+ return RPMRC_FAIL;
+
+ rc = rpmpluginsCallInit(plugin, plugins->ts);
+
+ if (rc == RPMRC_OK) {
+ plugins->plugins = xrealloc(plugins->plugins,
+ (plugins->count + 1) * sizeof(*plugins->plugins));
+ plugins->plugins[plugins->count] = plugin;
+ plugins->count++;
+ } else {
+ rpmPluginFree(plugin);
+ }
- return rpmpluginsCallInit(plugins, name, opts);
+ return rc;
}
rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name)
@@ -83,9 +155,11 @@ rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name
rpmRC rc = RPMRC_FAIL;
path = rpmExpand("%{?__", type, "_", name, "}", NULL);
+ //rpmlog(RPMLOG_WARNING, "rpmpluginsAddPlugin, path:%s\n", path);
if (!path || rstreq(path, "")) {
- rpmlog(RPMLOG_ERR, _("Failed to expand %%__%s_%s macro\n"),
+ rpmlog(RPMLOG_DEBUG, _("Plugin %%__%s_%s not configured\n"),
type, name);
+ rc = RPMRC_NOTFOUND;
goto exit;
}
@@ -112,222 +186,245 @@ rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name
rpmPlugins rpmpluginsFree(rpmPlugins plugins)
{
- int i;
- for (i = 0; i < plugins->count; i++) {
- rpmpluginsCallCleanup(plugins, plugins->names[i]);
- dlclose(plugins->handles[i]);
+ if (plugins) {
+ for (int i = 0; i < plugins->count; i++) {
+ rpmPlugin plugin = plugins->plugins[i];
+ rpmPluginFree(plugin);
+ }
+ plugins->plugins = _free(plugins->plugins);
+ plugins->ts = NULL;
+ _free(plugins);
}
- plugins->handles = _free(plugins->handles);
- plugins->names = argvFree(plugins->names);
- plugins->ts = NULL;
- _free(plugins);
return NULL;
}
+#define RPMPLUGINS_GET_PLUGIN(name) \
+ plugin = rpmpluginsGetPlugin(plugins, name); \
+ if (plugin == NULL || plugin->handle == NULL) { \
+ rpmlog(RPMLOG_ERR, _("Plugin %s not loaded\n"), name); \
+ return RPMRC_FAIL; \
+ }
/* Common define for all rpmpluginsCall* hook functions */
#define RPMPLUGINS_SET_HOOK_FUNC(hook) \
- void *handle = NULL; \
- int index; \
- char * error; \
- index = rpmpluginsGetPluginIndex(plugins, name); \
- if (index < 0) { \
- rpmlog(RPMLOG_ERR, _("Plugin %s not loaded\n"), name); \
- return RPMRC_FAIL; \
- } \
- handle = plugins->handles[index]; \
- if (!handle) { \
- rpmlog(RPMLOG_ERR, _("Plugin %s not loaded\n"), name); \
- return RPMRC_FAIL; \
- } \
- if (!rpmpluginsHookIsSupported(handle, hook)) { \
- return RPMRC_OK; \
- } \
- *(void **)(&hookFunc) = dlsym(handle, STR(hook##_FUNC)); \
- if ((error = dlerror()) != NULL) { \
- rpmlog(RPMLOG_ERR, _("Failed to resolve %s plugin symbol %s: %s\n"), name, STR(hook##_FUNC), error); \
- return RPMRC_FAIL; \
- } \
- if (rpmtsFlags(plugins->ts) & (RPMTRANS_FLAG_TEST | RPMTRANS_FLAG_JUSTDB)) { \
- return RPMRC_OK; \
- } \
- rpmlog(RPMLOG_DEBUG, "Plugin: calling hook %s in %s plugin\n", STR(hook##_FUNC), name);
+ rpmPluginHooks hooks = (plugin != NULL) ? plugin->hooks : NULL; \
+ hookFunc = (hooks != NULL) ? hooks->hook : NULL; \
+ if (hookFunc) { \
+ rpmlog(RPMLOG_DEBUG, "Plugin: calling hook %s in %s plugin\n", \
+ STR(hook), plugin->name); \
+ }
-rpmRC rpmpluginsCallInit(rpmPlugins plugins, const char *name, const char *opts)
+static rpmRC rpmpluginsCallInit(rpmPlugin plugin, rpmts ts)
{
- rpmRC (*hookFunc)(rpmts, const char *, const char *);
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_INIT);
- return hookFunc(plugins->ts, name, opts);
+ rpmRC rc = RPMRC_OK;
+ plugin_init_func hookFunc;
+ RPMPLUGINS_SET_HOOK_FUNC(init);
+ if (hookFunc) {
+ rc = hookFunc(plugin, ts);
+ if (rc != RPMRC_OK && rc != RPMRC_NOTFOUND)
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook init failed\n", plugin->name);
+ }
+ return rc;
}
-rpmRC rpmpluginsCallCleanup(rpmPlugins plugins, const char *name)
+rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts)
{
- rpmRC (*hookFunc)(void);
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_CLEANUP);
- return hookFunc();
-}
+ plugin_tsm_pre_func hookFunc;
+ int i;
+ rpmRC rc = RPMRC_OK;
-rpmRC rpmpluginsCallOpenTE(rpmPlugins plugins, const char *name, rpmte te)
-{
- rpmRC (*hookFunc)(rpmte);
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_OPENTE);
- return hookFunc(te);
-}
+ for (i = 0; i < plugins->count; i++) {
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(tsm_pre);
+ if (hookFunc && hookFunc(plugin, ts) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook tsm_pre failed\n", plugin->name);
+ rc = RPMRC_FAIL;
+ }
+ }
-rpmRC rpmpluginsCallCollectionPostAdd(rpmPlugins plugins, const char *name)
-{
- rpmRC (*hookFunc)(void);
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_POST_ADD);
- return hookFunc();
+ return rc;
}
-rpmRC rpmpluginsCallCollectionPostAny(rpmPlugins plugins, const char *name)
+rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts, int res)
{
- rpmRC (*hookFunc)(void);
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_POST_ANY);
- return hookFunc();
+ plugin_tsm_post_func hookFunc;
+ int i;
+ rpmRC rc = RPMRC_OK;
+
+ for (i = 0; i < plugins->count; i++) {
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(tsm_post);
+ if (hookFunc && hookFunc(plugin, ts, res) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_WARNING, "Plugin %s: hook tsm_post failed\n", plugin->name);
+ }
+ }
+
+ return rc;
}
-rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins plugins, const char *name)
+rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te)
{
- rpmRC (*hookFunc)(void);
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_PRE_REMOVE);
- return hookFunc();
+ plugin_psm_pre_func hookFunc;
+ int i;
+ rpmRC rc = RPMRC_OK;
+
+ for (i = 0; i < plugins->count; i++) {
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(psm_pre);
+ if (hookFunc && hookFunc(plugin, te) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook psm_pre failed\n", plugin->name);
+ rc = RPMRC_FAIL;
+ }
+ }
+
+ return rc;
}
-rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts)
+rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te, int res)
{
- rpmRC (*hookFunc)(rpmts);
+ plugin_psm_post_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_PRE);
- if (hookFunc(ts) == RPMRC_FAIL)
- rc = RPMRC_FAIL;
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(psm_post);
+ if (hookFunc && hookFunc(plugin, te, res) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_WARNING, "Plugin %s: hook psm_post failed\n", plugin->name);
+ }
}
return rc;
}
-rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts, int res)
+rpmRC rpmpluginsCallScriptletPre(rpmPlugins plugins, const char *s_name, int type)
{
- rpmRC (*hookFunc)(rpmts, int);
+ plugin_scriptlet_pre_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_POST);
- if (hookFunc(ts, res) == RPMRC_FAIL)
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(scriptlet_pre);
+ if (hookFunc && hookFunc(plugin, s_name, type) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook scriplet_pre failed\n", plugin->name);
rc = RPMRC_FAIL;
+ }
}
return rc;
}
-rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te)
+rpmRC rpmpluginsCallScriptletForkPost(rpmPlugins plugins, const char *path, int type)
{
- rpmRC (*hookFunc)(rpmte);
+ plugin_scriptlet_fork_post_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_PRE);
- if (hookFunc(te) == RPMRC_FAIL)
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(scriptlet_fork_post);
+ if (hookFunc && hookFunc(plugin, path, type) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook scriplet_fork_post failed\n", plugin->name);
rc = RPMRC_FAIL;
+ }
}
return rc;
}
-rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te, int res)
+rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int type, int res)
{
- rpmRC (*hookFunc)(rpmte, int);
+ plugin_scriptlet_post_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_POST);
- if (hookFunc(te, res) == RPMRC_FAIL)
- rc = RPMRC_FAIL;
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(scriptlet_post);
+ if (hookFunc && hookFunc(plugin, s_name, type, res) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_WARNING, "Plugin %s: hook scriplet_post failed\n", plugin->name);
+ }
}
return rc;
}
-rpmRC rpmpluginsCallScriptletPre(rpmPlugins plugins, const char *s_name, int type)
+rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
+ mode_t file_mode, rpmFsmOp op)
{
- rpmRC (*hookFunc)(const char*, int);
+ plugin_fsm_file_pre_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPTLET_PRE);
- if (hookFunc(s_name, type) == RPMRC_FAIL)
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);
+ if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
rc = RPMRC_FAIL;
+ }
}
return rc;
}
-rpmRC rpmpluginsCallScriptletForkPost(rpmPlugins plugins, const char *path, int type)
+rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,
+ mode_t file_mode, rpmFsmOp op, int res)
{
- rpmRC (*hookFunc)(const char*, int);
+ plugin_fsm_file_post_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPTLET_FORK_POST);
- if (hookFunc(path, type) == RPMRC_FAIL)
- rc = RPMRC_FAIL;
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_post);
+ if (hookFunc && hookFunc(plugin, fi, path, file_mode, op, res) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_WARNING, "Plugin %s: hook fsm_file_post failed\n", plugin->name);
+ }
}
return rc;
}
-rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int type, int res)
+rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+ const char *path, const char *dest,
+ mode_t file_mode, rpmFsmOp op)
{
- rpmRC (*hookFunc)(const char*, int, int);
+ plugin_fsm_file_prepare_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPTLET_POST);
- if (hookFunc(s_name, type, res) == RPMRC_FAIL)
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_prepare);
+ if (hookFunc && hookFunc(plugin, fi, path, dest, file_mode, op) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_prepare failed\n", plugin->name);
rc = RPMRC_FAIL;
+ }
}
return rc;
}
-rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd sigtd,
+rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, int sigTagId,
pgpDigParams sig, DIGEST_CTX ctx, int res)
{
- rpmRC (*hookFunc)(rpmKeyring, rpmtd, pgpDigParams, DIGEST_CTX, int);
+ plugin_psm_verify_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
+
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_VERIFY);
- if (hookFunc(keyring, sigtd, sig, ctx, res) == RPMRC_FAIL)
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(psm_verify);
+
+ if (hookFunc && hookFunc(keyring, sigTagId, sig, ctx, res) == RPMRC_FAIL)
+ {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook psm_verify failed\n", plugin->name);
rc = RPMRC_FAIL;
+ }
}
return rc;
@@ -336,16 +433,21 @@ rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd sigtd,
rpmRC rpmpluginsCallFsmInit(rpmPlugins plugins, const char* path,
mode_t mode)
{
- rpmRC (*hookFunc)(const char*, mode_t);
+ plugin_fsm_file_init_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
+
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FSM_INIT);
- if (hookFunc(path, mode) == RPMRC_FAIL)
- rc = RPMRC_FAIL;
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_init);
+
+ if (hookFunc && hookFunc(path, mode) == RPMRC_FAIL)
+ {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_init failed\n", plugin->name);
+ rc = RPMRC_FAIL;
+
+ }
}
return rc;
@@ -354,16 +456,19 @@ rpmRC rpmpluginsCallFsmInit(rpmPlugins plugins, const char* path,
rpmRC rpmpluginsCallFsmCommit(rpmPlugins plugins, const char* path,
mode_t mode, int type)
{
- rpmRC (*hookFunc)(const char*, mode_t, int);
+ plugin_fsm_file_commit_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FSM_COMMIT);
- if (hookFunc(path, mode, type) == RPMRC_FAIL)
- rc = RPMRC_FAIL;
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_commit);
+
+ if (hookFunc && hookFunc(path, mode, type) == RPMRC_FAIL)
+ {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_commit failed\n", plugin->name);
+ rc = RPMRC_FAIL;
+ }
}
return rc;
@@ -372,17 +477,22 @@ rpmRC rpmpluginsCallFsmCommit(rpmPlugins plugins, const char* path,
rpmRC rpmpluginsCallFileConflict(rpmPlugins plugins, rpmts ts, char* path,
Header oldHeader, rpmfi oldFi, int res)
{
- rpmRC (*hookFunc)(rpmts, char*, Header, rpmfi, int);
+ plugin_fsm_file_conflict_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
- const char *name = NULL;
for (i = 0; i < plugins->count; i++) {
- name = plugins->names[i];
- RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FILE_CONFLICT);
- if (hookFunc(ts, path, oldHeader, oldFi, res) == RPMRC_FAIL)
- rc = RPMRC_FAIL;
+ rpmPlugin plugin = plugins->plugins[i];
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_conflict);
+
+ if (hookFunc && hookFunc(ts, path, oldHeader, oldFi, res) == RPMRC_FAIL)
+ {
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_conflict failed\n", plugin->name);
+ rc = RPMRC_FAIL;
+ }
}
return rc;
}
+
+
diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
index 8e35d81ab..0ef6e3eb4 100644
--- a/lib/rpmplugins.h
+++ b/lib/rpmplugins.h
@@ -2,79 +2,19 @@
#define _PLUGINS_H
#include <rpm/rpmtypes.h>
+#include <rpm/rpmfi.h>
+#include "lib/rpmplugin.h"
#ifdef __cplusplus
extern "C" {
#endif
-#define PLUGIN_HOOKS plugin_hooks
-
-#define PLUGINHOOK_INIT_FUNC pluginhook_init
-#define PLUGINHOOK_CLEANUP_FUNC pluginhook_cleanup
-
-#define PLUGINHOOK_OPENTE_FUNC pluginhook_opente
-#define PLUGINHOOK_COLL_POST_ADD_FUNC pluginhook_coll_post_add
-#define PLUGINHOOK_COLL_POST_ANY_FUNC pluginhook_coll_post_any
-#define PLUGINHOOK_COLL_PRE_REMOVE_FUNC pluginhook_coll_pre_remove
-
-#define PLUGINHOOK_TSM_PRE_FUNC pluginhook_tsm_pre
-#define PLUGINHOOK_TSM_POST_FUNC pluginhook_tsm_post
-
-#define PLUGINHOOK_PSM_PRE_FUNC pluginhook_psm_pre
-#define PLUGINHOOK_PSM_POST_FUNC pluginhook_psm_post
-#define PLUGINHOOK_VERIFY_FUNC pluginhook_verify
-
-#define PLUGINHOOK_SCRIPTLET_PRE_FUNC pluginhook_scriptlet_pre
-#define PLUGINHOOK_SCRIPTLET_FORK_POST_FUNC pluginhook_scriptlet_fork_post
-#define PLUGINHOOK_SCRIPTLET_POST_FUNC pluginhook_scriptlet_post
-
-#define PLUGINHOOK_FSM_INIT_FUNC pluginhook_fsm_init
-#define PLUGINHOOK_FSM_COMMIT_FUNC pluginhook_fsm_commit
-#define PLUGINHOOK_FILE_CONFLICT pluginhook_file_conflict
-
-enum rpmPluginHook_e {
- PLUGINHOOK_NONE = 0,
- PLUGINHOOK_INIT = 1 << 0,
- PLUGINHOOK_CLEANUP = 1 << 1,
- PLUGINHOOK_OPENTE = 1 << 2,
- PLUGINHOOK_COLL_POST_ADD = 1 << 3,
- PLUGINHOOK_COLL_POST_ANY = 1 << 4,
- PLUGINHOOK_COLL_PRE_REMOVE = 1 << 5,
- PLUGINHOOK_TSM_PRE = 1 << 6,
- PLUGINHOOK_TSM_POST = 1 << 7,
- PLUGINHOOK_PSM_PRE = 1 << 8,
- PLUGINHOOK_PSM_POST = 1 << 9,
- PLUGINHOOK_SCRIPTLET_PRE = 1 << 10,
- PLUGINHOOK_SCRIPTLET_FORK_POST = 1 << 11,
- PLUGINHOOK_SCRIPTLET_POST = 1 << 12,
- PLUGINHOOK_VERIFY = 1 << 13,
- PLUGINHOOK_FSM_INIT = 1 << 14,
- PLUGINHOOK_FSM_COMMIT = 1 << 15,
- PLUGINHOOK_FILE_CONFLICT = 1 << 16
-
-};
-
-/* indicates if a directory is part of rpm package or created by rpm itself */
-typedef enum rpmPluginDirType_e {
- DIR_TYPE_NONE = 0,
- DIR_TYPE_NORMAL = 1 << 0,
- DIR_TYPE_UNOWNED = 1 << 1
-} rpmPluginDirType;
-
-/* indicates the way the scriptlet is executed */
-typedef enum rpmScriptletExecutionFlow_e {
- RPMSCRIPTLET_NONE = 0,
- RPMSCRIPTLET_FORK = 1 << 0,
- RPMSCRIPTLET_EXEC = 1 << 1
-} rpmScriptletExecutionFlow;
-
-typedef rpmFlags rpmPluginHook;
-
/** \ingroup rpmplugins
* Create a new plugins structure
* @param ts transaction set
* @return new plugin structure
*/
+RPM_GNUC_INTERNAL
rpmPlugins rpmpluginsNew(rpmts ts);
/** \ingroup rpmplugins
@@ -82,6 +22,7 @@ rpmPlugins rpmpluginsNew(rpmts ts);
* @param plugins plugins structure to destroy
* @return NULL always
*/
+RPM_GNUC_INTERNAL
rpmPlugins rpmpluginsFree(rpmPlugins plugins);
/** \ingroup rpmplugins
@@ -92,15 +33,17 @@ rpmPlugins rpmpluginsFree(rpmPlugins plugins);
* @param opts options to pass to the plugin
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsAdd(rpmPlugins plugins, const char *name, const char *path, const char *opts);
/** \ingroup rpmplugins
* Add and open a rpm plugin
- * @param plugins plugins structure to add a collection plugin to
+ * @param plugins plugins structure to add a plugin to
* @param type type of plugin
* @param name name of plugin
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name);
/** \ingroup rpmplugins
@@ -109,65 +52,16 @@ rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name
* @param name name of plugin to check
* @return 1 if plugin name has already been added, 0 otherwise
*/
+RPM_GNUC_INTERNAL
int rpmpluginsPluginAdded(rpmPlugins plugins, const char *name);
-
-/** \ingroup rpmplugins
- * Call the init plugin hook
- * @param plugins plugins structure
- * @param name name of plugin
- * @param opts plugin options
- * @return RPMRC_OK on success, RPMRC_FAIL otherwise
- */
-rpmRC rpmpluginsCallInit(rpmPlugins plugins, const char *name, const char *opts);
-
-/** \ingroup rpmplugins
- * Call the cleanup plugin hook
- * @param plugins plugins structure
- * @param name name of plugin
- * @return RPMRC_OK on success, RPMRC_FAIL otherwise
- */
-rpmRC rpmpluginsCallCleanup(rpmPlugins plugins, const char *name);
-
-/** \ingroup rpmplugins
- * Call the open te plugin hook
- * @param plugins plugins structure
- * @param name name of plugin
- * @param te transaction element opened
- * @return RPMRC_OK on success, RPMRC_FAIL otherwise
- */
-rpmRC rpmpluginsCallOpenTE(rpmPlugins plugins, const char *name, rpmte te);
-
-/** \ingroup rpmplugins
- * Call the collection post add plugin hook
- * @param plugins plugins structure
- * @param name name of plugin
- * @return RPMRC_OK on success, RPMRC_FAIL otherwise
- */
-rpmRC rpmpluginsCallCollectionPostAdd(rpmPlugins plugins, const char *name);
-
-/** \ingroup rpmplugins
- * Call the collection post any plugin hook
- * @param plugins plugins structure
- * @param name name of plugin
- * @return RPMRC_OK on success, RPMRC_FAIL otherwise
- */
-rpmRC rpmpluginsCallCollectionPostAny(rpmPlugins plugins, const char *name);
-
-/** \ingroup rpmplugins
- * Call the collection pre remove plugin hook
- * @param plugins plugins structure
- * @param name name of plugin
- * @return RPMRC_OK on success, RPMRC_FAIL otherwise
- */
-rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins plugins, const char *name);
-
/** \ingroup rpmplugins
* Call the pre transaction plugin hook
* @param plugins plugins structure
* @param ts processed transaction
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts);
/** \ingroup rpmplugins
@@ -177,6 +71,7 @@ rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts);
* @param res transaction result code
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts, int res);
/** \ingroup rpmplugins
@@ -185,6 +80,7 @@ rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts, int res);
* @param te processed transaction element
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te);
/** \ingroup rpmplugins
@@ -194,6 +90,7 @@ rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te);
* @param res transaction element result code
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te, int res);
/** \ingroup rpmplugins
@@ -203,6 +100,7 @@ rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te, int res);
* @param type indicates the scriptlet execution flow, see rpmScriptletExecutionFlow
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallScriptletPre(rpmPlugins plugins, const char *s_name, int type);
/** \ingroup rpmplugins
@@ -212,6 +110,7 @@ rpmRC rpmpluginsCallScriptletPre(rpmPlugins plugins, const char *s_name, int typ
* @param type indicates the scriptlet execution flow, see rpmScriptletExecutionFlow
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallScriptletForkPost(rpmPlugins plugins, const char *path, int type);
/** \ingroup rpmplugins
@@ -222,9 +121,52 @@ rpmRC rpmpluginsCallScriptletForkPost(rpmPlugins plugins, const char *path, int
* @param res scriptlet execution result code
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int type, int res);
/** \ingroup rpmplugins
+ * Call the fsm file pre plugin hook
+ * @param plugins plugins structure
+ * @param fi file info iterator (or NULL)
+ * @param path file object path
+ * @param file_mode file object mode
+ * @param op file operation + associated flags
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char* path,
+ mode_t file_mode, rpmFsmOp op);
+
+/** \ingroup rpmplugins
+ * Call the fsm file post plugin hook
+ * @param plugins plugins structure
+ * @param fi file info iterator (or NULL)
+ * @param path file object path
+ * @param file_mode file object mode
+ * @param op file operation + associated flags
+ * @param res fsm result code
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,
+ mode_t file_mode, rpmFsmOp op, int res);
+
+/** \ingroup rpmplugins
+ * Call the fsm file prepare plugin hook. Called after setting
+ * permissions etc, but before committing file to destination path.
+ * @param plugins plugins structure
+ * @param fi file info iterator (or NULL)
+ * @param path file object current path
+ * @param dest file object destination path
+ * @param mode file object mode
+ * @param op file operation + associated flags
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+ const char *path, const char *dest,
+ mode_t mode, rpmFsmOp op);
+/** \ingroup rpmplugins
* Call the verify hook
* @param plugins plugins structure
* @param keyring RPM keyring
@@ -233,7 +175,8 @@ rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int ty
* @param res scriptlet execution result code
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
-rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd sigtd,
+RPM_GNUC_INTERNAL
+rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, int sigTagId,
pgpDigParams sig, DIGEST_CTX ctx, int res);
/** \ingroup rpmplugins
@@ -243,8 +186,9 @@ rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd sigtd,
* @param mode file mode
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallFsmInit(rpmPlugins plugins, const char* path, mode_t mode);
-
+
/** \ingroup rpmplugins
* Call the fsm commit hook
* @param plugins plugins structure
@@ -253,6 +197,7 @@ rpmRC rpmpluginsCallFsmInit(rpmPlugins plugins, const char* path, mode_t mode);
* @param type file type
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallFsmCommit(rpmPlugins plugins, const char* path, mode_t mode, int type);
/** \ingroup rpmplugins
@@ -265,8 +210,10 @@ rpmRC rpmpluginsCallFsmCommit(rpmPlugins plugins, const char* path, mode_t mode,
* @param res return code
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
+RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallFileConflict(rpmPlugins plugins, rpmts ts, char* path, Header oldHeader, rpmfi oldFi, int res);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/rpmprob.h b/lib/rpmprob.h
index 2b89f15ef..ac57885c6 100644
--- a/lib/rpmprob.h
+++ b/lib/rpmprob.h
@@ -43,7 +43,7 @@ typedef enum rpmProblemType_e {
RPMPROB_BADRELOCATE,/*!< path ... is not relocatable for package ... */
RPMPROB_REQUIRES, /*!< package ... has unsatisfied Requires: ... */
RPMPROB_CONFLICT, /*!< package ... has unsatisfied Conflicts: ... */
- RPMPROB_NEW_FILE_CONFLICT, /*!< file ... conflicts between attemped installs of ... */
+ RPMPROB_NEW_FILE_CONFLICT, /*!< file ... conflicts between attempted installs of ... */
RPMPROB_FILE_CONFLICT,/*!< file ... from install of ... conflicts with file from package ... */
RPMPROB_OLDPACKAGE, /*!< package ... (which is newer than ...) is already installed */
RPMPROB_DISKSPACE, /*!< installing package ... needs ... on the ... filesystem */
diff --git a/lib/rpmrc.c b/lib/rpmrc.c
index 7638e8114..cada3f788 100644
--- a/lib/rpmrc.c
+++ b/lib/rpmrc.c
@@ -1,6 +1,7 @@
#include "system.h"
#include <stdarg.h>
+#include <pthread.h>
#if defined(__linux__)
#include <elf.h>
@@ -11,7 +12,6 @@
#if HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif
-#include <netdb.h>
#include <ctype.h> /* XXX for /etc/rpm/platform contents */
#if HAVE_SYS_SYSTEMCFG_H
@@ -20,32 +20,32 @@
#define __power_pc() 0
#endif
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+
#include <rpm/rpmlib.h> /* RPM_MACTABLE*, Rc-prototypes */
#include <rpm/rpmmacro.h>
#include <rpm/rpmfileutil.h>
#include <rpm/rpmstring.h>
#include <rpm/rpmlog.h>
+#include <rpm/argv.h>
#include "rpmio/rpmlua.h"
#include "rpmio/rpmio_internal.h" /* XXX for rpmioSlurp */
#include "lib/misc.h"
#include "lib/rpmliblua.h"
+#include "lib/rpmug.h"
#include "debug.h"
static const char * defrcfiles = NULL;
const char * macrofiles = NULL;
-static const char * const platform = SYSCONFDIR "/rpm/platform";
-static char ** platpat = NULL;
-static int nplatpat = 0;
-
-typedef char * cptr_t;
-
typedef struct machCacheEntry_s {
char * name;
int count;
- cptr_t * equivs;
+ char ** equivs;
int visited;
} * machCacheEntry;
@@ -111,13 +111,6 @@ typedef struct tableType_s {
int canonsLength;
} * tableType;
-static struct tableType_s tables[RPM_MACHTABLE_COUNT] = {
- { "arch", 1, 0 },
- { "os", 1, 0 },
- { "buildarch", 0, 1 },
- { "buildos", 0, 1 }
-};
-
/* XXX get rid of this stuff... */
/* Stuff for maintaining "variables" like SOURCEDIR, BUILDDIR, etc */
#define RPMVAR_OPTFLAGS 3
@@ -142,23 +135,58 @@ static const size_t optionTableSize = sizeof(optionTable) / sizeof(*optionTable)
#define OS 0
#define ARCH 1
-static cptr_t current[2];
+typedef struct rpmrcCtx_s * rpmrcCtx;
+struct rpmrcCtx_s {
+ ARGV_t platpat;
+ char *current[2];
+ int currTables[2];
+ struct rpmvarValue values[RPMVAR_NUM];
+ struct tableType_s tables[RPM_MACHTABLE_COUNT];
+ int machDefaults;
+ int pathDefaults;
+ pthread_rwlock_t lock;
+};
-static int currTables[2] = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH };
+/* prototypes */
+static rpmRC doReadRC(rpmrcCtx ctx, const char * urlfn);
-static struct rpmvarValue values[RPMVAR_NUM];
+static void rpmSetVarArch(rpmrcCtx ctx,
+ int var, const char * val, const char * arch);
-static int defaultsInitialized = 0;
+static void rebuildCompatTables(rpmrcCtx ctx, int type, const char * name);
-/* prototypes */
-static rpmRC doReadRC(const char * urlfn);
+static void rpmRebuildTargetVars(rpmrcCtx ctx, const char **target, const char ** canontarget);
-static void rpmSetVarArch(int var, const char * val,
- const char * arch);
+/* Force context (lock) acquisition through a function */
+static rpmrcCtx rpmrcCtxAcquire(int write)
+{
+ static struct rpmrcCtx_s _globalCtx = {
+ .lock = PTHREAD_RWLOCK_INITIALIZER,
+ .currTables = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH },
+ .tables = {
+ { "arch", 1, 0 },
+ { "os", 1, 0 },
+ { "buildarch", 0, 1 },
+ { "buildos", 0, 1 }
+ },
+ };
+ rpmrcCtx ctx = &_globalCtx;
+
+ /* XXX: errors should be handled */
+ if (write)
+ pthread_rwlock_wrlock(&ctx->lock);
+ else
+ pthread_rwlock_rdlock(&ctx->lock);
-static void rebuildCompatTables(int type, const char * name);
+ return ctx;
+}
-static void rpmRebuildTargetVars(const char **target, const char ** canontarget);
+/* Release context (lock) */
+static rpmrcCtx rpmrcCtxRelease(rpmrcCtx ctx)
+{
+ pthread_rwlock_unlock(&ctx->lock);
+ return NULL;
+}
static int optionCompare(const void * a, const void * b)
{
@@ -452,7 +480,7 @@ static void setDefaults(void)
}
/* FIX: se usage inconsistent, W2DO? */
-static rpmRC doReadRC(const char * urlfn)
+static rpmRC doReadRC(rpmrcCtx ctx, const char * urlfn)
{
char *s;
char *se, *next, *buf = NULL, *fn;
@@ -519,7 +547,7 @@ static rpmRC doReadRC(const char * urlfn)
while (*se && !risspace(*se)) se++;
if (*se != '\0') *se = '\0';
- if (doReadRC(s)) {
+ if (doReadRC(ctx, s)) {
rpmlog(RPMLOG_ERR, _("cannot open %s at %s:%d: %m\n"),
s, fn, linenum);
goto exit;
@@ -551,48 +579,49 @@ static rpmRC doReadRC(const char * urlfn)
/* Only add macros if appropriate for this arch */
if (option->macroize &&
- (arch == NULL || rstreq(arch, current[ARCH]))) {
+ (arch == NULL || rstreq(arch, ctx->current[ARCH]))) {
char *n, *name;
n = name = xmalloc(strlen(option->name)+2);
if (option->localize)
*n++ = '_';
strcpy(n, option->name);
- addMacro(NULL, name, NULL, val, RMIL_RPMRC);
+ rpmPushMacro(NULL, name, NULL, val, RMIL_RPMRC);
free(name);
}
- rpmSetVarArch(option->var, val, arch);
+ rpmSetVarArch(ctx, option->var, val, arch);
fn = _free(fn);
- } else { /* For arch/os compatibilty tables ... */
+ } else { /* For arch/os compatibility tables ... */
int gotit;
int i;
gotit = 0;
for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
- if (rstreqn(tables[i].key, s, strlen(tables[i].key)))
+ if (rstreqn(ctx->tables[i].key, s, strlen(ctx->tables[i].key)))
break;
}
if (i < RPM_MACHTABLE_COUNT) {
- const char *rest = s + strlen(tables[i].key);
+ const char *rest = s + strlen(ctx->tables[i].key);
if (*rest == '_') rest++;
if (rstreq(rest, "compat")) {
if (machCompatCacheAdd(se, fn, linenum,
- &tables[i].cache))
+ &ctx->tables[i].cache))
goto exit;
gotit = 1;
- } else if (tables[i].hasTranslate &&
+ } else if (ctx->tables[i].hasTranslate &&
rstreq(rest, "translate")) {
- if (addDefault(&tables[i].defaults,
- &tables[i].defaultsLength,
+ if (addDefault(&ctx->tables[i].defaults,
+ &ctx->tables[i].defaultsLength,
se, fn, linenum))
goto exit;
gotit = 1;
- } else if (tables[i].hasCanon &&
+ } else if (ctx->tables[i].hasCanon &&
rstreq(rest, "canon")) {
- if (addCanon(&tables[i].canons, &tables[i].canonsLength,
+ if (addCanon(&ctx->tables[i].canons,
+ &ctx->tables[i].canonsLength,
se, fn, linenum))
goto exit;
gotit = 1;
@@ -618,7 +647,7 @@ exit:
/**
*/
-static rpmRC rpmPlatform(const char * platform)
+static rpmRC rpmPlatform(rpmrcCtx ctx, const char * platform)
{
const char *cpu = NULL, *vendor = NULL, *os = NULL, *gnu = NULL;
uint8_t * b = NULL;
@@ -651,10 +680,7 @@ static rpmRC rpmPlatform(const char * platform)
while (--t > p && isspace(*t))
*t = '\0';
if (t > p) {
- platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
- platpat[nplatpat] = xstrdup(p);
- nplatpat++;
- platpat[nplatpat] = NULL;
+ argvAdd(&ctx->platpat, p);
}
continue;
}
@@ -690,14 +716,14 @@ static rpmRC rpmPlatform(const char * platform)
if (*p != '\0') *p = '\0';
}
- addMacro(NULL, "_host_cpu", NULL, cpu, -1);
- addMacro(NULL, "_host_vendor", NULL, vendor, -1);
- addMacro(NULL, "_host_os", NULL, os, -1);
+ rpmPushMacro(NULL, "_host_cpu", NULL, cpu, -1);
+ rpmPushMacro(NULL, "_host_vendor", NULL, vendor, -1);
+ rpmPushMacro(NULL, "_host_os", NULL, os, -1);
- platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
- platpat[nplatpat] = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}", (gnu && *gnu ? "-" : NULL), gnu, NULL);
- nplatpat++;
- platpat[nplatpat] = NULL;
+ char *plat = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}",
+ (gnu && *gnu ? "-" : NULL), gnu, NULL);
+ argvAdd(&ctx->platpat, plat);
+ free(plat);
init_platform++;
}
@@ -789,8 +815,21 @@ static inline int RPMClass(void)
cpu = (tfms>>8)&15;
+ if (cpu == 5
+ && cpuid_ecx(0) == '68xM'
+ && cpuid_edx(0) == 'Teni'
+ && (cpuid_edx(1) & ((1<<8)|(1<<15))) == ((1<<8)|(1<<15))) {
+ sigaction(SIGILL, &oldsa, NULL);
+ return 6; /* has CX8 and CMOV */
+ }
+
sigaction(SIGILL, &oldsa, NULL);
+#define USER686 ((1<<4) | (1<<8) | (1<<15))
+ /* Transmeta Crusoe CPUs say that their CPU family is "5" but they have enough features for i686. */
+ if (cpu == 5 && (cap & USER686) == USER686)
+ return 6;
+
if (cpu < 6)
return cpu;
@@ -912,13 +951,19 @@ static int is_geode(void)
#if defined(__linux__)
/**
- * Populate rpmat structure with parsed info from /proc/self/auxv
+ * Populate rpmat structure with auxv values
*/
-static void parse_auxv(void)
+static void read_auxv(void)
{
static int oneshot = 1;
if (oneshot) {
+#ifdef HAVE_GETAUXVAL
+ rpmat.platform = (char *) getauxval(AT_PLATFORM);
+ if (!rpmat.platform)
+ rpmat.platform = "";
+ rpmat.hwcap = getauxval(AT_HWCAP);
+#else
rpmat.platform = "";
int fd = open("/proc/self/auxv", O_RDONLY);
@@ -943,6 +988,7 @@ static void parse_auxv(void)
}
close(fd);
}
+#endif
oneshot = 0; /* only try once even if it fails */
}
return;
@@ -951,22 +997,21 @@ static void parse_auxv(void)
/**
*/
-static void defaultMachine(const char ** arch,
- const char ** os)
+static void defaultMachine(rpmrcCtx ctx, const char ** arch, const char ** os)
{
+ const char * const platform_path = SYSCONFDIR "/rpm/platform";
static struct utsname un;
- static int gotDefaults = 0;
char * chptr;
canonEntry canon;
int rc;
#if defined(__linux__)
/* Populate rpmat struct with hw info */
- parse_auxv();
+ read_auxv();
#endif
- while (!gotDefaults) {
- if (!rpmPlatform(platform)) {
+ while (!ctx->machDefaults) {
+ if (!rpmPlatform(ctx, platform_path)) {
char * s = rpmExpand("%{_host_cpu}", NULL);
if (s) {
rstrlcpy(un.machine, s, sizeof(un.machine));
@@ -977,7 +1022,7 @@ static void defaultMachine(const char ** arch,
rstrlcpy(un.sysname, s, sizeof(un.sysname));
free(s);
}
- gotDefaults = 1;
+ ctx->machDefaults = 1;
break;
}
rc = uname(&un);
@@ -988,11 +1033,15 @@ static void defaultMachine(const char ** arch,
strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
sprintf(un.sysname,"aix%s.%s", un.version, un.release);
}
- else if(rstreq(un.sysname, "Darwin")) {
-#ifdef __ppc__
+ else if (rstreq(un.sysname, "Darwin")) {
+#if defined(__ppc__)
strcpy(un.machine, "ppc");
-#else ifdef __i386__
+#elif defined(__i386__)
strcpy(un.machine, "i386");
+#elif defined(__x86_64__)
+ strcpy(un.machine, "x86_64");
+#else
+ #warning "No architecture defined! Automatic detection may not work!"
#endif
}
else if (rstreq(un.sysname, "SunOS")) {
@@ -1020,12 +1069,54 @@ static void defaultMachine(const char ** arch,
# if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
/* little endian */
- strcpy(un.machine, "mipsel");
+# if defined(__mips64)
+ /* 64-bit */
+# if !defined(__mips_isa_rev) || __mips_isa_rev < 6
+ /* r1-r5 */
+ strcpy(un.machine, "mips64el");
+# else
+ /* r6 */
+ strcpy(un.machine, "mips64r6el");
+# endif
+# else
+ /* 32-bit */
+# if !defined(__mips_isa_rev) || __mips_isa_rev < 6
+ /* r1-r5 */
+ strcpy(un.machine, "mipsel");
+# else
+ /* r6 */
+ strcpy(un.machine, "mipsr6el");
+# endif
+# endif
# elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
/* big endian */
- strcpy(un.machine, "mips");
+# if defined(__mips64)
+ /* 64-bit */
+# if !defined(__mips_isa_rev) || __mips_isa_rev < 6
+ /* r1-r5 */
+ strcpy(un.machine, "mips64");
+# else
+ /* r6 */
+ strcpy(un.machine, "mips64r6");
+# endif
+# else
+ /* 32-bit */
+# if !defined(__mips_isa_rev) || __mips_isa_rev < 6
+ /* r1-r5 */
+ strcpy(un.machine, "mips");
+# else
+ /* r6 */
+ strcpy(un.machine, "mipsr6");
+# endif
+# endif
# endif
+#if defined(__linux__)
+ /* in linux, lets rename parisc to hppa */
+ if (rstreq(un.machine, "parisc"))
+ strcpy(un.machine, "hppa");
+#endif
+
# if defined(__hpux) && defined(_SC_CPU_VERSION)
{
# if !defined(CPU_PA_RISC1_2)
@@ -1069,6 +1160,9 @@ static void defaultMachine(const char ** arch,
# endif /* hpux */
# if defined(__linux__) && defined(__sparc__)
+# if !defined(HWCAP_SPARC_BLKINIT)
+# define HWCAP_SPARC_BLKINIT 0x00000040
+# endif
if (rstreq(un.machine, "sparc")) {
#define PERS_LINUX 0x00000000
#define PERS_LINUX_32BIT 0x00800000
@@ -1088,10 +1182,20 @@ static void defaultMachine(const char ** arch,
}
personality(oldpers);
}
+
+ /* This is how glibc detects Niagara so... */
+ if (rpmat.hwcap & HWCAP_SPARC_BLKINIT) {
+ if (rstreq(un.machine, "sparcv9") || rstreq(un.machine, "sparc")) {
+ strcpy(un.machine, "sparcv9v");
+ } else if (rstreq(un.machine, "sparc64")) {
+ strcpy(un.machine, "sparc64v");
+ }
+ }
}
# endif /* sparc*-linux */
# if defined(__linux__) && defined(__powerpc__)
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
{
int powerlvl;
if (!rstreq(un.machine, "ppc") &&
@@ -1100,8 +1204,43 @@ static void defaultMachine(const char ** arch,
strcpy(un.machine, "ppc64p7");
}
}
+# endif /* __ORDER_BIG_ENDIAN__ */
# endif /* ppc64*-linux */
+# if defined(__linux__) && defined(__arm__) && defined(__ARM_PCS_VFP)
+# if !defined(HWCAP_ARM_VFP)
+# define HWCAP_ARM_VFP (1 << 6)
+# endif
+# if !defined(HWCAP_ARM_NEON)
+# define HWCAP_ARM_NEON (1 << 12)
+# endif
+# if !defined(HWCAP_ARM_VFPv3)
+# define HWCAP_ARM_VFPv3 (1 << 13)
+# endif
+ if (rstreq(un.machine, "armv7l")) {
+ if (rpmat.hwcap & HWCAP_ARM_VFPv3) {
+ if (rpmat.hwcap & HWCAP_ARM_NEON)
+ strcpy(un.machine, "armv7hnl");
+ else
+ strcpy(un.machine, "armv7hl");
+ }
+ } else if (rstreq(un.machine, "armv6l")) {
+ if (rpmat.hwcap & HWCAP_ARM_VFP)
+ strcpy(un.machine, "armv6hl");
+ }
+# endif /* arm*-linux */
+
+# if defined(__linux__) && defined(__riscv__)
+ if (rstreq(un.machine, "riscv")) {
+ if (sizeof(long) == 4)
+ strcpy(un.machine, "riscv32");
+ else if (sizeof(long) == 8)
+ strcpy(un.machine, "riscv64");
+ else if (sizeof(long) == 16)
+ strcpy(un.machine, "riscv128");
+ }
+# endif /* riscv */
+
# if defined(__GNUC__) && defined(__alpha__)
{
unsigned long amask, implver;
@@ -1147,17 +1286,17 @@ static void defaultMachine(const char ** arch,
/* the uname() result goes through the arch_canon table */
canon = lookupInCanonTable(un.machine,
- tables[RPM_MACHTABLE_INSTARCH].canons,
- tables[RPM_MACHTABLE_INSTARCH].canonsLength);
+ ctx->tables[RPM_MACHTABLE_INSTARCH].canons,
+ ctx->tables[RPM_MACHTABLE_INSTARCH].canonsLength);
if (canon)
rstrlcpy(un.machine, canon->short_name, sizeof(un.machine));
canon = lookupInCanonTable(un.sysname,
- tables[RPM_MACHTABLE_INSTOS].canons,
- tables[RPM_MACHTABLE_INSTOS].canonsLength);
+ ctx->tables[RPM_MACHTABLE_INSTOS].canons,
+ ctx->tables[RPM_MACHTABLE_INSTOS].canonsLength);
if (canon)
rstrlcpy(un.sysname, canon->short_name, sizeof(un.sysname));
- gotDefaults = 1;
+ ctx->machDefaults = 1;
break;
}
@@ -1166,34 +1305,30 @@ static void defaultMachine(const char ** arch,
}
static
-const char * rpmGetVarArch(int var, const char * arch)
+const char * rpmGetVarArch(rpmrcCtx ctx, int var, const char * arch)
{
const struct rpmvarValue * next;
- if (arch == NULL) arch = current[ARCH];
+ if (arch == NULL) arch = ctx->current[ARCH];
if (arch) {
- next = &values[var];
+ next = &ctx->values[var];
while (next) {
if (next->arch && rstreq(next->arch, arch)) return next->value;
next = next->next;
}
}
- next = values + var;
+ next = ctx->values + var;
while (next && next->arch) next = next->next;
return next ? next->value : NULL;
}
-static const char *rpmGetVar(int var)
-{
- return rpmGetVarArch(var, NULL);
-}
-
-static void rpmSetVarArch(int var, const char * val, const char * arch)
+static void rpmSetVarArch(rpmrcCtx ctx,
+ int var, const char * val, const char * arch)
{
- struct rpmvarValue * next = values + var;
+ struct rpmvarValue * next = ctx->values + var;
if (next->value) {
if (arch) {
@@ -1225,39 +1360,23 @@ static void rpmSetVarArch(int var, const char * val, const char * arch)
next->arch = (arch ? xstrdup(arch) : NULL);
}
-static void rpmSetTables(int archTable, int osTable)
+static void rpmSetTables(rpmrcCtx ctx, int archTable, int osTable)
{
const char * arch, * os;
- defaultMachine(&arch, &os);
+ defaultMachine(ctx, &arch, &os);
- if (currTables[ARCH] != archTable) {
- currTables[ARCH] = archTable;
- rebuildCompatTables(ARCH, arch);
+ if (ctx->currTables[ARCH] != archTable) {
+ ctx->currTables[ARCH] = archTable;
+ rebuildCompatTables(ctx, ARCH, arch);
}
- if (currTables[OS] != osTable) {
- currTables[OS] = osTable;
- rebuildCompatTables(OS, os);
+ if (ctx->currTables[OS] != osTable) {
+ ctx->currTables[OS] = osTable;
+ rebuildCompatTables(ctx, OS, os);
}
}
-int rpmMachineScore(int type, const char * name)
-{
- machEquivInfo info = NULL;
- if (name)
- info = machEquivSearch(&tables[type].equiv, name);
- return info ? info->score : 0;
-}
-
-int rpmIsKnownArch(const char *name)
-{
- canonEntry canon = lookupInCanonTable(name,
- tables[RPM_MACHTABLE_INSTARCH].canons,
- tables[RPM_MACHTABLE_INSTARCH].canonsLength);
- return (canon != NULL || rstreq(name, "noarch"));
-}
-
/** \ingroup rpmrc
* Set current arch/os names.
* NULL as argument is set to the default value (munged uname())
@@ -1265,43 +1384,44 @@ int rpmIsKnownArch(const char *name)
* @deprecated Use addMacro to set _target_* macros.
* @todo Eliminate
*
+ * @param ctx rpmrc context
* @param arch arch name (or NULL)
* @param os os name (or NULL)
* */
-static void rpmSetMachine(const char * arch, const char * os)
+static void rpmSetMachine(rpmrcCtx ctx, const char * arch, const char * os)
{
const char * host_cpu, * host_os;
- defaultMachine(&host_cpu, &host_os);
+ defaultMachine(ctx, &host_cpu, &host_os);
if (arch == NULL) {
arch = host_cpu;
- if (tables[currTables[ARCH]].hasTranslate)
+ if (ctx->tables[ctx->currTables[ARCH]].hasTranslate)
arch = lookupInDefaultTable(arch,
- tables[currTables[ARCH]].defaults,
- tables[currTables[ARCH]].defaultsLength);
+ ctx->tables[ctx->currTables[ARCH]].defaults,
+ ctx->tables[ctx->currTables[ARCH]].defaultsLength);
}
if (arch == NULL) return; /* XXX can't happen */
if (os == NULL) {
os = host_os;
- if (tables[currTables[OS]].hasTranslate)
+ if (ctx->tables[ctx->currTables[OS]].hasTranslate)
os = lookupInDefaultTable(os,
- tables[currTables[OS]].defaults,
- tables[currTables[OS]].defaultsLength);
+ ctx->tables[ctx->currTables[OS]].defaults,
+ ctx->tables[ctx->currTables[OS]].defaultsLength);
}
if (os == NULL) return; /* XXX can't happen */
- if (!current[ARCH] || !rstreq(arch, current[ARCH])) {
- current[ARCH] = _free(current[ARCH]);
- current[ARCH] = xstrdup(arch);
- rebuildCompatTables(ARCH, host_cpu);
+ if (!ctx->current[ARCH] || !rstreq(arch, ctx->current[ARCH])) {
+ ctx->current[ARCH] = _free(ctx->current[ARCH]);
+ ctx->current[ARCH] = xstrdup(arch);
+ rebuildCompatTables(ctx, ARCH, host_cpu);
}
- if (!current[OS] || !rstreq(os, current[OS])) {
+ if (!ctx->current[OS] || !rstreq(os, ctx->current[OS])) {
char * t = xstrdup(os);
- current[OS] = _free(current[OS]);
+ ctx->current[OS] = _free(ctx->current[OS]);
/*
* XXX Capitalizing the 'L' is needed to insure that old
* XXX os-from-uname (e.g. "Linux") is compatible with the new
@@ -1312,79 +1432,49 @@ static void rpmSetMachine(const char * arch, const char * os)
*/
if (rstreq(t, "linux"))
*t = 'L';
- current[OS] = t;
+ ctx->current[OS] = t;
- rebuildCompatTables(OS, host_os);
+ rebuildCompatTables(ctx, OS, host_os);
}
}
-static void rebuildCompatTables(int type, const char * name)
+static void rebuildCompatTables(rpmrcCtx ctx, int type, const char * name)
{
- machFindEquivs(&tables[currTables[type]].cache,
- &tables[currTables[type]].equiv,
+ machFindEquivs(&ctx->tables[ctx->currTables[type]].cache,
+ &ctx->tables[ctx->currTables[type]].equiv,
name);
}
-static void getMachineInfo(int type, const char ** name,
- int * num)
+static void getMachineInfo(rpmrcCtx ctx,
+ int type, const char ** name, int * num)
{
canonEntry canon;
- int which = currTables[type];
+ int which = ctx->currTables[type];
/* use the normal canon tables, even if we're looking up build stuff */
if (which >= 2) which -= 2;
- canon = lookupInCanonTable(current[type],
- tables[which].canons,
- tables[which].canonsLength);
+ canon = lookupInCanonTable(ctx->current[type],
+ ctx->tables[which].canons,
+ ctx->tables[which].canonsLength);
if (canon) {
if (num) *num = canon->num;
if (name) *name = canon->short_name;
} else {
if (num) *num = 255;
- if (name) *name = current[type];
+ if (name) *name = ctx->current[type];
- if (tables[currTables[type]].hasCanon) {
- rpmlog(RPMLOG_WARNING, _("Unknown system: %s\n"), current[type]);
+ if (ctx->tables[ctx->currTables[type]].hasCanon) {
+ rpmlog(RPMLOG_WARNING, _("Unknown system: %s\n"),
+ ctx->current[type]);
rpmlog(RPMLOG_WARNING, _("Please contact %s\n"), PACKAGE_BUGREPORT);
}
}
}
-void rpmGetArchInfo(const char ** name, int * num)
-{
- getMachineInfo(ARCH, name, num);
-}
-
-int rpmGetArchColor(const char *arch)
-{
- const char *color;
- char *e;
- int color_i;
-
- arch = lookupInDefaultTable(arch,
- tables[currTables[ARCH]].defaults,
- tables[currTables[ARCH]].defaultsLength);
- color = rpmGetVarArch(RPMVAR_ARCHCOLOR, arch);
- if (color == NULL) {
- return -1;
- }
-
- color_i = strtol(color, &e, 10);
- if (!(e && *e == '\0')) {
- return -1;
- }
-
- return color_i;
-}
-
-void rpmGetOsInfo(const char ** name, int * num)
-{
- getMachineInfo(OS, name, num);
-}
-
-static void rpmRebuildTargetVars(const char ** target, const char ** canontarget)
+static void rpmRebuildTargetVars(rpmrcCtx ctx,
+ const char ** target, const char ** canontarget)
{
char *ca = NULL, *co = NULL, *ct = NULL;
@@ -1392,9 +1482,9 @@ static void rpmRebuildTargetVars(const char ** target, const char ** canontarget
/* Rebuild the compat table to recalculate the current target arch. */
- rpmSetMachine(NULL, NULL);
- rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
- rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
+ rpmSetMachine(ctx, NULL, NULL);
+ rpmSetTables(ctx, RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
+ rpmSetTables(ctx, RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
if (target && *target) {
char *c;
@@ -1419,16 +1509,16 @@ static void rpmRebuildTargetVars(const char ** target, const char ** canontarget
const char *a = NULL;
const char *o = NULL;
/* Set build target from rpm arch and os */
- rpmGetArchInfo(&a, NULL);
+ getMachineInfo(ctx, ARCH, &a, NULL);
ca = (a) ? xstrdup(a) : NULL;
- rpmGetOsInfo(&o, NULL);
+ getMachineInfo(ctx, OS, &o, NULL);
co = (o) ? xstrdup(o) : NULL;
}
/* If still not set, Set target arch/os from default uname(2) values */
if (ca == NULL) {
const char *a = NULL;
- defaultMachine(&a, NULL);
+ defaultMachine(ctx, &a, NULL);
ca = xstrdup(a ? a : "(arch)");
}
for (x = 0; ca[x] != '\0'; x++)
@@ -1436,7 +1526,7 @@ static void rpmRebuildTargetVars(const char ** target, const char ** canontarget
if (co == NULL) {
const char *o = NULL;
- defaultMachine(NULL, &o);
+ defaultMachine(ctx, NULL, &o);
co = xstrdup(o ? o : "(os)");
}
for (x = 0; co[x] != '\0'; x++)
@@ -1451,19 +1541,19 @@ static void rpmRebuildTargetVars(const char ** target, const char ** canontarget
* XXX All this macro pokery/jiggery could be achieved by doing a delayed
* rpmInitMacros(NULL, PER-PLATFORM-MACRO-FILE-NAMES);
*/
- delMacro(NULL, "_target");
- addMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
- delMacro(NULL, "_target_cpu");
- addMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
- delMacro(NULL, "_target_os");
- addMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
+ rpmPopMacro(NULL, "_target");
+ rpmPushMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
+ rpmPopMacro(NULL, "_target_cpu");
+ rpmPushMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
+ rpmPopMacro(NULL, "_target_os");
+ rpmPushMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
/*
* XXX Make sure that per-arch optflags is initialized correctly.
*/
- { const char *optflags = rpmGetVarArch(RPMVAR_OPTFLAGS, ca);
+ { const char *optflags = rpmGetVarArch(ctx, RPMVAR_OPTFLAGS, ca);
if (optflags != NULL) {
- delMacro(NULL, "optflags");
- addMacro(NULL, "optflags", NULL, optflags, RMIL_RPMRC);
+ rpmPopMacro(NULL, "optflags");
+ rpmPushMacro(NULL, "optflags", NULL, optflags, RMIL_RPMRC);
}
}
@@ -1475,97 +1565,20 @@ static void rpmRebuildTargetVars(const char ** target, const char ** canontarget
free(co);
}
-void rpmFreeRpmrc(void)
-{
- int i, j, k;
-
- if (platpat)
- for (i = 0; i < nplatpat; i++)
- platpat[i] = _free(platpat[i]);
- platpat = _free(platpat);
- nplatpat = 0;
-
- for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
- tableType t;
- t = tables + i;
- if (t->equiv.list) {
- for (j = 0; j < t->equiv.count; j++)
- t->equiv.list[j].name = _free(t->equiv.list[j].name);
- t->equiv.list = _free(t->equiv.list);
- t->equiv.count = 0;
- }
- if (t->cache.cache) {
- for (j = 0; j < t->cache.size; j++) {
- machCacheEntry e;
- e = t->cache.cache + j;
- if (e == NULL)
- continue;
- e->name = _free(e->name);
- if (e->equivs) {
- for (k = 0; k < e->count; k++)
- e->equivs[k] = _free(e->equivs[k]);
- e->equivs = _free(e->equivs);
- }
- }
- t->cache.cache = _free(t->cache.cache);
- t->cache.size = 0;
- }
- if (t->defaults) {
- for (j = 0; j < t->defaultsLength; j++) {
- t->defaults[j].name = _free(t->defaults[j].name);
- t->defaults[j].defName = _free(t->defaults[j].defName);
- }
- t->defaults = _free(t->defaults);
- t->defaultsLength = 0;
- }
- if (t->canons) {
- for (j = 0; j < t->canonsLength; j++) {
- t->canons[j].name = _free(t->canons[j].name);
- t->canons[j].short_name = _free(t->canons[j].short_name);
- }
- t->canons = _free(t->canons);
- t->canonsLength = 0;
- }
- }
-
- for (i = 0; i < RPMVAR_NUM; i++) {
- struct rpmvarValue * vp;
- while ((vp = values[i].next) != NULL) {
- values[i].next = vp->next;
- vp->value = _free(vp->value);
- vp->arch = _free(vp->arch);
- vp = _free(vp);
- }
- values[i].value = _free(values[i].value);
- values[i].arch = _free(values[i].arch);
- }
- current[OS] = _free(current[OS]);
- current[ARCH] = _free(current[ARCH]);
- defaultsInitialized = 0;
-/* FIX: platpat/current may be NULL */
-
- /* XXX doesn't really belong here but... */
- rpmFreeCrypto();
-#ifdef WITH_LUA
- rpmLuaFree();
-#endif
-
- return;
-}
-
/** \ingroup rpmrc
* Read rpmrc (and macro) configuration file(s).
+ * @param ctx rpmrc context
* @param rcfiles colon separated files to read (NULL uses default)
* @return RPMRC_OK on success
*/
-static rpmRC rpmReadRC(const char * rcfiles)
+static rpmRC rpmReadRC(rpmrcCtx ctx, const char * rcfiles)
{
ARGV_t p, globs = NULL, files = NULL;
rpmRC rc = RPMRC_FAIL;
- if (!defaultsInitialized) {
+ if (!ctx->pathDefaults) {
setDefaults();
- defaultsInitialized = 1;
+ ctx->pathDefaults = 1;
}
if (rcfiles == NULL)
@@ -1592,29 +1605,47 @@ static rpmRC rpmReadRC(const char * rcfiles)
goto exit;
break;
} else {
- rc = doReadRC(*p);
+ rc = doReadRC(ctx, *p);
}
}
rc = RPMRC_OK;
- rpmSetMachine(NULL, NULL); /* XXX WTFO? Why bother? */
+ rpmSetMachine(ctx, NULL, NULL); /* XXX WTFO? Why bother? */
exit:
argvFree(files);
return rc;
}
+static void register_atexit(void)
+{
+ if (atexit(rpmAtExit) != 0)
+ rpmlog(RPMLOG_WARNING, _("failed to register exit handler"));
+}
+
+/* External interfaces */
+
int rpmReadConfigFiles(const char * file, const char * target)
{
+ static pthread_once_t atexit_registered = PTHREAD_ONCE_INIT;
+ int rc = -1; /* assume failure */
+ rpmrcCtx ctx = rpmrcCtxAcquire(1);
+
+ pthread_once(&atexit_registered, register_atexit);
+
/* Force preloading of dlopen()'ed libraries in case we go chrooting */
- (void) gethostbyname("localhost");
- (void) rpmInitCrypto();
+ if (rpmugInit())
+ goto exit;
+
+ if (rpmInitCrypto())
+ goto exit;
/* Preset target macros */
/* FIX: target can be NULL */
- rpmRebuildTargetVars(&target, NULL);
+ rpmRebuildTargetVars(ctx, &target, NULL);
/* Read the files */
- if (rpmReadRC(file)) return -1;
+ if (rpmReadRC(ctx, file))
+ goto exit;
if (macrofiles != NULL) {
char *mf = rpmGetPath(macrofiles, NULL);
@@ -1623,12 +1654,12 @@ int rpmReadConfigFiles(const char * file, const char * target)
}
/* Reset target macros */
- rpmRebuildTargetVars(&target, NULL);
+ rpmRebuildTargetVars(ctx, &target, NULL);
/* Finally set target platform */
{ char *cpu = rpmExpand("%{_target_cpu}", NULL);
char *os = rpmExpand("%{_target_os}", NULL);
- rpmSetMachine(cpu, os);
+ rpmSetMachine(ctx, cpu, os);
free(cpu);
free(os);
}
@@ -1637,12 +1668,93 @@ int rpmReadConfigFiles(const char * file, const char * target)
/* Force Lua state initialization */
rpmLuaInit();
#endif
+ rc = 0;
- return 0;
+exit:
+ rpmrcCtxRelease(ctx);
+ return rc;
+}
+
+void rpmFreeRpmrc(void)
+{
+ rpmrcCtx ctx = rpmrcCtxAcquire(1);
+ int i, j, k;
+
+ ctx->platpat = argvFree(ctx->platpat);
+
+ for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
+ tableType t;
+ t = ctx->tables + i;
+ if (t->equiv.list) {
+ for (j = 0; j < t->equiv.count; j++)
+ t->equiv.list[j].name = _free(t->equiv.list[j].name);
+ t->equiv.list = _free(t->equiv.list);
+ t->equiv.count = 0;
+ }
+ if (t->cache.cache) {
+ for (j = 0; j < t->cache.size; j++) {
+ machCacheEntry e;
+ e = t->cache.cache + j;
+ if (e == NULL)
+ continue;
+ e->name = _free(e->name);
+ if (e->equivs) {
+ for (k = 0; k < e->count; k++)
+ e->equivs[k] = _free(e->equivs[k]);
+ e->equivs = _free(e->equivs);
+ }
+ }
+ t->cache.cache = _free(t->cache.cache);
+ t->cache.size = 0;
+ }
+ if (t->defaults) {
+ for (j = 0; j < t->defaultsLength; j++) {
+ t->defaults[j].name = _free(t->defaults[j].name);
+ t->defaults[j].defName = _free(t->defaults[j].defName);
+ }
+ t->defaults = _free(t->defaults);
+ t->defaultsLength = 0;
+ }
+ if (t->canons) {
+ for (j = 0; j < t->canonsLength; j++) {
+ t->canons[j].name = _free(t->canons[j].name);
+ t->canons[j].short_name = _free(t->canons[j].short_name);
+ }
+ t->canons = _free(t->canons);
+ t->canonsLength = 0;
+ }
+ }
+
+ for (i = 0; i < RPMVAR_NUM; i++) {
+ struct rpmvarValue * vp;
+ while ((vp = ctx->values[i].next) != NULL) {
+ ctx->values[i].next = vp->next;
+ vp->value = _free(vp->value);
+ vp->arch = _free(vp->arch);
+ vp = _free(vp);
+ }
+ ctx->values[i].value = _free(ctx->values[i].value);
+ ctx->values[i].arch = _free(ctx->values[i].arch);
+ }
+ ctx->current[OS] = _free(ctx->current[OS]);
+ ctx->current[ARCH] = _free(ctx->current[ARCH]);
+ ctx->machDefaults = 0;
+ ctx->pathDefaults = 0;
+
+ /* XXX doesn't really belong here but... */
+ rpmFreeCrypto();
+#ifdef WITH_LUA
+ rpmLuaFree();
+#endif
+
+ rpmrcCtxRelease(ctx);
+ return;
}
int rpmShowRC(FILE * fp)
{
+ /* Write-context necessary as this calls rpmSetTables(), ugh */
+ rpmrcCtx ctx = rpmrcCtxAcquire(1);
const struct rpmOption *opt;
rpmds ds = NULL;
int i;
@@ -1650,43 +1762,43 @@ int rpmShowRC(FILE * fp)
/* the caller may set the build arch which should be printed here */
fprintf(fp, "ARCHITECTURE AND OS:\n");
- fprintf(fp, "build arch : %s\n", current[ARCH]);
+ fprintf(fp, "build arch : %s\n", ctx->current[ARCH]);
fprintf(fp, "compatible build archs:");
- equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
+ equivTable = &ctx->tables[RPM_MACHTABLE_BUILDARCH].equiv;
for (i = 0; i < equivTable->count; i++)
fprintf(fp," %s", equivTable->list[i].name);
fprintf(fp, "\n");
- fprintf(fp, "build os : %s\n", current[OS]);
+ fprintf(fp, "build os : %s\n", ctx->current[OS]);
fprintf(fp, "compatible build os's :");
- equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
+ equivTable = &ctx->tables[RPM_MACHTABLE_BUILDOS].equiv;
for (i = 0; i < equivTable->count; i++)
fprintf(fp," %s", equivTable->list[i].name);
fprintf(fp, "\n");
- rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
- rpmSetMachine(NULL, NULL); /* XXX WTFO? Why bother? */
+ rpmSetTables(ctx, RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
+ rpmSetMachine(ctx, NULL, NULL); /* XXX WTFO? Why bother? */
- fprintf(fp, "install arch : %s\n", current[ARCH]);
- fprintf(fp, "install os : %s\n", current[OS]);
+ fprintf(fp, "install arch : %s\n", ctx->current[ARCH]);
+ fprintf(fp, "install os : %s\n", ctx->current[OS]);
fprintf(fp, "compatible archs :");
- equivTable = &tables[RPM_MACHTABLE_INSTARCH].equiv;
+ equivTable = &ctx->tables[RPM_MACHTABLE_INSTARCH].equiv;
for (i = 0; i < equivTable->count; i++)
fprintf(fp," %s", equivTable->list[i].name);
fprintf(fp, "\n");
fprintf(fp, "compatible os's :");
- equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
+ equivTable = &ctx->tables[RPM_MACHTABLE_INSTOS].equiv;
for (i = 0; i < equivTable->count; i++)
fprintf(fp," %s", equivTable->list[i].name);
fprintf(fp, "\n");
fprintf(fp, "\nRPMRC VALUES:\n");
for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
- const char *s = rpmGetVar(opt->var);
+ const char *s = rpmGetVarArch(ctx, opt->var, NULL);
if (s != NULL || rpmIsVerbose())
fprintf(fp, "%-21s : %s\n", opt->name, s ? s : "(not set)");
}
@@ -1703,7 +1815,74 @@ int rpmShowRC(FILE * fp)
ds = rpmdsFree(ds);
fprintf(fp, "\n");
+ fprintf(fp, "Macro path: %s\n", macrofiles);
+ fprintf(fp, "\n");
+
rpmDumpMacroTable(NULL, fp);
+ /* XXX: Move this earlier eventually... */
+ rpmrcCtxRelease(ctx);
+
return 0;
}
+
+int rpmMachineScore(int type, const char * name)
+{
+ int score = 0;
+ if (name) {
+ rpmrcCtx ctx = rpmrcCtxAcquire(0);
+ machEquivInfo info = machEquivSearch(&ctx->tables[type].equiv, name);
+ if (info)
+ score = info->score;
+ rpmrcCtxRelease(ctx);
+ }
+ return score;
+}
+
+int rpmIsKnownArch(const char *name)
+{
+ rpmrcCtx ctx = rpmrcCtxAcquire(0);
+ canonEntry canon = lookupInCanonTable(name,
+ ctx->tables[RPM_MACHTABLE_INSTARCH].canons,
+ ctx->tables[RPM_MACHTABLE_INSTARCH].canonsLength);
+ int known = (canon != NULL || rstreq(name, "noarch"));
+ rpmrcCtxRelease(ctx);
+ return known;
+}
+
+void rpmGetArchInfo(const char ** name, int * num)
+{
+ rpmrcCtx ctx = rpmrcCtxAcquire(0);
+ getMachineInfo(ctx, ARCH, name, num);
+ rpmrcCtxRelease(ctx);
+}
+
+int rpmGetArchColor(const char *arch)
+{
+ rpmrcCtx ctx = rpmrcCtxAcquire(0);
+ const char *color;
+ char *e;
+ int color_i = -1; /* assume failure */
+
+ arch = lookupInDefaultTable(arch,
+ ctx->tables[ctx->currTables[ARCH]].defaults,
+ ctx->tables[ctx->currTables[ARCH]].defaultsLength);
+ color = rpmGetVarArch(ctx, RPMVAR_ARCHCOLOR, arch);
+ if (color) {
+ color_i = strtol(color, &e, 10);
+ if (!(e && *e == '\0')) {
+ color_i = -1;
+ }
+ }
+ rpmrcCtxRelease(ctx);
+
+ return color_i;
+}
+
+void rpmGetOsInfo(const char ** name, int * num)
+{
+ rpmrcCtx ctx = rpmrcCtxAcquire(0);
+ getMachineInfo(ctx, OS, name, num);
+ rpmrcCtxRelease(ctx);
+}
+
diff --git a/lib/rpmscript.c b/lib/rpmscript.c
index a27251c9a..cc98c4885 100644
--- a/lib/rpmscript.c
+++ b/lib/rpmscript.c
@@ -10,6 +10,7 @@
#include <rpm/rpmio.h>
#include <rpm/rpmlog.h>
#include <rpm/header.h>
+#include <rpm/rpmds.h>
#include "rpmio/rpmlua.h"
#include "lib/rpmscript.h"
@@ -18,20 +19,73 @@
#include "debug.h"
+struct scriptNextFileFunc_s {
+ char *(*func)(void *); /* function producing input for script */
+ void *param; /* parameter for func */
+};
+
+typedef struct scriptNextFileFunc_s *scriptNextFileFunc;
+
struct rpmScript_s {
+ rpmscriptTypes type; /* script type */
rpmTagVal tag; /* script tag */
char **args; /* scriptlet call arguments */
char *body; /* script body */
char *descr; /* description for logging */
rpmscriptFlags flags; /* flags to control operation */
+ struct scriptNextFileFunc_s nextFileFunc; /* input function */
+};
+
+struct scriptInfo_s {
+ rpmscriptTypes type;
+ const char *desc;
+ rpmsenseFlags sense;
+ rpmTagVal tag;
+ rpmTagVal progtag;
+ rpmTagVal flagtag;
+};
+
+static const struct scriptInfo_s scriptInfo[] = {
+ { RPMSCRIPT_PREIN, "%prein", 0,
+ RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS },
+ { RPMSCRIPT_PREUN, "%preun", 0,
+ RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS },
+ { RPMSCRIPT_POSTIN, "%post", 0,
+ RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS },
+ { RPMSCRIPT_POSTUN, "%postun", 0,
+ RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS },
+ { RPMSCRIPT_PRETRANS, "%pretrans", 0,
+ RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS },
+ { RPMSCRIPT_POSTTRANS, "%posttrans", 0,
+ RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS },
+ { RPMSCRIPT_TRIGGERPREIN, "%triggerprein", RPMSENSE_TRIGGERPREIN,
+ RPMTAG_TRIGGERPREIN, 0, 0 },
+ { RPMSCRIPT_TRIGGERUN, "%triggerun", RPMSENSE_TRIGGERUN,
+ RPMTAG_TRIGGERUN, 0, 0 },
+ { RPMSCRIPT_TRIGGERIN, "%triggerin", RPMSENSE_TRIGGERIN,
+ RPMTAG_TRIGGERIN, 0, 0 },
+ { RPMSCRIPT_TRIGGERPOSTUN, "%triggerpostun", RPMSENSE_TRIGGERPOSTUN,
+ RPMTAG_TRIGGERPOSTUN, 0, 0 },
+ { RPMSCRIPT_VERIFY, "%verify", 0,
+ RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
+ { 0, "unknown", 0,
+ RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND }
};
+static const struct scriptInfo_s * findTag(rpmTagVal tag)
+{
+ const struct scriptInfo_s * si = scriptInfo;
+ while (si->type && si->tag != tag)
+ si++;
+ return si;
+}
/**
* Run internal Lua script.
*/
-static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes,
+static rpmRC runLuaScript(rpmPlugins plugins, ARGV_const_t prefixes,
const char *sname, rpmlogLvl lvl, FD_t scriptFd,
- ARGV_t * argvp, const char *script, int arg1, int arg2)
+ ARGV_t * argvp, const char *script, int arg1, int arg2,
+ scriptNextFileFunc nextFileFunc)
{
rpmRC rc = RPMRC_FAIL;
#ifdef WITH_LUA
@@ -45,6 +99,7 @@ static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
/* Create arg variable */
rpmluaPushTable(lua, "arg");
rpmluavSetListMode(var, 1);
+ rpmluaSetNextFileFunc(nextFileFunc->func, nextFileFunc->param);
if (argv) {
char **p;
for (p = argv; *p; p++) {
@@ -68,10 +123,16 @@ static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
if (cwd != -1) {
mode_t oldmask = umask(0);
umask(oldmask);
+ pid_t pid = getpid();
if (chdir("/") == 0 && rpmluaRunScript(lua, script, sname) == 0) {
rc = RPMRC_OK;
}
+ if (pid != getpid()) {
+ /* Terminate child process forked in lua scriptlet */
+ rpmlog(RPMLOG_ERR, _("No exec() called after fork() in lua scriptlet\n"));
+ _exit(EXIT_FAILURE);
+ }
/* This failing would be fatal, return something different for it... */
if (fchdir(cwd)) {
rpmlog(RPMLOG_ERR, _("Unable to restore current directory: %m"));
@@ -93,22 +154,16 @@ static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
-static void doScriptExec(int selinux, ARGV_const_t argv, ARGV_const_t prefixes,
+static void doScriptExec(ARGV_const_t argv, ARGV_const_t prefixes,
FD_t scriptFd, FD_t out)
{
- int pipes[2];
int flag;
int fdno;
int xx;
int open_max;
+ /* SIGPIPE is ignored in rpm, reset to default for the scriptlet */
(void) signal(SIGPIPE, SIG_DFL);
- pipes[0] = pipes[1] = 0;
- /* make stdin inaccessible */
- xx = pipe(pipes);
- xx = close(pipes[1]);
- xx = dup2(pipes[0], STDIN_FILENO);
- xx = close(pipes[0]);
/* XXX Force FD_CLOEXEC on all inherited fdno's. */
open_max = sysconf(_SC_OPEN_MAX);
@@ -165,11 +220,6 @@ static void doScriptExec(int selinux, ARGV_const_t argv, ARGV_const_t prefixes,
/* XXX Don't mtrace into children. */
unsetenv("MALLOC_CHECK_");
- /* Permit libselinux to do the scriptlet exec. */
- if (selinux == 1) {
- xx = rpm_execcon(0, argv[0], argv, environ);
- }
-
if (xx == 0) {
xx = execv(argv[0], argv);
}
@@ -204,14 +254,19 @@ exit:
/**
* Run an external script.
*/
-static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes,
+static rpmRC runExtScript(rpmPlugins plugins, ARGV_const_t prefixes,
const char *sname, rpmlogLvl lvl, FD_t scriptFd,
- ARGV_t * argvp, const char *script, int arg1, int arg2)
+ ARGV_t * argvp, const char *script, int arg1, int arg2,
+ scriptNextFileFunc nextFileFunc)
{
FD_t out = NULL;
char * fn = NULL;
pid_t pid, reaped;
int status;
+ int inpipe[2];
+ FILE *in = NULL;
+ const char *line;
+ char *mline = NULL;
rpmRC rc = RPMRC_FAIL;
rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);
@@ -234,6 +289,14 @@ static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
}
}
+ if (pipe(inpipe) < 0) {
+ rpmlog(RPMLOG_ERR,
+ ("Couldn't create pipe: %s\n"), strerror(errno));
+ goto exit;
+ }
+ in = fdopen(inpipe[1], "w");
+ inpipe[1] = 0;
+
if (scriptFd != NULL) {
if (rpmIsVerbose()) {
out = fdDup(Fileno(scriptFd));
@@ -261,13 +324,41 @@ static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
sname, *argvp[0], (unsigned)getpid());
+ fclose(in);
+ dup2(inpipe[0], STDIN_FILENO);
+
/* Run scriptlet post fork hook for all plugins */
if (rpmpluginsCallScriptletForkPost(plugins, *argvp[0], RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC) != RPMRC_FAIL) {
- doScriptExec(selinux, *argvp, prefixes, scriptFd, out);
+ doScriptExec(*argvp, prefixes, scriptFd, out);
} else {
_exit(126); /* exit 126 for compatibility with bash(1) */
}
}
+ close(inpipe[0]);
+ inpipe[0] = 0;
+
+ if (nextFileFunc->func) {
+ while ((line = nextFileFunc->func(nextFileFunc->param)) != NULL) {
+ size_t size = strlen(line);
+ size_t ret_size;
+ mline = xstrdup(line);
+ mline[size] = '\n';
+
+ ret_size = fwrite(mline, size + 1, 1, in);
+ mline = _free(mline);
+ if (ret_size != 1) {
+ if (errno == EPIPE) {
+ break;
+ } else {
+ rpmlog(RPMLOG_ERR, _("Fwrite failed: %s"), strerror(errno));
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+ }
+ }
+ }
+ fclose(in);
+ in = NULL;
do {
reaped = waitpid(pid, &status, 0);
@@ -293,6 +384,12 @@ static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
}
exit:
+ if (in)
+ fclose(in);
+
+ if (inpipe[0])
+ close(inpipe[0]);
+
if (out)
Fclose(out); /* XXX dup'd STDOUT_FILENO */
@@ -301,11 +398,13 @@ exit:
unlink(fn);
free(fn);
}
+ free(mline);
+
return rc;
}
rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
- ARGV_const_t prefixes, int warn_only, int selinux, rpmPlugins plugins)
+ ARGV_const_t prefixes, int warn_only, rpmPlugins plugins)
{
ARGV_t args = NULL;
rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
@@ -329,9 +428,9 @@ rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
if (rc != RPMRC_FAIL) {
if (script_type & RPMSCRIPTLET_EXEC) {
- rc = runExtScript(plugins, selinux, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
+ rc = runExtScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
} else {
- rc = runLuaScript(plugins, selinux, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
+ rc = runLuaScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
}
}
@@ -343,54 +442,24 @@ rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
return rc;
}
+static rpmscriptTypes getScriptType(rpmTagVal scriptTag)
+{
+ return findTag(scriptTag)->type;
+}
+
static rpmTagVal getProgTag(rpmTagVal scriptTag)
{
- switch (scriptTag) {
- case RPMTAG_PREIN: return RPMTAG_PREINPROG;
- case RPMTAG_POSTIN: return RPMTAG_POSTINPROG;
- case RPMTAG_PREUN: return RPMTAG_PREUNPROG;
- case RPMTAG_POSTUN: return RPMTAG_POSTUNPROG;
- case RPMTAG_PRETRANS: return RPMTAG_PRETRANSPROG;
- case RPMTAG_POSTTRANS: return RPMTAG_POSTTRANSPROG;
- case RPMTAG_VERIFYSCRIPT: return RPMTAG_VERIFYSCRIPTPROG;
- default: return RPMTAG_NOT_FOUND;
- }
+ return findTag(scriptTag)->progtag;
}
static rpmTagVal getFlagTag(rpmTagVal scriptTag)
{
- switch (scriptTag) {
- case RPMTAG_PRETRANS: return RPMTAG_PRETRANSFLAGS;
- case RPMTAG_POSTTRANS: return RPMTAG_POSTTRANSFLAGS;
- case RPMTAG_PREUN: return RPMTAG_PREUNFLAGS;
- case RPMTAG_POSTUN: return RPMTAG_POSTUNFLAGS;
- case RPMTAG_PREIN: return RPMTAG_PREINFLAGS;
- case RPMTAG_POSTIN: return RPMTAG_POSTINFLAGS;
- case RPMTAG_VERIFYSCRIPT: return RPMTAG_VERIFYSCRIPTFLAGS;
- case RPMTAG_TRIGGERSCRIPTS: return RPMTAG_TRIGGERSCRIPTFLAGS;
- default:
- break;
- }
- return RPMTAG_NOT_FOUND;
+ return findTag(scriptTag)->flagtag;
}
static const char * tag2sln(rpmTagVal tag)
{
- switch (tag) {
- case RPMTAG_PRETRANS: return "%pretrans";
- case RPMTAG_TRIGGERPREIN: return "%triggerprein";
- case RPMTAG_PREIN: return "%pre";
- case RPMTAG_POSTIN: return "%post";
- case RPMTAG_TRIGGERIN: return "%triggerin";
- case RPMTAG_TRIGGERUN: return "%triggerun";
- case RPMTAG_PREUN: return "%preun";
- case RPMTAG_POSTUN: return "%postun";
- case RPMTAG_POSTTRANS: return "%posttrans";
- case RPMTAG_TRIGGERPOSTUN: return "%triggerpostun";
- case RPMTAG_VERIFYSCRIPT: return "%verify";
- default: break;
- }
- return "%unknownscript";
+ return findTag(tag)->desc;
}
static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
@@ -399,6 +468,7 @@ static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
rpmScript script = xcalloc(1, sizeof(*script));
script->tag = tag;
+ script->type = getScriptType(tag);
script->flags = flags;
script->body = (body != NULL) ? xstrdup(body) : NULL;
rasprintf(&script->descr, "%s(%s)", tag2sln(tag), nevra);
@@ -416,20 +486,101 @@ static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
script->body = body;
}
+ script->nextFileFunc.func = NULL;
+ script->nextFileFunc.param = NULL;
+
free(nevra);
return script;
}
-rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag, uint32_t ix)
+void rpmScriptSetNextFileFunc(rpmScript script, char *(*func)(void *),
+ void *param)
+{
+ script->nextFileFunc.func = func;
+ script->nextFileFunc.param = param;
+}
+
+rpmTagVal triggerDsTag(rpmscriptTriggerModes tm)
+{
+ rpmTagVal tag = RPMTAG_NOT_FOUND;
+ switch (tm) {
+ case RPMSCRIPT_NORMALTRIGGER:
+ tag = RPMTAG_TRIGGERNAME;
+ break;
+ case RPMSCRIPT_FILETRIGGER:
+ tag = RPMTAG_FILETRIGGERNAME;
+ break;
+ case RPMSCRIPT_TRANSFILETRIGGER:
+ tag = RPMTAG_TRANSFILETRIGGERNAME;
+ break;
+ }
+ return tag;
+}
+
+rpmscriptTriggerModes triggerMode(rpmTagVal tag)
+{
+ rpmscriptTriggerModes tm = 0;
+ switch (tag) {
+ case RPMTAG_TRIGGERNAME:
+ tm = RPMSCRIPT_NORMALTRIGGER;
+ break;
+ case RPMTAG_FILETRIGGERNAME:
+ tm = RPMSCRIPT_FILETRIGGER;
+ break;
+ case RPMTAG_TRANSFILETRIGGERNAME:
+ tm = RPMSCRIPT_TRANSFILETRIGGER;
+ break;
+ }
+ return tm;
+}
+
+rpmTagVal triggertag(rpmsenseFlags sense)
+{
+ rpmTagVal tag = RPMTAG_NOT_FOUND;
+ switch (sense) {
+ case RPMSENSE_TRIGGERIN:
+ tag = RPMTAG_TRIGGERIN;
+ break;
+ case RPMSENSE_TRIGGERUN:
+ tag = RPMTAG_TRIGGERUN;
+ break;
+ case RPMSENSE_TRIGGERPOSTUN:
+ tag = RPMTAG_TRIGGERPOSTUN;
+ break;
+ case RPMSENSE_TRIGGERPREIN:
+ tag = RPMTAG_TRIGGERPREIN;
+ break;
+ default:
+ break;
+ }
+ return tag;
+}
+
+rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag,
+ rpmscriptTriggerModes tm, uint32_t ix)
{
rpmScript script = NULL;
struct rpmtd_s tscripts, tprogs, tflags;
headerGetFlags hgflags = HEADERGET_MINMEM;
- headerGet(h, RPMTAG_TRIGGERSCRIPTS, &tscripts, hgflags);
- headerGet(h, RPMTAG_TRIGGERSCRIPTPROG, &tprogs, hgflags);
- headerGet(h, RPMTAG_TRIGGERSCRIPTFLAGS, &tflags, hgflags);
-
+ switch (tm) {
+ case RPMSCRIPT_NORMALTRIGGER:
+ headerGet(h, RPMTAG_TRIGGERSCRIPTS, &tscripts, hgflags);
+ headerGet(h, RPMTAG_TRIGGERSCRIPTPROG, &tprogs, hgflags);
+ headerGet(h, RPMTAG_TRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ break;
+ case RPMSCRIPT_FILETRIGGER:
+ headerGet(h, RPMTAG_FILETRIGGERSCRIPTS, &tscripts, hgflags);
+ headerGet(h, RPMTAG_FILETRIGGERSCRIPTPROG, &tprogs, hgflags);
+ headerGet(h, RPMTAG_FILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ break;
+ case RPMSCRIPT_TRANSFILETRIGGER:
+ headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTS, &tscripts, hgflags);
+ headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTPROG, &tprogs, hgflags);
+ headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ break;
+ }
+
if (rpmtdSetIndex(&tscripts, ix) >= 0 && rpmtdSetIndex(&tprogs, ix) >= 0) {
rpmscriptFlags sflags = 0;
const char *prog = rpmtdGetString(&tprogs);
@@ -487,3 +638,8 @@ rpmTagVal rpmScriptTag(rpmScript script)
{
return (script != NULL) ? script->tag : RPMTAG_NOT_FOUND;
}
+
+rpmscriptTypes rpmScriptType(rpmScript script)
+{
+ return (script != NULL) ? script->type : 0;
+}
diff --git a/lib/rpmscript.h b/lib/rpmscript.h
index 852735b8d..3768077c7 100644
--- a/lib/rpmscript.h
+++ b/lib/rpmscript.h
@@ -3,6 +3,33 @@
#include <rpm/rpmtypes.h>
#include <rpm/argv.h>
+#include <rpm/rpmds.h>
+
+/* Rpm scriptlet types */
+enum rpmscriptTypes_e {
+ RPMSCRIPT_PREIN = (1 << 0),
+ RPMSCRIPT_PREUN = (1 << 1),
+ RPMSCRIPT_POSTIN = (1 << 2),
+ RPMSCRIPT_POSTUN = (1 << 3),
+ RPMSCRIPT_TRIGGERPREIN = (1 << 4),
+ RPMSCRIPT_TRIGGERUN = (1 << 6),
+ RPMSCRIPT_TRIGGERIN = (1 << 5),
+ RPMSCRIPT_TRIGGERPOSTUN = (1 << 7),
+ RPMSCRIPT_PRETRANS = (1 << 8),
+ RPMSCRIPT_POSTTRANS = (1 << 9),
+ /* ... */
+ RPMSCRIPT_VERIFY = (1 << 24),
+};
+
+typedef rpmFlags rpmscriptTypes;
+
+enum rpmscriptTriggerMode_e {
+ RPMSCRIPT_NORMALTRIGGER = (1 << 0),
+ RPMSCRIPT_FILETRIGGER = (1 << 1),
+ RPMSCRIPT_TRANSFILETRIGGER = (1 << 2),
+};
+
+typedef rpmFlags rpmscriptTriggerModes;
enum rpmscriptFlags_e {
RPMSCRIPT_FLAG_NONE = 0,
@@ -19,20 +46,37 @@ extern "C" {
#endif
RPM_GNUC_INTERNAL
+rpmTagVal triggerDsTag(rpmscriptTriggerModes tm);
+
+RPM_GNUC_INTERNAL
+rpmscriptTriggerModes triggerMode(rpmTagVal tag);
+
+RPM_GNUC_INTERNAL
+rpmTagVal triggertag(rpmsenseFlags sense);
+
+RPM_GNUC_INTERNAL
rpmScript rpmScriptFromTag(Header h, rpmTagVal scriptTag);
RPM_GNUC_INTERNAL
-rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag, uint32_t ix);
+rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag,
+ rpmscriptTriggerModes tm, uint32_t ix);
RPM_GNUC_INTERNAL
rpmScript rpmScriptFree(rpmScript script);
RPM_GNUC_INTERNAL
rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
- ARGV_const_t prefixes, int warn_only, int selinux, rpmPlugins plugins);
+ ARGV_const_t prefixes, int warn_only, rpmPlugins plugins);
RPM_GNUC_INTERNAL
rpmTagVal rpmScriptTag(rpmScript script);
+
+RPM_GNUC_INTERNAL
+rpmscriptTypes rpmScriptType(rpmScript script);
+
+RPM_GNUC_INTERNAL
+void rpmScriptSetNextFileFunc(rpmScript script, char *(*func)(void *),
+ void *param);
#ifdef __cplusplus
}
#endif
diff --git a/lib/rpmtag.h b/lib/rpmtag.h
index 025a0a415..4491aa9a4 100644
--- a/lib/rpmtag.h
+++ b/lib/rpmtag.h
@@ -1,6 +1,12 @@
#ifndef _RPMTAG_H
#define _RPMTAG_H
+/** \ingroup rpmtag
+ * \file lib/rpmtag.h
+ *
+ * Accessing RPM tags: values, types, ...
+ */
+
#include <rpm/rpmtypes.h>
#ifdef __cplusplus
@@ -57,6 +63,8 @@ typedef enum rpmTag_e {
#define RPMTAG_HDRID RPMTAG_SHA1HEADER /* s */
RPMTAG_LONGSIGSIZE = RPMTAG_SIG_BASE+14, /* l */
RPMTAG_LONGARCHIVESIZE = RPMTAG_SIG_BASE+15, /* l */
+ /* RPMTAG_SIG_BASE+16 reserved */
+ RPMTAG_SHA256HEADER = RPMTAG_SIG_BASE+17, /* s */
RPMTAG_NAME = 1000, /* s */
#define RPMTAG_N RPMTAG_NAME /* s */
@@ -117,8 +125,8 @@ typedef enum rpmTag_e {
RPMTAG_REQUIRENAME = 1049, /* s[] */
#define RPMTAG_REQUIRES RPMTAG_REQUIRENAME /* s[] */
RPMTAG_REQUIREVERSION = 1050, /* s[] */
- RPMTAG_NOSOURCE = 1051, /* i */
- RPMTAG_NOPATCH = 1052, /* i */
+ RPMTAG_NOSOURCE = 1051, /* i[] */
+ RPMTAG_NOPATCH = 1052, /* i[] */
RPMTAG_CONFLICTFLAGS = 1053, /* i[] */
RPMTAG_CONFLICTNAME = 1054, /* s[] */
#define RPMTAG_CONFLICTS RPMTAG_CONFLICTNAME /* s[] */
@@ -217,14 +225,14 @@ typedef enum rpmTag_e {
RPMTAG_PRETRANSPROG = 1153, /* s[] */
RPMTAG_POSTTRANSPROG = 1154, /* s[] */
RPMTAG_DISTTAG = 1155, /* s */
- RPMTAG_SUGGESTSNAME = 1156, /* s[] extension */
-#define RPMTAG_SUGGESTS RPMTAG_SUGGESTSNAME /* s[] */
- RPMTAG_SUGGESTSVERSION = 1157, /* s[] extension */
- RPMTAG_SUGGESTSFLAGS = 1158, /* i[] extension */
- RPMTAG_ENHANCESNAME = 1159, /* s[] extension */
-#define RPMTAG_ENHANCES RPMTAG_ENHANCESNAME /* s[] */
- RPMTAG_ENHANCESVERSION = 1160, /* s[] extension */
- RPMTAG_ENHANCESFLAGS = 1161, /* i[] extension */
+ RPMTAG_OLDSUGGESTSNAME = 1156, /* s[] - obsolete */
+#define RPMTAG_OLDSUGGESTS RPMTAG_OLDSUGGESTSNAME /* s[] - obsolete */
+ RPMTAG_OLDSUGGESTSVERSION = 1157, /* s[] - obsolete */
+ RPMTAG_OLDSUGGESTSFLAGS = 1158, /* i[] - obsolete */
+ RPMTAG_OLDENHANCESNAME = 1159, /* s[] - obsolete */
+#define RPMTAG_OLDENHANCES RPMTAG_OLDENHANCESNAME /* s[] - obsolete */
+ RPMTAG_OLDENHANCESVERSION = 1160, /* s[] - obsolete */
+ RPMTAG_OLDENHANCESFLAGS = 1161, /* i[] - obsolete */
RPMTAG_PRIORITY = 1162, /* i[] extension placeholder (unimplemented) */
RPMTAG_CVSID = 1163, /* s (unimplemented) */
#define RPMTAG_SVNID RPMTAG_CVSID /* s (unimplemented) */
@@ -261,7 +269,9 @@ typedef enum rpmTag_e {
RPMTAG_BUILDOBSOLETES = 1194, /* internal (unimplemented) */
RPMTAG_DBINSTANCE = 1195, /* i extension */
RPMTAG_NVRA = 1196, /* s extension */
- /* tags 1997-4999 reserved */
+ RPMTAG_MULTIFILELIST = 1197, /* s */
+
+ /* tags 1998-4999 reserved */
RPMTAG_FILENAMES = 5000, /* s[] extension */
RPMTAG_FILEPROVIDE = 5001, /* s[] extension */
RPMTAG_FILEREQUIRE = 5002, /* s[] extension */
@@ -290,7 +300,7 @@ typedef enum rpmTag_e {
RPMTAG_POSTTRANSFLAGS = 5025, /* i */
RPMTAG_VERIFYSCRIPTFLAGS = 5026, /* i */
RPMTAG_TRIGGERSCRIPTFLAGS = 5027, /* i[] */
- RPMTAG_COLLECTIONS = 5029, /* s[] list of collections */
+ RPMTAG_COLLECTIONS = 5029, /* s[] list of collections (unimplemented) */
RPMTAG_POLICYNAMES = 5030, /* s[] */
RPMTAG_POLICYTYPES = 5031, /* s[] */
RPMTAG_POLICYTYPESINDEXES = 5032, /* i[] */
@@ -307,8 +317,62 @@ typedef enum rpmTag_e {
RPMTAG_OBSOLETENEVRS = 5043, /* s[] extension */
RPMTAG_CONFLICTNEVRS = 5044, /* s[] extension */
RPMTAG_FILENLINKS = 5045, /* i[] extension */
+ RPMTAG_RECOMMENDNAME = 5046, /* s[] */
+#define RPMTAG_RECOMMENDS RPMTAG_RECOMMENDNAME /* s[] */
+ RPMTAG_RECOMMENDVERSION = 5047, /* s[] */
+ RPMTAG_RECOMMENDFLAGS = 5048, /* i[] */
+ RPMTAG_SUGGESTNAME = 5049, /* s[] */
+#define RPMTAG_SUGGESTS RPMTAG_SUGGESTNAME /* s[] */
+ RPMTAG_SUGGESTVERSION = 5050, /* s[] extension */
+ RPMTAG_SUGGESTFLAGS = 5051, /* i[] extension */
+ RPMTAG_SUPPLEMENTNAME = 5052, /* s[] */
+#define RPMTAG_SUPPLEMENTS RPMTAG_SUPPLEMENTNAME /* s[] */
+ RPMTAG_SUPPLEMENTVERSION = 5053, /* s[] */
+ RPMTAG_SUPPLEMENTFLAGS = 5054, /* i[] */
+ RPMTAG_ENHANCENAME = 5055, /* s[] */
+#define RPMTAG_ENHANCES RPMTAG_ENHANCENAME /* s[] */
+ RPMTAG_ENHANCEVERSION = 5056, /* s[] */
+ RPMTAG_ENHANCEFLAGS = 5057, /* i[] */
+ RPMTAG_RECOMMENDNEVRS = 5058, /* s[] extension */
+ RPMTAG_SUGGESTNEVRS = 5059, /* s[] extension */
+ RPMTAG_SUPPLEMENTNEVRS = 5060, /* s[] extension */
+ RPMTAG_ENHANCENEVRS = 5061, /* s[] extension */
+ RPMTAG_ENCODING = 5062, /* s */
+ RPMTAG_FILETRIGGERIN = 5063, /* internal */
+ RPMTAG_FILETRIGGERUN = 5064, /* internal */
+ RPMTAG_FILETRIGGERPOSTUN = 5065, /* internal */
+ RPMTAG_FILETRIGGERSCRIPTS = 5066, /* s[] */
+ RPMTAG_FILETRIGGERSCRIPTPROG = 5067, /* s[] */
+ RPMTAG_FILETRIGGERSCRIPTFLAGS = 5068, /* i[] */
+ RPMTAG_FILETRIGGERNAME = 5069, /* s[] */
+ RPMTAG_FILETRIGGERINDEX = 5070, /* i[] */
+ RPMTAG_FILETRIGGERVERSION = 5071, /* s[] */
+ RPMTAG_FILETRIGGERFLAGS = 5072, /* i[] */
+ RPMTAG_TRANSFILETRIGGERIN = 5073, /* internal */
+ RPMTAG_TRANSFILETRIGGERUN = 5074, /* internal */
+ RPMTAG_TRANSFILETRIGGERPOSTUN = 5075, /* internal */
+ RPMTAG_TRANSFILETRIGGERSCRIPTS = 5076, /* s[] */
+ RPMTAG_TRANSFILETRIGGERSCRIPTPROG = 5077, /* s[] */
+ RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS = 5078, /* i[] */
+ RPMTAG_TRANSFILETRIGGERNAME = 5079, /* s[] */
+ RPMTAG_TRANSFILETRIGGERINDEX = 5080, /* i[] */
+ RPMTAG_TRANSFILETRIGGERVERSION = 5081, /* s[] */
+ RPMTAG_TRANSFILETRIGGERFLAGS = 5082, /* i[] */
+ RPMTAG_REMOVEPATHPOSTFIXES = 5083, /* s internal */
+ RPMTAG_FILETRIGGERPRIORITIES = 5084, /* i[] */
+ RPMTAG_TRANSFILETRIGGERPRIORITIES = 5085, /* i[] */
+ RPMTAG_FILETRIGGERCONDS = 5086, /* s[] extension */
+ RPMTAG_FILETRIGGERTYPE = 5087, /* s[] extension */
+ RPMTAG_TRANSFILETRIGGERCONDS = 5088, /* s[] extension */
+ RPMTAG_TRANSFILETRIGGERTYPE = 5089, /* s[] extension */
+ RPMTAG_FILESIGNATURES = 5090, /* s[] */
+ RPMTAG_FILESIGNATURELENGTH = 5091, /* i */
+ RPMTAG_PAYLOADDIGEST = 5092, /* s[] */
+ RPMTAG_PAYLOADDIGESTALGO = 5093, /* i */
+ /* Skip numbers which might be used in new RPM versions */
+ RPMTAG_BUILDINFO = 7000, /* s[] information about build */
- RPMTAG_FIRSTFREE_TAG /*!< internal */
+ RPMTAG_FIRSTFREE_TAG, /*!< internal */
} rpmTag;
#define RPMTAG_EXTERNAL_TAG 1000000
@@ -332,6 +396,12 @@ typedef enum rpmDbiTag_e {
RPMDBI_SIGMD5 = RPMTAG_SIGMD5,
RPMDBI_SHA1HEADER = RPMTAG_SHA1HEADER,
RPMDBI_INSTFILENAMES = RPMTAG_INSTFILENAMES,
+ RPMDBI_FILETRIGGERNAME = RPMTAG_FILETRIGGERNAME,
+ RPMDBI_TRANSFILETRIGGERNAME = RPMTAG_TRANSFILETRIGGERNAME,
+ RPMDBI_RECOMMENDNAME = RPMTAG_RECOMMENDNAME,
+ RPMDBI_SUGGESTNAME = RPMTAG_SUGGESTNAME,
+ RPMDBI_SUPPLEMENTNAME = RPMTAG_SUPPLEMENTNAME,
+ RPMDBI_ENHANCENAME = RPMTAG_ENHANCENAME,
} rpmDbiTag;
/** \ingroup signature
@@ -346,13 +416,15 @@ typedef enum rpmSigTag_e {
RPMSIGTAG_GPG = 1005, /*!< internal GnuPG signature. */
RPMSIGTAG_PGP5 = 1006, /*!< internal PGP5 signature @deprecated legacy. */
RPMSIGTAG_PAYLOADSIZE = 1007,/*!< internal uncompressed payload size (32bit) in bytes. */
+ RPMSIGTAG_RESERVEDSPACE = 1008,/*!< internal space reserved for signatures */
RPMSIGTAG_BADSHA1_1 = RPMTAG_BADSHA1_1, /*!< internal Broken SHA1, take 1. */
RPMSIGTAG_BADSHA1_2 = RPMTAG_BADSHA1_2, /*!< internal Broken SHA1, take 2. */
- RPMSIGTAG_SHA1 = RPMTAG_SHA1HEADER, /*!< internal sha1 header digest. */
RPMSIGTAG_DSA = RPMTAG_DSAHEADER, /*!< internal DSA header signature. */
RPMSIGTAG_RSA = RPMTAG_RSAHEADER, /*!< internal RSA header signature. */
+ RPMSIGTAG_SHA1 = RPMTAG_SHA1HEADER, /*!< internal sha1 header digest. */
RPMSIGTAG_LONGSIZE = RPMTAG_LONGSIGSIZE, /*!< internal Header+Payload size (64bit) in bytes. */
RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */
+ RPMSIGTAG_SHA256 = RPMTAG_SHA256HEADER,
} rpmSigTag;
diff --git a/lib/rpmtd.c b/lib/rpmtd.c
index 550d733ab..e33c8cb53 100644
--- a/lib/rpmtd.c
+++ b/lib/rpmtd.c
@@ -19,7 +19,7 @@ rpmtd rpmtdFree(rpmtd td)
{
/* permit free on NULL td */
if (td != NULL) {
- /* XXX should we free data too - a flag maybe? */
+ rpmtdFreeData(td);
free(td);
}
return NULL;
@@ -27,19 +27,16 @@ rpmtd rpmtdFree(rpmtd td)
void rpmtdReset(rpmtd td)
{
- assert(td != NULL);
-
- memset(td, 0, sizeof(*td));
- td->ix = -1;
+ if (td) {
+ memset(td, 0, sizeof(*td));
+ td->ix = -1;
+ }
}
void rpmtdFreeData(rpmtd td)
{
- assert(td != NULL);
-
- if (td->flags & RPMTD_ALLOCED) {
+ if (td && td->data && td->flags & RPMTD_ALLOCED) {
if (td->flags & RPMTD_PTR_ALLOCED) {
- assert(td->data != NULL);
char **data = td->data;
for (int i = 0; i < td->count; i++) {
free(data[i]);
@@ -52,27 +49,32 @@ void rpmtdFreeData(rpmtd td)
rpm_count_t rpmtdCount(rpmtd td)
{
- assert(td != NULL);
- /* fix up for binary type abusing count as data length */
- return (td->type == RPM_BIN_TYPE) ? 1 : td->count;
+ rpm_count_t count = 0;
+ if (td != NULL) {
+ /* fix up for binary type abusing count as data length */
+ count = (td->type == RPM_BIN_TYPE) ? 1 : td->count;
+ }
+ return count;
+}
+
+rpm_count_t rpmtdSize(rpmtd td)
+{
+ return (td != NULL) ? td->size : 0;
}
rpmTagVal rpmtdTag(rpmtd td)
{
- assert(td != NULL);
- return td->tag;
+ return (td != NULL) ? td->tag : 0;
}
rpmTagType rpmtdType(rpmtd td)
{
- assert(td != NULL);
- return td->type;
+ return (td != NULL) ? td->type : 0;
}
rpmTagClass rpmtdClass(rpmtd td)
{
- assert(td != NULL);
- return rpmTagTypeGetClass(td->type);
+ return (td != NULL) ? rpmTagTypeGetClass(td->type) : 0;
}
rpmtdFlags rpmtdGetFlags(rpmtd td)
@@ -82,15 +84,12 @@ rpmtdFlags rpmtdGetFlags(rpmtd td)
int rpmtdGetIndex(rpmtd td)
{
- assert(td != NULL);
- return td->ix;
+ return (td != NULL) ? td->ix : -1;
}
int rpmtdSetIndex(rpmtd td, int index)
{
- assert(td != NULL);
-
- if (index < 0 || index >= rpmtdCount(td)) {
+ if (td == NULL || index < 0 || index >= rpmtdCount(td)) {
return -1;
}
td->ix = index;
@@ -99,7 +98,8 @@ int rpmtdSetIndex(rpmtd td, int index)
int rpmtdInit(rpmtd td)
{
- assert(td != NULL);
+ if (td == NULL)
+ return -1;
/* XXX check that this is an array type? */
td->ix = -1;
@@ -108,11 +108,9 @@ int rpmtdInit(rpmtd td)
int rpmtdNext(rpmtd td)
{
- assert(td != NULL);
-
int i = -1;
- if (++td->ix >= 0) {
+ if (td != NULL && ++td->ix >= 0) {
if (td->ix < rpmtdCount(td)) {
i = td->ix;
} else {
@@ -124,7 +122,6 @@ int rpmtdNext(rpmtd td)
uint32_t *rpmtdNextUint32(rpmtd td)
{
- assert(td != NULL);
uint32_t *res = NULL;
if (rpmtdNext(td) >= 0) {
res = rpmtdGetUint32(td);
@@ -134,7 +131,6 @@ uint32_t *rpmtdNextUint32(rpmtd td)
uint64_t *rpmtdNextUint64(rpmtd td)
{
- assert(td != NULL);
uint64_t *res = NULL;
if (rpmtdNext(td) >= 0) {
res = rpmtdGetUint64(td);
@@ -144,7 +140,6 @@ uint64_t *rpmtdNextUint64(rpmtd td)
const char *rpmtdNextString(rpmtd td)
{
- assert(td != NULL);
const char *res = NULL;
if (rpmtdNext(td) >= 0) {
res = rpmtdGetString(td);
@@ -156,9 +151,7 @@ char * rpmtdGetChar(rpmtd td)
{
char *res = NULL;
- assert(td != NULL);
-
- if (td->type == RPM_CHAR_TYPE) {
+ if (td != NULL && td->type == RPM_CHAR_TYPE) {
int ix = (td->ix >= 0 ? td->ix : 0);
res = (char *) td->data + ix;
}
@@ -168,9 +161,7 @@ uint16_t * rpmtdGetUint16(rpmtd td)
{
uint16_t *res = NULL;
- assert(td != NULL);
-
- if (td->type == RPM_INT16_TYPE) {
+ if (td != NULL && td->type == RPM_INT16_TYPE) {
int ix = (td->ix >= 0 ? td->ix : 0);
res = (uint16_t *) td->data + ix;
}
@@ -181,9 +172,7 @@ uint32_t * rpmtdGetUint32(rpmtd td)
{
uint32_t *res = NULL;
- assert(td != NULL);
-
- if (td->type == RPM_INT32_TYPE) {
+ if (td != NULL && td->type == RPM_INT32_TYPE) {
int ix = (td->ix >= 0 ? td->ix : 0);
res = (uint32_t *) td->data + ix;
}
@@ -194,9 +183,7 @@ uint64_t * rpmtdGetUint64(rpmtd td)
{
uint64_t *res = NULL;
- assert(td != NULL);
-
- if (td->type == RPM_INT64_TYPE) {
+ if (td != NULL && td->type == RPM_INT64_TYPE) {
int ix = (td->ix >= 0 ? td->ix : 0);
res = (uint64_t *) td->data + ix;
}
@@ -207,7 +194,8 @@ const char * rpmtdGetString(rpmtd td)
{
const char *str = NULL;
- assert(td != NULL);
+ if (td == NULL)
+ return NULL;
if (td->type == RPM_STRING_TYPE) {
str = (const char *) td->data;
@@ -222,10 +210,12 @@ const char * rpmtdGetString(rpmtd td)
uint64_t rpmtdGetNumber(rpmtd td)
{
- assert(td != NULL);
uint64_t val = 0;
int ix = (td->ix >= 0 ? td->ix : 0);
+ if (td == NULL)
+ return 0;
+
switch (td->type) {
case RPM_INT64_TYPE:
val = *((uint64_t *) td->data + ix);
@@ -248,12 +238,12 @@ uint64_t rpmtdGetNumber(rpmtd td)
char *rpmtdFormat(rpmtd td, rpmtdFormats fmt, const char *errmsg)
{
- headerTagFormatFunction func = rpmHeaderFormatFuncByValue(fmt);
+ headerFmt ext = rpmHeaderFormatByValue(fmt);
const char *err = NULL;
char *str = NULL;
- if (func) {
- str = func(td);
+ if (ext) {
+ str = rpmHeaderFormatCall(ext, td);
} else {
err = _("Unknown format");
}
@@ -267,10 +257,12 @@ char *rpmtdFormat(rpmtd td, rpmtdFormats fmt, const char *errmsg)
int rpmtdSetTag(rpmtd td, rpmTagVal tag)
{
- assert(td != NULL);
rpmTagType newtype = rpmTagGetTagType(tag);
int rc = 0;
+ if (td == NULL)
+ goto exit;
+
/*
* Sanity checks:
* - is the new tag valid at all
@@ -425,8 +417,10 @@ rpmtd rpmtdDup(rpmtd td)
rpmtd newtd = NULL;
char **data = NULL;
int i;
+
+ if (td == NULL)
+ return NULL;
- assert(td != NULL);
/* TODO: permit other types too */
if (td->type != RPM_STRING_ARRAY_TYPE && td->type != RPM_I18NSTRING_TYPE) {
return NULL;
diff --git a/lib/rpmtd.h b/lib/rpmtd.h
index de7101123..040ddb340 100644
--- a/lib/rpmtd.h
+++ b/lib/rpmtd.h
@@ -1,6 +1,12 @@
#ifndef _RPMTD_H
#define _RPMTD_H
+/** \ingroup rpmtd
+ * \file lib/rpmtd.h
+ *
+ * RPM Tag Data Container API
+ */
+
#include <rpm/rpmtypes.h>
#include <rpm/argv.h>
@@ -30,6 +36,7 @@ struct rpmtd_s {
rpm_data_t data; /* pointer to actual data */
rpmtdFlags flags; /* flags on memory allocation etc */
int ix; /* iteration index */
+ rpm_count_t size; /* size of data (only works for RPMTD_IMMUTABLE atm) */
};
/** \ingroup rpmtd
@@ -67,6 +74,14 @@ void rpmtdFreeData(rpmtd td);
rpm_count_t rpmtdCount(rpmtd td);
/** \ingroup rpmtd
+ * Retrieve container data size (eg required for allocation).
+ * Note this currently only works for RPMTD_IMMUTABLE data.
+ * @param td Tag data container
+ * @return Data size in bytes.
+ */
+rpm_count_t rpmtdSize(rpmtd td);
+
+/** \ingroup rpmtd
* Retrieve tag of the container.
* @param td Tag data container
* @return Rpm tag.
diff --git a/lib/rpmte.c b/lib/rpmte.c
index da6f48c5c..66194dc3b 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -13,6 +13,7 @@
#include <rpm/rpmdb.h>
#include <rpm/rpmlog.h>
+#include "lib/misc.h"
#include "lib/rpmplugins.h"
#include "lib/rpmte_internal.h"
/* strpool-related interfaces */
@@ -50,7 +51,8 @@ struct rpmte_s {
rpmds conflicts; /*!< Conflicts: dependencies. */
rpmds obsoletes; /*!< Obsoletes: dependencies. */
rpmds order; /*!< Order: dependencies. */
- rpmfi fi; /*!< File information. */
+ rpmfiles files; /*!< File information. */
+ rpmfi fi; /*!< File iterator (backwards compat) */
rpmps probs; /*!< Problems (relocations) */
rpmts ts; /*!< Parent transaction */
@@ -70,11 +72,6 @@ struct rpmte_s {
int failed; /*!< (parent) install/erase failed */
rpmfs fs;
-
- ARGV_t lastInCollectionsAny; /*!< list of collections this te is the last to be installed or removed */
- ARGV_t lastInCollectionsAdd; /*!< list of collections this te is the last to be only installed */
- ARGV_t firstInCollectionsRemove; /*!< list of collections this te is the first to be only removed */
- ARGV_t collections; /*!< list of collections */
};
/* forward declarations */
@@ -91,111 +88,26 @@ void rpmteCleanDS(rpmte te)
te->order = rpmdsFree(te->order);
}
-static rpmfi getFI(rpmte p, Header h)
+static rpmfiles getFiles(rpmte p, Header h)
{
rpmfiFlags fiflags;
fiflags = (p->type == TR_ADDED) ? (RPMFI_NOHEADER | RPMFI_FLAGS_INSTALL) :
(RPMFI_NOHEADER | RPMFI_FLAGS_ERASE);
/* relocate stuff in header if necessary */
- if (rpmteType(p) == TR_ADDED && rpmfsFC(p->fs) > 0 && p->nrelocs) {
- if (!headerIsSource(h) && !headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
- rpmRelocateFileList(p->relocs, p->nrelocs, p->fs, h);
- }
- }
- return rpmfiNewPool(rpmtsPool(p->ts), h, RPMTAG_BASENAMES, fiflags);
-}
-
-/* stupid bubble sort, but it's probably faster here */
-static void sortRelocs(rpmRelocation *relocations, int numRelocations)
-{
- for (int i = 0; i < numRelocations; i++) {
- int madeSwap = 0;
- for (int j = 1; j < numRelocations; j++) {
- rpmRelocation tmpReloc;
- if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
- relocations[j ].oldPath == NULL || /* XXX can't happen */
- strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
- continue;
- tmpReloc = relocations[j - 1];
- relocations[j - 1] = relocations[j];
- relocations[j] = tmpReloc;
- madeSwap = 1;
- }
- if (!madeSwap) break;
- }
-}
-
-static char * stripTrailingChar(char * s, char c)
-{
- char * t;
- for (t = s + strlen(s) - 1; *t == c && t >= s; t--)
- *t = '\0';
- return s;
-}
-
-static void buildRelocs(rpmte p, Header h, rpmRelocation *relocs)
-{
- int i;
- struct rpmtd_s validRelocs;
-
- for (rpmRelocation *r = relocs; r->oldPath || r->newPath; r++)
- p->nrelocs++;
-
- headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM);
- p->relocs = xmalloc(sizeof(*p->relocs) * (p->nrelocs+1));
-
- /* Build sorted relocation list from raw relocations. */
- for (i = 0; i < p->nrelocs; i++) {
- char * t;
-
- /*
- * Default relocations (oldPath == NULL) are handled in the UI,
- * not rpmlib.
- */
- if (relocs[i].oldPath == NULL) continue; /* XXX can't happen */
-
- /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
- too, but those are more trouble to fix up. :-( */
- t = xstrdup(relocs[i].oldPath);
- p->relocs[i].oldPath = (t[0] == '/' && t[1] == '\0')
- ? t
- : stripTrailingChar(t, '/');
-
- /* An old path w/o a new path is valid, and indicates exclusion */
- if (relocs[i].newPath) {
- int valid = 0;
- const char *validprefix;
-
- t = xstrdup(relocs[i].newPath);
- p->relocs[i].newPath = (t[0] == '/' && t[1] == '\0')
- ? t
- : stripTrailingChar(t, '/');
-
- /* FIX: relocations[i].oldPath == NULL */
- /* Verify that the relocation's old path is in the header. */
- rpmtdInit(&validRelocs);
- while ((validprefix = rpmtdNextString(&validRelocs))) {
- if (rstreq(validprefix, p->relocs[i].oldPath)) {
- valid = 1;
- break;
+ if (rpmteType(p) == TR_ADDED && rpmfsFC(p->fs) > 0) {
+ if (!headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
+ if (rpmteIsSource(p)) {
+ /* Unlike binary packages, source relocation can fail */
+ if (rpmRelocateSrpmFileList(h, rpmtsRootDir(p->ts)) < 0) {
+ return NULL;
}
+ } else {
+ rpmRelocateFileList(p->relocs, p->nrelocs, p->fs, h);
}
-
- if (!valid) {
- if (p->badrelocs == NULL)
- p->badrelocs = xcalloc(p->nrelocs, sizeof(*p->badrelocs));
- p->badrelocs[i] = 1;
- }
- } else {
- p->relocs[i].newPath = NULL;
}
}
- p->relocs[i].oldPath = NULL;
- p->relocs[i].newPath = NULL;
- sortRelocs(p->relocs, p->nrelocs);
-
- rpmtdFreeData(&validRelocs);
+ return rpmfilesNew(rpmtsPool(p->ts), h, RPMTAG_BASENAMES, fiflags);
}
/**
@@ -208,7 +120,7 @@ static void buildRelocs(rpmte p, Header h, rpmRelocation *relocs)
static int addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
{
rpmstrPool tspool = rpmtsPool(p->ts);
- struct rpmtd_s colls, bnames;
+ struct rpmtd_s bnames;
int rc = 1; /* assume failure */
p->name = headerGetAsString(h, RPMTAG_NAME);
@@ -237,7 +149,7 @@ static int addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
p->relocs = NULL;
p->badrelocs = NULL;
if (relocs != NULL)
- buildRelocs(p, h, relocs);
+ rpmRelocationBuild(h, relocs, &p->nrelocs, &p->relocs, &p->badrelocs);
p->db_instance = headerGetInstance(h);
p->key = key;
@@ -258,10 +170,10 @@ static int addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
p->fs = rpmfsNew(rpmtdCount(&bnames), (p->type == TR_ADDED));
rpmtdFreeData(&bnames);
- p->fi = getFI(p, h);
+ p->files = getFiles(p, h);
/* Packages with no files return an empty file info set, NULL is an error */
- if (p->fi == NULL)
+ if (p->files == NULL)
goto exit;
/* See if we have pre/posttrans scripts. */
@@ -272,19 +184,6 @@ static int addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
headerIsEntry(h, RPMTAG_POSTTRANSPROG)) ?
RPMTE_HAVE_POSTTRANS : 0;
- p->lastInCollectionsAny = NULL;
- p->lastInCollectionsAdd = NULL;
- p->firstInCollectionsRemove = NULL;
- p->collections = NULL;
- if (headerGet(h, RPMTAG_COLLECTIONS, &colls, HEADERGET_MINMEM)) {
- const char *collname;
- while ((collname = rpmtdNextString(&colls))) {
- argvAdd(&p->collections, collname);
- }
- argvSort(p->collections, NULL);
- rpmtdFreeData(&colls);
- }
-
rpmteColorDS(p, RPMTAG_PROVIDENAME);
rpmteColorDS(p, RPMTAG_REQUIRENAME);
@@ -320,16 +219,12 @@ rpmte rpmteFree(rpmte te)
fdFree(te->fd);
rpmfiFree(te->fi);
+ rpmfilesFree(te->files);
headerFree(te->h);
rpmfsFree(te->fs);
rpmpsFree(te->probs);
rpmteCleanDS(te);
- argvFree(te->collections);
- argvFree(te->lastInCollectionsAny);
- argvFree(te->lastInCollectionsAdd);
- argvFree(te->firstInCollectionsRemove);
-
memset(te, 0, sizeof(*te)); /* XXX trash and burn */
free(te);
}
@@ -433,46 +328,6 @@ rpm_color_t rpmteSetColor(rpmte te, rpm_color_t color)
return ocolor;
}
-ARGV_const_t rpmteCollections(rpmte te)
-{
- return (te != NULL) ? te->collections : NULL;
-}
-
-int rpmteHasCollection(rpmte te, const char *collname)
-{
- return (argvSearch(rpmteCollections(te), collname, NULL) != NULL);
-}
-
-int rpmteAddToLastInCollectionAdd(rpmte te, const char *collname)
-{
- if (te != NULL) {
- argvAdd(&te->lastInCollectionsAdd, collname);
- argvSort(te->lastInCollectionsAdd, NULL);
- return 0;
- }
- return -1;
-}
-
-int rpmteAddToLastInCollectionAny(rpmte te, const char *collname)
-{
- if (te != NULL) {
- argvAdd(&te->lastInCollectionsAny, collname);
- argvSort(te->lastInCollectionsAny, NULL);
- return 0;
- }
- return -1;
-}
-
-int rpmteAddToFirstInCollectionRemove(rpmte te, const char *collname)
-{
- if (te != NULL) {
- argvAdd(&te->firstInCollectionsRemove, collname);
- argvSort(te->firstInCollectionsRemove, NULL);
- return 0;
- }
- return -1;
-}
-
rpm_loff_t rpmtePkgFileSize(rpmte te)
{
return (te != NULL ? te->pkgFileSize : 0);
@@ -571,14 +426,12 @@ rpmds rpmteDS(rpmte te, rpmTagVal tag)
return NULL;
}
-rpmfi rpmteSetFI(rpmte te, rpmfi fi)
+void rpmteCleanFiles(rpmte te)
{
if (te != NULL) {
te->fi = rpmfiFree(te->fi);
- if (fi != NULL)
- te->fi = rpmfiLink(fi);
+ te->files = rpmfilesFree(te->files);
}
- return NULL;
}
rpmfi rpmteFI(rpmte te)
@@ -586,12 +439,20 @@ rpmfi rpmteFI(rpmte te)
if (te == NULL)
return NULL;
+ if (te->fi == NULL)
+ te->fi = rpmfilesIter(te->files, RPMFI_ITER_FWD);
+
return te->fi; /* XXX take fi reference here? */
}
+rpmfiles rpmteFiles(rpmte te)
+{
+ return (te != NULL) ? rpmfilesLink(te->files) : NULL;
+}
+
static void rpmteColorDS(rpmte te, rpmTag tag)
{
- rpmfi fi = rpmteFI(te);
+ rpmfi fi;
rpmds ds = rpmteDS(te, tag);
char deptype = 'R';
char mydt;
@@ -602,7 +463,7 @@ static void rpmteColorDS(rpmte te, rpmTag tag)
unsigned ix;
int ndx, i;
- if (!(te && (Count = rpmdsCount(ds)) > 0 && rpmfiFC(fi) > 0))
+ if (!(te && (Count = rpmdsCount(ds)) > 0 && rpmfilesFC(te->files) > 0))
return;
switch (tag) {
@@ -620,8 +481,7 @@ static void rpmteColorDS(rpmte te, rpmTag tag)
colors = xcalloc(Count, sizeof(*colors));
/* Calculate dependency color. */
- fi = rpmfiInit(fi, 0);
- if (fi != NULL)
+ fi = rpmfilesIter(te->files, RPMFI_ITER_FWD);
while (rpmfiNext(fi) >= 0) {
val = rpmfiFColor(fi);
ddict = NULL;
@@ -646,6 +506,7 @@ assert (ix < Count);
(void) rpmdsSetColor(ds, val);
}
free(colors);
+ rpmfiFree(fi);
}
static Header rpmteDBHeader(rpmte te)
@@ -707,8 +568,8 @@ static int rpmteOpen(rpmte te, int reload_fi)
if (h != NULL) {
if (reload_fi) {
/* This can fail if we get a different, bad header from callback */
- te->fi = getFI(te, h);
- rc = (te->fi != NULL);
+ te->files = getFiles(te, h);
+ rc = (te->files != NULL);
} else {
rc = 1;
}
@@ -739,7 +600,7 @@ static int rpmteClose(rpmte te, int reset_fi)
}
rpmteSetHeader(te, NULL);
if (reset_fi) {
- rpmteSetFI(te, NULL);
+ rpmteCleanFiles(te);
}
return 1;
}
@@ -864,7 +725,7 @@ void rpmteAddRelocProblems(rpmte te)
const char * rpmteTypeString(rpmte te)
{
- switch(rpmteType(te)) {
+ switch (rpmteType(te)) {
case TR_ADDED: return _("install");
case TR_REMOVED: return _("erase");
default: return "???";
@@ -876,70 +737,7 @@ rpmfs rpmteGetFileStates(rpmte te)
return te->fs;
}
-rpmRC rpmteSetupCollectionPlugins(rpmte te)
-{
- ARGV_const_t colls = rpmteCollections(te);
- rpmPlugins plugins = rpmtsPlugins(te->ts);
- rpmRC rc = RPMRC_OK;
-
- if (!colls) {
- return rc;
- }
-
- rpmteOpen(te, 0);
- for (; colls && *colls; colls++) {
- if (!rpmpluginsPluginAdded(plugins, *colls)) {
- rc = rpmpluginsAddPlugin(plugins, "collection", *colls);
- if (rc != RPMRC_OK) {
- break;
- }
- }
- rc = rpmpluginsCallOpenTE(plugins, *colls, te);
- if (rc != RPMRC_OK) {
- break;
- }
- }
- rpmteClose(te, 0);
-
- return rc;
-}
-
-static rpmRC rpmteRunAllCollections(rpmte te, rpmPluginHook hook)
-{
- ARGV_const_t colls;
- rpmRC(*collHook) (rpmPlugins, const char *);
- rpmRC rc = RPMRC_OK;
-
- if (rpmtsFlags(te->ts) & RPMTRANS_FLAG_NOCOLLECTIONS) {
- goto exit;
- }
-
- switch (hook) {
- case PLUGINHOOK_COLL_POST_ADD:
- colls = te->lastInCollectionsAdd;
- collHook = rpmpluginsCallCollectionPostAdd;
- break;
- case PLUGINHOOK_COLL_POST_ANY:
- colls = te->lastInCollectionsAny;
- collHook = rpmpluginsCallCollectionPostAny;
- break;
- case PLUGINHOOK_COLL_PRE_REMOVE:
- colls = te->firstInCollectionsRemove;
- collHook = rpmpluginsCallCollectionPreRemove;
- break;
- default:
- goto exit;
- }
-
- for (; colls && *colls; colls++) {
- rc = collHook(rpmtsPlugins(te->ts), *colls);
- }
-
- exit:
- return rc;
-}
-
-int rpmteProcess(rpmte te, pkgGoal goal)
+int rpmteProcess(rpmte te, pkgGoal goal, int num)
{
/* Only install/erase resets pkg file info */
int scriptstage = (goal != PKG_INSTALL && goal != PKG_ERASE);
@@ -954,20 +752,16 @@ int rpmteProcess(rpmte te, pkgGoal goal)
}
}
- if (!scriptstage) {
- rpmteRunAllCollections(te, PLUGINHOOK_COLL_PRE_REMOVE);
- }
-
if (rpmteOpen(te, reset_fi)) {
+ if (!scriptstage) {
+ rpmtsNotify(te->ts, te, RPMCALLBACK_ELEM_PROGRESS, num,
+ rpmtsMembers(te->ts)->orderCount);
+ }
+
failed = rpmpsmRun(te->ts, te, goal);
rpmteClose(te, reset_fi);
}
- if (!scriptstage) {
- rpmteRunAllCollections(te, PLUGINHOOK_COLL_POST_ADD);
- rpmteRunAllCollections(te, PLUGINHOOK_COLL_POST_ANY);
- }
-
if (failed) {
failed = rpmteMarkFailed(te);
}
diff --git a/lib/rpmte.h b/lib/rpmte.h
index a66c1e91f..c52c44a09 100644
--- a/lib/rpmte.h
+++ b/lib/rpmte.h
@@ -233,27 +233,19 @@ int rpmteFailed(rpmte te);
rpmds rpmteDS(rpmte te, rpmTagVal tag);
/** \ingroup rpmte
- * Retrieve file info tag set from transaction element.
+ * Retrieve file info set from transaction element.
* @param te transaction element
- * @return file info tag set
+ * @return file info set (refcounted)
*/
-rpmfi rpmteFI(rpmte te);
+rpmfiles rpmteFiles(rpmte te);
/** \ingroup rpmte
- * Retrieve list of collections
+ * Retrieve file info iterator from transaction element.
+ * @deprecated use rpmteFiles() instead
* @param te transaction element
- * @return list of collections
- */
-ARGV_const_t rpmteCollections(rpmte te);
-
-/** \ingroup rpmte
- * Determine a transaction element is part of a collection
- * @param te transaction element
- * @param collname collection name
- * @return 1 if collname is part of a collection, 0 if not
+ * @return file info tag set
*/
-int rpmteHasCollection(rpmte te, const char * collname);
-
+rpmfi rpmteFI(rpmte te);
#ifdef __cplusplus
}
diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h
index abcdb9020..a5a991ec5 100644
--- a/lib/rpmte_internal.h
+++ b/lib/rpmte_internal.h
@@ -14,6 +14,8 @@ typedef enum pkgGoal_e {
PKG_VERIFY = RPMTAG_VERIFYSCRIPT,
PKG_PRETRANS = RPMTAG_PRETRANS,
PKG_POSTTRANS = RPMTAG_POSTTRANS,
+ PKG_TRANSFILETRIGGERIN = RPMTAG_TRANSFILETRIGGERIN,
+ PKG_TRANSFILETRIGGERUN = RPMTAG_TRANSFILETRIGGERUN,
} pkgGoal;
/** \ingroup rpmte
@@ -47,7 +49,7 @@ RPM_GNUC_INTERNAL
rpmte rpmteFree(rpmte te);
RPM_GNUC_INTERNAL
-rpmfi rpmteSetFI(rpmte te, rpmfi fi);
+void rpmteCleanFiles(rpmte te);
RPM_GNUC_INTERNAL
FD_t rpmteSetFd(rpmte te, FD_t fd);
@@ -56,7 +58,7 @@ RPM_GNUC_INTERNAL
FD_t rpmtePayload(rpmte te);
RPM_GNUC_INTERNAL
-int rpmteProcess(rpmte te, pkgGoal goal);
+int rpmteProcess(rpmte te, pkgGoal goal, int num);
RPM_GNUC_INTERNAL
void rpmteAddProblem(rpmte te, rpmProblemType type,
@@ -84,18 +86,6 @@ int rpmteHaveTransScript(rpmte te, rpmTagVal tag);
/* XXX should be internal too but build code needs for now... */
rpmfs rpmteGetFileStates(rpmte te);
-/* XXX here for now... */
-/**
- * Relocate files in header.
- * @todo multilib file dispositions need to be checked.
- * @param relocations relocations
- * @param numRelocations number of relocations
- * @param fs file state set
- * @param h package header to relocate
- */
-RPM_GNUC_INTERNAL
-void rpmRelocateFileList(rpmRelocation *relocs, int numRelocations, rpmfs fs, Header h);
-
/** \ingroup rpmte
* Retrieve size in bytes of package header.
* @param te transaction element
@@ -114,44 +104,6 @@ unsigned int rpmteHeaderSize(rpmte te);
RPM_GNUC_INTERNAL
rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal);
-/** \ingroup rpmte
- * Add a collection to the list of last collections for the installation
- * section of a transaction element
- * @param te transaction element
- * @param collname collection name
- * @return 0 on success, non-zero on error
- */
-RPM_GNUC_INTERNAL
-int rpmteAddToLastInCollectionAdd(rpmte te, const char * collname);
-
-/** \ingroup rpmte
- * Add a collection to the list of last collections for the installation
- * or removal section of a transaction element
- * @param te transaction element
- * @param collname collection name
- * @return 0 on success, non-zero on error
- */
-RPM_GNUC_INTERNAL
-int rpmteAddToLastInCollectionAny(rpmte te, const char * collname);
-
-/** \ingroup rpmte
- * Add a collection to the list of first collections for the removal
- * section of a transaction element
- * @param te transaction element
- * @param collname collection name
- * @return 0 on success, non-zero on error
- */
-RPM_GNUC_INTERNAL
-int rpmteAddToFirstInCollectionRemove(rpmte te, const char * collname);
-
-/** \ingroup rpmte
- * Sends the open te plugin hook for each plugins with the transaction element open
- * @param te transaction element
- * @return 0 on success, non-zero on error
- */
-RPM_GNUC_INTERNAL
-rpmRC rpmteSetupCollectionPlugins(rpmte te);
-
#ifdef __cplusplus
}
#endif
diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c
new file mode 100644
index 000000000..23a913d35
--- /dev/null
+++ b/lib/rpmtriggers.c
@@ -0,0 +1,632 @@
+#include "system.h"
+
+#include <rpm/rpmts.h>
+#include <rpm/rpmdb.h>
+#include <rpm/rpmds.h>
+#include <rpm/rpmfi.h>
+#include <stdlib.h>
+
+#include "lib/rpmtriggers.h"
+#include "lib/rpmts_internal.h"
+#include "lib/rpmdb_internal.h"
+#include "lib/rpmds_internal.h"
+#include "lib/rpmfi_internal.h"
+#include "lib/rpmte_internal.h"
+#include "lib/rpmchroot.h"
+
+#define TRIGGER_PRIORITY_BOUND 10000
+
+rpmtriggers rpmtriggersCreate(unsigned int hint)
+{
+ rpmtriggers triggers = xmalloc(sizeof(struct rpmtriggers_s));
+ triggers->count = 0;
+ triggers->alloced = hint;
+ triggers->triggerInfo = xmalloc(sizeof(struct triggerInfo_s) *
+ triggers->alloced);
+ return triggers;
+}
+
+rpmtriggers rpmtriggersFree(rpmtriggers triggers)
+{
+ _free(triggers->triggerInfo);
+ _free(triggers);
+
+ return NULL;
+}
+
+static void rpmtriggersAdd(rpmtriggers trigs, unsigned int hdrNum,
+ unsigned int tix, unsigned int priority)
+{
+ if (trigs->count == trigs->alloced) {
+ trigs->alloced <<= 1;
+ trigs->triggerInfo = xrealloc(trigs->triggerInfo,
+ sizeof(struct triggerInfo_s) * trigs->alloced);
+ }
+
+ trigs->triggerInfo[trigs->count].hdrNum = hdrNum;
+ trigs->triggerInfo[trigs->count].tix = tix;
+ trigs->triggerInfo[trigs->count].priority = priority;
+ trigs->count++;
+}
+
+static int trigCmp(const void *a, const void *b)
+{
+ const struct triggerInfo_s *trigA = a, *trigB = b;
+
+ if (trigA->priority < trigB->priority)
+ return 1;
+
+ if (trigA->priority > trigB->priority)
+ return -1;
+
+ if (trigA->hdrNum < trigB->hdrNum)
+ return -1;
+
+ if (trigA->hdrNum > trigB->hdrNum)
+ return 1;
+
+ if (trigA->tix < trigB->tix)
+ return -1;
+
+ if (trigA->tix > trigB->tix)
+ return 1;
+
+ return 0;
+}
+
+static void rpmtriggersSortAndUniq(rpmtriggers trigs)
+{
+ unsigned int from;
+ unsigned int to = 0;
+ unsigned int count = trigs->count;
+
+ if (count > 1)
+ qsort(trigs->triggerInfo, count, sizeof(struct triggerInfo_s), trigCmp);
+
+ for (from = 0; from < count; from++) {
+ if (from > 0 &&
+ !trigCmp((const void *) &trigs->triggerInfo[from - 1],
+ (const void *) &trigs->triggerInfo[from])) {
+
+ trigs->count--;
+ continue;
+ }
+ if (from != to)
+ trigs->triggerInfo[to] = trigs->triggerInfo[from];
+ to++;
+ }
+}
+
+void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te)
+{
+ rpmdbMatchIterator mi;
+ rpmdbIndexIterator ii;
+ Header trigH;
+ const void *key;
+ size_t keylen;
+ rpmfiles files;
+ rpmds rpmdsTriggers;
+ rpmds rpmdsTrigger;
+
+ ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMDBI_TRANSFILETRIGGERNAME);
+ mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_PACKAGES);
+ files = rpmteFiles(te);
+
+ /* Iterate over file triggers in rpmdb */
+ while ((rpmdbIndexIteratorNext(ii, &key, &keylen)) == 0) {
+ char pfx[keylen + 1];
+ memcpy(pfx, key, keylen);
+ pfx[keylen] = '\0';
+ /* Check if file trigger matches any installed file in this te */
+ rpmfi fi = rpmfilesFindPrefix(files, pfx);
+ while (rpmfiNext(fi) >= 0) {
+ if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) {
+ /* If yes then store it */
+ rpmdbAppendIterator(mi, rpmdbIndexIteratorPkgOffsets(ii),
+ rpmdbIndexIteratorNumPkgs(ii));
+ break;
+ }
+ }
+ rpmfiFree(fi);
+ }
+ rpmdbIndexIteratorFree(ii);
+
+ if (rpmdbGetIteratorCount(mi)) {
+ /* Filter triggers and save only trans postun triggers into ts */
+ while ((trigH = rpmdbNextIterator(mi)) != NULL) {
+ int tix = 0;
+ rpmdsTriggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0);
+ while ((rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, tix))) {
+ if ((rpmdsNext(rpmdsTrigger) >= 0) &&
+ (rpmdsFlags(rpmdsTrigger) & RPMSENSE_TRIGGERPOSTUN)) {
+ struct rpmtd_s priorities;
+
+ headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES,
+ &priorities, HEADERGET_MINMEM);
+ rpmtdSetIndex(&priorities, tix);
+ rpmtriggersAdd(ts->trigs2run, rpmdbGetIteratorOffset(mi),
+ tix, *rpmtdGetUint32(&priorities));
+ }
+ rpmdsFree(rpmdsTrigger);
+ tix++;
+ }
+ rpmdsFree(rpmdsTriggers);
+ }
+ }
+ rpmdbFreeIterator(mi);
+}
+
+int runPostUnTransFileTrigs(rpmts ts)
+{
+ int i;
+ Header trigH;
+ struct rpmtd_s installPrefixes;
+ rpmScript script;
+ rpmtriggers trigs = ts->trigs2run;
+ int nerrors = 0;
+
+ if (rpmChrootIn() != 0)
+ return -1;
+
+ rpmtriggersSortAndUniq(trigs);
+ /* Iterate over stored triggers */
+ for (i = 0; i < trigs->count; i++) {
+ /* Get header containing trigger script */
+ trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts),
+ trigs->triggerInfo[i].hdrNum);
+
+ /* Maybe package with this trigger is already uninstalled */
+ if (trigH == NULL)
+ continue;
+
+ /* Prepare and run script */
+ script = rpmScriptFromTriggerTag(trigH,
+ triggertag(RPMSENSE_TRIGGERPOSTUN),
+ RPMSCRIPT_TRANSFILETRIGGER, trigs->triggerInfo[i].tix);
+
+ headerGet(trigH, RPMTAG_INSTPREFIXES, &installPrefixes,
+ HEADERGET_ALLOC|HEADERGET_ARGV);
+
+ nerrors += runScript(ts, NULL, trigH, installPrefixes.data, script, 0, 0);
+ rpmtdFreeData(&installPrefixes);
+ rpmScriptFree(script);
+ headerFree(trigH);
+ }
+
+ rpmChrootOut();
+
+ return nerrors;
+}
+
+/*
+ * Get files from next package from match iterator. If files are
+ * available in memory then don't read them from rpmdb.
+ */
+static rpmfiles rpmtsNextFiles(rpmts ts, rpmdbMatchIterator mi)
+{
+ Header h;
+ rpmte *te;
+ rpmfiles files = NULL;
+ rpmstrPool pool = ts->members->pool;
+ int ix;
+ unsigned int offset;
+
+ ix = rpmdbGetIteratorIndex(mi);
+ if (ix < rpmdbGetIteratorCount(mi)) {
+ offset = rpmdbGetIteratorOffsetFor(mi, ix);
+ if (packageHashGetEntry(ts->members->removedPackages, offset,
+ &te, NULL, NULL)) {
+ /* Files are available in memory */
+ files = rpmteFiles(te[0]);
+ }
+
+ if (packageHashGetEntry(ts->members->installedPackages, offset,
+ &te, NULL, NULL)) {
+ /* Files are available in memory */
+ files = rpmteFiles(te[0]);
+ }
+ }
+
+ if (files) {
+ rpmdbSetIteratorIndex(mi, ix + 1);
+ } else {
+ /* Files are not available in memory. Read them from rpmdb */
+ h = rpmdbNextIterator(mi);
+ if (h) {
+ files = rpmfilesNew(pool, h, RPMTAG_BASENAMES,
+ RPMFI_FLAGS_FILETRIGGER);
+ }
+ }
+
+ return files;
+}
+
+
+typedef struct matchFilesIter_s {
+ rpmts ts;
+ rpmds rpmdsTrigger;
+ rpmfiles files;
+ rpmfi fi;
+ rpmfs fs;
+ const char *pfx;
+ rpmdbMatchIterator pi;
+ packageHash tranPkgs;
+} *matchFilesIter;
+
+static matchFilesIter matchFilesIterator(rpmds trigger, rpmfiles files, rpmte te)
+{
+ matchFilesIter mfi = xcalloc(1, sizeof(*mfi));
+ rpmdsInit(trigger);
+ mfi->rpmdsTrigger = trigger;
+ mfi->files = rpmfilesLink(files);
+ mfi->fs = rpmteGetFileStates(te);
+ return mfi;
+}
+
+static matchFilesIter matchDBFilesIterator(rpmds trigger, rpmts ts,
+ int inTransaction)
+{
+ matchFilesIter mfi = xcalloc(1, sizeof(*mfi));
+ rpmsenseFlags sense;
+
+ rpmdsSetIx(trigger, 0);
+ sense = rpmdsFlags(trigger);
+ rpmdsInit(trigger);
+
+ mfi->rpmdsTrigger = trigger;
+ mfi->ts = ts;
+
+ /* If inTransaction is set then filter out packages that aren't in transaction */
+ if (inTransaction) {
+ if (sense & RPMSENSE_TRIGGERIN)
+ mfi->tranPkgs = ts->members->installedPackages;
+ else
+ mfi->tranPkgs = ts->members->removedPackages;
+ }
+ return mfi;
+}
+
+static const char *matchFilesNext(matchFilesIter mfi)
+{
+ const char *matchFile = NULL;
+ int fx = 0;
+
+ /* Decide if we iterate over given files (mfi->files) */
+ if (!mfi->ts)
+ do {
+ /* Get next file from mfi->fi */
+ matchFile = NULL;
+ while (matchFile == NULL && rpmfiNext(mfi->fi) >= 0) {
+ if (!XFA_SKIPPING(rpmfsGetAction(mfi->fs, rpmfiFX(mfi->fi))))
+ matchFile = rpmfiFN(mfi->fi);
+ }
+ if (matchFile)
+ break;
+
+ /* If we are done with current mfi->fi, create mfi->fi for next prefix */
+ fx = rpmdsNext(mfi->rpmdsTrigger);
+ mfi->pfx = rpmdsN(mfi->rpmdsTrigger);
+ rpmfiFree(mfi->fi);
+ mfi->fi = rpmfilesFindPrefix(mfi->files, mfi->pfx);
+
+ } while (fx >= 0);
+ /* or we iterate over files in rpmdb */
+ else
+ do {
+ matchFile = NULL;
+ while (matchFile == NULL && rpmfiNext(mfi->fi) >= 0) {
+ if (RPMFILE_IS_INSTALLED(rpmfiFState(mfi->fi)))
+ matchFile = rpmfiFN(mfi->fi);
+ }
+ if (matchFile)
+ break;
+
+ /* If we are done with current mfi->fi, create mfi->fi for next package */
+ rpmfilesFree(mfi->files);
+ rpmfiFree(mfi->fi);
+ mfi->files = rpmtsNextFiles(mfi->ts, mfi->pi);
+ mfi->fi = rpmfilesFindPrefix(mfi->files, mfi->pfx);
+ if (mfi->files)
+ continue;
+
+ /* If we are done with all packages, go through packages with new prefix */
+ fx = rpmdsNext(mfi->rpmdsTrigger);
+ mfi->pfx = rpmdsN(mfi->rpmdsTrigger);
+ rpmdbFreeIterator(mfi->pi);
+ mfi->pi = rpmdbInitPrefixIterator(rpmtsGetRdb(mfi->ts),
+ RPMDBI_DIRNAMES, mfi->pfx, 0);
+
+ rpmdbFilterIterator(mfi->pi, mfi->tranPkgs, 0);
+ /* Only walk through each header with matches once */
+ rpmdbUniqIterator(mfi->pi);
+
+ } while (fx >= 0);
+
+
+ return matchFile;
+}
+
+static int matchFilesEmpty(matchFilesIter mfi)
+{
+ const char *matchFile;
+
+ /* Try to get the first file */
+ matchFile = matchFilesNext(mfi);
+
+ /* Rewind back this file */
+ rpmfiInit(mfi->fi, 0);
+
+ if (matchFile)
+ /* We have at least one file so iterator is not empty */
+ return 0;
+ else
+ /* No file in iterator */
+ return 1;
+}
+
+static matchFilesIter matchFilesIteratorFree(matchFilesIter mfi)
+{
+ rpmfiFree(mfi->fi);
+ rpmfilesFree(mfi->files);
+ rpmdbFreeIterator(mfi->pi);
+ free(mfi);
+ return NULL;
+}
+
+/*
+ * Run all file triggers in header h
+ * @param searchMode 0 match trigger prefixes against files in te
+ * 1 match trigger prefixes against files in whole ts
+ * 2 match trigger prefixes against files in whole
+ * rpmdb
+ */
+static int runHandleTriggersInPkg(rpmts ts, rpmte te, Header h,
+ rpmsenseFlags sense, rpmscriptTriggerModes tm,
+ int searchMode, int ti)
+{
+ int nerrors = 0;
+ rpmds rpmdsTriggers, rpmdsTrigger;
+ rpmfiles files = NULL;
+ matchFilesIter mfi = NULL;
+ rpmScript script;
+ struct rpmtd_s installPrefixes;
+ char *(*inputFunc)(void *);
+
+ rpmdsTriggers = rpmdsNew(h, triggerDsTag(tm), 0);
+ rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, ti);
+ /*
+ * Now rpmdsTrigger contains all dependencies belonging to one trigger
+ * with trigger index tix. Have a look at the first one to check flags.
+ */
+ if ((rpmdsNext(rpmdsTrigger) >= 0) &&
+ (rpmdsFlags(rpmdsTrigger) & sense)) {
+
+ switch (searchMode) {
+ case 0:
+ /* Create iterator over files in te that this trigger matches */
+ files = rpmteFiles(te);
+ mfi = matchFilesIterator(rpmdsTrigger, files, te);
+ break;
+ case 1:
+ /* Create iterator over files in ts that this trigger matches */
+ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 1);
+ break;
+ case 2:
+ /* Create iterator over files in whole rpmd that this trigger matches */
+ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 0);
+ break;
+ }
+
+ /* If this trigger matches any file then run trigger script */
+ if (!matchFilesEmpty(mfi)) {
+ script = rpmScriptFromTriggerTag(h, triggertag(sense), tm, ti);
+
+ headerGet(h, RPMTAG_INSTPREFIXES, &installPrefixes,
+ HEADERGET_ALLOC|HEADERGET_ARGV);
+
+
+ /*
+ * As input function set function to get next file from
+ * matching file iterator. As parameter for this function
+ * set matching file iterator. Input function will be called
+ * during execution of trigger script in order to get data
+ * that will be passed as stdin to trigger script. To get
+ * these data from lua script function rpm.input() can be used.
+ */
+ inputFunc = (char *(*)(void *)) matchFilesNext;
+ rpmScriptSetNextFileFunc(script, inputFunc, mfi);
+
+ nerrors += runScript(ts, te, h, installPrefixes.data,
+ script, 0, 0);
+ rpmtdFreeData(&installPrefixes);
+ rpmScriptFree(script);
+ }
+ rpmfilesFree(files);
+ matchFilesIteratorFree(mfi);
+ }
+ rpmdsFree(rpmdsTrigger);
+ rpmdsFree(rpmdsTriggers);
+
+ return nerrors;
+}
+
+/* Return true if any file in package (te) starts with pfx */
+static int matchFilesInPkg(rpmts ts, rpmte te, const char *pfx,
+ rpmsenseFlags sense)
+{
+ int rc;
+ rpmfiles files = rpmteFiles(te);
+ rpmfi fi = rpmfilesFindPrefix(files, pfx);
+
+ rc = (fi != NULL);
+ rpmfilesFree(files);
+ rpmfiFree(fi);
+ return rc;
+}
+
+/* Return number of added/removed files starting with pfx in transaction */
+static int matchFilesInTran(rpmts ts, rpmte te, const char *pfx,
+ rpmsenseFlags sense)
+{
+ int rc = 1;
+ rpmdbMatchIterator pi;
+
+ /* Get all files from rpmdb starting with pfx */
+ pi = rpmdbInitPrefixIterator(rpmtsGetRdb(ts), RPMDBI_DIRNAMES, pfx, 0);
+
+ if (sense & RPMSENSE_TRIGGERIN)
+ /* Leave in pi only files installed in ts */
+ rpmdbFilterIterator(pi, ts->members->installedPackages, 0);
+ else
+ /* Leave in pi only files removed in ts */
+ rpmdbFilterIterator(pi, ts->members->removedPackages, 0);
+
+ rc = rpmdbGetIteratorCount(pi);
+ rpmdbFreeIterator(pi);
+
+ return rc;
+}
+
+rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm, int priorityClass)
+{
+ int nerrors = 0, i;
+ rpmdbIndexIterator ii;
+ const void *key;
+ char *pfx;
+ size_t keylen;
+ Header trigH;
+ int (*matchFunc)(rpmts, rpmte, const char*, rpmsenseFlags sense);
+ rpmTagVal priorityTag;
+ rpmtriggers triggers = rpmtriggersCreate(10);
+
+ /* Decide if we match triggers against files in te or in whole ts */
+ if (tm == RPMSCRIPT_FILETRIGGER) {
+ matchFunc = matchFilesInPkg;
+ priorityTag = RPMTAG_FILETRIGGERPRIORITIES;
+ } else {
+ matchFunc = matchFilesInTran;
+ priorityTag = RPMTAG_TRANSFILETRIGGERPRIORITIES;
+ }
+
+ ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), triggerDsTag(tm));
+
+ /* Loop over all file triggers in rpmdb */
+ while ((rpmdbIndexIteratorNext(ii, &key, &keylen)) == 0) {
+ pfx = xmalloc(keylen + 1);
+ memcpy(pfx, key, keylen);
+ pfx[keylen] = '\0';
+
+ /* Check if file trigger is fired by any file in ts/te */
+ if (matchFunc(ts, te, pfx, sense)) {
+ for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++) {
+ struct rpmtd_s priorities;
+ unsigned int priority;
+ unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i);
+ unsigned int tix = rpmdbIndexIteratorTagNum(ii, i);
+
+ /*
+ * Don't handle transaction triggers installed in current
+ * transaction to avoid executing the same script two times.
+ * These triggers are handled in runImmedFileTriggers().
+ */
+ if (tm == RPMSCRIPT_TRANSFILETRIGGER &&
+ (packageHashHasEntry(ts->members->removedPackages, offset) ||
+ packageHashHasEntry(ts->members->installedPackages, offset)))
+ continue;
+
+ /* Get priority of trigger from header */
+ trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offset);
+ headerGet(trigH, priorityTag, &priorities, HEADERGET_MINMEM);
+ rpmtdSetIndex(&priorities, tix);
+ priority = *rpmtdGetUint32(&priorities);
+ headerFree(trigH);
+
+ /* Store file trigger in array */
+ rpmtriggersAdd(triggers, offset, tix, priority);
+ }
+ }
+ free(pfx);
+ }
+ rpmdbIndexIteratorFree(ii);
+
+ /* Sort triggers by priority, offset, trigger index */
+ rpmtriggersSortAndUniq(triggers);
+
+ if (rpmChrootIn() != 0) {
+ rpmtriggersFree(triggers);
+ return RPMRC_FAIL;
+ }
+
+ /* Handle stored triggers */
+ for (i = 0; i < triggers->count; i++) {
+ if (priorityClass == 1) {
+ if (triggers->triggerInfo[i].priority < TRIGGER_PRIORITY_BOUND)
+ continue;
+ } else if (priorityClass == 2) {
+ if (triggers->triggerInfo[i].priority >= TRIGGER_PRIORITY_BOUND)
+ continue;
+ }
+
+ trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts), triggers->triggerInfo[i].hdrNum);
+ if (tm == RPMSCRIPT_FILETRIGGER)
+ nerrors += runHandleTriggersInPkg(ts, te, trigH, sense, tm, 0,
+ triggers->triggerInfo[i].tix);
+ else
+ nerrors += runHandleTriggersInPkg(ts, te, trigH, sense, tm, 1,
+ triggers->triggerInfo[i].tix);
+ headerFree(trigH);
+ }
+ rpmtriggersFree(triggers);
+ /* XXX an error here would require a full abort */
+ (void) rpmChrootOut();
+
+ return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
+
+rpmRC runImmedFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm, int priorityClass)
+{
+ int nerrors = 0;
+ int triggersCount, i;
+ Header trigH = rpmteHeader(te);
+ struct rpmtd_s priorities;
+ rpmTagVal priorityTag;
+ rpmtriggers triggers;
+
+ if (tm == RPMSCRIPT_FILETRIGGER) {
+ priorityTag = RPMTAG_FILETRIGGERPRIORITIES;
+ } else {
+ priorityTag = RPMTAG_TRANSFILETRIGGERPRIORITIES;
+ }
+ headerGet(trigH, priorityTag, &priorities, HEADERGET_MINMEM);
+
+ triggersCount = rpmtdCount(&priorities);
+ triggers = rpmtriggersCreate(triggersCount);
+
+ for (i = 0; i < triggersCount; i++) {
+ rpmtdSetIndex(&priorities, i);
+ /* Offset is not important, all triggers are from the same package */
+ rpmtriggersAdd(triggers, 0, i, *rpmtdGetUint32(&priorities));
+ }
+
+ /* Sort triggers by priority, offset, trigger index */
+ rpmtriggersSortAndUniq(triggers);
+
+ for (i = 0; i < triggersCount; i++) {
+ if (priorityClass == 1) {
+ if (triggers->triggerInfo[i].priority < TRIGGER_PRIORITY_BOUND)
+ continue;
+ } else if (priorityClass == 2) {
+ if (triggers->triggerInfo[i].priority >= TRIGGER_PRIORITY_BOUND)
+ continue;
+ }
+
+ nerrors += runHandleTriggersInPkg(ts, te, trigH, sense, tm, 2,
+ triggers->triggerInfo[i].tix);
+ }
+ rpmtriggersFree(triggers);
+ headerFree(trigH);
+
+ return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
diff --git a/lib/rpmtriggers.h b/lib/rpmtriggers.h
new file mode 100644
index 000000000..5ae9edd00
--- /dev/null
+++ b/lib/rpmtriggers.h
@@ -0,0 +1,84 @@
+#ifndef _RPMTRIGGERS_H
+#define _RPMTRIGGERS_H
+
+#include <rpm/rpmutil.h>
+#include "lib/rpmscript.h"
+
+struct triggerInfo_s {
+ unsigned int hdrNum;
+ unsigned int tix;
+ unsigned int priority;
+};
+
+typedef struct rpmtriggers_s {
+ struct triggerInfo_s *triggerInfo;
+ int count;
+ int alloced;
+} *rpmtriggers;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+RPM_GNUC_INTERNAL
+rpmtriggers rpmtriggersCreate(unsigned int hint);
+
+RPM_GNUC_INTERNAL
+rpmtriggers rpmtriggersFree(rpmtriggers triggers);
+
+/*
+ * Prepare post trans uninstall file triggers. After transcation uninstalled
+ * files are not saved anywhere. So we need during uninstalation of every
+ * package, in time when the files to uninstall are still available,
+ * to determine and store triggers that should be set off after transaction.
+ */
+RPM_GNUC_INTERNAL
+void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te);
+
+/* Run triggers stored in ts */
+RPM_GNUC_INTERNAL
+int runPostUnTransFileTrigs(rpmts ts);
+
+/*
+ * It runs file triggers in other package(s) this package/transaction sets off.
+ * If tm is RPMSCRIPT_FILETRIGGERSCRIPT then it runs file triggers that are
+ * fired by files in transaction entry. If tm is RPMSCRIPT_TRANSFILETRIGGERSCRIPT
+ * then it runs file triggers that are fired by all files in transaction set.
+ * In that case te can be NULL.
+ *
+ * @param ts transaction set
+ * @param te transaction entry
+ * @param sense defines which triggers should be set off (triggerin,
+ * triggerun, triggerpostun)
+ * @param tm trigger mode, (filetrigger/transfiletrigger)
+ * @param priorityClass 1 to run triggers that should be executed before
+ * standard scriptlets
+ * 2 to run triggers that should be executed after
+ * standard scriptlets
+ * 0 to run all triggers
+ */
+RPM_GNUC_INTERNAL
+rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm, int priorityClass);
+
+/* Run file triggers in this te other package(s) set off.
+ * @param ts transaction set
+ * @param te transaction entry
+ * @param sense defines which triggers should be set off (triggerin,
+ * triggerun, triggerpostun)
+ * @param tm trigger mode, (filetrigger/transfiletrigger)
+ * @param priorityClass 1 to run triggers that should be executed before
+ * standard scriptlets
+ * 2 to run triggers that should be executed after
+ * standard scriptlets
+ * 0 to run all triggers
+ */
+RPM_GNUC_INTERNAL
+rpmRC runImmedFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm, int priorityClass);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _RPMTRIGGERS_H */
+
diff --git a/lib/rpmts.c b/lib/rpmts.c
index d3b893a1d..49f1a369b 100644
--- a/lib/rpmts.c
+++ b/lib/rpmts.c
@@ -19,6 +19,7 @@
#include <rpm/rpmds.h>
#include <rpm/rpmfi.h>
#include <rpm/rpmlog.h>
+#include <rpm/rpmsq.h>
#include <rpm/rpmte.h>
#include "rpmio/digest.h"
@@ -28,6 +29,7 @@
#include "lib/rpmts_internal.h"
#include "lib/rpmte_internal.h"
#include "lib/misc.h"
+#include "lib/rpmtriggers.h"
#include "debug.h"
@@ -39,6 +41,12 @@ struct rpmtsi_s {
int oc; /*!< iterator index. */
};
+struct rpmtxn_s {
+ rpmlock lock; /* transaction lock */
+ rpmtxnFlags flags; /* transaction flags */
+ rpmts ts; /* parent transaction set reference */
+};
+
static void loadKeyring(rpmts ts);
int _rpmts_stats = 0;
@@ -97,16 +105,16 @@ int rpmtsOpenDB(rpmts ts, int dbmode)
int rpmtsSuspendResumeDBLock(rpmts ts, int mode)
{
- return rpmdbSuspendResumeDBLock(ts->rdb, mode);
+ return 0;//rpmdbSuspendResumeDBLock(ts->rdb, mode);
}
int rpmtsInitDB(rpmts ts, int dbmode)
{
- rpmlock lock = rpmtsAcquireLock(ts);
+ rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE);
int rc = -1;
- if (lock)
+ if (txn)
rc = rpmdbInit(ts->rootDir, dbmode);
- rpmlockFree(lock);
+ rpmtxnEnd(txn);
return rc;
}
@@ -131,19 +139,19 @@ int rpmtsSetDBMode(rpmts ts, int dbmode)
int rpmtsRebuildDB(rpmts ts)
{
int rc = -1;
- rpmlock lock = NULL;
+ rpmtxn txn = NULL;
/* Cannot do this on a populated transaction set */
if (rpmtsNElements(ts) > 0)
return -1;
- lock = rpmtsAcquireLock(ts);
- if (lock) {
+ txn = rpmtxnBegin(ts, RPMTXN_WRITE);
+ if (txn) {
if (!(ts->vsflags & RPMVSF_NOHDRCHK))
rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
else
rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
- rpmlockFree(lock);
+ rpmtxnEnd(txn);
}
return rc;
}
@@ -151,10 +159,10 @@ int rpmtsRebuildDB(rpmts ts)
int rpmtsVerifyDB(rpmts ts)
{
int rc = -1;
- rpmlock lock = rpmtsAcquireLock(ts);
- if (lock) {
+ rpmtxn txn = rpmtxnBegin(ts, RPMTXN_READ);
+ if (txn) {
rc = rpmdbVerify(ts->rootDir);
- rpmlockFree(lock);
+ rpmtxnEnd(txn);
}
return rc;
}
@@ -273,7 +281,10 @@ static int loadKeyringFromFiles(rpmts ts)
}
for (char **f = files; *f; f++) {
+ int subkeysCount, i;
+ rpmPubkey *subkeys;
rpmPubkey key = rpmPubkeyRead(*f);
+
if (!key) {
rpmlog(RPMLOG_ERR, _("%s: reading of public key failed.\n"), *f);
continue;
@@ -282,7 +293,22 @@ static int loadKeyringFromFiles(rpmts ts)
nkeys++;
rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", *f);
}
+ subkeys = rpmGetSubkeys(key, &subkeysCount);
rpmPubkeyFree(key);
+
+ for (i = 0; i < subkeysCount; i++) {
+ rpmPubkey subkey = subkeys[i];
+
+ if (rpmKeyringAddKey(ts->keyring, subkey) == 0) {
+ rpmlog(RPMLOG_DEBUG,
+ "added subkey %d of main key %s to keyring\n",
+ i, *f);
+
+ nkeys++;
+ }
+ rpmPubkeyFree(subkey);
+ }
+ free(subkeys);
}
exit:
free(pkpath);
@@ -311,6 +337,9 @@ static int loadKeyringFromDB(rpmts ts)
if (rpmBase64Decode(key, (void **) &pkt, &pktlen) == 0) {
rpmPubkey key = rpmPubkeyNew(pkt, pktlen);
+ int subkeysCount, i;
+ rpmPubkey *subkeys = rpmGetSubkeys(key, &subkeysCount);
+
if (rpmKeyringAddKey(ts->keyring, key) == 0) {
char *nvr = headerGetAsString(h, RPMTAG_NVR);
rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", nvr);
@@ -318,6 +347,22 @@ static int loadKeyringFromDB(rpmts ts)
nkeys++;
}
rpmPubkeyFree(key);
+
+ for (i = 0; i < subkeysCount; i++) {
+ rpmPubkey subkey = subkeys[i];
+
+ if (rpmKeyringAddKey(ts->keyring, subkey) == 0) {
+ char *nvr = headerGetAsString(h, RPMTAG_NVR);
+ rpmlog(RPMLOG_DEBUG,
+ "added subkey %d of main key %s to keyring\n",
+ i, nvr);
+
+ free(nvr);
+ nkeys++;
+ }
+ rpmPubkeyFree(subkey);
+ }
+ free(subkeys);
free(pkt);
}
}
@@ -343,7 +388,8 @@ static void loadKeyring(rpmts ts)
}
/* Build pubkey header. */
-static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp)
+static int makePubkeyHeader(rpmts ts, rpmPubkey key, rpmPubkey *subkeys,
+ int subkeysCount, Header * hdrp)
{
Header h = headerNew();
const char * afmt = "%{pubkeys:armor}";
@@ -364,6 +410,7 @@ static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp)
char * r = NULL;
char * evr = NULL;
int rc = -1;
+ int i;
if ((enc = rpmPubkeyBase64(key)) == NULL)
goto exit;
@@ -374,12 +421,12 @@ static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp)
/* Build header elements. */
v = pgpHexStr(pubp->signid, sizeof(pubp->signid));
- r = pgpHexStr(pubp->time, sizeof(pubp->time));
userid = pubp->userid ? pubp->userid : "none";
- keytime = pgpGrab(pubp->time, sizeof(pubp->time));
+ keytime = pubp->time;
rasprintf(&n, "gpg(%s)", v+8);
rasprintf(&u, "gpg(%s)", userid);
+ rasprintf(&r, "%x", keytime);
rasprintf(&evr, "%d:%s-%s", pubp->version, v, r);
headerPutString(h, RPMTAG_PUBKEYS, enc);
@@ -411,6 +458,27 @@ static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp)
headerPutUint32(h, RPMTAG_BUILDTIME, &keytime, 1);
headerPutString(h, RPMTAG_SOURCERPM, "(none)");
+ for (i = 0; i < subkeysCount; i++) {
+ char *v, *r, *n, *evr;
+ pgpDigParams pgpkey;
+
+ pgpkey = rpmPubkeyPgpDigParams(subkeys[i]);
+ v = pgpHexStr(pgpkey->signid, sizeof(pgpkey->signid));
+
+ rasprintf(&n, "gpg(%s)", v+8);
+ rasprintf(&r, "%x", pgpkey->time);
+ rasprintf(&evr, "%d:%s-%s", pubp->version, v, r);
+
+ headerPutString(h, RPMTAG_PROVIDENAME, n);
+ headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
+ headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
+
+ free(v);
+ free(r);
+ free(n);
+ free(evr);
+ }
+
/* Reload the lot to immutable region and stomp sha1 digest on it */
h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
if (h != NULL) {
@@ -446,14 +514,32 @@ exit:
return rc;
}
+rpmRC rpmtsImportHeader(rpmtxn txn, Header h, rpmFlags flags)
+{
+ rpmRC rc = RPMRC_FAIL;
+
+ if (txn && h && rpmtsOpenDB(txn->ts, (O_RDWR|O_CREAT)) == 0) {
+ if (rpmdbAdd(rpmtsGetRdb(txn->ts), h) == 0) {
+ rc = RPMRC_OK;
+ }
+ }
+ return rc;
+}
+
rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen)
{
Header h = NULL;
rpmRC rc = RPMRC_FAIL; /* assume failure */
rpmPubkey pubkey = NULL;
+ rpmPubkey *subkeys = NULL;
+ int subkeysCount = 0;
rpmVSFlags oflags = rpmtsVSFlags(ts);
rpmKeyring keyring;
- int krc;
+ rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE);
+ int krc, i;
+
+ if (txn == NULL)
+ return rc;
/* XXX keyring wont load if sigcheck disabled, force it temporarily */
rpmtsSetVSFlags(ts, (oflags & ~_RPMVSF_NOSIGNATURES));
@@ -462,6 +548,10 @@ rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen
if ((pubkey = rpmPubkeyNew(pkt, pktlen)) == NULL)
goto exit;
+
+ if ((subkeys = rpmGetSubkeys(pubkey, &subkeysCount)) == NULL)
+ goto exit;
+
krc = rpmKeyringAddKey(keyring, pubkey);
if (krc < 0)
goto exit;
@@ -470,7 +560,7 @@ rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen
if (krc == 0) {
rpm_tid_t tid = rpmtsGetTid(ts);
- if (makePubkeyHeader(ts, pubkey, &h) != 0)
+ if (makePubkeyHeader(ts, pubkey, subkeys, subkeysCount, &h) != 0)
goto exit;
headerPutUint32(h, RPMTAG_INSTALLTIME, &tid, 1);
@@ -478,10 +568,7 @@ rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen
/* Add header to database. */
if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
- if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
- goto exit;
- if (rpmdbAdd(rpmtsGetRdb(ts), h) != 0)
- goto exit;
+ rc = rpmtsImportHeader(txn, h, 0);
}
}
rc = RPMRC_OK;
@@ -490,7 +577,12 @@ exit:
/* Clean up. */
headerFree(h);
rpmPubkeyFree(pubkey);
+ for (i = 0; i < subkeysCount; i++)
+ rpmPubkeyFree(subkeys[i]);
+ free(subkeys);
+
rpmKeyringFree(keyring);
+ rpmtxnEnd(txn);
return rc;
}
@@ -593,7 +685,7 @@ void rpmtsEmpty(rpmts ts)
tsmem->orderCount = 0;
/* The pool cannot be emptied, there might be references to its contents */
tsmem->pool = rpmstrPoolFree(tsmem->pool);
- removedHashEmpty(tsmem->removedPackages);
+ packageHashEmpty(tsmem->removedPackages);
return;
}
@@ -642,7 +734,8 @@ rpmts rpmtsFree(rpmts ts)
(void) rpmtsCloseDB(ts);
- tsmem->removedPackages = removedHashFree(tsmem->removedPackages);
+ tsmem->removedPackages = packageHashFree(tsmem->removedPackages);
+ tsmem->installedPackages = packageHashFree(tsmem->installedPackages);
tsmem->order = _free(tsmem->order);
ts->members = _free(ts->members);
@@ -654,6 +747,7 @@ rpmts rpmtsFree(rpmts ts)
}
ts->rootDir = _free(ts->rootDir);
ts->lockPath = _free(ts->lockPath);
+ ts->lock = rpmlockFree(ts->lock);
ts->keyring = rpmKeyringFree(ts->keyring);
ts->netsharedPaths = argvFree(ts->netsharedPaths);
@@ -661,6 +755,8 @@ rpmts rpmtsFree(rpmts ts)
ts->plugins = rpmpluginsFree(ts->plugins);
+ rpmtriggersFree(ts->trigs2run);
+
if (_rpmts_stats)
rpmtsPrintStats(ts);
@@ -731,63 +827,6 @@ void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
}
}
-struct selabel_handle * rpmtsSELabelHandle(rpmts ts)
-{
-#if WITH_SELINUX
- if (ts != NULL) {
- return ts->selabelHandle;
- }
-#endif
- return NULL;
-}
-
-rpmRC rpmtsSELabelInit(rpmts ts, int open_status)
-{
-#if WITH_SELINUX
- const char * path = selinux_file_context_path();
-
- if (ts == NULL || path == NULL) {
- return RPMRC_FAIL;
- }
-
- if (open_status) {
- selinux_status_close();
- if (selinux_status_open(0) < 0) {
- return RPMRC_FAIL;
- }
- } else if (!selinux_status_updated() && ts->selabelHandle) {
- return RPMRC_OK;
- }
-
- struct selinux_opt opts[] = {
- { .type = SELABEL_OPT_PATH, .value = path}
- };
-
- if (ts->selabelHandle) {
- rpmtsSELabelFini(ts, 0);
- }
- ts->selabelHandle = selabel_open(SELABEL_CTX_FILE, opts, 1);
-
- if (!ts->selabelHandle) {
- return RPMRC_FAIL;
- }
-#endif
- return RPMRC_OK;
-}
-
-void rpmtsSELabelFini(rpmts ts, int close_status)
-{
-#if WITH_SELINUX
- if (ts && ts->selabelHandle) {
- selabel_close(ts->selabelHandle);
- ts->selabelHandle = NULL;
- }
- if (close_status) {
- selinux_status_close();
- }
-#endif
-}
-
rpm_tid_t rpmtsGetTid(rpmts ts)
{
rpm_tid_t tid = (rpm_tid_t)-1; /* XXX -1 is time(2) error return. */
@@ -918,7 +957,14 @@ rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
rpmPlugins rpmtsPlugins(rpmts ts)
{
- return (ts != NULL ? ts->plugins : NULL);
+ rpmPlugins plugins = NULL;
+
+ if (ts != NULL) {
+ if (ts->plugins == NULL)
+ ts->plugins = rpmpluginsNew(ts);
+ plugins = ts->plugins;
+ }
+ return plugins;
}
int rpmtsSetNotifyCallback(rpmts ts,
@@ -999,7 +1045,8 @@ rpmts rpmtsCreate(void)
tsmem->pool = NULL;
tsmem->delta = 5;
tsmem->addedPackages = NULL;
- tsmem->removedPackages = removedHashCreate(128, uintId, uintCmp, NULL, NULL);
+ tsmem->removedPackages = packageHashCreate(128, uintId, uintCmp, NULL, NULL);
+ tsmem->installedPackages = packageHashCreate(128, uintId, uintCmp, NULL, NULL);
tsmem->orderAlloced = 0;
tsmem->orderCount = 0;
tsmem->order = NULL;
@@ -1008,11 +1055,13 @@ rpmts rpmtsCreate(void)
ts->rootDir = NULL;
ts->keyring = NULL;
- ts->selabelHandle = NULL;
-
ts->nrefs = 0;
- ts->plugins = rpmpluginsNew(ts);
+ ts->plugins = NULL;
+
+ ts->trigs2run = rpmtriggersCreate(10);
+
+ ts->min_writes = rpmExpandNumeric("%{_minimize_writes}");
return rpmtsLink(ts);
}
@@ -1069,9 +1118,13 @@ rpmte rpmtsiNext(rpmtsi tsi, rpmElementTypes types)
}
#define RPMLOCK_PATH LOCALSTATEDIR "/rpm/.rpm.lock"
-rpmlock rpmtsAcquireLock(rpmts ts)
+rpmtxn rpmtxnBegin(rpmts ts, rpmtxnFlags flags)
{
static const char * const rpmlock_path_default = "%{?_rpmlock_path}";
+ rpmtxn txn = NULL;
+
+ if (ts == NULL)
+ return NULL;
if (ts->lockPath == NULL) {
const char *rootDir = rpmtsRootDir(ts);
@@ -1089,6 +1142,30 @@ rpmlock rpmtsAcquireLock(rpmts ts)
(void) rpmioMkpath(dirname(t), 0755, getuid(), getgid());
free(t);
}
- return rpmlockAcquire(ts->lockPath, _("transaction"));
+
+ if (ts->lock == NULL)
+ ts->lock = rpmlockNew(ts->lockPath, _("transaction"));
+
+ if (rpmlockAcquire(ts->lock)) {
+ txn = xcalloc(1, sizeof(*txn));
+ txn->lock = ts->lock;
+ txn->flags = flags;
+ txn->ts = rpmtsLink(ts);
+ if (txn->flags & RPMTXN_WRITE)
+ rpmsqBlock(SIG_BLOCK);
+ }
+
+ return txn;
}
+rpmtxn rpmtxnEnd(rpmtxn txn)
+{
+ if (txn) {
+ rpmlockRelease(txn->lock);
+ if (txn->flags & RPMTXN_WRITE)
+ rpmsqBlock(SIG_UNBLOCK);
+ rpmtsFree(txn->ts);
+ free(txn);
+ }
+ return NULL;
+}
diff --git a/lib/rpmts.h b/lib/rpmts.h
index 059f46d24..e09569a90 100644
--- a/lib/rpmts.h
+++ b/lib/rpmts.h
@@ -34,9 +34,10 @@ enum rpmtransFlags_e {
RPMTRANS_FLAG_NOTRIGGERS = (1 << 4), /*!< from --notriggers */
RPMTRANS_FLAG_NODOCS = (1 << 5), /*!< from --excludedocs */
RPMTRANS_FLAG_ALLFILES = (1 << 6), /*!< from --allfiles */
- /* bit 7 unused */
+ RPMTRANS_FLAG_NOPLUGINS = (1 << 7), /*!< from --noplugins */
RPMTRANS_FLAG_NOCONTEXTS = (1 << 8), /*!< from --nocontexts */
- /* bits 9-15 unused */
+ RPMTRANS_FLAG_NOCAPS = (1 << 9), /*!< from --nocaps */
+ /* bits 10-15 unused */
RPMTRANS_FLAG_NOTRIGGERPREIN= (1 << 16), /*!< from --notriggerprein */
RPMTRANS_FLAG_NOPRE = (1 << 17), /*!< from --nopre */
RPMTRANS_FLAG_NOPOST = (1 << 18), /*!< from --nopost */
@@ -45,8 +46,9 @@ enum rpmtransFlags_e {
RPMTRANS_FLAG_NOPREUN = (1 << 21), /*!< from --nopreun */
RPMTRANS_FLAG_NOPOSTUN = (1 << 22), /*!< from --nopostun */
RPMTRANS_FLAG_NOTRIGGERPOSTUN = (1 << 23), /*!< from --notriggerpostun */
- /* bits 24-25 unused */
- RPMTRANS_FLAG_NOCOLLECTIONS = (1 << 26), /*!< from --nocollections */
+ RPMTRANS_FLAG_NOPRETRANS = (1 << 24), /*!< from --nopretrans */
+ RPMTRANS_FLAG_NOPOSTTRANS = (1 << 25), /*!< from --noposttrans */
+ /* bit 26 unused */
RPMTRANS_FLAG_NOMD5 = (1 << 27), /*!< from --nomd5 */
RPMTRANS_FLAG_NOFILEDIGEST = (1 << 27), /*!< from --nofiledigest (alias to --nomd5) */
/* bits 28-29 unused */
@@ -60,7 +62,9 @@ typedef rpmFlags rpmtransFlags;
( RPMTRANS_FLAG_NOPRE | \
RPMTRANS_FLAG_NOPOST | \
RPMTRANS_FLAG_NOPREUN | \
- RPMTRANS_FLAG_NOPOSTUN \
+ RPMTRANS_FLAG_NOPOSTUN | \
+ RPMTRANS_FLAG_NOPRETRANS | \
+ RPMTRANS_FLAG_NOPOSTTRANS \
)
#define _noTransTriggers \
@@ -93,11 +97,11 @@ enum rpmVSFlags_e {
RPMVSF_NEEDPAYLOAD = (1 << 1),
/* bit(s) 2-7 unused */
RPMVSF_NOSHA1HEADER = (1 << 8),
- RPMVSF_NOMD5HEADER = (1 << 9), /* unimplemented */
+ RPMVSF_NOSHA256HEADER = (1 << 9),
RPMVSF_NODSAHEADER = (1 << 10),
- RPMVSF_NORSAHEADER = (1 << 11), /* unimplemented */
+ RPMVSF_NORSAHEADER = (1 << 11),
/* bit(s) 12-15 unused */
- RPMVSF_NOSHA1 = (1 << 16), /* unimplemented */
+ RPMVSF_NOPAYLOAD = (1 << 16),
RPMVSF_NOMD5 = (1 << 17),
RPMVSF_NODSA = (1 << 18),
RPMVSF_NORSA = (1 << 19)
@@ -108,8 +112,8 @@ typedef rpmFlags rpmVSFlags;
#define _RPMVSF_NODIGESTS \
( RPMVSF_NOSHA1HEADER | \
- RPMVSF_NOMD5HEADER | \
- RPMVSF_NOSHA1 | \
+ RPMVSF_NOSHA256HEADER | \
+ RPMVSF_NOPAYLOAD | \
RPMVSF_NOMD5 )
#define _RPMVSF_NOSIGNATURES \
@@ -120,13 +124,13 @@ typedef rpmFlags rpmVSFlags;
#define _RPMVSF_NOHEADER \
( RPMVSF_NOSHA1HEADER | \
- RPMVSF_NOMD5HEADER | \
+ RPMVSF_NOSHA256HEADER | \
RPMVSF_NODSAHEADER | \
RPMVSF_NORSAHEADER )
#define _RPMVSF_NOPAYLOAD \
- ( RPMVSF_NOSHA1 | \
- RPMVSF_NOMD5 | \
+ ( RPMVSF_NOMD5 | \
+ RPMVSF_NOPAYLOAD | \
RPMVSF_NODSA | \
RPMVSF_NORSA )
@@ -153,6 +157,12 @@ typedef enum rpmtsOpX_e {
RPMTS_OP_MAX = 17
} rpmtsOpX;
+enum rpmtxnFlags_e {
+ RPMTXN_READ = (1 << 0),
+ RPMTXN_WRITE = (1 << 1),
+};
+typedef rpmFlags rpmtxnFlags;
+
/** \ingroup rpmts
* Perform dependency resolution on the transaction set.
*
@@ -275,6 +285,15 @@ rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag,
const void * keyp, size_t keylen);
/** \ingroup rpmts
+ * Import a header into the rpmdb
+ * @param txn transaction handle
+ * @param h header
+ * @param flags (unused)
+ * @return RPMRC_OK/RPMRC_FAIL
+ */
+rpmRC rpmtsImportHeader(rpmtxn txn, Header h, rpmFlags flags);
+
+/** \ingroup rpmts
* Import public key packet(s).
* @todo Implicit --update policy for gpg-pubkey headers.
* @param ts transaction set
@@ -470,7 +489,7 @@ rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags);
rpm_color_t rpmtsColor(rpmts ts);
/** \ingroup rpmts
- * Retrieve prefered file color
+ * Retrieve preferred file color
* @param ts transaction set
* @return color bits
*/
@@ -485,7 +504,7 @@ rpm_color_t rpmtsPrefColor(rpmts ts);
rpm_color_t rpmtsSetColor(rpmts ts, rpm_color_t color);
/** \ingroup rpmts
- * Set prefered file color
+ * Set preferred file color
* @param ts transaction set
* @param color new color bits
* @return previous color bits
@@ -546,6 +565,16 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
rpmRelocation * relocs);
/** \ingroup rpmts
+ * Add package to be reinstalled to transaction set.
+ *
+ * @param ts transaction set
+ * @param h header
+ * @param key package retrieval key (e.g. file name)
+ * @return 0 on success
+ */
+int rpmtsAddReinstallElement(rpmts ts, Header h, const fnpyKey key);
+
+/** \ingroup rpmts
* Add package to be erased to transaction set.
* @param ts transaction set
* @param h header
@@ -554,6 +583,21 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
*/
int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset);
+/** \ingroup rpmts
+ * Create a transaction (lock) handle
+ * @param ts transaction set
+ * @param flags flags
+ * @return transaction handle
+ */
+rpmtxn rpmtxnBegin(rpmts ts, rpmtxnFlags flags);
+
+/** \ingroup rpmts
+ * Destroy transaction (lock) handle
+ * @param txn transaction handle
+ * @return NULL always
+ */
+rpmtxn rpmtxnEnd(rpmtxn txn);
+
/** \ingroup rpmte
* Destroy transaction element iterator.
* @param tsi transaction element iterator
diff --git a/lib/rpmts_internal.h b/lib/rpmts_internal.h
index d4f25e17e..1e166d632 100644
--- a/lib/rpmts_internal.h
+++ b/lib/rpmts_internal.h
@@ -8,13 +8,16 @@
#include "lib/fprint.h"
#include "lib/rpmlock.h"
#include "lib/rpmdb_internal.h"
+#include "lib/rpmscript.h"
+#include "lib/rpmtriggers.h"
typedef struct diskspaceInfo_s * rpmDiskSpaceInfo;
/* Transaction set elements information */
typedef struct tsMembers_s {
rpmstrPool pool; /*!< Global string pool */
- removedHash removedPackages; /*!< Set of packages being removed. */
+ packageHash removedPackages; /*!< Set of packages being removed. */
+ packageHash installedPackages; /*!< Set of installed packages */
rpmal addedPackages; /*!< Set of packages being installed. */
rpmds rpmlib; /*!< rpmlib() dependency set. */
@@ -24,6 +27,17 @@ typedef struct tsMembers_s {
int delta; /*!< Delta for reallocation. */
} * tsMembers;
+typedef struct tsTrigger_s {
+ unsigned int hdrNum;
+ int index;
+} tsTrigger;
+
+typedef struct tsTriggers_s {
+ tsTrigger *trigger;
+ int count;
+ int alloced;
+} tsTriggers;
+
/** \ingroup rpmts
* The set of packages to be installed/removed atomically.
*/
@@ -47,10 +61,9 @@ struct rpmts_s {
tsMembers members; /*!< Transaction set member info (order etc) */
- struct selabel_handle * selabelHandle; /*!< Handle to selabel */
-
char * rootDir; /*!< Path to top of install tree. */
char * lockPath; /*!< Transaction lock path */
+ rpmlock lock; /*!< Transaction lock file */
FD_t scriptFd; /*!< Scriptlet stdout/stderr. */
rpm_tid_t tid; /*!< Transaction id. */
@@ -69,6 +82,10 @@ struct rpmts_s {
rpmPlugins plugins; /*!< Transaction plugins */
int nrefs; /*!< Reference count. */
+
+ rpmtriggers trigs2run; /*!< Transaction file triggers */
+
+ int min_writes; /*!< macro minimize_writes used */
};
#ifdef __cplusplus
@@ -86,6 +103,11 @@ rpmstrPool rpmtsPool(rpmts ts);
RPM_GNUC_INTERNAL
tsMembers rpmtsMembers(rpmts ts);
+/* Return rpmdb iterator with removals optionally pruned out */
+RPM_GNUC_INTERNAL
+rpmdbMatchIterator rpmtsPrunedIterator(rpmts ts, rpmDbiTagVal tag,
+ const char * key, int prune);
+
RPM_GNUC_INTERNAL
rpmal rpmtsCreateAl(rpmts ts, rpmElementTypes types);
@@ -94,29 +116,11 @@ RPM_GNUC_INTERNAL
int rpmtsSolve(rpmts ts, rpmds key);
RPM_GNUC_INTERNAL
-rpmlock rpmtsAcquireLock(rpmts ts);
+rpmRC rpmtsSetupTransactionPlugins(rpmts ts);
-/** \ingroup rpmts
- * Get the selabel handle from the transaction set
- * @param ts transaction set
- * @return rpm selabel handle, or NULL if it hasn't been initialized yet
- */
-struct selabel_handle * rpmtsSELabelHandle(rpmts ts);
-
-/** \ingroup rpmts
- * Initialize selabel
- * @param ts transaction set
- * @param open_status if the func should open selinux status or just check it
- * @return RPMRC_OK on success, RPMRC_FAIL otherwise
- */
-rpmRC rpmtsSELabelInit(rpmts ts, int open_status);
-
-/** \ingroup rpmts
- * Clean up selabel
- * @param ts transaction set
- * @param close_status whether we should close selinux status
- */
-void rpmtsSELabelFini(rpmts ts, int close_status);
+RPM_GNUC_INTERNAL
+rpmRC runScript(rpmts ts, rpmte te, Header h, ARGV_const_t prefixes,
+ rpmScript script, int arg1, int arg2);
#ifdef __cplusplus
}
diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h
index 91ea94907..1948d183b 100644
--- a/lib/rpmtypes.h
+++ b/lib/rpmtypes.h
@@ -64,10 +64,12 @@ typedef struct rpmts_s * rpmts;
typedef struct rpmte_s * rpmte;
typedef struct rpmds_s * rpmds;
typedef struct rpmfi_s * rpmfi;
+typedef struct rpmfiles_s * rpmfiles;
typedef struct rpmdb_s * rpmdb;
typedef struct rpmdbMatchIterator_s * rpmdbMatchIterator;
typedef struct rpmtsi_s * rpmtsi;
typedef struct rpmps_s * rpmps;
+typedef struct rpmtxn_s * rpmtxn;
typedef struct rpmdbIndexIterator_s * rpmdbIndexIterator;
typedef const void * fnpyKey;
@@ -80,6 +82,7 @@ typedef struct rpmKeyring_s * rpmKeyring;
typedef uint32_t rpmsid;
typedef struct rpmstrPool_s * rpmstrPool;
+typedef struct rpmPlugin_s * rpmPlugin;
typedef struct rpmPlugins_s * rpmPlugins;
typedef struct rpmgi_s * rpmgi;
diff --git a/lib/rpmug.c b/lib/rpmug.c
index 53a5a6e4d..119d8e585 100644
--- a/lib/rpmug.c
+++ b/lib/rpmug.c
@@ -1,7 +1,9 @@
#include "system.h"
+#include <pthread.h>
#include <pwd.h>
#include <grp.h>
+#include <netdb.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmstring.h>
@@ -9,32 +11,6 @@
#include "lib/rpmug.h"
#include "debug.h"
-#define HASHTYPE strCache
-#define HTKEYTYPE const char *
-#include "lib/rpmhash.H"
-#include "lib/rpmhash.C"
-#undef HASHTYPE
-#undef HTKEYTYPE
-
-static strCache strStash = NULL;
-
-const char * rpmugStashStr(const char *str)
-{
- const char *ret = NULL;
- if (str) {
- if (strStash == NULL) {
- strStash = strCacheCreate(64, rstrhash, strcmp,
- (strCacheFreeKey)rfree);
- }
-
- if (!strCacheGetEntry(strStash, str, &ret)) {
- strCacheAddEntry(strStash, xstrdup(str));
- (void) strCacheGetEntry(strStash, str, &ret);
- }
- }
- return ret;
-}
-
/*
* These really ought to use hash tables. I just made the
* guess that most files would be owned by root or the same person/group
@@ -55,7 +31,7 @@ int rpmugUid(const char * thisUname, uid_t * uid)
if (!thisUname) {
lastUnameLen = 0;
return -1;
- } else if (rstreq(thisUname, "root")) {
+ } else if (rstreq(thisUname, UID_0_USER)) {
*uid = 0;
return 0;
}
@@ -98,7 +74,7 @@ int rpmugGid(const char * thisGname, gid_t * gid)
if (thisGname == NULL) {
lastGnameLen = 0;
return -1;
- } else if (rstreq(thisGname, "root")) {
+ } else if (rstreq(thisGname, GID_0_GROUP)) {
*gid = 0;
return 0;
}
@@ -140,7 +116,7 @@ const char * rpmugUname(uid_t uid)
lastUid = (uid_t) -1;
return NULL;
} else if (uid == (uid_t) 0) {
- return "root";
+ return UID_0_USER;
} else if (uid == lastUid) {
return lastUname;
} else {
@@ -171,7 +147,7 @@ const char * rpmugGname(gid_t gid)
lastGid = (gid_t) -1;
return NULL;
} else if (gid == (gid_t) 0) {
- return "root";
+ return GID_0_GROUP;
} else if (gid == lastGid) {
return lastGname;
} else {
@@ -192,11 +168,27 @@ const char * rpmugGname(gid_t gid)
}
}
+static void loadLibs(void)
+{
+ (void) getpwnam(UID_0_USER);
+ endpwent();
+ (void) getgrnam(GID_0_GROUP);
+ endgrent();
+ (void) gethostbyname("localhost");
+}
+
+int rpmugInit(void)
+{
+ static pthread_once_t libsLoaded = PTHREAD_ONCE_INIT;
+
+ pthread_once(&libsLoaded, loadLibs);
+ return 0;
+}
+
void rpmugFree(void)
{
rpmugUid(NULL, NULL);
rpmugGid(NULL, NULL);
rpmugUname(-1);
rpmugGname(-1);
- strStash = strCacheFree(strStash);
}
diff --git a/lib/rpmug.h b/lib/rpmug.h
index 35e5d631d..22d64eb88 100644
--- a/lib/rpmug.h
+++ b/lib/rpmug.h
@@ -3,8 +3,6 @@
#include <sys/types.h>
-const char * rpmugStashStr(const char *str);
-
int rpmugUid(const char * name, uid_t * uid);
int rpmugGid(const char * name, gid_t * gid);
@@ -13,6 +11,8 @@ const char * rpmugUname(uid_t uid);
const char * rpmugGname(gid_t gid);
+int rpmugInit(void);
+
void rpmugFree(void);
#endif /* _RPMUG_H */
diff --git a/lib/rpmvercmp.c b/lib/rpmvercmp.c
index de3beeab4..b3d08faa4 100644
--- a/lib/rpmvercmp.c
+++ b/lib/rpmvercmp.c
@@ -36,7 +36,7 @@ int rpmvercmp(const char * a, const char * b)
while (*one && !risalnum(*one) && *one != '~') one++;
while (*two && !risalnum(*two) && *two != '~') two++;
- /* handle the tilde separator, it sorts before everthing else */
+ /* handle the tilde separator, it sorts before everything else */
if (*one == '~' || *two == '~') {
if (*one != '~') return 1;
if (*two != '~') return -1;
diff --git a/lib/rpmvf.h b/lib/rpmvf.h
index 51690b857..4cb463c2f 100644
--- a/lib/rpmvf.h
+++ b/lib/rpmvf.h
@@ -3,9 +3,11 @@
/** \ingroup rpmvf
* \file lib/rpmvf.h
- * @todo Add a more complete API...
+ *
+ * \brief Verify a package. The constants that enable/disable some sanity checks (mainly used at post (un)install)
*/
#include <rpm/rpmtypes.h>
+#include <rpm/rpmutil.h>
#ifdef __cplusplus
extern "C" {
@@ -85,13 +87,14 @@ typedef rpmFlags rpmVerifyFlags;
/** \ingroup rpmvf
* Verify file attributes (including digest).
- * @todo gnorpm and python bindings prevent this from being static.
+ * @deprecated use rpmfiVerify() / rpmfilesVerify() instead
* @param ts transaction set
* @param fi file info (with linked header and current file index)
* @retval *res bit(s) returned to indicate failure
* @param omitMask bit(s) to disable verify checks
* @return 0 on success (or not installed), 1 on error
*/
+RPM_GNUC_DEPRECATED
int rpmVerifyFile(const rpmts ts, rpmfi fi,
rpmVerifyAttrs * res, rpmVerifyAttrs omitMask);
diff --git a/lib/rpmvs.c b/lib/rpmvs.c
new file mode 100644
index 000000000..f77bfb02d
--- /dev/null
+++ b/lib/rpmvs.c
@@ -0,0 +1,456 @@
+#include "system.h"
+
+#include <rpm/rpmkeyring.h>
+#include "lib/rpmvs.h"
+#include "rpmio/digest.h"
+
+#include "debug.h"
+
+struct rpmvs_s {
+ struct rpmsinfo_s *sigs;
+ rpmRC *rcs;
+ char **results;
+ int nsigs;
+ int nalloced;
+};
+
+struct vfytag_s {
+ rpmTagVal tag;
+ rpmTagType tagtype;
+ rpm_count_t tagcount;
+ rpm_count_t tagsize;
+};
+
+static const struct vfytag_s rpmvfytags[] = {
+ { RPMSIGTAG_SIZE, RPM_BIN_TYPE, 0, 0, },
+ { RPMSIGTAG_PGP, RPM_BIN_TYPE, 0, 0, },
+ { RPMSIGTAG_MD5, RPM_BIN_TYPE, 0, 16, },
+ { RPMSIGTAG_GPG, RPM_BIN_TYPE, 0, 0, },
+ { RPMSIGTAG_PGP5, RPM_BIN_TYPE, 0, 0, },
+ { RPMSIGTAG_PAYLOADSIZE, RPM_INT32_TYPE, 1, 4, },
+ { RPMSIGTAG_RESERVEDSPACE, RPM_BIN_TYPE, 0, 0, },
+ { RPMTAG_DSAHEADER, RPM_BIN_TYPE, 0, 0, },
+ { RPMTAG_RSAHEADER, RPM_BIN_TYPE, 0, 0, },
+ { RPMTAG_SHA1HEADER, RPM_STRING_TYPE, 1, 41, },
+ { RPMSIGTAG_LONGSIZE, RPM_INT64_TYPE, 1, 8, },
+ { RPMSIGTAG_LONGARCHIVESIZE, RPM_INT64_TYPE, 1, 8, },
+ { RPMTAG_SHA256HEADER, RPM_STRING_TYPE, 1, 65, },
+ { RPMTAG_PAYLOADDIGEST, RPM_STRING_ARRAY_TYPE, 0, 0, },
+ { 0 } /* sentinel */
+};
+
+struct vfyinfo_s {
+ rpmTagVal tag;
+ struct rpmsinfo_s vi;
+};
+
+static const struct vfyinfo_s rpmvfyitems[] = {
+ { RPMSIGTAG_SIZE,
+ { RPMSIG_OTHER_TYPE, 0,
+ (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
+ { RPMSIGTAG_PGP,
+ { RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSA,
+ (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
+ { RPMSIGTAG_MD5,
+ { RPMSIG_DIGEST_TYPE, RPMVSF_NOMD5,
+ (RPMSIG_HEADER|RPMSIG_PAYLOAD), PGPHASHALGO_MD5, }, },
+ { RPMSIGTAG_GPG,
+ { RPMSIG_SIGNATURE_TYPE, RPMVSF_NODSA,
+ (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
+ { RPMSIGTAG_PGP5,
+ { RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSA,
+ (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
+ { RPMSIGTAG_PAYLOADSIZE,
+ { RPMSIG_OTHER_TYPE, 0,
+ (RPMSIG_PAYLOAD), 0, }, },
+ { RPMSIGTAG_RESERVEDSPACE,
+ { RPMSIG_OTHER_TYPE, 0,
+ 0, 0, }, },
+ { RPMTAG_DSAHEADER,
+ { RPMSIG_SIGNATURE_TYPE, RPMVSF_NODSAHEADER,
+ (RPMSIG_HEADER), 0, }, },
+ { RPMTAG_RSAHEADER,
+ { RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSAHEADER,
+ (RPMSIG_HEADER), 0, }, },
+ { RPMTAG_SHA1HEADER,
+ { RPMSIG_DIGEST_TYPE, RPMVSF_NOSHA1HEADER,
+ (RPMSIG_HEADER), PGPHASHALGO_SHA1, }, },
+ { RPMSIGTAG_LONGSIZE,
+ { RPMSIG_OTHER_TYPE, 0,
+ (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
+ { RPMSIGTAG_LONGARCHIVESIZE,
+ { RPMSIG_OTHER_TYPE, 0,
+ (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
+ { RPMTAG_SHA256HEADER,
+ { RPMSIG_DIGEST_TYPE, RPMVSF_NOSHA256HEADER,
+ (RPMSIG_HEADER), PGPHASHALGO_SHA256, }, },
+ { RPMTAG_PAYLOADDIGEST,
+ { RPMSIG_DIGEST_TYPE, RPMVSF_NOPAYLOAD,
+ (RPMSIG_PAYLOAD), PGPHASHALGO_SHA256, }, },
+ { 0 } /* sentinel */
+};
+
+static const char *rangeName(int range);
+static const char * rpmSigString(rpmRC res);
+static rpmRC rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo,
+ DIGEST_CTX ctx, char ** result);
+
+static int sinfoLookup(rpmTagVal tag)
+{
+ const struct vfyinfo_s *start = &rpmvfyitems[0];
+ int ix = -1;
+ for (const struct vfyinfo_s *si = start; si->tag; si++) {
+ if (tag == si->tag) {
+ ix = si - start;
+ break;
+ }
+ }
+ return ix;
+}
+
+static int validHex(const char *str, size_t slen)
+{
+ int valid = 0; /* Assume invalid */
+ const char *b;
+
+ /* Our hex data is always even sized and at least sha-1 long */
+ if (slen % 2 || slen < 40)
+ goto exit;
+
+ for (b = str ; *b != '\0'; b++) {
+ if (strchr("0123456789abcdefABCDEF", *b) == NULL)
+ goto exit;
+ }
+ valid = 1;
+
+exit:
+ return valid;
+}
+
+static rpmRC rpmsinfoInit(rpmtd td, const char *origin,
+ struct rpmsinfo_s *sinfo, char **msg)
+{
+ rpmRC rc = RPMRC_FAIL;
+ const void *data = NULL;
+ const struct vfytag_s *tinfo;
+ const struct vfyinfo_s *vinfo;
+ rpm_count_t dlen = 0;
+ int ix;
+
+ if ((ix = sinfoLookup(td->tag)) == -1) {
+ /* anything unknown just falls through for now */
+ rc = RPMRC_OK;
+ goto exit;
+ }
+ vinfo = &rpmvfyitems[ix];
+ tinfo = &rpmvfytags[ix];
+ assert(tinfo->tag == vinfo->tag);
+
+ *sinfo = rpmvfyitems[ix].vi; /* struct assignment */
+
+ if (tinfo->tagtype && tinfo->tagtype != td->type) {
+ rasprintf(msg, _("%s tag %u: invalid type %u"),
+ origin, td->tag, td->type);
+ goto exit;
+ }
+
+ if (tinfo->tagcount && tinfo->tagcount != td->count) {
+ rasprintf(msg, _("%s: tag %u: invalid count %u"),
+ origin, td->tag, td->count);
+ goto exit;
+ }
+
+ switch (td->type) {
+ case RPM_STRING_TYPE:
+ case RPM_STRING_ARRAY_TYPE:
+ data = rpmtdGetString(td);
+ if (data)
+ dlen = strlen(data);
+ break;
+ case RPM_BIN_TYPE:
+ data = td->data;
+ dlen = td->count;
+ break;
+ }
+
+ /* MD5 has data length of 16, everything else is (much) larger */
+ if (sinfo->hashalgo && (data == NULL || dlen < 16)) {
+ rasprintf(msg, _("%s tag %u: invalid data %p (%u)"),
+ origin, td->tag, data, dlen);
+ goto exit;
+ }
+
+ if (td->type == RPM_STRING_TYPE && td->size == 0)
+ td->size = dlen + 1;
+
+ if (tinfo->tagsize && (td->flags & RPMTD_IMMUTABLE) &&
+ tinfo->tagsize != td->size) {
+ rasprintf(msg, _("%s tag %u: invalid size %u"),
+ origin, td->tag, td->size);
+ goto exit;
+ }
+
+ if (sinfo->type == RPMSIG_SIGNATURE_TYPE) {
+ if (pgpPrtParams(data, dlen, PGPTAG_SIGNATURE, &sinfo->sig)) {
+ rasprintf(msg, _("%s tag %u: invalid OpenPGP signature"),
+ origin, td->tag);
+ goto exit;
+ }
+ sinfo->hashalgo = pgpDigParamsAlgo(sinfo->sig, PGPVAL_HASHALGO);
+ sinfo->keyid = pgpGrab(sinfo->sig->signid+4, 4);
+ } else if (sinfo->type == RPMSIG_DIGEST_TYPE) {
+ if (td->type == RPM_BIN_TYPE) {
+ sinfo->dig = pgpHexStr(data, dlen);
+ } else {
+ if (!validHex(data, dlen)) {
+ rasprintf(msg, _("%s: tag %u: invalid hex"), origin, td->tag);
+ goto exit;
+ }
+ sinfo->dig = xstrdup(data);
+ }
+ }
+
+ if (sinfo->hashalgo)
+ sinfo->id = (td->tag << 16) | rpmtdGetIndex(td);
+
+ rc = RPMRC_OK;
+
+exit:
+ return rc;
+}
+
+static void rpmsinfoFini(struct rpmsinfo_s *sinfo)
+{
+ if (sinfo) {
+ if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
+ pgpDigParamsFree(sinfo->sig);
+ else if (sinfo->type == RPMSIG_DIGEST_TYPE)
+ free(sinfo->dig);
+ free(sinfo->descr);
+ memset(sinfo, 0, sizeof(*sinfo));
+ }
+}
+
+static int rpmsinfoDisabled(const struct rpmsinfo_s *sinfo, rpmVSFlags vsflags)
+{
+ if (!(sinfo->type & RPMSIG_VERIFIABLE_TYPE))
+ return 1;
+ if (vsflags & sinfo->disabler)
+ return 1;
+ if ((vsflags & RPMVSF_NEEDPAYLOAD) && (sinfo->range & RPMSIG_PAYLOAD))
+ return 1;
+ return 0;
+}
+
+static void rpmvsReserve(struct rpmvs_s *vs, int n)
+{
+ if (vs->nsigs + n >= vs->nalloced) {
+ vs->nalloced = (vs->nsigs * 2) + n;
+ vs->rcs = xrealloc(vs->rcs, vs->nalloced * sizeof(*vs->rcs));
+ vs->results = xrealloc(vs->results, vs->nalloced * sizeof(*vs->results));
+ vs->sigs = xrealloc(vs->sigs, vs->nalloced * sizeof(*vs->sigs));
+ }
+}
+
+const char *rpmsinfoDescr(struct rpmsinfo_s *sinfo)
+{
+ if (sinfo->descr == NULL) {
+ char *t;
+ switch (sinfo->type) {
+ case RPMSIG_DIGEST_TYPE:
+ rasprintf(&sinfo->descr, _("%s%s %s"),
+ rangeName(sinfo->range),
+ pgpValString(PGPVAL_HASHALGO, sinfo->hashalgo),
+ _("digest"));
+ break;
+ case RPMSIG_SIGNATURE_TYPE:
+ t = sinfo->sig ? pgpIdentItem(sinfo->sig) : NULL;
+ rasprintf(&sinfo->descr, _("%s%s"),
+ rangeName(sinfo->range), t ? t : _("signature"));
+ free(t);
+ break;
+ }
+ }
+ return sinfo->descr;
+}
+
+char *rpmsinfoMsg(struct rpmsinfo_s *sinfo, rpmRC rc, const char *emsg)
+{
+ char *msg = NULL;
+ if (emsg) {
+ rasprintf(&msg, "%s: %s (%s)",
+ rpmsinfoDescr(sinfo), rpmSigString(rc), emsg);
+ } else {
+ rasprintf(&msg, "%s: %s", rpmsinfoDescr(sinfo), rpmSigString(rc));
+ }
+ return msg;
+}
+
+void rpmvsAppend(struct rpmvs_s *sis, hdrblob blob, rpmTagVal tag)
+{
+ struct rpmtd_s td;
+ rpmRC rc = hdrblobGet(blob, tag, &td);
+
+ if (rc == RPMRC_OK) {
+ const char *o = (blob->il > blob->ril) ? _("header") : _("package");
+ int ix;
+
+ rpmvsReserve(sis, rpmtdCount(&td));
+
+ while ((ix = rpmtdNext(&td)) >= 0) {
+ sis->results[sis->nsigs] = NULL;
+ sis->rcs[sis->nsigs] = rpmsinfoInit(&td, o,
+ &sis->sigs[sis->nsigs],
+ &sis->results[sis->nsigs]);
+ sis->nsigs++;
+ }
+ rpmtdFreeData(&td);
+ }
+}
+
+struct rpmvs_s *rpmvsCreate(hdrblob blob, rpmVSFlags vsflags)
+{
+ struct rpmvs_s *sis = xcalloc(1, sizeof(*sis));
+
+ rpmvsReserve(sis, 2); /* XXX bump this up later */
+
+ for (const struct vfyinfo_s *si = &rpmvfyitems[0]; si->tag; si++) {
+ if (rpmsinfoDisabled(&si->vi, vsflags))
+ continue;
+ rpmvsAppend(sis, blob, si->tag);
+ }
+ return sis;
+}
+
+struct rpmvs_s *rpmvsFree(struct rpmvs_s *sis)
+{
+ if (sis) {
+ free(sis->rcs);
+ for (int i = 0; i < sis->nsigs; i++) {
+ rpmsinfoFini(&sis->sigs[i]);
+ free(sis->results[i]);
+ }
+ free(sis->sigs);
+ free(sis->results);
+ free(sis);
+ }
+ return NULL;
+}
+
+void rpmvsInitDigests(struct rpmvs_s *sis, int range, rpmDigestBundle bundle)
+{
+ for (int i = 0; i < sis->nsigs; i++) {
+ struct rpmsinfo_s *sinfo = &sis->sigs[i];
+ if (sinfo->range & range) {
+ if (sis->rcs[i] == RPMRC_OK)
+ rpmDigestBundleAddID(bundle, sinfo->hashalgo, sinfo->id, 0);
+ }
+ }
+}
+
+int rpmvsVerifyItems(rpmPlugins plugins, struct rpmvs_s *sis, int range, rpmDigestBundle bundle,
+ rpmKeyring keyring, rpmsinfoCb cb, void *cbdata)
+{
+ int failed = 0;
+
+ for (int i = 0; i < sis->nsigs; i++) {
+ struct rpmsinfo_s *sinfo = &sis->sigs[i];
+
+ if (sinfo->range == range) {
+ if (sis->rcs[i] == RPMRC_OK) {
+ DIGEST_CTX ctx = rpmDigestBundleDupCtx(bundle, sinfo->id);
+ sis->results[i] = _free(sis->results[i]);
+ sis->rcs[i] = rpmVerifySignature(keyring, sinfo, ctx, &sis->results[i]);
+ /* Run verify hook for all plugins */
+ sis->rcs[i] = rpmpluginsCallVerify(plugins, keyring, sinfo->id, sinfo->sig, ctx, sis->rcs[i]);
+ rpmDigestFinal(ctx, NULL, NULL, 0);
+ rpmDigestBundleFinal(bundle, sinfo->id, NULL, NULL, 0);
+ }
+
+ if (cb)
+ sis->rcs[i] = cb(sinfo, sis->rcs[i], sis->results[i], cbdata);
+
+ if (sis->rcs[i] != RPMRC_OK)
+ failed++;
+ }
+ }
+
+ return failed;
+}
+
+static const char * rpmSigString(rpmRC res)
+{
+ const char * str;
+ switch (res) {
+ case RPMRC_OK: str = "OK"; break;
+ case RPMRC_FAIL: str = "BAD"; break;
+ case RPMRC_NOKEY: str = "NOKEY"; break;
+ case RPMRC_NOTTRUSTED: str = "NOTTRUSTED"; break;
+ default:
+ case RPMRC_NOTFOUND: str = "UNKNOWN"; break;
+ }
+ return str;
+}
+
+static const char *rangeName(int range)
+{
+ switch (range) {
+ case RPMSIG_HEADER: return _("Header ");
+ case RPMSIG_PAYLOAD: return _("Payload ");
+ }
+ /* trad. output for (RPMSIG_HEADER|RPMSIG_PAYLOAD) range is "" */
+ return "";
+}
+
+static rpmRC verifyDigest(struct rpmsinfo_s *sinfo, DIGEST_CTX digctx,
+ char **msg)
+{
+ rpmRC res = RPMRC_FAIL; /* assume failure */
+ char * dig = NULL;
+ size_t diglen = 0;
+ DIGEST_CTX ctx = rpmDigestDup(digctx);
+
+ if (rpmDigestFinal(ctx, (void **)&dig, &diglen, 1) || diglen == 0)
+ goto exit;
+
+ if (strcasecmp(sinfo->dig, dig) == 0) {
+ res = RPMRC_OK;
+ } else {
+ rasprintf(msg, "Expected %s != %s", sinfo->dig, dig);
+ }
+
+exit:
+ free(dig);
+ return res;
+}
+
+/**
+ * Verify DSA/RSA signature.
+ * @param keyring pubkey keyring
+ * @param sinfo OpenPGP signature parameters
+ * @param hashctx digest context
+ * @retval msg verbose success/failure text
+ * @return RPMRC_OK on success
+ */
+static rpmRC
+verifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo,
+ DIGEST_CTX hashctx, char **msg)
+{
+ rpmRC res = rpmKeyringVerifySig(keyring, sinfo->sig, hashctx);
+
+ return res;
+}
+
+static rpmRC
+rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo,
+ DIGEST_CTX ctx, char ** result)
+{
+ rpmRC res = RPMRC_FAIL;
+
+ if (sinfo->type == RPMSIG_DIGEST_TYPE)
+ res = verifyDigest(sinfo, ctx, result);
+ else if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
+ res = verifySignature(keyring, sinfo, ctx, result);
+
+ return res;
+}
diff --git a/lib/rpmvs.h b/lib/rpmvs.h
new file mode 100644
index 000000000..f96f20219
--- /dev/null
+++ b/lib/rpmvs.h
@@ -0,0 +1,75 @@
+#ifndef _RPMVS_H
+#define _RPMVS_H
+
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmts.h> /* for rpmVSFlags */
+#include "lib/header_internal.h"
+
+enum {
+ RPMSIG_UNKNOWN_TYPE = 0,
+ RPMSIG_DIGEST_TYPE = (1 << 0),
+ RPMSIG_SIGNATURE_TYPE = (1 << 1),
+ RPMSIG_OTHER_TYPE = (1 << 2),
+};
+
+#define RPMSIG_VERIFIABLE_TYPE (RPMSIG_DIGEST_TYPE|RPMSIG_SIGNATURE_TYPE)
+
+/* siginfo range bits */
+enum {
+ RPMSIG_HEADER = (1 << 0),
+ RPMSIG_PAYLOAD = (1 << 1),
+};
+
+struct rpmsinfo_s {
+ /* static data */
+ int type;
+ int disabler;
+ int range;
+ /* parsed data */
+ int hashalgo;
+ int id;
+ unsigned int keyid;
+ union {
+ pgpDigParams sig;
+ char *dig;
+ };
+ char *descr;
+};
+
+typedef rpmRC (*rpmsinfoCb)(struct rpmsinfo_s *sinfo, rpmRC sigres, const char *result, void *cbdata);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+RPM_GNUC_INTERNAL
+const char *rpmsinfoDescr(struct rpmsinfo_s *sinfo);
+
+RPM_GNUC_INTERNAL
+char *rpmsinfoMsg(struct rpmsinfo_s *sinfo, rpmRC rc, const char *emsg);
+
+RPM_GNUC_INTERNAL
+struct rpmvs_s *rpmvsCreate(hdrblob blob, rpmVSFlags vsflags);
+
+RPM_GNUC_INTERNAL
+struct rpmvs_s *rpmvsFree(struct rpmvs_s *sis);
+
+RPM_GNUC_INTERNAL
+void rpmvsAppend(struct rpmvs_s *sis, hdrblob blob, rpmTagVal tag);
+
+RPM_GNUC_INTERNAL
+void rpmvsInitDigests(struct rpmvs_s *sis, int range, rpmDigestBundle bundle);
+
+RPM_GNUC_INTERNAL
+int rpmvsVerifyItems(rpmPlugins plugins, struct rpmvs_s *sis, int range, rpmDigestBundle bundle,
+ rpmKeyring keyring, rpmsinfoCb cb, void *cbdata);
+
+RPM_GNUC_INTERNAL
+rpmRC rpmpkgRead(rpmPlugins plugins, rpmKeyring keyring, rpmVSFlags flags, FD_t fd,
+ rpmsinfoCb cb, void *cbdata, Header *hdrp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RPMVS_H */
diff --git a/lib/signature.c b/lib/signature.c
index 1c5327072..6f04962e8 100644
--- a/lib/signature.c
+++ b/lib/signature.c
@@ -11,238 +11,74 @@
#include <rpm/rpmstring.h>
#include <rpm/rpmfileutil.h>
#include <rpm/rpmlog.h>
-#include <rpm/rpmkeyring.h>
+#include <rpm/rpmmacro.h>
#include "lib/rpmlead.h"
-#include "lib/signature.h"
#include "lib/header_internal.h"
+#include "lib/signature.h"
#include "debug.h"
-/* Dumb wrapper around headerPut() for signature header */
-static int sighdrPut(Header h, rpmTagVal tag, rpmTagType type,
- rpm_data_t p, rpm_count_t c)
-{
- struct rpmtd_s sigtd;
- rpmtdReset(&sigtd);
- sigtd.tag = tag;
- sigtd.type = type;
- sigtd.data = p;
- sigtd.count = c;
- return headerPut(h, &sigtd, HEADERPUT_DEFAULT);
-}
-
/**
- * Print package size.
- * @todo rpmio: use fdSize rather than fstat(2) to get file size.
+ * Print package size (debug purposes only)
* @param fd package file handle
- * @param siglen signature header size
- * @param pad signature padding
- * @param datalen length of header+payload
- * @return rpmRC return code
+ * @param sigh signature header
*/
-static inline rpmRC printSize(FD_t fd, size_t siglen, size_t pad, rpm_loff_t datalen)
+static void printSize(FD_t fd, Header sigh)
{
struct stat st;
int fdno = Fileno(fd);
+ size_t siglen = headerSizeof(sigh, HEADER_MAGIC_YES);
+ size_t pad = (8 - (siglen % 8)) % 8; /* 8-byte pad */
+ struct rpmtd_s sizetag;
+ rpm_loff_t datalen = 0;
- if (fstat(fdno, &st) < 0)
- return RPMRC_FAIL;
+ /* Print package component sizes. */
+ if (headerGet(sigh, RPMSIGTAG_LONGSIZE, &sizetag, HEADERGET_DEFAULT)) {
+ rpm_loff_t *tsize = rpmtdGetUint64(&sizetag);
+ datalen = (tsize) ? *tsize : 0;
+ } else if (headerGet(sigh, RPMSIGTAG_SIZE, &sizetag, HEADERGET_DEFAULT)) {
+ rpm_off_t *tsize = rpmtdGetUint32(&sizetag);
+ datalen = (tsize) ? *tsize : 0;
+ }
+ rpmtdFreeData(&sizetag);
rpmlog(RPMLOG_DEBUG,
"Expected size: %12" PRIu64 \
" = lead(%d)+sigs(%zd)+pad(%zd)+data(%" PRIu64 ")\n",
RPMLEAD_SIZE+siglen+pad+datalen,
RPMLEAD_SIZE, siglen, pad, datalen);
- rpmlog(RPMLOG_DEBUG,
- " Actual size: %12" PRIu64 "\n", (rpm_loff_t) st.st_size);
- return RPMRC_OK;
+ if (fstat(fdno, &st) == 0) {
+ rpmlog(RPMLOG_DEBUG,
+ " Actual size: %12" PRIu64 "\n", (rpm_loff_t) st.st_size);
+ }
}
-rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
+rpmRC rpmReadSignature(FD_t fd, Header * sighp, char ** msg)
{
char *buf = NULL;
- int32_t block[4];
- int32_t il;
- int32_t dl;
- int32_t * ei = NULL;
- entryInfo pe;
- unsigned int nb, uc;
- int32_t ril = 0;
- struct indexEntry_s entry;
- struct entryInfo_s info;
- unsigned char * dataStart;
- unsigned char * dataEnd = NULL;
+ struct hdrblob_s blob;
Header sigh = NULL;
rpmRC rc = RPMRC_FAIL; /* assume failure */
- int xx;
- int i;
if (sighp)
*sighp = NULL;
- if (sig_type != RPMSIGTYPE_HEADERSIG)
- goto exit;
-
- memset(block, 0, sizeof(block));
- if ((xx = Freadall(fd, block, sizeof(block))) != sizeof(block)) {
- rasprintf(&buf, _("sigh size(%d): BAD, read returned %d\n"),
- (int)sizeof(block), xx);
- goto exit;
- }
- if (memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) {
- rasprintf(&buf, _("sigh magic: BAD\n"));
+ if (hdrblobRead(fd, 1, 1, RPMTAG_HEADERSIGNATURES, &blob, &buf) != RPMRC_OK)
goto exit;
- }
- il = ntohl(block[2]);
- if (il < 0 || il > 32) {
- rasprintf(&buf,
- _("sigh tags: BAD, no. of tags(%d) out of range\n"), il);
- goto exit;
- }
- dl = ntohl(block[3]);
- if (dl < 0 || dl > 8192) {
- rasprintf(&buf,
- _("sigh data: BAD, no. of bytes(%d) out of range\n"), dl);
- goto exit;
- }
-
- memset(&entry, 0, sizeof(entry));
- memset(&info, 0, sizeof(info));
-
- nb = (il * sizeof(struct entryInfo_s)) + dl;
- uc = sizeof(il) + sizeof(dl) + nb;
- ei = xmalloc(uc);
- ei[0] = block[2];
- ei[1] = block[3];
- pe = (entryInfo) &ei[2];
- dataStart = (unsigned char *) (pe + il);
- if ((xx = Freadall(fd, pe, nb)) != nb) {
- rasprintf(&buf,
- _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx);
- goto exit;
- }
- /* Check (and convert) the 1st tag element. */
- xx = headerVerifyInfo(1, dl, pe, &entry.info, 0);
- if (xx != -1) {
- rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
- 0, entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
-
- /* Is there an immutable header region tag? */
- if (entry.info.tag == RPMTAG_HEADERSIGNATURES) {
- /* Is the region tag sane? */
- if (!(entry.info.type == REGION_TAG_TYPE &&
- entry.info.count == REGION_TAG_COUNT)) {
- rasprintf(&buf,
- _("region tag: BAD, tag %d type %d offset %d count %d\n"),
- entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
-
- /* Is the trailer within the data area? */
- if (entry.info.offset + REGION_TAG_COUNT > dl) {
- rasprintf(&buf,
- _("region offset: BAD, tag %d type %d offset %d count %d\n"),
- entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
-
- /* Is there an immutable header region tag trailer? */
- dataEnd = dataStart + entry.info.offset;
- (void) memcpy(&info, dataEnd, REGION_TAG_COUNT);
- /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */
- if (info.tag == htonl(RPMTAG_HEADERIMAGE)) {
- rpmTagVal stag = htonl(RPMTAG_HEADERSIGNATURES);
- info.tag = stag;
- memcpy(dataEnd, &stag, sizeof(stag));
- }
- dataEnd += REGION_TAG_COUNT;
-
- xx = headerVerifyInfo(1, il * sizeof(*pe), &info, &entry.info, 1);
- if (xx != -1 ||
- !((entry.info.tag == RPMTAG_HEADERSIGNATURES || entry.info.tag == RPMTAG_HEADERIMAGE)
- && entry.info.type == REGION_TAG_TYPE
- && entry.info.count == REGION_TAG_COUNT))
- {
- rasprintf(&buf,
- _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
- entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
- memset(&info, 0, sizeof(info));
-
- /* Is the no. of tags in the region less than the total no. of tags? */
- ril = entry.info.offset/sizeof(*pe);
- if ((entry.info.offset % sizeof(*pe)) || ril > il) {
- rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
- goto exit;
- }
- }
-
- /* Sanity check signature tags */
- memset(&info, 0, sizeof(info));
- for (i = 1; i < il; i++) {
- xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0);
- if (xx != -1) {
- rasprintf(&buf,
- _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
- i, entry.info.tag, entry.info.type,
- entry.info.offset, entry.info.count);
- goto exit;
- }
- }
-
/* OK, blob looks sane, load the header. */
- sigh = headerImport(ei, uc, 0);
- if (sigh == NULL) {
- rasprintf(&buf, _("sigh load: BAD\n"));
+ if (hdrblobImport(&blob, 0, &sigh, &buf) != RPMRC_OK)
goto exit;
- }
- { size_t sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
- size_t pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
- ssize_t trc;
- struct rpmtd_s sizetag;
- rpm_loff_t archSize = 0;
-
- /* Position at beginning of header. */
- if (pad && (trc = Freadall(fd, block, pad)) != pad) {
- rasprintf(&buf,
- _("sigh pad(%zd): BAD, read %zd bytes\n"), pad, trc);
- goto exit;
- }
-
- /* Print package component sizes. */
- if (headerGet(sigh, RPMSIGTAG_LONGSIZE, &sizetag, HEADERGET_DEFAULT)) {
- rpm_loff_t *tsize = rpmtdGetUint64(&sizetag);
- archSize = (tsize) ? *tsize : 0;
- } else if (headerGet(sigh, RPMSIGTAG_SIZE, &sizetag, HEADERGET_DEFAULT)) {
- rpm_off_t *tsize = rpmtdGetUint32(&sizetag);
- archSize = (tsize) ? *tsize : 0;
- }
- rpmtdFreeData(&sizetag);
- rc = printSize(fd, sigSize, pad, archSize);
- if (rc != RPMRC_OK) {
- rasprintf(&buf,
- _("sigh sigSize(%zd): BAD, fstat(2) failed\n"), sigSize);
- goto exit;
- }
- }
- ei = NULL; /* XXX will be freed with header */
+ printSize(fd, sigh);
+ rc = RPMRC_OK;
exit:
if (sighp && sigh && rc == RPMRC_OK)
*sighp = headerLink(sigh);
headerFree(sigh);
- free(ei);
if (msg != NULL) {
*msg = buf;
@@ -255,7 +91,7 @@ exit:
int rpmWriteSignature(FD_t fd, Header sigh)
{
- static uint8_t buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ static const uint8_t zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int sigSize, pad;
int rc;
@@ -266,276 +102,128 @@ int rpmWriteSignature(FD_t fd, Header sigh)
sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
pad = (8 - (sigSize % 8)) % 8;
if (pad) {
- if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
+ if (Fwrite(zeros, sizeof(zeros[0]), pad, fd) != pad)
rc = 1;
}
rpmlog(RPMLOG_DEBUG, "Signature: size(%d)+pad(%d)\n", sigSize, pad);
return rc;
}
-Header rpmNewSignature(void)
-{
- Header sigh = headerNew();
- return sigh;
-}
-
-Header rpmFreeSignature(Header sigh)
-{
- return headerFree(sigh);
-}
-
-static int makeHDRDigest(Header sigh, const char * file, rpmTagVal sigTag)
-{
- Header h = NULL;
- FD_t fd = NULL;
- char * SHA1 = NULL;
- int ret = -1; /* assume failure. */
-
- switch (sigTag) {
- case RPMSIGTAG_SHA1:
- fd = Fopen(file, "r.fdio");
- if (fd == NULL || Ferror(fd))
- goto exit;
- h = headerRead(fd, HEADER_MAGIC_YES);
- if (h == NULL)
- goto exit;
-
- if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
- DIGEST_CTX ctx;
- struct rpmtd_s utd;
-
- if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)
- || utd.data == NULL)
- {
- rpmlog(RPMLOG_ERR,
- _("Immutable header region could not be read. "
- "Corrupted package?\n"));
- goto exit;
- }
- ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
- (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
- (void) rpmDigestUpdate(ctx, utd.data, utd.count);
- (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
- rpmtdFreeData(&utd);
- } else {
- rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n"));
- goto exit;
- }
-
- if (SHA1 == NULL)
- goto exit;
- if (!sighdrPut(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
- goto exit;
- ret = 0;
- break;
- default:
- break;
- }
-
-exit:
- free(SHA1);
- headerFree(h);
- if (fd != NULL) (void) Fclose(fd);
- return ret;
-}
-
-int rpmGenDigest(Header sigh, const char * file, rpmTagVal sigTag)
+rpmRC rpmGenerateSignature(char *SHA256, char *SHA1, uint8_t *MD5,
+ rpm_loff_t size, rpm_loff_t payloadSize, FD_t fd)
{
- struct stat st;
- uint8_t * pkt = NULL;
- size_t pktlen;
- int ret = -1; /* assume failure. */
-
- switch (sigTag) {
- case RPMSIGTAG_SIZE: {
- rpm_off_t size;
- if (stat(file, &st) != 0)
- break;
- size = st.st_size;
- if (!sighdrPut(sigh, sigTag, RPM_INT32_TYPE, &size, 1))
- break;
- ret = 0;
- } break;
- case RPMSIGTAG_LONGSIZE: {
- rpm_loff_t size;
- if (stat(file, &st) != 0)
- break;
- size = st.st_size;
- if (!sighdrPut(sigh, sigTag, RPM_INT64_TYPE, &size, 1))
- break;
- ret = 0;
- } break;
- case RPMSIGTAG_MD5:
- pktlen = 16;
- pkt = xcalloc(pktlen, sizeof(*pkt));
- if (rpmDoDigest(PGPHASHALGO_MD5, file, 0, pkt, NULL)
- || !sighdrPut(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
- break;
- ret = 0;
- break;
- case RPMSIGTAG_SHA1:
- ret = makeHDRDigest(sigh, file, sigTag);
- break;
- default:
- break;
- }
- free(pkt);
-
- return ret;
-}
-
-static const char * rpmSigString(rpmRC res)
-{
- const char * str;
- switch (res) {
- case RPMRC_OK: str = "OK"; break;
- case RPMRC_FAIL: str = "BAD"; break;
- case RPMRC_NOKEY: str = "NOKEY"; break;
- case RPMRC_NOTTRUSTED: str = "NOTRUSTED"; break;
- default:
- case RPMRC_NOTFOUND: str = "UNKNOWN"; break;
- }
- return str;
-}
-
-static rpmRC
-verifyMD5Digest(rpmtd sigtd, DIGEST_CTX md5ctx, char **msg)
-{
- rpmRC res = RPMRC_FAIL; /* assume failure */
- uint8_t * md5sum = NULL;
- size_t md5len = 0;
- char *md5;
- const char *title = _("MD5 digest:");
- *msg = NULL;
- DIGEST_CTX ctx = rpmDigestDup(md5ctx);
-
- if (ctx == NULL) {
- rasprintf(msg, "%s %s\n", title, rpmSigString(res));
+ Header sig = headerNew();
+ struct rpmtd_s td;
+ rpmRC rc = RPMRC_OK;
+ char *reservedSpace;
+ int spaceSize = 32; /* always reserve a bit of space */
+ int gpgSize = rpmExpandNumeric("%{__gpg_reserved_space}");
+ rpm_off_t size32 = size;
+ rpm_off_t payloadSize32 = payloadSize;
+
+ /* Prepare signature */
+ if (SHA256) {
+ rpmtdReset(&td);
+ td.tag = RPMSIGTAG_SHA256;
+ td.count = 1;
+ td.type = RPM_STRING_TYPE;
+ td.data = SHA256;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+ }
+
+ if (SHA1) {
+ rpmtdReset(&td);
+ td.tag = RPMSIGTAG_SHA1;
+ td.count = 1;
+ td.type = RPM_STRING_TYPE;
+ td.data = SHA1;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+ }
+
+ if (MD5) {
+ rpmtdReset(&td);
+ td.tag = RPMSIGTAG_MD5;
+ td.count = 16;
+ td.type = RPM_BIN_TYPE;
+ td.data = MD5;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+ }
+
+ rpmtdReset(&td);
+ td.count = 1;
+ td.type = RPM_INT32_TYPE;
+
+ td.tag = RPMSIGTAG_PAYLOADSIZE;
+ td.data = &payloadSize32;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ td.tag = RPMSIGTAG_SIZE;
+ td.data = &size32;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ if (size >= UINT32_MAX || payloadSize >= UINT32_MAX) {
+ /*
+ * Put the 64bit size variants into the header, but
+ * modify spaceSize so that the resulting header has
+ * the same size. Note that this only works if all tags
+ * with a lower number than RPMSIGTAG_RESERVEDSPACE are
+ * already added and no tag with a higher number is
+ * added yet.
+ */
+ rpm_loff_t p = payloadSize;
+ rpm_loff_t s = size;
+ int newsigSize, oldsigSize;
+
+ oldsigSize = headerSizeof(sig, HEADER_MAGIC_YES);
+
+ headerDel(sig, RPMSIGTAG_PAYLOADSIZE);
+ headerDel(sig, RPMSIGTAG_SIZE);
+
+ td.type = RPM_INT64_TYPE;
+
+ td.tag = RPMSIGTAG_LONGARCHIVESIZE;
+ td.data = &p;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ td.tag = RPMSIGTAG_LONGSIZE;
+ td.data = &s;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ newsigSize = headerSizeof(sig, HEADER_MAGIC_YES);
+ spaceSize -= newsigSize - oldsigSize;
+ }
+
+ if (gpgSize > 0)
+ spaceSize += gpgSize;
+
+ if (spaceSize > 0) {
+ reservedSpace = xcalloc(spaceSize, sizeof(char));
+ rpmtdReset(&td);
+ td.tag = RPMSIGTAG_RESERVEDSPACE;
+ td.count = spaceSize;
+ td.type = RPM_BIN_TYPE;
+ td.data = reservedSpace;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+ free(reservedSpace);
+ }
+
+ /* Reallocate the signature into one contiguous region. */
+ sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
+ if (sig == NULL) { /* XXX can't happen */
+ rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
+ rc = RPMRC_FAIL;
goto exit;
}
- (void) rpmDigestFinal(ctx, (void **)&md5sum, &md5len, 0);
-
- md5 = pgpHexStr(md5sum, md5len);
- if (md5len != sigtd->count || memcmp(md5sum, sigtd->data, md5len)) {
- char *hex = rpmtdFormat(sigtd, RPMTD_FORMAT_STRING, NULL);
- rasprintf(msg, "%s %s Expected(%s) != (%s)\n", title,
- rpmSigString(res), hex, md5);
- free(hex);
- } else {
- res = RPMRC_OK;
- rasprintf(msg, "%s %s (%s)\n", title, rpmSigString(res), md5);
- }
- free(md5);
-
-exit:
- md5sum = _free(md5sum);
- return res;
-}
-
-/**
- * Verify header immutable region SHA1 digest.
- * @retval msg verbose success/failure text
- * @param sha1ctx
- * @return RPMRC_OK on success
- */
-static rpmRC
-verifySHA1Digest(rpmtd sigtd, DIGEST_CTX sha1ctx, char **msg)
-{
- rpmRC res = RPMRC_FAIL; /* assume failure */
- char * SHA1 = NULL;
- const char *title = _("Header SHA1 digest:");
- const char *sig = sigtd->data;
- *msg = NULL;
- DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
-
- if (ctx == NULL) {
- rasprintf(msg, "%s %s\n", title, rpmSigString(res));
+ /* Write the signature section into the package. */
+ if (rpmWriteSignature(fd, sig)) {
+ rc = RPMRC_FAIL;
goto exit;
}
- (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
-
- if (SHA1 == NULL || !rstreq(SHA1, sig)) {
- rasprintf(msg, "%s %s Expected(%s) != (%s)\n", title,
- rpmSigString(res), sig, SHA1 ? SHA1 : "(nil)");
- } else {
- res = RPMRC_OK;
- rasprintf(msg, "%s %s (%s)\n", title, rpmSigString(res), SHA1);
- }
-
exit:
- SHA1 = _free(SHA1);
- return res;
-}
-
-/**
- * Verify DSA/RSA signature.
- * @param keyring pubkey keyring
- * @param sig OpenPGP signature parameters
- * @param hashctx digest context
- * @param isHdr header-only signature?
- * @retval msg verbose success/failure text
- * @return RPMRC_OK on success
- */
-static rpmRC
-verifySignature(rpmKeyring keyring, pgpDigParams sig, DIGEST_CTX hashctx,
- int isHdr, char **msg)
-{
-
- rpmRC res = rpmKeyringVerifySig(keyring, sig, hashctx);
-
- char *sigid = pgpIdentItem(sig);
- rasprintf(msg, "%s%s: %s\n", isHdr ? _("Header ") : "", sigid,
- rpmSigString(res));
- free(sigid);
- return res;
+ headerFree(sig);
+ return rc;
}
-rpmRC
-rpmVerifySignature(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig,
- DIGEST_CTX ctx, char ** result)
-{
- rpmRC res = RPMRC_NOTFOUND;
- char *msg = NULL;
- int hdrsig = 0;
- if (sigtd->data == NULL || sigtd->count <= 0 || ctx == NULL)
- goto exit;
-
- switch (sigtd->tag) {
- case RPMSIGTAG_MD5:
- res = verifyMD5Digest(sigtd, ctx, &msg);
- break;
- case RPMSIGTAG_SHA1:
- res = verifySHA1Digest(sigtd, ctx, &msg);
- break;
- case RPMSIGTAG_RSA:
- case RPMSIGTAG_DSA:
- hdrsig = 1;
- /* fallthrough */
- case RPMSIGTAG_PGP5: /* XXX legacy */
- case RPMSIGTAG_PGP:
- case RPMSIGTAG_GPG:
- if (sig != NULL)
- res = verifySignature(keyring, sig, ctx, hdrsig, &msg);
- break;
- default:
- break;
- }
-
-exit:
- if (res == RPMRC_NOTFOUND) {
- rasprintf(&msg,
- _("Verify signature: BAD PARAMETERS (%d %p %d %p %p)\n"),
- sigtd->tag, sigtd->data, sigtd->count, ctx, sig);
- res = RPMRC_FAIL;
- }
-
- if (result) {
- *result = msg;
- } else {
- free(msg);
- }
- return res;
-}
diff --git a/lib/signature.h b/lib/signature.h
index 18bbdc709..85dccd1d3 100644
--- a/lib/signature.h
+++ b/lib/signature.h
@@ -5,36 +5,21 @@
* \file lib/signature.h
* Generate and verify signatures.
*/
-
-#include <rpm/header.h>
-
-/** \ingroup signature
- * Signature types stored in rpm lead.
- */
-typedef enum sigType_e {
- RPMSIGTYPE_HEADERSIG= 5 /*!< Header style signature */
-} sigType;
+#include <rpm/rpmtypes.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \ingroup signature
- * Return new, empty (signature) header instance.
- * @return signature header
- */
-Header rpmNewSignature(void);
-
-/** \ingroup signature
* Read (and verify header+payload size) signature header.
* If an old-style signature is found, we emulate a new style one.
* @param fd file handle
* @retval sighp address of (signature) header (or NULL)
- * @param sig_type type of signature header to read (from lead)
* @retval msg failure msg
* @return rpmRC return code
*/
-rpmRC rpmReadSignature(FD_t fd, Header *sighp, sigType sig_type, char ** msg);
+rpmRC rpmReadSignature(FD_t fd, Header *sighp, char ** msg);
/** \ingroup signature
* Write signature header.
@@ -45,38 +30,16 @@ rpmRC rpmReadSignature(FD_t fd, Header *sighp, sigType sig_type, char ** msg);
int rpmWriteSignature(FD_t fd, Header h);
/** \ingroup signature
- * Generate digest(s) from a header+payload file, save in signature header.
- * @param sigh signature header
- * @param file header+payload file name
- * @param sigTag type of digest(s) to add
- * @return 0 on success, -1 on failure
+ * Generate signature and write to file
+ * @param SHA256 SHA256 digest
+ * @param SHA1 SHA1 digest
+ * @param MD5 MD5 digest
+ * @param size size of header
+ * @param payloadSize size of archive
+ * @param fd output file
*/
-int rpmGenDigest(Header sigh, const char * file, rpmTagVal sigTag);
-
-/** \ingroup signature
- * Verify a signature from a package.
- *
- * @param keyring keyring handle
- * @param sigtd signature tag data container
- * @param sig signature/pubkey parameters
- * @retval result detailed text result of signature verification
- * (malloc'd)
- * @return result of signature verification
- */
-rpmRC rpmVerifySignature(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig,
- DIGEST_CTX ctx, char ** result);
-
-/** \ingroup signature
- * Destroy signature header from package.
- * @param h signature header
- * @return NULL always
- */
-Header rpmFreeSignature(Header h);
-
-/* Dumb wrapper around pgpPrtParams() to log some error messages on failure */
-RPM_GNUC_INTERNAL
-int parsePGPSig(rpmtd sigtd, const char *type, const char *fn,
- pgpDigParams *sig);
+rpmRC rpmGenerateSignature(char *SHA256, char *SHA1, uint8_t *MD5,
+ rpm_loff_t size, rpm_loff_t payloadSize, FD_t fd);
#ifdef __cplusplus
}
diff --git a/lib/tagexts.c b/lib/tagexts.c
index 563c1b43c..00b500c26 100644
--- a/lib/tagexts.c
+++ b/lib/tagexts.c
@@ -272,6 +272,7 @@ static char * strtolocale(char *str)
locisutf8 = 0;
if (locisutf8 == strisutf8) {
wstr = _free(wstr);
+ cc = _free(cc);
return str;
}
str = _free((char *)str);
@@ -300,28 +301,65 @@ static char * strtolocale(char *str)
return (char *)cc;
}
+typedef enum tMode_e {
+ NORMALTRIGGER = 0,
+ FILETRIGGER = 1,
+ TRANSFILETRIGGER = 2,
+} tMode;
+
/**
* Retrieve trigger info.
+ * @param mode type of trigger (see tMode_e)
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
-static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
+static int triggercondsTagFor(tMode mode, Header h, rpmtd td,
+ headerGetFlags hgflags)
{
uint32_t * indices;
int i, j;
char ** conds;
struct rpmtd_s nametd, indextd, flagtd, versiontd, scripttd;
int hgeflags = HEADERGET_MINMEM;
+ rpmTagVal triggername, triggerindex, triggerflags;
+ rpmTagVal triggerversion, triggerscripts;
+
+ switch (mode) {
+ case NORMALTRIGGER:
+ triggername = RPMTAG_TRIGGERNAME;
+ triggerindex = RPMTAG_TRIGGERINDEX;
+ triggerflags = RPMTAG_TRIGGERFLAGS;
+ triggerversion = RPMTAG_TRIGGERVERSION;
+ triggerscripts = RPMTAG_TRIGGERSCRIPTS;
+ break;
+ case FILETRIGGER:
+ triggername = RPMTAG_FILETRIGGERNAME;
+ triggerindex = RPMTAG_FILETRIGGERINDEX;
+ triggerflags = RPMTAG_FILETRIGGERFLAGS;
+ triggerversion = RPMTAG_FILETRIGGERVERSION;
+ triggerscripts = RPMTAG_FILETRIGGERSCRIPTS;
+ break;
+ case TRANSFILETRIGGER:
+ triggername = RPMTAG_TRANSFILETRIGGERNAME;
+ triggerindex = RPMTAG_TRANSFILETRIGGERINDEX;
+ triggerflags = RPMTAG_TRANSFILETRIGGERFLAGS;
+ triggerversion = RPMTAG_TRANSFILETRIGGERVERSION;
+ triggerscripts = RPMTAG_TRANSFILETRIGGERSCRIPTS;
+ break;
+ default:
+ return 0;
+ }
- if (!headerGet(h, RPMTAG_TRIGGERNAME, &nametd, hgeflags)) {
+ if (!headerGet(h, triggername, &nametd, hgeflags)) {
return 0;
}
- headerGet(h, RPMTAG_TRIGGERINDEX, &indextd, hgeflags);
- headerGet(h, RPMTAG_TRIGGERFLAGS, &flagtd, hgeflags);
- headerGet(h, RPMTAG_TRIGGERVERSION, &versiontd, hgeflags);
- headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripttd, hgeflags);
+ headerGet(h, triggerindex, &indextd, hgeflags);
+ headerGet(h, triggerflags, &flagtd, hgeflags);
+ headerGet(h, triggerversion, &versiontd, hgeflags);
+ headerGet(h, triggerscripts, &scripttd, hgeflags);
td->type = RPM_STRING_ARRAY_TYPE;
td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
@@ -370,24 +408,63 @@ static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
return 1;
}
+static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return triggercondsTagFor(NORMALTRIGGER, h, td, hgflags);
+}
+
+static int filetriggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return triggercondsTagFor(FILETRIGGER, h, td, hgflags);
+}
+
+static int transfiletriggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return triggercondsTagFor(TRANSFILETRIGGER, h, td, hgflags);
+}
+
/**
* Retrieve trigger type info.
+ * @param mode type of trigger (see tMode_e)
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
-static int triggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
+static int triggertypeTagFor(tMode mode, Header h, rpmtd td,
+ headerGetFlags hgflags)
{
int i;
char ** conds;
struct rpmtd_s indices, flags, scripts;
+ rpmTagVal triggerindex, triggerflags, triggerscripts;
+
+ switch (mode) {
+ case NORMALTRIGGER:
+ triggerindex = RPMTAG_TRIGGERINDEX;
+ triggerflags = RPMTAG_TRIGGERFLAGS;
+ triggerscripts = RPMTAG_TRIGGERSCRIPTS;
+ break;
+ case FILETRIGGER:
+ triggerindex = RPMTAG_FILETRIGGERINDEX;
+ triggerflags = RPMTAG_FILETRIGGERFLAGS;
+ triggerscripts = RPMTAG_FILETRIGGERSCRIPTS;
+ break;
+ case TRANSFILETRIGGER:
+ triggerindex = RPMTAG_TRANSFILETRIGGERINDEX;
+ triggerflags = RPMTAG_TRANSFILETRIGGERFLAGS;
+ triggerscripts = RPMTAG_TRANSFILETRIGGERSCRIPTS;
+ break;
+ default:
+ return 0;
+ }
- if (!headerGet(h, RPMTAG_TRIGGERINDEX, &indices, HEADERGET_MINMEM)) {
+ if (!headerGet(h, triggerindex, &indices, HEADERGET_MINMEM)) {
return 0;
}
- headerGet(h, RPMTAG_TRIGGERFLAGS, &flags, HEADERGET_MINMEM);
- headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripts, HEADERGET_MINMEM);
+ headerGet(h, triggerflags, &flags, HEADERGET_MINMEM);
+ headerGet(h, triggerscripts, &scripts, HEADERGET_MINMEM);
td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
td->count = rpmtdCount(&scripts);
@@ -423,20 +500,38 @@ static int triggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
return 1;
}
+static int triggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return triggertypeTagFor(NORMALTRIGGER, h, td, hgflags);
+}
+
+static int filetriggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return triggertypeTagFor(FILETRIGGER, h, td, hgflags);
+}
+
+static int transfiletriggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return triggertypeTagFor(TRANSFILETRIGGER, h, td, hgflags);
+}
+
/**
* Retrieve installed file paths.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int instfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
{
return fnTag(h, RPMTAG_BASENAMES, 1, td);
}
+
/**
* Retrieve file paths.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int filenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -448,6 +543,7 @@ static int filenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
* Retrieve original file paths (wrt relocation).
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int origfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -498,6 +594,7 @@ static char *makeFClass(rpmfi fi)
* Retrieve/generate file classes.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int fileclassTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -528,6 +625,7 @@ static int fileclassTag(Header h, rpmtd td, headerGetFlags hgflags)
* Retrieve file provides.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int fileprovideTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -539,6 +637,7 @@ static int fileprovideTag(Header h, rpmtd td, headerGetFlags hgflags)
* Retrieve file requires.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -560,6 +659,7 @@ static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
* @param h header
* @param tag tag
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags)
@@ -655,6 +755,7 @@ static int localeTag(Header h, rpmTag tag, rpmtd td)
* Retrieve summary text.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int summaryTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -666,6 +767,7 @@ static int summaryTag(Header h, rpmtd td, headerGetFlags hgflags)
* Retrieve description text.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int descriptionTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -687,6 +789,7 @@ static int changelogtextTag(Header h, rpmtd td)
* Retrieve group text.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int groupTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -733,6 +836,7 @@ static int get64(Header h, rpmtd td, rpmTag newtag, rpmTag oldtag)
* Retrieve file sizes as 64bit regardless of how they're stored.
* @param h header
* @retval td tag data container
+ * @param hgflags header get flags
* @return 1 on success
*/
static int longfilesizesTag(Header h, rpmtd td, headerGetFlags hgflags)
@@ -799,7 +903,7 @@ typedef rpmFlags nevraFlags;
static int getNEVRA(Header h, rpmtd td, nevraFlags flags)
{
const char *val = NULL;
- char *res = NULL;
+ char *res = xstrdup("");
if ((flags & NEVRA_NAME)) {
val = headerGetString(h, RPMTAG_NAME);
@@ -906,11 +1010,63 @@ static int depnevrsTag(Header h, rpmtd td, headerGetFlags hgflags,
return (ndeps > 0);
}
+#define RPMSENSE_STRONG (1 << 27)
+
+static int depnevrsTagFiltered(Header h, rpmtd td, headerGetFlags hgflags,
+ rpmTagVal tag, int strong)
+{
+ rpmds ds = rpmdsNew(h, tag, 0);
+ int ndeps = rpmdsCount(ds);
+
+ if (ndeps > 0) {
+ char **deps = xmalloc(sizeof(*deps) * ndeps);
+ ndeps = 0;
+ while (rpmdsNext(ds) >= 0) {
+ if ((rpmdsFlags(ds) & RPMSENSE_STRONG) == (strong ? RPMSENSE_STRONG : 0))
+ deps[ndeps++] = rpmdsNewDNEVR(NULL, ds);
+ }
+ if (ndeps) {
+ td->data = deps;
+ td->type = RPM_STRING_ARRAY_TYPE;
+ td->count = ndeps;
+ td->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
+ } else {
+ _free(deps);
+ }
+ }
+ rpmdsFree(ds);
+ return (ndeps > 0);
+}
+
static int requirenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
{
return depnevrsTag(h, td, hgflags, RPMTAG_REQUIRENAME);
}
+static int recommendnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return depnevrsTag(h, td, hgflags, RPMTAG_RECOMMENDNAME) ||
+ depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDSUGGESTSNAME, 1);
+}
+
+static int suggestnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return depnevrsTag(h, td, hgflags, RPMTAG_SUGGESTNAME) ||
+ depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDSUGGESTSNAME, 0);
+}
+
+static int supplementnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return depnevrsTag(h, td, hgflags, RPMTAG_SUPPLEMENTNAME) ||
+ depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDENHANCESNAME, 1);
+}
+
+static int enhancenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
+{
+ return depnevrsTag(h, td, hgflags, RPMTAG_ENHANCENAME) ||
+ depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDENHANCESNAME, 0);
+}
+
static int providenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
{
return depnevrsTag(h, td, hgflags, RPMTAG_PROVIDENAME);
@@ -957,7 +1113,11 @@ static const struct headerTagFunc_s rpmHeaderTagExtensions[] = {
{ RPMTAG_FILEPROVIDE, fileprovideTag },
{ RPMTAG_FILEREQUIRE, filerequireTag },
{ RPMTAG_TRIGGERCONDS, triggercondsTag },
+ { RPMTAG_FILETRIGGERCONDS, filetriggercondsTag },
+ { RPMTAG_TRANSFILETRIGGERCONDS, transfiletriggercondsTag },
{ RPMTAG_TRIGGERTYPE, triggertypeTag },
+ { RPMTAG_FILETRIGGERTYPE, filetriggertypeTag },
+ { RPMTAG_TRANSFILETRIGGERTYPE, transfiletriggertypeTag },
{ RPMTAG_LONGFILESIZES, longfilesizesTag },
{ RPMTAG_LONGARCHIVESIZE, longarchivesizeTag },
{ RPMTAG_LONGSIZE, longsizeTag },
@@ -975,6 +1135,10 @@ static const struct headerTagFunc_s rpmHeaderTagExtensions[] = {
{ RPMTAG_EPOCHNUM, epochnumTag },
{ RPMTAG_INSTFILENAMES, instfilenamesTag },
{ RPMTAG_REQUIRENEVRS, requirenevrsTag },
+ { RPMTAG_RECOMMENDNEVRS, recommendnevrsTag},
+ { RPMTAG_SUGGESTNEVRS, suggestnevrsTag},
+ { RPMTAG_SUPPLEMENTNEVRS, supplementnevrsTag},
+ { RPMTAG_ENHANCENEVRS, enhancenevrsTag},
{ RPMTAG_PROVIDENEVRS, providenevrsTag },
{ RPMTAG_OBSOLETENEVRS, obsoletenevrsTag },
{ RPMTAG_CONFLICTNEVRS, conflictnevrsTag },
diff --git a/lib/tagname.c b/lib/tagname.c
index 0c2696803..68b252991 100644
--- a/lib/tagname.c
+++ b/lib/tagname.c
@@ -4,6 +4,8 @@
#include "system.h"
+#include <pthread.h>
+
#include <rpm/header.h>
#include <rpm/rpmstring.h>
#include "debug.h"
@@ -23,26 +25,11 @@ struct headerTagTableEntry_s {
#include "lib/tagtbl.C"
-static const int rpmTagTableSize = sizeof(rpmTagTable) / sizeof(rpmTagTable[0]) - 1;
+#define TABLESIZE (sizeof(rpmTagTable) / sizeof(rpmTagTable[0]) - 1)
+static const int rpmTagTableSize = TABLESIZE;
-/**
- */
-typedef struct headerTagIndices_s * headerTagIndices;
-
-struct headerTagIndices_s {
- int (*loadIndex) (headerTagTableEntry ** ipp, int * np,
- int (*cmp) (const void * avp, const void * bvp));
- /*!< load sorted tag index. */
- headerTagTableEntry * byName; /*!< header tags sorted by name. */
- int byNameSize; /*!< no. of entries. */
- int (*byNameCmp) (const void * avp, const void * bvp); /*!< compare entries by name. */
- rpmTagVal (*tagValue) (const char * name); /* return value from name. */
- headerTagTableEntry * byValue; /*!< header tags sorted by value. */
- int byValueSize; /*!< no. of entries. */
- int (*byValueCmp) (const void * avp, const void * bvp); /*!< compare entries by value. */
- const char * (*tagName) (rpmTagVal value); /* Return name from value. */
- rpmTagType (*tagType) (rpmTagVal value); /* Return type from value. */
-};
+static headerTagTableEntry tagsByName[TABLESIZE]; /*!< tags sorted by name. */
+static headerTagTableEntry tagsByValue[TABLESIZE]; /*!< tags sorted by value. */
/**
* Compare tag table entries by name.
@@ -74,56 +61,76 @@ static int tagCmpValue(const void * avp, const void * bvp)
return ret;
}
-/**
- * Load/sort a tag index.
- * @retval *ipp tag index
- * @retval *np no. of tags
- * @param cmp sort compare routine
- * @return 0 always
- */
-static int tagLoadIndex(headerTagTableEntry ** ipp, int * np,
- int (*cmp) (const void * avp, const void * bvp))
+static pthread_once_t tagsLoaded = PTHREAD_ONCE_INIT;
+
+/* Initialize tag by-value and by-name lookup tables */
+static void loadTags(void)
{
- headerTagTableEntry tte, *ip;
- int n = 0;
-
- ip = xcalloc(rpmTagTableSize, sizeof(*ip));
- n = 0;
- for (tte = (headerTagTableEntry)rpmTagTable; tte->name != NULL; tte++) {
- ip[n] = tte;
- n++;
+ for (int i = 0; i < rpmTagTableSize; i++) {
+ tagsByValue[i] = &rpmTagTable[i];
+ tagsByName[i] = &rpmTagTable[i];
}
-assert(n == rpmTagTableSize);
- if (n > 1)
- qsort(ip, n, sizeof(*ip), cmp);
- *ipp = ip;
- *np = n;
- return 0;
+ qsort(tagsByValue, rpmTagTableSize, sizeof(*tagsByValue), tagCmpValue);
+ qsort(tagsByName, rpmTagTableSize, sizeof(*tagsByName), tagCmpName);
}
+static headerTagTableEntry entryByTag(rpmTagVal tag)
+{
+ headerTagTableEntry entry = NULL;
+ int i, comparison;
+ int l = 0;
+ int u = rpmTagTableSize;
-/* forward refs */
-static const char * _tagName(rpmTagVal tag);
-static rpmTagType _tagType(rpmTagVal tag);
-static rpmTagVal _tagValue(const char * tagstr);
+ while (l < u) {
+ i = (l + u) / 2;
+ comparison = (tag - tagsByValue[i]->val);
-static struct headerTagIndices_s _rpmTags = {
- tagLoadIndex,
- NULL, 0, tagCmpName, _tagValue,
- NULL, 0, tagCmpValue, _tagName, _tagType,
-};
+ if (comparison < 0) {
+ u = i;
+ } else if (comparison > 0) {
+ l = i + 1;
+ } else {
+ /* Make sure that the bsearch retrieve is stable. */
+ while (i > 0 && tag == tagsByValue[i-1]->val) {
+ i--;
+ }
+ entry = tagsByValue[i];
+ break;
+ }
+ }
+ return entry;
+}
+
+static headerTagTableEntry entryByName(const char *tag)
+{
+ headerTagTableEntry entry = NULL;
+ int i, comparison;
+ int l = 0;
+ int u = rpmTagTableSize;
-static headerTagIndices const rpmTags = &_rpmTags;
+ while (l < u) {
+ i = (l + u) / 2;
+ comparison = rstrcasecmp(tag, tagsByName[i]->shortname);
-static const char * _tagName(rpmTagVal tag)
+ if (comparison < 0) {
+ u = i;
+ } else if (comparison > 0) {
+ l = i + 1;
+ } else {
+ entry = tagsByName[i];
+ break;
+ }
+ }
+ return entry;
+}
+
+const char * rpmTagGetName(rpmTagVal tag)
{
const char *name = "(unknown)";
const struct headerTagTableEntry_s *t;
- int comparison, i, l, u;
- if (_rpmTags.byValue == NULL)
- tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize, tagCmpValue);
+ pthread_once(&tagsLoaded, loadTags);
switch (tag) {
case RPMDBI_PACKAGES:
@@ -138,119 +145,54 @@ static const char * _tagName(rpmTagVal tag)
break;
default:
- if (_rpmTags.byValue == NULL)
- break;
- l = 0;
- u = _rpmTags.byValueSize;
- while (l < u) {
- i = (l + u) / 2;
- t = _rpmTags.byValue[i];
-
- comparison = (tag - t->val);
-
- if (comparison < 0)
- u = i;
- else if (comparison > 0)
- l = i + 1;
- else {
- /* Make sure that the bsearch retrieve is stable. */
- while (i > 0 && tag == _rpmTags.byValue[i-1]->val) {
- i--;
- }
- t = _rpmTags.byValue[i];
- if (t->shortname != NULL)
- name = t->shortname;
- break;
- }
- }
+ t = entryByTag(tag);
+ if (t && t->shortname)
+ name = t->shortname;
break;
}
return name;
}
-static rpmTagType _tagType(rpmTagVal tag)
+rpmTagType rpmTagGetType(rpmTagVal tag)
{
const struct headerTagTableEntry_s *t;
- int comparison, i, l, u;
-
- if (_rpmTags.byValue == NULL)
- tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize, tagCmpValue);
- if (_rpmTags.byValue) {
- l = 0;
- u = _rpmTags.byValueSize;
- while (l < u) {
- i = (l + u) / 2;
- t = _rpmTags.byValue[i];
-
- comparison = (tag - t->val);
-
- if (comparison < 0)
- u = i;
- else if (comparison > 0)
- l = i + 1;
- else {
- /* Make sure that the bsearch retrieve is stable. */
- while (i > 0 && t->val == _rpmTags.byValue[i-1]->val) {
- i--;
- }
- t = _rpmTags.byValue[i];
- /* XXX this is dumb */
- return (rpmTagType)(t->type | t->retype);
- }
- }
+ rpmTagType tagtype = RPM_NULL_TYPE;
+
+ pthread_once(&tagsLoaded, loadTags);
+
+ t = entryByTag(tag);
+ if (t) {
+ /* XXX this is dumb */
+ tagtype = (rpmTagType)(t->type | t->retype);
}
- return RPM_NULL_TYPE;
+ return tagtype;
}
-static rpmTagVal _tagValue(const char * tagstr)
+rpmTagVal rpmTagGetValue(const char * tagstr)
{
const struct headerTagTableEntry_s *t;
- int comparison, i, l, u;
+ rpmTagType tagval = RPMTAG_NOT_FOUND;
+
+ pthread_once(&tagsLoaded, loadTags);
if (!rstrcasecmp(tagstr, "Packages"))
return RPMDBI_PACKAGES;
- if (_rpmTags.byName == NULL)
- tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
- if (_rpmTags.byName == NULL)
- return RPMTAG_NOT_FOUND;
-
- l = 0;
- u = _rpmTags.byNameSize;
- while (l < u) {
- i = (l + u) / 2;
- t = _rpmTags.byName[i];
+ t = entryByName(tagstr);
+ if (t)
+ tagval = t->val;
- comparison = rstrcasecmp(tagstr, t->shortname);
-
- if (comparison < 0)
- u = i;
- else if (comparison > 0)
- l = i + 1;
- else
- return t->val;
- }
- return RPMTAG_NOT_FOUND;
-}
-
-const char * rpmTagGetName(rpmTagVal tag)
-{
- return ((*rpmTags->tagName)(tag));
-}
-
-rpmTagType rpmTagGetType(rpmTagVal tag)
-{
- return ((*rpmTags->tagType)(tag));
+ return tagval;
}
rpmTagType rpmTagGetTagType(rpmTagVal tag)
{
- return (rpmTagType)((*rpmTags->tagType)(tag) & RPM_MASK_TYPE);
+ return (rpmTagGetType(tag) & RPM_MASK_TYPE);
}
rpmTagReturnType rpmTagGetReturnType(rpmTagVal tag)
{
- return ((*rpmTags->tagType)(tag) & RPM_MASK_RETURN_TYPE);
+ return (rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE);
}
rpmTagClass rpmTagTypeGetClass(rpmTagType type)
@@ -285,30 +227,25 @@ rpmTagClass rpmTagGetClass(rpmTagVal tag)
return rpmTagTypeGetClass(rpmTagGetTagType(tag));
}
-rpmTagVal rpmTagGetValue(const char * tagstr)
-{
- return ((*rpmTags->tagValue)(tagstr));
-}
-
int rpmTagGetNames(rpmtd tagnames, int fullname)
{
const char **names;
const char *name;
- if (_rpmTags.byName == NULL)
- tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
- if (tagnames == NULL ||_rpmTags.byName == NULL)
+ pthread_once(&tagsLoaded, loadTags);
+
+ if (tagnames == NULL || tagsByName == NULL)
return 0;
rpmtdReset(tagnames);
- tagnames->count = _rpmTags.byNameSize;
+ tagnames->count = rpmTagTableSize;
tagnames->data = names = xmalloc(tagnames->count * sizeof(*names));
tagnames->type = RPM_STRING_ARRAY_TYPE;
tagnames->flags = RPMTD_ALLOCED | RPMTD_IMMUTABLE;
for (int i = 0; i < tagnames->count; i++) {
- name = fullname ? _rpmTags.byName[i]->name :
- _rpmTags.byName[i]->shortname;
+ name = fullname ? tagsByName[i]->name :
+ tagsByName[i]->shortname;
names[i] = name;
}
return tagnames->count;
diff --git a/lib/transaction.c b/lib/transaction.c
index fa17d34b7..6af1d1662 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -4,6 +4,9 @@
#include "system.h"
+#include <inttypes.h>
+#include <libgen.h>
+
#include <rpm/rpmlib.h> /* rpmMachineScore, rpmReadPackageFile */
#include <rpm/rpmmacro.h> /* XXX for rpmExpand */
#include <rpm/rpmlog.h>
@@ -11,6 +14,7 @@
#include <rpm/rpmds.h>
#include <rpm/rpmfileutil.h>
#include <rpm/rpmstring.h>
+#include <rpm/rpmsq.h>
#include "lib/fprint.h"
#include "lib/misc.h"
@@ -21,6 +25,7 @@
#include "lib/rpmte_internal.h" /* only internal apis */
#include "lib/rpmts_internal.h"
#include "rpmio/rpmhook.h"
+#include "lib/rpmtriggers.h"
#include "lib/rpmplugins.h"
@@ -63,6 +68,45 @@ struct diskspaceInfo_s {
#define adj_fs_blocks(_nb) (((_nb) * 21) / 20)
#define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
+static char *getMntPoint(const char *dirName, dev_t dev)
+{
+ char mntPoint[PATH_MAX];
+ char *resolved_path = realpath(dirName, mntPoint);
+ char *end = NULL;
+ struct stat sb;
+ char *res = NULL;
+
+ if (!resolved_path) {
+ strncpy(mntPoint, dirName, PATH_MAX);
+ mntPoint[PATH_MAX-1] = '\0';
+ }
+
+ while (end != mntPoint) {
+ end = strrchr(mntPoint, '/');
+ if (end == mntPoint) { /* reached "/" */
+ stat("/", &sb);
+ if (dev != sb.st_dev) {
+ res = xstrdup(mntPoint);
+ } else {
+ res = xstrdup("/");
+ }
+ break;
+ } else if (end) {
+ *end = '\0';
+ } else { /* dirName doesn't start with / - should not happen */
+ res = xstrdup(dirName);
+ break;
+ }
+ stat(mntPoint, &sb);
+ if (dev != sb.st_dev) {
+ *end = '/';
+ res = xstrdup(mntPoint);
+ break;
+ }
+ }
+ return res;
+}
+
static int rpmtsInitDSI(const rpmts ts)
{
if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
@@ -77,8 +121,6 @@ static rpmDiskSpaceInfo rpmtsCreateDSI(const rpmts ts, dev_t dev,
{
rpmDiskSpaceInfo dsi;
struct stat sb;
- char * resolved_path;
- char mntPoint[PATH_MAX];
int rc;
#if STATFS_IN_SYS_STATVFS
@@ -119,11 +161,7 @@ static rpmDiskSpaceInfo rpmtsCreateDSI(const rpmts ts, dev_t dev,
dsi->bneeded = 0;
dsi->ineeded = 0;
#ifdef STATFS_HAS_F_BAVAIL
-# ifdef ST_RDONLY
dsi->bavail = (sfb.f_flag & ST_RDONLY) ? 0 : sfb.f_bavail;
-# else
- dsi->bavail = sfb.f_bavail;
-# endif
#else
/* FIXME: the statfs struct doesn't have a member to tell how many blocks are
* available for non-superusers. f_blocks - f_bfree is probably too big, but
@@ -137,34 +175,16 @@ static rpmDiskSpaceInfo rpmtsCreateDSI(const rpmts ts, dev_t dev,
? sfb.f_ffree : -1;
/* Find mount point belonging to this device number */
- resolved_path = realpath(dirName, mntPoint);
- if (!resolved_path) {
- strncpy(mntPoint, dirName, PATH_MAX);
- mntPoint[PATH_MAX-1] = '\0';
- }
- char * end = NULL;
- while (end != mntPoint) {
- end = strrchr(mntPoint, '/');
- if (end == mntPoint) { /* reached "/" */
- stat("/", &sb);
- if (dsi->dev != sb.st_dev) {
- dsi->mntPoint = xstrdup(mntPoint);
- } else {
- dsi->mntPoint = xstrdup("/");
- }
- break;
- } else if (end) {
- *end = '\0';
- } else { /* dirName doesn't start with / - should not happen */
- dsi->mntPoint = xstrdup(dirName);
- break;
- }
- stat(mntPoint, &sb);
- if (dsi->dev != sb.st_dev) {
- *end = '/';
- dsi->mntPoint = xstrdup(mntPoint);
- break;
- }
+ dsi->mntPoint = getMntPoint(dirName, dsi->dev);
+
+ /* normalize block size to 4096 bytes if it is too big. */
+ if (dsi->bsize > 4096) {
+ uint64_t old_size = dsi->bavail * dsi->bsize;
+ rpmlog(RPMLOG_DEBUG,
+ "dubious blocksize % " PRId64 " on %s, normalizing to 4096\n",
+ dsi->bsize, dsi->mntPoint);
+ dsi->bsize = 4096; /* Assume 4k block size */
+ dsi->bavail = old_size / dsi->bsize;
}
rpmlog(RPMLOG_DEBUG,
@@ -291,17 +311,21 @@ static uint64_t countFiles(rpmts ts)
uint64_t fc = 0;
rpmtsi pi = rpmtsiInit(ts);
rpmte p;
- while ((p = rpmtsiNext(pi, 0)) != NULL)
- fc += rpmfiFC(rpmteFI(p));
+ rpmfiles files;
+ while ((p = rpmtsiNext(pi, 0)) != NULL) {
+ files = rpmteFiles(p);
+ fc += rpmfilesFC(files);
+ rpmfilesFree(files);
+ }
rpmtsiFree(pi);
return fc;
}
-static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx)
+static int handleRemovalConflict(rpmfiles fi, int fx, rpmfiles ofi, int ofx)
{
int rConflicts = 0; /* Removed files don't conflict, normally */
- rpmFileTypes ft = rpmfiWhatis(rpmfiFModeIndex(fi, fx));
- rpmFileTypes oft = rpmfiWhatis(rpmfiFModeIndex(ofi, ofx));
+ rpmFileTypes ft = rpmfiWhatis(rpmfilesFMode(fi, fx));
+ rpmFileTypes oft = rpmfiWhatis(rpmfilesFMode(ofi, ofx));
struct stat sb;
char *fn = NULL;
@@ -312,7 +336,7 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx)
} else if (oft == LINK) {
/* We can't correctly handle directory symlink changing to directory */
if (ft == XDIR) {
- fn = rpmfiFNIndex(fi, fx);
+ fn = rpmfilesFN(fi, fx);
if (stat(fn, &sb) == 0 && S_ISDIR(sb.st_mode))
rConflicts = 1;
}
@@ -324,7 +348,7 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx)
*/
if (rConflicts) {
if (fn == NULL)
- fn = rpmfiFNIndex(fi, fx);
+ fn = rpmfilesFN(fi, fx);
if (lstat(fn, &sb) || rpmfiWhatis(sb.st_mode) == ft)
rConflicts = 0;
}
@@ -342,15 +366,15 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx)
* unnecessary with careful packaging.
*/
static int handleColorConflict(rpmts ts,
- rpmfs fs, rpmfi fi, int fx,
- rpmfs ofs, rpmfi ofi, int ofx)
+ rpmfs fs, rpmfiles fi, int fx,
+ rpmfs ofs, rpmfiles ofi, int ofx)
{
int rConflicts = 1;
rpm_color_t tscolor = rpmtsColor(ts);
if (tscolor != 0) {
- rpm_color_t fcolor = rpmfiFColorIndex(fi, fx) & tscolor;
- rpm_color_t ofcolor = rpmfiFColorIndex(ofi, ofx) & tscolor;
+ rpm_color_t fcolor = rpmfilesFColor(fi, fx) & tscolor;
+ rpm_color_t ofcolor = rpmfilesFColor(ofi, ofx) & tscolor;
if (fcolor != 0 && ofcolor != 0 && fcolor != ofcolor) {
rpm_color_t prefcolor = rpmtsPrefColor(ts);
@@ -377,22 +401,24 @@ static int handleColorConflict(rpmts ts,
* @param ts transaction set
* @param p current transaction element
* @param fi file info set
- * @param shared shared file info
- * @param sharedCount no. of shared elements
- * @param reportConflicts
+ * @param fx file index
+ * @param otherHeader header containing the matching file
+ * @param otherFi matching file info set
+ * @param ofx matching file index
+ * @param beingRemoved file being removed (installed otherwise)
*/
/* XXX only ts->{probs,rpmdb} modified */
-static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, int fx,
- Header otherHeader, rpmfi otherFi, int ofx,
+static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfiles fi, int fx,
+ Header otherHeader, rpmfiles otherFi, int ofx,
int beingRemoved)
{
rpmfs fs = rpmteGetFileStates(p);
- int isCfgFile = ((rpmfiFFlagsIndex(otherFi, ofx) | rpmfiFFlagsIndex(fi, fx)) & RPMFILE_CONFIG);
+ int isCfgFile = ((rpmfilesFFlags(otherFi, ofx) | rpmfilesFFlags(fi, fx)) & RPMFILE_CONFIG);
if (XFA_SKIPPING(rpmfsGetAction(fs, fx)))
return;
- if (rpmfiCompareIndex(otherFi, ofx, fi, fx)) {
+ if (rpmfilesCompare(otherFi, ofx, fi, fx)) {
int rConflicts = 1;
char rState = RPMFILE_STATE_REPLACED;
@@ -421,20 +447,22 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, int fx,
rState = RPMFILE_STATE_WRONGCOLOR;
}
+
if (rConflicts) {
- char *path = rpmfiFNIndex(fi, fx);
+ char *path = rpmfilesFN(fi, fx);
/* Call file conflict hook for all plugins */
rpmpluginsCallFileConflict(ts->plugins, ts, path, otherHeader, otherFi, rConflicts);
}
-
+
/* Somebody used The Force, lets shut up... */
if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) {
rConflicts = 0;
}
+
if (rConflicts) {
char *altNEVR = headerGetAsString(otherHeader, RPMTAG_NEVRA);
- char *fn = rpmfiFNIndex(fi, fx);
+ char *fn = rpmfilesFN(fi, fx);
rpmteAddProblem(p, RPMPROB_FILE_CONFLICT, altNEVR, fn,
headerGetInstance(otherHeader));
free(fn);
@@ -449,34 +477,42 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, int fx,
}
}
- /* Determine config file dispostion, skipping missing files (if any). */
+ /* Determine config file disposition, skipping missing files (if any). */
if (isCfgFile) {
int skipMissing = ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1);
rpmFileAction action;
- action = rpmfiDecideFateIndex(otherFi, ofx, fi, fx, skipMissing);
+ action = rpmfilesDecideFate(otherFi, ofx, fi, fx, skipMissing);
rpmfsSetAction(fs, fx, action);
}
- rpmfiSetFReplacedSizeIndex(fi, fx, rpmfiFSizeIndex(otherFi, ofx));
+
+ /* Skip already existing files - if 'minimize_writes' is set. */
+ if ((!isCfgFile) && (rpmfsGetAction(fs, fx) == FA_UNKNOWN) && ts->min_writes) {
+ if (rpmfileContentsEqual(otherFi, ofx, fi, fx)) {
+ rpmfsSetAction(fs, fx, FA_TOUCH);
+ }
+ }
+
+ rpmfilesSetFReplacedSize(fi, fx, rpmfilesFSize(otherFi, ofx));
}
/**
* Update disk space needs on each partition for this package's files.
*/
/* XXX only ts->{probs,di} modified */
-static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi fi)
+static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfiles fi)
{
rpm_loff_t fixupSize = 0;
int i, j;
rpmfs fs = rpmteGetFileStates(p);
rpmfs otherFs;
- rpm_count_t fc = rpmfiFC(fi);
+ rpm_count_t fc = rpmfilesFC(fi);
int reportConflicts = !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES);
- fingerPrint * fpList = rpmfiFps(fi);
+ fingerPrint * fpList = rpmfilesFps(fi);
for (i = 0; i < fc; i++) {
struct fingerPrint_s * fiFps;
int otherPkgNum, otherFileNum;
- rpmfi otherFi;
+ rpmfiles otherFi;
rpmte otherTe;
rpmfileAttrs FFlags;
struct rpmffi_s * recs;
@@ -485,7 +521,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi
if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
continue;
- FFlags = rpmfiFFlagsIndex(fi, i);
+ FFlags = rpmfilesFFlags(fi, i);
fixupSize = 0;
@@ -513,7 +549,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi
* that were just installed.
* If both this and the other package are being removed, then each
* file removal from preceding packages needs to be skipped so that
- * the file removal occurs only on the last occurence of an overlapped
+ * the file removal occurs only on the last occurrence of an overlapped
* file in the transaction set.
*
*/
@@ -535,7 +571,6 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi
for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
otherTe = recs[otherPkgNum].p;
- otherFi = rpmteFI(otherTe);
otherFileNum = recs[otherPkgNum].fileno;
otherFs = rpmteGetFileStates(otherTe);
@@ -544,8 +579,10 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi
continue;
/* XXX Happens iff fingerprint for incomplete package install. */
- if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN)
+ if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN) {
+ otherFi = rpmteFiles(otherTe);
break;
+ }
}
switch (rpmteType(p)) {
@@ -555,7 +592,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi
rpmFileAction action;
if (rpmfsGetAction(fs, i) != FA_UNKNOWN)
break;
- if (rpmfiConfigConflictIndex(fi, i)) {
+ if (rpmfilesConfigConflict(fi, i)) {
/* Here is a non-overlapped pre-existing config file. */
action = (FFlags & RPMFILE_NOREPLACE) ?
FA_ALTNAME : FA_BACKUP;
@@ -568,7 +605,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi
assert(otherFi != NULL);
/* Mark added overlapped non-identical files as a conflict. */
- if (rpmfiCompareIndex(otherFi, otherFileNum, fi, i)) {
+ if (rpmfilesCompare(otherFi, otherFileNum, fi, i)) {
int rConflicts;
/* If enabled, resolve colored conflicts to preferred type */
@@ -576,7 +613,7 @@ assert(otherFi != NULL);
otherFs, otherFi, otherFileNum);
if (rConflicts && reportConflicts) {
- char *fn = rpmfiFNIndex(fi, i);
+ char *fn = rpmfilesFN(fi, i);
rpmteAddProblem(p, RPMPROB_NEW_FILE_CONFLICT,
rpmteNEVRA(otherTe), fn, 0);
free(fn);
@@ -587,10 +624,13 @@ assert(otherFi != NULL);
if (oaction != FA_UNKNOWN && !XFA_SKIPPING(oaction)) {
rpmfileAttrs oflags;
/* ...but ghosts aren't really created so... */
- oflags = rpmfiFFlagsIndex(otherFi, otherFileNum);
+ oflags = rpmfilesFFlags(otherFi, otherFileNum);
if (!(oflags & RPMFILE_GHOST)) {
rpmfsSetAction(fs, i, FA_SKIP);
}
+ /* if the other file is color skipped then skip this file too */
+ } else if (oaction == FA_SKIPCOLOR) {
+ rpmfsSetAction(fs, i, FA_SKIPCOLOR);
}
}
@@ -599,9 +639,9 @@ assert(otherFi != NULL);
break;
/* Try to get the disk accounting correct even if a conflict. */
- fixupSize = rpmfiFSizeIndex(otherFi, otherFileNum);
+ fixupSize = rpmfilesFSize(otherFi, otherFileNum);
- if (rpmfiConfigConflictIndex(fi, i)) {
+ if (rpmfilesConfigConflict(fi, i)) {
/* Here is an overlapped pre-existing config file. */
rpmFileAction action;
action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SKIP;
@@ -627,12 +667,14 @@ assert(otherFi != NULL);
}
if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
break;
- if (rpmfiFStateIndex(fi, i) != RPMFILE_STATE_NORMAL)
+ if (rpmfilesFState(fi, i) != RPMFILE_STATE_NORMAL) {
+ rpmfsSetAction(fs, i, FA_SKIP);
break;
+ }
/* Pre-existing modified config files need to be saved. */
- if (rpmfiConfigConflictIndex(fi, i)) {
- rpmfsSetAction(fs, i, FA_BACKUP);
+ if (rpmfilesConfigConflict(fi, i)) {
+ rpmfsSetAction(fs, i, FA_SAVE);
break;
}
@@ -640,10 +682,11 @@ assert(otherFi != NULL);
rpmfsSetAction(fs, i, FA_ERASE);
break;
}
+ rpmfilesFree(otherFi);
/* Update disk space info for a file. */
rpmtsUpdateDSI(ts, fpEntryDev(fpc, fiFps), fpEntryDir(fpc, fiFps),
- rpmfiFSizeIndex(fi, i), rpmfiFReplacedSizeIndex(fi, i),
+ rpmfilesFSize(fi, i), rpmfilesFReplacedSize(fi, i),
fixupSize, rpmfsGetAction(fs, i));
}
@@ -654,7 +697,6 @@ assert(otherFi != NULL);
* @param tspool transaction string pool
* @param p current transaction element
* @param h installed header
- * @param ps problem set
*/
static void ensureOlder(rpmstrPool tspool, const rpmte p, const Header h)
{
@@ -677,9 +719,9 @@ static void ensureOlder(rpmstrPool tspool, const rpmte p, const Header h)
* netshardpath and though should be excluded.
* @param ts transaction set
* @param fi file info set
- * @returns pointer to matching path or NULL
+ * @returns 1 if path is net shared path, otherwise 0
*/
-static char ** matchNetsharedpath(const rpmts ts, rpmfi fi)
+static int matchNetsharedpath(const rpmts ts, rpmfi fi)
{
char ** nsp;
const char * dn, * bn;
@@ -717,29 +759,25 @@ static char ** matchNetsharedpath(const rpmts ts, rpmfi fi)
break;
}
- return nsp;
+ return (nsp != NULL && *nsp != NULL);
}
-static void skipEraseFiles(const rpmts ts, rpmte p)
+static void skipEraseFiles(const rpmts ts, rpmfiles files, rpmfs fs)
{
- rpmfi fi = rpmteFI(p);
- rpmfs fs = rpmteGetFileStates(p);
int i;
- char ** nsp;
/*
* Skip net shared paths.
* Net shared paths are not relative to the current root (though
* they do need to take package relocations into account).
*/
if (ts->netsharedPaths) {
- fi = rpmfiInit(fi, 0);
+ rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);
while ((i = rpmfiNext(fi)) >= 0)
{
- nsp = matchNetsharedpath(ts, fi);
- if (nsp && *nsp) {
+ if (matchNetsharedpath(ts, fi))
rpmfsSetAction(fs, i, FA_SKIPNETSHARED);
- }
}
+ rpmfiFree(fi);
}
}
@@ -747,9 +785,10 @@ static void skipEraseFiles(const rpmts ts, rpmte p)
/**
* Skip any files that do not match install policies.
* @param ts transaction set
- * @param fi file info set
+ * @param files file info set
+ * @param fs file states
*/
-static void skipInstallFiles(const rpmts ts, rpmte p)
+static void skipInstallFiles(const rpmts ts, rpmfiles files, rpmfs fs)
{
rpm_color_t tscolor = rpmtsColor(ts);
rpm_color_t FColor;
@@ -759,8 +798,7 @@ static void skipInstallFiles(const rpmts ts, rpmte p)
char * dff;
int dc;
int i, j, ix;
- rpmfi fi = rpmteFI(p);
- rpmfs fs = rpmteGetFileStates(p);
+ rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);
if (!noDocs)
noDocs = rpmExpandNumeric("%{_excludedocs}");
@@ -772,13 +810,13 @@ static void skipInstallFiles(const rpmts ts, rpmte p)
fi = rpmfiInit(fi, 0);
while ((i = rpmfiNext(fi)) >= 0) {
- char ** nsp;
const char *flangs;
ix = rpmfiDX(fi);
drc[ix]++;
/* Don't bother with skipped files */
+ /* XXX FIXME: --excludepath on %license should not be permitted */
if (XFA_SKIPPING(rpmfsGetAction(fs, i))) {
drc[ix]--; dff[ix] = 1;
continue;
@@ -798,8 +836,7 @@ static void skipInstallFiles(const rpmts ts, rpmte p)
* they do need to take package relocations into account).
*/
if (ts->netsharedPaths) {
- nsp = matchNetsharedpath(ts, fi);
- if (nsp && *nsp) {
+ if (matchNetsharedpath(ts, fi)) {
drc[ix]--; dff[ix] = 1;
rpmfsSetAction(fs, i, FA_SKIPNETSHARED);
continue;
@@ -807,6 +844,14 @@ static void skipInstallFiles(const rpmts ts, rpmte p)
}
/*
+ * In general, excluding license files is not permitted. In case
+ * of SKIPNETSHARED and SKIPCOLOR the file is expected to be
+ * there via other means however so that is ok.
+ */
+ if (rpmfiFFlags(fi) & RPMFILE_LICENSE)
+ continue;
+
+ /*
* Skip i18n language specific files.
*/
flangs = (ts->installLangs != NULL) ? rpmfiFLangs(fi) : NULL;
@@ -851,7 +896,8 @@ static void skipInstallFiles(const rpmts ts, rpmte p)
}
/* Skip (now empty) directories that had skipped files. */
- for (j = 0; j < dc; j++) {
+ /* Iterate over dirs in reversed order to solve subdirs at first */
+ for (j = dc - 1; j >= 0; j--) {
const char * dn, * bn;
size_t dnlen, bnlen;
@@ -859,7 +905,7 @@ static void skipInstallFiles(const rpmts ts, rpmte p)
if (!dff[j]) continue; /* dir was not emptied here. */
/* Find parent directory and basename. */
- dn = rpmfiDNIndex(fi, j); dnlen = strlen(dn) - 1;
+ dn = rpmfilesDN(files, j); dnlen = strlen(dn) - 1;
bn = dn + dnlen; bnlen = 0;
while (bn > dn && bn[-1] != '/') {
bnlen++;
@@ -892,12 +938,18 @@ static void skipInstallFiles(const rpmts ts, rpmte p)
continue;
rpmlog(RPMLOG_DEBUG, "excluding directory %s\n", dn);
rpmfsSetAction(fs, i, FA_SKIPNSTATE);
+ ix = rpmfiDX(fi);
+ /* Decrease count of files for parent directory */
+ drc[ix]--;
+ /* Mark directory because something was removed from them */
+ dff[ix] = 1;
break;
}
}
free(drc);
free(dff);
+ rpmfiFree(fi);
}
#undef HASHTYPE
@@ -932,6 +984,7 @@ rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount)
tsMembers tsmem = rpmtsMembers(ts);
rpmstrPool tspool = rpmtsPool(ts);
rpmtsi pi; rpmte p;
+ rpmfiles files;
rpmfi fi;
rpmdbMatchIterator mi;
int oc = 0;
@@ -945,12 +998,13 @@ rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount)
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
- (void) rpmdbCheckSignals();
+ (void) rpmsqPoll();
rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_PROGRESS, oc++, tsmem->orderCount);
/* Gather all installed headers with matching basename's. */
- fi = rpmfiInit(rpmteFI(p), 0);
+ files = rpmteFiles(p);
+ fi = rpmfilesIter(files, RPMFI_ITER_FWD);
while (rpmfiNext(fi) >= 0) {
size_t keylen;
@@ -965,7 +1019,9 @@ rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount)
keylen++; /* XXX "/" fixup. */
rpmdbExtendIterator(mi, baseName, keylen);
rpmStringSetAddEntry(baseNames, baseNameId);
- }
+ }
+ rpmfiFree(fi);
+ rpmfilesFree(files);
}
rpmtsiFree(pi);
rpmStringSetFree(baseNames);
@@ -986,7 +1042,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc)
{
tsMembers tsmem = rpmtsMembers(ts);
rpmte p;
- rpmfi fi;
+ rpmfiles fi;
rpmfs fs;
int j;
unsigned int fileNum;
@@ -1015,15 +1071,15 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc)
fingerPrint *fpp = NULL;
unsigned int installedPkg;
int beingRemoved = 0;
- rpmfi otherFi = NULL;
+ rpmfiles otherFi = NULL;
rpmte *removedPkg = NULL;
/* Is this package being removed? */
installedPkg = rpmdbGetIteratorOffset(mi);
- if (removedHashGetEntry(tsmem->removedPackages, installedPkg,
+ if (packageHashGetEntry(tsmem->removedPackages, installedPkg,
&removedPkg, NULL, NULL)) {
beingRemoved = 1;
- otherFi = rpmfiLink(rpmteFI(removedPkg[0]));
+ otherFi = rpmteFiles(removedPkg[0]);
}
h = headerLink(h);
@@ -1057,7 +1113,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc)
fpLookup(fpc, dirName, baseName, &fpp);
fpIx = 0;
} else {
- fpp = rpmfiFps(otherFi);
+ fpp = rpmfilesFps(otherFi);
fpIx = fileNum;
}
@@ -1066,7 +1122,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc)
for (j = 0; j < numRecs; j++) {
p = recs[j].p;
- fi = rpmteFI(p);
+ fi = rpmteFiles(p);
fs = rpmteGetFileStates(p);
/* Determine the fate of each file. */
@@ -1074,7 +1130,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc)
case TR_ADDED:
if (!otherFi) {
/* XXX What to do if this fails? */
- otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
+ otherFi = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
}
handleInstInstalledFile(ts, p, fi, recs[j].fileno,
h, otherFi, fileNum, beingRemoved);
@@ -1086,13 +1142,14 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc)
}
break;
}
+ rpmfilesFree(fi);
}
newheader = rpmdbNextIterator(mi);
} while (newheader==h);
- otherFi = rpmfiFree(otherFi);
+ otherFi = rpmfilesFree(otherFi);
if (!beingRemoved) {
rpmtdFreeData(&ostates);
rpmtdFreeData(&bnames);
@@ -1146,7 +1203,7 @@ static rpmps checkProblems(rpmts ts)
if (!(probFilter & RPMPROB_FILTER_REPLACEPKG)) {
Header h;
rpmdbMatchIterator mi;
- mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(p), 0);
+ mi = rpmtsPrunedIterator(ts, RPMDBI_NAME, rpmteN(p), 1);
rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(p));
rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(p));
rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(p));
@@ -1180,92 +1237,16 @@ static int runTransScripts(rpmts ts, pkgGoal goal)
int rc = 0;
rpmte p;
rpmtsi pi = rpmtsiInit(ts);
- while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
- rc += rpmteProcess(p, goal);
- }
- rpmtsiFree(pi);
- return rc;
-}
-
-static int rpmtsSetupCollections(rpmts ts)
-{
- /* seenCollectionsPost and TEs are basically a key-value pair. each item in
- * seenCollectionsPost is a collection that has been seen from any package,
- * and the associated index in the TEs is the last transaction element
- * where that collection was seen. */
- ARGV_t seenCollectionsPost = NULL;
- rpmte *TEs = NULL;
- int numSeenPost = 0;
-
- /* seenCollectionsPre is a list of collections that have been seen from
- * only removed packages */
- ARGV_t seenCollectionsPre = NULL;
- int numSeenPre = 0;
-
- ARGV_const_t collname;
- int installing = 1;
- int i;
-
- rpmte p;
- rpmtsi pi = rpmtsiInit(ts);
- while ((p = rpmtsiNext(pi, 0)) != NULL) {
- /* detect when we switch from installing to removing packages, and
- * update the lastInCollectionAdd lists */
- if (installing && rpmteType(p) == TR_REMOVED) {
- installing = 0;
- for (i = 0; i < numSeenPost; i++) {
- rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]);
- }
- }
-
- rpmteSetupCollectionPlugins(p);
-
- for (collname = rpmteCollections(p); collname && *collname; collname++) {
- /* figure out if we've seen this collection in post before */
- for (i = 0; i < numSeenPost && strcmp(*collname, seenCollectionsPost[i]); i++) {
- }
- if (i < numSeenPost) {
- /* we've seen the collection, update the index */
- TEs[i] = p;
- } else {
- /* haven't seen the collection yet, add it */
- argvAdd(&seenCollectionsPost, *collname);
- TEs = xrealloc(TEs, sizeof(*TEs) * (numSeenPost + 1));
- TEs[numSeenPost] = p;
- numSeenPost++;
- }
+ rpmElementTypes types = TR_ADDED;
+ int i = 0;
+ if (goal == PKG_TRANSFILETRIGGERUN)
+ types = TR_REMOVED;
- /* figure out if we've seen this collection in pre remove before */
- if (installing == 0) {
- for (i = 0; i < numSeenPre && strcmp(*collname, seenCollectionsPre[i]); i++) {
- }
- if (i >= numSeenPre) {
- /* haven't seen this collection, add it */
- rpmteAddToFirstInCollectionRemove(p, *collname);
- argvAdd(&seenCollectionsPre, *collname);
- numSeenPre++;
- }
- }
- }
+ while ((p = rpmtsiNext(pi, types)) != NULL) {
+ rc += rpmteProcess(p, goal, i++);
}
rpmtsiFree(pi);
-
- /* we've looked at all the rpmte's, update the lastInCollectionAny lists */
- for (i = 0; i < numSeenPost; i++) {
- rpmteAddToLastInCollectionAny(TEs[i], seenCollectionsPost[i]);
- if (installing == 1) {
- /* lastInCollectionAdd is only updated above if packages were
- * removed. if nothing is removed in the transaction, we need to
- * update that list here */
- rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]);
- }
- }
-
- argvFree(seenCollectionsPost);
- argvFree(seenCollectionsPre);
- _free(TEs);
-
- return 0;
+ return rc;
}
static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet)
@@ -1279,21 +1260,7 @@ static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet)
(void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
if (rpmtsFlags(ts) & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_TEST))
- (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers | RPMTRANS_FLAG_NOCOLLECTIONS));
-
- /* if SELinux isn't enabled or it is a test run, don't bother... */
- if (!is_selinux_enabled() || (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
- rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
- }
-
- if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS) {
- rpmlog(RPMLOG_DEBUG, "Selinux disabled.\n");
- } else {
- if (rpmtsSELabelInit(ts, 1)) {
- rpmlog(RPMLOG_WARNING, "Failed to open SELinux handle.\n");
- rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
- }
- }
+ (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
/*
* Make sure the database is open RDWR for package install/erase.
@@ -1315,9 +1282,6 @@ static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet)
static int rpmtsFinish(rpmts ts)
{
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
- rpmtsSELabelFini(ts, 1);
- }
return rpmChrootSet(NULL);
}
@@ -1326,7 +1290,6 @@ static int rpmtsPrepare(rpmts ts)
tsMembers tsmem = rpmtsMembers(ts);
rpmtsi pi;
rpmte p;
- rpmfi fi;
int rc = 0;
uint64_t fileCount = countFiles(ts);
const char *dbhome = NULL;
@@ -1336,16 +1299,21 @@ static int rpmtsPrepare(rpmts ts)
rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount);
- /* Skip netshared paths, not our i18n files, and excluded docs */
+ /* Reset actions, set skip for netshared paths and excluded files */
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
- if (rpmfiFC(rpmteFI(p)) == 0)
- continue;
- if (rpmteType(p) == TR_ADDED) {
- skipInstallFiles(ts, p);
- } else {
- skipEraseFiles(ts, p);
+ rpmfiles files = rpmteFiles(p);
+ if (rpmfilesFC(files) > 0) {
+ rpmfs fs = rpmteGetFileStates(p);
+ /* Ensure clean state, this could get called more than once. */
+ rpmfsResetActions(fs);
+ if (rpmteType(p) == TR_ADDED) {
+ skipInstallFiles(ts, files, fs);
+ } else {
+ skipEraseFiles(ts, files, fs);
+ }
}
+ rpmfilesFree(files);
}
rpmtsiFree(pi);
@@ -1368,13 +1336,14 @@ static int rpmtsPrepare(rpmts ts)
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
- if ((fi = rpmteFI(p)) == NULL)
+ rpmfiles files = rpmteFiles(p);;
+ if (files == NULL)
continue; /* XXX can't happen */
(void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
/* check files in ts against each other and update disk space
needs on each partition for this package. */
- handleOverlappedFiles(ts, fpc, p, fi);
+ handleOverlappedFiles(ts, fpc, p, files);
/* Check added package has sufficient space on each partition used. */
if (rpmteType(p) == TR_ADDED) {
@@ -1391,6 +1360,7 @@ static int rpmtsPrepare(rpmts ts)
rpmtsCheckDSIProblems(ts, p);
}
(void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
+ rpmfilesFree(files);
}
rpmtsiFree(pi);
rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, tsmem->orderCount);
@@ -1403,7 +1373,7 @@ static int rpmtsPrepare(rpmts ts)
if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))) {
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
- rpmteSetFI(p, NULL);
+ rpmteCleanFiles(p);
}
rpmtsiFree(pi);
}
@@ -1421,6 +1391,7 @@ static int rpmtsProcess(rpmts ts)
{
rpmtsi pi; rpmte p;
int rc = 0;
+ int i = 0;
pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
@@ -1429,49 +1400,114 @@ static int rpmtsProcess(rpmts ts)
rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n",
rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
- if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
- rpmtsSELabelInit(ts, 0);
- }
-
- failed = rpmteProcess(p, rpmteType(p));
+ failed = rpmteProcess(p, rpmteType(p), i++);
if (failed) {
rpmlog(RPMLOG_ERR, "%s: %s %s\n", rpmteNEVRA(p),
rpmteTypeString(p), failed > 1 ? _("skipped") : _("failed"));
rc++;
}
- (void) rpmdbSync(rpmtsGetRdb(ts));
}
rpmtsiFree(pi);
return rc;
}
-static rpmRC rpmtsSetupTransactionPlugins(rpmts ts)
+rpmRC rpmtsSetupTransactionPlugins(rpmts ts)
{
rpmRC rc = RPMRC_OK;
- char *plugins = NULL, *plugin = NULL;
- const char *delims = ",";
-
- plugins = rpmExpand("%{?__transaction_plugins}", NULL);
- if (!plugins || rstreq(plugins, "")) {
- goto exit;
- }
+ ARGV_t files = NULL;
+ int nfiles = 0;
+ char *dsoPath = NULL;
- plugin = strtok(plugins, delims);
- while(plugin != NULL) {
- rpmlog(RPMLOG_DEBUG, "plugin is %s\n", plugin);
- if (!rpmpluginsPluginAdded(ts->plugins, (const char*)plugin)) {
- if (rpmpluginsAddPlugin(ts->plugins, "transaction",
- (const char*)plugin) == RPMRC_FAIL) {
- /* any configured plugin failing to load is a failure */
+ /*
+ * Assume allocated equals initialized. There are some oddball cases
+ * (verification of non-installed package) where this is not true
+ * currently but that's not a new issue.
+ */
+ if ((rpmtsFlags(ts) & RPMTRANS_FLAG_NOPLUGINS) || rpmPluginsGetCount(rpmtsPlugins(ts)) != 0)
+ return RPMRC_OK;
+
+ dsoPath = rpmExpand("%{__plugindir}/*.so", NULL);
+ if (rpmGlob(dsoPath, &nfiles, &files) == 0) {
+ rpmPlugins tsplugins = rpmtsPlugins(ts);
+ for (int i = 0; i < nfiles; i++) {
+ char *bn = basename(files[i]);
+ bn[strlen(bn)-strlen(".so")] = '\0';
+ if (rpmpluginsAddPlugin(tsplugins, "transaction", bn) == RPMRC_FAIL)
+ {
+ /* any configured plugin failing to load is a failure */
// temporally make the loading policy relaxed: no failures
+ //refer to commit id: 3959da1846227711d97c17495aa4779e653a1b3a
//rc = RPMRC_FAIL;
}
}
- plugin = strtok(NULL, delims);
+ files = argvFree(files);
}
+ free(dsoPath);
+
+ return rc;
+}
+/**
+ * Run a scriptlet with args.
+ *
+ * Run a script with an interpreter. If the interpreter is not specified,
+ * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
+ * the header will be ignored, passing instead arg1 and arg2.
+ *
+ * @param ts transaction set
+ * @param te transaction element
+ * @param prefixes install prefixes
+ * @param script scriptlet from header
+ * @param arg1 no. instances of package installed after scriptlet exec
+ * (-1 is no arg)
+ * @param arg2 ditto, but for the target package
+ * @return 0 on success
+ */
+rpmRC runScript(rpmts ts, rpmte te, Header h, ARGV_const_t prefixes,
+ rpmScript script, int arg1, int arg2)
+{
+ rpmte xte = te;
+ rpmRC stoprc, rc = RPMRC_OK;
+ rpmTagVal stag = rpmScriptTag(script);
+ FD_t sfd = NULL;
+ int warn_only = (stag != RPMTAG_PREIN &&
+ stag != RPMTAG_PREUN &&
+ stag != RPMTAG_PRETRANS &&
+ stag != RPMTAG_VERIFYSCRIPT);
+
+ /* Fake up a transaction element for triggers from rpmdb */
+ if (te == NULL) {
+ te = rpmteNew(ts, h, TR_REMOVED, NULL, NULL);
+ rpmteSetHeader(te, h);
+ }
+
+ sfd = rpmtsNotify(ts, te, RPMCALLBACK_SCRIPT_START, stag, 0);
+ if (sfd == NULL)
+ sfd = rpmtsScriptFd(ts);
+
+ rpmswEnter(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0);
+ rc = rpmScriptRun(script, arg1, arg2, sfd,
+ prefixes, warn_only, rpmtsPlugins(ts));
+ rpmswExit(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0);
+
+ /* Map warn-only errors to "notfound" for script stop callback */
+ stoprc = (rc != RPMRC_OK && warn_only) ? RPMRC_NOTFOUND : rc;
+ rpmtsNotify(ts, te, RPMCALLBACK_SCRIPT_STOP, stag, stoprc);
+
+ /*
+ * Notify callback for all errors. "total" abused for warning/error,
+ * rc only reflects whether the condition prevented install/erase
+ * (which is only happens with %prein and %preun scriptlets) or not.
+ */
+ if (rc != RPMRC_OK) {
+ if (warn_only) {
+ rc = RPMRC_OK;
+ }
+ rpmtsNotify(ts, te, RPMCALLBACK_SCRIPT_ERROR, stag, rc);
+ }
+
+ if (te != xte)
+ rpmteFree(te);
-exit:
- free(plugins);
return rc;
}
@@ -1479,9 +1515,11 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
{
int rc = -1; /* assume failure */
tsMembers tsmem = rpmtsMembers(ts);
- rpmlock lock = NULL;
+ rpmtxn txn = NULL;
rpmps tsprobs = NULL;
int TsmPreDone = 0; /* TsmPre hook hasn't been called */
+ /* Ignore SIGPIPE for the duration of transaction */
+ rpmsqAction_t oact = rpmsqSetAction(SIGPIPE, RPMSQ_IGN);
/* Force default 022 umask during transaction for consistent results */
mode_t oldmask = umask(022);
@@ -1494,7 +1532,7 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
/* If we are in test mode, then there's no need for transaction lock. */
if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
- if (!(lock = rpmtsAcquireLock(ts))) {
+ if (!(txn = rpmtxnBegin(ts, RPMTXN_WRITE))) {
goto exit;
}
}
@@ -1504,24 +1542,20 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
goto exit;
}
- if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL) {
- goto exit;
- }
-
- rpmtsSetupCollections(ts);
-
/* Check package set for problems */
tsprobs = checkProblems(ts);
/* Run pre transaction hook for all plugins */
TsmPreDone = 1;
- if (rpmpluginsCallTsmPre(ts->plugins, ts) == RPMRC_FAIL) {
+ if (rpmpluginsCallTsmPre(rpmtsPlugins(ts), ts) == RPMRC_FAIL) {
goto exit;
}
- /* Run pre-transaction scripts, but only if there are no known
- * problems up to this point and not disabled otherwise. */
- if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRE))
+ /* Run %pretrans scripts, but only if there are no known problems up to
+ * this point and not disabled otherwise. This is evil as it runs before
+ * fingerprinting and problem checking and is best avoided.
+ */
+ if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRETRANS))
|| (rpmpsNumProblems(tsprobs)))) {
rpmlog(RPMLOG_DEBUG, "running pre-transaction scripts\n");
runTransScripts(ts, PKG_PRETRANS);
@@ -1553,24 +1587,47 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)))
tsmem->pool = rpmstrPoolFree(tsmem->pool);
+ /* Run %transfiletriggerun scripts unless disabled */
+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRETRANS|
+ RPMTRANS_FLAG_NOTRIGGERUN))) {
+
+ runFileTriggers(ts, NULL, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_TRANSFILETRIGGER, 0);
+ runTransScripts(ts, PKG_TRANSFILETRIGGERUN);
+ }
+
/* Actually install and remove packages, get final exit code */
rc = rpmtsProcess(ts) ? -1 : 0;
- /* Run post-transaction scripts unless disabled */
- if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOST))) {
+ /* Run %posttrans scripts unless disabled */
+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS))) {
rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n");
runTransScripts(ts, PKG_POSTTRANS);
}
+ /* Run %transfiletriggerpostun scripts unless disabled */
+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) {
+ runFileTriggers(ts, NULL, RPMSENSE_TRIGGERIN, RPMSCRIPT_TRANSFILETRIGGER, 0);
+ }
+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) {
+ runPostUnTransFileTrigs(ts);
+ }
+
+ /* Run %transfiletriggerin scripts unless disabled */
+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) {
+ runTransScripts(ts, PKG_TRANSFILETRIGGERIN);
+ }
exit:
/* Run post transaction hook for all plugins */
if (TsmPreDone) /* If TsmPre hook has been called, call the TsmPost hook */
- rpmpluginsCallTsmPost(ts->plugins, ts, rc);
+ rpmpluginsCallTsmPost(rpmtsPlugins(ts), ts, rc);
/* Finish up... */
(void) umask(oldmask);
(void) rpmtsFinish(ts);
rpmpsFree(tsprobs);
- rpmlockFree(lock);
+ rpmtxnEnd(txn);
+ /* Restore SIGPIPE *after* unblocking signals in rpmtxnEnd() */
+ rpmsqSetAction(SIGPIPE, oact);
return rc;
}
diff --git a/lib/verify.c b/lib/verify.c
index 3dcec10f7..5528ba95e 100644
--- a/lib/verify.c
+++ b/lib/verify.c
@@ -53,25 +53,22 @@ static int cap_compare(cap_t acap, cap_t bcap)
}
#endif
-int rpmVerifyFile(const rpmts ts, const rpmfi fi,
- rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
+rpmVerifyAttrs rpmfilesVerify(rpmfiles fi, int ix, rpmVerifyAttrs omitMask)
{
- rpm_mode_t fmode = rpmfiFMode(fi);
- rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
- rpmVerifyAttrs flags = rpmfiVFlags(fi);
- const char * fn = rpmfiFN(fi);
+ rpm_mode_t fmode = rpmfilesFMode(fi, ix);
+ rpmfileAttrs fileAttrs = rpmfilesFFlags(fi, ix);
+ rpmVerifyAttrs flags = rpmfilesVFlags(fi, ix);
+ const char * fn = rpmfilesFN(fi, ix);
struct stat sb;
- int rc;
-
- *res = RPMVERIFY_NONE;
+ rpmVerifyAttrs vfy = RPMVERIFY_NONE;
/*
* Check to see if the file was installed - if not pretend all is OK.
*/
- switch (rpmfiFState(fi)) {
+ switch (rpmfilesFState(fi, ix)) {
case RPMFILE_STATE_NETSHARED:
case RPMFILE_STATE_NOTINSTALLED:
- return 0;
+ goto exit;
break;
case RPMFILE_STATE_REPLACED:
/* For replaced files we can only verify if it exists at all */
@@ -92,8 +89,23 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
}
if (fn == NULL || lstat(fn, &sb) != 0) {
- *res |= RPMVERIFY_LSTATFAIL;
- return 1;
+ vfy |= RPMVERIFY_LSTATFAIL;
+ goto exit;
+ }
+
+ /* If we expected a directory but got a symlink to one, follow the link */
+ if (S_ISDIR(fmode) && S_ISLNK(sb.st_mode)) {
+ struct stat dsb;
+ /* ...if it actually points to a directory */
+ if (stat(fn, &dsb) == 0 && S_ISDIR(dsb.st_mode)) {
+ uid_t fuid;
+ /* ...and is by a legit user, to match fsmVerify() behavior */
+ if (sb.st_uid == 0 ||
+ (rpmugUid(rpmfilesFUser(fi, ix), &fuid) == 0 &&
+ sb.st_uid == fuid)) {
+ sb = dsb; /* struct assignment */
+ }
+ }
}
/* Links have no mode, other types have no linkto */
@@ -122,19 +134,19 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
size_t diglen;
/* XXX If --nomd5, then prelinked library sizes are not corrected. */
- if ((digest = rpmfiFDigest(fi, &algo, &diglen))) {
+ if ((digest = rpmfilesFDigest(fi, ix, &algo, &diglen))) {
unsigned char fdigest[diglen];
rpm_loff_t fsize;
- rc = rpmDoDigest(algo, fn, 0, fdigest, &fsize);
- sb.st_size = fsize;
- if (rc) {
- *res |= (RPMVERIFY_READFAIL|RPMVERIFY_FILEDIGEST);
- } else if (memcmp(fdigest, digest, diglen)) {
- *res |= RPMVERIFY_FILEDIGEST;
+ if (rpmDoDigest(algo, fn, 0, fdigest, &fsize)) {
+ vfy |= (RPMVERIFY_READFAIL|RPMVERIFY_FILEDIGEST);
+ } else {
+ sb.st_size = fsize;
+ if (memcmp(fdigest, digest, diglen))
+ vfy |= RPMVERIFY_FILEDIGEST;
}
} else {
- *res |= RPMVERIFY_FILEDIGEST;
+ vfy |= RPMVERIFY_FILEDIGEST;
}
}
@@ -143,18 +155,18 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
int size = 0;
if ((size = readlink(fn, linkto, sizeof(linkto)-1)) == -1)
- *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
+ vfy |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
else {
- const char * flink = rpmfiFLink(fi);
+ const char * flink = rpmfilesFLink(fi, ix);
linkto[size] = '\0';
if (flink == NULL || !rstreq(linkto, flink))
- *res |= RPMVERIFY_LINKTO;
+ vfy |= RPMVERIFY_LINKTO;
}
}
if (flags & RPMVERIFY_FILESIZE) {
- if (sb.st_size != rpmfiFSize(fi))
- *res |= RPMVERIFY_FILESIZE;
+ if (sb.st_size != rpmfilesFSize(fi, ix))
+ vfy |= RPMVERIFY_FILESIZE;
}
if (flags & RPMVERIFY_MODE) {
@@ -176,7 +188,7 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
}
if (metamode != filemode)
- *res |= RPMVERIFY_MODE;
+ vfy |= RPMVERIFY_MODE;
#if WITH_ACL
/*
@@ -186,7 +198,7 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
acl_t facl = acl_get_file(fn, ACL_TYPE_ACCESS);
if (facl) {
if (acl_equiv_mode(facl, NULL) == 1) {
- *res |= RPMVERIFY_MODE;
+ vfy |= RPMVERIFY_MODE;
}
acl_free(facl);
}
@@ -197,12 +209,12 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
|| S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
{
- *res |= RPMVERIFY_RDEV;
+ vfy |= RPMVERIFY_RDEV;
} else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
rpm_rdev_t st_rdev = (sb.st_rdev & 0xffff);
- rpm_rdev_t frdev = (rpmfiFRdev(fi) & 0xffff);
+ rpm_rdev_t frdev = (rpmfilesFRdev(fi, ix) & 0xffff);
if (st_rdev != frdev)
- *res |= RPMVERIFY_RDEV;
+ vfy |= RPMVERIFY_RDEV;
}
}
@@ -213,7 +225,7 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
* capabilities at all but suffices for now...
*/
cap_t cap, fcap;
- cap = cap_from_text(rpmfiFCaps(fi));
+ cap = cap_from_text(rpmfilesFCaps(fi, ix));
if (!cap) {
cap = cap_from_text("=");
}
@@ -223,32 +235,71 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
}
if (cap_compare(cap, fcap) != 0)
- *res |= RPMVERIFY_CAPS;
+ vfy |= RPMVERIFY_CAPS;
cap_free(fcap);
cap_free(cap);
}
#endif
- if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfiFMtime(fi))) {
- *res |= RPMVERIFY_MTIME;
+ if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfilesFMtime(fi, ix))) {
+ vfy |= RPMVERIFY_MTIME;
}
if (flags & RPMVERIFY_USER) {
const char * name = rpmugUname(sb.st_uid);
- const char * fuser = rpmfiFUser(fi);
- if (name == NULL || fuser == NULL || !rstreq(name, fuser))
- *res |= RPMVERIFY_USER;
+ const char * fuser = rpmfilesFUser(fi, ix);
+ uid_t uid;
+ int namematch = 0;
+ int idmatch = 0;
+
+ if (name && fuser)
+ namematch = rstreq(name, fuser);
+ if (fuser && rpmugUid(fuser, &uid) == 0)
+ idmatch = (uid == sb.st_uid);
+
+ if (namematch != idmatch) {
+ rpmlog(RPMLOG_WARNING,
+ _("Duplicate username or UID for user %s\n"), fuser);
+ }
+
+ if (!(namematch || idmatch))
+ vfy |= RPMVERIFY_USER;
}
if (flags & RPMVERIFY_GROUP) {
const char * name = rpmugGname(sb.st_gid);
- const char * fgroup = rpmfiFGroup(fi);
- if (name == NULL || fgroup == NULL || !rstreq(name, fgroup))
- *res |= RPMVERIFY_GROUP;
+ const char * fgroup = rpmfilesFGroup(fi, ix);
+ gid_t gid;
+ int namematch = 0;
+ int idmatch = 0;
+
+ if (name && fgroup)
+ namematch = rstreq(name, fgroup);
+ if (fgroup && rpmugGid(fgroup, &gid) == 0)
+ idmatch = (gid == sb.st_gid);
+
+ if (namematch != idmatch) {
+ rpmlog(RPMLOG_WARNING,
+ _("Duplicate groupname or GID for group %s\n"), fgroup);
+ }
+
+ if (!(namematch || idmatch))
+ vfy |= RPMVERIFY_GROUP;
}
- return 0;
+exit:
+ return vfy;
+}
+
+int rpmVerifyFile(const rpmts ts, const rpmfi fi,
+ rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
+{
+ rpmVerifyAttrs vfy = rpmfiVerify(fi, omitMask);
+ if (res)
+ *res = vfy;
+
+ return (vfy & RPMVERIFY_LSTATFAIL) ? 1 : 0;
}
/**
@@ -314,7 +365,7 @@ char * rpmVerifyString(uint32_t verifyResult, const char *pad)
char * rpmFFlagsString(uint32_t fflags, const char *pad)
{
char *fmt = NULL;
- rasprintf(&fmt, "%s%s%s%s%s%s%s%s",
+ rasprintf(&fmt, "%s%s%s%s%s%s%s%s%s",
(fflags & RPMFILE_DOC) ? "d" : pad,
(fflags & RPMFILE_CONFIG) ? "c" : pad,
(fflags & RPMFILE_SPECFILE) ? "s" : pad,
@@ -322,22 +373,43 @@ char * rpmFFlagsString(uint32_t fflags, const char *pad)
(fflags & RPMFILE_NOREPLACE) ? "n" : pad,
(fflags & RPMFILE_GHOST) ? "g" : pad,
(fflags & RPMFILE_LICENSE) ? "l" : pad,
- (fflags & RPMFILE_README) ? "r" : pad);
+ (fflags & RPMFILE_README) ? "r" : pad,
+ (fflags & RPMFILE_ARTIFACT) ? "a" : pad);
return fmt;
}
+static const char * stateStr(rpmfileState fstate)
+{
+ switch (fstate) {
+ case RPMFILE_STATE_NORMAL:
+ return NULL;
+ case RPMFILE_STATE_NOTINSTALLED:
+ return rpmIsVerbose() ? _("not installed") : NULL;
+ case RPMFILE_STATE_NETSHARED:
+ return rpmIsVerbose() ? _("net shared") : NULL;
+ case RPMFILE_STATE_WRONGCOLOR:
+ return rpmIsVerbose() ? _("wrong color") : NULL;
+ case RPMFILE_STATE_REPLACED:
+ return _("replaced");
+ case RPMFILE_STATE_MISSING:
+ return _("no state");
+ }
+ return _("unknown state");
+}
+
/**
* Check file info from header against what's actually installed.
* @param ts transaction set
* @param h header to verify
* @param omitMask bits to disable verify checks
- * @param ghosts should ghosts be verified?
+ * @param skipAttr skip files with these attrs (eg %ghost)
* @return 0 no problems, 1 problems found
*/
-static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts)
+static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask,
+ rpmfileAttrs skipAttrs)
{
rpmVerifyAttrs verifyResult = 0;
- int ec = 0; /* assume no problems */
+ rpmVerifyAttrs verifyAll = 0; /* assume no problems */
rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_FLAGS_VERIFY);
if (fi == NULL)
@@ -347,17 +419,17 @@ static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts)
while (rpmfiNext(fi) >= 0) {
rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
char *buf = NULL, *attrFormat;
+ const char *fstate = NULL;
char ac;
- int rc;
- /* If not verifying %ghost, skip ghost files. */
- if ((fileAttrs & RPMFILE_GHOST) && !ghosts)
+ /* Skip on attributes (eg from --noghost) */
+ if (skipAttrs & fileAttrs)
continue;
- rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
+ verifyResult = rpmfiVerify(fi, omitMask);
/* Filter out timestamp differences of shared files */
- if (rc == 0 && (verifyResult & RPMVERIFY_MTIME)) {
+ if (verifyResult & RPMVERIFY_MTIME) {
rpmdbMatchIterator mi;
mi = rpmtsInitIterator(ts, RPMDBI_BASENAMES, rpmfiFN(fi), 0);
if (rpmdbGetIteratorCount(mi) > 1)
@@ -365,9 +437,13 @@ static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts)
rpmdbFreeIterator(mi);
}
+ /* State is only meaningful for installed packages */
+ if (headerGetInstance(h))
+ fstate = stateStr(rpmfiFState(fi));
+
attrFormat = rpmFFlagsString(fileAttrs, "");
ac = rstreq(attrFormat, "") ? ' ' : attrFormat[0];
- if (rc) {
+ if (verifyResult & RPMVERIFY_LSTATFAIL) {
if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
rasprintf(&buf, _("missing %c %s"), ac, rpmfiFN(fi));
if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 &&
@@ -377,25 +453,30 @@ static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts)
rstrcat(&buf, app);
free(app);
}
- ec = rc;
}
- } else if (verifyResult || rpmIsVerbose()) {
+ } else if (verifyResult || fstate || rpmIsVerbose()) {
char *verifyFormat = rpmVerifyString(verifyResult, ".");
rasprintf(&buf, "%s %c %s", verifyFormat, ac, rpmfiFN(fi));
free(verifyFormat);
-
- if (verifyResult) ec = 1;
}
free(attrFormat);
if (buf) {
+ if (fstate)
+ buf = rstrscat(&buf, " (", fstate, ")", NULL);
rpmlog(RPMLOG_NOTICE, "%s\n", buf);
buf = _free(buf);
}
+
+ /* Filter out missing %ghost/%missingok errors from final result */
+ if (fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST))
+ verifyResult &= ~RPMVERIFY_LSTATFAIL;
+
+ verifyAll |= verifyResult;
}
rpmfiFree(fi);
- return ec;
+ return (verifyAll != 0) ? 1 : 0;
}
/**
@@ -440,7 +521,6 @@ static int verifyDependencies(rpmts ts, Header h)
int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
{
rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
- int ghosts = (qva->qva_fflags & RPMFILE_GHOST);
int ec = 0;
int rc;
@@ -449,7 +529,7 @@ int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
ec = rc;
}
if (qva->qva_flags & VERIFY_FILES) {
- if ((rc = verifyHeader(ts, h, omitMask, ghosts)) != 0)
+ if ((rc = verifyHeader(ts, h, omitMask, qva->qva_fflags)) != 0)
ec = rc;
}
if (qva->qva_flags & VERIFY_SCRIPT) {