PR27349, ar breaks symlinks

PR 27349
	* rename.c (smart_rename): Test for existence and type of output
	file with lstat.
This commit is contained in:
Alan Modra
2021-02-05 22:33:08 +10:30
parent 9c9d63b15a
commit 51a2525281
2 changed files with 16 additions and 7 deletions

View File

@ -1,3 +1,9 @@
2021-02-06 Alan Modra <amodra@gmail.com>
PR 27349
* rename.c (smart_rename): Test for existence and type of output
file with lstat.
2021-02-05 Nick Clifton <nickc@redhat.com> 2021-02-05 Nick Clifton <nickc@redhat.com>
* MAINTAINERS: Remove Richard Henderson as the ALPHA maintainer. * MAINTAINERS: Remove Richard Henderson as the ALPHA maintainer.

View File

@ -179,7 +179,10 @@ smart_rename (const char *from, const char *to, int fd ATTRIBUTE_UNUSED,
int preserve_dates ATTRIBUTE_UNUSED) int preserve_dates ATTRIBUTE_UNUSED)
{ {
int ret = 0; int ret = 0;
bfd_boolean exists = target_stat != NULL; struct stat to_stat;
bfd_boolean exists;
exists = lstat (to, &to_stat) == 0;
#if defined (_WIN32) && !defined (__CYGWIN32__) #if defined (_WIN32) && !defined (__CYGWIN32__)
/* Win32, unlike unix, will not erase `to' in `rename(from, to)' but /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
@ -214,16 +217,16 @@ smart_rename (const char *from, const char *to, int fd ATTRIBUTE_UNUSED,
external change. */ external change. */
if (! exists if (! exists
|| (fd >= 0 || (fd >= 0
&& !S_ISLNK (target_stat->st_mode) && !S_ISLNK (to_stat.st_mode)
&& S_ISREG (target_stat->st_mode) && S_ISREG (to_stat.st_mode)
&& (target_stat->st_mode & S_IWUSR) && (to_stat.st_mode & S_IWUSR)
&& target_stat->st_nlink == 1) && to_stat.st_nlink == 1)
) )
{ {
ret = rename (from, to); ret = rename (from, to);
if (ret == 0) if (ret == 0)
{ {
if (exists) if (exists && target_stat != NULL)
try_preserve_permissions (fd, target_stat); try_preserve_permissions (fd, target_stat);
} }
else else
@ -239,7 +242,7 @@ smart_rename (const char *from, const char *to, int fd ATTRIBUTE_UNUSED,
if (ret != 0) if (ret != 0)
non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno)); non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno));
if (preserve_dates) if (preserve_dates && target_stat != NULL)
set_times (to, target_stat); set_times (to, target_stat);
unlink (from); unlink (from);
} }