Browse Source

use liblzma-dev to provide xz/lzma support

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.
debian/1.8.y
David Kalnischkies 8 years ago
parent
commit
7f350a377e
  1. 8
      apt-pkg/aptconfiguration.cc
  2. 280
      apt-pkg/contrib/fileutl.cc
  3. 3
      apt-pkg/makefile
  4. 3
      buildlib/config.h.in
  5. 1
      buildlib/environment.mak.in
  6. 7
      configure.ac
  7. 8
      debian/control

8
apt-pkg/aptconfiguration.cc

@ -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();

280
apt-pkg/contrib/fileutl.cc

@ -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()" /*{{{*/

3
apt-pkg/makefile

@ -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

3
buildlib/config.h.in

@ -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

1
buildlib/environment.mak.in

@ -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

7
configure.ac

@ -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

8
debian/control

@ -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.

Loading…
Cancel
Save