aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/src
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/src')
-rw-r--r--libstdc++-v3/src/c++17/fs_ops.cc30
-rw-r--r--libstdc++-v3/src/filesystem/ops-common.h11
2 files changed, 40 insertions, 1 deletions
diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc
index 3817655..3e1671e 100644
--- a/libstdc++-v3/src/c++17/fs_ops.cc
+++ b/libstdc++-v3/src/c++17/fs_ops.cc
@@ -1394,6 +1394,36 @@ fs::rename(const path& from, const path& to)
void
fs::rename(const path& from, const path& to, error_code& ec) noexcept
{
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ const auto to_status = fs::status(to, ec);
+ if (to_status.type() == file_type::not_found)
+ ec.clear();
+ else if (ec)
+ return;
+
+ if (fs::exists(to_status))
+ {
+ const auto from_status = fs::status(from, ec);
+ if (ec)
+ return;
+
+ if (fs::is_directory(to_status))
+ {
+ if (!fs::is_directory(from_status))
+ {
+ // Cannot rename a non-directory over an existing directory.
+ ec = std::make_error_code(std::errc::is_a_directory);
+ return;
+ }
+ }
+ else if (fs::is_directory(from_status))
+ {
+ // Cannot rename a directory over an existing non-directory.
+ ec = std::make_error_code(std::errc::not_a_directory);
+ return;
+ }
+ }
+#endif
if (posix::rename(from.c_str(), to.c_str()))
ec.assign(errno, std::generic_category());
else
diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h
index 118256a..529d4e0 100644
--- a/libstdc++-v3/src/filesystem/ops-common.h
+++ b/libstdc++-v3/src/filesystem/ops-common.h
@@ -104,7 +104,16 @@ namespace __gnu_posix
#endif
inline int rename(const wchar_t* oldname, const wchar_t* newname)
- { return _wrename(oldname, newname); }
+ {
+ if (MoveFileExW(oldname, newname,
+ MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
+ return 0;
+ if (GetLastError() == ERROR_ACCESS_DENIED)
+ errno = EACCES;
+ else
+ errno = EIO;
+ return -1;
+ }
inline int truncate(const wchar_t* path, _off64_t length)
{