This source file includes following definitions.
- rpl_rename
- rpl_rename
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22 #include <stdio.h>
23
24 #undef rename
25
26 #if defined _WIN32 && ! defined __CYGWIN__
27
28
29
30
31 # include <errno.h>
32 # include <stdbool.h>
33 # include <stdlib.h>
34 # include <sys/stat.h>
35 # include <unistd.h>
36
37 # define WIN32_LEAN_AND_MEAN
38 # include <windows.h>
39
40 # include "dirname.h"
41
42
43 # undef MoveFileEx
44 # define MoveFileEx MoveFileExA
45
46
47
48
49 int
50 rpl_rename (char const *src, char const *dst)
51 {
52 int error;
53 size_t src_len = strlen (src);
54 size_t dst_len = strlen (dst);
55 char *src_base = last_component (src);
56 char *dst_base = last_component (dst);
57 bool src_slash;
58 bool dst_slash;
59 bool dst_exists;
60 struct stat src_st;
61 struct stat dst_st;
62
63
64 if (!src_len || !dst_len)
65 {
66 errno = ENOENT;
67 return -1;
68 }
69 if (*src_base == '.')
70 {
71 size_t len = base_len (src_base);
72 if (len == 1 || (len == 2 && src_base[1] == '.'))
73 {
74 errno = EINVAL;
75 return -1;
76 }
77 }
78 if (*dst_base == '.')
79 {
80 size_t len = base_len (dst_base);
81 if (len == 1 || (len == 2 && dst_base[1] == '.'))
82 {
83 errno = EINVAL;
84 return -1;
85 }
86 }
87
88
89
90
91
92
93 src_slash = ISSLASH (src[src_len - 1]);
94 dst_slash = ISSLASH (dst[dst_len - 1]);
95 if (stat (src, &src_st))
96 return -1;
97 if (stat (dst, &dst_st))
98 {
99 if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
100 return -1;
101 dst_exists = false;
102 }
103 else
104 {
105 if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
106 {
107 errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
108 return -1;
109 }
110 dst_exists = true;
111 }
112
113
114
115
116
117
118
119
120
121
122
123 if (dst_exists && S_ISDIR (dst_st.st_mode))
124 {
125 char *cwd = getcwd (NULL, 0);
126 char *src_temp;
127 char *dst_temp;
128 if (!cwd || chdir (cwd))
129 return -1;
130 if (IS_ABSOLUTE_FILE_NAME (src))
131 {
132 dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
133 src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
134 }
135 else
136 {
137 src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
138 if (!IS_ABSOLUTE_FILE_NAME (dst) && chdir (cwd))
139 abort ();
140 dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
141 }
142 if (chdir (cwd))
143 abort ();
144 free (cwd);
145 if (!src_temp || !dst_temp)
146 {
147 free (src_temp);
148 free (dst_temp);
149 errno = ENOMEM;
150 return -1;
151 }
152 src_len = strlen (src_temp);
153 if (strncmp (src_temp, dst_temp, src_len) == 0
154 && (ISSLASH (dst_temp[src_len]) || dst_temp[src_len] == '\0'))
155 {
156 error = dst_temp[src_len];
157 free (src_temp);
158 free (dst_temp);
159 if (error)
160 {
161 errno = EINVAL;
162 return -1;
163 }
164 return 0;
165 }
166 if (rmdir (dst))
167 {
168 free (src_temp);
169 free (dst_temp);
170 return -1;
171 }
172 free (src_temp);
173 free (dst_temp);
174 }
175
176
177
178
179
180 if (MoveFileEx (src, dst, 0))
181 return 0;
182
183
184
185 error = GetLastError ();
186 if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS)
187 {
188 if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING))
189 return 0;
190
191 error = GetLastError ();
192 }
193
194 switch (error)
195 {
196 case ERROR_FILE_NOT_FOUND:
197 case ERROR_PATH_NOT_FOUND:
198 case ERROR_BAD_PATHNAME:
199 case ERROR_DIRECTORY:
200 errno = ENOENT;
201 break;
202
203 case ERROR_ACCESS_DENIED:
204 case ERROR_SHARING_VIOLATION:
205 errno = EACCES;
206 break;
207
208 case ERROR_OUTOFMEMORY:
209 errno = ENOMEM;
210 break;
211
212 case ERROR_CURRENT_DIRECTORY:
213 errno = EBUSY;
214 break;
215
216 case ERROR_NOT_SAME_DEVICE:
217 errno = EXDEV;
218 break;
219
220 case ERROR_WRITE_PROTECT:
221 errno = EROFS;
222 break;
223
224 case ERROR_WRITE_FAULT:
225 case ERROR_READ_FAULT:
226 case ERROR_GEN_FAILURE:
227 errno = EIO;
228 break;
229
230 case ERROR_HANDLE_DISK_FULL:
231 case ERROR_DISK_FULL:
232 case ERROR_DISK_TOO_FRAGMENTED:
233 errno = ENOSPC;
234 break;
235
236 case ERROR_FILE_EXISTS:
237 case ERROR_ALREADY_EXISTS:
238 errno = EEXIST;
239 break;
240
241 case ERROR_BUFFER_OVERFLOW:
242 case ERROR_FILENAME_EXCED_RANGE:
243 errno = ENAMETOOLONG;
244 break;
245
246 case ERROR_INVALID_NAME:
247 case ERROR_DELETE_PENDING:
248 errno = EPERM;
249 break;
250
251 # ifndef ERROR_FILE_TOO_LARGE
252
253 # define ERROR_FILE_TOO_LARGE 223
254 # endif
255 case ERROR_FILE_TOO_LARGE:
256 errno = EFBIG;
257 break;
258
259 default:
260 errno = EINVAL;
261 break;
262 }
263
264 return -1;
265 }
266
267 #else
268
269 # include <errno.h>
270 # include <stdio.h>
271 # include <stdlib.h>
272 # include <string.h>
273 # include <sys/stat.h>
274 # include <unistd.h>
275
276 # include "dirname.h"
277 # include "same-inode.h"
278
279
280
281 int
282 rpl_rename (char const *src, char const *dst)
283 {
284 size_t src_len = strlen (src);
285 size_t dst_len = strlen (dst);
286 char *src_temp = (char *) src;
287 char *dst_temp = (char *) dst;
288 bool src_slash;
289 bool dst_slash;
290 _GL_UNUSED bool dst_exists;
291 int ret_val = -1;
292 int rename_errno = ENOTDIR;
293 struct stat src_st;
294 struct stat dst_st;
295
296 if (!src_len || !dst_len)
297 return rename (src, dst);
298
299 # if RENAME_DEST_EXISTS_BUG
300 {
301 char *src_base = last_component (src);
302 char *dst_base = last_component (dst);
303 if (*src_base == '.')
304 {
305 size_t len = base_len (src_base);
306 if (len == 1 || (len == 2 && src_base[1] == '.'))
307 {
308 errno = EINVAL;
309 return -1;
310 }
311 }
312 if (*dst_base == '.')
313 {
314 size_t len = base_len (dst_base);
315 if (len == 1 || (len == 2 && dst_base[1] == '.'))
316 {
317 errno = EINVAL;
318 return -1;
319 }
320 }
321 }
322 # endif
323
324 src_slash = src[src_len - 1] == '/';
325 dst_slash = dst[dst_len - 1] == '/';
326
327 # if !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG
328
329
330
331 if (!src_slash && !dst_slash)
332 return rename (src, dst);
333 # endif
334
335
336
337
338
339 if (lstat (src, &src_st))
340 return -1;
341 if (lstat (dst, &dst_st))
342 {
343 if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
344 return -1;
345 dst_exists = false;
346 }
347 else
348 {
349 if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
350 {
351 errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
352 return -1;
353 }
354 # if RENAME_HARD_LINK_BUG
355 if (SAME_INODE (src_st, dst_st))
356 return 0;
357 # endif
358 dst_exists = true;
359 }
360
361 # if (RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG \
362 || RENAME_HARD_LINK_BUG)
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383 if (src_slash)
384 {
385 src_temp = strdup (src);
386 if (!src_temp)
387 {
388
389 rename_errno = ENOMEM;
390 goto out;
391 }
392 strip_trailing_slashes (src_temp);
393 if (lstat (src_temp, &src_st))
394 {
395 rename_errno = errno;
396 goto out;
397 }
398 if (S_ISLNK (src_st.st_mode))
399 goto out;
400 }
401 if (dst_slash)
402 {
403 dst_temp = strdup (dst);
404 if (!dst_temp)
405 {
406 rename_errno = ENOMEM;
407 goto out;
408 }
409 strip_trailing_slashes (dst_temp);
410 if (lstat (dst_temp, &dst_st))
411 {
412 if (errno != ENOENT)
413 {
414 rename_errno = errno;
415 goto out;
416 }
417 }
418 else if (S_ISLNK (dst_st.st_mode))
419 goto out;
420 }
421 # endif
422
423
424 # if RENAME_DEST_EXISTS_BUG
425
426
427
428
429
430
431
432 if (dst_exists && S_ISDIR (dst_st.st_mode))
433 {
434 if (src_st.st_dev != dst_st.st_dev)
435 {
436 rename_errno = EXDEV;
437 goto out;
438 }
439 if (src_temp != src)
440 free (src_temp);
441 src_temp = canonicalize_file_name (src);
442 if (dst_temp != dst)
443 free (dst_temp);
444 dst_temp = canonicalize_file_name (dst);
445 if (!src_temp || !dst_temp)
446 {
447 rename_errno = ENOMEM;
448 goto out;
449 }
450 src_len = strlen (src_temp);
451 if (strncmp (src_temp, dst_temp, src_len) == 0
452 && dst_temp[src_len] == '/')
453 {
454 rename_errno = EINVAL;
455 goto out;
456 }
457 if (rmdir (dst))
458 {
459 rename_errno = errno;
460 goto out;
461 }
462 }
463 # endif
464
465 ret_val = rename (src_temp, dst_temp);
466 rename_errno = errno;
467
468 out: _GL_UNUSED_LABEL;
469
470 if (src_temp != src)
471 free (src_temp);
472 if (dst_temp != dst)
473 free (dst_temp);
474 errno = rename_errno;
475 return ret_val;
476 }
477 #endif