msys2 / MSYS2-packages

Package scripts for MSYS2.
https://packages.msys2.org
BSD 3-Clause "New" or "Revised" License
1.29k stars 490 forks source link

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

Open diffsetter opened 4 years ago

diffsetter commented 4 years ago

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 commented 4 years ago

MSYS2 gcc 10.1.0, bug reproduced

ckravatz commented 4 years ago

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

petitg1987 commented 3 years ago

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 commented 3 years ago

did anyone already solve this problem?

JonatanAntoni commented 3 years ago

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 commented 2 years ago

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";
}
maraakate commented 2 years ago

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

Nambers commented 2 years ago

Still happened. :(

dhbloo commented 2 years ago

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

Biswa96 commented 2 years ago

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

creek23 commented 1 year ago

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

creek23 commented 1 year ago

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 commented 1 year ago

any update?

jwakely commented 3 months ago

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

jwakely commented 3 months ago

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