]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/fileutl.cc
test/integration/test-ubuntu-bug-346386-apt-get-update-paywall: use downloadfile()
[apt.git] / apt-pkg / contrib / fileutl.cc
index 22730ec043daa1ab86c75003ea22b53117f6e6ca..1ba4674e583194155be2477097188fff8775e19f 100644 (file)
@@ -1,6 +1,5 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: fileutl.cc,v 1.42 2002/09/14 05:29:22 jgg Exp $
 /* ######################################################################
    
    File Utilities
 #ifdef HAVE_LZMA
        #include <lzma.h>
 #endif
-
-#ifdef WORDS_BIGENDIAN
-#include <inttypes.h>
-#endif
+#include <endian.h>
+#include <stdint.h>
 
 #include <apti18n.h>
                                                                        /*}}}*/
 
 using namespace std;
 
-class FileFdPrivate {
-       public:
-#ifdef HAVE_ZLIB
-       gzFile gz;
-#endif
-#ifdef HAVE_BZ2
-       BZFILE* bz2;
-#endif
-#ifdef HAVE_LZMA
-       struct LZMAFILE {
-          FILE* file;
-          uint8_t buffer[4096];
-          lzma_stream stream;
-          lzma_ret err;
-          bool eof;
-          bool compressing;
-
-          LZMAFILE() : file(NULL), eof(false), compressing(false) {}
-          ~LZMAFILE() {
-             if (compressing == true)
-             {
-               for (;;) {
-                       stream.avail_out = sizeof(buffer)/sizeof(buffer[0]);
-                       stream.next_out = buffer;
-                       err = lzma_code(&stream, LZMA_FINISH);
-                       if (err != LZMA_OK && err != LZMA_STREAM_END)
-                       {
-                               _error->Error("~LZMAFILE: Compress finalisation failed");
-                               break;
-                       }
-                       size_t const n =  sizeof(buffer)/sizeof(buffer[0]) - stream.avail_out;
-                       if (n && fwrite(buffer, 1, n, file) != n)
-                       {
-                               _error->Errno("~LZMAFILE",_("Write error"));
-                               break;
-                       }
-                       if (err == LZMA_STREAM_END)
-                               break;
-               }
-             }
-             lzma_end(&stream);
-             fclose(file);
-          }
-       };
-       LZMAFILE* lzma;
-#endif
-       int compressed_fd;
-       pid_t compressor_pid;
-       bool pipe;
-       APT::Configuration::Compressor compressor;
-       unsigned int openmode;
-       unsigned long long seekpos;
-       FileFdPrivate() :
-#ifdef HAVE_ZLIB
-                         gz(NULL),
-#endif
-#ifdef HAVE_BZ2
-                         bz2(NULL),
-#endif
-#ifdef HAVE_LZMA
-                         lzma(NULL),
-#endif
-                         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
-#ifdef HAVE_LZMA
-          if (lzma != NULL) {
-             delete lzma;
-             lzma = 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      /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -201,7 +101,11 @@ bool RunScripts(const char *Cnf)
       {
         if (Opts->Value.empty() == true)
            continue;
-        
+
+         if(_config->FindB("Debug::RunScripts", false) == true)
+            std::clog << "Running external script: '"
+                      << Opts->Value << "'" << std::endl;
+
         if (system(Opts->Value.c_str()) != 0)
            _exit(100+Count);
       }
@@ -932,13 +836,129 @@ bool ExecWait(pid_t Pid,const char *Name,bool Reap)
 }
                                                                        /*}}}*/
 
+class FileFdPrivate {                                                  /*{{{*/
+       public:
+#ifdef HAVE_ZLIB
+       gzFile gz;
+#endif
+#ifdef HAVE_BZ2
+       BZFILE* bz2;
+#endif
+#ifdef HAVE_LZMA
+       struct LZMAFILE {
+          FILE* file;
+          uint8_t buffer[4096];
+          lzma_stream stream;
+          lzma_ret err;
+          bool eof;
+          bool compressing;
+
+          LZMAFILE() : file(NULL), eof(false), compressing(false) {}
+          ~LZMAFILE() {
+             if (compressing == true)
+             {
+               for (;;) {
+                       stream.avail_out = sizeof(buffer)/sizeof(buffer[0]);
+                       stream.next_out = buffer;
+                       err = lzma_code(&stream, LZMA_FINISH);
+                       if (err != LZMA_OK && err != LZMA_STREAM_END)
+                       {
+                               _error->Error("~LZMAFILE: Compress finalisation failed");
+                               break;
+                       }
+                       size_t const n =  sizeof(buffer)/sizeof(buffer[0]) - stream.avail_out;
+                       if (n && fwrite(buffer, 1, n, file) != n)
+                       {
+                               _error->Errno("~LZMAFILE",_("Write error"));
+                               break;
+                       }
+                       if (err == LZMA_STREAM_END)
+                               break;
+               }
+             }
+             lzma_end(&stream);
+             fclose(file);
+          }
+       };
+       LZMAFILE* lzma;
+#endif
+       int compressed_fd;
+       pid_t compressor_pid;
+       bool pipe;
+       APT::Configuration::Compressor compressor;
+       unsigned int openmode;
+       unsigned long long seekpos;
+       FileFdPrivate() :
+#ifdef HAVE_ZLIB
+                         gz(NULL),
+#endif
+#ifdef HAVE_BZ2
+                         bz2(NULL),
+#endif
+#ifdef HAVE_LZMA
+                         lzma(NULL),
+#endif
+                         compressed_fd(-1), compressor_pid(-1), pipe(false),
+                         openmode(0), seekpos(0) {};
+       bool InternalClose(std::string const &FileName)
+       {
+          if (false)
+             /* dummy so that the rest can be 'else if's */;
+#ifdef HAVE_ZLIB
+          else 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)
+                return _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str());
+          }
+#endif
+#ifdef HAVE_BZ2
+          else if (bz2 != NULL) {
+             BZ2_bzclose(bz2);
+             bz2 = NULL;
+          }
+#endif
+#ifdef HAVE_LZMA
+          else if (lzma != NULL) {
+             delete lzma;
+             lzma = NULL;
+          }
+#endif
+          return true;
+       }
+       bool CloseDown(std::string const &FileName)
+       {
+          bool const Res = InternalClose(FileName);
+
+          if (compressor_pid > 0)
+             ExecWait(compressor_pid, "FileFdCompressor", true);
+          compressor_pid = -1;
+
+          return Res;
+       }
+       bool InternalStream() const {
+          return false
+#ifdef HAVE_BZ2
+             || bz2 != NULL
+#endif
+#ifdef HAVE_LZMA
+             || lzma != NULL
+#endif
+             ;
+       }
+
+
+       ~FileFdPrivate() { CloseDown(""); }
+};
+                                                                       /*}}}*/
 // FileFd::Open - Open a file                                          /*{{{*/
 // ---------------------------------------------------------------------
 /* The most commonly used open mode combinations are given with Mode */
-bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const Perms)
+bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const AccessMode)
 {
    if (Mode == ReadOnlyGzip)
-      return Open(FileName, ReadOnly, Gzip, Perms);
+      return Open(FileName, ReadOnly, Gzip, AccessMode);
 
    if (Compress == Auto && (Mode & WriteOnly) == WriteOnly)
       return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
@@ -1005,9 +1025,9 @@ bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress,
 
    if (compressor == compressors.end())
       return FileFdError("Can't find a match for specified compressor mode for file %s", FileName.c_str());
-   return Open(FileName, Mode, *compressor, Perms);
+   return Open(FileName, Mode, *compressor, AccessMode);
 }
-bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const Perms)
+bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const AccessMode)
 {
    Close();
    Flags = AutoClose;
@@ -1057,11 +1077,18 @@ bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Co
       TemporaryFileName = string(name);
       free(name);
 
-      if(Perms != 600 && fchmod(iFd, Perms) == -1)
+      // umask() will always set the umask and return the previous value, so
+      // we first set the umask and then reset it to the old value
+      mode_t const CurrentUmask = umask(0);
+      umask(CurrentUmask);
+      // calculate the actual file permissions (just like open/creat)
+      mode_t const FilePermissions = (AccessMode & ~CurrentUmask);
+
+      if(fchmod(iFd, FilePermissions) == -1)
           return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName.c_str());
    }
    else
