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