maint: cleanup whitespace in recent commits
[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.  */
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.  */
175   if (MoveFileEx (src, dst, 0))
176     return 0;
177
178   /* Retry with MOVEFILE_REPLACE_EXISTING if the move failed
179      due to the destination already existing.  */
180   error = GetLastError ();
181   if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS)
182     {
183       if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING))
184         return 0;
185
186       error = GetLastError ();
187     }
188
189   switch (error)
190     {
191     case ERROR_FILE_NOT_FOUND:
192     case ERROR_PATH_NOT_FOUND:
193     case ERROR_BAD_PATHNAME:
194     case ERROR_DIRECTORY:
195       errno = ENOENT;
196       break;
197
198     case ERROR_ACCESS_DENIED:
199     case ERROR_SHARING_VIOLATION:
200       errno = EACCES;
201       break;
202
203     case ERROR_OUTOFMEMORY:
204       errno = ENOMEM;
205       break;
206
207     case ERROR_CURRENT_DIRECTORY:
208       errno = EBUSY;
209       break;
210
211     case ERROR_NOT_SAME_DEVICE:
212       errno = EXDEV;
213       break;
214
215     case ERROR_WRITE_PROTECT:
216       errno = EROFS;
217       break;
218
219     case ERROR_WRITE_FAULT:
220     case ERROR_READ_FAULT:
221     case ERROR_GEN_FAILURE:
222       errno = EIO;
223       break;
224
225     case ERROR_HANDLE_DISK_FULL:
226     case ERROR_DISK_FULL:
227     case ERROR_DISK_TOO_FRAGMENTED:
228       errno = ENOSPC;
229       break;
230
231     case ERROR_FILE_EXISTS:
232     case ERROR_ALREADY_EXISTS:
233       errno = EEXIST;
234       break;
235
236     case ERROR_BUFFER_OVERFLOW:
237     case ERROR_FILENAME_EXCED_RANGE:
238       errno = ENAMETOOLONG;
239       break;
240
241     case ERROR_INVALID_NAME:
242     case ERROR_DELETE_PENDING:
243       errno = EPERM;        /* ? */
244       break;
245
246 # ifndef ERROR_FILE_TOO_LARGE
247 /* This value is documented but not defined in all versions of windows.h.  */
248 #  define ERROR_FILE_TOO_LARGE 223
249 # endif
250     case ERROR_FILE_TOO_LARGE:
251       errno = EFBIG;
252       break;
253
254     default:
255       errno = EINVAL;
256       break;
257     }
258
259   return -1;
260 }
261
262 #else /* ! W32 platform */
263
264 # include <errno.h>
265 # include <stdio.h>
266 # include <stdlib.h>
267 # include <string.h>
268 # include <sys/stat.h>
269 # include <unistd.h>
270
271 # include "dirname.h"
272 # include "same-inode.h"
273
274 /* Rename the file SRC to DST, fixing any trailing slash bugs.  */
275
276 int
277 rpl_rename (char const *src, char const *dst)
278 {
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;
285   bool dst_exists;
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.  */
293
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
319   src_slash = src[src_len - 1] == '/';
320   dst_slash = dst[dst_len - 1] == '/';
321
322 # if !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG
323   /* If there are no trailing slashes, then trust the native
324      implementation unless we also suspect issues with hard link
325      detection or file/directory conflicts.  */
326   if (!src_slash && !dst_slash)
327     return rename (src, dst);
328 # endif /* !RENAME_HARD_LINK_BUG && !RENAME_DEST_EXISTS_BUG */
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     {
338       if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
339         return -1;
340       dst_exists = false;
341     }
342   else
343     {
344       if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
345         {
346           errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
347           return -1;
348         }
349 # if RENAME_HARD_LINK_BUG
350       if (SAME_INODE (src_st, dst_st))
351         return 0;
352 # endif /* RENAME_HARD_LINK_BUG */
353       dst_exists = true;
354     }
355
356 # if (RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG        \
357       || RENAME_HARD_LINK_BUG)
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
362      Solaris 9, or if a directory can overwrite a symlink, as on
363      Cygwin 1.5, or if directories cannot be created with trailing
364      slash, as on NetBSD 1.6, then we must strip the offending slash
365      and check that we have not encountered a symlink instead of a
366      directory.
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.  */
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     }
416 # endif /* RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG
417            || RENAME_HARD_LINK_BUG */
418
419 # if RENAME_DEST_EXISTS_BUG
420   /* Cygwin 1.5 sometimes behaves oddly when moving a non-empty
421      directory on top of an empty one (the old directory name can
422      reappear if the new directory tree is removed).  Work around this
423      by removing the target first, but don't remove the target if it
424      is a subdirectory of the source.  */
425   if (dst_exists && S_ISDIR (dst_st.st_mode))
426     {
427       if (src_temp != src)
428         free (src_temp);
429       src_temp = canonicalize_file_name (src);
430       if (dst_temp != dst)
431         free (dst_temp);
432       dst_temp = canonicalize_file_name (dst);
433       if (!src_temp || !dst_temp)
434         {
435           rename_errno = ENOMEM;
436           goto out;
437         }
438       src_len = strlen (src_temp);
439       if (strncmp (src_temp, dst_temp, src_len) == 0
440           && dst_temp[src_len] == '/')
441         {
442           rename_errno = EINVAL;
443           goto out;
444         }
445       if (rmdir (dst))
446         {
447           rename_errno = errno;
448           goto out;
449         }
450     }
451 # endif /* RENAME_DEST_EXISTS_BUG */
452
453   ret_val = rename (src_temp, dst_temp);
454   rename_errno = errno;
455  out:
456   if (src_temp != src)
457     free (src_temp);
458   if (dst_temp != dst)
459     free (dst_temp);
460   errno = rename_errno;
461   return ret_val;
462 }
463 #endif /* ! W32 platform */