blob: b27fd9100d02a5bb7ac62c75e1a92a03ebc75b69 [file] [log] [blame]
/* Work around rename bugs in some systems. On SunOS 4.1.1_U1
and mips-dec-ultrix4.4, rename fails when the source file has
a trailing slash. On mingw, rename fails when the destination
exists.
Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* written by Volker Borchert */
#include <config.h>
#undef rename
#if RENAME_DEST_EXISTS_BUG
/* This replacement must come first, otherwise when cross
* compiling to Windows we will guess that it has the trailing
* slash bug and entirely miss this one. */
#include <errno.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* Rename the file SRC to DST. This replacement is necessary on
Windows, on which the system rename function will not replace
an existing DST. */
int
rpl_rename (char const *src, char const *dst)
{
int error;
/* MoveFileEx works if SRC is a directory without any flags,
but fails with MOVEFILE_REPLACE_EXISTING, so try without
flags first. */
if (MoveFileEx (src, dst, 0))
return 0;
/* Retry with MOVEFILE_REPLACE_EXISTING if the move failed
* due to the destination already existing. */
error = GetLastError ();
if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS)
{
if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING))
return 0;
error = GetLastError ();
}
switch (error)
{
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_BAD_PATHNAME:
case ERROR_DIRECTORY:
errno = ENOENT;
break;
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
errno = EACCES;
break;
case ERROR_OUTOFMEMORY:
errno = ENOMEM;
break;
case ERROR_CURRENT_DIRECTORY:
errno = EBUSY;
break;
case ERROR_NOT_SAME_DEVICE:
errno = EXDEV;
break;
case ERROR_WRITE_PROTECT:
errno = EROFS;
break;
case ERROR_WRITE_FAULT:
case ERROR_READ_FAULT:
case ERROR_GEN_FAILURE:
errno = EIO;
break;
case ERROR_HANDLE_DISK_FULL:
case ERROR_DISK_FULL:
case ERROR_DISK_TOO_FRAGMENTED:
errno = ENOSPC;
break;
case ERROR_FILE_EXISTS:
case ERROR_ALREADY_EXISTS:
errno = EEXIST;
break;
case ERROR_BUFFER_OVERFLOW:
case ERROR_FILENAME_EXCED_RANGE:
errno = ENAMETOOLONG;
break;
case ERROR_INVALID_NAME:
case ERROR_DELETE_PENDING:
errno = EPERM; /* ? */
break;
#ifndef ERROR_FILE_TOO_LARGE
/* This value is documented but not defined in all versions of windows.h. */
#define ERROR_FILE_TOO_LARGE 223
#endif
case ERROR_FILE_TOO_LARGE:
errno = EFBIG;
break;
default:
errno = EINVAL;
break;
}
return -1;
}
#elif RENAME_TRAILING_SLASH_BUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dirname.h"
#include "xalloc.h"
/* Rename the file SRC to DST, removing any trailing
slashes from SRC. Needed for SunOS 4.1.1_U1. */
int
rpl_rename (char const *src, char const *dst)
{
char *src_temp;
int ret_val;
size_t s_len = strlen (src);
if (s_len && src[s_len - 1] == '/')
{
src_temp = xstrdup (src);
strip_trailing_slashes (src_temp);
}
else
src_temp = (char *) src;
ret_val = rename (src_temp, dst);
if (src_temp != src)
free (src_temp);
return ret_val;
}
#endif /* RENAME_TRAILING_SLASH_BUG */