]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/fileutl.cc
merged debian-sid branch and resolved conflicts
[apt.git] / apt-pkg / contrib / fileutl.cc
index 30d0b6662e7986c55febeb59ed7c573e6002bc0b..6e13b91d9580e3c55a6760d9a215ca3d268c9c54 100644 (file)
 #include <dirent.h>
 #include <signal.h>
 #include <errno.h>
+#include <glob.h>
+
 #include <set>
 #include <algorithm>
 
 #ifdef HAVE_ZLIB
        #include <zlib.h>
 #endif
+#ifdef HAVE_BZ2
+       #include <bzlib.h>
+#endif
 
 #ifdef WORDS_BIGENDIAN
 #include <inttypes.h>
@@ -63,6 +68,11 @@ class FileFdPrivate {
        gzFile gz;
 #else
        void* gz;
+#endif
+#ifdef HAVE_BZ2
+       BZFILE* bz2;
+#else
+       void* bz2;
 #endif
        int compressed_fd;
        pid_t compressor_pid;
@@ -70,8 +80,34 @@ class FileFdPrivate {
        APT::Configuration::Compressor compressor;
        unsigned int openmode;
        unsigned long long seekpos;
-       FileFdPrivate() : gz(NULL), compressed_fd(-1), compressor_pid(-1), pipe(false),
+       FileFdPrivate() : gz(NULL), bz2(NULL),
+                         compressed_fd(-1), compressor_pid(-1), pipe(false),
                          openmode(0), seekpos(0) {};
+       bool CloseDown(std::string const &FileName)
+       {
+          bool Res = true;
+#ifdef HAVE_ZLIB
+          if (gz != NULL) {
+             int const e = gzclose(gz);
+             gz = NULL;
+             // gzdclose() on empty files always fails with "buffer error" here, ignore that
+             if (e != 0 && e != Z_BUF_ERROR)
+                Res &= _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str());
+          }
+#endif
+#ifdef HAVE_BZ2
+          if (bz2 != NULL) {
+             BZ2_bzclose(bz2);
+             bz2 = NULL;
+          }
+#endif
+          if (compressor_pid > 0)
+             ExecWait(compressor_pid, "FileFdCompressor", true);
+          compressor_pid = -1;
+
+          return Res;
+       }
+       ~FileFdPrivate() { CloseDown(""); }
 };
 
 // RunScripts - Run a set of scripts from a configuration subtree      /*{{{*/
@@ -353,7 +389,7 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
 
    std::vector<string> List;
 
-   if (DirectoryExists(Dir.c_str()) == false)
+   if (DirectoryExists(Dir) == false)
    {
       _error->Error(_("List of files can't be created as '%s' is not a directory"), Dir.c_str());
       return List;
@@ -379,14 +415,14 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
       if (Ent->d_type != DT_REG)
 #endif
       {
-        if (RealFileExists(File.c_str()) == false)
+        if (RealFileExists(File) == false)
         {
            // do not show ignoration warnings for directories
            if (
 #ifdef _DIRENT_HAVE_D_TYPE
                Ent->d_type == DT_DIR ||
 #endif
-               DirectoryExists(File.c_str()) == true)
+               DirectoryExists(File) == true)
               continue;
            if (SilentIgnore.Match(Ent->d_name) == false)
               _error->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent->d_name, Dir.c_str());
@@ -467,7 +503,7 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, bool SortList)
 
    std::vector<string> List;
 
