cmCPackArchiveGenerator.cxx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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 "cmCPackArchiveGenerator.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 <errno.h>
  19. #include <cmsys/SystemTools.hxx>
  20. #include <cm_libarchive.h>
  21. //----------------------------------------------------------------------
  22. cmCPackArchiveGenerator::cmCPackArchiveGenerator(CompressType t,
  23. ArchiveType at)
  24. {
  25. this->Compress = t;
  26. this->Archive = at;
  27. }
  28. //----------------------------------------------------------------------
  29. cmCPackArchiveGenerator::~cmCPackArchiveGenerator()
  30. {
  31. }
  32. static const size_t cmCPackTGZ_Data_BlockSize = 16384;
  33. // make this an anonymous namespace so that archive.h does not
  34. // have to be included in the .h file for this class
  35. namespace
  36. {
  37. bool SetArchiveType(struct archive* a,
  38. cmCPackArchiveGenerator::CompressType ct,
  39. cmCPackArchiveGenerator::ArchiveType at)
  40. {
  41. int res = 0;
  42. // pick the archive type
  43. switch(at)
  44. {
  45. case cmCPackArchiveGenerator::TAR:
  46. // maybe this:
  47. res = archive_write_set_format_pax_restricted(a);
  48. break;
  49. case cmCPackArchiveGenerator::ZIP:
  50. res = archive_write_set_format_zip(a);
  51. break;
  52. }
  53. if(res != ARCHIVE_OK)
  54. {
  55. return false;
  56. }
  57. // pick a compression type
  58. switch(ct)
  59. {
  60. case cmCPackArchiveGenerator::GZIP:
  61. res = archive_write_set_compression_gzip(a);
  62. break;
  63. case cmCPackArchiveGenerator::BZIP2:
  64. res = archive_write_set_compression_bzip2(a);
  65. break;
  66. case cmCPackArchiveGenerator::COMPRESS:
  67. res = archive_write_set_compression_compress(a);
  68. break;
  69. case cmCPackArchiveGenerator::LZMA:
  70. res = archive_write_set_compression_lzma(a);
  71. break;
  72. case cmCPackArchiveGenerator::NONE:
  73. default:
  74. res = archive_write_set_compression_none(a);
  75. }
  76. if(res != ARCHIVE_OK)
  77. {
  78. return false;
  79. }
  80. // do not pad the last block!!
  81. res = archive_write_set_bytes_in_last_block(a, 1);
  82. if(res != ARCHIVE_OK)
  83. {
  84. return false;
  85. }
  86. return true;
  87. }
  88. struct StreamData
  89. {
  90. StreamData(cmGeneratedFileStream* gfs,
  91. cmCPackArchiveGenerator* ag)
  92. {
  93. this->GeneratedFileStream = gfs;
  94. this->Generator = ag;
  95. }
  96. cmGeneratedFileStream* GeneratedFileStream;
  97. cmCPackArchiveGenerator* Generator;
  98. };
  99. extern "C"
  100. {
  101. int OpenArchive(struct archive *, void *client_data)
  102. {
  103. struct StreamData *data = (StreamData*)client_data;
  104. if(data->GeneratedFileStream &&
  105. *data->GeneratedFileStream)
  106. {
  107. if(data->Generator->
  108. GenerateHeader(data->GeneratedFileStream))
  109. {
  110. return ARCHIVE_OK;
  111. }
  112. }
  113. return (ARCHIVE_FATAL);
  114. }
  115. __LA_SSIZE_T WriteArchive(struct archive *,
  116. void *client_data,
  117. const void *buff,
  118. size_t n)
  119. {
  120. struct StreamData *data = (StreamData*)client_data;
  121. data->GeneratedFileStream->
  122. write(reinterpret_cast<const char*>(buff),n);
  123. if(!data->GeneratedFileStream->bad())
  124. {
  125. return n;
  126. }
  127. return 0;
  128. }
  129. int CloseArchive(struct archive *, void *client_data)
  130. {
  131. struct StreamData *data = (StreamData*)client_data;
  132. if(data->GeneratedFileStream->Close())
  133. {
  134. delete data->GeneratedFileStream;
  135. return ARCHIVE_OK;
  136. }
  137. return ARCHIVE_FATAL;
  138. }
  139. } //extern C
  140. } // anon name space
  141. //----------------------------------------------------------------------
  142. int cmCPackArchiveGenerator::InitializeInternal()
  143. {
  144. this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
  145. return this->Superclass::InitializeInternal();
  146. }
  147. int cmCPackArchiveGenerator::PackageFiles()
  148. {
  149. int res = ARCHIVE_OK;
  150. #define CHECK_ARCHIVE_ERROR(res, msg) \
  151. if(res != ARCHIVE_OK) \
  152. {\
  153. cmCPackLogger(cmCPackLog::LOG_ERROR, msg \
  154. << archive_error_string(a) \
  155. << cmSystemTools::GetLastSystemError() \
  156. << " " << res \
  157. << "\n"); \
  158. }
  159. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: "
  160. << toplevel << std::endl);
  161. // create a new archive
  162. struct archive* a = archive_write_new();
  163. // Set the compress and archive types for the archive
  164. SetArchiveType(a, this->Compress, this->Archive);
  165. // Open binary stream
  166. cmGeneratedFileStream* gf = new cmGeneratedFileStream;
  167. gf->Open(packageFileNames[0].c_str(), false, true);
  168. StreamData data(gf, this);
  169. // pass callbacks to archive_write_open to handle stream
  170. res = archive_write_open(a,
  171. &data,
  172. OpenArchive,
  173. WriteArchive,
  174. CloseArchive);
  175. CHECK_ARCHIVE_ERROR(res, "archive_write_open:");
  176. // create a new disk struct
  177. struct archive* disk = archive_read_disk_new();
  178. #if !defined(_WIN32) || defined(__CYGWIN__)
  179. res = archive_read_disk_set_standard_lookup(disk);
  180. #endif
  181. CHECK_ARCHIVE_ERROR(res, "archive_read_disk_set_standard_lookup:");
  182. std::vector<std::string>::const_iterator fileIt;
  183. std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
  184. cmSystemTools::ChangeDirectory(toplevel.c_str());
  185. for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
  186. {
  187. // create a new entry for each file
  188. struct archive_entry *entry = archive_entry_new();
  189. // Get the relative path to the file
  190. std::string rp = cmSystemTools::RelativePath(toplevel.c_str(), fileIt->c_str());
  191. // Set the name of the entry to the file name
  192. archive_entry_set_pathname(entry, rp.c_str());
  193. res = archive_read_disk_entry_from_file(disk, entry, -1, 0);
  194. CHECK_ARCHIVE_ERROR(res, "archive_read_disk_entry_from_file:");
  195. // write entry header
  196. res = archive_write_header(a, entry);
  197. CHECK_ARCHIVE_ERROR(res, "archive_write_header:");
  198. // the entry size can be 0 if it is a symlink
  199. if(archive_entry_size(entry) > 0)
  200. {
  201. // now copy contents of file into archive a
  202. FILE* file = fopen(fileIt->c_str(), "rb");
  203. if(!file)
  204. {
  205. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with fopen(): "
  206. << fileIt->c_str()
  207. << strerror(errno)
  208. << std::endl);
  209. return 0;
  210. }
  211. char buff[cmCPackTGZ_Data_BlockSize];
  212. size_t len = fread(buff, 1, sizeof(buff), file);
  213. while (len > 0)
  214. {
  215. size_t wlen = archive_write_data(a, buff, len);
  216. if(wlen != len)
  217. {
  218. cmCPackLogger(cmCPackLog::LOG_ERROR, "archive_write_data(): "
  219. << "tried to write " << len << "\n"
  220. << "write " << wlen << "\n");
  221. return 0;
  222. }
  223. len = fread(buff, 1, sizeof(buff), file);
  224. }
  225. // close the file and free the entry
  226. fclose(file);
  227. }
  228. archive_entry_free(entry);
  229. }
  230. cmSystemTools::ChangeDirectory(dir.c_str());
  231. // close the archive and finish the write
  232. archive_write_close(a);
  233. archive_write_finish(a);
  234. archive_read_finish(disk);
  235. return 1;
  236. }
  237. //----------------------------------------------------------------------
  238. int cmCPackArchiveGenerator::GenerateHeader(std::ostream*)
  239. {
  240. return 1;
  241. }