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__)
42static 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
50static int
51simple_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
98void
99set_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
145int
146smart_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}
221