--- /dev/null
+#include <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h> /* for mkdir(2) !?! */
+#include <unistd.h>
+
+#include "messages.h"
+#include "rpmdb.h"
+#include "rpmerr.h"
+#include "rpmlib.h"
+
+int rpmdbRebuild(char * rootdir) {
+ rpmdb olddb, newdb;
+ char * dbpath, * newdbpath;
+ unsigned int recnum;
+ Header h;
+ int failed = 0;
+
+ message(MESS_DEBUG, "rebuilding database in rootdir %s\n", rootdir);
+
+ dbpath = getVar(RPMVAR_DBPATH);
+ if (!dbpath) {
+ message(MESS_DEBUG, "no dbpath has been set");
+ return 1;
+ }
+
+ newdbpath = alloca(strlen(dbpath) + 50 + strlen(rootdir));
+ sprintf(newdbpath, "%s/%s/rebuilddb.%d", rootdir, dbpath, getpid());
+
+ if (!access(newdbpath, F_OK)) {
+ error(RPMERR_MKDIR, "temporary database %s already exists",
+ newdbpath);
+ }
+
+ message(MESS_DEBUG, "creating directory: %s\n", newdbpath);
+ if (mkdir(newdbpath, 0755)) {
+ error(RPMERR_MKDIR, "error creating directory %s: %s",
+ newdbpath, strerror(errno));
+ }
+
+ sprintf(newdbpath, "%s/rebuilddb.%d", dbpath, getpid());
+
+ message(MESS_DEBUG, "opening old database\n");
+ if (openDatabase(rootdir, dbpath, &olddb, O_RDONLY, 0644, 0)) {
+ return 1;
+ }
+
+ message(MESS_DEBUG, "opening new database\n");
+ if (openDatabase(rootdir, newdbpath, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
+ return 1;
+ }
+
+ recnum = rpmdbFirstRecNum(olddb);
+ while (recnum) {
+ if (!(h = rpmdbGetRecord(olddb, recnum))) {
+ error(RPMERR_INTERNAL, "cannot read database record at %d", recnum);
+ failed = 1;
+ break;
+ }
+ if (rpmdbAdd(newdb, h)) {
+ error(RPMERR_INTERNAL, "cannot add record originally at %d",
+ recnum);
+ failed = 1;
+ break;
+ }
+ recnum = rpmdbNextRecNum(olddb, recnum);
+ }
+
+ rpmdbClose(olddb);
+ rpmdbClose(newdb);
+
+ if (failed) {
+ message(MESS_NORMAL, "failed to rebuild database; original database "
+ "remains in place\n");
+
+ rpmdbRemoveDatabase(rootdir, newdbpath);
+ return 1;
+ } else {
+ if (rpmdbMoveDatabase(rootdir, newdbpath, dbpath)) {
+ message(MESS_ERROR, "failed to replace old database with new "
+ "database!\n");
+ message(MESS_ERROR, "replaces files in %s with files from %s "
+ "to recover", dbpath, newdbpath);
+ return 1;
+ }
+ rmdir(newdbpath);
+ }
+
+
+ return 0;
+}
--- /dev/null
+#ifndef H_RPMDB
+#define H_RPMDB
+
+#include "rpmlib.h"
+
+/* for RPM's internal use only */
+
+int openDatabase(char * prefix, char * dbpath, rpmdb *rpmdbp, int mode,
+ int perms, int justcheck);
+int rpmdbRemove(rpmdb db, unsigned int offset, int tolerant);
+int rpmdbAdd(rpmdb db, Header dbentry);
+int rpmdbUpdateRecord(rpmdb db, int secOffset, Header secHeader);
+void rpmdbRemoveDatabase(char * rootdir, char * dbpath);
+int rpmdbMoveDatabase(char * rootdir, char * olddbpath, char * newdbpath);
+
+#endif