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 <[email protected]>
---
 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


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to