aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbutl/fdstream.cxx36
-rw-r--r--libbutl/filesystem.cxx5
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)