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
rpl_rename(char const * src,char const * dst)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
rpl_rename(char const * src,char const * dst)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