Automatic date update in version.in
[deliverable/binutils-gdb.git] / binutils / rename.c
CommitLineData
252b5132 1/* rename.c -- rename a file, preserving symlinks.
250d07de 2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
252b5132
RH
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
32866df7 8 the Free Software Foundation; either version 3 of the License, or
252b5132
RH
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
b43b5d5f
NC
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19 02110-1301, USA. */
252b5132 20
3db64b00 21#include "sysdep.h"
252b5132
RH
22#include "bfd.h"
23#include "bucomm.h"
24
252b5132
RH
25#ifdef HAVE_GOOD_UTIME_H
26#include <utime.h>
27#else /* ! HAVE_GOOD_UTIME_H */
28#ifdef HAVE_UTIMES
29#include <sys/time.h>
30#endif /* HAVE_UTIMES */
31#endif /* ! HAVE_GOOD_UTIME_H */
32
cbee2975 33#if ! defined (_WIN32) || defined (__CYGWIN32__)
2da42df6 34static int simple_copy (const char *, const char *);
252b5132
RH
35
36/* The number of bytes to copy at once. */
37#define COPY_BUF 8192
38
39/* Copy file FROM to file TO, performing no translations.
40 Return 0 if ok, -1 if error. */
41
42static int
2da42df6 43simple_copy (const char *from, const char *to)
252b5132
RH
44{
45 int fromfd, tofd, nread;
46 int saved;
47 char buf[COPY_BUF];
48
18226413 49 fromfd = open (from, O_RDONLY | O_BINARY);
252b5132
RH
50 if (fromfd < 0)
51 return -1;
18226413
ILT
52#ifdef O_CREAT
53 tofd = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0777);
54#else
252b5132 55 tofd = creat (to, 0777);
18226413 56#endif
252b5132
RH
57 if (tofd < 0)
58 {
59 saved = errno;
60 close (fromfd);
61 errno = saved;
62 return -1;
63 }
64 while ((nread = read (fromfd, buf, sizeof buf)) > 0)
65 {
66 if (write (tofd, buf, nread) != nread)
67 {
68 saved = errno;
69 close (fromfd);
70 close (tofd);
71 errno = saved;
72 return -1;
73 }
74 }
75 saved = errno;
76 close (fromfd);
77 close (tofd);
78 if (nread < 0)
79 {
80 errno = saved;
81 return -1;
82 }
83 return 0;
84}
cbee2975 85#endif /* __CYGWIN32__ or not _WIN32 */
252b5132
RH
86
87/* Set the times of the file DESTINATION to be the same as those in
88 STATBUF. */
89
90void
2da42df6 91set_times (const char *destination, const struct stat *statbuf)
252b5132
RH
92{
93 int result;
94
95 {
96#ifdef HAVE_GOOD_UTIME_H
97 struct utimbuf tb;
98
99 tb.actime = statbuf->st_atime;
100 tb.modtime = statbuf->st_mtime;
101 result = utime (destination, &tb);
102#else /* ! HAVE_GOOD_UTIME_H */
103#ifndef HAVE_UTIMES
104 long tb[2];
105
106 tb[0] = statbuf->st_atime;
107 tb[1] = statbuf->st_mtime;
108 result = utime (destination, tb);
109#else /* HAVE_UTIMES */
110 struct timeval tv[2];
111
112 tv[0].tv_sec = statbuf->st_atime;
113 tv[0].tv_usec = 0;
114 tv[1].tv_sec = statbuf->st_mtime;
115 tv[1].tv_usec = 0;
116 result = utimes (destination, tv);
117#endif /* HAVE_UTIMES */
118#endif /* ! HAVE_GOOD_UTIME_H */
119 }
120
121 if (result != 0)
122 non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
123}
124
125#ifndef S_ISLNK
126#ifdef S_IFLNK
127#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
128#else
129#define S_ISLNK(m) 0
130#define lstat stat
131#endif
132#endif
133
014cc7f8
SP
134#if !defined (_WIN32) || defined (__CYGWIN32__)
135/* Try to preserve the permission bits and ownership of an existing file when
136 rename overwrites it. FD is the file being renamed and TARGET_STAT has the
137 status of the file that was overwritten. */
138static void
139try_preserve_permissions (int fd, struct stat *target_stat)
140{
141 struct stat from_stat;
142 int ret = 0;
143
144 if (fstat (fd, &from_stat) != 0)
145 return;
146
147 int from_mode = from_stat.st_mode & 0777;
148 int to_mode = target_stat->st_mode & 0777;
149
150 /* Fix up permissions before we potentially lose ownership with fchown.
151 Clear the setxid bits because in case the fchown below fails then we don't
152 want to end up with a sxid file owned by the invoking user. If the user
153 hasn't changed or if fchown succeeded, we add back the sxid bits at the
154 end. */
155 if (from_mode != to_mode)
156 fchmod (fd, to_mode);
157
158 /* Fix up ownership, this will clear the setxid bits. */
159 if (from_stat.st_uid != target_stat->st_uid
160 || from_stat.st_gid != target_stat->st_gid)
161 ret = fchown (fd, target_stat->st_uid, target_stat->st_gid);
162
163 /* Fix up the sxid bits if either the fchown wasn't needed or it
164 succeeded. */
165 if (ret == 0)
166 fchmod (fd, target_stat->st_mode & 07777);
167}
168#endif
169
170/* Rename FROM to TO, copying if TO is either a link or is not a regular file.
171 FD is an open file descriptor pointing to FROM that we can use to safely fix
172 up permissions of the file after renaming. TARGET_STAT has the file status
173 that is used to fix up permissions and timestamps after rename. Return 0 if
174 ok, -1 if error and FD is closed before returning. */
252b5132
RH
175
176int
014cc7f8
SP
177smart_rename (const char *from, const char *to, int fd ATTRIBUTE_UNUSED,
178 struct stat *target_stat ATTRIBUTE_UNUSED,
179 int preserve_dates ATTRIBUTE_UNUSED)
252b5132 180{
252b5132 181 int ret = 0;
014cc7f8 182 bfd_boolean exists = target_stat != NULL;
252b5132
RH
183
184#if defined (_WIN32) && !defined (__CYGWIN32__)
185 /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
186 fail instead. Also, chown is not present. */
187
82716b78 188 if (exists)
252b5132
RH
189 remove (to);
190
191 ret = rename (from, to);
192 if (ret != 0)
193 {
53c7db4b 194 /* We have to clean up here. */
216ff8b4 195 non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
252b5132
RH
196 unlink (from);
197 }
198#else
014cc7f8
SP
199 /* Avoid a full copy and use rename if we can fix up permissions of the
200 file after renaming, i.e.:
201
202 - TO is not a symbolic link
203 - TO is a regular file with only one hard link
204 - We have permission to write to TO
205 - FD is available to safely fix up permissions to be the same as the file
206 we overwrote with the rename.
207
208 Note though that the actual file on disk that TARGET_STAT describes may
209 have changed and we're only trying to preserve the status we know about.
210 At no point do we try to interact with the new file changes, so there can
211 only be two outcomes, i.e. either the external file change survives
212 without knowledge of our change (if it happens after the rename syscall)
213 or our rename and permissions fixup survive without any knowledge of the
214 external change. */
195f52b5 215 if (! exists
014cc7f8
SP
216 || (fd >= 0
217 && !S_ISLNK (target_stat->st_mode)
218 && S_ISREG (target_stat->st_mode)
219 && (target_stat->st_mode & S_IWUSR)
220 && target_stat->st_nlink == 1)
195f52b5 221 )
252b5132
RH
222 {
223 ret = rename (from, to);
224 if (ret == 0)
225 {
226 if (exists)
014cc7f8 227 try_preserve_permissions (fd, target_stat);
252b5132
RH
228 }
229 else
230 {
53c7db4b 231 /* We have to clean up here. */
216ff8b4 232 non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
252b5132
RH
233 unlink (from);
234 }
235 }
236 else
237 {
238 ret = simple_copy (from, to);
239 if (ret != 0)
216ff8b4 240 non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno));
252b5132
RH
241
242 if (preserve_dates)
014cc7f8 243 set_times (to, target_stat);
252b5132
RH
244 unlink (from);
245 }
014cc7f8
SP
246 if (fd >= 0)
247 close (fd);
252b5132
RH
248#endif /* _WIN32 && !__CYGWIN32__ */
249
250 return ret;
251}
This page took 0.899124 seconds and 4 git commands to generate.