160484Sobrien/* rename.c -- rename a file, preserving symlinks.
2218822Sdim   Copyright 1999, 2002, 2003, 2007 Free Software Foundation, Inc.
360484Sobrien
460484Sobrien   This file is part of GNU Binutils.
560484Sobrien
660484Sobrien   This program is free software; you can redistribute it and/or modify
760484Sobrien   it under the terms of the GNU General Public License as published by
860484Sobrien   the Free Software Foundation; either version 2 of the License, or
960484Sobrien   (at your option) any later version.
1060484Sobrien
1160484Sobrien   This program is distributed in the hope that it will be useful,
1260484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1360484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1460484Sobrien   GNU General Public License for more details.
1560484Sobrien
1660484Sobrien   You should have received a copy of the GNU General Public License
1760484Sobrien   along with this program; if not, write to the Free Software
18218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19218822Sdim   02110-1301, USA.  */
2060484Sobrien
21218822Sdim#include "sysdep.h"
2260484Sobrien#include "bfd.h"
2360484Sobrien#include "bucomm.h"
2460484Sobrien
2560484Sobrien#include <sys/stat.h>
2660484Sobrien
2760484Sobrien#ifdef HAVE_GOOD_UTIME_H
2860484Sobrien#include <utime.h>
2960484Sobrien#else /* ! HAVE_GOOD_UTIME_H */
3060484Sobrien#ifdef HAVE_UTIMES
3160484Sobrien#include <sys/time.h>
3260484Sobrien#endif /* HAVE_UTIMES */
3360484Sobrien#endif /* ! HAVE_GOOD_UTIME_H */
3460484Sobrien
3560484Sobrien/* We need to open the file in binary modes on system where that makes
3660484Sobrien   a difference.  */
3760484Sobrien#ifndef O_BINARY
3860484Sobrien#define O_BINARY 0
3960484Sobrien#endif
4060484Sobrien
41218822Sdim#if ! defined (_WIN32) || defined (__CYGWIN32__)
42130561Sobrienstatic int simple_copy (const char *, const char *);
4360484Sobrien
4460484Sobrien/* The number of bytes to copy at once.  */
4560484Sobrien#define COPY_BUF 8192
4660484Sobrien
4760484Sobrien/* Copy file FROM to file TO, performing no translations.
4860484Sobrien   Return 0 if ok, -1 if error.  */
4960484Sobrien
5060484Sobrienstatic int
51130561Sobriensimple_copy (const char *from, const char *to)
5260484Sobrien{
5360484Sobrien  int fromfd, tofd, nread;
5460484Sobrien  int saved;
5560484Sobrien  char buf[COPY_BUF];
5660484Sobrien
5760484Sobrien  fromfd = open (from, O_RDONLY | O_BINARY);
5860484Sobrien  if (fromfd < 0)
5960484Sobrien    return -1;
6060484Sobrien#ifdef O_CREAT
6160484Sobrien  tofd = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0777);
6260484Sobrien#else
6360484Sobrien  tofd = creat (to, 0777);
6460484Sobrien#endif
6560484Sobrien  if (tofd < 0)
6660484Sobrien    {
6760484Sobrien      saved = errno;
6860484Sobrien      close (fromfd);
6960484Sobrien      errno = saved;
7060484Sobrien      return -1;
7160484Sobrien    }
7260484Sobrien  while ((nread = read (fromfd, buf, sizeof buf)) > 0)
7360484Sobrien    {
7460484Sobrien      if (write (tofd, buf, nread) != nread)
7560484Sobrien	{
7660484Sobrien	  saved = errno;
7760484Sobrien	  close (fromfd);
7860484Sobrien	  close (tofd);
7960484Sobrien	  errno = saved;
8060484Sobrien	  return -1;
8160484Sobrien	}
8260484Sobrien    }
8360484Sobrien  saved = errno;
8460484Sobrien  close (fromfd);
8560484Sobrien  close (tofd);
8660484Sobrien  if (nread < 0)
8760484Sobrien    {
8860484Sobrien      errno = saved;
8960484Sobrien      return -1;
9060484Sobrien    }
9160484Sobrien  return 0;
9260484Sobrien}
93218822Sdim#endif /* __CYGWIN32__ or not _WIN32 */
9460484Sobrien
9560484Sobrien/* Set the times of the file DESTINATION to be the same as those in
9660484Sobrien   STATBUF.  */
9760484Sobrien
9860484Sobrienvoid
99130561Sobrienset_times (const char *destination, const struct stat *statbuf)
10060484Sobrien{
10160484Sobrien  int result;
10260484Sobrien
10360484Sobrien  {
10460484Sobrien#ifdef HAVE_GOOD_UTIME_H
10560484Sobrien    struct utimbuf tb;
10660484Sobrien
10760484Sobrien    tb.actime = statbuf->st_atime;
10860484Sobrien    tb.modtime = statbuf->st_mtime;
10960484Sobrien    result = utime (destination, &tb);
11060484Sobrien#else /* ! HAVE_GOOD_UTIME_H */
11160484Sobrien#ifndef HAVE_UTIMES
11260484Sobrien    long tb[2];
11360484Sobrien
11460484Sobrien    tb[0] = statbuf->st_atime;
11560484Sobrien    tb[1] = statbuf->st_mtime;
11660484Sobrien    result = utime (destination, tb);
11760484Sobrien#else /* HAVE_UTIMES */
11860484Sobrien    struct timeval tv[2];
11960484Sobrien
12060484Sobrien    tv[0].tv_sec = statbuf->st_atime;
12160484Sobrien    tv[0].tv_usec = 0;
12260484Sobrien    tv[1].tv_sec = statbuf->st_mtime;
12360484Sobrien    tv[1].tv_usec = 0;
12460484Sobrien    result = utimes (destination, tv);
12560484Sobrien#endif /* HAVE_UTIMES */
12660484Sobrien#endif /* ! HAVE_GOOD_UTIME_H */
12760484Sobrien  }
12860484Sobrien
12960484Sobrien  if (result != 0)
13060484Sobrien    non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
13160484Sobrien}
13260484Sobrien
13360484Sobrien#ifndef S_ISLNK
13460484Sobrien#ifdef S_IFLNK
13560484Sobrien#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
13660484Sobrien#else
13760484Sobrien#define S_ISLNK(m) 0
13860484Sobrien#define lstat stat
13960484Sobrien#endif
14060484Sobrien#endif
14160484Sobrien
14260484Sobrien/* Rename FROM to TO, copying if TO is a link.
14360484Sobrien   Return 0 if ok, -1 if error.  */
14460484Sobrien
14560484Sobrienint
146218822Sdimsmart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNUSED)
14760484Sobrien{
148130561Sobrien  bfd_boolean exists;
14960484Sobrien  struct stat s;
15060484Sobrien  int ret = 0;
15160484Sobrien
15260484Sobrien  exists = lstat (to, &s) == 0;
15360484Sobrien
15460484Sobrien#if defined (_WIN32) && !defined (__CYGWIN32__)
15560484Sobrien  /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
15660484Sobrien     fail instead.  Also, chown is not present.  */
15760484Sobrien
15860484Sobrien  if (exists)
15960484Sobrien    remove (to);
16060484Sobrien
16160484Sobrien  ret = rename (from, to);
16260484Sobrien  if (ret != 0)
16360484Sobrien    {
164104834Sobrien      /* We have to clean up here.  */
165130561Sobrien      non_fatal (_("unable to rename '%s' reason: %s"), to, strerror (errno));
16660484Sobrien      unlink (from);
16760484Sobrien    }
16860484Sobrien#else
16960484Sobrien  /* Use rename only if TO is not a symbolic link and has
170130561Sobrien     only one hard link, and we have permission to write to it.  */
171130561Sobrien  if (! exists
172130561Sobrien      || (!S_ISLNK (s.st_mode)
173130561Sobrien	  && S_ISREG (s.st_mode)
174130561Sobrien	  && (s.st_mode & S_IWUSR)
175130561Sobrien	  && s.st_nlink == 1)
176130561Sobrien      )
17760484Sobrien    {
17860484Sobrien      ret = rename (from, to);
17960484Sobrien      if (ret == 0)
18060484Sobrien	{
18160484Sobrien	  if (exists)
18260484Sobrien	    {
18360484Sobrien	      /* Try to preserve the permission bits and ownership of
18460484Sobrien		 TO.  First get the mode right except for the setuid
18560484Sobrien		 bit.  Then change the ownership.  Then fix the setuid
18660484Sobrien		 bit.  We do the chmod before the chown because if the
18760484Sobrien		 chown succeeds, and we are a normal user, we won't be
18860484Sobrien		 able to do the chmod afterward.  We don't bother to
18960484Sobrien		 fix the setuid bit first because that might introduce
19060484Sobrien		 a fleeting security problem, and because the chown
19160484Sobrien		 will clear the setuid bit anyhow.  We only fix the
19260484Sobrien		 setuid bit if the chown succeeds, because we don't
19360484Sobrien		 want to introduce an unexpected setuid file owned by
19460484Sobrien		 the user running objcopy.  */
19560484Sobrien	      chmod (to, s.st_mode & 0777);
19660484Sobrien	      if (chown (to, s.st_uid, s.st_gid) >= 0)
19760484Sobrien		chmod (to, s.st_mode & 07777);
19860484Sobrien	    }
19960484Sobrien	}
20060484Sobrien      else
20160484Sobrien	{
202104834Sobrien	  /* We have to clean up here.  */
203130561Sobrien	  non_fatal (_("unable to rename '%s' reason: %s"), to, strerror (errno));
20460484Sobrien	  unlink (from);
20560484Sobrien	}
20660484Sobrien    }
20760484Sobrien  else
20860484Sobrien    {
20960484Sobrien      ret = simple_copy (from, to);
21060484Sobrien      if (ret != 0)
211130561Sobrien	non_fatal (_("unable to copy file '%s' reason: %s"), to, strerror (errno));
21260484Sobrien
21360484Sobrien      if (preserve_dates)
21460484Sobrien	set_times (to, &s);
21560484Sobrien      unlink (from);
21660484Sobrien    }
21760484Sobrien#endif /* _WIN32 && !__CYGWIN32__ */
21860484Sobrien
21960484Sobrien  return ret;
22060484Sobrien}
221