[PATCH] D38570: Support: Rewrite Windows implementation of sys::fs::rename to be more POSIXy.

Zachary Turner via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 4 18:00:12 PDT 2017


zturner added a comment.

So if I understand the problem correctly, you don't have any issue with `ReplaceFile`'s behavior on the destination, only the source.  So, for example, you call `ReplaceFile`, it returns, and then some other process tries to open the //source// file and fails.

If this is correct, then what about this idea?

1. Move the source file to a temporary file name.
2. Call `ReplaceFile` specifying the new temporary file as the source.

This is still not atomic, but neither is the code here, so it's a question of which tradeoffs do we prefer.  With a truly atomic rename, there are two outcomes:

1. Dest exists before rename.  After the rename, there was never a window of time where Dest existed but not Source.  Either They both exist, or exactly 1 exists at it is Dest with Source's original content.
2. Dest doesn't exist before rename.  After the rename, there was never a window of time where 0 or 2 files existed.  There was always exactly 1 file.

With the approach mentioned above, you can still satisfy 2, but not 1.  There will be a short window of time where Dest is moved to a temporary location but not yet overwritten onto Source.



================
Comment at: llvm/lib/Support/Windows/Path.inc:368-369
 
-  // Retry while we see recoverable errors.
-  // System scanners (eg. indexer) might open the source file when it is written
-  // and closed.
+  std::vector<char> RenameInfoBuf(sizeof(FILE_RENAME_INFO) +
+                                  (ToWide.size() * sizeof(wchar_t)));
+  FILE_RENAME_INFO &RenameInfo =
----------------
I think this is allocating 1 character too many.  `ToWide.size()` already includes the null terminator, but so does `sizeof(FILE_RENAME_INFO)` since it has a 1 character array.


================
Comment at: llvm/lib/Support/Windows/Path.inc:374
+  RenameInfo.RootDirectory = 0;
+  RenameInfo.FileNameLength = ToWide.size();
+  std::copy(ToWide.begin(), ToWide.end(), RenameInfo.FileName);
----------------
If I understand correctly, `ToWide.size()` contains the number of characters including null terminator, but this value should be number of characters *not* including null terminator.


https://reviews.llvm.org/D38570





More information about the llvm-commits mailing list