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 -#else /* ! HAVE_GOOD_UTIME_H */ -#ifdef HAVE_UTIMES +#elif defined HAVE_UTIMES #include -#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; }