rename.c revision 60484
160484Sobrien/* rename.c -- rename a file, preserving symlinks.
260484Sobrien   Copyright (C) 1999 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
1860484Sobrien   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1960484Sobrien   02111-1307, USA.  */
2060484Sobrien
2160484Sobrien#include "bfd.h"
2260484Sobrien#include "bucomm.h"
2360484Sobrien
2460484Sobrien#include <sys/stat.h>
2560484Sobrien
2660484Sobrien#ifdef HAVE_GOOD_UTIME_H
2760484Sobrien#include <utime.h>
2860484Sobrien#else /* ! HAVE_GOOD_UTIME_H */
2960484Sobrien#ifdef HAVE_UTIMES
3060484Sobrien#include <sys/time.h>
3160484Sobrien#endif /* HAVE_UTIMES */
3260484Sobrien#endif /* ! HAVE_GOOD_UTIME_H */
3360484Sobrien
3460484Sobrien/* We need to open the file in binary modes on system where that makes
3560484Sobrien   a difference.  */
3660484Sobrien#ifndef O_BINARY
3760484Sobrien#define O_BINARY 0
3860484Sobrien#endif
3960484Sobrien
4060484Sobrienstatic int simple_copy PARAMS ((const char *, const char *));
4160484Sobrien
4260484Sobrien/* The number of bytes to copy at once.  */
4360484Sobrien#define COPY_BUF 8192
4460484Sobrien
4560484Sobrien/* Copy file FROM to file TO, performing no translations.
4660484Sobrien   Return 0 if ok, -1 if error.  */
4760484Sobrien
4860484Sobrienstatic int
4960484Sobriensimple_copy (from, to)
5060484Sobrien     const char *from;
5160484Sobrien     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}
9360484Sobrien
9460484Sobrien/* Set the times of the file DESTINATION to be the same as those in
9560484Sobrien   STATBUF.  */
9660484Sobrien
9760484Sobrienvoid
9860484Sobrienset_times (destination, statbuf)
9960484Sobrien     const char *destination;
10060484Sobrien     const struct stat *statbuf;
10160484Sobrien{
10260484Sobrien  int result;
10360484Sobrien
10460484Sobrien  {
10560484Sobrien#ifdef HAVE_GOOD_UTIME_H
10660484Sobrien    struct utimbuf tb;
10760484Sobrien
10860484Sobrien    tb.actime = statbuf->st_atime;
10960484Sobrien    tb.modtime = statbuf->st_mtime;
11060484Sobrien    result = utime (destination, &tb);
11160484Sobrien#else /* ! HAVE_GOOD_UTIME_H */
11260484Sobrien#ifndef HAVE_UTIMES
11360484Sobrien    long tb[2];
11460484Sobrien
11560484Sobrien    tb[0] = statbuf->st_atime;
11660484Sobrien    tb[1] = statbuf->st_mtime;
11760484Sobrien    result = utime (destination, tb);
11860484Sobrien#else /* HAVE_UTIMES */
11960484Sobrien    struct timeval tv[2];
12060484Sobrien
12160484Sobrien    tv[0].tv_sec = statbuf->st_atime;
12260484Sobrien    tv[0].tv_usec = 0;
12360484Sobrien    tv[1].tv_sec = statbuf->st_mtime;
12460484Sobrien    tv[1].tv_usec = 0;
12560484Sobrien    result = utimes (destination, tv);
12660484Sobrien#endif /* HAVE_UTIMES */
12760484Sobrien#endif /* ! HAVE_GOOD_UTIME_H */
12860484Sobrien  }
12960484Sobrien
13060484Sobrien  if (result != 0)
13160484Sobrien    non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
13260484Sobrien}
13360484Sobrien
13460484Sobrien#ifndef S_ISLNK
13560484Sobrien#ifdef S_IFLNK
13660484Sobrien#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
13760484Sobrien#else
13860484Sobrien#define S_ISLNK(m) 0
13960484Sobrien#define lstat stat
14060484Sobrien#endif
14160484Sobrien#endif
14260484Sobrien
14360484Sobrien/* Rename FROM to TO, copying if TO is a link.
14460484Sobrien   Return 0 if ok, -1 if error.  */
14560484Sobrien
14660484Sobrienint
14760484Sobriensmart_rename (from, to, preserve_dates)
14860484Sobrien     const char *from;
14960484Sobrien     const char *to;
15060484Sobrien     int preserve_dates;
15160484Sobrien{
15260484Sobrien  boolean exists;
15360484Sobrien  struct stat s;
15460484Sobrien  int ret = 0;
15560484Sobrien
15660484Sobrien  exists = lstat (to, &s) == 0;
15760484Sobrien
15860484Sobrien#if defined (_WIN32) && !defined (__CYGWIN32__)
15960484Sobrien  /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
16060484Sobrien     fail instead.  Also, chown is not present.  */
16160484Sobrien
16260484Sobrien  if (exists)
16360484Sobrien    remove (to);
16460484Sobrien
16560484Sobrien  ret = rename (from, to);
16660484Sobrien  if (ret != 0)
16760484Sobrien    {
16860484Sobrien      /* We have to clean up here. */
16960484Sobrien
17060484Sobrien      non_fatal (_("%s: rename: %s"), to, strerror (errno));
17160484Sobrien      unlink (from);
17260484Sobrien    }
17360484Sobrien#else
17460484Sobrien  /* Use rename only if TO is not a symbolic link and has
17560484Sobrien     only one hard link.  */
17660484Sobrien  if (! exists || (!S_ISLNK (s.st_mode) && s.st_nlink == 1))
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	{
20260484Sobrien	  /* We have to clean up here. */
20360484Sobrien	  non_fatal (_("%s: rename: %s"), to, strerror (errno));
20460484Sobrien	  unlink (from);
20560484Sobrien	}
20660484Sobrien    }
20760484Sobrien  else
20860484Sobrien    {
20960484Sobrien      ret = simple_copy (from, to);
21060484Sobrien      if (ret != 0)
21160484Sobrien	non_fatal (_("%s: simple_copy: %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