Coverage Report

Created: 2023-08-28 06:26

/src/binutils-gdb/binutils/rename.c
Line
Count
Source (jump to first uncovered line)
1
/* rename.c -- rename a file, preserving symlinks.
2
   Copyright (C) 1999-2023 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
0
{
41
0
  int tofd, nread;
42
0
  int saved;
43
0
  char buf[COPY_BUF];
44
45
0
  if (fromfd < 0
46
0
      || lseek (fromfd, 0, SEEK_SET) != 0)
47
0
    return -1;
48
49
0
  tofd = open (to, O_WRONLY | O_TRUNC | O_BINARY);
50
0
  if (tofd < 0)
51
0
    {
52
0
      saved = errno;
53
0
      close (fromfd);
54
0
      errno = saved;
55
0
      return -1;
56
0
    }
57
58
0
  while ((nread = read (fromfd, buf, sizeof buf)) > 0)
59
0
    {
60
0
      if (write (tofd, buf, nread) != nread)
61
0
  {
62
0
    saved = errno;
63
0
    close (fromfd);
64
0
    close (tofd);
65
0
    errno = saved;
66
0
    return -1;
67
0
  }
68
0
    }
69
70
0
  saved = errno;
71
72
0
#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
0
  if (target_stat != NULL)
76
0
    fchmod (tofd, target_stat->st_mode);
77
0
#endif
78
79
0
  close (fromfd);
80
0
  close (tofd);
81
0
  if (nread < 0)
82
0
    {
83
0
      errno = saved;
84
0
      return -1;
85
0
    }
86
0
  return 0;
87
0
}
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
0
#  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
0
{
112
0
# if defined STAT_TIMESPEC
113
0
  return STAT_TIMESPEC (st, st_atim).tv_nsec;
114
0
# elif defined STAT_TIMESPEC_NS
115
0
  return STAT_TIMESPEC_NS (st, st_atim);
116
0
# else
117
0
  return 0;
118
0
# endif
119
0
}
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
0
{
125
0
# if defined STAT_TIMESPEC
126
0
  return STAT_TIMESPEC (st, st_mtim).tv_nsec;
127
0
# elif defined STAT_TIMESPEC_NS
128
0
  return STAT_TIMESPEC_NS (st, st_mtim);
129
0
# else
130
0
  return 0;
131
0
# endif
132
0
}
133
134
#if defined HAVE_UTIMENSAT
135
/* Return *ST's access time.  */
136
static inline struct timespec
137
get_stat_atime (struct stat const *st)
138
0
{
139
0
#ifdef STAT_TIMESPEC
140
0
  return STAT_TIMESPEC (st, st_atim);
141
#else
142
  struct timespec t;
143
  t.tv_sec = st->st_atime;
144
  t.tv_nsec = get_stat_atime_ns (st);
145
  return t;
146
#endif
147
0
}
148
149
/* Return *ST's data modification time.  */
150
static inline struct timespec
151
get_stat_mtime (struct stat const *st)
152
0
{
153
0
#ifdef STAT_TIMESPEC
154
0
  return STAT_TIMESPEC (st, st_mtim);
155
#else
156
  struct timespec t;
157
  t.tv_sec = st->st_mtime;
158
  t.tv_nsec = get_stat_mtime_ns (st);
159
  return t;
160
#endif
161
0
}
162
#endif
163
/* End FIXME.  */
164
165
/* Set the times of the file DESTINATION to be the same as those in
166
   STATBUF.  */
167
168
void
169
set_times (const char *destination, const struct stat *statbuf)
170
0
{
171
0
  int result;
172
0
#if defined HAVE_UTIMENSAT
173
0
  struct timespec times[2];
174
0
  times[0] = get_stat_atime (statbuf);
175
0
  times[1] = get_stat_mtime (statbuf);
176
0
  result = utimensat (AT_FDCWD, destination, times, 0);
177
#elif defined HAVE_UTIMES
178
  struct timeval tv[2];
179
180
  tv[0].tv_sec = statbuf->st_atime;
181
  tv[0].tv_usec = get_stat_atime_ns (statbuf) / 1000;
182
  tv[1].tv_sec = statbuf->st_mtime;
183
  tv[1].tv_usec = get_stat_mtime_ns (statbuf) / 1000;
184
  result = utimes (destination, tv);
185
#elif defined HAVE_GOOD_UTIME_H
186
  struct utimbuf tb;
187
188
  tb.actime = statbuf->st_atime;
189
  tb.modtime = statbuf->st_mtime;
190
  result = utime (destination, &tb);
191
#else
192
  long tb[2];
193
194
  tb[0] = statbuf->st_atime;
195
  tb[1] = statbuf->st_mtime;
196
  result = utime (destination, tb);
197
#endif
198
199
0
  if (result != 0)
200
0
    non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
201
0
}
202
203
/* Copy FROM to TO.  TARGET_STAT has the file status that, if non-NULL,
204
   is used to fix up timestamps.  Return 0 if ok, -1 if error.
205
   At one time this function renamed files, but file permissions are
206
   tricky to update given the number of different schemes used by
207
   various systems.  So now we just copy.  */
208
209
int
210
smart_rename (const char *from, const char *to, int fromfd,
211
        struct stat *target_stat, bool preserve_dates)
212
186
{
213
186
  int ret = 0;
214
215
186
  if (to != from)
216
0
    {
217
0
      ret = simple_copy (fromfd, to, target_stat);
218
0
      if (ret != 0)
219
0
  non_fatal (_("unable to copy file '%s'; reason: %s"),
220
0
       to, strerror (errno));
221
0
      unlink (from);
222
0
    }
223
224
186
  if (preserve_dates)
225
0
    set_times (to, target_stat);
226
227
186
  return ret;
228
186
}