1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCPackTGZGenerator.cxx,v $
6 Date: $Date: 2007-09-27 18:44:10 $
7 Version: $Revision: 1.19 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "cmCPackTGZGenerator.h"
21 #include "cmGlobalGenerator.h"
22 #include "cmLocalGenerator.h"
23 #include "cmSystemTools.h"
24 #include "cmMakefile.h"
25 #include "cmGeneratedFileStream.h"
26 #include "cmCPackLog.h"
28 #include <cmsys/SystemTools.hxx>
30 #include <libtar/libtar.h>
31 #include <memory> // auto_ptr
35 //----------------------------------------------------------------------
36 class cmCPackTGZGeneratorForward
39 static int GenerateHeader(cmCPackTGZGenerator
* gg
, std::ostream
* os
)
41 return gg
->GenerateHeader(os
);
45 //----------------------------------------------------------------------
46 cmCPackTGZGenerator::cmCPackTGZGenerator()
48 this->Compress
= true;
51 //----------------------------------------------------------------------
52 cmCPackTGZGenerator::~cmCPackTGZGenerator()
56 static const size_t cmCPackTGZ_Data_BlockSize
= 16384;
58 //----------------------------------------------------------------------
62 cmCPackTGZ_Data(cmCPackTGZGenerator
* gen
, bool compress
) :
63 OutputStream(0), Generator(gen
),
64 CompressionLevel(Z_DEFAULT_COMPRESSION
),
66 std::ostream
* OutputStream
;
67 cmCPackTGZGenerator
* Generator
;
68 char CompressedBuffer
[cmCPackTGZ_Data_BlockSize
];
75 //----------------------------------------------------------------------
77 int cmCPackTGZ_Data_Open(void *client_data
, const char* name
, int oflags
,
79 ssize_t
cmCPackTGZ_Data_Write(void *client_data
, void *buff
, size_t n
);
80 int cmCPackTGZ_Data_Close(void *client_data
);
84 //----------------------------------------------------------------------
85 int cmCPackTGZ_Data_Open(void *client_data
, const char* pathname
,
88 cmCPackTGZ_Data
*mydata
= (cmCPackTGZ_Data
*)client_data
;
90 if ( mydata
->Compress
)
92 mydata
->ZLibStream
.zalloc
= Z_NULL
;
93 mydata
->ZLibStream
.zfree
= Z_NULL
;
94 mydata
->ZLibStream
.opaque
= Z_NULL
;
95 int strategy
= Z_DEFAULT_STRATEGY
;
96 if ( deflateInit2(&mydata
->ZLibStream
, mydata
->CompressionLevel
,
97 Z_DEFLATED
, -MAX_WBITS
, 8, strategy
) != Z_OK
)
103 cmGeneratedFileStream
* gf
= new cmGeneratedFileStream
;
105 gf
->Open(pathname
, false, true);
106 mydata
->OutputStream
= gf
;
107 if ( !*mydata
->OutputStream
)
112 if ( !cmCPackTGZGeneratorForward::GenerateHeader(mydata
->Generator
,gf
))
117 if ( mydata
->Compress
)
119 mydata
->CRC
= crc32(0L, Z_NULL
, 0);
125 //----------------------------------------------------------------------
126 ssize_t
cmCPackTGZ_Data_Write(void *client_data
, void *buff
, size_t n
)
128 cmCPackTGZ_Data
*mydata
= (cmCPackTGZ_Data
*)client_data
;
130 if ( mydata
->Compress
)
132 mydata
->ZLibStream
.avail_in
= static_cast<uInt
>(n
);
133 mydata
->ZLibStream
.next_in
= reinterpret_cast<Bytef
*>(buff
);
136 mydata
->ZLibStream
.avail_out
= cmCPackTGZ_Data_BlockSize
;
137 mydata
->ZLibStream
.next_out
138 = reinterpret_cast<Bytef
*>(mydata
->CompressedBuffer
);
139 // no bad return value
140 int ret
= deflate(&mydata
->ZLibStream
, (n
?Z_NO_FLUSH
:Z_FINISH
));
141 if(ret
== Z_STREAM_ERROR
)
146 size_t compressedSize
147 = cmCPackTGZ_Data_BlockSize
- mydata
->ZLibStream
.avail_out
;
149 mydata
->OutputStream
->write(
150 reinterpret_cast<const char*>(mydata
->CompressedBuffer
),
152 } while ( mydata
->ZLibStream
.avail_out
== 0 );
154 if ( !*mydata
->OutputStream
)
160 mydata
->CRC
= crc32(mydata
->CRC
, reinterpret_cast<Bytef
*>(buff
),
161 static_cast<uInt
>(n
));
166 mydata
->OutputStream
->write(reinterpret_cast<char*>(buff
), n
);
171 //----------------------------------------------------------------------
172 int cmCPackTGZ_Data_Close(void *client_data
)
174 cmCPackTGZ_Data
*mydata
= (cmCPackTGZ_Data
*)client_data
;
176 if ( mydata
->Compress
)
178 cmCPackTGZ_Data_Write(client_data
, 0, 0);
182 uLong x
= mydata
->CRC
;
183 for (n
= 0; n
< 4; n
++) {
184 buffer
[n
] = (int)(x
& 0xff);
187 x
= mydata
->ZLibStream
.total_in
;
188 for (n
= 0; n
< 4; n
++) {
189 buffer
[n
+4] = (int)(x
& 0xff);
193 mydata
->OutputStream
->write(buffer
, 8);
194 (void)deflateEnd(&mydata
->ZLibStream
);
196 delete mydata
->OutputStream
;
197 mydata
->OutputStream
= 0;
201 //----------------------------------------------------------------------
202 int cmCPackTGZGenerator::InitializeInternal()
204 this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
205 return this->Superclass::InitializeInternal();
208 //----------------------------------------------------------------------
209 int cmCPackTGZGenerator::CompressFiles(const char* outFileName
,
210 const char* toplevel
, const std::vector
<std::string
>& files
)
212 cmCPackLogger(cmCPackLog::LOG_DEBUG
, "Toplevel: "
213 << (toplevel
? toplevel
: "(NULL)") << std::endl
);
214 cmCPackTGZ_Data
mydata(this, this->Compress
);
216 char buf
[TAR_MAXPATHLEN
];
217 char pathname
[TAR_MAXPATHLEN
];
220 (openfunc_t
)cmCPackTGZ_Data_Open
,
221 (closefunc_t
)cmCPackTGZ_Data_Close
,
223 (writefunc_t
)cmCPackTGZ_Data_Write
,
227 // Ok, this libtar is not const safe. for now use auto_ptr hack
228 char* realName
= new char[ strlen(outFileName
) + 1 ];
229 std::auto_ptr
<char> realNamePtr(realName
);
230 strcpy(realName
, outFileName
);
231 int flags
= O_WRONLY
| O_CREAT
;
233 if(this->GeneratorVerbose
)
235 options
|= TAR_VERBOSE
;
240 if (tar_open(&t
, realName
,
245 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Problem with tar_open(): "
246 << strerror(errno
) << std::endl
);
250 std::vector
<std::string
>::const_iterator fileIt
;
251 for ( fileIt
= files
.begin(); fileIt
!= files
.end(); ++ fileIt
)
253 std::string rp
= cmSystemTools::RelativePath(toplevel
, fileIt
->c_str());
254 strncpy(pathname
, fileIt
->c_str(), sizeof(pathname
));
255 pathname
[sizeof(pathname
)-1] = 0;
256 strncpy(buf
, rp
.c_str(), sizeof(buf
));
257 buf
[sizeof(buf
)-1] = 0;
258 if (tar_append_tree(t
, pathname
, buf
) != 0)
260 cmCPackLogger(cmCPackLog::LOG_ERROR
,
261 "Problem with tar_append_tree(\"" << buf
<< "\", \""
262 << pathname
<< "\"): "
263 << strerror(errno
) << std::endl
);
268 if (tar_append_eof(t
) != 0)
270 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Problem with tar_append_eof(): "
271 << strerror(errno
) << std::endl
);
276 if (tar_close(t
) != 0)
278 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Problem with tar_close(): "
279 << strerror(errno
) << std::endl
);
285 //----------------------------------------------------------------------
286 int cmCPackTGZGenerator::GenerateHeader(std::ostream
* os
)
288 if ( this->Compress
)
290 const int gz_magic
[2] = {0x1f, 0x8b}; /* gzip magic header */
292 sprintf(header
, "%c%c%c%c%c%c%c%c%c%c", gz_magic
[0], gz_magic
[1],
293 Z_DEFLATED
, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/,
294 3 /* zlib os code for UNIX, not really used anyway */);
295 os
->write(header
, 10);