[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH 3/4] dpkg: (I)nstall conffile: split rename into link + unlink



Split up the rename(<conffile>.dpkg-new, <conffile>) into

	link(<conffile>.dpkg-new, <conffile>);
	unlink(<conffile>.dpkg-new);

in preparation for an operation in between.  Since link() does
not actually atomically replace its target, we must simulate it
by linking to a temporary file and then renaming into place.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 lib/dpkg/dpkg.h |    1 +
 src/configure.c |   24 +++++++++++++++++++-----
 src/remove.c    |    7 ++++++-
 3 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/lib/dpkg/dpkg.h b/lib/dpkg/dpkg.h
index 78a2fe6..97b1e0b 100644
--- a/lib/dpkg/dpkg.h
+++ b/lib/dpkg/dpkg.h
@@ -57,6 +57,7 @@ DPKG_BEGIN_DECLS
 #define DPKGNEWEXT         ".dpkg-new"
 #define DPKGOLDEXT         ".dpkg-old"
 #define DPKGDISTEXT        ".dpkg-dist"
+#define DPKGLINKEXT        ".dpkg-inst"
 
 #define CONTROLFILE        "control"
 #define CONFFILESFILE      "conffiles"
diff --git a/src/configure.c b/src/configure.c
index 2764729..29878e4 100644
--- a/src/configure.c
+++ b/src/configure.c
@@ -74,10 +74,11 @@ deferred_configure_conffile(struct pkginfo *pkg, struct conffile *conff)
 	enum conffopt what;
 	struct stat stab;
 	struct varbuf cdr = VARBUF_INIT, cdr2;
-	const int max_extension_sz = max(
-		max(sizeof(DPKGNEWEXT),
-		    sizeof(DPKGOLDEXT)),
-		sizeof(DPKGDISTEXT));
+	const int max_extension_sz = max(max(max(
+		sizeof(DPKGNEWEXT),
+		sizeof(DPKGOLDEXT)),
+		sizeof(DPKGDISTEXT)),
+		sizeof(DPKGLINKEXT));
 	char *cdrrest, *cdr2rest;
 	int r;
 
@@ -205,11 +206,24 @@ deferred_configure_conffile(struct pkginfo *pkg, struct conffile *conff)
 		printf(_("Installing new version of config file %s ...\n"),
 		       usenode->name);
 	case cfo_newconff:
-		strcpy(cdr2rest, DPKGNEWEXT);
+		strcpy(cdrrest, DPKGNEWEXT);
+		strcpy(cdr2rest, DPKGLINKEXT);
+		if (unlink(cdr2.buf) && errno != ENOENT)
+			warning(_("%s: failed to remove '%.250s' "
+				"(before overwrite): %s"),
+			        pkg->name, cdr2.buf, strerror(errno));
+		if (link(cdr.buf, cdr2.buf))
+			ohshite(_("failed to link '%.250s' to '%.250s'"),
+			        cdr.buf, cdr2.buf);
 		trig_file_activate(usenode, pkg);
+		strcpy(cdrrest, "");
 		if (rename(cdr2.buf, cdr.buf))
 			ohshite(_("unable to install `%.250s' as `%.250s'"),
 			        cdr2.buf, cdr.buf);
+		strcpy(cdr2rest, DPKGNEWEXT);
+		if (unlink(cdr2.buf))
+			warning(_("%s: failed to remove '%.250s': %s"),
+				pkg->name, cdr2.buf, strerror(errno));
 		break;
 	default:
 		internerr("unknown conffopt '%d'", what);
diff --git a/src/remove.c b/src/remove.c
index 5e44a3b..59f4128 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -219,9 +219,14 @@ static void removal_bulk_remove_files(
       varbufaddstr(&fnvb,DPKGTEMPEXT);
       varbufaddc(&fnvb,0);
       debug(dbg_eachfiledetail, "removal_bulk cleaning temp `%s'", fnvb.buf);
-      
       ensure_pathname_nonexisting(fnvb.buf);
       
+      fnvb.used = before;
+      varbufaddstr(&fnvb, DPKGLINKEXT);
+      varbufaddc(&fnvb, 0);
+      debug(dbg_eachfiledetail, "remove_bulk cleaning temp `%s'", fnvb.buf);
+      ensure_pathname_nonexisting(fnvb.buf);
+
       fnvb.used= before;
       varbufaddstr(&fnvb,DPKGNEWEXT);
       varbufaddc(&fnvb,0);
-- 
1.6.5.2


Reply to: