]> git.saurik.com Git - apt.git/commitdiff
use liblzma-dev to provide xz/lzma support
authorDavid Kalnischkies <david@kalnischkies.de>
Wed, 12 Mar 2014 13:39:18 +0000 (14:39 +0100)
committerDavid Kalnischkies <david@kalnischkies.de>
Thu, 13 Mar 2014 13:00:38 +0000 (14:00 +0100)
We have xz/lzma support for a while, but only via an external binary
provided by xz-utils. Now that the Debian archive provides xz by default
and dpkg pre-depends on the library provided by liblzma-dev we can switch
now to use this library as well to avoid requiring an external binary.
For now the binary is in a prio:required package, but this might change
in the future.

API wise it is quiet similar to bz2 code expect that it doesn't provide
file I/O methods, so we piece this together on our own.

apt-pkg/aptconfiguration.cc
apt-pkg/contrib/fileutl.cc
apt-pkg/makefile
buildlib/config.h.in
buildlib/environment.mak.in
configure.ac
debian/control

index 941a9c3348e3ab7b3ddef66ea48d9ed7123ab51d..6ba04756093a0999f179c9b2c71c18bd0800c3a2 100644 (file)
@@ -462,8 +462,16 @@ const Configuration::getCompressors(bool const Cached) {
 #endif
        if (_config->Exists("Dir::Bin::xz") == false || FileExists(_config->FindFile("Dir::Bin::xz")) == true)
                compressors.push_back(Compressor("xz",".xz","xz","-6","-d",4));
+#ifdef HAVE_LZMA
+       else
+               compressors.push_back(Compressor("xz",".xz","false", NULL, NULL, 4));
+#endif
        if (_config->Exists("Dir::Bin::lzma") == false || FileExists(_config->FindFile("Dir::Bin::lzma")) == true)
                compressors.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
+#ifdef HAVE_LZMA
+       else
+               compressors.push_back(Compressor("lzma",".lzma","false", NULL, NULL, 5));
+#endif
 
        std::vector<std::string> const comp = _config->FindVector("APT::Compressor");
        for (std::vector<std::string>::const_iterator c = comp.begin();
index 057cb6a947c0397faa7a736144ddb4a97d0d24dc..22730ec043daa1ab86c75003ea22b53117f6e6ca 100644 (file)
@@ -58,6 +58,9 @@
 #ifdef HAVE_BZ2
        #include <bzlib.h>
 #endif
+#ifdef HAVE_LZMA
+       #include <lzma.h>
+#endif
 
 #ifdef WORDS_BIGENDIAN
 #include <inttypes.h>
@@ -72,13 +75,47 @@ class FileFdPrivate {
        public:
 #ifdef HAVE_ZLIB
        gzFile gz;
-#else
-       void* gz;
 #endif
 #ifdef HAVE_BZ2
        BZFILE* bz2;
-#else
-       void* bz2;
+#endif
+#ifdef HAVE_LZMA
+       struct LZMAFILE {
+          FILE* file;
+          uint8_t buffer[4096];
+          lzma_stream stream;
+          lzma_ret err;
+          bool eof;
+          bool compressing;
+
+          LZMAFILE() : file(NULL), eof(false), compressing(false) {}
+          ~LZMAFILE() {
+             if (compressing == true)
+             {
+               for (;;) {
+                       stream.avail_out = sizeof(buffer)/sizeof(buffer[0]);
+                       stream.next_out = buffer;
+                       err = lzma_code(&stream, LZMA_FINISH);
+                       if (err != LZMA_OK && err != LZMA_STREAM_END)
+                       {
+                               _error->Error("~LZMAFILE: Compress finalisation failed");
+                               break;
+                       }
+                       size_t const n =  sizeof(buffer)/sizeof(buffer[0]) - stream.avail_out;
+                       if (n && fwrite(buffer, 1, n, file) != n)
+                       {
+                               _error->Errno("~LZMAFILE",_("Write error"));
+                               break;
+                       }
+                       if (err == LZMA_STREAM_END)
+                               break;
+               }
+             }
+             lzma_end(&stream);
+             fclose(file);
+          }
+       };
+       LZMAFILE* lzma;
 #endif
        int compressed_fd;
        pid_t compressor_pid;
@@ -86,7 +123,16 @@ class FileFdPrivate {
        APT::Configuration::Compressor compressor;
        unsigned int openmode;
        unsigned long long seekpos;
-       FileFdPrivate() : gz(NULL), bz2(NULL),
+       FileFdPrivate() :
+#ifdef HAVE_ZLIB
+                         gz(NULL),
+#endif
+#ifdef HAVE_BZ2
+                         bz2(NULL),
+#endif
+#ifdef HAVE_LZMA
+                         lzma(NULL),
+#endif
                          compressed_fd(-1), compressor_pid(-1), pipe(false),
                          openmode(0), seekpos(0) {};
        bool CloseDown(std::string const &FileName)
@@ -106,6 +152,12 @@ class FileFdPrivate {
              BZ2_bzclose(bz2);
              bz2 = NULL;
           }
+#endif
+#ifdef HAVE_LZMA
+          if (lzma != NULL) {
+             delete lzma;
+             lzma = NULL;
+          }
 #endif
           if (compressor_pid > 0)
              ExecWait(compressor_pid, "FileFdCompressor", true);
@@ -1089,12 +1141,14 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
    if (compressor.Name == "." || compressor.Binary.empty() == true)
       return true;
 
-#if defined HAVE_ZLIB || defined HAVE_BZ2
+#if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
    // the API to open files is similar, so setup to avoid code duplicates later
    // and while at it ensure that we close before opening (if its a reopen)
    void* (*compress_open)(int, const char *) = NULL;
+   if (false)
+      /* dummy so that the rest can be 'else if's */;
 #define APT_COMPRESS_INIT(NAME,OPEN,CLOSE,STRUCT) \
-   if (compressor.Name == NAME) \
+   else if (compressor.Name == NAME) \
    { \
       compress_open = (void*(*)(int, const char *)) OPEN; \
       if (d != NULL && STRUCT != NULL) { CLOSE(STRUCT); STRUCT = NULL; } \
@@ -1105,6 +1159,17 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
 #ifdef HAVE_BZ2
    APT_COMPRESS_INIT("bzip2", BZ2_bzdopen, BZ2_bzclose, d->bz2)
 #endif
+#ifdef HAVE_LZMA
+   else if (compressor.Name == "xz" || compressor.Name == "lzma")
+   {
+      compress_open = (void*(*)(int, const char*)) fdopen;
+      if (d != NULL && d->lzma != NULL)
+      {
+        delete d->lzma;
+        d->lzma = NULL;
+      }
+   }
+#endif
 #undef APT_COMPRESS_INIT
 #endif
 
@@ -1113,7 +1178,7 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
       d = new FileFdPrivate();
       d->openmode = Mode;
       d->compressor = compressor;
-#if defined HAVE_ZLIB || defined HAVE_BZ2
+#if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
       if (AutoClose == false && compress_open != NULL)
       {
         // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
@@ -1125,7 +1190,7 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
 #endif
    }
 
-#if defined HAVE_ZLIB || defined HAVE_BZ2
+#if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
    if (compress_open != NULL)
    {
       void* compress_struct = NULL;
@@ -1138,13 +1203,60 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
       if (compress_struct == NULL)
         return false;
 
+      if (false)
+        /* dummy so that the rest can be 'else if's */;
 #ifdef HAVE_ZLIB
-      if (compressor.Name == "gzip")
+      else if (compressor.Name == "gzip")
         d->gz = (gzFile) compress_struct;
 #endif
 #ifdef HAVE_BZ2
-      if (compressor.Name == "bzip2")
+      else if (compressor.Name == "bzip2")
         d->bz2 = (BZFILE*) compress_struct;
+#endif
+#ifdef HAVE_LZMA
+      else if (compressor.Name == "xz" || compressor.Name == "lzma")
+      {
+        uint32_t const xzlevel = 6;
+        uint64_t const memlimit = UINT64_MAX;
+        if (d->lzma == NULL)
+           d->lzma = new FileFdPrivate::LZMAFILE;
+        d->lzma->file = (FILE*) compress_struct;
+        d->lzma->stream = LZMA_STREAM_INIT;
+
+        if ((Mode & ReadWrite) == ReadWrite)
+           return FileFdError("ReadWrite mode is not supported for file %s", FileName.c_str());
+
+        if ((Mode & WriteOnly) == WriteOnly)
+        {
+           if (compressor.Name == "xz")
+           {
+              if (lzma_easy_encoder(&d->lzma->stream, xzlevel, LZMA_CHECK_CRC32) != LZMA_OK)
+                 return false;
+           }
+           else
+           {
+              lzma_options_lzma options;
+              lzma_lzma_preset(&options, xzlevel);
+              if (lzma_alone_encoder(&d->lzma->stream, &options) != LZMA_OK)
+                 return false;
+           }
+           d->lzma->compressing = true;
+        }
+        else
+        {
+           if (compressor.Name == "xz")
+           {
+              if (lzma_auto_decoder(&d->lzma->stream, memlimit, 0) != LZMA_OK)
+                 return false;
+           }
+           else
+           {
+              if (lzma_alone_decoder(&d->lzma->stream, memlimit) != LZMA_OK)
+                 return false;
+           }
+           d->lzma->compressing = false;
+        }
+      }
 #endif
       Flags |= Compressed;
       return true;
@@ -1202,7 +1314,7 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
       }
       else
       {
-        if (FileName.empty() == true)
+        if (d->compressed_fd != -1)
            dup2(d->compressed_fd,STDIN_FILENO);
         dup2(Pipe[1],STDOUT_FILENO);
       }
@@ -1271,24 +1383,55 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
    *((char *)To) = '\0';
    do
    {
+      if (false)
+        /* dummy so that the rest can be 'else if's */;
 #ifdef HAVE_ZLIB
-      if (d != NULL && d->gz != NULL)
+      else if (d != NULL && d->gz != NULL)
         Res = gzread(d->gz,To,Size);
-      else
 #endif
 #ifdef HAVE_BZ2
-      if (d != NULL && d->bz2 != NULL)
+      else if (d != NULL && d->bz2 != NULL)
         Res = BZ2_bzread(d->bz2,To,Size);
-      else
 #endif
+#ifdef HAVE_LZMA
+      else if (d != NULL && d->lzma != NULL)
+      {
+        if (d->lzma->eof == true)
+           break;
+
+        d->lzma->stream.next_out = (uint8_t *) To;
+        d->lzma->stream.avail_out = Size;
+        if (d->lzma->stream.avail_in == 0)
+        {
+           d->lzma->stream.next_in = d->lzma->buffer;
+           d->lzma->stream.avail_in = fread(d->lzma->buffer, 1, sizeof(d->lzma->buffer)/sizeof(d->lzma->buffer[0]), d->lzma->file);
+        }
+        d->lzma->err = lzma_code(&d->lzma->stream, LZMA_RUN);
+        if (d->lzma->err == LZMA_STREAM_END)
+        {
+           d->lzma->eof = true;
+           Res = Size - d->lzma->stream.avail_out;
+        }
+        else if (d->lzma->err != LZMA_OK)
+        {
+           Res = -1;
+           errno = 0;
+        }
+        else
+           Res = Size - d->lzma->stream.avail_out;
+      }
+#endif
+      else
          Res = read(iFd,To,Size);
 
       if (Res < 0)
       {
         if (errno == EINTR)
            continue;
+        if (false)
+           /* dummy so that the rest can be 'else if's */;
 #ifdef HAVE_ZLIB
-        if (d != NULL && d->gz != NULL)
+        else if (d != NULL && d->gz != NULL)
         {
            int err;
            char const * const errmsg = gzerror(d->gz, &err);
@@ -1297,13 +1440,17 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
         }
 #endif
 #ifdef HAVE_BZ2
-        if (d != NULL && d->bz2 != NULL)
+        else if (d != NULL && d->bz2 != NULL)
         {
            int err;
            char const * const errmsg = BZ2_bzerror(d->bz2, &err);
            if (err != BZ_IO_ERROR)
               return FileFdError("BZ2_bzread: %s (%d: %s)", _("Read error"), err, errmsg);
         }
+#endif
+#ifdef HAVE_LZMA
+        else if (d != NULL && d->lzma != NULL)
+           return FileFdError("lzma_read: %s (%d)", _("Read error"), d->lzma->err);
 #endif
         return FileFdErrno("read",_("Read error"));
       }
@@ -1368,23 +1515,45 @@ bool FileFd::Write(const void *From,unsigned long long Size)
    errno = 0;
    do
    {
+      if (false)
+        /* dummy so that the rest can be 'else if's */;
 #ifdef HAVE_ZLIB
-      if (d != NULL && d->gz != NULL)
-         Res = gzwrite(d->gz,From,Size);
-      else
+      else if (d != NULL && d->gz != NULL)
+        Res = gzwrite(d->gz,From,Size);
 #endif
 #ifdef HAVE_BZ2
-      if (d != NULL && d->bz2 != NULL)
-         Res = BZ2_bzwrite(d->bz2,(void*)From,Size);
-      else
+      else if (d != NULL && d->bz2 != NULL)
+        Res = BZ2_bzwrite(d->bz2,(void*)From,Size);
 #endif
-         Res = write(iFd,From,Size);
+#ifdef HAVE_LZMA
+      else if (d != NULL && d->lzma != NULL)
+      {
+        d->lzma->stream.next_in = (uint8_t *)From;
+        d->lzma->stream.avail_in = Size;
+        d->lzma->stream.next_out = d->lzma->buffer;
+        d->lzma->stream.avail_out = sizeof(d->lzma->buffer)/sizeof(d->lzma->buffer[0]);
+        d->lzma->err = lzma_code(&d->lzma->stream, LZMA_RUN);
+        if (d->lzma->err != LZMA_OK)
+           return false;
+        size_t const n = sizeof(d->lzma->buffer)/sizeof(d->lzma->buffer[0]) - d->lzma->stream.avail_out;
+        size_t const m = (n == 0) ? 0 : fwrite(d->lzma->buffer, 1, n, d->lzma->file);
+        if (m != n)
+           Res = -1;
+        else
+           Res = Size - d->lzma->stream.avail_in;
+      }
+#endif
+      else
+        Res = write(iFd,From,Size);
+
       if (Res < 0 && errno == EINTR)
         continue;
       if (Res < 0)
       {
+        if (false)
+           /* dummy so that the rest can be 'else if's */;
 #ifdef HAVE_ZLIB
-        if (d != NULL && d->gz != NULL)
+        else if (d != NULL && d->gz != NULL)
         {
            int err;
            char const * const errmsg = gzerror(d->gz, &err);
@@ -1393,13 +1562,17 @@ bool FileFd::Write(const void *From,unsigned long long Size)
         }
 #endif
 #ifdef HAVE_BZ2
-        if (d != NULL && d->bz2 != NULL)
+        else if (d != NULL && d->bz2 != NULL)
         {
            int err;
            char const * const errmsg = BZ2_bzerror(d->bz2, &err);
            if (err != BZ_IO_ERROR)
               return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
         }
+#endif
+#ifdef HAVE_LZMA
+        else if (d != NULL && d->lzma != NULL)
+           return FileFdErrno("lzma_fwrite", _("Write error"));
 #endif
         return FileFdErrno("write",_("Write error"));
       }
@@ -1447,6 +1620,9 @@ bool FileFd::Seek(unsigned long long To)
    if (d != NULL && (d->pipe == true
 #ifdef HAVE_BZ2
                        || d->bz2 != NULL
+#endif
+#ifdef HAVE_LZMA
+                       || d->lzma != NULL
 #endif
        ))
    {
@@ -1459,12 +1635,21 @@ bool FileFd::Seek(unsigned long long To)
 
       if ((d->openmode & ReadOnly) != ReadOnly)
         return FileFdError("Reopen is only implemented for read-only files!");
+      if (false)
+        /* dummy so that the rest can be 'else if's */;
 #ifdef HAVE_BZ2
-     if (d->bz2 != NULL) 
-     {
-       BZ2_bzclose(d->bz2);
-       d->bz2 = NULL;
-     }
+      else if (d->bz2 != NULL)
+      {
+        BZ2_bzclose(d->bz2);
+        d->bz2 = NULL;
+      }
+#endif
+#ifdef HAVE_LZMA
+      else if (d->lzma != NULL)
+      {
+        delete d->lzma;
+        d->lzma = NULL;
+      }
 #endif
       if (iFd != -1)
         close(iFd);
@@ -1514,6 +1699,9 @@ bool FileFd::Skip(unsigned long long Over)
    if (d != NULL && (d->pipe == true
 #ifdef HAVE_BZ2
                        || d->bz2 != NULL
+#endif
+#ifdef HAVE_LZMA
+                       || d->lzma != NULL
 #endif
        ))
    {
@@ -1552,8 +1740,18 @@ bool FileFd::Truncate(unsigned long long To)
    // truncating /dev/null is always successful - as we get an error otherwise
    if (To == 0 && FileName == "/dev/null")
       return true;
-#if defined HAVE_ZLIB || defined HAVE_BZ2
-   if (d != NULL && (d->gz != NULL || d->bz2 != NULL))
+#if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
+   if (d != NULL && (
+#ifdef HAVE_ZLIB
+           d->gz != NULL ||
+#endif
+#ifdef HAVE_BZ2
+           d->bz2 != NULL ||
+#endif
+#ifdef HAVE_LZMA
+           d->lzma != NULL ||
+#endif
+           false))
       return FileFdError("Truncating compressed files is not implemented (%s)", FileName.c_str());
 #endif
    if (ftruncate(iFd,To) != 0)
@@ -1574,6 +1772,9 @@ unsigned long long FileFd::Tell()
    if (d != NULL && (d->pipe == true
 #ifdef HAVE_BZ2
                        || d->bz2 != NULL
+#endif
+#ifdef HAVE_LZMA
+                       || d->lzma != NULL
 #endif
        ))
       return d->seekpos;
@@ -1653,6 +1854,9 @@ unsigned long long FileFd::Size()
    if (d != NULL && (d->pipe == true
 #ifdef HAVE_BZ2
                        || (d->bz2 && size > 0)
+#endif
+#ifdef HAVE_LZMA
+                       || (d->lzma && size > 0)
 #endif
        ))
    {
@@ -1797,7 +2001,13 @@ bool FileFd::FileFdError(const char *Description,...) {
 }
                                                                        /*}}}*/
 
-gzFile FileFd::gzFd() { return d->gz; }
+APT_DEPRECATED gzFile FileFd::gzFd() {
+#ifdef HAVE_ZLIB
+   return d->gz;
+#else
+   return NULL;
+#endif
+}
 
 
 // Glob - wrapper around "glob()"                                      /*{{{*/
index a90131f80f58ce14f35640177be6cb7a7eddf3b7..1d456873b278372639532d5fa64745dea1f30637 100644 (file)
@@ -21,6 +21,9 @@ endif
 ifeq ($(HAVE_BZ2),yes)
 SLIBS+= -lbz2
 endif
+ifeq ($(HAVE_LZMA),yes)
+SLIBS+= -llzma
+endif
 APT_DOMAIN:=libapt-pkg$(LIBAPTPKG_MAJOR)
 
 # Source code for the contributed non-core things
index 6779e07bc94b68aacc6fc34e7a98a20400b401b6..6b72fb393b2a3c2ff2c2b4af07f519a0382e3d28 100644 (file)
@@ -11,6 +11,9 @@
 /* Define if we have the bz2 library for bzip2 */
 #undef HAVE_BZ2
 
+/* Define if we have the lzma library for lzma/xz */
+#undef HAVE_LZMA
+
 /* These two are used by the statvfs shim for glibc2.0 and bsd */
 /* Define if we have sys/vfs.h */
 #undef HAVE_VFS_H
index 9cc449573ba3ef07c1d3cdfb6fecf376358f4753..c1bf29672fd8cfd0954b19e6bae80ac5a47979db 100644 (file)
@@ -61,6 +61,7 @@ INTLLIBS = @INTLLIBS@
 HAVE_STATVFS = @HAVE_STATVFS@
 HAVE_ZLIB = @HAVE_ZLIB@
 HAVE_BZ2 = @HAVE_BZ2@
+HAVE_LZMA = @HAVE_LZMA@
 NEED_SOCKLEN_T_DEFINE = @NEED_SOCKLEN_T_DEFINE@
 
 # Shared library things
index 40556ee54a09e5fcb0553981572a7574114eb2f7..4f782f873b0de55c9658cbcf662d9721e7b910aa 100644 (file)
@@ -107,6 +107,13 @@ if test "x$HAVE_BZ2" = "xyes"; then
        AC_DEFINE(HAVE_BZ2)
 fi
 
+HAVE_LZMA=no
+AC_CHECK_LIB(lzma, lzma_easy_encoder,[AC_CHECK_HEADER(lzma.h, [HAVE_LZMA=yes], [])], [])
+AC_SUBST(HAVE_LZMA)
+if test "x$HAVE_LZMA" = "xyes"; then
+       AC_DEFINE(HAVE_LZMA)
+fi
+
 dnl Converts the ARCH to be something singular for this general CPU family
 dnl This is often the dpkg architecture string.
 dnl First check against the full canonical canoncial-system-type in $target
index 5ce68414e63bc80ce9c5582670761e1cc29d2c01..cb6f9b995fcc1d13d74fcec3409342b7adae241f 100644 (file)
@@ -7,8 +7,9 @@ Uploaders: Michael Vogt <mvo@debian.org>, Christian Perrier <bubulle@debian.org>
 Standards-Version: 3.9.5
 Build-Depends: dpkg-dev (>= 1.15.8), debhelper (>= 8.1.3~), libdb-dev,
  gettext (>= 0.12), libcurl4-gnutls-dev (>= 7.19.4~),
- zlib1g-dev, libbz2-dev, xsltproc, docbook-xsl, docbook-xml,
- po4a (>= 0.34-2), autotools-dev, autoconf, automake
+ zlib1g-dev, libbz2-dev, liblzma-dev,
+ xsltproc, docbook-xsl, docbook-xml, po4a (>= 0.34-2),
+ autotools-dev, autoconf, automake
 Build-Depends-Indep: doxygen, debiandoc-sgml, graphviz
 Build-Conflicts: autoconf2.13, automake1.4
 Vcs-Git: git://anonscm.debian.org/apt/apt.git
@@ -41,7 +42,7 @@ Package: libapt-pkg4.12
 Architecture: any
 Multi-Arch: same
 Pre-Depends: ${misc:Pre-Depends}
-Depends: ${shlibs:Depends}, ${misc:Depends}, xz-utils
+Depends: ${shlibs:Depends}, ${misc:Depends}
 Breaks: apt (<< 0.9.4~), libapt-inst1.5 (<< 0.9.9~)
 Section: libs
 Description: package management runtime library
@@ -107,7 +108,6 @@ Description: documentation for APT development
 Package: apt-utils
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}
-Suggests: xz-utils
 Description: package management related utility programs
  This package contains some less used commandline utilities related
  to package management with APT.