-   if (DirectoryExists(Dir.c_str()) == false)
+   if (DirectoryExists(Dir) == false)
    {
       _error->Error(_("List of files can't be created as '%s' is not a directory"), Dir.c_str());
       return List;
@@ -492,7 +528,7 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, bool SortList)
       if (Ent->d_type != DT_REG)
 #endif
       {
-        if (RealFileExists(File.c_str()) == false)
+        if (RealFileExists(File) == false)
         {
            if (Debug == true)
               std::clog << "Bad file: " << Ent->d_name << " → it is not a real file" << std::endl;
@@ -818,6 +854,26 @@ bool ExecWait(pid_t Pid,const char *Name,bool Reap)
 }
                                                                        /*}}}*/
 
+// StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned     /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool StartsWithGPGClearTextSignature(string const &FileName)
+{
+   static const char* SIGMSG = "-----BEGIN PGP SIGNED MESSAGE-----\n";
+   char buffer[strlen(SIGMSG)+1];
+   FILE* gpg = fopen(FileName.c_str(), "r");
+   if (gpg == NULL)
+      return false;
+
+   char const * const test = fgets(buffer, sizeof(buffer), gpg);
+   fclose(gpg);
+   if (test == NULL || strcmp(buffer, SIGMSG) != 0)
+      return false;
+
+   return true;
+}
+
+
 // FileFd::Open - Open a file                                          /*{{{*/
 // ---------------------------------------------------------------------
 /* The most commonly used open mode combinations are given with Mode */
@@ -896,8 +952,6 @@ bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress,
 bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const Perms)
 {
    Close();
-   d = new FileFdPrivate;
-   d->openmode = Mode;
    Flags = AutoClose;
 
    if ((Mode & WriteOnly) != WriteOnly && (Mode & (Atomic | Create | Empty | Exclusive)) != 0)
@@ -991,10 +1045,21 @@ bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compre
 bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration::Compressor const &compressor, bool AutoClose)
 {
    Close();
-   d = new FileFdPrivate;
-   d->openmode = Mode;
    Flags = (AutoClose) ? FileFd::AutoClose : 0;
-   iFd = Fd;
+   if (AutoClose == false && (
+#ifdef HAVE_ZLIB
+       compressor.Name == "gzip" ||
+#endif
+#ifdef HAVE_BZ2
+       compressor.Name == "bzip2" ||
+#endif
+       false))
+   {
+      // Need to duplicate fd here or gzclose for cleanup will close the fd as well
+      iFd = dup(Fd);
+   }
+   else
+      iFd = Fd;
    this->FileName = "";
    if (OpenInternDescriptor(Mode, compressor) == false)
    {
@@ -1006,32 +1071,71 @@ bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration:
 }
 bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::Compressor const &compressor)
 {
-   d->compressor = compressor;
    if (compressor.Name == "." || compressor.Binary.empty() == true)
       return true;
+
+   if (d == NULL)
+   {
+      d = new FileFdPrivate();
+      d->openmode = Mode;
+      d->compressor = compressor;
+   }
+
 #ifdef HAVE_ZLIB
-   else if (compressor.Name == "gzip")
+   if (compressor.Name == "gzip")
    {
+      if (d->gz != NULL)
+      {
+        gzclose(d->gz);
+        d->gz = NULL;
+      }
       if ((Mode & ReadWrite) == ReadWrite)
         d->gz = gzdopen(iFd, "r+");
       else if ((Mode & WriteOnly) == WriteOnly)
         d->gz = gzdopen(iFd, "w");
       else
-        d->gz = gzdopen (iFd, "r");
+        d->gz = gzdopen(iFd, "r");
       if (d->gz == NULL)
         return false;
       Flags |= Compressed;
       return true;
    }
 #endif
+#ifdef HAVE_BZ2
+   if (compressor.Name == "bzip2")
+   {
+      if (d->bz2 != NULL)
+      {
+        BZ2_bzclose(d->bz2);
+        d->bz2 = NULL;
+      }
+      if ((Mode & ReadWrite) == ReadWrite)
+        d->bz2 = BZ2_bzdopen(iFd, "r+");
+      else if ((Mode & WriteOnly) == WriteOnly)
+        d->bz2 = BZ2_bzdopen(iFd, "w");
+      else
+        d->bz2 = BZ2_bzdopen(iFd, "r");
+      if (d->bz2 == NULL)
+        return false;
+      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)
+   {
+      Flags |= Fail;
       return _error->Error("ReadWrite mode is not supported for file %s", FileName.c_str());
+   }
 
    bool const Comp = (Mode & WriteOnly) == WriteOnly;
-   // Handle 'decompression' of empty files
    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)
@@ -1040,13 +1144,19 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
       // 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)
+   {
+      Flags |= Fail;
       return _error->Errno("pipe",_("Failed to create subprocess IPC"));
+   }
    for (int J = 0; J != 2; J++)
       SetCloseExec(Pipe[J],true);
 
@@ -1073,6 +1183,12 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
            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);
@@ -1102,8 +1218,6 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
       close(Pipe[0]);
    else
       close(Pipe[1]);
-   if (Comp == true || FileName.empty() == true)
-      close(d->compressed_fd);
 
    return true;
 }
