Parcourir la source

dpkg: Keep parent directories of directories kept during removal

When a directory is kept during removal to be later dealt with during
purge, due to the directory containing conffiles from the same package,
it not being empty, etc, we should keep all its parent to make sure
when the subsequent trial is performed they are properly cleaned up.

Closes: #454694

Based-on-patch-by: Ondřej Surý <ondrej@debian.org>
Guillem Jover il y a 15 ans
Parent
commit
799d38599c
4 fichiers modifiés avec 44 ajouts et 0 suppressions
  1. 3 0
      debian/changelog
  2. 31 0
      src/help.c
  3. 2 0
      src/main.h
  4. 8 0
      src/remove.c

+ 3 - 0
debian/changelog

@@ -63,6 +63,9 @@ dpkg (1.16.1) UNRELEASED; urgency=low
     directory itself. Thanks to Ondřej Surý <ondrej@debian.org>.
   * On purge correctly remove symlinks acting as directories, when they are
     not being used by any other package's files.
+  * Do not lose track of parent directories on removal so that they can
+    be properly cleaned up on purge if not used by any other package.
+    Based on a patch by Ondřej Surý <ondrej@debian.org>. Closes: #454694
 
   [ Updated dpkg translations ]
   * German (Sven Joachim). Closes: #620312

+ 31 - 0
src/help.c

@@ -514,6 +514,37 @@ dir_is_used_by_others(struct filenamenode *file, struct pkginfo *pkg)
   return false;
 }
 
+/*
+ * Returns true if the file is used by pkg, false otherwise.
+ */
+bool
+dir_is_used_by_pkg(struct filenamenode *file, struct pkginfo *pkg,
+                   struct fileinlist *list)
+{
+  struct fileinlist *node;
+  size_t namelen;
+
+  debug(dbg_veryverbose, "dir_is_used_by_pkg '%s' (by %s)",
+        file->name, pkg ? pkg->name : "<none>");
+
+  namelen = strlen(file->name);
+
+  for (node = list; node; node = node->next) {
+    debug(dbg_veryverbose, "dir_is_used_by_pkg considering %s ...",
+          node->namenode->name);
+
+    if (strncmp(file->name, node->namenode->name, namelen) == 0 &&
+        node->namenode->name[namelen] == '/') {
+      debug(dbg_veryverbose, "dir_is_used_by_pkg yes");
+      return true;
+    }
+  }
+
+  debug(dbg_veryverbose, "dir_is_used_by_pkg no");
+
+  return false;
+}
+
 void oldconffsetflags(const struct conffile *searchconff) {
   struct filenamenode *namenode;
 

+ 2 - 0
src/main.h

@@ -249,6 +249,8 @@ void post_postinst_tasks(struct pkginfo *pkg, enum pkgstatus new_status);
 
 void clear_istobes(void);
 bool dir_is_used_by_others(struct filenamenode *namenode, struct pkginfo *pkg);
+bool dir_is_used_by_pkg(struct filenamenode *namenode, struct pkginfo *pkg,
+                        struct fileinlist *list);
 bool dir_has_conffiles(struct filenamenode *namenode, struct pkginfo *pkg);
 
 void log_action(const char *action, struct pkginfo *pkg);

+ 8 - 0
src/remove.c

@@ -257,6 +257,10 @@ removal_bulk_remove_files(struct pkginfo *pkg)
 	  push_leftover(&leftover,namenode);
 	  continue;
 	}
+        if (dir_is_used_by_pkg(namenode, pkg, leftover)) {
+          push_leftover(&leftover, namenode);
+          continue;
+        }
         if (dir_is_used_by_others(namenode, pkg))
           continue;
       }
@@ -339,6 +343,10 @@ static void removal_bulk_remove_leftover_dirs(struct pkginfo *pkg) {
       /* Only delete a directory or a link to one if we're the only
        * package which uses it. Other files should only be listed
        * in this package (but we don't check). */
+      if (dir_is_used_by_pkg(namenode, pkg, leftover)) {
+        push_leftover(&leftover, namenode);
+        continue;
+      }
       if (dir_is_used_by_others(namenode, pkg))
         continue;
     }