cmCPackTGZGenerator.cxx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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 "cmCPackTGZGenerator.h"
  14. #include "cmake.h"
  15. #include "cmGlobalGenerator.h"
  16. #include "cmLocalGenerator.h"
  17. #include "cmSystemTools.h"
  18. #include "cmMakefile.h"
  19. #include "cmGeneratedFileStream.h"
  20. #include "cmCPackLog.h"
  21. #include <cmsys/SystemTools.hxx>
  22. #include <cm_zlib.h>
  23. #include <libtar/libtar.h>
  24. #include <memory> // auto_ptr
  25. #include <fcntl.h>
  26. #include <errno.h>
  27. //----------------------------------------------------------------------
  28. class cmCPackTGZGeneratorForward
  29. {
  30. public:
  31. static int GenerateHeader(cmCPackTGZGenerator* gg, std::ostream* os)
  32. {
  33. return gg->GenerateHeader(os);
  34. }
  35. };
  36. //----------------------------------------------------------------------
  37. cmCPackTGZGenerator::cmCPackTGZGenerator()
  38. {
  39. this->Compress = true;
  40. }
  41. //----------------------------------------------------------------------
  42. cmCPackTGZGenerator::~cmCPackTGZGenerator()
  43. {
  44. }
  45. static const size_t cmCPackTGZ_Data_BlockSize = 16384;
  46. //----------------------------------------------------------------------
  47. class cmCPackTGZ_Data
  48. {
  49. public:
  50. cmCPackTGZ_Data(cmCPackTGZGenerator* gen, bool compress) :
  51. OutputStream(0), Generator(gen),
  52. CompressionLevel(Z_DEFAULT_COMPRESSION),
  53. Compress(compress) {}
  54. std::ostream* OutputStream;
  55. cmCPackTGZGenerator* Generator;
  56. char CompressedBuffer[cmCPackTGZ_Data_BlockSize];
  57. int CompressionLevel;
  58. z_stream ZLibStream;
  59. uLong CRC;
  60. bool Compress;
  61. };
  62. //----------------------------------------------------------------------
  63. extern "C" {
  64. int cmCPackTGZ_Data_Open(void *client_data, const char* name, int oflags,
  65. mode_t mode);
  66. ssize_t cmCPackTGZ_Data_Write(void *client_data, void *buff, size_t n);
  67. int cmCPackTGZ_Data_Close(void *client_data);
  68. }
  69. //----------------------------------------------------------------------
  70. int cmCPackTGZ_Data_Open(void *client_data, const char* pathname,
  71. int, mode_t)
  72. {
  73. cmCPackTGZ_Data *mydata = (cmCPackTGZ_Data*)client_data;
  74. if ( mydata->Compress )
  75. {
  76. mydata->ZLibStream.zalloc = Z_NULL;
  77. mydata->ZLibStream.zfree = Z_NULL;
  78. mydata->ZLibStream.opaque = Z_NULL;
  79. int strategy = Z_DEFAULT_STRATEGY;
  80. if ( deflateInit2(&mydata->ZLibStream, mydata->CompressionLevel,
  81. Z_DEFLATED, -MAX_WBITS, 8, strategy) != Z_OK )
  82. {
  83. return -1;
  84. }
  85. }
  86. cmGeneratedFileStream* gf = new cmGeneratedFileStream;
  87. // Open binary
  88. gf->Open(pathname, false, true);
  89. mydata->OutputStream = gf;
  90. if ( !*mydata->OutputStream )
  91. {
  92. return -1;
  93. }
  94. if ( !cmCPackTGZGeneratorForward::GenerateHeader(mydata->Generator,gf))
  95. {
  96. return -1;
  97. }
  98. if ( mydata->Compress )
  99. {
  100. mydata->CRC = crc32(0L, Z_NULL, 0);
  101. }
  102. return 0;
  103. }
  104. //----------------------------------------------------------------------
  105. ssize_t cmCPackTGZ_Data_Write(void *client_data, void *buff, size_t n)
  106. {
  107. cmCPackTGZ_Data *mydata = (cmCPackTGZ_Data*)client_data;
  108. if ( mydata->Compress )
  109. {
  110. mydata->ZLibStream.avail_in = n;
  111. mydata->ZLibStream.next_in = reinterpret_cast<Bytef*>(buff);
  112. do {
  113. mydata->ZLibStream.avail_out = cmCPackTGZ_Data_BlockSize;
  114. mydata->ZLibStream.next_out
  115. = reinterpret_cast<Bytef*>(mydata->CompressedBuffer);
  116. // no bad return value
  117. int ret = deflate(&mydata->ZLibStream, (n?Z_NO_FLUSH:Z_FINISH));
  118. if(ret == Z_STREAM_ERROR)
  119. {
  120. return 0;
  121. }
  122. size_t compressedSize
  123. = cmCPackTGZ_Data_BlockSize - mydata->ZLibStream.avail_out;
  124. mydata->OutputStream->write(
  125. reinterpret_cast<const char*>(mydata->CompressedBuffer),
  126. compressedSize);
  127. } while ( mydata->ZLibStream.avail_out == 0 );
  128. if ( !*mydata->OutputStream )
  129. {
  130. return 0;
  131. }
  132. if ( n )
  133. {
  134. mydata->CRC = crc32(mydata->CRC, reinterpret_cast<Bytef *>(buff), n);
  135. }
  136. }
  137. else
  138. {
  139. mydata->OutputStream->write(reinterpret_cast<char*>(buff), n);
  140. }
  141. return n;
  142. }
  143. //----------------------------------------------------------------------
  144. int cmCPackTGZ_Data_Close(void *client_data)
  145. {
  146. cmCPackTGZ_Data *mydata = (cmCPackTGZ_Data*)client_data;
  147. if ( mydata->Compress )
  148. {
  149. cmCPackTGZ_Data_Write(client_data, 0, 0);
  150. char buffer[8];
  151. int n;
  152. uLong x = mydata->CRC;
  153. for (n = 0; n < 4; n++) {
  154. buffer[n] = (int)(x & 0xff);
  155. x >>= 8;
  156. }
  157. x = mydata->ZLibStream.total_in;
  158. for (n = 0; n < 4; n++) {
  159. buffer[n+4] = (int)(x & 0xff);
  160. x >>= 8;
  161. }
  162. mydata->OutputStream->write(buffer, 8);
  163. (void)deflateEnd(&mydata->ZLibStream);
  164. }
  165. delete mydata->OutputStream;
  166. mydata->OutputStream = 0;
  167. return (0);
  168. }
  169. //----------------------------------------------------------------------
  170. int cmCPackTGZGenerator::InitializeInternal()
  171. {
  172. this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
  173. return this->Superclass::InitializeInternal();
  174. }
  175. //----------------------------------------------------------------------
  176. int cmCPackTGZGenerator::CompressFiles(const char* outFileName,
  177. const char* toplevel, const std::vector<std::string>& files)
  178. {
  179. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: "
  180. << (toplevel ? toplevel : "(NULL)") << std::endl);
  181. cmCPackTGZ_Data mydata(this, this->Compress);
  182. TAR *t;
  183. char buf[TAR_MAXPATHLEN];
  184. char pathname[TAR_MAXPATHLEN];
  185. tartype_t gztype = {
  186. (openfunc_t)cmCPackTGZ_Data_Open,
  187. (closefunc_t)cmCPackTGZ_Data_Close,
  188. (readfunc_t)0,
  189. (writefunc_t)cmCPackTGZ_Data_Write,
  190. &mydata
  191. };
  192. // Ok, this libtar is not const safe. for now use auto_ptr hack
  193. char* realName = new char[ strlen(outFileName) + 1 ];
  194. std::auto_ptr<char> realNamePtr(realName);
  195. strcpy(realName, outFileName);
  196. int flags = O_WRONLY | O_CREAT;
  197. if (tar_open(&t, realName,
  198. &gztype,
  199. flags, 0644,
  200. (this->GeneratorVerbose?TAR_VERBOSE:0)
  201. | 0) == -1)
  202. {
  203. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_open(): "
  204. << strerror(errno) << std::endl);
  205. return 0;
  206. }
  207. std::vector<std::string>::const_iterator fileIt;
  208. for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
  209. {
  210. std::string rp = cmSystemTools::RelativePath(toplevel, fileIt->c_str());
  211. strncpy(pathname, fileIt->c_str(), sizeof(pathname));
  212. pathname[sizeof(pathname)-1] = 0;
  213. strncpy(buf, rp.c_str(), sizeof(buf));
  214. buf[sizeof(buf)-1] = 0;
  215. if (tar_append_tree(t, pathname, buf) != 0)
  216. {
  217. cmCPackLogger(cmCPackLog::LOG_ERROR,
  218. "Problem with tar_append_tree(\"" << buf << "\", \""
  219. << pathname << "\"): "
  220. << strerror(errno) << std::endl);
  221. tar_close(t);
  222. return 0;
  223. }
  224. }
  225. if (tar_append_eof(t) != 0)
  226. {
  227. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_append_eof(): "
  228. << strerror(errno) << std::endl);
  229. tar_close(t);
  230. return 0;
  231. }
  232. if (tar_close(t) != 0)
  233. {
  234. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_close(): "
  235. << strerror(errno) << std::endl);
  236. return 0;
  237. }
  238. return 1;
  239. }
  240. //----------------------------------------------------------------------
  241. int cmCPackTGZGenerator::GenerateHeader(std::ostream* os)
  242. {
  243. if ( this->Compress )
  244. {
  245. const int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
  246. char header[11];
  247. sprintf(header, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
  248. Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/,
  249. 3 /* zlib os code for UNIX, not really used anyway */);
  250. os->write(header, 10);
  251. }
  252. return 1;
  253. }