Переглянути джерело

cmSystemTools: Teach RenameFile to disable Windows Search Indexing

Create RAII class SaveRestoreFileAttributes to manage Windows Search
Indexing.  Turn it off temporarily while renaming a directory.

Issue: #19580
Ron W Moore 5 роки тому
батько
коміт
e39e9c4043
1 змінених файлів з 59 додано та 0 видалено
  1. 59 0
      Source/cmSystemTools.cxx

+ 59 - 0
Source/cmSystemTools.cxx

@@ -751,6 +751,57 @@ std::string cmSystemTools::FileExistsInParentDirectories(
 #ifdef _WIN32
 namespace {
 
+/* Helper class to save and restore the specified file (or directory)
+   attribute bits. Instantiate this class as an automatic variable on the
+   stack. Its constructor saves a copy of the file attributes, and then its
+   destructor restores the original attribute settings.  */
+class SaveRestoreFileAttributes
+{
+public:
+  SaveRestoreFileAttributes(std::wstring const& path,
+                            uint32_t file_attrs_to_set);
+  ~SaveRestoreFileAttributes();
+
+  SaveRestoreFileAttributes(SaveRestoreFileAttributes const&) = delete;
+  SaveRestoreFileAttributes& operator=(SaveRestoreFileAttributes const&) =
+    delete;
+
+  void SetPath(std::wstring const& path) { path_ = path; }
+
+private:
+  std::wstring path_;
+  uint32_t original_attr_bits_;
+};
+
+SaveRestoreFileAttributes::SaveRestoreFileAttributes(
+  std::wstring const& path, uint32_t file_attrs_to_set)
+  : path_(path)
+  , original_attr_bits_(0)
+{
+  // Set the specified attributes for the source file/directory.
+  original_attr_bits_ = GetFileAttributesW(path_.c_str());
+  if ((INVALID_FILE_ATTRIBUTES != original_attr_bits_) &&
+      ((file_attrs_to_set & original_attr_bits_) != file_attrs_to_set)) {
+    SetFileAttributesW(path_.c_str(), original_attr_bits_ | file_attrs_to_set);
+  }
+}
+
+// We set attribute bits.  Now we need to restore their original state.
+SaveRestoreFileAttributes::~SaveRestoreFileAttributes()
+{
+  DWORD last_error = GetLastError();
+  // Verify or restore the original attributes.
+  const DWORD source_attr_bits = GetFileAttributesW(path_.c_str());
+  if (INVALID_FILE_ATTRIBUTES != source_attr_bits) {
+    if (original_attr_bits_ != source_attr_bits) {
+      // The file still exists, and its attributes aren't our saved values.
+      // Time to restore them.
+      SetFileAttributesW(path_.c_str(), original_attr_bits_);
+    }
+  }
+  SetLastError(last_error);
+}
+
 struct WindowsFileRetryInit
 {
   cmSystemTools::WindowsFileRetry Retry;
@@ -924,6 +975,12 @@ bool cmSystemTools::RenameFile(const std::string& oldname,
      Try multiple times since we may be racing against another process
      creating/opening the destination file just before our MoveFileEx.  */
   WindowsFileRetry retry = GetWindowsRetry(oldname_wstr);
+
+  // Use RAII to set the attribute bit blocking Microsoft Search Indexing,
+  // and restore the previous value upon return.
+  SaveRestoreFileAttributes save_restore_file_attributes(
+    oldname_wstr, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
+
   DWORD move_last_error = 0;
   while (!cmMoveFile(oldname_wstr, newname_wstr) && --retry.Count) {
     move_last_error = GetLastError();
@@ -961,6 +1018,8 @@ bool cmSystemTools::RenameFile(const std::string& oldname,
   // If we were successful, then there was no error.
   if (retry.Count > 0) {
     move_last_error = 0;
+    // Restore the attributes on the new name.
+    save_restore_file_attributes.SetPath(newname_wstr);
   }
   SetLastError(move_last_error);
   return retry.Count > 0;