PR27349, ar breaks symlinks
authorAlan Modra <amodra@gmail.com>
Fri, 5 Feb 2021 12:03:08 +0000 (22:33 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 5 Feb 2021 20:58:21 +0000 (07:28 +1030)
PR 27349
* rename.c (smart_rename): Test for existence and type of output
file with lstat.

binutils/ChangeLog
binutils/rename.c

index 2721767a5fc366fd0ed038647f45149a2e22a245..23a8d8eafaf39d9885bd097afce59bde0f0c19f7 100644 (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>
 
        * MAINTAINERS: Remove Richard Henderson as the ALPHA maintainer.
index fece311791532c68d7fff2ee796d432a7a1d5fc9..e36b75132ded18ff0cbf56d95aaaef4a67b6e0c5 100644 (file)
@@ -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);
     }