cmGeneratedFileStream.cxx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmGeneratedFileStream.h"
  14. #include "cmSystemTools.h"
  15. // Includes needed for implementation of RenameFile. This is not in
  16. // system tools because it is not implemented robustly enough to move
  17. // files across directories.
  18. #ifdef _WIN32
  19. # include <windows.h>
  20. # include <sys/stat.h>
  21. #endif
  22. //----------------------------------------------------------------------------
  23. cmGeneratedFileStream::cmGeneratedFileStream(const char* name, bool quiet):
  24. cmGeneratedFileStreamBase(name),
  25. Stream(m_TempName.c_str())
  26. {
  27. // Check if the file opened.
  28. if(!*this && !quiet)
  29. {
  30. cmSystemTools::Error("Cannot open file for write: ", m_TempName.c_str());
  31. cmSystemTools::ReportLastSystemError("");
  32. }
  33. }
  34. //----------------------------------------------------------------------------
  35. cmGeneratedFileStream::~cmGeneratedFileStream()
  36. {
  37. // This is the first destructor called. Check the status of the
  38. // stream and give the information to the private base. Next the
  39. // stream will be destroyed which will close the temporary file.
  40. // Finally the base destructor will be called to replace the
  41. // destination file.
  42. m_Okay = (*this)?true:false;
  43. }
  44. //----------------------------------------------------------------------------
  45. void cmGeneratedFileStream::SetCopyIfDifferent(bool copy_if_different)
  46. {
  47. m_CopyIfDifferent = copy_if_different;
  48. }
  49. //----------------------------------------------------------------------------
  50. cmGeneratedFileStreamBase::cmGeneratedFileStreamBase(const char* name):
  51. m_Name(name),
  52. m_TempName(name),
  53. m_CopyIfDifferent(false),
  54. m_Okay(false)
  55. {
  56. // Create the name of the temporary file.
  57. m_TempName += ".tmp";
  58. // Make sure the temporary file that will be used is not present.
  59. cmSystemTools::RemoveFile(m_TempName.c_str());
  60. }
  61. //----------------------------------------------------------------------------
  62. cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
  63. {
  64. // Only consider replacing the destination file if no error
  65. // occurred.
  66. if(m_Okay &&
  67. (!m_CopyIfDifferent ||
  68. cmSystemTools::FilesDiffer(m_TempName.c_str(), m_Name.c_str())))
  69. {
  70. // The destination is to be replaced. Rename the temporary to the
  71. // destination atomically.
  72. this->RenameFile(m_TempName.c_str(), m_Name.c_str());
  73. }
  74. else
  75. {
  76. // The destination was not replaced. Just delete the temporary
  77. // file.
  78. cmSystemTools::RemoveFile(m_TempName.c_str());
  79. }
  80. }
  81. //----------------------------------------------------------------------------
  82. int cmGeneratedFileStreamBase::RenameFile(const char* oldname,
  83. const char* newname)
  84. {
  85. #ifdef _WIN32
  86. /* On Windows the move functions will not replace existing files.
  87. Check if the destination exists. */
  88. struct stat newFile;
  89. if(stat(newname, &newFile) == 0)
  90. {
  91. /* The destination exists. We have to replace it carefully. The
  92. MoveFileEx function does what we need but is not available on
  93. Win9x. */
  94. OSVERSIONINFO osv;
  95. DWORD attrs;
  96. /* Make sure the destination is not read only. */
  97. attrs = GetFileAttributes(newname);
  98. if(attrs & FILE_ATTRIBUTE_READONLY)
  99. {
  100. SetFileAttributes(newname, attrs & ~FILE_ATTRIBUTE_READONLY);
  101. }
  102. /* Check the windows version number. */
  103. osv.dwOSVersionInfoSize = sizeof(osv);
  104. GetVersionEx(&osv);
  105. if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  106. {
  107. /* This is Win9x. There is no MoveFileEx implementation. We
  108. cannot quite rename the file atomically. Just delete the
  109. destination and then move the file. */
  110. DeleteFile(newname);
  111. return MoveFile(oldname, newname);
  112. }
  113. else
  114. {
  115. /* This is not Win9x. Use the MoveFileEx implementation. */
  116. return MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING);
  117. }
  118. }
  119. else
  120. {
  121. /* The destination does not exist. Just move the file. */
  122. return MoveFile(oldname, newname);
  123. }
  124. #else
  125. /* On UNIX we have an OS-provided call to do this atomically. */
  126. return rename(oldname, newname) == 0;
  127. #endif
  128. }