+ return true;
+}
+bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::Compressor const &compressor)
+{
+ if (iFd == -1)
+ return false;
+ if (compressor.Name == "." || compressor.Binary.empty() == true)
+ return true;
+
+#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) \
+ else if (compressor.Name == NAME) \
+ { \
+ compress_open = (void*(*)(int, const char *)) OPEN; \
+ if (d != NULL) d->InternalClose(FileName); \
+ }
+#ifdef HAVE_ZLIB
+ APT_COMPRESS_INIT("gzip", gzdopen)
+#endif
+#ifdef HAVE_BZ2
+ APT_COMPRESS_INIT("bzip2", BZ2_bzdopen)
+#endif
+#ifdef HAVE_LZMA
+ APT_COMPRESS_INIT("xz", fdopen)
+ APT_COMPRESS_INIT("lzma", fdopen)
+#endif
+#undef APT_COMPRESS_INIT
+#endif
+
+ if (d == NULL)
+ {
+ d = new FileFdPrivate();
+ d->openmode = Mode;
+ d->compressor = compressor;
+#if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
+ if ((Flags & AutoClose) != AutoClose && compress_open != NULL)
+ {
+ // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
+ int const internFd = dup(iFd);
+ if (internFd == -1)
+ return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd);
+ iFd = internFd;
+ }
+#endif
+ }
+
+#if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
+ if (compress_open != NULL)
+ {
+ void* compress_struct = NULL;
+ if ((Mode & ReadWrite) == ReadWrite)
+ compress_struct = compress_open(iFd, "r+");
+ else if ((Mode & WriteOnly) == WriteOnly)
+ compress_struct = compress_open(iFd, "w");
+ else
+ compress_struct = compress_open(iFd, "r");
+ if (compress_struct == NULL)
+ return false;
+
+ if (false)
+ /* dummy so that the rest can be 'else if's */;
+#ifdef HAVE_ZLIB
+ else if (compressor.Name == "gzip")
+ d->gz = (gzFile) compress_struct;
+#endif
+#ifdef HAVE_BZ2
+ 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;
+ }
+#endif
+
+ // collect zombies here in case we reopen
+ if (d->compressor_pid > 0)
+ ExecWait(d->compressor_pid, "FileFdCompressor", true);
+
+ if ((Mode & ReadWrite) == ReadWrite)
+ return FileFdError("ReadWrite mode is not supported for file %s", FileName.c_str());
+
+ bool const Comp = (Mode & WriteOnly) == WriteOnly;
+ if (Comp == false)
+ {
+ // Handle 'decompression' of empty files
+ struct stat Buf;
+ fstat(iFd, &Buf);
+ if (Buf.st_size == 0 && S_ISFIFO(Buf.st_mode) == false)
+ return true;
+
+ // We don't need the file open - instead let the compressor open it
+ // as he properly knows better how to efficiently read from 'his' file
+ if (FileName.empty() == false)
+ {
+ close(iFd);
+ iFd = -1;
+ }
+ }
+
+ // Create a data pipe
+ int Pipe[2] = {-1,-1};
+ if (pipe(Pipe) != 0)
+ return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
+ for (int J = 0; J != 2; J++)
+ SetCloseExec(Pipe[J],true);
+
+ d->compressed_fd = iFd;
+ d->pipe = true;
+
+ if (Comp == true)
+ iFd = Pipe[1];
+ else
+ iFd = Pipe[0];
+
+ // The child..
+ d->compressor_pid = ExecFork();
+ if (d->compressor_pid == 0)
+ {
+ if (Comp == true)
+ {
+ dup2(d->compressed_fd,STDOUT_FILENO);
+ dup2(Pipe[0],STDIN_FILENO);
+ }
+ else
+ {
+ if (d->compressed_fd != -1)
+ dup2(d->compressed_fd,STDIN_FILENO);
+ dup2(Pipe[1],STDOUT_FILENO);
+ }
+ int const nullfd = open("/dev/null", O_WRONLY);
+ if (nullfd != -1)
+ {
+ dup2(nullfd,STDERR_FILENO);
+ close(nullfd);
+ }
+
+ SetCloseExec(STDOUT_FILENO,false);
+ SetCloseExec(STDIN_FILENO,false);
+
+ std::vector<char const*> Args;
+ Args.push_back(compressor.Binary.c_str());
+ std::vector<std::string> const * const addArgs =
+ (Comp == true) ? &(compressor.CompressArgs) : &(compressor.UncompressArgs);
+ for (std::vector<std::string>::const_iterator a = addArgs->begin();
+ a != addArgs->end(); ++a)
+ Args.push_back(a->c_str());
+ if (Comp == false && FileName.empty() == false)
+ {
+ Args.push_back("--stdout");
+ if (TemporaryFileName.empty() == false)
+ Args.push_back(TemporaryFileName.c_str());
+ else
+ Args.push_back(FileName.c_str());
+ }
+ Args.push_back(NULL);
+
+ execvp(Args[0],(char **)&Args[0]);
+ cerr << _("Failed to exec compressor ") << Args[0] << endl;
+ _exit(100);
+ }
+ if (Comp == true)
+ close(Pipe[0]);
+ else
+ close(Pipe[1]);
+