+// ExecCompressor - Open a de/compressor pipe /*{{{*/
+// ---------------------------------------------------------------------
+/* This opens the compressor, either in compress mode or decompress
+ mode. FileFd is always the compressor input/output file,
+ OutFd is the created pipe, Input for Compress, Output for Decompress. */
+bool ExecCompressor(APT::Configuration::Compressor const &Prog,
+ pid_t *Pid, int const FileFd, int &OutFd, bool const Comp)
+{
+ if (Pid != NULL)
+ *Pid = -1;
+
+ // No compression
+ if (Prog.Binary.empty() == true)
+ {
+ OutFd = dup(FileFd);
+ return true;
+ }
+
+ // Handle 'decompression' of empty files
+ if (Comp == false)
+ {
+ struct stat Buf;
+ fstat(FileFd, &Buf);
+ if (Buf.st_size == 0 && S_ISFIFO(Buf.st_mode) == false)
+ {
+ OutFd = FileFd;
+ return true;
+ }
+ }
+
+ // Create a data pipe
+ int Pipe[2] = {-1,-1};
+ if (pipe(Pipe) != 0)
+ return _error->Errno("pipe",_("Failed to create subprocess IPC"));
+ for (int J = 0; J != 2; J++)
+ SetCloseExec(Pipe[J],true);
+
+ if (Comp == true)
+ OutFd = Pipe[1];
+ else
+ OutFd = Pipe[0];
+
+ // The child..
+ pid_t child = ExecFork();
+ if (Pid != NULL)
+ *Pid = child;
+ if (child == 0)
+ {
+ if (Comp == true)
+ {
+ dup2(FileFd,STDOUT_FILENO);
+ dup2(Pipe[0],STDIN_FILENO);
+ }
+ else
+ {
+ dup2(FileFd,STDIN_FILENO);
+ dup2(Pipe[1],STDOUT_FILENO);
+ }
+
+ SetCloseExec(STDOUT_FILENO,false);
+ SetCloseExec(STDIN_FILENO,false);
+
+ std::vector<char const*> Args;
+ Args.push_back(Prog.Binary.c_str());
+ std::vector<std::string> const * const addArgs =
+ (Comp == true) ? &(Prog.CompressArgs) : &(Prog.UncompressArgs);
+ for (std::vector<std::string>::const_iterator a = addArgs->begin();
+ a != addArgs->end(); ++a)
+ Args.push_back(a->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]);
+
+ if (Pid == NULL)
+ ExecWait(child, Prog.Binary.c_str(), true);
+
+ return true;
+}
+bool ExecCompressor(APT::Configuration::Compressor const &Prog,
+ pid_t *Pid, std::string const &FileName, int &OutFd, bool const Comp)
+{
+ if (Pid != NULL)
+ *Pid = -1;
+
+ // No compression
+ if (Prog.Binary.empty() == true)
+ {
+ if (Comp == true)
+ OutFd = open(FileName.c_str(), O_WRONLY, 0666);
+ else
+ OutFd = open(FileName.c_str(), O_RDONLY);
+ return true;
+ }
+
+ // Handle 'decompression' of empty files
+ if (Comp == false)
+ {
+ struct stat Buf;
+ stat(FileName.c_str(), &Buf);
+ if (Buf.st_size == 0)
+ {
+ OutFd = open(FileName.c_str(), O_RDONLY);
+ return true;
+ }
+ }
+
+ // Create a data pipe
+ int Pipe[2] = {-1,-1};
+ if (pipe(Pipe) != 0)
+ return _error->Errno("pipe",_("Failed to create subprocess IPC"));
+ for (int J = 0; J != 2; J++)
+ SetCloseExec(Pipe[J],true);
+
+ int FileFd = -1;
+ if (Comp == true)
+ {
+ OutFd = Pipe[1];
+ // FIXME: we should handle openmode and permission from Open() here
+ FileFd = open(FileName.c_str(), O_WRONLY, 0666);
+ }
+ else
+ OutFd = Pipe[0];
+
+ // The child..
+ pid_t child = ExecFork();
+ if (Pid != NULL)
+ *Pid = child;
+ if (child == 0)
+ {
+ if (Comp == true)
+ {
+ dup2(Pipe[0],STDIN_FILENO);
+ dup2(FileFd,STDOUT_FILENO);
+ SetCloseExec(STDIN_FILENO,false);
+ }
+ else
+ {
+ dup2(Pipe[1],STDOUT_FILENO);
+ }
+ SetCloseExec(STDOUT_FILENO,false);
+
+ std::vector<char const*> Args;
+ Args.push_back(Prog.Binary.c_str());
+ std::vector<std::string> const * const addArgs =
+ (Comp == true) ? &(Prog.CompressArgs) : &(Prog.UncompressArgs);
+ for (std::vector<std::string>::const_iterator a = addArgs->begin();
+ a != addArgs->end(); ++a)
+ Args.push_back(a->c_str());
+ if (Comp == false)
+ {
+ Args.push_back("--stdout");
+ 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]);
+ close(FileFd);
+ }
+ else
+ close(Pipe[1]);
+
+ if (Pid == NULL)
+ ExecWait(child, Prog.Binary.c_str(), false);
+
+ return true;
+}
+ /*}}}*/
+