-      iFd = open(FileName.c_str(), fileflags, Perms);
+      iFd = open(FileName.c_str(), fileflags, AccessMode);
 
    this->FileName = FileName;
    if (iFd == -1 || OpenInternDescriptor(Mode, compressor) == false)
@@ -1147,28 +1174,21 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
    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,CLOSE,STRUCT) \
+#define APT_COMPRESS_INIT(NAME,OPEN) \
    else if (compressor.Name == NAME) \
    { \
       compress_open = (void*(*)(int, const char *)) OPEN; \
-      if (d != NULL && STRUCT != NULL) { CLOSE(STRUCT); STRUCT = NULL; } \
+      if (d != NULL) d->InternalClose(FileName); \
    }
 #ifdef HAVE_ZLIB
-   APT_COMPRESS_INIT("gzip", gzdopen, gzclose, d->gz)
+   APT_COMPRESS_INIT("gzip", gzdopen)
 #endif
 #ifdef HAVE_BZ2
-   APT_COMPRESS_INIT("bzip2", BZ2_bzdopen, BZ2_bzclose, d->bz2)
+   APT_COMPRESS_INIT("bzip2", BZ2_bzdopen)
 #endif
 #ifdef HAVE_LZMA
-   else if (compressor.Name == "xz" || compressor.Name == "lzma")
-   {
-      compress_open = (void*(*)(int, const char*)) fdopen;
-      if (d != NULL && d->lzma != NULL)
-      {
-        delete d->lzma;
-        d->lzma = NULL;
-      }
-   }
+   APT_COMPRESS_INIT("xz", fdopen)
+   APT_COMPRESS_INIT("lzma", fdopen)
 #endif
 #undef APT_COMPRESS_INIT
 #endif
@@ -1179,7 +1199,7 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
       d->openmode = Mode;
       d->compressor = compressor;
 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
-      if (AutoClose == false && compress_open != NULL)
+      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);
@@ -1221,7 +1241,8 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
         if (d->lzma == NULL)
            d->lzma = new FileFdPrivate::LZMAFILE;
         d->lzma->file = (FILE*) compress_struct;
-        d->lzma->stream = LZMA_STREAM_INIT;
+         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());
@@ -1337,7 +1358,10 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
         Args.push_back(a->c_str());
       if (Comp == false && FileName.empty() == false)
       {
-        Args.push_back("--stdout");
+        // 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
@@ -1418,7 +1442,15 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
            errno = 0;
         }
         else
+        {
            Res = Size - d->lzma->stream.avail_out;
+           if (Res == 0)
+           {
+              // lzma run was okay, but produced no output…
+              Res = -1;
+              errno = EINTR;
+           }
+        }
       }
 #endif
       else
