1 /* rename.c -- rename a file, preserving symlinks.
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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.
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.
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
25 #ifdef HAVE_GOOD_UTIME_H
27 #else /* ! HAVE_GOOD_UTIME_H */
30 #endif /* HAVE_UTIMES */
31 #endif /* ! HAVE_GOOD_UTIME_H */
33 #if ! defined (_WIN32) || defined (__CYGWIN32__)
34 static int simple_copy (const char *, const char *);
36 /* The number of bytes to copy at once. */
39 /* Copy file FROM to file TO, performing no translations.
40 Return 0 if ok, -1 if error. */
43 simple_copy (const char *from
, const char *to
)
45 int fromfd
, tofd
, nread
;
49 fromfd
= open (from
, O_RDONLY
| O_BINARY
);
53 tofd
= open (to
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
, 0777);
55 tofd
= creat (to
, 0777);
64 while ((nread
= read (fromfd
, buf
, sizeof buf
)) > 0)
66 if (write (tofd
, buf
, nread
) != nread
)
85 #endif /* __CYGWIN32__ or not _WIN32 */
87 /* Set the times of the file DESTINATION to be the same as those in
91 set_times (const char *destination
, const struct stat
*statbuf
)
96 #ifdef HAVE_GOOD_UTIME_H
99 tb
.actime
= statbuf
->st_atime
;
100 tb
.modtime
= statbuf
->st_mtime
;
101 result
= utime (destination
, &tb
);
102 #else /* ! HAVE_GOOD_UTIME_H */
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];
112 tv
[0].tv_sec
= statbuf
->st_atime
;
114 tv
[1].tv_sec
= statbuf
->st_mtime
;
116 result
= utimes (destination
, tv
);
117 #endif /* HAVE_UTIMES */
118 #endif /* ! HAVE_GOOD_UTIME_H */
122 non_fatal (_("%s: cannot set time: %s"), destination
, strerror (errno
));
127 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
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. */
139 try_preserve_permissions (int fd
, struct stat
*target_stat
)
141 struct stat from_stat
;
144 if (fstat (fd
, &from_stat
) != 0)
147 int from_mode
= from_stat
.st_mode
& 0777;
148 int to_mode
= target_stat
->st_mode
& 0777;
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
155 if (from_mode
!= to_mode
)
156 fchmod (fd
, to_mode
);
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
);
163 /* Fix up the sxid bits if either the fchown wasn't needed or it
166 fchmod (fd
, target_stat
->st_mode
& 07777);
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. */
177 smart_rename (const char *from
, const char *to
, int fd ATTRIBUTE_UNUSED
,
178 struct stat
*target_stat ATTRIBUTE_UNUSED
,
179 int preserve_dates ATTRIBUTE_UNUSED
)
182 bfd_boolean exists
= target_stat
!= NULL
;
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. */
191 ret
= rename (from
, to
);
194 /* We have to clean up here. */
195 non_fatal (_("unable to rename '%s'; reason: %s"), to
, strerror (errno
));
199 /* Avoid a full copy and use rename if we can fix up permissions of the
200 file after renaming, i.e.:
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.
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
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)
223 ret
= rename (from
, to
);
227 try_preserve_permissions (fd
, target_stat
);
231 /* We have to clean up here. */
232 non_fatal (_("unable to rename '%s'; reason: %s"), to
, strerror (errno
));
238 ret
= simple_copy (from
, to
);
240 non_fatal (_("unable to copy file '%s'; reason: %s"), to
, strerror (errno
));
243 set_times (to
, target_stat
);
248 #endif /* _WIN32 && !__CYGWIN32__ */