From 205c54bf10f4b0fdce64c5dace5c5a86de27d248 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 7 Jul 2020 11:52:40 +0300 Subject: On Windows make fdopen() to retry for a second on ERROR_SHARING_VIOLATION error --- libbutl/fdstream.cxx | 36 +++++++++++++++++++++++++++++++++--- libbutl/filesystem.cxx | 5 ++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/libbutl/fdstream.cxx b/libbutl/fdstream.cxx index 9f54852..b12ce78 100644 --- a/libbutl/fdstream.cxx +++ b/libbutl/fdstream.cxx @@ -1123,9 +1123,39 @@ namespace butl // of |= _O_NOINHERIT; - int fd (pass_perm - ? _sopen (f, of, _SH_DENYNO, pf) - : _sopen (f, of, _SH_DENYNO)); + int fd; + + // For reasons unknown an attempt to open an existing file for writing + // sometimes ends up with the EACCES POSIX error which is presumably a + // translation of the ERROR_SHARING_VIOLATION system error returned by the + // underlying CreateFile() function call (see mventry() for details). If + // that's the case, we will keep trying to open the file for a second. + // + for (size_t i (0); i < 11; ++i) + { + // Sleep 100 milliseconds before the open retry. + // + if (i != 0) + Sleep (100); + + fd = pass_perm + ? _sopen (f, of, _SH_DENYNO, pf) + : _sopen (f, of, _SH_DENYNO); + + // Note that MSVCRT's _sopen() calls CreateFile() underneath, + // translating the system error to POSIX on failure and bailing out + // afterwords. Thus, we can query the original error code on _sopen() + // failure. + // + // Note that MinGW's _sopen() is just a stub forwarding the call to the + // (publicly available) MSVCRT's implementation. + // + if (!(fd == -1 && + out && + errno == EACCES && + GetLastError () == ERROR_SHARING_VIOLATION)) + break; + } #endif diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx index f246214..f145ee7 100644 --- a/libbutl/filesystem.cxx +++ b/libbutl/filesystem.cxx @@ -1724,7 +1724,10 @@ namespace butl // we will keep trying to move the file for a second. // // The thinking is that there can be some Windows process analyzing newly - // created files and so preventing their move or removal. + // created files and so preventing their move, removal, or change. + // + // Note that we address this issue in a similar way in try_rmfile() and + // fdopen(). // DWORD ec; for (size_t i (0); i < 11; ++i) -- cgit v1.1