cmCPackTGZGenerator.cxx 8.1 KB

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