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