--- ./lib/backend/bdb_ro.c.orig 2020-05-28 10:04:25.027136631 +0000 +++ ./lib/backend/bdb_ro.c 2021-01-07 15:24:08.866776792 +0000 @@ -790,6 +790,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-08-31 09:14:07.991087349 +0000 +++ ./lib/backend/dbi.c 2021-01-07 15:24:08.866776792 +0000 @@ -119,11 +119,20 @@ exit: } rdb->db_descr = rdb->db_ops->name; + rdb->db_ops_config = cfg; 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 2021-01-07 15:23:56.122812108 +0000 +++ ./lib/backend/dbi.h 2021-01-07 15:24:08.866776792 +0000 @@ -11,6 +11,7 @@ enum rpmdbFlags { RPMDB_FLAG_REBUILD = (1 << 1), RPMDB_FLAG_VERIFYONLY = (1 << 2), RPMDB_FLAG_SALVAGE = (1 << 3), + RPMDB_FLAG_CONVERT = (1 << 4), }; typedef enum dbCtrlOp_e { @@ -63,6 +64,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 */ @@ -209,6 +211,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 @@ -252,6 +262,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/backend/ndb/rpmpkg.c.orig 2021-01-07 15:24:37.266698082 +0000 +++ ./lib/backend/ndb/rpmpkg.c 2021-01-07 15:27:46.678173133 +0000 @@ -1116,11 +1116,12 @@ static int rpmpkgPutInternal(rpmpkgdb pk if (rpmpkgWriteBlob(pkgdb, pkgidx, blkoff, blkcnt, blob, blobl, pkgdb->generation)) { return RPMRC_FAIL; } + /* update nextpkgidx if needed */ + if (pkgidx >= pkgdb->nextpkgidx) { + pkgdb->nextpkgidx = pkgidx + 1; + } /* 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; --- ./lib/rpmdb.c.orig 2021-01-07 15:23:56.122812108 +0000 +++ ./lib/rpmdb.c 2021-01-07 15:24:08.866776792 +0000 @@ -516,7 +516,13 @@ static int openDatabase(const char * pre rpmsqActivate(1); } - rc = doOpen(db, justPkgs); + if (!db->db_pkgs && !justCheck && (mode & O_ACCMODE) == O_RDWR && dbiNeedConversion(db)) { + rc = rpmdbRebuild(prefix, NULL, NULL, RPMDB_REBUILD_FLAG_CONVERT); + db->db_ops = NULL; /* force re-detection of backend */ + } + + if (!rc) + rc = doOpen(db, justPkgs); if (!db->db_descr) db->db_descr = "unknown db"; @@ -2311,6 +2317,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; @@ -2506,7 +2521,22 @@ int rpmdbRebuild(const char * prefix, rp } rootdbpath = rpmGetPath(prefix, dbpath, NULL); - newdbpath = rpmGetPath("%{?_dbpath_rebuild}", NULL); + if ((rebuildflags & RPMDB_REBUILD_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()); @@ -2532,7 +2562,9 @@ 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 | + (rebuildflags & RPMDB_REBUILD_FLAG_CONVERT ? + RPMDB_FLAG_CONVERT : 0))) { rc = 1; goto exit; } --- ./lib/rpmdb_internal.h.orig 2020-05-28 10:04:25.037136686 +0000 +++ ./lib/rpmdb_internal.h 2021-01-07 15:24:08.866776792 +0000 @@ -25,6 +25,7 @@ extern "C" { enum rpmdbRebuildFlags_e { RPMDB_REBUILD_FLAG_SALVAGE = (1 << 0), + RPMDB_REBUILD_FLAG_CONVERT = (1 << 1), }; /** \ingroup rpmdb