Automatic date update in version.in
[deliverable/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 #if defined HAVE_UTIMES
26 #include <sys/time.h>
27 #elif defined HAVE_GOOD_UTIME_H
28 #include <utime.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,
39 struct stat *target_stat ATTRIBUTE_UNUSED)
40 {
41 int tofd, nread;
42 int saved;
43 char buf[COPY_BUF];
44
45 if (fromfd < 0
46 || lseek (fromfd, 0, SEEK_SET) != 0)
47 return -1;
48
49 tofd = open (to, O_WRONLY | O_TRUNC | O_BINARY);
50 if (tofd < 0)
51 {
52 saved = errno;
53 close (fromfd);
54 errno = saved;
55 return -1;
56 }
57
58 while ((nread = read (fromfd, buf, sizeof buf)) > 0)
59 {
60 if (write (tofd, buf, nread) != nread)
61 {
62 saved = errno;
63 close (fromfd);
64 close (tofd);
65 errno = saved;
66 return -1;
67 }
68 }
69
70 saved = errno;
71
72 #if !defined (_WIN32) || defined (__CYGWIN32__)
73 /* Writing to a setuid/setgid file may clear S_ISUID and S_ISGID.
74 Try to restore them, ignoring failure. */
75 if (target_stat != NULL)
76 fchmod (tofd, target_stat->st_mode);
77 #endif
78
79 close (fromfd);
80 close (tofd);
81 if (nread < 0)
82 {
83 errno = saved;
84 return -1;
85 }
86 return 0;
87 }
88
89 /* The following defines and inline functions are copied from gnulib.
90 FIXME: Use a gnulib import and stat-time.h instead. */
91 #if defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
92 # if defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
93 # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
94 # else
95 # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec)
96 # endif
97 #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
98 # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec)
99 #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC
100 # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec)
101 #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC
102 # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec)
103 #endif
104
105 static inline long int get_stat_atime_ns (struct stat const *) ATTRIBUTE_UNUSED;
106 static inline long int get_stat_mtime_ns (struct stat const *) ATTRIBUTE_UNUSED;
107
108 /* Return the nanosecond component of *ST's access time. */
109 static inline long int
110 get_stat_atime_ns (struct stat const *st ATTRIBUTE_UNUSED)
111 {
112 # if defined STAT_TIMESPEC
113 return STAT_TIMESPEC (st, st_atim).tv_nsec;
114 # elif defined STAT_TIMESPEC_NS
115 return STAT_TIMESPEC_NS (st, st_atim);
116 # else
117 return 0;
118 # endif
119 }
120
121 /* Return the nanosecond component of *ST's data modification time. */
122 static inline long int
123 get_stat_mtime_ns (struct stat const *st ATTRIBUTE_UNUSED)
124 {
125 # if defined STAT_TIMESPEC
126 return STAT_TIMESPEC (st, st_mtim).tv_nsec;
127 # elif defined STAT_TIMESPEC_NS
128 return STAT_TIMESPEC_NS (st, st_mtim);
129 # else
130 return 0;
131 # endif
132 }
133
134 /* Return *ST's access time. */
135 static inline struct timespec
136 get_stat_atime (struct stat const *st)
137 {
138 #ifdef STAT_TIMESPEC
139 return STAT_TIMESPEC (st, st_atim);
140 #else
141 struct timespec t;
142 t.tv_sec = st->st_atime;
143 t.tv_nsec = get_stat_atime_ns (st);
144 return t;
145 #endif
146 }
147
148 /* Return *ST's data modification time. */
149 static inline struct timespec
150 get_stat_mtime (struct stat const *st)
151 {
152 #ifdef STAT_TIMESPEC
153 return STAT_TIMESPEC (st, st_mtim);
154 #else
155 struct timespec t;
156 t.tv_sec = st->st_mtime;
157 t.tv_nsec = get_stat_mtime_ns (st);
158 return t;
159 #endif
160 }
161 /* End FIXME. */
162
163 /* Set the times of the file DESTINATION to be the same as those in
164 STATBUF. */
165
166 void
167 set_times (const char *destination, const struct stat *statbuf)
168 {
169 int result;
170 #if defined HAVE_UTIMENSAT
171 struct timespec times[2];
172 times[0] = get_stat_atime (statbuf);
173 times[1] = get_stat_mtime (statbuf);
174 result = utimensat (AT_FDCWD, destination, times, 0);
175 #elif defined HAVE_UTIMES
176 struct timeval tv[2];
177
178 tv[0].tv_sec = statbuf->st_atime;
179 tv[0].tv_usec = get_stat_atime_ns (statbuf) / 1000;
180 tv[1].tv_sec = statbuf->st_mtime;
181 tv[1].tv_usec = get_stat_mtime_ns (statbuf) / 1000;
182 result = utimes (destination, tv);
183 #elif defined HAVE_GOOD_UTIME_H
184 struct utimbuf tb;
185
186 tb.actime = statbuf->st_atime;
187 tb.modtime = statbuf->st_mtime;
188 result = utime (destination, &tb);
189 #else
190 long tb[2];
191
192 tb[0] = statbuf->st_atime;
193 tb[1] = statbuf->st_mtime;
194 result = utime (destination, tb);
195 #endif
196
197 if (result != 0)
198 non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
199 }
200
201 /* Copy FROM to TO. TARGET_STAT has the file status that, if non-NULL,
202 is used to fix up timestamps. Return 0 if ok, -1 if error.
203 At one time this function renamed files, but file permissions are
204 tricky to update given the number of different schemes used by
205 various systems. So now we just copy. */
206
207 int
208 smart_rename (const char *from, const char *to, int fromfd,
209 struct stat *target_stat, bool preserve_dates)
210 {
211 int ret = 0;
212
213 if (to != from)
214 {
215 ret = simple_copy (fromfd, to, target_stat);
216 if (ret != 0)
217 non_fatal (_("unable to copy file '%s'; reason: %s"),
218 to, strerror (errno));
219 unlink (from);
220 }
221
222 if (preserve_dates)
223 set_times (to, target_stat);
224
225 return ret;
226 }
This page took 0.034493 seconds and 4 git commands to generate.