From 069d2b507080e2cb2b4f9ed112c9b7d8c3f2dc22 Mon Sep 17 00:00:00 2001 From: LynX <_LynX@bk.ru> Date: Sat, 7 Jan 2012 11:50:57 +0200 Subject: [PATCH] Fix bug #10284 with renaming a directory on MS-Windows. src/w32.c (sys_rename): Report EXDEV when rename of a directory fails because the target is on another logical disk. (Bug#10284) --- src/ChangeLog | 5 +++++ src/w32.c | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 468e73c190b..3e0eed38cfb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2012-01-07 LynX <_LynX@bk.ru> (tiny change) + + * w32.c (sys_rename): Report EXDEV when rename of a directory + fails because the target is on another logical disk. (Bug#10284) + 2012-01-07 David Benjamin (tiny change) * xterm.c (x_embed_request_focus): New function. diff --git a/src/w32.c b/src/w32.c index 3c277668949..f610a36ecf4 100644 --- a/src/w32.c +++ b/src/w32.c @@ -2894,6 +2894,8 @@ sys_rename (const char * oldname, const char * newname) { BOOL result; char temp[MAX_PATH]; + int newname_dev; + int oldname_dev; /* MoveFile on Windows 95 doesn't correctly change the short file name alias in a number of circumstances (it is not easy to predict when @@ -2910,6 +2912,9 @@ sys_rename (const char * oldname, const char * newname) strcpy (temp, map_w32_filename (oldname, NULL)); + /* volume_info is set indirectly by map_w32_filename. */ + oldname_dev = volume_info.serialnum; + if (os_subtype == OS_WIN95) { char * o; @@ -2953,13 +2958,38 @@ sys_rename (const char * oldname, const char * newname) all the permutations of shared or subst'd drives, etc.) */ newname = map_w32_filename (newname, NULL); + + /* volume_info is set indirectly by map_w32_filename. */ + newname_dev = volume_info.serialnum; + result = rename (temp, newname); - if (result < 0 - && errno == EEXIST - && _chmod (newname, 0666) == 0 - && _unlink (newname) == 0) - result = rename (temp, newname); + if (result < 0) + { + + if (errno == EACCES + && newname_dev != oldname_dev) + { + /* The implementation of `rename' on Windows does not return + errno = EXDEV when you are moving a directory to a + different storage device (ex. logical disk). It returns + EACCES instead. So here we handle such situations and + return EXDEV. */ + DWORD attributes; + + if ((attributes = GetFileAttributes (temp)) != -1 + && attributes & FILE_ATTRIBUTE_DIRECTORY) + errno = EXDEV; + } + else if (errno == EEXIST) + { + if (_chmod (newname, 0666) != 0) + return result; + if (_unlink (newname) != 0) + return result; + result = rename (temp, newname); + } + } return result; }