[pacman-dev] [PATCH] Save backup files with extension .pacsave.timestamp

Pang Yan Han pangyanhan at gmail.com
Fri Jul 29 03:03:03 EDT 2011


Teach pacman to save backup files using extension of .pacsave.timestamp
"timestamp" is the time of removal of the backup file. It is in
<year>-<month>-<day>-<HHMMSS> format, where:

- year is either the year with century or a 2 digit number from 00 to 99 (year
  without century) if the timestamp string exceeds 20 characters
- month is a 2 digit number from 01 to 12
- day is a 2 digit number from 01 to 31
- HH is a 2 digit number from 00 to 23 representing the hour
- MM and SS are 2 digit numbers from 00 to 59 representing minutes and seconds
  respectively

An example of such a pacsave file is /etc/pacman.conf.pacsave.2011-07-29-145035

This addresses FS#24192 (pacman overwrites .pacsave files)

FILE_PACSAVE rule for the test suite is updated to reflect the change in
.pacsave file extension. FILE_PACSAVE rules can be used as per before this patch.

Signed-off-by: Pang Yan Han <pangyanhan at gmail.com>
---
 doc/pacman.8.txt      |   13 ++++++++++++-
 lib/libalpm/remove.c  |   20 ++++++++++++++++++--
 test/pacman/pmrule.py |   21 +++++++++++++++++++--
 3 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index 64b1ff3..d029294 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -54,8 +54,19 @@ Operations
 	removed, in which case every package in that group will be removed.
 	Files belonging to the specified package will be deleted, and the
 	database will be updated. Most configuration files will be saved
-	with a '.pacsave' extension unless the '\--nosave' option is used.
+	with a '.pacsave-<timestamp>' extension unless the '\--nosave' option is used.
 	See <<RO,Remove Options>> below.
++
+'<timestamp>' is the time of removal of the configuration file. It is in
+<year>-<month>-<day>-<HHMMSS> format, where:
++
+	- year is either the year with century or a 2 digit number from 00 to 99
+	  (year without century) if the string exceeds 20 characters
+	- month is a 2 digit number from 01 to 12
+	- day is a 2 digit number from 01 to 31
+	- HH is a 2 digit number from 00 to 23 representing the hour
+	- MM and SS are 2 digit numbers from 00 to 59 representing minutes and seconds
+	  respectively
 
 *-S, \--sync*::
 	Synchronize packages. Packages are installed directly from the ftp
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index 83c437f..a39a154 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
+#include <time.h>
 #include <limits.h>
 #include <unistd.h>
 #include <sys/stat.h>
@@ -287,7 +288,8 @@ static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,
 			}
 		}
 	} else {
-		/* if the file needs backup and has been modified, back it up to .pacsave */
+		/* if the file needs backup and has been modified, back it up to
+		 * .pacsave.YYYY-MM-DD-HHMMSS */
 		alpm_backup_t *backup = _alpm_needbackup(fileobj->name, info);
 		if(backup) {
 			if(nosave) {
@@ -298,7 +300,21 @@ static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,
 				FREE(filehash);
 				if(cmp != 0) {
 					char newpath[PATH_MAX];
-					snprintf(newpath, PATH_MAX, "%s.pacsave", file);
+					char timestr[21];
+					time_t curtime;
+					struct tm tm;
+					size_t ret;
+
+					curtime = time(NULL);
+					localtime_r(&curtime, &tm);
+					ret = strftime(timestr, 21, "%Y-%m-%d-%H%M%S", &tm);
+					if (ret == 0) {
+						/* Year with century can't fit.
+						 * So we print year without century (00 to 99) */
+						strftime(timestr, 21, "%y-%m-%d-%H%M%S", &tm);
+					}
+
+					snprintf(newpath, PATH_MAX, "%s.pacsave.%s", file, timestr);
 					rename(file, newpath);
 					_alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), file, newpath);
 					alpm_logaction(handle, "warning: %s saved as %s\n", file, newpath);
diff --git a/test/pacman/pmrule.py b/test/pacman/pmrule.py
index cb7ae88..44cee8a 100644
--- a/test/pacman/pmrule.py
+++ b/test/pacman/pmrule.py
@@ -17,6 +17,7 @@
 
 import os
 import stat
+import re
 
 import util
 
@@ -141,8 +142,24 @@ def check(self, test):
                 if not os.path.isfile("%s.pacorig" % filename):
                     success = 0
             elif case == "PACSAVE":
-                if not os.path.isfile("%s.pacsave" % filename):
-                    success = 0
+                # pacsave.YYYY-MM-DD-HHMMSS
+                saved_re = re.compile(filename + ".pacsave." + "\d{2,}-\d{2}-\d{2}-\d{6}")
+
+                # Extract directory component of pacsave file
+                dir_ = ""
+                dir_re = re.compile('(.*)/[^/]*')
+                dir_match = dir_re.match(filename)
+                if dir_match is not None:
+                    dir_ = dir_match.group(1)
+                dir_ = os.path.join(test.root, dir_)
+
+                success = 0
+                files = os.listdir(dir_)
+                for f in files:
+                    fullname = os.path.join(dir_, f)
+                    if saved_re.match(fullname):
+                        success = 1
+                        break
             else:
                 print "FILE rule '%s' not found" % case
                 success = -1
-- 
1.7.6.178.g55272



More information about the pacman-dev mailing list