--- ./lib/backend/bdb_ro.c.orig 2020-03-24 20:45:19.121907476 +0000 +++ ./lib/backend/bdb_ro.c 2020-03-24 20:46:17.141727988 +0000 @@ -795,6 +795,7 @@ static unsigned int bdbro_pkgdbKey(dbiIn struct rpmdbOps_s bdbro_dbops = { .name = "bdb_ro", .path = "Packages", + .readonly = 1, .open = bdbro_Open, .close = bdbro_Close, --- ./lib/backend/dbi.c.orig 2020-03-24 20:45:19.121907476 +0000 +++ ./lib/backend/dbi.c 2020-03-24 20:46:17.141727988 +0000 @@ -105,11 +105,20 @@ dbDetectBackend(rpmdb rdb) } rdb->db_descr = rdb->db_ops->name; + rdb->db_ops_config = ops_config; if (db_backend) free(db_backend); } +int dbiNeedConversion(rpmdb rdb) +{ + if (!rdb->db_ops) + dbDetectBackend(rdb); + return rdb->db_ops->readonly && rdb->db_ops_config + && rdb->db_ops_config->path && !rdb->db_ops_config->readonly; +} + const char * dbiName(dbiIndex dbi) { return dbi->dbi_file; --- ./lib/backend/dbi.h.orig 2020-03-24 20:45:19.121907476 +0000 +++ ./lib/backend/dbi.h 2020-03-24 20:46:17.141727988 +0000 @@ -10,6 +10,7 @@ enum rpmdbFlags { RPMDB_FLAG_JUSTCHECK = (1 << 0), RPMDB_FLAG_REBUILD = (1 << 1), RPMDB_FLAG_VERIFYONLY = (1 << 2), + RPMDB_FLAG_CONVERT = (1 << 3), }; typedef enum dbCtrlOp_e { @@ -62,6 +63,7 @@ struct rpmdb_s { int db_buildindex; /*!< Index rebuild indicator */ const struct rpmdbOps_s * db_ops; /*!< backend ops */ + const struct rpmdbOps_s * db_ops_config; /*!< configured backend ops */ /* dbenv and related parameters */ void * db_dbenv; /*!< Backend private handle */ @@ -201,6 +203,14 @@ RPM_GNUC_INTERNAL const char * dbiName(dbiIndex dbi); /** \ingroup dbi + * Check if the database needs to be converted to a different format + * @param db rpm database + * @return boolean + */ +RPM_GNUC_INTERNAL +int dbiNeedConversion(rpmdb rdb); + +/** \ingroup dbi * Open a database cursor. * @param dbi index database handle * @param flags DBC_WRITE if writing, or 0 (DBC_READ) for reading @@ -246,6 +256,7 @@ const void * idxdbKey(dbiIndex dbi, dbiC struct rpmdbOps_s { const char *name; /* backend name */ const char *path; /* main database name */ + int readonly; /* cannot modify database */ int (*open)(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags); int (*close)(dbiIndex dbi, unsigned int flags); --- ./lib/rpmdb.c.orig 2020-03-24 20:45:19.117907488 +0000 +++ ./lib/rpmdb.c 2020-03-24 21:01:54.870821518 +0000 @@ -513,8 +513,16 @@ static int openDatabase(const char * pre rpmsqActivate(1); } + /* Convert the database if needed */ + if (!db->db_pkgs && !justCheck && (mode & O_ACCMODE) == O_RDWR && dbiNeedConversion(db)) { + rpmlog(RPMLOG_WARNING, _("Converting database from %s to %s format\n"), db->db_ops->name, db->db_ops_config->name); + rc = rpmdbRebuild(prefix, NULL, NULL, RPMDB_FLAG_CONVERT); + db->db_ops = NULL; /* force re-detection of backend */ + } + /* Just the primary Packages database opened here */ - rc = pkgdbOpen(db, db->db_flags, NULL); + if (!rc) + rc = pkgdbOpen(db, db->db_flags, NULL); if (!db->db_descr) db->db_descr = "unknown db"; } @@ -2316,6 +2324,15 @@ int rpmdbAdd(rpmdb db, Header h) if (db == NULL) return 0; + if ((db->db_flags & RPMDB_FLAG_CONVERT) != 0) { + /* keep old instance numbers when converting */ + hdrNum = headerGetInstance(h); + if (hdrNum == 0) { + ret = -1; + goto exit; + } + } + hdrBlob = headerExport(h, &hdrLen); if (hdrBlob == NULL || hdrLen == 0) { ret = -1; @@ -2331,7 +2348,8 @@ int rpmdbAdd(rpmdb db, Header h) /* Add header to primary index */ dbc = dbiCursorInit(dbi, DBC_WRITE); - ret = pkgdbNew(dbi, dbc, &hdrNum); + if ((db->db_flags & RPMDB_FLAG_CONVERT) == 0) + ret = pkgdbNew(dbi, dbc, &hdrNum); if (ret == 0) ret = pkgdbPut(dbi, dbc, hdrNum, hdrBlob, hdrLen); dbiCursorFree(dbi, dbc); @@ -2491,7 +2509,8 @@ static int rpmdbSetPermissions(char * sr } int rpmdbRebuild(const char * prefix, rpmts ts, - rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg)) + rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg), + int newdbflags) { rpmdb olddb; char * dbpath = NULL; @@ -2512,7 +2531,22 @@ int rpmdbRebuild(const char * prefix, rp } rootdbpath = rpmGetPath(prefix, dbpath, NULL); - newdbpath = rpmGetPath("%{?_dbpath_rebuild}", NULL); + if ((newdbflags & RPMDB_FLAG_CONVERT) != 0) { + char lbuf[PATH_MAX]; + ssize_t s = readlink(rootdbpath, lbuf, PATH_MAX); + if (s > 0 && s < PATH_MAX) { + lbuf[s] = 0; + free(dbpath); + if (lbuf[0] == '/') + dbpath = strdup(lbuf); + else + dbpath = rpmGetPath("%{?_dbpath}", "/../", lbuf, NULL); + free(rootdbpath); + rootdbpath = rpmGetPath(prefix, dbpath, NULL); + } + newdbpath = strdup(""); + } else + newdbpath = rpmGetPath("%{?_dbpath_rebuild}", NULL); if (rstreq(newdbpath, "") || rstreq(newdbpath, dbpath)) { newdbpath = _free(newdbpath); rasprintf(&newdbpath, "%srebuilddb.%d", dbpath, (int) getpid()); @@ -2536,7 +2570,7 @@ int rpmdbRebuild(const char * prefix, rp goto exit; } if (openDatabase(prefix, newdbpath, &newdb, - (O_RDWR | O_CREAT), 0644, RPMDB_FLAG_REBUILD)) { + (O_RDWR | O_CREAT), 0644, RPMDB_FLAG_REBUILD | newdbflags)) { rc = 1; goto exit; } --- ./lib/rpmdb_internal.h.orig 2019-06-26 14:17:31.412985694 +0000 +++ ./lib/rpmdb_internal.h 2020-03-24 20:46:17.141727988 +0000 @@ -63,11 +63,13 @@ int rpmdbClose (rpmdb db); * @param prefix path to top of install tree * @param ts transaction set (or NULL) * @param (*hdrchk) headerCheck() vector (or NULL) + * @param newdbflags extra flags for the new database * @return 0 on success */ RPM_GNUC_INTERNAL int rpmdbRebuild(const char * prefix, rpmts ts, - rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg)); + rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg), + int newdbflags); /** \ingroup rpmdb * Verify database components. --- ./lib/rpmts.c.orig 2020-03-24 20:45:19.105907526 +0000 +++ ./lib/rpmts.c 2020-03-24 20:46:17.145727976 +0000 @@ -143,9 +143,9 @@ int rpmtsRebuildDB(rpmts ts) txn = rpmtxnBegin(ts, RPMTXN_WRITE); if (txn) { if (!(ts->vsflags & RPMVSF_NOHDRCHK)) - rc = rpmdbRebuild(ts->rootDir, ts, headerCheck); + rc = rpmdbRebuild(ts->rootDir, ts, headerCheck, 0); else - rc = rpmdbRebuild(ts->rootDir, NULL, NULL); + rc = rpmdbRebuild(ts->rootDir, NULL, NULL, 0); rpmtxnEnd(txn); } return rc;