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