+ 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;
+}
+
+#else /* ! W32 platform */
+
+# include <errno.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/stat.h>
+# include <unistd.h>
+
+# include "dirname.h"
+# include "same-inode.h"
+
+/* Rename the file SRC to DST, fixing any trailing slash bugs. */
+
+int
+rpl_rename (char const *src, char const *dst)
+{
+ size_t src_len = strlen (src);
+ size_t dst_len = strlen (dst);
+ char *src_temp = (char *) src;
+ char *dst_temp = (char *) dst;
+ bool src_slash;
+ bool dst_slash;
+ bool dst_exists;
+ int ret_val = -1;
+ int rename_errno = ENOTDIR;
+ struct stat src_st;
+ struct stat dst_st;
+
+ if (!src_len || !dst_len)
+ return rename (src, dst); /* Let strace see the ENOENT failure. */
+
+# if RENAME_DEST_EXISTS_BUG
+ {
+ char *src_base = last_component (src);
+ char *dst_base = last_component (dst);
+ if (*src_base == '.')
+ {
+ size_t len = base_len (src_base);
+ if (len == 1 || (len == 2 && src_base[1] == '.'))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ if (*dst_base == '.')
+ {
+ size_t len = base_len (dst_base);
+ if (len == 1 || (len == 2 && dst_base[1] == '.'))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ }
+# endif /* RENAME_DEST_EXISTS_BUG */
+
+ src_slash = src[src_len - 1] == '/';
+ dst_slash = dst[dst_len - 1] == '/';
+
+# if !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG
+ /* If there are no trailing slashes, then trust the native
+ implementation unless we also suspect issues with hard link
+ detection or file/directory conflicts. */
+ if (!src_slash && !dst_slash)
+ return rename (src, dst);
+# endif /* !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG */
+
+ /* Presence of a trailing slash requires directory semantics. If
+ the source does not exist, or if the destination cannot be turned
+ into a directory, give up now. Otherwise, strip trailing slashes
+ before calling rename. */
+ if (lstat (src, &src_st))
+ return -1;
+ if (lstat (dst, &dst_st))
+ {
+ if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
+ return -1;
+ dst_exists = false;