[pacman-dev] [PATCH] Restore .pacsave file if present

Allan McRae mcrae_allan at hotmail.com
Sat May 10 11:15:24 EDT 2008


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 at 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





More information about the pacman-dev mailing list