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