aboutsummaryrefslogtreecommitdiff
path: root/binutils/rename.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-02-23 12:10:58 +1030
committerAlan Modra <amodra@gmail.com>2021-02-24 09:34:42 +1030
commitc42c71a1527dd70417d3966dce7ba9edbcf4bdb4 (patch)
treec84495ca493b5b03e8e144701fcc276a01d736d5 /binutils/rename.c
parentcca8873dd5a6015d5557ea44bc1ea9c252435a29 (diff)
downloadbinutils-c42c71a1527dd70417d3966dce7ba9edbcf4bdb4.zip
binutils-c42c71a1527dd70417d3966dce7ba9edbcf4bdb4.tar.gz
binutils-c42c71a1527dd70417d3966dce7ba9edbcf4bdb4.tar.bz2
Use make_tempname file descriptor in smart_rename
This patch makes use of the temp file descriptor in smart_rename rather than reopening the file. I don't believe there is a security issue in reopening the file, but this way is one less directory operation. The patch also attempts to preserve S_ISUID and S_ISGID. PR 27456 * bucomm.h (smart_rename): Update prototype. * rename.c (smart_rename): Add fromfd and preserve_dates params. Pass fromfd and target_stat to simple_copy. Call set_times when preserve_dates. (simple_copy): Accept fromfd rather than from filename. Add target_stat param. Rewind fromfd rather than opening. Open "to" file without O_CREAT. Try to preserve S_ISUID and S_ISGID. * ar.c (write_archive): Rename ofd to tmpfd. Dup tmpfd before closing output temp file, and pass tmpfd to smart_rename. * arsup.c (temp_fd): Rename from real_fd. (ar_save): Dup temp_fd and pass to smart_rename. * objcopy.c (strip_main, copy_main): Likewise, and pass preserve_dates.
Diffstat (limited to 'binutils/rename.c')
-rw-r--r--binutils/rename.c35
1 files changed, 21 insertions, 14 deletions
diff --git a/binutils/rename.c b/binutils/rename.c
index 72a9323..f688f35 100644
--- a/binutils/rename.c
+++ b/binutils/rename.c
@@ -31,24 +31,21 @@
/* 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)
{
- 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;
@@ -56,6 +53,7 @@ simple_copy (const char *from, const char *to)
errno = saved;
return -1;
}
+
while ((nread = read (fromfd, buf, sizeof buf)) > 0)
{
if (write (tofd, buf, nread) != nread)
@@ -67,7 +65,16 @@ simple_copy (const char *from, const char *to)
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)
@@ -118,17 +125,17 @@ set_times (const char *destination, const struct stat *statbuf)
various systems. So now we just copy. */
int
-smart_rename (const char *from, const char *to,
- struct stat *target_stat)
+smart_rename (const char *from, const char *to, int fromfd,
+ struct stat *target_stat, bfd_boolean preserve_dates)
{
int ret;
- ret = simple_copy (from, to);
+ ret = simple_copy (fromfd, to, target_stat);
if (ret != 0)
non_fatal (_("unable to copy file '%s'; reason: %s"),
to, strerror (errno));
- if (target_stat != NULL)
+ if (preserve_dates)
set_times (to, target_stat);
unlink (from);