Open diffsetter opened 4 years ago
MSYS2 gcc 10.1.0, bug reproduced
Yeah, I'm getting the same bug, 10.1.0, regardless of copy_options passed.
Similar error with copy (msys2/g++ 10.2.0):
#include <filesystem>
int main() {
std::filesystem::copy("fooDir", "barDir", std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive);
return 0;
}
If "barDir" does not exist yet, the copying succeeds. Otherwise, I've got this error:
terminate called after throwing an instance of 'std::filesystem::__cxx11::filesystem_error' what(): filesystem error: cannot copy: File exists [fooDir] [barDir]
did anyone already solve this problem?
Hi,
Same issue with msys2/g++ 10.3.0:
$ g++ --version g++.exe (Rev5, Built by MSYS2 project) 10.3.0
Can we expect a fix or do we need to work around this issue?
Thanks, Jonatan
Hi i debugged this problem and it looks like it's upstream bug in gcc libstdc++. in file \gcc-11.2.0\libstdc++-v3\src\filesystem\ops-common.h line 376 in procedure do_copy_file they define following condition:
if (to_st->st_dev == from_st->st_dev && to_st->st_ino == from_st->st_ino)
{
ec = std::make_error_code(std::errc::file_exists);
return false;
}
st_ino members are taken from _wstat64 function, but on windows it always returns 0 as linux file inodes has no meaning on windows. As explained here https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions?view=msvc-170 . So for any two different files on same drive this condition will be true. They should use GetFileInformationByHandle instead, or disable checking this condition on windows. Sample code included below.
#include <cstring>
#include <iostream>
#include <fstream>
#include <filesystem>
// copied from from C:\M\mingw-w64-gcc\src\gcc-11.2.0\libstdc++-v3\src\filesystem\ops-common.h
// just changed namespace name __gnu_posix to my_posix
namespace my_posix {
typedef struct ::__stat64 stat_type;
inline int stat(const wchar_t* path, stat_type* buffer)
{ return ::_wstat64(path, buffer); }
}
int main()
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
std::cout << "Have _GLIBCXX_FILESYSTEM_IS_WINDOWS \n";
#endif
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
std::cout << "Have _GLIBCXX_HAVE_SYS_STAT_H \n";
#endif
#if _UNICODE
std::cout << "Have _UNICODE \n";
#endif
// create test files
std::wstring filename1 = L"file1.txt";
std::ofstream f;
f.open(filename1.c_str());
if(f.is_open()) {
f << "file1";
f.close();
}
std::wstring filename2 = L"file2.txt";
f.open(filename2.c_str());
if(f.is_open()) {
f << "file2....";
f.close();
}
// check for bug in msys where overwritting existing file fails
std:std::error_code ec;
std::filesystem::copy_file(filename1,filename2,std::filesystem::copy_options::overwrite_existing, ec);
std::cout << "copy_file returned: " << ec.message() << "\n";
my_posix::stat_type st1, st2;
int rv1 = my_posix::stat(filename1.c_str(), &st1);
int rv2 = my_posix::stat(filename2.c_str(), &st2);
if (rv1 || rv2) {
std::cout << "stat returned error!\n";
return 1;
}
// same condition as in \gcc-11.2.0\libstdc++-v3\src\filesystem\ops.cc line 376
if (st2.st_dev == st1.st_dev
&& st2.st_ino == st1.st_ino) {
std::cout << "Error: do_copy_file considers files as same file\n";
}
else std::cout << "All ok. Files are not considered identical\n";
}
This bug still exists in latest MSYS2 as of 3/15/2022.
Still happened. :(
This bug still exists in MSYS2 build as of 9/15/2022.
Can you provide any sample code? Are you compiling for native Windows program? If yes you should use mingw gcc toolchain.
problem persists on this version: g++.exe (Rev10, Built by MSYS2 project) 12.2.0
snippet from my code:
std::filesystem::path l_currentPath = std::filesystem::current_path(); std::filesystem::current_path(std::filesystem::temp_directory_path()); std::filesystem::create_directories("testcopy"); std::filesystem::path l_sourceFile = "c:\fileoriginal.txt"; std::filesystem::path l_newFile = std::filesystem::temp_directory_path() / "testcopy/filecopy.txt"; if (std::filesystem::exists(l_newFile) == false) { std::filesystem::copy(l_source, l_newFile, std::filesystem::copy_options::update_existing); }
any update?
A patch to fix this was proposed upstream in March and reviewed in May. https://gcc.gnu.org/pipermail/gcc-patches/2024-March/648302.html https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652038.html
Fixed by a different patch, but based on a similar approach to Björn's patch. https://gcc.gnu.org/g:017e3f89b081e4828a588a3bd27b5feacea042b7 https://github.com/gcc-mirror/gcc/commit/017e3f89b081e4828a588a3bd27b5feacea042b7
The following program throws if the regular file "bar" already exist with
This does not happen under linux and also not under cygwin as I have been told. So I guess it could be an msys2 issue.
If "bar" does not exist yet, the copying succeeds. I use an up to date msys2 64bit system.