@@ -1427,7 +1459,12 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
       if (Res < 0)
       {
         if (errno == EINTR)
+        {
+           // trick the while-loop into running again
+           Res = 1;
+           errno = 0;
            continue;
+        }
         if (false)
            /* dummy so that the rest can be 'else if's */;
 #ifdef HAVE_ZLIB
@@ -1617,14 +1654,9 @@ bool FileFd::Write(int Fd, const void *From, unsigned long long Size)
 /* */
 bool FileFd::Seek(unsigned long long To)
 {
-   if (d != NULL && (d->pipe == true
-#ifdef HAVE_BZ2
-                       || d->bz2 != NULL
-#endif
-#ifdef HAVE_LZMA
-                       || d->lzma != NULL
-#endif
-       ))
+   Flags &= ~HitEof;
+
+   if (d != NULL && (d->pipe == true || d->InternalStream() == true))
    {
       // Our poor man seeking in pipes is costly, so try to avoid it
       unsigned long long seekpos = Tell();
@@ -1635,22 +1667,7 @@ bool FileFd::Seek(unsigned long long To)
 
       if ((d->openmode & ReadOnly) != ReadOnly)
         return FileFdError("Reopen is only implemented for read-only files!");
-      if (false)
-        /* dummy so that the rest can be 'else if's */;
-#ifdef HAVE_BZ2
-      else if (d->bz2 != NULL)
-      {
-        BZ2_bzclose(d->bz2);
-        d->bz2 = NULL;
-      }
-#endif
-#ifdef HAVE_LZMA
-      else if (d->lzma != NULL)
-      {
-        delete d->lzma;
-        d->lzma = NULL;
-      }
-#endif
+      d->InternalClose(FileName);
       if (iFd != -1)
         close(iFd);
       iFd = -1;
@@ -1696,16 +1713,8 @@ bool FileFd::Seek(unsigned long long To)
 /* */
 bool FileFd::Skip(unsigned long long Over)
 {
-   if (d != NULL && (d->pipe == true
-#ifdef HAVE_BZ2
-                       || d->bz2 != NULL
-#endif
-#ifdef HAVE_LZMA
-                       || d->lzma != NULL
-#endif
-       ))
+   if (d != NULL && (d->pipe == true || d->InternalStream() == true))
    {
-      d->seekpos += Over;
       char buffer[1024];
       while (Over != 0)
       {
@@ -1741,17 +1750,11 @@ bool FileFd::Truncate(unsigned long long To)
    if (To == 0 && FileName == "/dev/null")
       return true;
 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
-   if (d != NULL && (
+   if (d != NULL && (d->InternalStream() == true
 #ifdef HAVE_ZLIB
-           d->gz != NULL ||
-#endif
-#ifdef HAVE_BZ2
-           d->bz2 != NULL ||
-#endif
-#ifdef HAVE_LZMA
-           d->lzma != NULL ||
+           || d->gz != NULL
 #endif
-           false))
+           ))
       return FileFdError("Truncating compressed files is not implemented (%s)", FileName.c_str());
 #endif
    if (ftruncate(iFd,To) != 0)
@@ -1769,14 +1772,7 @@ 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 != NULL && (d->pipe == true
-#ifdef HAVE_BZ2
-                       || d->bz2 != NULL
-#endif
-#ifdef HAVE_LZMA
-                       || d->lzma != NULL
-#endif
-       ))
+   if (d != NULL && (d->pipe == true || d->InternalStream() == true))
       return d->seekpos;
 
    off_t Res;
@@ -1802,7 +1798,8 @@ static bool StatFileFd(char const * const msg, int const iFd, std::string const
         // higher-level code will generate more meaningful messages,
         // even translated this would be meaningless for users
         return _error->Errno("fstat", "Unable to determine %s for fd %i", msg, iFd);
-      ispipe = S_ISFIFO(Buf.st_mode);
+      if (FileName.empty() == false)
+        ispipe = S_ISFIFO(Buf.st_mode);
    }
 
    // for compressor pipes st_size is undefined and at 'best' zero
@@ -1851,14 +1848,7 @@ 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 != NULL && (d->pipe == true
-#ifdef HAVE_BZ2
-                       || (d->bz2 && size > 0)
-#endif
-#ifdef HAVE_LZMA
-                       || (d->lzma && size > 0)
-#endif
-       ))
+   if (d != NULL && (d->pipe == true || (d->InternalStream() == true && size > 0)))
    {
       unsigned long long const oldSeek = Tell();
       char ignore[1000];
@@ -1889,19 +1879,13 @@ unsigned long long FileFd::Size()
          FileFdErrno("lseek","Unable to seek to end of gzipped file");
          return 0;
        }
-       size = 0;
+       uint32_t size = 0;
        if (read(iFd, &size, 4) != 4)
        {
          FileFdErrno("read","Unable to read original size of gzipped file");
          return 0;
        }
-
-#ifdef WORDS_BIGENDIAN
-       uint32_t tmp_size = size;
-       uint8_t const * const p = (uint8_t const * const) &tmp_size;
-       tmp_size = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
-       size = tmp_size;
-#endif
+       size = le32toh(size);
 
        if (lseek(iFd, oldPos, SEEK_SET) < 0)
        {
@@ -2055,3 +2039,14 @@ std::string GetTempDir()
 
    return string(tmpdir);
 }
+
+bool Rename(std::string From, std::string To)
+{
+   if (rename(From.c_str(),To.c_str()) != 0)
+   {
+      _error->Error(_("rename failed, %s (%s -> %s)."),strerror(errno),
+                    From.c_str(),To.c_str());
+      return false;
+   }   
+   return true;
+}