Blob Blame History Raw
--- 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