@@ -1115,6 +1229,12 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
 FileFd::~FileFd()
 {
    Close();
+   if (d != NULL)
+   {
+      d->CloseDown(FileName);
+      delete d;
+      d = NULL;
+   }
 }
                                                                        /*}}}*/
 // FileFd::Read - Read a bit of the file                               /*{{{*/
@@ -1131,8 +1251,13 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
    do
    {
 #ifdef HAVE_ZLIB
-      if (d->gz != NULL)
-         Res = gzread(d->gz,To,Size);
+      if (d != NULL && d->gz != NULL)
+        Res = gzread(d->gz,To,Size);
+      else
+#endif
+#ifdef HAVE_BZ2
+      if (d != NULL && d->bz2 != NULL)
+        Res = BZ2_bzread(d->bz2,To,Size);
       else
 #endif
          Res = read(iFd,To,Size);
@@ -1143,20 +1268,30 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
            continue;
         Flags |= Fail;
 #ifdef HAVE_ZLIB
-        if (d->gz != NULL)
+        if (d != NULL && d->gz != NULL)
         {
            int err;
            char const * const errmsg = gzerror(d->gz, &err);
            if (err != Z_ERRNO)
               return _error->Error("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
         }
+#endif
+#ifdef HAVE_BZ2
+        if (d != NULL && d->bz2 != NULL)
+        {
+           int err;
+           char const * const errmsg = BZ2_bzerror(d->bz2, &err);
+           if (err != BZ_IO_ERROR)
+              return _error->Error("BZ2_bzread: %s (%d: %s)", _("Read error"), err, errmsg);
+        }
 #endif
         return _error->Errno("read",_("Read error"));
       }
       
       To = (char *)To + Res;
       Size -= Res;
-      d->seekpos += Res;
+      if (d != NULL)
+        d->seekpos += Res;
       if (Actual != 0)
         *Actual += Res;
    }
