From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.hazardy.de (mail.hazardy.de [78.94.181.132]) by sourceware.org (Postfix) with ESMTPS id 65DB23858D35; Sun, 24 Mar 2024 21:34:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 65DB23858D35 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=hazardy.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=hazardy.de ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 65DB23858D35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=78.94.181.132 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1711316064; cv=none; b=VH+k2wRbl4sEKTMTD7m2VTy4rkpsbW2rFrqhVDHqyueYDuToemMfEtVoEHGO8i+mFFitMUvaNjrTxZyKrb/1mdZY6AFp4nK2jlqSP+bvj/OxxHRXrQQCmTYztMEXlevG46xWThu5JK55xtb9aBBiuoRM1MLkpESMOocVMJt7zXE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1711316064; c=relaxed/simple; bh=fuBEXDeld9QhOkwjSC0i0EPh5iddVJt1ra6Lq91bDco=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=Cc7cn0z9ZKTT4V2kZGx5+DJkYXyZTyVDtrDJPe8MGfP346/qxtxxUYr6xYZ0oRYS/QaOr47dDtGWnra5d5B1jnXKSWKolDBeioavTeKSPUby//pO+TIsuPXW8SVzoPwJ2Hm4803pJ6X07+InF8gACnfYvitBpCpsIAzhJAGJLpo= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from DE-23012.kuennecke.com (unknown [78.94.181.132]) by mail.hazardy.de (Postfix) with ESMTPSA id 23CA2700492; Sun, 24 Mar 2024 22:34:20 +0100 (CET) From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= To: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org Cc: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Subject: [PATCH] Fix overwriting files with fs::copy_file on windows Date: Sun, 24 Mar 2024 22:34:01 +0100 Message-ID: <20240324213401.47870-1-gcc@hazardy.de> X-Mailer: git-send-email 2.44.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00,GIT_PATCH_0,KAM_DMARC_STATUS,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: From: Björn Schäpers This fixes i.e. https://github.com/msys2/MSYS2-packages/issues/1937 I don't know if I picked the right way to do it. When acceptable I think the declaration should be moved into ops-common.h, since then we could use stat_type and also use that in the commonly used function. Manually tested on i686-w64-mingw32. -- >8 -- libstdc++: Fix overwriting files on windows The inodes have no meaning on windows, thus all files have an inode of 0. Use a differenz approach to identify equivalent files. As a result std::filesystem::copy_file did not honor copy_options::overwrite_existing. Factored the method out of std::filesystem::equivalent. libstdc++-v3/Changelog: * include/bits/fs_ops.h: Add declaration of __detail::equivalent_win32. * src/c++17/fs_ops.cc (__detail::equivalent_win32): Implement it (fs::equivalent): Use __detail::equivalent_win32, factored the old test out. * src/filesystem/ops-common.h (_GLIBCXX_FILESYSTEM_IS_WINDOWS): Use the function. Signed-off-by: Björn Schäpers --- libstdc++-v3/include/bits/fs_ops.h | 8 +++ libstdc++-v3/src/c++17/fs_ops.cc | 79 +++++++++++++----------- libstdc++-v3/src/filesystem/ops-common.h | 10 ++- 3 files changed, 60 insertions(+), 37 deletions(-) diff --git a/libstdc++-v3/include/bits/fs_ops.h b/libstdc++-v3/include/bits/fs_ops.h index 90650c47b46..d10b78a4bdd 100644 --- a/libstdc++-v3/include/bits/fs_ops.h +++ b/libstdc++-v3/include/bits/fs_ops.h @@ -40,6 +40,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace filesystem { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +namespace __detail +{ + bool + equivalent_win32(const wchar_t* p1, const wchar_t* p2, error_code& ec); +} // namespace __detail +#endif //_GLIBCXX_FILESYSTEM_IS_WINDOWS + /** @addtogroup filesystem * @{ */ diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc index 61df19753ef..3cc87d45237 100644 --- a/libstdc++-v3/src/c++17/fs_ops.cc +++ b/libstdc++-v3/src/c++17/fs_ops.cc @@ -67,6 +67,49 @@ namespace fs = std::filesystem; namespace posix = std::filesystem::__gnu_posix; +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +bool +fs::__detail::equivalent_win32(const wchar_t* p1, const wchar_t* p2, + error_code& ec) +{ + 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 = __last_system_error(); + return false; + } + if (!h1.get_info() || !h2.get_info()) + { + ec = __last_system_error(); + return false; + } + return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber + && h1.info.nFileIndexHigh == h2.info.nFileIndexHigh + && h1.info.nFileIndexLow == h2.info.nFileIndexLow; +} +#endif //_GLIBCXX_FILESYSTEM_IS_WINDOWS + fs::path fs::absolute(const path& p) { @@ -858,41 +901,7 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept 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 = __last_system_error(); - return false; - } - if (!h1.get_info() || !h2.get_info()) - { - ec = __last_system_error(); - return false; - } - return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber - && h1.info.nFileIndexHigh == h2.info.nFileIndexHigh - && h1.info.nFileIndexLow == h2.info.nFileIndexLow; + return __detail::equivalent_win32(p1.c_str(), p2.c_str(), ec); #else return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; #endif diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h index d917fddbeb1..7e67286bd01 100644 --- a/libstdc++-v3/src/filesystem/ops-common.h +++ b/libstdc++-v3/src/filesystem/ops-common.h @@ -489,8 +489,14 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM return false; } - if (to_st->st_dev == from_st->st_dev - && to_st->st_ino == from_st->st_ino) +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + // st_ino is not set, so can't be used to distinguish files + std::error_code not_used; + if (st1.st_mode != st2.st_mode || st1.st_dev != st2.st_dev || + fs::__detail::equivalent_win32(from, to, not_used)) +#else + if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) +#endif { ec = std::make_error_code(std::errc::file_exists); return false; -- 2.44.0