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