From: Ivy Foster <[email protected]>

Closes #46107

Signed-off-by: Ivy Foster <[email protected]>
---
 lib/libalpm/alpm.h    |  1 +
 lib/libalpm/be_sync.c | 26 +++++++++++++++++++++++++-
 lib/libalpm/error.c   |  2 ++
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 168d71b..0dd68a7 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -75,6 +75,7 @@ typedef enum _alpm_errno_t {
        ALPM_ERR_DB_VERSION,
        ALPM_ERR_DB_WRITE,
        ALPM_ERR_DB_REMOVE,
+       ALPM_ERR_DB_BACKUP,
        /* Servers */
        ALPM_ERR_SERVER_BAD_URL,
        ALPM_ERR_SERVER_NONE,
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
index 32a669d..ee438f8 100644
--- a/lib/libalpm/be_sync.c
+++ b/lib/libalpm/be_sync.c
@@ -182,6 +182,9 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
        mode_t oldmask;
        alpm_handle_t *handle;
        alpm_siglevel_t level;
+       char *newdb;
+       char *olddb;
+       size_t len;
 
        /* Sanity checks */
        ASSERT(db != NULL, return -1);
@@ -218,10 +221,23 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
 
        dbext = db->handle->dbext;
 
+       len = strlen(syncpath) + strlen(db->treename) + strlen(dbext) + 2;
+       /* TODO fix leak syncpath and umask unset */
+       MALLOC(newdb, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
+       snprintf(newdb, len, "%s/%s%s", syncpath, db->treename, dbext);
+       len += 4;
+       /* TODO fix leak syncpath and umask unset */
+       MALLOC(olddb, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
+       snprintf(olddb, len, "%s.bak", newdb);
+       if (rename(newdb, olddb) == -1) {
+               ret = -1;
+               handle->pm_errno = ALPM_ERR_DB_BACKUP;
+               goto cleanup;
+       }
+
        for(i = db->servers; i; i = i->next) {
                const char *server = i->data, *final_db_url = NULL;
                struct dload_payload payload;
-               size_t len;
                int sig_ret = 0;
 
                memset(&payload, 0, sizeof(struct dload_payload));
@@ -315,15 +331,23 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
                }
        }
 
+cleanup:
        if(ret == -1) {
                /* pm_errno was set by the download code */
                _alpm_log(handle, ALPM_LOG_DEBUG, "failed to sync db: %s\n",
                                alpm_strerror(handle->pm_errno));
+               if (handle->pm_errno != ALPM_ERR_DB_BACKUP && rename(olddb, 
newdb) == -1) {
+                       _alpm_log(handle, ALPM_LOG_DEBUG, "failed to replace 
original db: %s\n",
+                                       alpm_strerror(ALPM_ERR_DB_BACKUP));
+               }
        } else {
+               unlink(olddb);
                handle->pm_errno = 0;
        }
 
        _alpm_handle_unlock(handle);
+       free(newdb);
+       free(olddb);
        free(syncpath);
        umask(oldmask);
        return ret;
diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c
index 2d6d071..e707d43 100644
--- a/lib/libalpm/error.c
+++ b/lib/libalpm/error.c
@@ -78,6 +78,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
                        return _("could not update database");
                case ALPM_ERR_DB_REMOVE:
                        return _("could not remove database entry");
+               case ALPM_ERR_DB_BACKUP:
+                       return _("could not back up old database");
                /* Servers */
                case ALPM_ERR_SERVER_BAD_URL:
                        return _("invalid url for server");
-- 
2.9.3

Reply via email to