aboutsummaryrefslogtreecommitdiffstats
path: root/src/w32.c
diff options
context:
space:
mode:
authorLynX <[email protected]>2012-01-07 11:50:57 +0200
committerEli Zaretskii <[email protected]>2012-01-07 11:50:57 +0200
commit069d2b507080e2cb2b4f9ed112c9b7d8c3f2dc22 (patch)
treeccd1ba62708aec369c08772c2d92c65eec4717ca /src/w32.c
parente490b28922e17178224c6842b40429675b751cc8 (diff)
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)
Diffstat (limited to 'src/w32.c')
-rw-r--r--src/w32.c40
1 files changed, 35 insertions, 5 deletions
diff --git a/src/w32.c b/src/w32.c
index 3c27766894..f610a36ecf 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;
}