--- lib/backend/bdb_ro.c.orig 2022-04-07 11:13:18.994517848 +0000 +++ lib/backend/bdb_ro.c 2022-12-02 13:22:16.726408071 +0000 @@ -793,6 +793,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 2022-04-07 11:13:18.994517848 +0000 +++ lib/backend/dbi.c 2022-12-02 13:22:16.726408071 +0000 @@ -138,11 +138,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 2022-04-07 11:13:18.994517848 +0000 +++ lib/backend/dbi.h 2022-12-02 13:22:16.726408071 +0000 @@ -13,6 +13,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 { @@ -53,6 +54,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 */ @@ -197,6 +199,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 @@ -240,6 +250,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 2022-04-07 11:13:18.997517869 +0000 +++ lib/backend/ndb/rpmpkg.c 2022-12-02 13:22:16.726408071 +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 2022-09-20 12:08:27.197920294 +0000 +++ lib/rpmdb.c 2022-12-02 13:24:02.830159868 +0000 @@ -469,7 +469,12 @@ static int openDatabase(const char * pre /* Open just bare minimum when rebuilding a potentially damaged db */ int justPkgs = (db->db_flags & RPMDB_FLAG_REBUILD) && ((db->db_mode & O_ACCMODE) == O_RDONLY); - 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"; @@ -2228,6 +2233,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; @@ -2423,7 +2437,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()); @@ -2449,7 +2478,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 2022-04-07 11:13:19.014517984 +0000 +++ lib/rpmdb_internal.h 2022-12-02 13:22:16.726408071 +0000 @@ -25,6 +25,7 @@ extern "C" { enum rpmdbRebuildFlags_e { RPMDB_REBUILD_FLAG_SALVAGE = (1 << 0), + RPMDB_REBUILD_FLAG_CONVERT = (1 << 1), }; /** \ingroup rpmdb