+// DecompressFile - wrapper for decompressing gzip/bzip2/xz compressed files /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool DecompressFile(string Filename, int *fd, off_t *FileSize)
+{
+ string CompressProg;
+ string CompressProgFind;
+ FileFd From;
+ struct stat Buf;
+ *fd = -1;
+
+ if (stat((Filename + ".gz").c_str(), &Buf) == 0)
+ {
+ CompressProg = "gzip";
+ CompressProgFind = "Dir::bin::gzip";
+ From.Open(Filename + ".gz",FileFd::ReadOnly);
+ }
+ else if (stat((Filename + ".bz2").c_str(), &Buf) == 0)
+ {
+ CompressProg = "bzip2";
+ CompressProgFind = "Dir::bin::bzip2";
+ From.Open(Filename + ".bz2",FileFd::ReadOnly);
+ }
+ else if (stat((Filename + ".xz").c_str(), &Buf) == 0)
+ {
+ CompressProg = "xz";
+ CompressProgFind = "Dir::bin::xz";
+ From.Open(Filename + ".xz",FileFd::ReadOnly);
+ }
+ else
+ {
+ return _error->Errno("decompressor", "Unable to parse file");
+ }
+
+ if (_error->PendingError() == true)
+ return -1;
+
+ *FileSize = Buf.st_size;
+
+ // Get a temp file
+ FILE *tmp = tmpfile();
+ if (tmp == 0)
+ return _error->Errno("tmpfile","Unable to create a tmp file");
+ *fd = dup(fileno(tmp));
+ fclose(tmp);
+
+ // Fork decompressor
+ pid_t Process = fork();
+ if (Process < 0)
+ return _error->Errno("fork","Couldn't fork to run decompressor");
+
+ // The child
+ if (Process == 0)
+ {
+ dup2(From.Fd(),STDIN_FILENO);
+ dup2(*fd,STDOUT_FILENO);
+ SetCloseExec(STDIN_FILENO,false);
+ SetCloseExec(STDOUT_FILENO,false);
+
+ const char *Args[3];
+ string Tmp = _config->Find(CompressProgFind, CompressProg);
+ Args[0] = Tmp.c_str();
+ Args[1] = "-d";
+ Args[2] = 0;
+ if(execvp(Args[0],(char **)Args))
+ return(_error->Errno("decompressor","decompress failed"));
+ /* Should never get here */
+ exit(100);
+ }
+
+ // Wait for decompress to finish
+ if (ExecWait(Process,CompressProg.c_str(),false) == false)
+ return false;
+
+ return true;
+}
+ /*}}}*/