(root)/
binutils-2.41/
binutils/
rename.c
       1  /* rename.c -- rename a file, preserving symlinks.
       2     Copyright (C) 1999-2023 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
      19     02110-1301, USA.  */
      20  
      21  #include "sysdep.h"
      22  #include "bfd.h"
      23  #include "bucomm.h"
      24  
      25  #if defined HAVE_UTIMES
      26  #include <sys/time.h>
      27  #elif defined HAVE_GOOD_UTIME_H
      28  #include <utime.h>
      29  #endif
      30  
      31  /* The number of bytes to copy at once.  */
      32  #define COPY_BUF 8192
      33  
      34  /* Copy file FROMFD to file TO, performing no translations.
      35     Return 0 if ok, -1 if error.  */
      36  
      37  static int
      38  simple_copy (int fromfd, const char *to,
      39  	     struct stat *target_stat ATTRIBUTE_UNUSED)
      40  {
      41    int tofd, nread;
      42    int saved;
      43    char buf[COPY_BUF];
      44  
      45    if (fromfd < 0
      46        || lseek (fromfd, 0, SEEK_SET) != 0)
      47      return -1;
      48  
      49    tofd = open (to, O_WRONLY | O_TRUNC | O_BINARY);
      50    if (tofd < 0)
      51      {
      52        saved = errno;
      53        close (fromfd);
      54        errno = saved;
      55        return -1;
      56      }
      57  
      58    while ((nread = read (fromfd, buf, sizeof buf)) > 0)
      59      {
      60        if (write (tofd, buf, nread) != nread)
      61  	{
      62  	  saved = errno;
      63  	  close (fromfd);
      64  	  close (tofd);
      65  	  errno = saved;
      66  	  return -1;
      67  	}
      68      }
      69  
      70    saved = errno;
      71  
      72  #if !defined (_WIN32) || defined (__CYGWIN32__)
      73    /* Writing to a setuid/setgid file may clear S_ISUID and S_ISGID.
      74       Try to restore them, ignoring failure.  */
      75    if (target_stat != NULL)
      76      fchmod (tofd, target_stat->st_mode);
      77  #endif
      78  
      79    close (fromfd);
      80    close (tofd);
      81    if (nread < 0)
      82      {
      83        errno = saved;
      84        return -1;
      85      }
      86    return 0;
      87  }
      88  
      89  /* The following defines and inline functions are copied from gnulib.
      90     FIXME: Use a gnulib import and stat-time.h instead.  */
      91  #if defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
      92  # if defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
      93  #  define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
      94  # else
      95  #  define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec)
      96  # endif
      97  #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
      98  # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec)
      99  #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC
     100  # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec)
     101  #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC
     102  # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec)
     103  #endif
     104  
     105  static inline long int get_stat_atime_ns (struct stat const *) ATTRIBUTE_UNUSED;
     106  static inline long int get_stat_mtime_ns (struct stat const *) ATTRIBUTE_UNUSED;
     107  
     108  /* Return the nanosecond component of *ST's access time.  */
     109  static inline long int
     110  get_stat_atime_ns (struct stat const *st ATTRIBUTE_UNUSED)
     111  {
     112  # if defined STAT_TIMESPEC
     113    return STAT_TIMESPEC (st, st_atim).tv_nsec;
     114  # elif defined STAT_TIMESPEC_NS
     115    return STAT_TIMESPEC_NS (st, st_atim);
     116  # else
     117    return 0;
     118  # endif
     119  }
     120  
     121  /* Return the nanosecond component of *ST's data modification time.  */
     122  static inline long int
     123  get_stat_mtime_ns (struct stat const *st ATTRIBUTE_UNUSED)
     124  {
     125  # if defined STAT_TIMESPEC
     126    return STAT_TIMESPEC (st, st_mtim).tv_nsec;
     127  # elif defined STAT_TIMESPEC_NS
     128    return STAT_TIMESPEC_NS (st, st_mtim);
     129  # else
     130    return 0;
     131  # endif
     132  }
     133  
     134  #if defined HAVE_UTIMENSAT
     135  /* Return *ST's access time.  */
     136  static inline struct timespec
     137  get_stat_atime (struct stat const *st)
     138  {
     139  #ifdef STAT_TIMESPEC
     140    return STAT_TIMESPEC (st, st_atim);
     141  #else
     142    struct timespec t;
     143    t.tv_sec = st->st_atime;
     144    t.tv_nsec = get_stat_atime_ns (st);
     145    return t;
     146  #endif
     147  }
     148  
     149  /* Return *ST's data modification time.  */
     150  static inline struct timespec
     151  get_stat_mtime (struct stat const *st)
     152  {
     153  #ifdef STAT_TIMESPEC
     154    return STAT_TIMESPEC (st, st_mtim);
     155  #else
     156    struct timespec t;
     157    t.tv_sec = st->st_mtime;
     158    t.tv_nsec = get_stat_mtime_ns (st);
     159    return t;
     160  #endif
     161  }
     162  #endif
     163  /* End FIXME.  */
     164  
     165  /* Set the times of the file DESTINATION to be the same as those in
     166     STATBUF.  */
     167  
     168  void
     169  set_times (const char *destination, const struct stat *statbuf)
     170  {
     171    int result;
     172  #if defined HAVE_UTIMENSAT
     173    struct timespec times[2];
     174    times[0] = get_stat_atime (statbuf);
     175    times[1] = get_stat_mtime (statbuf);
     176    result = utimensat (AT_FDCWD, destination, times, 0);
     177  #elif defined HAVE_UTIMES
     178    struct timeval tv[2];
     179  
     180    tv[0].tv_sec = statbuf->st_atime;
     181    tv[0].tv_usec = get_stat_atime_ns (statbuf) / 1000;
     182    tv[1].tv_sec = statbuf->st_mtime;
     183    tv[1].tv_usec = get_stat_mtime_ns (statbuf) / 1000;
     184    result = utimes (destination, tv);
     185  #elif defined HAVE_GOOD_UTIME_H
     186    struct utimbuf tb;
     187  
     188    tb.actime = statbuf->st_atime;
     189    tb.modtime = statbuf->st_mtime;
     190    result = utime (destination, &tb);
     191  #else
     192    long tb[2];
     193  
     194    tb[0] = statbuf->st_atime;
     195    tb[1] = statbuf->st_mtime;
     196    result = utime (destination, tb);
     197  #endif
     198  
     199    if (result != 0)
     200      non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
     201  }
     202  
     203  /* Copy FROM to TO.  TARGET_STAT has the file status that, if non-NULL,
     204     is used to fix up timestamps.  Return 0 if ok, -1 if error.
     205     At one time this function renamed files, but file permissions are
     206     tricky to update given the number of different schemes used by
     207     various systems.  So now we just copy.  */
     208  
     209  int
     210  smart_rename (const char *from, const char *to, int fromfd,
     211  	      struct stat *target_stat, bool preserve_dates)
     212  {
     213    int ret = 0;
     214  
     215    if (to != from)
     216      {
     217        ret = simple_copy (fromfd, to, target_stat);
     218        if (ret != 0)
     219  	non_fatal (_("unable to copy file '%s'; reason: %s"),
     220  		   to, strerror (errno));
     221        unlink (from);
     222      }
     223  
     224    if (preserve_dates)
     225      set_times (to, target_stat);
     226  
     227    return ret;
     228  }