summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2010-08-10 18:35:41 (GMT)
committerCMake Topic Stage <kwrobot@kitware.com>2010-08-10 18:35:41 (GMT)
commit6d856795510fc7cdab8c1ab1d7aa0ade1113646b (patch)
treeab3bb8d9770cc6763966c7092334f81f3bbf5a72
parentcc31f89c17f365c63065c78a25d26075f453d31a (diff)
parentaef672311aa8b802c4477a4d51f531f752a6a787 (diff)
downloadCMake-6d856795510fc7cdab8c1ab1d7aa0ade1113646b.zip
CMake-6d856795510fc7cdab8c1ab1d7aa0ade1113646b.tar.gz
CMake-6d856795510fc7cdab8c1ab1d7aa0ade1113646b.tar.bz2
Merge topic 'libarchive-wrapper'
aef6723 cmArchiveWrite: Fix signed/unsigned compare/convert 1b5b2ed Include entries for directories in tarballs (#11020) c7c9009 Create class cmArchiveWrite to wrap libarchive (#11020) ac26737 Merge branch 'system-libarchive-include' into libarchive-wrapper 3296e6a Include headers from chosen libarchive (#10923)
-rw-r--r--Source/CMakeLists.txt1
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.cxx4
-rw-r--r--Source/cmArchiveWrite.cxx247
-rw-r--r--Source/cmArchiveWrite.h84
-rw-r--r--Source/cmSystemTools.cxx148
-rw-r--r--Utilities/cmThirdParty.h.in1
-rw-r--r--Utilities/cm_libarchive.h25
7 files changed, 382 insertions, 128 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index b098da1..71284b2 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -112,6 +112,7 @@ ENDIF(CMAKE_USE_ELF_PARSER)
#
SET(SRCS
cmStandardIncludes.cxx
+ cmArchiveWrite.cxx
cmBootstrapCommands.cxx
cmCacheManager.cxx
cmCacheManager.h
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
index a52d05e..5981603 100644
--- a/Source/CPack/cmCPackArchiveGenerator.cxx
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -22,9 +22,7 @@
#include <errno.h>
#include <cmsys/SystemTools.hxx>
-#include <cmlibarchive/libarchive/archive.h>
-#include <cmlibarchive/libarchive/archive_entry.h>
-
+#include <cm_libarchive.h>
//----------------------------------------------------------------------
cmCPackArchiveGenerator::cmCPackArchiveGenerator(CompressType t,
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
new file mode 100644
index 0000000..88874aa
--- /dev/null
+++ b/Source/cmArchiveWrite.cxx
@@ -0,0 +1,247 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmArchiveWrite.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/ios/iostream>
+#include <cmsys/Directory.hxx>
+#include <cm_libarchive.h>
+
+//----------------------------------------------------------------------------
+class cmArchiveWrite::Entry
+{
+ struct archive_entry* Object;
+public:
+ Entry(): Object(archive_entry_new()) {}
+ ~Entry() { archive_entry_free(this->Object); }
+ operator struct archive_entry*() { return this->Object; }
+};
+
+//----------------------------------------------------------------------------
+struct cmArchiveWrite::Callback
+{
+ // archive_write_callback
+ static __LA_SSIZE_T Write(struct archive*, void *cd,
+ const void *b, size_t n)
+ {
+ cmArchiveWrite* self = static_cast<cmArchiveWrite*>(cd);
+ if(self->Stream.write(static_cast<const char*>(b),
+ static_cast<cmsys_ios::streamsize>(n)))
+ {
+ return static_cast<__LA_SSIZE_T>(n);
+ }
+ else
+ {
+ return static_cast<__LA_SSIZE_T>(-1);
+ }
+ }
+};
+
+//----------------------------------------------------------------------------
+cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c):
+ Stream(os),
+ Archive(archive_write_new()),
+ Disk(archive_read_disk_new()),
+ Verbose(false)
+{
+ switch (c)
+ {
+ case CompressNone:
+ if(archive_write_set_compression_none(this->Archive) != ARCHIVE_OK)
+ {
+ this->Error = "archive_write_set_compression_none: ";
+ this->Error += archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ case CompressGZip:
+ if(archive_write_set_compression_gzip(this->Archive) != ARCHIVE_OK)
+ {
+ this->Error = "archive_write_set_compression_gzip: ";
+ this->Error += archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ case CompressBZip2:
+ if(archive_write_set_compression_bzip2(this->Archive) != ARCHIVE_OK)
+ {
+ this->Error = "archive_write_set_compression_bzip2: ";
+ this->Error += archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ };
+ archive_read_disk_set_standard_lookup(this->Disk);
+ if(archive_write_set_format_pax_restricted(this->Archive) != ARCHIVE_OK)
+ {
+ this->Error = "archive_write_set_format_pax_restricted: ";
+ this->Error += archive_error_string(this->Archive);
+ return;
+ }
+
+ if(archive_write_open(
+ this->Archive, this, 0,
+ reinterpret_cast<archive_write_callback*>(&Callback::Write),
+ 0) != ARCHIVE_OK)
+ {
+ this->Error = "archive_write_open: ";
+ this->Error += archive_error_string(this->Archive);
+ return;
+ }
+}
+
+//----------------------------------------------------------------------------
+cmArchiveWrite::~cmArchiveWrite()
+{
+ archive_read_finish(this->Disk);
+ archive_write_finish(this->Archive);
+}
+
+//----------------------------------------------------------------------------
+bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix)
+{
+ if(this->Okay())
+ {
+ if(!path.empty() && path[path.size()-1] == '/')
+ {
+ path.erase(path.size()-1);
+ }
+ this->AddPath(path.c_str(), skip, prefix);
+ }
+ return this->Okay();
+}
+
+//----------------------------------------------------------------------------
+bool cmArchiveWrite::AddPath(const char* path,
+ size_t skip, const char* prefix)
+{
+ if(!this->AddFile(path, skip, prefix))
+ {
+ return false;
+ }
+ if(!cmSystemTools::FileIsDirectory(path))
+ {
+ return true;
+ }
+ cmsys::Directory d;
+ if(d.Load(path))
+ {
+ std::string next = path;
+ next += "/";
+ std::string::size_type end = next.size();
+ unsigned long n = d.GetNumberOfFiles();
+ for(unsigned long i = 0; i < n; ++i)
+ {
+ const char* file = d.GetFile(i);
+ if(strcmp(file, ".") != 0 && strcmp(file, "..") != 0)
+ {
+ next.erase(end);
+ next += file;
+ if(!this->AddPath(next.c_str(), skip, prefix))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmArchiveWrite::AddFile(const char* file,
+ size_t skip, const char* prefix)
+{
+ // Skip the file if we have no name for it. This may happen on a
+ // top-level directory, which does not need to be included anyway.
+ if(skip >= strlen(file))
+ {
+ return true;
+ }
+ const char* out = file + skip;
+
+ // Meta-data.
+ std::string dest = prefix? prefix : "";
+ dest += out;
+ if(this->Verbose)
+ {
+ std::cout << dest << "\n";
+ }
+ Entry e;
+ archive_entry_copy_sourcepath(e, file);
+ archive_entry_set_pathname(e, dest.c_str());
+ if(archive_read_disk_entry_from_file(this->Disk, e, -1, 0) != ARCHIVE_OK)
+ {
+ this->Error = "archive_read_disk_entry_from_file: ";
+ this->Error += archive_error_string(this->Disk);
+ return false;
+ }
+ if(archive_write_header(this->Archive, e) != ARCHIVE_OK)
+ {
+ this->Error = "archive_write_header: ";
+ this->Error += archive_error_string(this->Archive);
+ return false;
+ }
+
+ // Content.
+ if(size_t size = static_cast<size_t>(archive_entry_size(e)))
+ {
+ return this->AddData(file, size);
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmArchiveWrite::AddData(const char* file, size_t size)
+{
+ std::ifstream fin(file, std::ios::in | cmsys_ios_binary);
+ if(!fin)
+ {
+ this->Error = "Error opening \"";
+ this->Error += file;
+ this->Error += "\": ";
+ this->Error += cmSystemTools::GetLastSystemError();
+ return false;
+ }
+
+ char buffer[16384];
+ size_t nleft = size;
+ while(nleft > 0)
+ {
+ cmsys_ios::streamsize nnext = static_cast<cmsys_ios::streamsize>(
+ nleft > sizeof(buffer)? sizeof(buffer) : nleft);
+ fin.read(buffer, nnext);
+ // Some stream libraries (older HPUX) return failure at end of
+ // file on the last read even if some data were read. Check
+ // gcount instead of trusting the stream error status.
+ if(fin.gcount() != nnext)
+ {
+ break;
+ }
+ if(archive_write_data(this->Archive, buffer,
+ static_cast<size_t>(nnext)) != nnext)
+ {
+ this->Error = "archive_write_data: ";
+ this->Error += archive_error_string(this->Archive);
+ return false;
+ }
+ nleft -= static_cast<size_t>(nnext);
+ }
+ if(nleft > 0)
+ {
+ this->Error = "Error reading \"";
+ this->Error += file;
+ this->Error += "\": ";
+ this->Error += cmSystemTools::GetLastSystemError();
+ return false;
+ }
+ return true;
+}
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
new file mode 100644
index 0000000..92c0c73
--- /dev/null
+++ b/Source/cmArchiveWrite.h
@@ -0,0 +1,84 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmArchiveWrite_h
+#define cmArchiveWrite_h
+
+#include "cmStandardIncludes.h"
+
+#if !defined(CMAKE_BUILD_WITH_CMAKE)
+# error "cmArchiveWrite not allowed during bootstrap build!"
+#endif
+
+/** \class cmArchiveWrite
+ * \brief Wrapper around libarchive for writing.
+ *
+ */
+class cmArchiveWrite
+{
+ typedef void (cmArchiveWrite::* safe_bool)();
+ void safe_bool_true() {}
+public:
+ /** Compression type. */
+ enum Compress
+ {
+ CompressNone,
+ CompressGZip,
+ CompressBZip2
+ };
+
+ /** Construct with output stream to which to write archive. */
+ cmArchiveWrite(std::ostream& os, Compress c = CompressNone);
+ ~cmArchiveWrite();
+
+ /**
+ * Add a path (file or directory) to the archive. Directories are
+ * added recursively. The "path" must be readable on disk, either
+ * full path or relative to current working directory. The "skip"
+ * value indicates how many leading bytes from the input path to
+ * skip. The remaining part of the input path is appended to the
+ * "prefix" value to construct the final name in the archive.
+ */
+ bool Add(std::string path, size_t skip = 0, const char* prefix = 0);
+
+ /** Returns true if there has been no error. */
+ operator safe_bool() const
+ { return this->Okay()? &cmArchiveWrite::safe_bool_true : 0; }
+
+ /** Returns true if there has been an error. */
+ bool operator!() const { return !this->Okay(); }
+
+ /** Return the error string; empty if none. */
+ std::string GetError() const { return this->Error; }
+
+ // TODO: More general callback instead of hard-coding calls to
+ // std::cout.
+ void SetVerbose(bool v) { this->Verbose = v; }
+
+private:
+ bool Okay() const { return this->Error.empty(); }
+ bool AddPath(const char* path, size_t skip, const char* prefix);
+ bool AddFile(const char* file, size_t skip, const char* prefix);
+ bool AddData(const char* file, size_t size);
+
+ struct Callback;
+ friend struct Callback;
+
+ class Entry;
+
+ std::ostream& Stream;
+ struct archive* Archive;
+ struct archive* Disk;
+ bool Verbose;
+ std::string Error;
+};
+
+#endif
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 0badbba..a26452c 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -23,8 +23,8 @@
#include <cmsys/Directory.hxx>
#include <cmsys/System.h>
#if defined(CMAKE_BUILD_WITH_CMAKE)
-#include <cmlibarchive/libarchive/archive.h>
-#include <cmlibarchive/libarchive/archive_entry.h>
+# include "cmArchiveWrite.h"
+# include <cm_libarchive.h>
# include <cmsys/Terminal.h>
#endif
#include <cmsys/stl/algorithm>
@@ -1719,142 +1719,40 @@ bool cmSystemTools::CreateTar(const char* outFileName,
bool gzip, bool bzip2, bool verbose)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
-
- // Create a macro to handle return from libarchive
- // functions
-#define CHECK_ARCHIVE_ERROR(res, msg)\
- if(res != ARCHIVE_OK)\
- {\
- cmSystemTools::Error(msg, \
- archive_error_string(a));\
- return false;\
- }
-
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- // recursively expand all directories in files so that we have a list
- // of files
- std::vector<std::string> expandedFiles;
+ std::ofstream fout(outFileName, std::ios::out | cmsys_ios_binary);
+ if(!fout)
+ {
+ std::string e = "Cannot open output file \"";
+ e += outFileName;
+ e += "\": ";
+ e += cmSystemTools::GetLastSystemError();
+ cmSystemTools::Error(e.c_str());
+ return false;
+ }
+ cmArchiveWrite a(fout, (gzip? cmArchiveWrite::CompressGZip :
+ (bzip2? cmArchiveWrite::CompressBZip2 :
+ cmArchiveWrite::CompressNone)));
+ a.SetVerbose(verbose);
for(std::vector<cmStdString>::const_iterator i = files.begin();
i != files.end(); ++i)
{
- if(cmSystemTools::FileIsDirectory(i->c_str()))
+ std::string path = *i;
+ if(cmSystemTools::FileIsFullPath(path.c_str()))
{
- cmsys::Glob gl;
- std::string findExpr = *i;
- if ( findExpr[findExpr.size()-1] != '/' )
- {
- findExpr +="/";
- }
- findExpr += "*";
- gl.RecurseOn();
- if ( gl.FindFiles(findExpr) )
- {
- std::vector<std::string> dirfiles = gl.GetFiles();
- std::copy(dirfiles.begin(), dirfiles.end(),
- std::back_inserter(expandedFiles));
- }
+ // Get the relative path to the file.
+ path = cmSystemTools::RelativePath(cwd.c_str(), path.c_str());
}
- else
+ if(!a.Add(path))
{
- if(!cmSystemTools::FileIsFullPath(i->c_str()))
- {
- std::string fullp = cwd + "/" + *i;
- expandedFiles.push_back(fullp);
- }
- else
- {
- expandedFiles.push_back(*i);
- }
+ break;
}
}
- int res;
- // create a new archive
- struct archive* a = archive_write_new();
if(!a)
{
- cmSystemTools::Error("Unable to use create archive");
+ cmSystemTools::Error(a.GetError().c_str());
return false;
}
-
- if(gzip)
- {
- res = archive_write_set_compression_gzip(a);
- CHECK_ARCHIVE_ERROR(res, "Can not set gzip:");
- }
- if(bzip2)
- {
- res = archive_write_set_compression_bzip2(a);
- CHECK_ARCHIVE_ERROR(res, "Can not set bzip2:");
- }
- if(!bzip2 && !gzip)
- {
- res = archive_write_set_compression_none(a);
- CHECK_ARCHIVE_ERROR(res, "Can not set none:");
- }
- res = archive_write_set_format_pax_restricted(a);
- CHECK_ARCHIVE_ERROR(res, "Can not set tar format:");
- res = archive_write_open_file(a, outFileName);
- CHECK_ARCHIVE_ERROR(res, "write open:");
- // create a new disk struct
- struct archive* disk = archive_read_disk_new();
- archive_read_disk_set_standard_lookup(disk);
- std::vector<std::string>::const_iterator fileIt;
- for ( fileIt = expandedFiles.begin();
- fileIt != expandedFiles.end(); ++ fileIt )
- {
- // create a new entry for each file
- struct archive_entry *entry = archive_entry_new();
- // Get the relative path to the file
- std::string rp = cmSystemTools::RelativePath(cwd.c_str(),
- fileIt->c_str());
- if(verbose)
- {
- std::cout << rp << "\n";
- }
- // Set the name of the entry to the file name
- archive_entry_set_pathname(entry, rp.c_str());
- archive_read_disk_entry_from_file(disk, entry, -1, 0);
- CHECK_ARCHIVE_ERROR(res, "read disk entry:");
-
- // write entry header
- res = archive_write_header(a, entry);
- CHECK_ARCHIVE_ERROR(res, "write header: ");
- if(archive_entry_size(entry) > 0)
- {
- // now copy contents of file into archive a
- FILE* file = fopen(fileIt->c_str(), "rb");
- if(!file)
- {
- cmSystemTools::Error("Problem with fopen(): ",
- fileIt->c_str());
- return false;
- }
- char buff[16384];
- size_t len = fread(buff, 1, sizeof(buff), file);
- while (len > 0)
- {
- size_t wlen = archive_write_data(a, buff, len);
- if(wlen != len)
- {
- cmOStringStream error;
- error << "Problem with archive_write_data\n"
- << "Tried to write [" << len << "] bytes.\n"
- << "archive_write_data wrote [" << wlen << "] bytes.\n";
- cmSystemTools::Error(error.str().c_str(),
- archive_error_string(a)
- );
- return false;
- }
- len = fread(buff, 1, sizeof(buff), file);
- }
- // close the file and free the entry
- fclose(file);
- }
- archive_entry_free(entry);
- }
- archive_write_close(a);
- archive_write_finish(a);
- archive_read_finish(disk);
return true;
#else
(void)outFileName;
diff --git a/Utilities/cmThirdParty.h.in b/Utilities/cmThirdParty.h.in
index 6cdd47c..daf8114 100644
--- a/Utilities/cmThirdParty.h.in
+++ b/Utilities/cmThirdParty.h.in
@@ -16,6 +16,7 @@
#cmakedefine CMAKE_USE_SYSTEM_CURL
#cmakedefine CMAKE_USE_SYSTEM_EXPAT
#cmakedefine CMAKE_USE_SYSTEM_ZLIB
+#cmakedefine CMAKE_USE_SYSTEM_LIBARCHIVE
#cmakedefine CTEST_USE_XMLRPC
#endif
diff --git a/Utilities/cm_libarchive.h b/Utilities/cm_libarchive.h
new file mode 100644
index 0000000..1469bae
--- /dev/null
+++ b/Utilities/cm_libarchive.h
@@ -0,0 +1,25 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef __cm_libarchive_h
+#define __cm_libarchive_h
+
+/* Use the libarchive configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_LIBARCHIVE
+# include <archive.h>
+# include <archive_entry.h>
+#else
+# include <cmlibarchive/libarchive/archive.h>
+# include <cmlibarchive/libarchive/archive_entry.h>
+#endif
+
+#endif