(root)/
m4-1.4.19/
lib/
rename.c
       1  /* Work around rename bugs in some systems.
       2  
       3     Copyright (C) 2001-2003, 2005-2006, 2009-2021 Free Software Foundation, Inc.
       4  
       5     This program is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published by
       7     the Free Software Foundation; either version 3 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Written by Volker Borchert, Eric Blake.  */
      19  
      20  #include <config.h>
      21  
      22  #include <stdio.h>
      23  
      24  #undef rename
      25  
      26  #if defined _WIN32 && ! defined __CYGWIN__
      27  /* The mingw rename has problems with trailing slashes; it also
      28     requires use of native Windows calls to allow atomic renames over
      29     existing files.  */
      30  
      31  # include <errno.h>
      32  # include <stdbool.h>
      33  # include <stdlib.h>
      34  # include <sys/stat.h>
      35  # include <unistd.h>
      36  
      37  # define WIN32_LEAN_AND_MEAN
      38  # include <windows.h>
      39  
      40  # include "dirname.h"
      41  
      42  /* Don't assume that UNICODE is not defined.  */
      43  # undef MoveFileEx
      44  # define MoveFileEx MoveFileExA
      45  
      46  /* Rename the file SRC to DST.  This replacement is necessary on
      47     Windows, on which the system rename function will not replace
      48     an existing DST.  */
      49  int
      50  rpl_rename (char const *src, char const *dst)
      51  {
      52    int error;
      53    size_t src_len = strlen (src);
      54    size_t dst_len = strlen (dst);
      55    char *src_base = last_component (src);
      56    char *dst_base = last_component (dst);
      57    bool src_slash;
      58    bool dst_slash;
      59    bool dst_exists;
      60    struct stat src_st;
      61    struct stat dst_st;
      62  
      63    /* Filter out dot as last component.  */
      64    if (!src_len || !dst_len)
      65      {
      66        errno = ENOENT;
      67        return -1;
      68      }
      69    if (*src_base == '.')
      70      {
      71        size_t len = base_len (src_base);
      72        if (len == 1 || (len == 2 && src_base[1] == '.'))
      73          {
      74            errno = EINVAL;
      75            return -1;
      76          }
      77      }
      78    if (*dst_base == '.')
      79      {
      80        size_t len = base_len (dst_base);
      81        if (len == 1 || (len == 2 && dst_base[1] == '.'))
      82          {
      83            errno = EINVAL;
      84            return -1;
      85          }
      86      }
      87  
      88    /* Presence of a trailing slash requires directory semantics.  If
      89       the source does not exist, or if the destination cannot be turned
      90       into a directory, give up now.  Otherwise, strip trailing slashes
      91       before calling rename.  There are no symlinks on mingw, so stat
      92       works instead of lstat.  */
      93    src_slash = ISSLASH (src[src_len - 1]);
      94    dst_slash = ISSLASH (dst[dst_len - 1]);
      95    if (stat (src, &src_st))
      96      return -1;
      97    if (stat (dst, &dst_st))
      98      {
      99        if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
     100          return -1;
     101        dst_exists = false;
     102      }
     103    else
     104      {
     105        if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
     106          {
     107            errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
     108            return -1;
     109          }
     110        dst_exists = true;
     111      }
     112  
     113    /* There are no symlinks, so if a file existed with a trailing
     114       slash, it must be a directory, and we don't have to worry about
     115       stripping strip trailing slash.  However, mingw refuses to
     116       replace an existing empty directory, so we have to help it out.
     117       And canonicalize_file_name is not yet ported to mingw; however,
     118       for directories, getcwd works as a viable alternative.  Ensure
     119       that we can get back to where we started before using it; later
     120       attempts to return are fatal.  Note that we can end up losing a
     121       directory if rename then fails, but it was empty, so not much
     122       damage was done.  */
     123    if (dst_exists && S_ISDIR (dst_st.st_mode))
     124      {
     125        char *cwd = getcwd (NULL, 0);
     126        char *src_temp;
     127        char *dst_temp;
     128        if (!cwd || chdir (cwd))
     129          return -1;
     130        if (IS_ABSOLUTE_FILE_NAME (src))
     131          {
     132            dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
     133            src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
     134          }
     135        else
     136          {
     137            src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
     138            if (!IS_ABSOLUTE_FILE_NAME (dst) && chdir (cwd))
     139              abort ();
     140            dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
     141          }
     142        if (chdir (cwd))
     143          abort ();
     144        free (cwd);
     145        if (!src_temp || !dst_temp)
     146          {
     147            free (src_temp);
     148            free (dst_temp);
     149            errno = ENOMEM;
     150            return -1;
     151          }
     152        src_len = strlen (src_temp);
     153        if (strncmp (src_temp, dst_temp, src_len) == 0
     154            && (ISSLASH (dst_temp[src_len]) || dst_temp[src_len] == '\0'))
     155          {
     156            error = dst_temp[src_len];
     157            free (src_temp);
     158            free (dst_temp);
     159            if (error)
     160              {
     161                errno = EINVAL;
     162                return -1;
     163              }
     164            return 0;
     165          }
     166        if (rmdir (dst))
     167          {
     168            free (src_temp);
     169            free (dst_temp);
     170            return -1;
     171          }
     172        free (src_temp);
     173        free (dst_temp);
     174      }
     175  
     176    /* MoveFileEx works if SRC is a directory without any flags, but
     177       fails with MOVEFILE_REPLACE_EXISTING, so try without flags first.
     178       Thankfully, MoveFileEx handles hard links correctly, even though
     179       rename() does not.  */
     180    if (MoveFileEx (src, dst, 0))
     181      return 0;
     182  
     183    /* Retry with MOVEFILE_REPLACE_EXISTING if the move failed
     184       due to the destination already existing.  */
     185    error = GetLastError ();
     186    if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS)
     187      {
     188        if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING))
     189          return 0;
     190  
     191        error = GetLastError ();
     192      }
     193  
     194    switch (error)
     195      {
     196      case ERROR_FILE_NOT_FOUND:
     197      case ERROR_PATH_NOT_FOUND:
     198      case ERROR_BAD_PATHNAME:
     199      case ERROR_DIRECTORY:
     200        errno = ENOENT;
     201        break;
     202  
     203      case ERROR_ACCESS_DENIED:
     204      case ERROR_SHARING_VIOLATION:
     205        errno = EACCES;
     206        break;
     207  
     208      case ERROR_OUTOFMEMORY:
     209        errno = ENOMEM;
     210        break;
     211  
     212      case ERROR_CURRENT_DIRECTORY:
     213        errno = EBUSY;
     214        break;
     215  
     216      case ERROR_NOT_SAME_DEVICE:
     217        errno = EXDEV;
     218        break;
     219  
     220      case ERROR_WRITE_PROTECT:
     221        errno = EROFS;
     222        break;
     223  
     224      case ERROR_WRITE_FAULT:
     225      case ERROR_READ_FAULT:
     226      case ERROR_GEN_FAILURE:
     227        errno = EIO;
     228        break;
     229  
     230      case ERROR_HANDLE_DISK_FULL:
     231      case ERROR_DISK_FULL:
     232      case ERROR_DISK_TOO_FRAGMENTED:
     233        errno = ENOSPC;
     234        break;
     235  
     236      case ERROR_FILE_EXISTS:
     237      case ERROR_ALREADY_EXISTS:
     238        errno = EEXIST;
     239        break;
     240  
     241      case ERROR_BUFFER_OVERFLOW:
     242      case ERROR_FILENAME_EXCED_RANGE:
     243        errno = ENAMETOOLONG;
     244        break;
     245  
     246      case ERROR_INVALID_NAME:
     247      case ERROR_DELETE_PENDING:
     248        errno = EPERM;        /* ? */
     249        break;
     250  
     251  # ifndef ERROR_FILE_TOO_LARGE
     252  /* This value is documented but not defined in all versions of windows.h.  */
     253  #  define ERROR_FILE_TOO_LARGE 223
     254  # endif
     255      case ERROR_FILE_TOO_LARGE:
     256        errno = EFBIG;
     257        break;
     258  
     259      default:
     260        errno = EINVAL;
     261        break;
     262      }
     263  
     264    return -1;
     265  }
     266  
     267  #else /* ! W32 platform */
     268  
     269  # include <errno.h>
     270  # include <stdio.h>
     271  # include <stdlib.h>
     272  # include <string.h>
     273  # include <sys/stat.h>
     274  # include <unistd.h>
     275  
     276  # include "dirname.h"
     277  # include "same-inode.h"
     278  
     279  /* Rename the file SRC to DST, fixing any trailing slash bugs.  */
     280  
     281  int
     282  rpl_rename (char const *src, char const *dst)
     283  {
     284    size_t src_len = strlen (src);
     285    size_t dst_len = strlen (dst);
     286    char *src_temp = (char *) src;
     287    char *dst_temp = (char *) dst;
     288    bool src_slash;
     289    bool dst_slash;
     290    bool dst_exists _GL_UNUSED;
     291    int ret_val = -1;
     292    int rename_errno = ENOTDIR;
     293    struct stat src_st;
     294    struct stat dst_st;
     295  
     296    if (!src_len || !dst_len)
     297      return rename (src, dst); /* Let strace see the ENOENT failure.  */
     298  
     299  # if RENAME_DEST_EXISTS_BUG
     300    {
     301      char *src_base = last_component (src);
     302      char *dst_base = last_component (dst);
     303      if (*src_base == '.')
     304        {
     305          size_t len = base_len (src_base);
     306          if (len == 1 || (len == 2 && src_base[1] == '.'))
     307            {
     308              errno = EINVAL;
     309              return -1;
     310            }
     311        }
     312      if (*dst_base == '.')
     313        {
     314          size_t len = base_len (dst_base);
     315          if (len == 1 || (len == 2 && dst_base[1] == '.'))
     316            {
     317              errno = EINVAL;
     318              return -1;
     319            }
     320        }
     321    }
     322  # endif /* RENAME_DEST_EXISTS_BUG */
     323  
     324    src_slash = src[src_len - 1] == '/';
     325    dst_slash = dst[dst_len - 1] == '/';
     326  
     327  # if !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG
     328    /* If there are no trailing slashes, then trust the native
     329       implementation unless we also suspect issues with hard link
     330       detection or file/directory conflicts.  */
     331    if (!src_slash && !dst_slash)
     332      return rename (src, dst);
     333  # endif /* !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG */
     334  
     335    /* Presence of a trailing slash requires directory semantics.  If
     336       the source does not exist, or if the destination cannot be turned
     337       into a directory, give up now.  Otherwise, strip trailing slashes
     338       before calling rename.  */
     339    if (lstat (src, &src_st))
     340      return -1;
     341    if (lstat (dst, &dst_st))
     342      {
     343        if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
     344          return -1;
     345        dst_exists = false;
     346      }
     347    else
     348      {
     349        if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
     350          {
     351            errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
     352            return -1;
     353          }
     354  # if RENAME_HARD_LINK_BUG
     355        if (SAME_INODE (src_st, dst_st))
     356          return 0;
     357  # endif /* RENAME_HARD_LINK_BUG */
     358        dst_exists = true;
     359      }
     360  
     361  # if (RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG        \
     362        || RENAME_HARD_LINK_BUG)
     363    /* If the only bug was that a trailing slash was allowed on a
     364       non-existing file destination, as in Solaris 10, then we've
     365       already covered that situation.  But if there is any problem with
     366       a trailing slash on an existing source or destination, as in
     367       Solaris 9, or if a directory can overwrite a symlink, as on
     368       Cygwin 1.5, or if directories cannot be created with trailing
     369       slash, as on NetBSD 1.6, then we must strip the offending slash
     370       and check that we have not encountered a symlink instead of a
     371       directory.
     372  
     373       Stripping a trailing slash interferes with POSIX semantics, where
     374       rename behavior on a symlink with a trailing slash operates on
     375       the corresponding target directory.  We prefer the GNU semantics
     376       of rejecting any use of a symlink with trailing slash, but do not
     377       enforce them, since Solaris 10 is able to obey POSIX semantics
     378       and there might be clients expecting it, as counter-intuitive as
     379       those semantics are.
     380  
     381       Technically, we could also follow the POSIX behavior by chasing a
     382       readlink trail, but that is harder to implement.  */
     383    if (src_slash)
     384      {
     385        src_temp = strdup (src);
     386        if (!src_temp)
     387          {
     388            /* Rather than rely on strdup-posix, we set errno ourselves.  */
     389            rename_errno = ENOMEM;
     390            goto out;
     391          }
     392        strip_trailing_slashes (src_temp);
     393        if (lstat (src_temp, &src_st))
     394          {
     395            rename_errno = errno;
     396            goto out;
     397          }
     398        if (S_ISLNK (src_st.st_mode))
     399          goto out;
     400      }
     401    if (dst_slash)
     402      {
     403        dst_temp = strdup (dst);
     404        if (!dst_temp)
     405          {
     406            rename_errno = ENOMEM;
     407            goto out;
     408          }
     409        strip_trailing_slashes (dst_temp);
     410        if (lstat (dst_temp, &dst_st))
     411          {
     412            if (errno != ENOENT)
     413              {
     414                rename_errno = errno;
     415                goto out;
     416              }
     417          }
     418        else if (S_ISLNK (dst_st.st_mode))
     419          goto out;
     420      }
     421  # endif /* RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG
     422             || RENAME_HARD_LINK_BUG */
     423  
     424  # if RENAME_DEST_EXISTS_BUG
     425    /* Cygwin 1.5 sometimes behaves oddly when moving a non-empty
     426       directory on top of an empty one (the old directory name can
     427       reappear if the new directory tree is removed).  Work around this
     428       by removing the target first, but don't remove the target if it
     429       is a subdirectory of the source.  Note that we can end up losing
     430       a directory if rename then fails, but it was empty, so not much
     431       damage was done.  */
     432    if (dst_exists && S_ISDIR (dst_st.st_mode))
     433      {
     434        if (src_st.st_dev != dst_st.st_dev)
     435          {
     436            rename_errno = EXDEV;
     437            goto out;
     438          }
     439        if (src_temp != src)
     440          free (src_temp);
     441        src_temp = canonicalize_file_name (src);
     442        if (dst_temp != dst)
     443          free (dst_temp);
     444        dst_temp = canonicalize_file_name (dst);
     445        if (!src_temp || !dst_temp)
     446          {
     447            rename_errno = ENOMEM;
     448            goto out;
     449          }
     450        src_len = strlen (src_temp);
     451        if (strncmp (src_temp, dst_temp, src_len) == 0
     452            && dst_temp[src_len] == '/')
     453          {
     454            rename_errno = EINVAL;
     455            goto out;
     456          }
     457        if (rmdir (dst))
     458          {
     459            rename_errno = errno;
     460            goto out;
     461          }
     462      }
     463  # endif /* RENAME_DEST_EXISTS_BUG */
     464  
     465    ret_val = rename (src_temp, dst_temp);
     466    rename_errno = errno;
     467  
     468   out: _GL_UNUSED_LABEL;
     469  
     470    if (src_temp != src)
     471      free (src_temp);
     472    if (dst_temp != dst)
     473      free (dst_temp);
     474    errno = rename_errno;
     475    return ret_val;
     476  }
     477  #endif /* ! W32 platform */