diff options
author | Brad King <brad.king@kitware.com> | 2010-08-10 18:35:41 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2010-08-10 18:35:41 (GMT) |
commit | 6d856795510fc7cdab8c1ab1d7aa0ade1113646b (patch) | |
tree | ab3bb8d9770cc6763966c7092334f81f3bbf5a72 | |
parent | cc31f89c17f365c63065c78a25d26075f453d31a (diff) | |
parent | aef672311aa8b802c4477a4d51f531f752a6a787 (diff) | |
download | CMake-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.txt | 1 | ||||
-rw-r--r-- | Source/CPack/cmCPackArchiveGenerator.cxx | 4 | ||||
-rw-r--r-- | Source/cmArchiveWrite.cxx | 247 | ||||
-rw-r--r-- | Source/cmArchiveWrite.h | 84 | ||||
-rw-r--r-- | Source/cmSystemTools.cxx | 148 | ||||
-rw-r--r-- | Utilities/cmThirdParty.h.in | 1 | ||||
-rw-r--r-- | Utilities/cm_libarchive.h | 25 |
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 |