Forráskód Böngészése

dpkg-divert: Properly handle diversions of shared files

dpkg-divert does nothing if the same diversion is recorded multiple
times. However when a diversion is removed, it does so even if
the shared file is still in place.

We change dpkg-divert's behaviour to ignore a diversion removal request
until the diverted file is no longer owned by another package of the
same package set.

We also update the test-suite to provide a status file now that
dpkg-divert reads it.

Sponsored-by: Linaro Limited

[guillem@debian.org:
 - Handle missing DPKG_MAINTSCRIPT_ARCH when upgrading from old dpkg.
 - Split ignore removal logic into a new function. ]

Signed-off-by: Guillem Jover <guillem@debian.org>
Raphaël Hertzog 15 éve
szülő
commit
babadd90c5
2 módosított fájl, 48 hozzáadás és 1 törlés
  1. 46 0
      src/divertcmd.c
  2. 2 1
      src/t/100_dpkg_divert.t

+ 46 - 0
src/divertcmd.c

@@ -4,6 +4,8 @@
  * Copyright © 1995 Ian Jackson
  * Copyright © 2000, 2001 Wichert Akkerman
  * Copyright © 2010 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -38,6 +40,7 @@
 #include <dpkg/i18n.h>
 #include <dpkg/dpkg.h>
 #include <dpkg/dpkg-db.h>
+#include <dpkg/arch.h>
 #include <dpkg/file.h>
 #include <dpkg/glob.h>
 #include <dpkg/buffer.h>
@@ -470,6 +473,38 @@ diversion_add(const char *const *argv)
 	return 0;
 }
 
+static bool
+diversion_is_shared(struct pkgset *set, struct filenamenode *namenode)
+{
+	const char *archname;
+	struct pkginfo *pkg;
+	struct dpkg_arch *arch;
+	struct filepackages_iterator *iter;
+	bool shared = false;
+
+	if (set == NULL)
+		return false;
+
+	archname = getenv("DPKG_MAINTSCRIPT_ARCH");
+	arch = dpkg_arch_find(archname);
+	if (arch->type == arch_none || arch->type == arch_empty)
+		return false;
+
+	for (pkg = &set->pkg; pkg; pkg = pkg->arch_next)
+		ensure_packagefiles_available(pkg);
+
+	iter = filepackages_iter_new(namenode);
+	while ((pkg = filepackages_iter_next(iter))) {
+		if (pkg->set == set && pkg->installed.arch != arch) {
+			shared = true;
+			break;
+		}
+	}
+	filepackages_iter_free(iter);
+
+	return shared;
+}
+
 static int
 diversion_remove(const char *const *argv)
 {
@@ -515,6 +550,15 @@ diversion_remove(const char *const *argv)
 		       diversion_current(filename),
 		       diversion_describe(contest));
 
+	/* Ignore removal request if the diverted file is still owned
+	 * by another package in the same set. */
+	if (diversion_is_shared(pkgset, namenode)) {
+		if (opt_verbose > 0)
+			printf(_("Ignoring removal of shared diversion '%s'.\n"),
+			       diversion_describe(contest));
+		exit(0);
+	}
+
 	if (opt_verbose > 0)
 		printf(_("Removing '%s'\n"), diversion_describe(contest));
 
@@ -693,11 +737,13 @@ main(int argc, const char * const *argv)
 
 	setvbuf(stdout, NULL, _IONBF, 0);
 
+	modstatdb_open(msdbrw_readonly);
 	filesdbinit();
 	ensure_diversions();
 
 	ret = cipaction->action(argv);
 
+	modstatdb_shutdown();
 	standard_shutdown();
 
 	return ret;

+ 2 - 1
src/t/100_dpkg_divert.t

@@ -36,7 +36,8 @@ if (! -x "@dd") {
 plan tests => 235;
 
 sub cleanup {
-    system("rm -rf $tmpdir && mkdir -p $testdir && mkdir -p $admindir");
+    system("rm -rf $tmpdir && mkdir -p $testdir");
+    system("mkdir -p $admindir/updates && touch $admindir/status");
 }
 
 sub install_diversions {