PR 6615
[external/binutils.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 }