@@ -1184,7 +1319,7 @@ char* FileFd::ReadLine(char *To, unsigned long long const Size)
 {
    *To = '\0';
 #ifdef HAVE_ZLIB
-   if (d->gz != NULL)
+   if (d != NULL && d->gz != NULL)
       return gzgets(d->gz, To, Size);
 #endif
 
@@ -1215,9 +1350,14 @@ bool FileFd::Write(const void *From,unsigned long long Size)
    do
    {
 #ifdef HAVE_ZLIB
-      if (d->gz != NULL)
+      if (d != NULL && d->gz != NULL)
          Res = gzwrite(d->gz,From,Size);
       else
+#endif
+#ifdef HAVE_BZ2
+      if (d != NULL && d->bz2 != NULL)
+         Res = BZ2_bzwrite(d->bz2,(void*)From,Size);
+      else
 #endif
          Res = write(iFd,From,Size);
       if (Res < 0 && errno == EINTR)
@@ -1225,12 +1365,31 @@ bool FileFd::Write(const void *From,unsigned long long Size)
       if (Res < 0)
       {
         Flags |= Fail;
+#ifdef HAVE_ZLIB
+        if (d != NULL && d->gz != NULL)
+        {
+           int err;
+           char const * const errmsg = gzerror(d->gz, &err);
+           if (err != Z_ERRNO)
+              return _error->Error("gzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
+        }
+#endif
+#ifdef HAVE_BZ2
+        if (d != NULL && d->bz2 != NULL)
+        {
+           int err;
+           char const * const errmsg = BZ2_bzerror(d->bz2, &err);
+           if (err != BZ_IO_ERROR)
+              return _error->Error("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
+        }
+#endif
         return _error->Errno("write",_("Write error"));
       }
       
       From = (char *)From + Res;
       Size -= Res;
-      d->seekpos += Res;
+      if (d != NULL)
+        d->seekpos += Res;
    }
    while (Res > 0 && Size > 0);
    
@@ -1239,6 +1398,28 @@ bool FileFd::Write(const void *From,unsigned long long Size)
    
    Flags |= Fail;
    return _error->Error(_("write, still have %llu to write but couldn't"), Size);
+}
+bool FileFd::Write(int Fd, const void *From, unsigned long long Size)
+{
+   int Res;
+   errno = 0;
+   do
+   {
+      Res = write(Fd,From,Size);
+      if (Res < 0 && errno == EINTR)
+        continue;
+      if (Res < 0)
+        return _error->Errno("write",_("Write error"));
+
+      From = (char *)From + Res;
+      Size -= Res;
+   }
+   while (Res > 0 && Size > 0);
+
+   if (Size == 0)
+      return true;
+
+   return _error->Error(_("write, still have %llu to write but couldn't"), Size);
 }
                                                                        /*}}}*/
 // FileFd::Seek - Seek in the file                                     /*{{{*/
@@ -1246,7 +1427,11 @@ bool FileFd::Write(const void *From,unsigned long long Size)
 /* */
 bool FileFd::Seek(unsigned long long To)
 {
-   if (d->pipe == true)
+   if (d != NULL && (d->pipe == true
+#ifdef HAVE_BZ2
+                       || d->bz2 != NULL
+#endif
+       ))
    {
       // Our poor man seeking in pipes is costly, so try to avoid it
       unsigned long long seekpos = Tell();
@@ -1256,9 +1441,17 @@ bool FileFd::Seek(unsigned long long To)
         return Skip(To - seekpos);
 
       if ((d->openmode & ReadOnly) != ReadOnly)
+      {
+        Flags |= Fail;
         return _error->Error("Reopen is only implemented for read-only files!");
-      close(iFd);
-      iFd = 0;
+      }
+#ifdef HAVE_BZ2
+      if (d->bz2 != NULL)
+        BZ2_bzclose(d->bz2);
+#endif
+      if (iFd != -1)
+        close(iFd);
+      iFd = -1;
       if (TemporaryFileName.empty() == false)
         iFd = open(TemporaryFileName.c_str(), O_RDONLY);
       else if (FileName.empty() == false)
@@ -1268,12 +1461,18 @@ bool FileFd::Seek(unsigned long long To)
         if (d->compressed_fd > 0)
            if (lseek(d->compressed_fd, 0, SEEK_SET) != 0)
               iFd = d->compressed_fd;
-        if (iFd <= 0)
+        if (iFd < 0)
+        {
+           Flags |= Fail;
            return _error->Error("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
+        }
       }
 
       if (OpenInternDescriptor(d->openmode, d->compressor) == false)
+      {
+        Flags |= Fail;
         return _error->Error("Seek on file %s because it couldn't be reopened", FileName.c_str());
+      }
 
       if (To != 0)
         return Skip(To);
@@ -1283,7 +1482,7 @@ bool FileFd::Seek(unsigned long long To)
    }
    int res;
 #ifdef HAVE_ZLIB
-   if (d->gz)
+   if (d != NULL && d->gz)
       res = gzseek(d->gz,To,SEEK_SET);
    else
 #endif
@@ -1294,7 +1493,8 @@ bool FileFd::Seek(unsigned long long To)
       return _error->Error("Unable to seek to %llu", To);
    }
 
-   d->seekpos = To;
+   if (d != NULL)
+      d->seekpos = To;
    return true;
 }
                                                                        /*}}}*/
@@ -1303,7 +1503,11 @@ bool FileFd::Seek(unsigned long long To)
 /* */
 bool FileFd::Skip(unsigned long long Over)
 {
-   if (d->pipe == true)
+   if (d != NULL && (d->pipe == true
+#ifdef HAVE_BZ2
+                       || d->bz2 != NULL
+#endif
+       ))
    {
       d->seekpos += Over;
       char buffer[1024];
@@ -1311,7 +1515,10 @@ bool FileFd::Skip(unsigned long long Over)
       {
         unsigned long long toread = std::min((unsigned long long) sizeof(buffer), Over);
         if (Read(buffer, toread) == false)
+        {
+           Flags |= Fail;
            return _error->Error("Unable to seek ahead %llu",Over);
+        }
         Over -= toread;
       }
       return true;
@@ -1319,7 +1526,7 @@ bool FileFd::Skip(unsigned long long Over)
 
    int res;
 #ifdef HAVE_ZLIB
-   if (d->gz != NULL)
+   if (d != NULL && d->gz != NULL)
       res = gzseek(d->gz,Over,SEEK_CUR);
    else
 #endif
@@ -1329,7 +1536,8 @@ bool FileFd::Skip(unsigned long long Over)
       Flags |= Fail;
       return _error->Error("Unable to seek ahead %llu",Over);
    }
-   d->seekpos = res;
+   if (d != NULL)
+      d->seekpos = res;
 
    return true;
 }
@@ -1339,11 +1547,13 @@ bool FileFd::Skip(unsigned long long Over)
 /* */
 bool FileFd::Truncate(unsigned long long To)
 {
-   if (d->gz != NULL)
+#if defined HAVE_ZLIB || defined HAVE_BZ2
+   if (d != NULL && (d->gz != NULL || d->bz2 != NULL))
    {
       Flags |= Fail;
-      return _error->Error("Truncating gzipped files is not implemented (%s)", FileName.c_str());
+      return _error->Error("Truncating compressed files is not implemented (%s)", FileName.c_str());
    }
+#endif
    if (ftruncate(iFd,To) != 0)
    {
       Flags |= Fail;
@@ -1362,19 +1572,27 @@ unsigned long long FileFd::Tell()
    // seeking around, but not all users of FileFd use always Seek() and co
    // so d->seekpos isn't always true and we can just use it as a hint if
    // we have nothing else, but not always as an authority…
-   if (d->pipe == true)
+   if (d != NULL && (d->pipe == true
+#ifdef HAVE_BZ2
+                       || d->bz2 != NULL
+#endif
+       ))
       return d->seekpos;
 
    off_t Res;
 #ifdef HAVE_ZLIB
-   if (d->gz != NULL)
+   if (d != NULL && d->gz != NULL)
      Res = gztell(d->gz);
    else
 #endif
      Res = lseek(iFd,0,SEEK_CUR);
    if (Res == (off_t)-1)
+   {
+      Flags |= Fail;
       _error->Errno("lseek","Failed to determine the current file position");
-   d->seekpos = Res;
+   }
+   if (d != NULL)
+      d->seekpos = Res;
    return Res;
 }
                                                                        /*}}}*/
@@ -1384,17 +1602,24 @@ unsigned long long FileFd::Tell()
 unsigned long long FileFd::FileSize()
 {
    struct stat Buf;
-   if (d->pipe == false && fstat(iFd,&Buf) != 0)
+   if ((d == NULL || d->pipe == false) && fstat(iFd,&Buf) != 0)
+   {
+      Flags |= Fail;
       return _error->Errno("fstat","Unable to determine the file size");
+   }
 
    // for compressor pipes st_size is undefined and at 'best' zero
-   if (d->pipe == true || S_ISFIFO(Buf.st_mode))
+   if ((d != NULL && d->pipe == true) || S_ISFIFO(Buf.st_mode))
    {
       // we set it here, too, as we get the info here for free
       // in theory the Open-methods should take care of it already
-      d->pipe = true;
+      if (d != NULL)
+        d->pipe = true;
       if (stat(FileName.c_str(), &Buf) != 0)
+      {
+        Flags |= Fail;
         return _error->Errno("stat","Unable to determine the file size");
+      }
    }
 
    return Buf.st_size;
@@ -1409,7 +1634,11 @@ unsigned long long FileFd::Size()
 
    // for compressor pipes st_size is undefined and at 'best' zero,
    // so we 'read' the content and 'seek' back - see there
-   if (d->pipe == true)
+   if (d != NULL && (d->pipe == true
+#ifdef HAVE_BZ2
+                       || (d->bz2 && size > 0)
+#endif
+       ))
    {
       unsigned long long const oldSeek = Tell();
       char ignore[1000];
@@ -1424,7 +1653,7 @@ unsigned long long FileFd::Size()
    // only check gzsize if we are actually a gzip file, just checking for
    // "gz" is not sufficient as uncompressed files could be opened with
    // gzopen in "direct" mode as well
-   else if (d->gz && !gzdirect(d->gz) && size > 0)
+   else if (d != NULL && d->gz && !gzdirect(d->gz) && size > 0)
    {
        off_t const oldPos = lseek(iFd,0,SEEK_CUR);
        /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
@@ -1432,10 +1661,16 @@ unsigned long long FileFd::Size()
        * bits of the file */
        // FIXME: Size for gz-files is limited by 32bit… no largefile support
        if (lseek(iFd, -4, SEEK_END) < 0)
-          return _error->Errno("lseek","Unable to seek to end of gzipped file");
+       {
+         Flags |= Fail;
+         return _error->Errno("lseek","Unable to seek to end of gzipped file");
+       }
        size = 0L;
        if (read(iFd, &size, 4) != 4)
-          return _error->Errno("read","Unable to read original size of gzipped file");
+       {
+         Flags |= Fail;
+         return _error->Errno("read","Unable to read original size of gzipped file");
+       }
 
 #ifdef WORDS_BIGENDIAN
        uint32_t tmp_size = size;
@@ -1445,7 +1680,10 @@ unsigned long long FileFd::Size()
 #endif
 
        if (lseek(iFd, oldPos, SEEK_SET) < 0)
-          return _error->Errno("lseek","Unable to seek in gzipped file");
+       {
+         Flags |= Fail;
+         return _error->Errno("lseek","Unable to seek in gzipped file");
+       }
 
        return size;
    }
@@ -1460,20 +1698,23 @@ unsigned long long FileFd::Size()
 time_t FileFd::ModificationTime()
 {
    struct stat Buf;
-   if (d->pipe == false && fstat(iFd,&Buf) != 0)
+   if ((d == NULL || d->pipe == false) && fstat(iFd,&Buf) != 0)
    {
+      Flags |= Fail;
       _error->Errno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
       return 0;
    }
 
    // for compressor pipes st_size is undefined and at 'best' zero
-   if (d->pipe == true || S_ISFIFO(Buf.st_mode))
+   if ((d != NULL && d->pipe == true) || S_ISFIFO(Buf.st_mode))
    {
       // we set it here, too, as we get the info here for free
       // in theory the Open-methods should take care of it already
-      d->pipe = true;
+      if (d != NULL)
+        d->pipe = true;
       if (stat(FileName.c_str(), &Buf) != 0)
       {
+        Flags |= Fail;
         _error->Errno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
         return 0;
       }
@@ -1493,19 +1734,18 @@ bool FileFd::Close()
    bool Res = true;
    if ((Flags & AutoClose) == AutoClose)
    {
-#ifdef HAVE_ZLIB
-      if (d != NULL && d->gz != NULL) {
-        int const e = gzclose(d->gz);
-        // gzdclose() on empty files always fails with "buffer error" here, ignore that
-        if (e != 0 && e != Z_BUF_ERROR)
-           Res &= _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str());
-      } else
-#endif
-        if (iFd > 0 && close(iFd) != 0)
-           Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str());
+      if ((Flags & Compressed) != Compressed && iFd > 0 && close(iFd) != 0)
+        Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str());
+
+      if (d != NULL)
+      {
+        Res &= d->CloseDown(FileName);
+        delete d;
+        d = NULL;
+      }
    }
 
-   if ((Flags & Replace) == Replace && iFd >= 0) {
+   if ((Flags & Replace) == Replace) {
       if (rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
         Res &= _error->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName.c_str(), FileName.c_str());
 
@@ -1520,14 +1760,8 @@ bool FileFd::Close()
       if (unlink(FileName.c_str()) != 0)
         Res &= _error->WarningE("unlnk",_("Problem unlinking the file %s"), FileName.c_str());
 
-   if (d != NULL)
-   {
-      if (d->compressor_pid > 0)
-        ExecWait(d->compressor_pid, "FileFdCompressor", true);
-      delete d;
-      d = NULL;
-   }
-
+   if (Res == false)
+      Flags |= Fail;
    return Res;
 }
                                                                        /*}}}*/
@@ -1536,12 +1770,42 @@ bool FileFd::Close()
 /* */
 bool FileFd::Sync()
 {
-#ifdef _POSIX_SYNCHRONIZED_IO
    if (fsync(iFd) != 0)
+   {
+      Flags |= Fail;
       return _error->Errno("sync",_("Problem syncing the file"));
-#endif
+   }
    return true;
 }
                                                                        /*}}}*/
 
 gzFile FileFd::gzFd() { return (gzFile) d->gz; }
+
+
+// Glob - wrapper around "glob()"                                      /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+std::vector<std::string> Glob(std::string const &pattern, int flags)
+{
+   std::vector<std::string> result;
+   glob_t globbuf;
+   int glob_res, i;
+
+   glob_res = glob(pattern.c_str(),  flags, NULL, &globbuf);
+
+   if (glob_res != 0)
+   {
+      if(glob_res != GLOB_NOMATCH) {
+         _error->Errno("glob", "Problem with glob");
+         return result;
+      }
+   }
+
+   // append results
+   for(i=0;i<globbuf.gl_pathc;i++)
+      result.push_back(string(globbuf.gl_pathv[i]));
+
+   globfree(&globbuf);
+   return result;
+}
+                                                                       /*}}}*/