From 51a25252814f8b6f88ff5999a091e47ca1dbdeb9 Mon Sep 17 00:00:00 2001
From: Alan Modra <amodra@gmail.com>
Date: Fri, 5 Feb 2021 22:33:08 +1030
Subject: [PATCH] PR27349, ar breaks symlinks

	PR 27349
	* rename.c (smart_rename): Test for existence and type of output
	file with lstat.
---
 binutils/rename.c  | 17 ++++++++++-------
 1 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/binutils/rename.c b/binutils/rename.c
index fece31179153..e36b75132ded 100644
--- a/binutils/rename.c
+++ b/binutils/rename.c
@@ -179,7 +179,10 @@ smart_rename (const char *from, const char *to, int fd ATTRIBUTE_UNUSED,
 	      int preserve_dates ATTRIBUTE_UNUSED)
 {
   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__)
   /* 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.  */
   if (! exists
       || (fd >= 0
-	  && !S_ISLNK (target_stat->st_mode)
-	  && S_ISREG (target_stat->st_mode)
-	  && (target_stat->st_mode & S_IWUSR)
-	  && target_stat->st_nlink == 1)
+	  && !S_ISLNK (to_stat.st_mode)
+	  && S_ISREG (to_stat.st_mode)
+	  && (to_stat.st_mode & S_IWUSR)
+	  && to_stat.st_nlink == 1)
       )
     {
       ret = rename (from, to);
       if (ret == 0)
 	{
-	  if (exists)
+	  if (exists && target_stat != NULL)
 	    try_preserve_permissions (fd, target_stat);
 	}
       else
@@ -239,7 +242,7 @@ smart_rename (const char *from, const char *to, int fd ATTRIBUTE_UNUSED,
       if (ret != 0)
 	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);
       unlink (from);
     }
