Mercurial > hg > octave-lyh > gnulib-hg
changeset 12103:832357ca223a
rename, fchdir: don't ignore chdir failure
Although we just checked that chdir(cwd) worked, there is a
race where it could disappear while we are temporarily away.
If that happens, forcefully give up rather than proceeding
in the wrong directory.
* lib/fchdir.c (get_name): Abort on unexpected chdir failure.
* lib/rename.c (rpl_rename) [W32]: Likewise.
(rpl_rename) [RENAME_DEST_EXISTS_BUG]: Avoid one case of losing
an empty destination directory if source cannot be renamed,
although there is still possibility for failure.
* doc/posix-functions/rename.texi (rename): Document the race.
Reported by Jim Meyering.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Fri, 02 Oct 2009 12:05:02 -0600 |
parents | 3ba227551e1d |
children | 39e066ee16aa |
files | ChangeLog doc/posix-functions/rename.texi lib/fchdir.c lib/rename.c |
diffstat | 4 files changed, 31 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2009-10-02 Eric Blake <ebb9@byu.net> + rename, fchdir: don't ignore chdir failure + * lib/fchdir.c (get_name): Abort on unexpected chdir failure. + * lib/rename.c (rpl_rename) [W32]: Likewise. + (rpl_rename) [RENAME_DEST_EXISTS_BUG]: Avoid one case of losing + an empty destination directory if source cannot be renamed, + although there is still possibility for failure. + * doc/posix-functions/rename.texi (rename): Document the race. + Reported by Jim Meyering. + maint: cleanup whitespace in recent commits * lib/rename.c (rpl_rename): Remove tabs. * tests/test-link.h (test_link): Likewise.
--- a/doc/posix-functions/rename.texi +++ b/doc/posix-functions/rename.texi @@ -27,7 +27,9 @@ @item This function will not always replace an existing destination on some platforms: -mingw. +Cygwin 1.5.x, mingw. +However, the replacement is not atomic for directories, and may end up +losing the empty destination if the source could not be renamed. @item This function mistakenly allows names ending in @samp{.} or @samp{..} on some platforms:
--- a/lib/fchdir.c +++ b/lib/fchdir.c @@ -106,7 +106,8 @@ return NULL; result = chdir (dir) ? NULL : getcwd (NULL, 0); saved_errno = errno; - chdir (cwd); + if (chdir (cwd)) + abort (); free (cwd); errno = saved_errno; }
--- a/lib/rename.c +++ b/lib/rename.c @@ -113,13 +113,16 @@ replace an existing empty directory, so we have to help it out. And canonicalize_file_name is not yet ported to mingw; however, for directories, getcwd works as a viable alternative. Ensure - that we can get back to where we started before using it. */ + that we can get back to where we started before using it; later + attempts to return are fatal. Note that we can end up losing a + directory if rename then fails, but it was empty, so not much + damage was done. */ if (dst_exists && S_ISDIR (dst_st.st_mode)) { char *cwd = getcwd (NULL, 0); char *src_temp; char *dst_temp; - if (chdir (cwd)) + if (!cwd || chdir (cwd)) return -1; if (IS_ABSOLUTE_FILE_NAME (src)) { @@ -129,11 +132,12 @@ else { src_temp = chdir (src) ? NULL : getcwd (NULL, 0); - if (!IS_ABSOLUTE_FILE_NAME (dst)) - chdir (cwd); + if (!IS_ABSOLUTE_FILE_NAME (dst) && chdir (cwd)) + abort (); dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0); } - chdir (cwd); + if (chdir (cwd)) + abort (); free (cwd); if (!src_temp || !dst_temp) { @@ -421,9 +425,16 @@ directory on top of an empty one (the old directory name can reappear if the new directory tree is removed). Work around this by removing the target first, but don't remove the target if it - is a subdirectory of the source. */ + is a subdirectory of the source. Note that we can end up losing + a directory if rename then fails, but it was empty, so not much + damage was done. */ if (dst_exists && S_ISDIR (dst_st.st_mode)) { + if (src_st.st_dev != dst_st.st_dev) + { + rename_errno = EXDEV; + goto out; + } if (src_temp != src) free (src_temp); src_temp = canonicalize_file_name (src);