cmGeneratedFileStream.cxx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmGeneratedFileStream.h"
  11. #include "cmSystemTools.h"
  12. #if defined(CMAKE_BUILD_WITH_CMAKE)
  13. # include <cm_zlib.h>
  14. #endif
  15. //----------------------------------------------------------------------------
  16. cmGeneratedFileStream::cmGeneratedFileStream():
  17. cmGeneratedFileStreamBase(), Stream()
  18. {
  19. }
  20. //----------------------------------------------------------------------------
  21. cmGeneratedFileStream::cmGeneratedFileStream(const char* name, bool quiet):
  22. cmGeneratedFileStreamBase(name),
  23. Stream(TempName.c_str())
  24. {
  25. // Check if the file opened.
  26. if(!*this && !quiet)
  27. {
  28. cmSystemTools::Error("Cannot open file for write: ",
  29. this->TempName.c_str());
  30. cmSystemTools::ReportLastSystemError("");
  31. }
  32. }
  33. //----------------------------------------------------------------------------
  34. cmGeneratedFileStream::~cmGeneratedFileStream()
  35. {
  36. // This is the first destructor called. Check the status of the
  37. // stream and give the information to the private base. Next the
  38. // stream will be destroyed which will close the temporary file.
  39. // Finally the base destructor will be called to replace the
  40. // destination file.
  41. this->Okay = (*this)?true:false;
  42. }
  43. //----------------------------------------------------------------------------
  44. cmGeneratedFileStream&
  45. cmGeneratedFileStream::Open(const char* name, bool quiet, bool binaryFlag)
  46. {
  47. // Store the file name and construct the temporary file name.
  48. this->cmGeneratedFileStreamBase::Open(name);
  49. // Open the temporary output file.
  50. if ( binaryFlag )
  51. {
  52. this->Stream::open(this->TempName.c_str(),
  53. std::ios::out | std::ios::binary);
  54. }
  55. else
  56. {
  57. this->Stream::open(this->TempName.c_str(), std::ios::out);
  58. }
  59. // Check if the file opened.
  60. if(!*this && !quiet)
  61. {
  62. cmSystemTools::Error("Cannot open file for write: ",
  63. this->TempName.c_str());
  64. cmSystemTools::ReportLastSystemError("");
  65. }
  66. return *this;
  67. }
  68. //----------------------------------------------------------------------------
  69. bool
  70. cmGeneratedFileStream::Close()
  71. {
  72. // Save whether the temporary output file is valid before closing.
  73. this->Okay = (*this)?true:false;
  74. // Close the temporary output file.
  75. this->Stream::close();
  76. // Remove the temporary file (possibly by renaming to the real file).
  77. return this->cmGeneratedFileStreamBase::Close();
  78. }
  79. //----------------------------------------------------------------------------
  80. void cmGeneratedFileStream::SetCopyIfDifferent(bool copy_if_different)
  81. {
  82. this->CopyIfDifferent = copy_if_different;
  83. }
  84. //----------------------------------------------------------------------------
  85. void cmGeneratedFileStream::SetCompression(bool compression)
  86. {
  87. this->Compress = compression;
  88. }
  89. //----------------------------------------------------------------------------
  90. void cmGeneratedFileStream::SetCompressionExtraExtension(bool ext)
  91. {
  92. this->CompressExtraExtension = ext;
  93. }
  94. //----------------------------------------------------------------------------
  95. cmGeneratedFileStreamBase::cmGeneratedFileStreamBase():
  96. Name(),
  97. TempName(),
  98. CopyIfDifferent(false),
  99. Okay(false),
  100. Compress(false),
  101. CompressExtraExtension(true)
  102. {
  103. }
  104. //----------------------------------------------------------------------------
  105. cmGeneratedFileStreamBase::cmGeneratedFileStreamBase(const char* name):
  106. Name(),
  107. TempName(),
  108. CopyIfDifferent(false),
  109. Okay(false),
  110. Compress(false),
  111. CompressExtraExtension(true)
  112. {
  113. this->Open(name);
  114. }
  115. //----------------------------------------------------------------------------
  116. cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
  117. {
  118. this->Close();
  119. }
  120. //----------------------------------------------------------------------------
  121. void cmGeneratedFileStreamBase::Open(const char* name)
  122. {
  123. // Save the original name of the file.
  124. this->Name = name;
  125. // Create the name of the temporary file.
  126. this->TempName = name;
  127. #if defined(__VMS)
  128. this->TempName += "_tmp";
  129. #else
  130. this->TempName += ".tmp";
  131. #endif
  132. // Make sure the temporary file that will be used is not present.
  133. cmSystemTools::RemoveFile(this->TempName);
  134. std::string dir = cmSystemTools::GetFilenamePath(this->TempName);
  135. cmSystemTools::MakeDirectory(dir.c_str());
  136. }
  137. //----------------------------------------------------------------------------
  138. bool cmGeneratedFileStreamBase::Close()
  139. {
  140. bool replaced = false;
  141. std::string resname = this->Name;
  142. if ( this->Compress && this->CompressExtraExtension )
  143. {
  144. resname += ".gz";
  145. }
  146. // Only consider replacing the destination file if no error
  147. // occurred.
  148. if(!this->Name.empty() &&
  149. this->Okay &&
  150. (!this->CopyIfDifferent ||
  151. cmSystemTools::FilesDiffer(this->TempName, resname)))
  152. {
  153. // The destination is to be replaced. Rename the temporary to the
  154. // destination atomically.
  155. if ( this->Compress )
  156. {
  157. std::string gzname = this->TempName + ".temp.gz";
  158. if ( this->CompressFile(this->TempName.c_str(), gzname.c_str()) )
  159. {
  160. this->RenameFile(gzname.c_str(), resname.c_str());
  161. }
  162. cmSystemTools::RemoveFile(gzname);
  163. }
  164. else
  165. {
  166. this->RenameFile(this->TempName.c_str(), resname.c_str());
  167. }
  168. replaced = true;
  169. }
  170. // Else, the destination was not replaced.
  171. //
  172. // Always delete the temporary file. We never want it to stay around.
  173. cmSystemTools::RemoveFile(this->TempName);
  174. return replaced;
  175. }
  176. //----------------------------------------------------------------------------
  177. #ifdef CMAKE_BUILD_WITH_CMAKE
  178. int cmGeneratedFileStreamBase::CompressFile(const char* oldname,
  179. const char* newname)
  180. {
  181. gzFile gf = gzopen(newname, "w");
  182. if ( !gf )
  183. {
  184. return 0;
  185. }
  186. FILE* ifs = cmsys::SystemTools::Fopen(oldname, "r");
  187. if ( !ifs )
  188. {
  189. return 0;
  190. }
  191. size_t res;
  192. const size_t BUFFER_SIZE = 1024;
  193. char buffer[BUFFER_SIZE];
  194. while ( (res = fread(buffer, 1, BUFFER_SIZE, ifs)) > 0 )
  195. {
  196. if ( !gzwrite(gf, buffer, static_cast<int>(res)) )
  197. {
  198. fclose(ifs);
  199. gzclose(gf);
  200. return 0;
  201. }
  202. }
  203. fclose(ifs);
  204. gzclose(gf);
  205. return 1;
  206. }
  207. #else
  208. int cmGeneratedFileStreamBase::CompressFile(const char*, const char*)
  209. {
  210. return 0;
  211. }
  212. #endif
  213. //----------------------------------------------------------------------------
  214. int cmGeneratedFileStreamBase::RenameFile(const char* oldname,
  215. const char* newname)
  216. {
  217. return cmSystemTools::RenameFile(oldname, newname);
  218. }
  219. //----------------------------------------------------------------------------
  220. void cmGeneratedFileStream::SetName(const std::string& fname)
  221. {
  222. this->Name = fname;
  223. }