From 9462778d8170079235701403000277ec404506ba Mon Sep 17 00:00:00 2001 From: usa Date: Mon, 13 Apr 2015 08:10:10 +0000 Subject: merge revision(s) 49634,49658,49663: [Backport #10865] * win32/win32.c (wrename): return EXDEV if moving a directory to another drive, since MoveFileExW does not set proper error code. [ruby-core:68162] [Bug #10865] * win32/win32.c (different_device_p): compare by volume serial numbers, not by path names. numbers, not by path names. [ruby-core:68162] [Bug #10865] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_1@50290 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- win32/win32.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'win32') diff --git a/win32/win32.c b/win32/win32.c index 1f56f43d6b..ed5bfa778e 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -4673,6 +4673,31 @@ rb_w32_getenv(const char *name) return w32_getenv(name, CP_ACP); } +/* License: Ruby's */ +static DWORD +get_volume_serial_number(const WCHAR *path) +{ + const DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE; + const DWORD creation = OPEN_EXISTING; + const DWORD flags = FILE_FLAG_BACKUP_SEMANTICS; + BY_HANDLE_FILE_INFORMATION st = {0}; + HANDLE h = CreateFileW(path, 0, share_mode, NULL, creation, flags, NULL); + BOOL ret; + + if (h == INVALID_HANDLE_VALUE) return 0; + ret = GetFileInformationByHandle(h, &st); + CloseHandle(h); + if (!ret) return 0; + return st.dwVolumeSerialNumber; +} + +/* License: Ruby's */ +static int +different_device_p(const WCHAR *oldpath, const WCHAR *newpath) +{ + return get_volume_serial_number(oldpath) != get_volume_serial_number(newpath); +} + /* License: Artistic or GPL */ static int wrename(const WCHAR *oldpath, const WCHAR *newpath) @@ -4696,8 +4721,14 @@ wrename(const WCHAR *oldpath, const WCHAR *newpath) if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) res = -1; - if (res) - errno = map_errno(GetLastError()); + if (res) { + DWORD e = GetLastError(); + if ((e == ERROR_ACCESS_DENIED) && (oldatts & FILE_ATTRIBUTE_DIRECTORY) && + different_device_p(oldpath, newpath)) + errno = EXDEV; + else + errno = map_errno(e); + } else SetFileAttributesW(newpath, oldatts); }); -- cgit v1.2.3