PR 6615
[deliverable/binutils-gdb.git] / binutils / rename.c
1 /* rename.c -- rename a file, preserving symlinks.
2 Copyright 1999, 2002, 2003, 2007, 2008 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 #include <sys/stat.h>
26
27 #ifdef HAVE_GOOD_UTIME_H
28 #include <utime.h>
29 #else /* ! HAVE_GOOD_UTIME_H */
30 #ifdef HAVE_UTIMES
31 #include <sys/time.h>
32 #endif /* HAVE_UTIMES */
33 #endif /* ! HAVE_GOOD_UTIME_H */
34
35 #if ! defined (_WIN32) || defined (__CYGWIN32__)
36 static int simple_copy (const char *, const char *);
37
38 /* The number of bytes to copy at once. */
39 #define COPY_BUF 8192
40
41 /* Copy file FROM to file TO, performing no translations.
42 Return 0 if ok, -1 if error. */
43
44 static int
45 simple_copy (const char *from, const char *to)
46 {
47 int fromfd, tofd, nread;
48 int saved;
49 char buf[COPY_BUF];
50
51 fromfd = open (from, O_RDONLY | O_BINARY);
52 if (fromfd < 0)
53 return -1;
54 #ifdef O_CREAT
55 tofd = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0777);
56 #else
57 tofd = creat (to, 0777);
58 #endif
59 if (tofd < 0)
60 {
61 saved = errno;
62 close (fromfd);
63 errno = saved;
64 return -1;
65 }
66 while ((nread = read (fromfd, buf, sizeof buf)) > 0)
67 {
68 if (write (tofd, buf, nread) != nread)
69 {
70 saved = errno;
71 close (fromfd);
72 close (tofd);
73 errno = saved;
74 return -1;
75 }
76 }
77 saved = errno;
78 close (fromfd);
79 close (tofd);
80 if (nread < 0)
81 {
82 errno = saved;
83 return -1;
84 }
85 return 0;
86 }
87 #endif /* __CYGWIN32__ or not _WIN32 */
88
89 /* Set the times of the file DESTINATION to be the same as those in
90 STATBUF. */
91
92 void
93 set_times (const char *destination, const struct stat *statbuf)
94 {
95 int result;
96
97 {
98 #ifdef HAVE_GOOD_UTIME_H
99 struct utimbuf tb;
100
101 tb.actime = statbuf->st_atime;
102 tb.modtime = statbuf->st_mtime;
103 result = utime (destination, &tb);
104 #else /* ! HAVE_GOOD_UTIME_H */
105 #ifndef HAVE_UTIMES
106 long tb[2];
107
108 tb[0] = statbuf->st_atime;
109 tb[1] = statbuf->st_mtime;
110 result = utime (destination, tb);
111 #else /* HAVE_UTIMES */
112 struct timeval tv[2];
113
114 tv[0].tv_sec = statbuf->st_atime;
115 tv[0].tv_usec = 0;
116 tv[1].tv_sec = statbuf->st_mtime;
117 tv[1].tv_usec = 0;
118 result = utimes (destination, tv);
119 #endif /* HAVE_UTIMES */
120 #endif /* ! HAVE_GOOD_UTIME_H */
121 }
122
123 if (result != 0)
124 non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
125 }
126
127 #ifndef S_ISLNK
128 #ifdef S_IFLNK
129 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
130 #else
131 #define S_ISLNK(m) 0
132 #define lstat stat
133 #endif
134 #endif
135
136 /* Rename FROM to TO, copying if TO is a link.
137 Return 0 if ok, -1 if error. */
138
139 int
140 smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNUSED)
141 {
142 bfd_boolean exists;
143 struct stat s;
144 int ret = 0;
145
146 exists = lstat (to, &s) == 0;
147
148 #if defined (_WIN32) && !defined (__CYGWIN32__)
149 /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
150 fail instead. Also, chown is not present. */
151
152 if (exists)
153 remove (to);
154
155 ret = rename (from, to);
156 if (ret != 0)
157 {
158 /* We have to clean up here. */
159 non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
160 unlink (from);
161 }
162 #else
163 /* Use rename only if TO is not a symbolic link and has
164 only one hard link, and we have permission to write to it. */
165 if (! exists
166 || (!S_ISLNK (s.st_mode)
167 && S_ISREG (s.st_mode)
168 && (s.st_mode & S_IWUSR)
169 && s.st_nlink == 1)
170 )
171 {
172 ret = rename (from, to);
173 if (ret == 0)
174 {
175 if (exists)
176 {
177 /* Try to preserve the permission bits and ownership of
178 TO. First get the mode right except for the setuid
179 bit. Then change the ownership. Then fix the setuid
180 bit. We do the chmod before the chown because if the
181 chown succeeds, and we are a normal user, we won't be
182 able to do the chmod afterward. We don't bother to
183 fix the setuid bit first because that might introduce
184 a fleeting security problem, and because the chown
185 will clear the setuid bit anyhow. We only fix the
186 setuid bit if the chown succeeds, because we don't
187 want to introduce an unexpected setuid file owned by
188 the user running objcopy. */
189 chmod (to, s.st_mode & 0777);
190 if (chown (to, s.st_uid, s.st_gid) >= 0)
191 chmod (to, s.st_mode & 07777);
192 }
193 }
194 else
195 {
196 /* We have to clean up here. */
197 non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
198 unlink (from);
199 }
200 }
201 else
202 {
203 ret = simple_copy (from, to);
204 if (ret != 0)
205 non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno));
206
207 if (preserve_dates)
208 set_times (to, &s);
209 unlink (from);
210 }
211 #endif /* _WIN32 && !__CYGWIN32__ */
212
213 return ret;
214 }
This page took 0.044549 seconds and 5 git commands to generate.