-#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;
- lzma_stream tmp_stream = LZMA_STREAM_INIT;
- d->lzma->stream = tmp_stream;
-
- 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)
- {
- // commands not needing arguments, do not need to be told about using standard output
- // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this
- if (compressor.CompressArgs.empty() == false && compressor.UncompressArgs.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);