aboutsummaryrefslogtreecommitdiff
path: root/binutils/arsup.c
diff options
context:
space:
mode:
authorSiddhesh Poyarekar <siddhesh@gotplt.org>2020-12-07 20:48:33 +0530
committerSiddhesh Poyarekar <siddhesh@gotplt.org>2020-12-07 20:48:33 +0530
commit014cc7f849e8209623fc99264814bce7b3b6faf2 (patch)
tree890c586d1a37643dfa2aa394935748a5e6542f51 /binutils/arsup.c
parent1a1c3b4cc17687091cff5a368bd6f13742bcfdf8 (diff)
downloadbinutils-014cc7f849e8209623fc99264814bce7b3b6faf2.zip
binutils-014cc7f849e8209623fc99264814bce7b3b6faf2.tar.gz
binutils-014cc7f849e8209623fc99264814bce7b3b6faf2.tar.bz2
binutils: Make smart_rename safe too
smart_rename is capable of handling symlinks by copying and it also tries to preserve ownership and permissions of files when they're overwritten during the rename. This is useful in objcopy where the file properties need to be preserved. However because smart_rename does this using file names, it leaves a race window between renames and permission fixes. This change removes this race window by using file descriptors from the original BFDs that were used to manipulate these files wherever possible. The file that is to be renamed is also passed as a file descriptor so that we use fchown/fchmod on the file descriptor, thus making sure that we only modify the file we have opened to write. Further, in case the file is to be overwritten (as is the case in ar or objcopy), the permissions that need to be restored are taken from the file descriptor that was opened for input so that integrity of the file status is maintained all the way through to the rename. binutils/ * rename.c * ar.c (write_archive) [!defined (_WIN32) || defined (__CYGWIN32__)]: Initialize TARGET_STAT and OFD to pass to SMART_RENAME. * arsup.c (ar_save) [defined (_WIN32) || defined (__CYGWIN32__)]: Likewise. * bucomm.h (smart_rename): Add new arguments to declaration. * objcopy.c (strip_main)[defined (_WIN32) || defined (__CYGWIN32__)]: Initialize COPYFD and pass to SMART_RENAME. (copy_main) [defined (_WIN32) || defined (__CYGWIN32__)]: Likewise. * rename.c (try_preserve_permissions): New function. (smart_rename): Use it and add new arguments.
Diffstat (limited to 'binutils/arsup.c')
-rw-r--r--binutils/arsup.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/binutils/arsup.c b/binutils/arsup.c
index a668f27..8b4437f 100644
--- a/binutils/arsup.c
+++ b/binutils/arsup.c
@@ -345,13 +345,25 @@ ar_save (void)
else
{
char *ofilename = xstrdup (bfd_get_filename (obfd));
+ bfd_boolean skip_stat = FALSE;
+ struct stat target_stat;
+ int ofd = -1;
if (deterministic > 0)
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
+#if !defined (_WIN32) || defined (__CYGWIN32__)
+ /* It's OK to fail; at worst it will result in SMART_RENAME using a slow
+ copy fallback to write the output. */
+ ofd = dup (fileno (obfd->iostream));
+ if (lstat (real_name, &target_stat) != 0)
+ skip_stat = TRUE;
+#endif
+
bfd_close (obfd);
- smart_rename (ofilename, real_name, 0);
+ smart_rename (ofilename, real_name, ofd,
+ skip_stat ? NULL : &target_stat, 0);
obfd = 0;
free (ofilename);
}