From: Ian Jackson Date: Wed, 10 Oct 2018 23:43:45 +0000 (+0100) Subject: Dgit.pm: rename_link_xf: Avoid copying if src is a link to dst X-Git-Tag: archive/debian/8.0~43 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=d18e956260fd206e3b0c260adeea36e697350a57;hp=89906fd58100567b415f9c13d83121b988dfa325;p=dgit.git Dgit.pm: rename_link_xf: Avoid copying if src is a link to dst Signed-off-by: Ian Jackson --- diff --git a/Debian/Dgit.pm b/Debian/Dgit.pm index 19ea85b6..5b1feff5 100644 --- a/Debian/Dgit.pm +++ b/Debian/Dgit.pm @@ -434,6 +434,8 @@ sub rename_link_xf ($$$) { # $@ to a reason message # $! to an errno value, or -1 if not known # having possibly printed something about mv to stderr. + # Not safe to use without $keeporig if $dst might be a symlink + # to $src, as it might delete $src leaving $dst invalid. my ($keeporig,$src,$dst) = @_; if ($keeporig ? link $src, $dst @@ -444,19 +446,40 @@ sub rename_link_xf ($$$) { $@ = "$!"; return 0; } - $!=0; $?=0; - my @cmd = (qw(cp --), $src, "$dst.tmp"); - debugcmd '+',@cmd; - if (system @cmd) { - failedcmd_report_cmd undef, @cmd; - $@ = failedcmd_waitstatus(); - $! = -1; + if (!stat $src) { + $@ = f_ "stat source file: %S", $!; return 0; } - if (!rename "$dst.tmp", $dst) { - $@ = f_ "finally install file after cp: %S", $!; + my @src_stat = (stat _)[0..1]; + + my @dst_stat; + if (stat $dst) { + @dst_stat = (stat _)[0..1]; + } elsif ($! == ENOENT) { + } else { + $@ = f_ "stat destination file: %S", $!; return 0; } + + if ("@src_stat" eq "@dst_stat") { + # (Symlinks to) the same file. No need for a copy but + # we may need to delete the original. + printdebug "rename_link_xf $keeporig $src $dst EXDEV but same\n"; + } else { + $!=0; $?=0; + my @cmd = (qw(cp --), $src, "$dst.tmp"); + debugcmd '+',@cmd; + if (system @cmd) { + failedcmd_report_cmd undef, @cmd; + $@ = failedcmd_waitstatus(); + $! = -1; + return 0; + } + if (!rename "$dst.tmp", $dst) { + $@ = f_ "finally install file after cp: %S", $!; + return 0; + } + } if (!$keeporig) { if (!unlink $src) { $@ = f_ "delete old file after cp: %S", $!;