binutils/binutils-CVE-2021-20197.patch
2021-03-11 14:30:48 +00:00

753 lines
22 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -rup binutils.orig/binutils/ar.c binutils-2.36.1/binutils/ar.c
--- binutils.orig/binutils/ar.c 2021-02-19 16:46:54.037875215 +0000
+++ binutils-2.36.1/binutils/ar.c 2021-02-19 16:54:24.412453329 +0000
@@ -25,7 +25,6 @@
#include "sysdep.h"
#include "bfd.h"
-#include "libbfd.h"
#include "libiberty.h"
#include "progress.h"
#include "getopt.h"
@@ -1255,8 +1254,7 @@ write_archive (bfd *iarch)
bfd *contents_head = iarch->archive_next;
int ofd = -1;
- old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1);
- strcpy (old_name, bfd_get_filename (iarch));
+ old_name = xstrdup (bfd_get_filename (iarch));
new_name = make_tempname (old_name, &ofd);
if (new_name == NULL)
@@ -1308,7 +1306,7 @@ write_archive (bfd *iarch)
/* We don't care if this fails; we might be creating the archive. */
bfd_close (iarch);
- if (smart_rename (new_name, old_name, 0) != 0)
+ if (smart_rename (new_name, old_name, NULL) != 0)
xexit (1);
free (old_name);
free (new_name);
diff -rup binutils.orig/binutils/arsup.c binutils-2.36.1/binutils/arsup.c
--- binutils.orig/binutils/arsup.c 2021-02-19 16:46:54.043875196 +0000
+++ binutils-2.36.1/binutils/arsup.c 2021-02-19 16:53:30.988621989 +0000
@@ -42,6 +42,8 @@ extern int deterministic;
static bfd *obfd;
static char *real_name;
+static char *temp_name;
+static int real_ofd;
static FILE *outfile;
static void
@@ -149,27 +151,24 @@ maybequit (void)
void
ar_open (char *name, int t)
{
- char *tname;
- const char *bname = lbasename (name);
- real_name = name;
-
- /* Prepend tmp- to the beginning, to avoid file-name clashes after
- truncation on filesystems with limited namespaces (DOS). */
- if (asprintf (&tname, "%.*stmp-%s", (int) (bname - name), name, bname) == -1)
+ real_name = xstrdup (name);
+ temp_name = make_tempname (real_name, &real_ofd);
+
+ if (temp_name == NULL)
{
- fprintf (stderr, _("%s: Can't allocate memory for temp name (%s)\n"),
+ fprintf (stderr, _("%s: Can't open temporary file (%s)\n"),
program_name, strerror(errno));
maybequit ();
return;
}
- obfd = bfd_openw (tname, NULL);
+ obfd = bfd_fdopenw (temp_name, NULL, real_ofd);
if (!obfd)
{
fprintf (stderr,
_("%s: Can't open output archive %s\n"),
- program_name, tname);
+ program_name, temp_name);
maybequit ();
}
@@ -344,16 +343,31 @@ ar_save (void)
}
else
{
- char *ofilename = xstrdup (bfd_get_filename (obfd));
+ struct stat target_stat;
if (deterministic > 0)
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
bfd_close (obfd);
- smart_rename (ofilename, real_name, 0);
- obfd = 0;
- free (ofilename);
+ if (stat (real_name, &target_stat) != 0)
+ {
+ /* The temp file created in ar_open has mode 0600 as per mkstemp.
+ Create the real empty output file here so smart_rename will
+ update the mode according to the process umask. */
+ obfd = bfd_openw (real_name, NULL);
+ if (obfd != NULL)
+ {
+ bfd_set_format (obfd, bfd_archive);
+ bfd_close (obfd);
+ }
+ }
+
+ smart_rename (temp_name, real_name, NULL);
+ obfd = NULL;
+ free (temp_name);
+ free (real_name);
+ temp_name = real_name = NULL;
}
}
diff -rup binutils.orig/binutils/bucomm.c binutils-2.36.1/binutils/bucomm.c
--- binutils.orig/binutils/bucomm.c 2021-02-19 16:46:54.052875168 +0000
+++ binutils-2.36.1/binutils/bucomm.c 2021-02-19 16:56:01.837145730 +0000
@@ -623,6 +623,21 @@ get_file_size (const char * file_name)
else if (statbuf.st_size < 0)
non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
file_name);
+#if defined (_WIN32) && !defined (__CYGWIN__)
+ else if (statbuf.st_size == 0)
+ {
+ /* MS-Windows 'stat' reports the null device as a regular file;
+ fix that. */
+ int fd = open (file_name, O_RDONLY | O_BINARY);
+ if (isatty (fd))
+ {
+ close (fd);
+ non_fatal (_("Warning: '%s' is not an ordinary file"),
+ /* libtool wants to see /dev/null in the output. */
+ strcasecmp (file_name, "nul") ? file_name : "/dev/null");
+ }
+ }
+#endif
else
return statbuf.st_size;
diff -rup binutils.orig/binutils/bucomm.h binutils-2.36.1/binutils/bucomm.h
--- binutils.orig/binutils/bucomm.h 2021-02-19 16:46:54.043875196 +0000
+++ binutils-2.36.1/binutils/bucomm.h 2021-02-19 16:55:22.653269446 +0000
@@ -71,7 +71,7 @@ extern void print_version (const char *)
/* In rename.c. */
extern void set_times (const char *, const struct stat *);
-extern int smart_rename (const char *, const char *, int);
+extern int smart_rename (const char *, const char *, struct stat *);
/* In libiberty. */
void *xmalloc (size_t);
diff -rup binutils.orig/binutils/objcopy.c binutils-2.36.1/binutils/objcopy.c
--- binutils.orig/binutils/objcopy.c 2021-02-19 16:46:54.052875168 +0000
+++ binutils-2.36.1/binutils/objcopy.c 2021-02-19 16:57:30.156866883 +0000
@@ -20,7 +20,6 @@
#include "sysdep.h"
#include "bfd.h"
-#include "libbfd.h"
#include "progress.h"
#include "getopt.h"
#include "libiberty.h"
@@ -2798,8 +2797,7 @@ copy_object (bfd *ibfd, bfd *obfd, const
pe->timestamp = pe_data (ibfd)->coff.timestamp;
}
- if (isympp)
- free (isympp);
+ free (isympp);
if (osympp != isympp)
free (osympp);
@@ -4617,8 +4615,7 @@ mark_symbols_used_in_relocations (bfd *i
(*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
}
- if (relpp != NULL)
- free (relpp);
+ free (relpp);
}
/* Write out debugging information. */
@@ -4866,12 +4863,10 @@ strip_main (int argc, char *argv[])
output_target, NULL);
if (status == 0)
{
- if (preserve_dates)
- set_times (tmpname, &statbuf);
if (output_file != tmpname)
status = (smart_rename (tmpname,
output_file ? output_file : argv[i],
- preserve_dates) != 0);
+ preserve_dates ? &statbuf : NULL) != 0);
if (status == 0)
status = hold_status;
}
@@ -5936,11 +5931,9 @@ copy_main (int argc, char *argv[])
output_target, input_arch);
if (status == 0)
{
- if (preserve_dates)
- set_times (tmpname, &statbuf);
if (tmpname != output_filename)
status = (smart_rename (tmpname, input_filename,
- preserve_dates) != 0);
+ preserve_dates ? &statbuf : NULL) != 0);
}
else
unlink_if_ordinary (tmpname);
@@ -5987,26 +5980,13 @@ copy_main (int argc, char *argv[])
}
}
- if (strip_specific_buffer)
- free (strip_specific_buffer);
-
- if (strip_unneeded_buffer)
- free (strip_unneeded_buffer);
-
- if (keep_specific_buffer)
- free (keep_specific_buffer);
-
- if (localize_specific_buffer)
- free (localize_specific_buffer);
-
- if (globalize_specific_buffer)
- free (globalize_specific_buffer);
-
- if (keepglobal_specific_buffer)
- free (keepglobal_specific_buffer);
-
- if (weaken_specific_buffer)
- free (weaken_specific_buffer);
+ free (strip_specific_buffer);
+ free (strip_unneeded_buffer);
+ free (keep_specific_buffer);
+ free (localize_specific_buffer);
+ free (globalize_specific_buffer);
+ free (keepglobal_specific_buffer);
+ free (weaken_specific_buffer);
return 0;
}
diff -rup binutils.orig/binutils/rename.c binutils-2.36.1/binutils/rename.c
--- binutils.orig/binutils/rename.c 2021-02-19 16:46:54.052875168 +0000
+++ binutils-2.36.1/binutils/rename.c 2021-02-19 16:58:27.771684984 +0000
@@ -122,26 +122,19 @@ set_times (const char *destination, cons
non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
}
-#ifndef S_ISLNK
-#ifdef S_IFLNK
-#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#else
-#define S_ISLNK(m) 0
-#define lstat stat
-#endif
-#endif
-
-/* Rename FROM to TO, copying if TO is a link.
- Return 0 if ok, -1 if error. */
+/* Rename FROM to TO, copying if TO exists. TARGET_STAT has the file status
+ that, if non-NULL, is used to fix up timestamps after rename. Return 0 if
+ ok, -1 if error. */
int
-smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNUSED)
+smart_rename (const char *from, const char *to,
+ struct stat *target_stat ATTRIBUTE_UNUSED)
{
- bfd_boolean exists;
- struct stat s;
int ret = 0;
+ struct stat to_stat;
+ bfd_boolean exists;
- exists = lstat (to, &s) == 0;
+ exists = lstat (to, &to_stat) == 0;
#if defined (_WIN32) && !defined (__CYGWIN32__)
/* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
@@ -158,38 +151,10 @@ smart_rename (const char *from, const ch
unlink (from);
}
#else
- /* Use rename only if TO is not a symbolic link and has
- only one hard link, and we have permission to write to it. */
- if (! exists
- || (!S_ISLNK (s.st_mode)
- && S_ISREG (s.st_mode)
- && (s.st_mode & S_IWUSR)
- && s.st_nlink == 1)
- )
+ /* Avoid a full copy and use rename if TO does not exist. */
+ if (!exists)
{
- ret = rename (from, to);
- if (ret == 0)
- {
- if (exists)
- {
- /* Try to preserve the permission bits and ownership of
- TO. First get the mode right except for the setuid
- bit. Then change the ownership. Then fix the setuid
- bit. We do the chmod before the chown because if the
- chown succeeds, and we are a normal user, we won't be
- able to do the chmod afterward. We don't bother to
- fix the setuid bit first because that might introduce
- a fleeting security problem, and because the chown
- will clear the setuid bit anyhow. We only fix the
- setuid bit if the chown succeeds, because we don't
- want to introduce an unexpected setuid file owned by
- the user running objcopy. */
- chmod (to, s.st_mode & 0777);
- if (chown (to, s.st_uid, s.st_gid) >= 0)
- chmod (to, s.st_mode & 07777);
- }
- }
- else
+ if ((ret = rename (from, to)) != 0)
{
/* We have to clean up here. */
non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
@@ -202,8 +167,8 @@ smart_rename (const char *from, const ch
if (ret != 0)
non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno));
- if (preserve_dates)
- set_times (to, &s);
+ if (target_stat != NULL)
+ set_times (to, target_stat);
unlink (from);
}
#endif /* _WIN32 && !__CYGWIN32__ */
diff -rup binutils.orig/binutils/ar.c binutils-2.36.1/binutils/ar.c
--- binutils.orig/binutils/ar.c 2021-03-11 12:57:40.206766885 +0000
+++ binutils-2.36.1/binutils/ar.c 2021-03-11 12:59:42.874957119 +0000
@@ -1252,21 +1252,21 @@ write_archive (bfd *iarch)
bfd *obfd;
char *old_name, *new_name;
bfd *contents_head = iarch->archive_next;
- int ofd = -1;
+ int tmpfd = -1;
old_name = xstrdup (bfd_get_filename (iarch));
- new_name = make_tempname (old_name, &ofd);
+ new_name = make_tempname (old_name, &tmpfd);
if (new_name == NULL)
bfd_fatal (_("could not create temporary file whilst writing archive"));
output_filename = new_name;
- obfd = bfd_fdopenw (new_name, bfd_get_target (iarch), ofd);
+ obfd = bfd_fdopenw (new_name, bfd_get_target (iarch), tmpfd);
if (obfd == NULL)
{
- close (ofd);
+ close (tmpfd);
bfd_fatal (old_name);
}
@@ -1297,6 +1297,7 @@ write_archive (bfd *iarch)
if (!bfd_set_archive_head (obfd, contents_head))
bfd_fatal (old_name);
+ tmpfd = dup (tmpfd);
if (!bfd_close (obfd))
bfd_fatal (old_name);
@@ -1306,7 +1307,7 @@ write_archive (bfd *iarch)
/* We don't care if this fails; we might be creating the archive. */
bfd_close (iarch);
- if (smart_rename (new_name, old_name, NULL) != 0)
+ if (smart_rename (new_name, old_name, tmpfd, NULL, FALSE) != 0)
xexit (1);
free (old_name);
free (new_name);
diff -rup binutils.orig/binutils/arsup.c binutils-2.36.1/binutils/arsup.c
--- binutils.orig/binutils/arsup.c 2021-03-11 12:57:40.190766990 +0000
+++ binutils-2.36.1/binutils/arsup.c 2021-03-11 13:00:35.897607109 +0000
@@ -43,7 +43,7 @@ extern int deterministic;
static bfd *obfd;
static char *real_name;
static char *temp_name;
-static int real_ofd;
+static int temp_fd;
static FILE *outfile;
static void
@@ -152,7 +152,7 @@ void
ar_open (char *name, int t)
{
real_name = xstrdup (name);
- temp_name = make_tempname (real_name, &real_ofd);
+ temp_name = make_tempname (real_name, &temp_fd);
if (temp_name == NULL)
{
@@ -162,7 +162,7 @@ ar_open (char *name, int t)
return;
}
- obfd = bfd_fdopenw (temp_name, NULL, real_ofd);
+ obfd = bfd_fdopenw (temp_name, NULL, temp_fd);
if (!obfd)
{
@@ -348,6 +348,7 @@ ar_save (void)
if (deterministic > 0)
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
+ temp_fd = dup (temp_fd);
bfd_close (obfd);
if (stat (real_name, &target_stat) != 0)
@@ -363,11 +364,10 @@ ar_save (void)
}
}
- smart_rename (temp_name, real_name, NULL);
+ smart_rename (temp_name, real_name, temp_fd, NULL, FALSE);
obfd = NULL;
free (temp_name);
free (real_name);
- temp_name = real_name = NULL;
}
}
diff -rup binutils.orig/binutils/bucomm.h binutils-2.36.1/binutils/bucomm.h
--- binutils.orig/binutils/bucomm.h 2021-03-11 12:57:40.205766891 +0000
+++ binutils-2.36.1/binutils/bucomm.h 2021-03-11 12:59:03.082219804 +0000
@@ -71,7 +71,8 @@ extern void print_version (const char *)
/* In rename.c. */
extern void set_times (const char *, const struct stat *);
-extern int smart_rename (const char *, const char *, struct stat *);
+extern int smart_rename (const char *, const char *, int,
+ struct stat *, bfd_boolean);
/* In libiberty. */
void *xmalloc (size_t);
diff -rup binutils.orig/binutils/objcopy.c binutils-2.36.1/binutils/objcopy.c
--- binutils.orig/binutils/objcopy.c 2021-03-11 12:57:40.196766951 +0000
+++ binutils-2.36.1/binutils/objcopy.c 2021-03-11 13:02:43.321765939 +0000
@@ -4822,6 +4822,7 @@ strip_main (int argc, char *argv[])
struct stat statbuf;
char *tmpname;
int tmpfd = -1;
+ int copyfd = -1;
if (get_file_size (argv[i]) < 1)
{
@@ -4831,7 +4832,11 @@ strip_main (int argc, char *argv[])
if (output_file == NULL
|| filename_cmp (argv[i], output_file) == 0)
- tmpname = make_tempname (argv[i], &tmpfd);
+ {
+ tmpname = make_tempname (argv[i], &tmpfd);
+ if (tmpfd >= 0)
+ copyfd = dup (tmpfd);
+ }
else
tmpname = output_file;
@@ -4849,14 +4854,18 @@ strip_main (int argc, char *argv[])
if (status == 0)
{
if (output_file != tmpname)
- status = (smart_rename (tmpname,
- output_file ? output_file : argv[i],
- preserve_dates ? &statbuf : NULL) != 0);
+ status = smart_rename (tmpname,
+ output_file ? output_file : argv[i],
+ copyfd, &statbuf, preserve_dates) != 0;
if (status == 0)
status = hold_status;
}
else
- unlink_if_ordinary (tmpname);
+ {
+ if (copyfd >= 0)
+ close (copyfd);
+ unlink_if_ordinary (tmpname);
+ }
if (output_file != tmpname)
free (tmpname);
}
@@ -5063,7 +5072,9 @@ copy_main (int argc, char *argv[])
bfd_boolean formats_info = FALSE;
bfd_boolean use_globalize = FALSE;
bfd_boolean use_keep_global = FALSE;
- int c, tmpfd = -1;
+ int c;
+ int tmpfd = -1;
+ int copyfd;
struct stat statbuf;
const bfd_arch_info_type *input_arch = NULL;
@@ -5901,27 +5912,38 @@ copy_main (int argc, char *argv[])
}
/* If there is no destination file, or the source and destination files
- are the same, then create a temp and rename the result into the input. */
+ are the same, then create a temp and copy the result into the input. */
+ copyfd = -1;
if (output_filename == NULL
|| filename_cmp (input_filename, output_filename) == 0)
- tmpname = make_tempname (input_filename, &tmpfd);
+ {
+ tmpname = make_tempname (input_filename, &tmpfd);
+ if (tmpfd >= 0)
+ copyfd = dup (tmpfd);
+ }
else
tmpname = output_filename;
if (tmpname == NULL)
- fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
- input_filename, strerror (errno));
+ {
+ fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
+ input_filename, strerror (errno));
+ }
copy_file (input_filename, tmpname, tmpfd, &statbuf, input_target,
output_target, input_arch);
if (status == 0)
{
if (tmpname != output_filename)
- status = (smart_rename (tmpname, input_filename,
- preserve_dates ? &statbuf : NULL) != 0);
+ status = smart_rename (tmpname, input_filename, copyfd,
+ &statbuf, preserve_dates) != 0;
}
else
- unlink_if_ordinary (tmpname);
+ {
+ if (copyfd >= 0)
+ close (copyfd);
+ unlink_if_ordinary (tmpname);
+ }
if (tmpname != output_filename)
free (tmpname);
diff -rup binutils.orig/binutils/rename.c binutils-2.36.1/binutils/rename.c
--- binutils.orig/binutils/rename.c 2021-03-11 12:57:40.206766885 +0000
+++ binutils-2.36.1/binutils/rename.c 2021-03-11 12:58:47.306323943 +0000
@@ -24,36 +24,29 @@
#ifdef HAVE_GOOD_UTIME_H
#include <utime.h>
-#else /* ! HAVE_GOOD_UTIME_H */
-#ifdef HAVE_UTIMES
+#elif defined HAVE_UTIMES
#include <sys/time.h>
-#endif /* HAVE_UTIMES */
-#endif /* ! HAVE_GOOD_UTIME_H */
-
-#if ! defined (_WIN32) || defined (__CYGWIN32__)
-static int simple_copy (const char *, const char *);
+#endif
/* The number of bytes to copy at once. */
#define COPY_BUF 8192
-/* Copy file FROM to file TO, performing no translations.
+/* Copy file FROMFD to file TO, performing no translations.
Return 0 if ok, -1 if error. */
static int
-simple_copy (const char *from, const char *to)
+simple_copy (int fromfd, const char *to,
+ struct stat *target_stat ATTRIBUTE_UNUSED)
{
- int fromfd, tofd, nread;
+ int tofd, nread;
int saved;
char buf[COPY_BUF];
- fromfd = open (from, O_RDONLY | O_BINARY);
- if (fromfd < 0)
+ if (fromfd < 0
+ || lseek (fromfd, 0, SEEK_SET) != 0)
return -1;
-#ifdef O_CREAT
- tofd = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0777);
-#else
- tofd = creat (to, 0777);
-#endif
+
+ tofd = open (to, O_WRONLY | O_TRUNC | O_BINARY);
if (tofd < 0)
{
saved = errno;
@@ -61,6 +54,7 @@ simple_copy (const char *from, const cha
errno = saved;
return -1;
}
+
while ((nread = read (fromfd, buf, sizeof buf)) > 0)
{
if (write (tofd, buf, nread) != nread)
@@ -72,7 +66,16 @@ simple_copy (const char *from, const cha
return -1;
}
}
+
saved = errno;
+
+#if !defined (_WIN32) || defined (__CYGWIN32__)
+ /* Writing to a setuid/setgid file may clear S_ISUID and S_ISGID.
+ Try to restore them, ignoring failure. */
+ if (target_stat != NULL)
+ fchmod (tofd, target_stat->st_mode);
+#endif
+
close (fromfd);
close (tofd);
if (nread < 0)
@@ -82,7 +85,6 @@ simple_copy (const char *from, const cha
}
return 0;
}
-#endif /* __CYGWIN32__ or not _WIN32 */
/* Set the times of the file DESTINATION to be the same as those in
STATBUF. */
@@ -91,87 +93,52 @@ void
set_times (const char *destination, const struct stat *statbuf)
{
int result;
-
- {
#ifdef HAVE_GOOD_UTIME_H
- struct utimbuf tb;
+ struct utimbuf tb;
- tb.actime = statbuf->st_atime;
- tb.modtime = statbuf->st_mtime;
- result = utime (destination, &tb);
-#else /* ! HAVE_GOOD_UTIME_H */
-#ifndef HAVE_UTIMES
- long tb[2];
-
- tb[0] = statbuf->st_atime;
- tb[1] = statbuf->st_mtime;
- result = utime (destination, tb);
-#else /* HAVE_UTIMES */
- struct timeval tv[2];
-
- tv[0].tv_sec = statbuf->st_atime;
- tv[0].tv_usec = 0;
- tv[1].tv_sec = statbuf->st_mtime;
- tv[1].tv_usec = 0;
- result = utimes (destination, tv);
-#endif /* HAVE_UTIMES */
-#endif /* ! HAVE_GOOD_UTIME_H */
- }
+ tb.actime = statbuf->st_atime;
+ tb.modtime = statbuf->st_mtime;
+ result = utime (destination, &tb);
+#elif defined HAVE_UTIMES
+ struct timeval tv[2];
+
+ tv[0].tv_sec = statbuf->st_atime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = statbuf->st_mtime;
+ tv[1].tv_usec = 0;
+ result = utimes (destination, tv);
+#else
+ long tb[2];
+
+ tb[0] = statbuf->st_atime;
+ tb[1] = statbuf->st_mtime;
+ result = utime (destination, tb);
+#endif
if (result != 0)
non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
}
-/* Rename FROM to TO, copying if TO exists. TARGET_STAT has the file status
- that, if non-NULL, is used to fix up timestamps after rename. Return 0 if
- ok, -1 if error. */
+/* Copy FROM to TO. TARGET_STAT has the file status that, if non-NULL,
+ is used to fix up timestamps. Return 0 if ok, -1 if error.
+ At one time this function renamed files, but file permissions are
+ tricky to update given the number of different schemes used by
+ various systems. So now we just copy. */
int
-smart_rename (const char *from, const char *to,
- struct stat *target_stat ATTRIBUTE_UNUSED)
+smart_rename (const char *from, const char *to, int fromfd,
+ struct stat *target_stat, bfd_boolean preserve_dates)
{
- int ret = 0;
- struct stat to_stat;
- bfd_boolean exists;
+ int ret;
- exists = lstat (to, &to_stat) == 0;
-
-#if defined (_WIN32) && !defined (__CYGWIN32__)
- /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
- fail instead. Also, chown is not present. */
-
- if (exists)
- remove (to);
-
- ret = rename (from, to);
+ ret = simple_copy (fromfd, to, target_stat);
if (ret != 0)
- {
- /* We have to clean up here. */
- non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
- unlink (from);
- }
-#else
- /* Avoid a full copy and use rename if TO does not exist. */
- if (!exists)
- {
- if ((ret = rename (from, to)) != 0)
- {
- /* We have to clean up here. */
- non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
- unlink (from);
- }
- }
- else
- {
- ret = simple_copy (from, to);
- if (ret != 0)
- non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno));
-
- if (target_stat != NULL)
- set_times (to, target_stat);
- unlink (from);
- }
-#endif /* _WIN32 && !__CYGWIN32__ */
+ non_fatal (_("unable to copy file '%s'; reason: %s"),
+ to, strerror (errno));
+
+ if (preserve_dates)
+ set_times (to, target_stat);
+ unlink (from);
return ret;
}