rename.c revision 104834
1/* rename.c -- rename a file, preserving symlinks.
2   Copyright 1999 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., 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, 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
40static int simple_copy PARAMS ((const char *, const char *));
41
42/* The number of bytes to copy at once.  */
43#define COPY_BUF 8192
44
45/* Copy file FROM to file TO, performing no translations.
46   Return 0 if ok, -1 if error.  */
47
48static int
49simple_copy (from, to)
50     const char *from;
51     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
94/* Set the times of the file DESTINATION to be the same as those in
95   STATBUF.  */
96
97void
98set_times (destination, statbuf)
99     const char *destination;
100     const struct stat *statbuf;
101{
102  int result;
103
104  {
105#ifdef HAVE_GOOD_UTIME_H
106    struct utimbuf tb;
107
108    tb.actime = statbuf->st_atime;
109    tb.modtime = statbuf->st_mtime;
110    result = utime (destination, &tb);
111#else /* ! HAVE_GOOD_UTIME_H */
112#ifndef HAVE_UTIMES
113    long tb[2];
114
115    tb[0] = statbuf->st_atime;
116    tb[1] = statbuf->st_mtime;
117    result = utime (destination, tb);
118#else /* HAVE_UTIMES */
119    struct timeval tv[2];
120
121    tv[0].tv_sec = statbuf->st_atime;
122    tv[0].tv_usec = 0;
123    tv[1].tv_sec = statbuf->st_mtime;
124    tv[1].tv_usec = 0;
125    result = utimes (destination, tv);
126#endif /* HAVE_UTIMES */
127#endif /* ! HAVE_GOOD_UTIME_H */
128  }
129
130  if (result != 0)
131    non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
132}
133
134#ifndef S_ISLNK
135#ifdef S_IFLNK
136#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
137#else
138#define S_ISLNK(m) 0
139#define lstat stat
140#endif
141#endif
142
143/* Rename FROM to TO, copying if TO is a link.
144   Return 0 if ok, -1 if error.  */
145
146int
147smart_rename (from, to, preserve_dates)
148     const char *from;
149     const char *to;
150     int preserve_dates;
151{
152  boolean exists;
153  struct stat s;
154  int ret = 0;
155
156  exists = lstat (to, &s) == 0;
157
158#if defined (_WIN32) && !defined (__CYGWIN32__)
159  /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
160     fail instead.  Also, chown is not present.  */
161
162  if (exists)
163    remove (to);
164
165  ret = rename (from, to);
166  if (ret != 0)
167    {
168      /* We have to clean up here.  */
169
170      non_fatal (_("%s: rename: %s"), to, strerror (errno));
171      unlink (from);
172    }
173#else
174  /* Use rename only if TO is not a symbolic link and has
175     only one hard link.  */
176  if (! exists || (!S_ISLNK (s.st_mode) && s.st_nlink == 1))
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 (_("%s: rename: %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 (_("%s: simple_copy: %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