Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

g++ 9.3.0 throw after trying to overwrite with std::filesystem::copy_options::overwrite_existing #1937

Open
diffsetter opened this issue May 1, 2020 · 13 comments

Comments

@diffsetter
Copy link

The following program throws if the regular file "bar" already exist with

terminate called after throwing an instance of 'std::filesystem::__cxx11::filesystem_error'
  what():  filesystem error: cannot copy file: File exists [foo] [bar]

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.

#include <filesystem>
int main() {
    std::filesystem::copy_file("foo","bar",std::filesystem::copy_options::overwrite_existing);
}

If "bar" does not exist yet, the copying succeeds. I use an up to date msys2 64bit system.

@o-kos
Copy link

o-kos commented May 18, 2020

MSYS2 gcc 10.1.0, bug reproduced

@ckravatz
Copy link

Yeah, I'm getting the same bug, 10.1.0, regardless of copy_options passed.

@petitg1987
Copy link

petitg1987 commented Dec 26, 2020

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]

@lucafei
Copy link

lucafei commented May 10, 2021

did anyone already solve this problem?

@JonatanAntoni
Copy link

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

@codeSilverWolf
Copy link

codeSilverWolf commented Dec 29, 2021

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";
}

codeSilverWolf added a commit to codeSilverWolf/Nemesis-bfx that referenced this issue Feb 10, 2022
Gnu libstdc++ used in msys has bug in implementation of filesystem::file_copy
on Windows platform, that causes file overwrite to throw exception.
Workaround this by deleting file first.

Msys issue #1937
msys2/MSYS2-packages#1937
@maraakate
Copy link

This bug still exists in latest MSYS2 as of 3/15/2022.

@Nambers
Copy link

Nambers commented Jul 21, 2022

Still happened.
:(

@dhbloo
Copy link

dhbloo commented Sep 15, 2022

This bug still exists in MSYS2 build as of 9/15/2022.

@Biswa96
Copy link
Member

Biswa96 commented Sep 15, 2022

Can you provide any sample code? Are you compiling for native Windows program? If yes you should use mingw gcc toolchain.

@creek23
Copy link

creek23 commented Apr 2, 2023

problem persists on this version:
g++.exe (Rev10, Built by MSYS2 project) 12.2.0

@creek23
Copy link

creek23 commented Apr 2, 2023

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);
}

@Turhvjbufv
Copy link

any update?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests