From: Jonathan Wakely Date: Thu, 17 Jan 2019 15:32:10 +0000 (+0000) Subject: Fix filesystem::equivalent for mingw X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=16d46c7bfda76b5b3e88a2d9a809aacdc3ed8e1a;p=gcc.git Fix filesystem::equivalent for mingw * src/c++17/fs_ops.cc (equivalent(const path&, const path&, error_code&)) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Use GetFileInformationByHandle to compare files instead of relying on incomplete info returned by stat. From-SVN: r268036 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 1be8354aeca..3ea31688ae8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,10 @@ 2019-01-17 Jonathan Wakely + * src/c++17/fs_ops.cc + (equivalent(const path&, const path&, error_code&)) + [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Use GetFileInformationByHandle to + compare files instead of relying on incomplete info returned by stat. + PR libstdc++/88884 * src/c++17/fs_ops.cc (absolute(const path&, error_code&)): Do nothing if the path is already absolute. diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc index c4b99fb36ce..3ff0ded1c66 100644 --- a/libstdc++-v3/src/c++17/fs_ops.cc +++ b/libstdc++-v3/src/c++17/fs_ops.cc @@ -851,7 +851,49 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept ec.clear(); if (is_other(s1) || is_other(s2)) return false; +#if _GLIBCXX_FILESYSTEM_IS_WINDOWS + // st_ino is not set, so can't be used to distinguish files + if (st1.st_mode != st2.st_mode || st1.st_dev != st2.st_dev) + return false; + + struct auto_handle { + explicit auto_handle(const path& p_) + : handle(CreateFileW(p_.c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) + { } + + ~auto_handle() + { if (*this) CloseHandle(handle); } + + explicit operator bool() const + { return handle != INVALID_HANDLE_VALUE; } + + bool get_info() + { return GetFileInformationByHandle(handle, &info); } + + HANDLE handle; + BY_HANDLE_FILE_INFORMATION info; + }; + auto_handle h1(p1); + auto_handle h2(p2); + if (!h1 || !h2) + { + if (!h1 && !h2) + ec.assign((int)GetLastError(), generic_category()); + return false; + } + if (!h1.get_info() || !h2.get_info()) + { + ec.assign((int)GetLastError(), generic_category()); + return false; + } + return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber + && h1.info.nFileIndexHigh == h2.info.nFileIndexHigh + && h1.info.nFileIndexLow == h2.info.nFileIndexLow; +#else return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; +#endif } else if (!exists(s1) && !exists(s2)) ec = std::make_error_code(std::errc::no_such_file_or_directory);