diff options
author | Bill Hoffman <bill.hoffman@kitware.com> | 2009-10-30 17:10:56 (GMT) |
---|---|---|
committer | Bill Hoffman <bill.hoffman@kitware.com> | 2009-10-30 17:10:56 (GMT) |
commit | fb51d98562a26b6dcde7d3597938a0b707b6b881 (patch) | |
tree | b42fbfb6b27b7a9e2d5068601f61d80e7033dc79 /Source/cmSystemTools.cxx | |
parent | 0615218bdf3e240e44e539f9eed6c1cf9fbff2d4 (diff) | |
download | CMake-fb51d98562a26b6dcde7d3597938a0b707b6b881.zip CMake-fb51d98562a26b6dcde7d3597938a0b707b6b881.tar.gz CMake-fb51d98562a26b6dcde7d3597938a0b707b6b881.tar.bz2 |
Switch to using libarchive from libtar for cpack and cmake -E tar
This allows for a built in bzip and zip capability, so external tools
will not be needed for these packagers. The cmake -E tar xf should be
able to handle all compression types now as well.
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r-- | Source/cmSystemTools.cxx | 567 |
1 files changed, 314 insertions, 253 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 031bfc3..d593d7e 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -18,11 +18,13 @@ #ifdef __QNX__ # include <malloc.h> /* for malloc/free on QNX */ #endif - +#include <cmsys/Glob.hxx> #include <cmsys/RegularExpression.hxx> #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 <cmsys/Terminal.h> #endif #include <cmsys/stl/algorithm> @@ -45,9 +47,8 @@ #endif #if defined(CMAKE_BUILD_WITH_CMAKE) -# include <libtar/libtar.h> +# include <memory> // auto_ptr # include <fcntl.h> -# include <cm_zlib.h> # include <cmsys/MD5.h> #endif @@ -1701,166 +1702,111 @@ bool cmSystemTools::IsPathToFramework(const char* path) return false; } -#if defined(CMAKE_BUILD_WITH_CMAKE) -struct cmSystemToolsGZStruct -{ - gzFile GZFile; -}; - -extern "C" { - int cmSystemToolsGZStructOpen(void* call_data, const char *pathname, - int oflags, mode_t mode); - int cmSystemToolsGZStructClose(void* call_data); - ssize_t cmSystemToolsGZStructRead(void* call_data, void* buf, size_t count); - ssize_t cmSystemToolsGZStructWrite(void* call_data, const void* buf, - size_t count); -} - -int cmSystemToolsGZStructOpen(void* call_data, const char *pathname, - int oflags, mode_t mode) -{ - const char *gzoflags; - int fd; - - cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data); - - switch (oflags & O_ACCMODE) - { - case O_WRONLY: - gzoflags = "wb"; - break; - case O_RDONLY: - gzoflags = "rb"; - break; - default: - case O_RDWR: - errno = EINVAL; - return -1; - } - - fd = open(pathname, oflags, mode); - if (fd == -1) - { - return -1; - } - -// no fchmod on BeOS 5...do pathname instead. -#if defined(__BEOS__) && !defined(__ZETA__) && !defined(__HAIKU__) - if ((oflags & O_CREAT) && chmod(pathname, mode)) - { - return -1; - } -#elif !defined(_WIN32) || defined(__CYGWIN__) - if ((oflags & O_CREAT) && fchmod(fd, mode)) - { - return -1; - } -#endif - - gzf->GZFile = gzdopen(fd, gzoflags); - if (!gzf->GZFile) - { - errno = ENOMEM; - return -1; - } - - return fd; -} - -int cmSystemToolsGZStructClose(void* call_data) -{ - cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data); - return gzclose(gzf->GZFile); -} - -ssize_t cmSystemToolsGZStructRead(void* call_data, void* buf, size_t count) -{ - cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data); - return gzread(gzf->GZFile, buf, static_cast<int>(count)); -} - -ssize_t cmSystemToolsGZStructWrite(void* call_data, const void* buf, - size_t count) -{ - cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data); - return gzwrite(gzf->GZFile, (void*)buf, static_cast<int>(count)); -} - -#endif - bool cmSystemTools::CreateTar(const char* outFileName, const std::vector<cmStdString>& files, bool gzip, bool verbose) { -#if defined(CMAKE_BUILD_WITH_CMAKE) - TAR *t; - char buf[TAR_MAXPATHLEN]; - char pathname[TAR_MAXPATHLEN]; - cmSystemToolsGZStruct gzs; - - tartype_t gztype = { - (openfunc_t)cmSystemToolsGZStructOpen, - (closefunc_t)cmSystemToolsGZStructClose, - (readfunc_t)cmSystemToolsGZStructRead, - (writefunc_t)cmSystemToolsGZStructWrite, - &gzs - }; - - // This libtar is not const safe. Make a non-const copy of outFileName - char* realName = new char[ strlen(outFileName) + 1 ]; - strcpy(realName, outFileName); - int options = 0; - if(verbose) +#if defined(CMAKE_BUILD_WITH_CMAKE) + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + // recursively expand all directories in files so that we have a list + // of files + std::vector<std::string> expandedFiles; + for(std::vector<cmStdString>::const_iterator i = files.begin(); + i != files.end(); ++i) { - options |= TAR_VERBOSE; - } -#ifdef __CYGWIN__ - options |= TAR_GNU; -#endif - if (tar_open(&t, realName, - (gzip? &gztype : NULL), - O_WRONLY | O_CREAT, 0644, - options) == -1) - { - cmSystemTools::Error("Problem with tar_open(): ", strerror(errno)); - delete [] realName; - return false; + if(cmSystemTools::FileIsDirectory(i->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)); + } + } + else + { + if(!cmSystemTools::FileIsFullPath(i->c_str())) + { + std::string fullp = cwd + "/" + *i; + expandedFiles.push_back(fullp); + } + else + { + expandedFiles.push_back(*i); + } + } } - - delete [] realName; - - std::vector<cmStdString>::const_iterator it; - for (it = files.begin(); it != files.end(); ++ it ) + int res; + // create a new archive + struct archive* a = archive_write_new(); + if(gzip) { - strncpy(pathname, it->c_str(), sizeof(pathname)); - pathname[sizeof(pathname)-1] = 0; - strncpy(buf, pathname, sizeof(buf)); - buf[sizeof(buf)-1] = 0; - if (tar_append_tree(t, buf, pathname) != 0) + res = archive_write_set_compression_gzip(a); + if(res != ARCHIVE_OK) { - cmOStringStream ostr; - ostr << "Problem with tar_append_tree(\"" << buf << "\", \"" - << pathname << "\"): " - << strerror(errno); - cmSystemTools::Error(ostr.str().c_str()); - tar_close(t); - return false; + cmSystemTools::Error("Unable to use gzip in libarchive"); } - } - - if (tar_append_eof(t) != 0) + } + res = archive_write_set_format_ustar(a); + if(res != ARCHIVE_OK) { - cmSystemTools::Error("Problem with tar_append_eof(): ", strerror(errno)); - tar_close(t); - return false; + cmSystemTools::Error("Unable to use tar libarchive"); } - - if (tar_close(t) != 0) + archive_write_open_file(a, outFileName); + // 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 ) { - cmSystemTools::Error("Problem with tar_close(): ", strerror(errno)); - return false; + // 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()); + // get the information about the file from stat + struct stat s; + stat(fileIt->c_str(), &s); + archive_read_disk_entry_from_file(disk, entry, -1, &s); + // write entry header + archive_write_header(a, entry); + // 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]; + int len = fread(buff, 1, sizeof(buff), file); + while (len > 0) + { + archive_write_data(a, buff, len); + len = fread(buff, 1, sizeof(buff), file); + } + // close the file and free the entry + fclose(file); + archive_entry_free(entry); } - + // close the archive and finish the write + archive_write_close(a); + archive_write_finish(a); return true; #else (void)outFileName; @@ -1871,130 +1817,245 @@ bool cmSystemTools::CreateTar(const char* outFileName, #endif } -bool cmSystemTools::ExtractTar(const char* outFileName, - const std::vector<cmStdString>& files, - bool gzip, bool verbose) -{ - (void)files; #if defined(CMAKE_BUILD_WITH_CMAKE) - TAR *t; - cmSystemToolsGZStruct gzs; - - tartype_t gztype = { - cmSystemToolsGZStructOpen, - cmSystemToolsGZStructClose, - cmSystemToolsGZStructRead, - cmSystemToolsGZStructWrite, - &gzs - }; - - // This libtar is not const safe. Make a non-const copy of outFileName - char* realName = new char[ strlen(outFileName) + 1 ]; - strcpy(realName, outFileName); - if (tar_open(&t, realName, - (gzip? &gztype : NULL), - O_RDONLY -#ifdef _WIN32 - | O_BINARY -#endif - , 0, - (verbose?TAR_VERBOSE:0) - | 0) == -1) +namespace{ +#define BSDTAR_FILESIZE_PRINTF "%lu" +#define BSDTAR_FILESIZE_TYPE unsigned long + void +list_item_verbose(FILE *out, struct archive_entry *entry) +{ + char tmp[100]; + size_t w; + const char *p; + const char *fmt; + time_t tim; + static time_t now; + size_t u_width = 6; + size_t gs_width = 13; + + /* + * We avoid collecting the entire list in memory at once by + * listing things as we see them. However, that also means we can't + * just pre-compute the field widths. Instead, we start with guesses + * and just widen them as necessary. These numbers are completely + * arbitrary. + */ + if (!now) + { + time(&now); + } + fprintf(out, "%s %d ", + archive_entry_strmode(entry), + archive_entry_nlink(entry)); + + /* Use uname if it's present, else uid. */ + p = archive_entry_uname(entry); + if ((p == NULL) || (*p == '\0')) { - cmSystemTools::Error("Problem with tar_open(): ", strerror(errno)); - delete [] realName; - return false; + sprintf(tmp, "%lu ", + (unsigned long)archive_entry_uid(entry)); + p = tmp; } - - delete [] realName; - - if (tar_extract_all(t, 0) != 0) - { - cmSystemTools::Error("Problem with tar_extract_all(): ", strerror(errno)); - return false; - } - - if (tar_close(t) != 0) + w = strlen(p); + if (w > u_width) { - cmSystemTools::Error("Problem with tar_close(): ", strerror(errno)); - return false; + u_width = w; } - return true; + fprintf(out, "%-*s ", (int)u_width, p); + + /* Use gname if it's present, else gid. */ + p = archive_entry_gname(entry); + if (p != NULL && p[0] != '\0') + { + fprintf(out, "%s", p); + w = strlen(p); + } + else + { + sprintf(tmp, "%lu", + (unsigned long)archive_entry_gid(entry)); + w = strlen(tmp); + fprintf(out, "%s", tmp); + } + + /* + * Print device number or file size, right-aligned so as to make + * total width of group and devnum/filesize fields be gs_width. + * If gs_width is too small, grow it. + */ + if (archive_entry_filetype(entry) == AE_IFCHR + || archive_entry_filetype(entry) == AE_IFBLK) + { + sprintf(tmp, "%lu,%lu", + (unsigned long)archive_entry_rdevmajor(entry), + (unsigned long)archive_entry_rdevminor(entry)); + } + else + { + /* + * Note the use of platform-dependent macros to format + * the filesize here. We need the format string and the + * corresponding type for the cast. + */ + sprintf(tmp, BSDTAR_FILESIZE_PRINTF, + (BSDTAR_FILESIZE_TYPE)archive_entry_size(entry)); + } + if (w + strlen(tmp) >= gs_width) + { + gs_width = w+strlen(tmp)+1; + } + fprintf(out, "%*s", (int)(gs_width - w), tmp); + + /* Format the time using 'ls -l' conventions. */ + tim = archive_entry_mtime(entry); +#define HALF_YEAR (time_t)365 * 86400 / 2 +#if defined(_WIN32) && !defined(__CYGWIN__) +#define DAY_FMT "%d" /* Windows' strftime function does not support %e format. */ #else - (void)outFileName; - (void)gzip; - (void)verbose; - return false; +#define DAY_FMT "%e" /* Day number without leading zeros */ #endif + if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) + { + fmt = DAY_FMT " %b %Y"; + } + else + { + fmt = DAY_FMT " %b %H:%M"; + } + strftime(tmp, sizeof(tmp), fmt, localtime(&tim)); + fprintf(out, " %s ", tmp); + fprintf(out, "%s", archive_entry_pathname(entry)); + + /* Extra information for links. */ + if (archive_entry_hardlink(entry)) /* Hard link */ + { + fprintf(out, " link to %s", + archive_entry_hardlink(entry)); + } + else if (archive_entry_symlink(entry)) /* Symbolic link */ + { + fprintf(out, " -> %s", archive_entry_symlink(entry)); + } } - -bool cmSystemTools::ListTar(const char* outFileName, - std::vector<cmStdString>& files, bool gzip, - bool verbose) + +int copy_data(struct archive *ar, struct archive *aw) { -#if defined(CMAKE_BUILD_WITH_CMAKE) - TAR *t; - cmSystemToolsGZStruct gzs; - - tartype_t gztype = { - cmSystemToolsGZStructOpen, - cmSystemToolsGZStructClose, - cmSystemToolsGZStructRead, - cmSystemToolsGZStructWrite, - &gzs - }; - - // This libtar is not const safe. Make a non-const copy of outFileName - char* realName = new char[ strlen(outFileName) + 1 ]; - strcpy(realName, outFileName); - if (tar_open(&t, realName, - (gzip? &gztype : NULL), - O_RDONLY -#ifdef _WIN32 - | O_BINARY -#endif - , 0, - (verbose?TAR_VERBOSE:0) - | 0) == -1) + int r; + const void *buff; + size_t size; + off_t offset; + + for (;;) { - cmSystemTools::Error("Problem with tar_open(): ", strerror(errno)); - delete [] realName; - return false; + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + { + return (ARCHIVE_OK); + } + if (r != ARCHIVE_OK) + { + return (r); + } + r = archive_write_data_block(aw, buff, size, offset); + if (r != ARCHIVE_OK) + { + cmSystemTools::Message("archive_write_data_block()", + archive_error_string(aw)); + return (r); + } } +} - delete [] realName; - - while ((th_read(t)) == 0) - { - const char* filename = th_get_pathname(t); - files.push_back(filename); - - if ( verbose ) +bool extract_tar(const char* outFileName, bool verbose, bool extract) +{ + struct archive* a = archive_read_new(); + struct archive *ext = archive_write_disk_new(); + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + struct archive_entry *entry; + int r = archive_read_open_file(a, outFileName, 10240); + if(r) + { + cmSystemTools::Error("Problem with archive_read_open_file(): ", + archive_error_string(a)); + return false; + } + for (;;) + { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) + { + break; + } + if (r != ARCHIVE_OK) + { + cmSystemTools::Error("Problem with archive_read_next_header(): ", + archive_error_string(a)); + } + if (verbose && extract) + { + cmSystemTools::Stdout("x "); + } + if(verbose && !extract) { - th_print_long_ls(t); + list_item_verbose(stdout, entry); } else { - std::cout << filename << std::endl; + cmSystemTools::Stdout(archive_entry_pathname(entry)); } - -#ifdef DEBUG - th_print(t); -#endif - if (TH_ISREG(t) && tar_skip_regfile(t) != 0) + if(extract) { - cmSystemTools::Error("Problem with tar_skip_regfile(): ", - strerror(errno)); - return false; + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) + { + cmSystemTools::Error("Problem with archive_write_header(): ", + archive_error_string(a)); + } + else + { + copy_data(a, ext); + r = archive_write_finish_entry(ext); + if (r != ARCHIVE_OK) + { + cmSystemTools::Error("Problem with archive_write_finish_entry(): ", + archive_error_string(ext)); + } + } + } + if (verbose || !extract) + { + cmSystemTools::Stdout("\n"); } - } - - if (tar_close(t) != 0) - { - cmSystemTools::Error("Problem with tar_close(): ", strerror(errno)); - return false; } + archive_read_close(a); + archive_read_finish(a); return true; + +} +} +#endif + +bool cmSystemTools::ExtractTar(const char* outFileName, + const std::vector<cmStdString>& files, + bool , bool verbose) +{ + (void)files; +#if defined(CMAKE_BUILD_WITH_CMAKE) + return extract_tar(outFileName, verbose, true); +#else + (void)outFileName; + (void)verbose; + return false; +#endif +} + +bool cmSystemTools::ListTar(const char* outFileName, + std::vector<cmStdString>& files, bool gzip, + bool verbose) +{ +#if defined(CMAKE_BUILD_WITH_CMAKE) + return extract_tar(outFileName, verbose, false); #else (void)outFileName; (void)files; |