[pacman-dev] [PATCH] Restore .pacsave file if present
This patch adds the ability to restore file "foo.pacsave" when installing file "foo". File "foo" is then installed as "foo.pacnew" I really need help with this one. I am a bit wary of this code given it is in one of the most essential parts of pacman. Despite the new pactest failure, I actually had the balls to test this out on my production system... Using the abs package and the /etc/abs.conf.pacsave file is restored and /etc/abs.conf.pacnew is created as expected. TODO: Query users about restore Remove .paccheck from file name in warning about .pacnew creation Figure out why pactest upgrade025 now fails Signed-off-by: Allan McRae <mcrae_allan@hotmail.com> --- lib/libalpm/add.c | 87 ++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 66 insertions(+), 21 deletions(-) diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 3389893..453d5a7 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -333,6 +333,33 @@ static int extract_single_file(struct archive *archive, return(0); } + /* if file does not exist, check for a .pacsave file to restore */ + struct stat lsbuf, sbuf; + int filename_lstat, filename_stat, pacsaverestore = 0; + + char pacsavefile[PATH_MAX]; + snprintf(pacsavefile, PATH_MAX, "%s.pacsave", filename); + + filename_lstat = _alpm_lstat(filename, &lsbuf); + filename_stat = stat(filename, &sbuf); + if(filename_lstat != 0 || filename_stat != 0) { + struct stat pslsbuf; + if(_alpm_lstat(pacsavefile, &pslsbuf) == 0) { + + /* TODO: query or notify about pacsave restore */ + + if(rename(pacsavefile, filename)) { + _alpm_log(PM_LOG_ERROR, _("could not rename %s (%s)\n"), pacsavefile, strerror(errno)); + alpm_logaction("error: could not rename %s (%s)\n", pacsavefile, strerror(errno)); + errors++; + } else { + pacsaverestore = 1; + filename_lstat = _alpm_lstat(filename, &lsbuf); + filename_stat = stat(filename, &sbuf); + } + } + } + /* Check for file existence. This is one of the more crucial parts * to get 'right'. Here are the possibilities, with the filesystem * on the left and the package on the top: @@ -354,8 +381,7 @@ static int extract_single_file(struct archive *archive, */ /* do both a lstat and a stat, so we can see what symlinks point to */ - struct stat lsbuf, sbuf; - if(_alpm_lstat(filename, &lsbuf) != 0 || stat(filename, &sbuf) != 0) { + if(filename_lstat != 0 || filename_stat != 0) { /* cases 1,2,3: couldn't stat an existing file, skip all backup checks */ } else { if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) { @@ -492,31 +518,50 @@ static int extract_single_file(struct archive *archive, if(!oldpkg) { /* looks like we have a local file that has a different hash as the - * file in the package, move it to a .pacorig */ + * file in the package, move it to a .pacorig if it has not been restored + * from a pacsave file, else write the package file to .pacnew */ if(strcmp(hash_local, hash_pkg) != 0) { - char newpath[PATH_MAX]; - snprintf(newpath, PATH_MAX, "%s.pacorig", filename); + if(pacsaverestore == 0) { + char newpath[PATH_MAX]; + snprintf(newpath, PATH_MAX, "%s.pacorig", filename); - /* move the existing file to the "pacorig" */ - if(rename(filename, newpath)) { - _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - filename, newpath, strerror(errno)); - alpm_logaction("error: could not rename %s to %s (%s)\n", - filename, newpath, strerror(errno)); - errors++; - } else { - /* rename the file we extracted to the real name */ - if(rename(checkfile, filename)) { + /* move the existing file to the "pacorig" */ + if(rename(filename, newpath)) { _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - checkfile, filename, strerror(errno)); + filename, newpath, strerror(errno)); alpm_logaction("error: could not rename %s to %s (%s)\n", - checkfile, filename, strerror(errno)); + filename, newpath, strerror(errno)); errors++; } else { - _alpm_log(PM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); - alpm_logaction("warning: %s saved as %s\n", filename, newpath); + /* rename the file we extracted to the real name */ + if(rename(checkfile, filename)) { + _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), + checkfile, filename, strerror(errno)); + alpm_logaction("error: could not rename %s to %s (%s)\n", + checkfile, filename, strerror(errno)); + errors++; + } else { + _alpm_log(PM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); + alpm_logaction("warning: %s saved as %s\n", filename, newpath); + } } - } + } else { /* .pacsave file was restored */ + char newpath[PATH_MAX]; + _alpm_log(PM_LOG_DEBUG, "action: keeping current file and installing" + " new one with .pacnew ending\n"); + snprintf(newpath, PATH_MAX, "%s.pacnew", filename); + if(rename(checkfile, newpath)) { + _alpm_log(PM_LOG_ERROR, _("could not install %s as %s: %s\n"), + checkfile, newpath, strerror(errno)); + alpm_logaction("error: could not install %s as %s: %s\n", + checkfile, newpath, strerror(errno)); + } else { + _alpm_log(PM_LOG_WARNING, _("%s installed as %s\n"), + checkfile, newpath); + alpm_logaction("warning: %s installed as %s\n", + checkfile, newpath); + } + } } } else if(hash_orig) { /* the fun part */ -- 1.5.5.1
Allan McRae wrote:
TODO: Query users about restore Remove .paccheck from file name in warning about .pacnew creation Figure out why pactest upgrade025 now fails
This is the new output of upgrade025 ================================================================================ Running 'upgrade025' Upgrade a package, with a file leaving 'backup' but staying in the pkg -------------------------------------------------------------------------------- ==> Generating test environment ==> Running test ==> Checking rules [ OK ] PKG_VERSION=dummy|1.0-2 [FAIL] FILE_PACSAVE=etc/dummy.conf [ OK ] !FILE_PACNEW=etc/dummy.conf [ OK ] FILE_EXIST=etc/dummy.conf ==> Test result FAIL So I broke something to do with pacsave files, which may be expected...
Allan McRae wrote:
This patch adds the ability to restore file "foo.pacsave" when installing file "foo". File "foo" is then installed as "foo.pacnew"
I really need help with this one. I am a bit wary of this code given it is in one of the most essential parts of pacman. Despite the new pactest failure, I actually had the balls to test this out on my production system... Using the abs package and the /etc/abs.conf.pacsave file is restored and /etc/abs.conf.pacnew is created as expected.
This feature looks nice, but the problem is that the whole backup handling code is really messy, with non obvious interactions in conflict.c, remove.c and add.c and ugly hacks. I probably even made the code worse when trying to do quick fixes for 3.1 releases. And no work has been done for cleaning that since then.
participants (2)
-
Allan McRae
-
Xavier