autoupdate
[gnulib.git] / lib / rename.c
1 /* Work around rename bugs in some systems.
2
3    Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Free Software
4    Foundation, Inc.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
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
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 /* Written by Volker Borchert, Eric Blake.  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24
25 #undef rename
26
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.  */
31
32 # include <errno.h>
33 # include <stdbool.h>
34 # include <stdlib.h>
35 # include <sys/stat.h>
36 # include <unistd.h>
37
38 # define WIN32_LEAN_AND_MEAN
39 # include <windows.h>
40
41 # include "dirname.h"
42
43 /* Rename the file SRC to DST.  This replacement is necessary on
44    Windows, on which the system rename function will not replace
45    an existing DST.  */
46 int
47 rpl_rename (char const *src, char const *dst)
48 {
49   int error;
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;
59
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))
103         {
104           errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
105           return -1;
106         }
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; later
117      attempts to return are fatal.  Note that we can end up losing a
118      directory if rename then fails, but it was empty, so not much
119      damage was done.  */
120   if (dst_exists && S_ISDIR (dst_st.st_mode))
121     {
122       char *cwd = getcwd (NULL, 0);
123       char *src_temp;
124       char *dst_temp;
125       if (!cwd || chdir (cwd))
126         return -1;
127       if (IS_ABSOLUTE_FILE_NAME (src))
128         {
129           dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
130           src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
131         }
132       else
133         {
134           src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
135           if (!IS_ABSOLUTE_FILE_NAME (dst) && chdir (cwd))
136             abort ();
137           dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
138         }
139       if (chdir (cwd))
140         abort ();
141       free (cwd);
142       if (!src_temp || !dst_temp)
143         {
144           free (src_temp);
145           free (dst_temp);
146           errno = ENOMEM;
147           return -1;
148         }
149       src_len = strlen (src_temp);
150       if (strncmp (src_temp, dst_temp, src_len) == 0
151           && (ISSLASH (dst_temp[src_len]) || dst_temp[src_len] == '\0'))
152         {
153           error = dst_temp[src_len];
154           free (src_temp);
155           free (dst_temp);
156           if (error)
157             {
158               errno = EINVAL;
159               return -1;
160             }
161           return 0;
162         }
163       if (rmdir (dst))
164         {
165           error = errno;
166           free (src_temp);
167           free (dst_temp);
168           errno = error;
169           return -1;
170         }
171       free (src_temp);
172       free (dst_temp);
173     }
174
175   /* MoveFileEx works if SRC is a directory without any flags, but
176      fails with MOVEFILE_REPLACE_EXISTING, so try without flags first.
177      Thankfully, MoveFileEx handles hard links correctly, even though
178      rename() does not.  */
179   if (MoveFileEx (src, dst, 0))
180     return 0;
181
182   /* Retry with MOVEFILE_REPLACE_EXISTING if the move failed
183      due to the destination already existing.  */
184   error = GetLastError ();
185   if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS)
186     {
187       if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING))
188         return 0;
189
190       error = GetLastError ();
191     }
192
193   switch (error)
194     {
195     case ERROR_FILE_NOT_FOUND:
196     case ERROR_PATH_NOT_FOUND:
197     case ERROR_BAD_PATHNAME:
198     case ERROR_DIRECTORY:
199       errno = ENOENT;
200       break;
201
202     case ERROR_ACCESS_DENIED:
203     case ERROR_SHARING_VIOLATION:
204       errno = EACCES;
205       break;
206
207     case ERROR_OUTOFMEMORY:
208       errno = ENOMEM;
209       break;
210
211     case ERROR_CURRENT_DIRECTORY:
212       errno = EBUSY;
213       break;
214
215     case ERROR_NOT_SAME_DEVICE:
216       errno = EXDEV;
217       break;
218
219     case ERROR_WRITE_PROTECT:
220       errno = EROFS;
221       break;
222
223     case ERROR_WRITE_FAULT:
224     case ERROR_READ_FAULT:
225     case ERROR_GEN_FAILURE:
226       errno = EIO;
227       break;
228
229     case ERROR_HANDLE_DISK_FULL:
230     case ERROR_DISK_FULL:
231     case ERROR_DISK_TOO_FRAGMENTED:
232       errno = ENOSPC;
233       break;
234
235     case ERROR_FILE_EXISTS:
236     case ERROR_ALREADY_EXISTS:
237       errno = EEXIST;
238       break;
239
240     case ERROR_BUFFER_OVERFLOW:
241     case ERROR_FILENAME_EXCED_RANGE:
242       errno = ENAMETOOLONG;
243       break;
244
245     case ERROR_INVALID_NAME:
246     case ERROR_DELETE_PENDING:
247       errno = EPERM;        /* ? */
248       break;
249
250 # ifndef ERROR_FILE_TOO_LARGE
251 /* This value is documented but not defined in all versions of windows.h.  */
252 #  define ERROR_FILE_TOO_LARGE 223
253 # endif
254     case ERROR_FILE_TOO_LARGE:
255       errno = EFBIG;
256       break;
257
258     default:
259       errno = EINVAL;
260       break;
261     }
262
263   return -1;
264 }
265
266 #else /* ! W32 platform */
267
268 # include <errno.h>
269 # include <stdio.h>
270 # include <stdlib.h>
271 # include <string.h>
272 # include <sys/stat.h>
273 # include <unistd.h>
274
275 # include "dirname.h"
276 # include "same-inode.h"
277
278 /* Rename the file SRC to DST, fixing any trailing slash bugs.  */
279
280 int
281 rpl_rename (char const *src, char const *dst)
282 {
283   size_t src_len = strlen (src);
284   size_t dst_len = strlen (dst);
285   char *src_temp = (char *) src;
286   char *dst_temp = (char *) dst;
287   bool src_slash;
288   bool dst_slash;
289   bool dst_exists;
290   int ret_val = -1;
291   int rename_errno = ENOTDIR;
292   struct stat src_st;
293   struct stat dst_st;
294
295   if (!src_len || !dst_len)
296     return rename (src, dst); /* Let strace see the ENOENT failure.  */
297
298 # if RENAME_DEST_EXISTS_BUG
299   {
300     char *src_base = last_component (src);
301     char *dst_base = last_component (dst);
302     if (*src_base == '.')
303       {
304         size_t len = base_len (src_base);
305         if (len == 1 || (len == 2 && src_base[1] == '.'))
306           {
307             errno = EINVAL;
308             return -1;
309           }
310       }
311     if (*dst_base == '.')
312       {
313         size_t len = base_len (dst_base);
314         if (len == 1 || (len == 2 && dst_base[1] == '.'))
315           {
316             errno = EINVAL;
317             return -1;
318           }
319       }
320   }
321 # endif /* RENAME_DEST_EXISTS_BUG */
322
323   src_slash = src[src_len - 1] == '/';
324   dst_slash = dst[dst_len - 1] == '/';
325
326 # if !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG
327   /* If there are no trailing slashes, then trust the native
328      implementation unless we also suspect issues with hard link
329      detection or file/directory conflicts.  */
330   if (!src_slash && !dst_slash)
331     return rename (src, dst);
332 # endif /* !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG */
333
334   /* Presence of a trailing slash requires directory semantics.  If
335      the source does not exist, or if the destination cannot be turned
336      into a directory, give up now.  Otherwise, strip trailing slashes
337      before calling rename.  */
338   if (lstat (src, &src_st))
339     return -1;
340   if (lstat (dst, &dst_st))
341     {
342       if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
343         return -1;
344       dst_exists = false;
345     }
346   else
347     {
348       if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
349         {
350           errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
351           return -1;
352         }
353 # if RENAME_HARD_LINK_BUG
354       if (SAME_INODE (src_st, dst_st))
355         return 0;
356 # endif /* RENAME_HARD_LINK_BUG */
357       dst_exists = true;
358     }
359
360 # if (RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG        \
361       || RENAME_HARD_LINK_BUG)
362   /* If the only bug was that a trailing slash was allowed on a
363      non-existing file destination, as in Solaris 10, then we've
364      already covered that situation.  But if there is any problem with
365      a trailing slash on an existing source or destination, as in
366      Solaris 9, or if a directory can overwrite a symlink, as on
367      Cygwin 1.5, or if directories cannot be created with trailing
368      slash, as on NetBSD 1.6, then we must strip the offending slash
369      and check that we have not encountered a symlink instead of a
370      directory.
371
372      Stripping a trailing slash interferes with POSIX semantics, where
373      rename behavior on a symlink with a trailing slash operates on
374      the corresponding target directory.  We prefer the GNU semantics
375      of rejecting any use of a symlink with trailing slash, but do not
376      enforce them, since Solaris 10 is able to obey POSIX semantics
377      and there might be clients expecting it, as counter-intuitive as
378      those semantics are.
379
380      Technically, we could also follow the POSIX behavior by chasing a
381      readlink trail, but that is harder to implement.  */
382   if (src_slash)
383     {
384       src_temp = strdup (src);
385       if (!src_temp)
386         {
387           /* Rather than rely on strdup-posix, we set errno ourselves.  */
388           rename_errno = ENOMEM;
389           goto out;
390         }
391       strip_trailing_slashes (src_temp);
392       if (lstat (src_temp, &src_st))
393         {
394           rename_errno = errno;
395           goto out;
396         }
397       if (S_ISLNK (src_st.st_mode))
398         goto out;
399     }
400   if (dst_slash)
401     {
402       dst_temp = strdup (dst);
403       if (!dst_temp)
404         {
405           rename_errno = ENOMEM;
406           goto out;
407         }
408       strip_trailing_slashes (dst_temp);
409       if (lstat (dst_temp, &dst_st))
410         {
411           if (errno != ENOENT)
412             {
413               rename_errno = errno;
414               goto out;
415             }
416         }
417       else if (S_ISLNK (dst_st.st_mode))
418         goto out;
419     }
420 # endif /* RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG
421            || RENAME_HARD_LINK_BUG */
422
423 # if RENAME_DEST_EXISTS_BUG
424   /* Cygwin 1.5 sometimes behaves oddly when moving a non-empty
425      directory on top of an empty one (the old directory name can
426      reappear if the new directory tree is removed).  Work around this
427      by removing the target first, but don't remove the target if it
428      is a subdirectory of the source.  Note that we can end up losing
429      a directory if rename then fails, but it was empty, so not much
430      damage was done.  */
431   if (dst_exists && S_ISDIR (dst_st.st_mode))
432     {
433       if (src_st.st_dev != dst_st.st_dev)
434         {
435           rename_errno = EXDEV;
436           goto out;
437         }
438       if (src_temp != src)
439         free (src_temp);
440       src_temp = canonicalize_file_name (src);
441       if (dst_temp != dst)
442         free (dst_temp);
443       dst_temp = canonicalize_file_name (dst);
444       if (!src_temp || !dst_temp)
445         {
446           rename_errno = ENOMEM;
447           goto out;
448         }
449       src_len = strlen (src_temp);
450       if (strncmp (src_temp, dst_temp, src_len) == 0
451           && dst_temp[src_len] == '/')
452         {
453           rename_errno = EINVAL;
454           goto out;
455         }
456       if (rmdir (dst))
457         {
458           rename_errno = errno;
459           goto out;
460         }
461     }
462 # endif /* RENAME_DEST_EXISTS_BUG */
463
464   ret_val = rename (src_temp, dst_temp);
465   rename_errno = errno;
466  out:
467   if (src_temp != src)
468     free (src_temp);
469   if (dst_temp != dst)
470     free (dst_temp);
471   errno = rename_errno;
472   return ret_val;
473 }
474 #endif /* ! W32 platform */