Use make_tempname file descriptor in smart_rename
[binutils-gdb.git] / binutils / rename.c
1 /* rename.c -- rename a file, preserving symlinks.
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19 02110-1301, USA. */
20
21 #include "sysdep.h"
22 #include "bfd.h"
23 #include "bucomm.h"
24
25 #ifdef HAVE_GOOD_UTIME_H
26 #include <utime.h>
27 #elif defined HAVE_UTIMES
28 #include <sys/time.h>
29 #endif
30
31 /* The number of bytes to copy at once. */
32 #define COPY_BUF 8192
33
34 /* Copy file FROMFD to file TO, performing no translations.
35 Return 0 if ok, -1 if error. */
36
37 static int
38 simple_copy (int fromfd, const char *to, struct stat *target_stat)
39 {
40 int tofd, nread;
41 int saved;
42 char buf[COPY_BUF];
43
44 if (fromfd < 0
45 || lseek (fromfd, 0, SEEK_SET) != 0)
46 return -1;
47
48 tofd = open (to, O_WRONLY | O_TRUNC | O_BINARY);
49 if (tofd < 0)
50 {
51 saved = errno;
52 close (fromfd);
53 errno = saved;
54 return -1;
55 }
56
57 while ((nread = read (fromfd, buf, sizeof buf)) > 0)
58 {
59 if (write (tofd, buf, nread) != nread)
60 {
61 saved = errno;
62 close (fromfd);
63 close (tofd);
64 errno = saved;
65 return -1;
66 }
67 }
68
69 saved = errno;
70
71 #if !defined (_WIN32) || defined (__CYGWIN32__)
72 /* Writing to a setuid/setgid file may clear S_ISUID and S_ISGID.
73 Try to restore them, ignoring failure. */
74 if (target_stat != NULL)
75 fchmod (tofd, target_stat->st_mode);
76 #endif
77
78 close (fromfd);
79 close (tofd);
80 if (nread < 0)
81 {
82 errno = saved;
83 return -1;
84 }
85 return 0;
86 }
87
88 /* Set the times of the file DESTINATION to be the same as those in
89 STATBUF. */
90
91 void
92 set_times (const char *destination, const struct stat *statbuf)
93 {
94 int result;
95 #ifdef HAVE_GOOD_UTIME_H
96 struct utimbuf tb;
97
98 tb.actime = statbuf->st_atime;
99 tb.modtime = statbuf->st_mtime;
100 result = utime (destination, &tb);
101 #elif defined HAVE_UTIMES
102 struct timeval tv[2];
103
104 tv[0].tv_sec = statbuf->st_atime;
105 tv[0].tv_usec = 0;
106 tv[1].tv_sec = statbuf->st_mtime;
107 tv[1].tv_usec = 0;
108 result = utimes (destination, tv);
109 #else
110 long tb[2];
111
112 tb[0] = statbuf->st_atime;
113 tb[1] = statbuf->st_mtime;
114 result = utime (destination, tb);
115 #endif
116
117 if (result != 0)
118 non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
119 }
120
121 /* Copy FROM to TO. TARGET_STAT has the file status that, if non-NULL,
122 is used to fix up timestamps. Return 0 if ok, -1 if error.
123 At one time this function renamed files, but file permissions are
124 tricky to update given the number of different schemes used by
125 various systems. So now we just copy. */
126
127 int
128 smart_rename (const char *from, const char *to, int fromfd,
129 struct stat *target_stat, bfd_boolean preserve_dates)
130 {
131 int ret;
132
133 ret = simple_copy (fromfd, to, target_stat);
134 if (ret != 0)
135 non_fatal (_("unable to copy file '%s'; reason: %s"),
136 to, strerror (errno));
137
138 if (preserve_dates)
139 set_times (to, target_stat);
140 unlink (from);
141
142 return ret;
143 }