[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: