cmCPackTGZGenerator.cxx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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 <cmzlib/zutil.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. }
  40. //----------------------------------------------------------------------
  41. cmCPackTGZGenerator::~cmCPackTGZGenerator()
  42. {
  43. }
  44. static const size_t cmCPackTGZ_Data_BlockSize = 16384;
  45. //----------------------------------------------------------------------
  46. class cmCPackTGZ_Data
  47. {
  48. public:
  49. cmCPackTGZ_Data(cmCPackTGZGenerator* gen) :
  50. OutputStream(0), Generator(gen),
  51. m_CompressionLevel(Z_DEFAULT_COMPRESSION) {}
  52. std::ostream* OutputStream;
  53. cmCPackTGZGenerator* Generator;
  54. char m_CompressedBuffer[cmCPackTGZ_Data_BlockSize];
  55. int m_CompressionLevel;
  56. z_stream m_ZLibStream;
  57. uLong m_CRC;
  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. mydata->m_ZLibStream.zalloc = Z_NULL;
  72. mydata->m_ZLibStream.zfree = Z_NULL;
  73. mydata->m_ZLibStream.opaque = Z_NULL;
  74. int strategy = Z_DEFAULT_STRATEGY;
  75. if ( deflateInit2(&mydata->m_ZLibStream, mydata->m_CompressionLevel,
  76. Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy) != Z_OK )
  77. {
  78. return -1;
  79. }
  80. cmGeneratedFileStream* gf = new cmGeneratedFileStream;
  81. // Open binary
  82. gf->Open(pathname, false, true);
  83. mydata->OutputStream = gf;
  84. if ( !*mydata->OutputStream )
  85. {
  86. return -1;
  87. }
  88. if ( !cmCPackTGZGeneratorForward::GenerateHeader(mydata->Generator,gf))
  89. {
  90. return -1;
  91. }
  92. mydata->m_CRC = crc32(0L, Z_NULL, 0);
  93. return 0;
  94. }
  95. //----------------------------------------------------------------------
  96. ssize_t cmCPackTGZ_Data_Write(void *client_data, void *buff, size_t n)
  97. {
  98. cmCPackTGZ_Data *mydata = (cmCPackTGZ_Data*)client_data;
  99. mydata->m_ZLibStream.avail_in = n;
  100. mydata->m_ZLibStream.next_in = reinterpret_cast<Bytef*>(buff);
  101. do {
  102. mydata->m_ZLibStream.avail_out = cmCPackTGZ_Data_BlockSize;
  103. mydata->m_ZLibStream.next_out
  104. = reinterpret_cast<Bytef*>(mydata->m_CompressedBuffer);
  105. // no bad return value
  106. int ret = deflate(&mydata->m_ZLibStream, (n?Z_NO_FLUSH:Z_FINISH));
  107. if(ret == Z_STREAM_ERROR)
  108. {
  109. return 0;
  110. }
  111. size_t compressedSize
  112. = cmCPackTGZ_Data_BlockSize - mydata->m_ZLibStream.avail_out;
  113. mydata->OutputStream->write(
  114. reinterpret_cast<const char*>(mydata->m_CompressedBuffer),
  115. compressedSize);
  116. } while ( mydata->m_ZLibStream.avail_out == 0 );
  117. if ( !*mydata->OutputStream )
  118. {
  119. return 0;
  120. }
  121. if ( n )
  122. {
  123. mydata->m_CRC = crc32(mydata->m_CRC, reinterpret_cast<Bytef *>(buff), n);
  124. }
  125. return n;
  126. }
  127. //----------------------------------------------------------------------
  128. int cmCPackTGZ_Data_Close(void *client_data)
  129. {
  130. cmCPackTGZ_Data *mydata = (cmCPackTGZ_Data*)client_data;
  131. cmCPackTGZ_Data_Write(client_data, 0, 0);
  132. char buffer[8];
  133. int n;
  134. uLong x = mydata->m_CRC;
  135. for (n = 0; n < 4; n++) {
  136. buffer[n] = (int)(x & 0xff);
  137. x >>= 8;
  138. }
  139. x = mydata->m_ZLibStream.total_in;
  140. for (n = 0; n < 4; n++) {
  141. buffer[n+4] = (int)(x & 0xff);
  142. x >>= 8;
  143. }
  144. mydata->OutputStream->write(buffer, 8);
  145. (void)deflateEnd(&mydata->m_ZLibStream);
  146. delete mydata->OutputStream;
  147. mydata->OutputStream = 0;
  148. return (0);
  149. }
  150. //----------------------------------------------------------------------
  151. int cmCPackTGZGenerator::CompressFiles(const char* outFileName,
  152. const char* toplevel, const std::vector<std::string>& files)
  153. {
  154. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
  155. cmCPackTGZ_Data mydata(this);
  156. TAR *t;
  157. char buf[TAR_MAXPATHLEN];
  158. char pathname[TAR_MAXPATHLEN];
  159. tartype_t gztype = {
  160. (openfunc_t)cmCPackTGZ_Data_Open,
  161. (closefunc_t)cmCPackTGZ_Data_Close,
  162. (readfunc_t)0,
  163. (writefunc_t)cmCPackTGZ_Data_Write,
  164. &mydata
  165. };
  166. // Ok, this libtar is not const safe. for now use auto_ptr hack
  167. char* realName = new char[ strlen(outFileName) + 1 ];
  168. std::auto_ptr<char> realNamePtr(realName);
  169. strcpy(realName, outFileName);
  170. int flags = O_WRONLY | O_CREAT;
  171. if (tar_open(&t, realName,
  172. &gztype,
  173. flags, 0644,
  174. (m_GeneratorVerbose?TAR_VERBOSE:0)
  175. | 0) == -1)
  176. {
  177. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_open(): "
  178. << strerror(errno) << std::endl);
  179. return 0;
  180. }
  181. std::vector<std::string>::const_iterator fileIt;
  182. for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
  183. {
  184. std::string rp = cmSystemTools::RelativePath(toplevel, fileIt->c_str());
  185. strncpy(pathname, fileIt->c_str(), sizeof(pathname));
  186. pathname[sizeof(pathname)-1] = 0;
  187. strncpy(buf, rp.c_str(), sizeof(buf));
  188. buf[sizeof(buf)-1] = 0;
  189. if (tar_append_tree(t, pathname, buf) != 0)
  190. {
  191. cmCPackLogger(cmCPackLog::LOG_ERROR,
  192. "Problem with tar_append_tree(\"" << buf << "\", \""
  193. << pathname << "\"): "
  194. << strerror(errno) << std::endl);
  195. tar_close(t);
  196. return 0;
  197. }
  198. }
  199. if (tar_append_eof(t) != 0)
  200. {
  201. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_append_eof(): "
  202. << strerror(errno) << std::endl);
  203. tar_close(t);
  204. return 0;
  205. }
  206. if (tar_close(t) != 0)
  207. {
  208. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_close(): "
  209. << strerror(errno) << std::endl);
  210. return 0;
  211. }
  212. return 1;
  213. }
  214. //----------------------------------------------------------------------
  215. int cmCPackTGZGenerator::GenerateHeader(std::ostream* os)
  216. {
  217. const int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
  218. char header[11];
  219. sprintf(header, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
  220. Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
  221. os->write(header, 10);
  222. return 1;
  223. }