Subject: bug#14763: mv directory cross-filesystem where destination exists fails to remove dest with EISDIR

From: Ken Booth <[email-masked]>
Date: Mon, 01 Jul 2013 22:21:36 +0100

Hi,

I have found a bug which affects RHEL 5.9, RHEL 6.4, Fedora 18, and the 
latest version of coreutils from the git repo this morning (1st July 
2013) in exactly the same way, and yet does not affect Solaris 10's mv 
command.

Test case:

f18 # mkdir /test /home/test
f18 # cp /etc/passwd /home/test
f18 # mv /home/test /
mv: overwrite ‘/test’? y
mv: inter-device move failed: ‘/home/test’ to ‘/test’; unable to remove 
target: Is a directory

Actual results:
mv: inter-device move failed: ‘/home/test’ to ‘/test’; unable to remove 
target: Is a directory

Expected results:
/home/test/passwd is copied to /test/passwd

I have determined that the problem can be "fixed" (made to behave the 
same as Solaris) by editting src/copy.c as follows:

2176c2176
< if (unlink (dst_name) != 0 && errno != ENOENT)
---
>       if (unlink (dst_name) != 0 &&  errno != ENOENT && errno != EISDIR)
2267,2269c2267,2278
< error (0, errno, _("cannot create directory %s"),
< quote (dst_name));
< goto un_backup;
---
 > if (errno == EEXIST)
 > {
 > if (lchmod (dst_name, dst_mode & ~omitted_permissions) != 0)
 > {
 > error (0, errno, _("setting permissions for %s"),
 > quote (dst_name));
 > }
 > } else {
 > error (0, errno, _("cannot create directory %s"),
 > quote (dst_name));
 > goto un_backup;
 > }

This has the same effect as mv does on Solaris 10.

Where the destination directory exists on the new mount point, the 
permissions are modified and new files will overwrite existing files in 
the destination tree. However, unique files in the destination directory 
will not be removed.

The BIG question is:
There is obviously a bug in the GNU mv command as its failing to unlink 
the directory, however ...

should the GNU mv command behave the same way as the Solaris mv commnd?

e.g.
f18# ls -la /home/test /test
/home/test:
total 12
drwxr-sr-x. 2 root root 4096 Jul 1 21:18 .
drwxr-xr-x. 14 root root 4096 Jul 1 21:18 ..
-rw-r--r--. 1 root root 2768 Jul 1 21:18 passwd

/test:
total 16
drwxr-xr-x. 2 root root 4096 Jul 1 21:20 .
dr-xr-xr-x. 25 root root 4096 Jul 1 21:09 ..
-rw-r--r--. 1 root root 1162 Jul 1 12:53 group
-rw-r--r--. 1 root root 2777 Jul 1 21:20 passwd
f18# /home/ken/git/fedora/coreutils/src/mv /home/test /
f18# ls -la /home/test /test
ls: cannot access /home/test: No such file or directory
/test:
total 16
drwxr-sr-x. 2 root root 4096 Jul 1 21:18 .
dr-xr-xr-x. 25 root root 4096 Jul 1 21:09 ..
-rw-r--r--. 1 root root 1162 Jul 1 12:53 group
-rw-r--r--. 1 root root 2768 Jul 1 21:18 passwd

or should we really be deleting the directory as defined by the man page 
wording "overwrite" and observed by the failed attempt at unlinking ?

e.g.
should we delete /test/group

Which behaviour is correct?

Regards,
Ken Booth
Red Hat UK Ltd

PS: There is a Red Hat bugzilla for this
https://bugzilla.redhat.com/show_bug.cgi?id=980061