This is the mail archive of the
cygwin-developers
mailing list for the Cygwin project.
Re: New rename(2) function
Corinna Vinschen wrote:
On Aug 9 21:23, Eric Blake wrote:
According to Christian Franke on 8/9/2007 10:38 AM:
...
Btw., this looks weird in mv:
$ mv -T Bar bar
mv: cannot remove `Bar': Operation not permitted
Huh? Nobody asked for removing Bar, afaics...
The root of the problem is IMO the copy.c:same_file_ok() function, see
attached code snippets (coreutils 6.9).
On -T, it treats the dest dir as a file and checks (1 < #links) which is
always true for a directory. The same_name() function is case sensitive.
Therefore, same_file_ok() returns true and sets unlink_src=true.
Later, copy_internal() handles the source path as a hard link to
destination and tries to unlink() the source. Fortunately, unlink() is
unable to rmdir().
No problem if both names match:
$ mv -T bar bar
mv: `bar' and `bar' are the same file
$ mv -T ./BAR BAR
mv: `./BAR' and `BAR' are the same file
In the file case, the problem does not occur because #links usually are 1:
$ touch Foo
$ mv Foo foo
mv: `Foo' and `foo' are the same file
But be aware: If there are hard links, things get really worse:
$ touch Foo
$ ln Foo Fool
$ mv -v Foo foo
removed `Foo'
$ ls foo* Foo*
ls: cannot access foo*: No such file or directory
Fool
This is probably not POSIX compliant ;-)
Christian
612 same_file_ok (...)
...
734 if (x->move_mode || x->unlink_dest_before_opening)
735 {
736 if (S_ISLNK (dst_sb_link->st_mode))
737 return true;
738
739 if (same_link
740 && 1 < dst_sb_link->st_nlink
741 && ! same_name (src_name, dst_name))
742 {
743 if (x->move_mode)
744 {
745 *unlink_src = true;
746 *return_now = true;
747 }
748 return true;
749 }
750 }
...
1014 copy_internal (...)
...
1102 bool return_now;
1103 bool unlink_src;
1104
1105 if (! same_file_ok (src_name, &src_sb, dst_name, &dst_sb,
1106 x, &return_now, &unlink_src))
1107 {
1108 error (0, 0, _("%s and %s are the same file"),
1109 quote_n (0, src_name), quote_n (1, dst_name));
1110 return false;
1111 }
...
1120 if (x->move_mode)
1121 {
1122 if (abandon_move (x, dst_name, &dst_sb)
1123 || (unlink_src && unlink (src_name) == 0))
1124 {
1125 /* Pretend the rename succeeded, so the caller (mv)
1126 doesn't end up removing the source file. */
1127 if (rename_succeeded)
1128 *rename_succeeded = true;
1129 if (unlink_src && x->verbose)
1130 printf (_("removed %s\n"), quote (src_name));
1131 return true;
1132 }
1133 if (unlink_src)
1134 {
1135 error (0, errno, _("cannot remove %s"), quote (src_name));
1136 return false;
1137 }
1138 }