Home | History | Annotate | Download | only in lib
      1 /* Work around rename bugs in some systems.  On SunOS 4.1.1_U1
      2    and mips-dec-ultrix4.4, rename fails when the source file has
      3    a trailing slash.  On mingw, rename fails when the destination
      4    exists.
      5 
      6    Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
      7 
      8    This program is free software: you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     20 
     21 /* written by Volker Borchert */
     22 
     23 #include <config.h>
     24 #undef rename
     25 
     26 #if RENAME_DEST_EXISTS_BUG
     27 /* This replacement must come first, otherwise when cross
     28  * compiling to Windows we will guess that it has the trailing
     29  * slash bug and entirely miss this one. */
     30 #include <errno.h>
     31 
     32 #define WIN32_LEAN_AND_MEAN
     33 #include <windows.h>
     34 
     35 /* Rename the file SRC to DST.  This replacement is necessary on
     36    Windows, on which the system rename function will not replace
     37    an existing DST.  */
     38 int
     39 rpl_rename (char const *src, char const *dst)
     40 {
     41   int error;
     42 
     43   /* MoveFileEx works if SRC is a directory without any flags,
     44      but fails with MOVEFILE_REPLACE_EXISTING, so try without
     45      flags first. */
     46   if (MoveFileEx (src, dst, 0))
     47     return 0;
     48 
     49   /* Retry with MOVEFILE_REPLACE_EXISTING if the move failed
     50    * due to the destination already existing. */
     51   error = GetLastError ();
     52   if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS)
     53     {
     54       if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING))
     55         return 0;
     56 
     57       error = GetLastError ();
     58     }
     59 
     60   switch (error)
     61     {
     62     case ERROR_FILE_NOT_FOUND:
     63     case ERROR_PATH_NOT_FOUND:
     64     case ERROR_BAD_PATHNAME:
     65     case ERROR_DIRECTORY:
     66       errno = ENOENT;
     67       break;
     68 
     69     case ERROR_ACCESS_DENIED:
     70     case ERROR_SHARING_VIOLATION:
     71       errno = EACCES;
     72       break;
     73 
     74     case ERROR_OUTOFMEMORY:
     75       errno = ENOMEM;
     76       break;
     77 
     78     case ERROR_CURRENT_DIRECTORY:
     79       errno = EBUSY;
     80       break;
     81 
     82     case ERROR_NOT_SAME_DEVICE:
     83       errno = EXDEV;
     84       break;
     85 
     86     case ERROR_WRITE_PROTECT:
     87       errno = EROFS;
     88       break;
     89 
     90     case ERROR_WRITE_FAULT:
     91     case ERROR_READ_FAULT:
     92     case ERROR_GEN_FAILURE:
     93       errno = EIO;
     94       break;
     95 
     96     case ERROR_HANDLE_DISK_FULL:
     97     case ERROR_DISK_FULL:
     98     case ERROR_DISK_TOO_FRAGMENTED:
     99       errno = ENOSPC;
    100       break;
    101 
    102     case ERROR_FILE_EXISTS:
    103     case ERROR_ALREADY_EXISTS:
    104       errno = EEXIST;
    105       break;
    106 
    107     case ERROR_BUFFER_OVERFLOW:
    108     case ERROR_FILENAME_EXCED_RANGE:
    109       errno = ENAMETOOLONG;
    110       break;
    111 
    112     case ERROR_INVALID_NAME:
    113     case ERROR_DELETE_PENDING:
    114       errno = EPERM;        /* ? */
    115       break;
    116 
    117 #ifndef ERROR_FILE_TOO_LARGE
    118 /* This value is documented but not defined in all versions of windows.h. */
    119 #define ERROR_FILE_TOO_LARGE 223
    120 #endif
    121     case ERROR_FILE_TOO_LARGE:
    122       errno = EFBIG;
    123       break;
    124 
    125     default:
    126       errno = EINVAL;
    127       break;
    128     }
    129 
    130   return -1;
    131 }
    132 #elif RENAME_TRAILING_SLASH_BUG
    133 #include <stdio.h>
    134 #include <stdlib.h>
    135 #include <string.h>
    136 
    137 #include "dirname.h"
    138 #include "xalloc.h"
    139 
    140 /* Rename the file SRC to DST, removing any trailing
    141    slashes from SRC.  Needed for SunOS 4.1.1_U1.  */
    142 
    143 int
    144 rpl_rename (char const *src, char const *dst)
    145 {
    146   char *src_temp;
    147   int ret_val;
    148   size_t s_len = strlen (src);
    149 
    150   if (s_len && src[s_len - 1] == '/')
    151     {
    152       src_temp = xstrdup (src);
    153       strip_trailing_slashes (src_temp);
    154     }
    155   else
    156     src_temp = (char *) src;
    157 
    158   ret_val = rename (src_temp, dst);
    159 
    160   if (src_temp != src)
    161     free (src_temp);
    162 
    163   return ret_val;
    164 }
    165 #endif /* RENAME_TRAILING_SLASH_BUG */
    166