Subject: Bug#836211: dpkg: Cannot upgrade some packages on overlayfs: Invalid cross-device link

From: Raphael Hertzog <[email-masked]>
Date: Fri, 2 Sep 2016 16:46:44 +0200

Hi,

On Wed, 31 Aug 2016, Felipe Sateler wrote:
> I don't know what the correct workaround should be.

Just for the record, the attached patch is what we use in Kali
to work-around this problem. It works but it's not going to be merged in
Debian because we really want a fix at the overlayfs level instead
(and this is just a hack relying on "mv" to copy the whole-directory).

I post it just in case other derivatives have a similar need.

Cheers,
-- 
Raphaël Hertzog ◈ Debian Developer

Support Debian LTS: http://www.freexian.com/services/debian-lts.html
Learn to master Debian: http://debian-handbook.info/get/
commit 237e415129217670699d81287c7cab7bdf451ca7
Author: Raphaël Hertzog <[email-masked]>
Date:   Fri Sep 2 13:55:29 2016 +0200

    Fallback on /bin/mv when rename syscall fails with EXDEV
    
    Work-around EXDEV error returned by overlayfs when trying to move away a
    directory by calling "mv" which will do a full copy of the tree followed
    by a removal of the source tree.
    
    Closes: #836211

diff --git a/debian/changelog b/debian/changelog
index 695c55d..233e413 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+dpkg (1.18.10kali1) kali-dev; urgency=medium
+
+  * Work-around EXDEV error returned by overlayfs when trying to move
+    away a directory by calling "mv" which will do a full copy of
+    the tree followed by a removal of the source tree. Closes: #836211
+
+ -- Raphaël Hertzog <[email-masked]>  Fri, 02 Sep 2016 13:53:39 +0200
+
 dpkg (1.18.10) unstable; urgency=medium
 
   [ Guillem Jover ]
diff --git a/src/archives.c b/src/archives.c
index d07d4a4..da43ab7 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -1021,9 +1021,25 @@ tarobject(void *ctx, struct tar_entry *ti)
       /* One of the two is a directory - can't do atomic install. */
       debug(dbg_eachfiledetail,"tarobject directory, nonatomic");
       nifd->namenode->flags |= fnnf_no_atomic_overwrite;
-      if (rename(fnamevb.buf,fnametmpvb.buf))
-        ohshite(_("unable to move aside '%.255s' to install new version"),
-                ti->name);
+      if (rename(fnamevb.buf,fnametmpvb.buf)) {
+	if (errno == EXDEV) {
+	  struct command cmd;
+	  pid_t pid;
+
+	  command_init(&cmd, "mv", "move directory aside");
+	  command_add_args(&cmd, "mv", fnamevb.buf, fnametmpvb.buf, NULL);
+	  pid = subproc_fork();
+
+	  if (pid == 0)
+            command_exec(&cmd);
+
+	  subproc_reap(pid, "mv", 0);
+	  command_destroy(&cmd);
+	} else {
+	  ohshite(_("unable to move aside '%.255s' to install new version"),
+                  ti->name);
+	}
+      }
     } else if (S_ISLNK(stab.st_mode)) {
       /* We can't make a symlink with two hardlinks, so we'll have to
        * copy it. (Pretend that making a copy of a symlink is the same