1
/*============================================================================
2
CMake - Cross Platform Makefile Generator
3
Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
5
Distributed under the OSI-approved BSD License (the "License");
6
see accompanying file Copyright.txt for details.
8
This software is distributed WITHOUT ANY WARRANTY; without even the
9
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
See the License for more information.
11
============================================================================*/
12
#include "cmArchiveWrite.h"
14
#include "cmSystemTools.h"
15
#include <cmsys/ios/iostream>
16
#include <cmsys/Directory.hxx>
17
#include <cm_libarchive.h>
19
//----------------------------------------------------------------------------
20
class cmArchiveWrite::Entry
22
struct archive_entry* Object;
24
Entry(): Object(archive_entry_new()) {}
25
~Entry() { archive_entry_free(this->Object); }
26
operator struct archive_entry*() { return this->Object; }
29
//----------------------------------------------------------------------------
30
struct cmArchiveWrite::Callback
32
// archive_write_callback
33
static __LA_SSIZE_T Write(struct archive*, void *cd,
34
const void *b, size_t n)
36
cmArchiveWrite* self = static_cast<cmArchiveWrite*>(cd);
37
if(self->Stream.write(static_cast<const char*>(b),
38
static_cast<cmsys_ios::streamsize>(n)))
40
return static_cast<__LA_SSIZE_T>(n);
44
return static_cast<__LA_SSIZE_T>(-1);
49
//----------------------------------------------------------------------------
50
cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c, Type t):
52
Archive(archive_write_new()),
53
Disk(archive_read_disk_new()),
59
if(archive_write_set_compression_none(this->Archive) != ARCHIVE_OK)
61
this->Error = "archive_write_set_compression_none: ";
62
this->Error += archive_error_string(this->Archive);
66
case CompressCompress:
67
if(archive_write_set_compression_compress(this->Archive) != ARCHIVE_OK)
69
this->Error = "archive_write_set_compression_compress: ";
70
this->Error += archive_error_string(this->Archive);
75
if(archive_write_set_compression_gzip(this->Archive) != ARCHIVE_OK)
77
this->Error = "archive_write_set_compression_gzip: ";
78
this->Error += archive_error_string(this->Archive);
83
if(archive_write_set_compression_bzip2(this->Archive) != ARCHIVE_OK)
85
this->Error = "archive_write_set_compression_bzip2: ";
86
this->Error += archive_error_string(this->Archive);
91
if(archive_write_set_compression_lzma(this->Archive) != ARCHIVE_OK)
93
this->Error = "archive_write_set_compression_lzma: ";
94
this->Error += archive_error_string(this->Archive);
99
if(archive_write_set_compression_xz(this->Archive) != ARCHIVE_OK)
101
this->Error = "archive_write_set_compression_xz: ";
102
this->Error += archive_error_string(this->Archive);
107
#if !defined(_WIN32) || defined(__CYGWIN__)
108
if (archive_read_disk_set_standard_lookup(this->Disk) != ARCHIVE_OK)
110
this->Error = "archive_read_disk_set_standard_lookup: ";
111
this->Error += archive_error_string(this->Archive);
118
if(archive_write_set_format_zip(this->Archive) != ARCHIVE_OK)
120
this->Error = "archive_write_set_format_zip: ";
121
this->Error += archive_error_string(this->Archive);
126
if(archive_write_set_format_pax_restricted(this->Archive) != ARCHIVE_OK)
128
this->Error = "archive_write_set_format_pax_restricted: ";
129
this->Error += archive_error_string(this->Archive);
135
// do not pad the last block!!
136
if (archive_write_set_bytes_in_last_block(this->Archive, 1))
138
this->Error = "archive_write_set_bytes_in_last_block: ";
139
this->Error += archive_error_string(this->Archive);
143
if(archive_write_open(
144
this->Archive, this, 0,
145
reinterpret_cast<archive_write_callback*>(&Callback::Write),
148
this->Error = "archive_write_open: ";
149
this->Error += archive_error_string(this->Archive);
154
//----------------------------------------------------------------------------
155
cmArchiveWrite::~cmArchiveWrite()
157
archive_read_finish(this->Disk);
158
archive_write_finish(this->Archive);
161
//----------------------------------------------------------------------------
162
bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix)
166
if(!path.empty() && path[path.size()-1] == '/')
168
path.erase(path.size()-1);
170
this->AddPath(path.c_str(), skip, prefix);
175
//----------------------------------------------------------------------------
176
bool cmArchiveWrite::AddPath(const char* path,
177
size_t skip, const char* prefix)
179
if(!this->AddFile(path, skip, prefix))
183
if(!cmSystemTools::FileIsDirectory(path) ||
184
cmSystemTools::FileIsSymlink(path))
191
std::string next = path;
193
std::string::size_type end = next.size();
194
unsigned long n = d.GetNumberOfFiles();
195
for(unsigned long i = 0; i < n; ++i)
197
const char* file = d.GetFile(i);
198
if(strcmp(file, ".") != 0 && strcmp(file, "..") != 0)
202
if(!this->AddPath(next.c_str(), skip, prefix))
212
//----------------------------------------------------------------------------
213
bool cmArchiveWrite::AddFile(const char* file,
214
size_t skip, const char* prefix)
216
// Skip the file if we have no name for it. This may happen on a
217
// top-level directory, which does not need to be included anyway.
218
if(skip >= strlen(file))
222
const char* out = file + skip;
225
std::string dest = prefix? prefix : "";
229
std::cout << dest << "\n";
232
archive_entry_copy_sourcepath(e, file);
233
archive_entry_set_pathname(e, dest.c_str());
234
if(archive_read_disk_entry_from_file(this->Disk, e, -1, 0) != ARCHIVE_OK)
236
this->Error = "archive_read_disk_entry_from_file: ";
237
this->Error += archive_error_string(this->Disk);
240
// Clear acl and xattr fields not useful for distribution.
241
archive_entry_acl_clear(e);
242
archive_entry_xattr_clear(e);
243
if(archive_write_header(this->Archive, e) != ARCHIVE_OK)
245
this->Error = "archive_write_header: ";
246
this->Error += archive_error_string(this->Archive);
251
if(size_t size = static_cast<size_t>(archive_entry_size(e)))
253
return this->AddData(file, size);
258
//----------------------------------------------------------------------------
259
bool cmArchiveWrite::AddData(const char* file, size_t size)
261
std::ifstream fin(file, std::ios::in | cmsys_ios_binary);
264
this->Error = "Error opening \"";
266
this->Error += "\": ";
267
this->Error += cmSystemTools::GetLastSystemError();
275
typedef cmsys_ios::streamsize ssize_type;
276
size_t const nnext = nleft > sizeof(buffer)? sizeof(buffer) : nleft;
277
ssize_type const nnext_s = static_cast<ssize_type>(nnext);
278
fin.read(buffer, nnext_s);
279
// Some stream libraries (older HPUX) return failure at end of
280
// file on the last read even if some data were read. Check
281
// gcount instead of trusting the stream error status.
282
if(static_cast<size_t>(fin.gcount()) != nnext)
286
if(archive_write_data(this->Archive, buffer, nnext) != nnext_s)
288
this->Error = "archive_write_data: ";
289
this->Error += archive_error_string(this->Archive);
296
this->Error = "Error reading \"";
298
this->Error += "\": ";
299
this->Error += cmSystemTools::GetLastSystemError();