filesystem::copy - Gleichzeitiges Lesen/Schreiben einer Datei verhindern



  • Hallo,

    wie kann ich in C++ verhindern, dass z.B. während ich eine Datei kopiere (std::filesystem::copy) die Datei beschrieben wird und somit Fehlerhaft wird? Ich habe versucht während ich ein Spiel spiele, den savegame Ordner in bestimmten Zeitabschnitten zu "sichern", also kopieren (runtime backup). Leider sind die Savegames zwar vollständig kopiert (es sind alle Dateien und Ordner vorhanden), aber leider ist auch bisher jedes Save korrupt (Ich nehme stark an dass das Spiel gerade abgespeichert hat (autosave), als ich am kopieren war, und somit gab es Fehler). Code sah ca. so aus (eher Pseudocode):

    const std::filesystem::path from = ...
    const std::filesystem::path to = ...
    
    Timer timer;
    while (true) {
    if (timer.has_elapsed(1min)) {
        timer.restart();
        if (!std::filesystem::exists(to)) {
            std::filesystem::create_directories(to);
        } else {
            std::filesystem::remove_all(to);
        }
        std::filesystem::copy(from, to, std::filesystem::copy_options::recursive);
    }
    }
    

    Hat jemand eine Idee? Oder muss ich meine eigene WinAPI Wrapper implementieren und LockFile verwenden? (das wär echt blöd und bestimmt fehleranfällig :/).

    Compiler:
    Target: x86_64-w64-mingw32
    gcc version 8.2.0 (Rev1, Built by MSYS2 project)

    OS:
    Windows (Frage gilt auch für Linux)

    LG

    P.S.: Ich hatte das Ganze auch schon mit Qt implementiert (QFile::copy usw.) und das lief immer ohne Probleme und ohne Fehler. Ich dachte std::filesystem würde da nicht anders funktionieren (ich wollte jetzt das Ganze als Konsolenanwendung ohne Qt umsetzen). Vielleicht mache ich auch nur etwas falsch.

    Update:
    Nach Untersuchen des Quellcodes fällt mir folgendes auf: Qt scheint (m. E. n. richtigerweise) direkt die Win32 Funktion CopyFile aufzurufen. Diese verhindert höchstwahrscheinlich, dass die Datei zum Schreiben geöffnet werden kann, während der Kopiervorgang läuft (nur eine Annahme).

    bool QFileSystemEngine::copyFile(const QFileSystemEntry &source,
        const QFileSystemEntry &target, QSystemError &error)
    {
        bool ret = ::CopyFile((wchar_t*)source.nativeFilePath().utf16(),
                              (wchar_t*)target.nativeFilePath().utf16(), true) != 0;
        if(!ret)
            error = QSystemError(::GetLastError(), QSystemError::NativeError);
        return ret;
    }
    

    gcc 8.2 macht aber was komplett anderes:

    bool
    fs::do_copy_file(const char* from, const char* to,
    		 copy_options_existing_file options,
    		 stat_type* from_st, stat_type* to_st,
    		 std::error_code& ec) noexcept {
    struct CloseFD {
        ~CloseFD() { if (fd != -1) ::close(fd); }
        bool close() { return ::close(std::exchange(fd, -1)) == 0; }
        int fd;
      };
    
      CloseFD in = { ::open(from, O_RDONLY) };
      int oflag = O_WRONLY|O_CREAT;
      if (options.overwrite || options.update)
        oflag |= O_TRUNC;
      else
        oflag |= O_EXCL;
      CloseFD out = { ::open(to, oflag, S_IWUSR) };
    
    ::chmod(to, from_st->st_mode)
      using std::ios;
      __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary);
      __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary);
    std::ostream(&sbout) << &sbin);
    }
    

    Die Definition von open unter Windows konnte ich leider nicht mehr finden, aber ich nehme an dass man eben noch die Datei zum Schreiben öffnen kann. Kann das jemand vllt. bestätigen oder widerlegen? Wahrscheinlich liegt das daran, dass mingw eben nur ein Port von GCC auf windows ist irgendwie.