]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/fileutl.cc
Change InternalReadLine to always use buffer.read() return value
[apt.git] / apt-pkg / contrib / fileutl.cc
index ca2710a793c990496cb7b2bb9c9a97b469db65b3..aa5831f583501e3711cf64b2962e57692549fc60 100644 (file)
@@ -919,9 +919,30 @@ bool ChangeOwnerAndPermissionOfFile(char const * const requester, char const * c
 }
                                                                        /*}}}*/
 
-class FileFdPrivate {                                                  /*{{{*/
+class APT_HIDDEN FileFdPrivate {                                                       /*{{{*/
 protected:
    FileFd * const filefd;
+   struct simple_buffer {
+         static constexpr size_t buffersize_max = 4096;
+        unsigned long long bufferstart = 0;
+        unsigned long long bufferend = 0;
+        char buffer[buffersize_max];
+
+        char *get() { return buffer + bufferstart; }
+        bool empty() { return bufferend <= bufferstart; }
+        unsigned long long size() { return bufferend-bufferstart; }
+        void reset() { bufferend = bufferstart = 0; }
+        ssize_t read(void *to, unsigned long long requested_size) APT_MUSTCHECK
+        {
+           if (size() < requested_size)
+              requested_size = size();
+           memcpy(to, buffer + bufferstart, requested_size);
+           bufferstart += requested_size;
+           if (bufferstart == bufferend)
+              bufferstart = bufferend = 0;
+           return requested_size;
+        }
+   } buffer;
 public:
    int compressed_fd;
    pid_t compressor_pid;
@@ -929,30 +950,63 @@ public:
    APT::Configuration::Compressor compressor;
    unsigned int openmode;
    unsigned long long seekpos;
-   FileFdPrivate(FileFd * const pfilefd) : filefd(pfilefd),
+   explicit FileFdPrivate(FileFd * const pfilefd) : filefd(pfilefd),
       compressed_fd(-1), compressor_pid(-1), is_pipe(false),
       openmode(0), seekpos(0) {};
 
    virtual bool InternalOpen(int const iFd, unsigned int const Mode) = 0;
-   virtual ssize_t InternalRead(void * const To, unsigned long long const Size) = 0;
-   virtual bool InternalReadError() { return filefd->FileFdErrno("read",_("Read error")); }
-   virtual char * InternalReadLine(char * const To, unsigned long long const Size)
+   ssize_t InternalRead(void * To, unsigned long long Size)
    {
-      unsigned long long read = 0;
-      while ((Size - 1) != read)
+      // Drain the buffer if needed.
+      if (buffer.empty() == false)
       {
-        unsigned long long done = 0;
-        if (filefd->Read(To + read, 1, &done) == false)
-           return NULL;
-        if (done == 0)
-           break;
-        if (To[read++] == '\n')
-           break;
+        return buffer.read(To, Size);
       }
-      if (read == 0)
-        return NULL;
-      To[read] = '\0';
-      return To;
+      return InternalUnbufferedRead(To, Size);
+   }
+   virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) = 0;
+   virtual bool InternalReadError() { return filefd->FileFdErrno("read",_("Read error")); }
+   virtual char * InternalReadLine(char * To, unsigned long long Size)
+   {
+      if (unlikely(Size == 0))
+        return nullptr;
+      --Size;
+      To[0] = '\0';
+      if (unlikely(Size == 0))
+        return To;
+      char * const InitialTo = To;
+
+      do {
+        if (buffer.empty() == true)
+        {
+           buffer.reset();
+           unsigned long long actualread = 0;
+           if (filefd->Read(buffer.get(), buffer.buffersize_max, &actualread) == false)
+              return nullptr;
+           buffer.bufferend = actualread;
+           if (buffer.size() == 0)
+           {
+              if (To == InitialTo)
+                 return nullptr;
+              break;
+           }
+           filefd->Flags &= ~FileFd::HitEof;
+        }
+
+        unsigned long long const OutputSize = std::min(Size, buffer.size());
+        char const * const newline = static_cast<char const * const>(memchr(buffer.get(), '\n', OutputSize));
+        // Read until end of line or up to Size bytes from the buffer.
+        unsigned long long actualread = buffer.read(To,
+                                                    (newline != nullptr)
+                                                    ? (newline - buffer.get()) + 1
+                                                    : OutputSize);
+        To += actualread;
+        Size -= actualread;
+        if (newline != nullptr)
+           break;
+      } while (Size > 0);
+      *To = '\0';
+      return InitialTo;
    }
    virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) = 0;
    virtual bool InternalWriteError() { return filefd->FileFdErrno("write",_("Write error")); }
@@ -987,6 +1041,7 @@ public:
       if (filefd->OpenInternDescriptor(openmode, compressor) == false)
         return filefd->FileFdError("Seek on file %s because it couldn't be reopened", filefd->FileName.c_str());
 
+      buffer.reset();
       if (To != 0)
         return filefd->Skip(To);
 
@@ -1016,7 +1071,7 @@ public:
       // 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…
-      return seekpos;
+      return seekpos - buffer.size();
    }
    virtual unsigned long long InternalSize()
    {
@@ -1043,7 +1098,7 @@ public:
    virtual ~FileFdPrivate() {}
 };
                                                                        /*}}}*/
-class GzipFileFdPrivate: public FileFdPrivate {                                /*{{{*/
+class APT_HIDDEN GzipFileFdPrivate: public FileFdPrivate {                             /*{{{*/
 #ifdef HAVE_ZLIB
 public:
    gzFile gz;
@@ -1058,7 +1113,7 @@ public:
       filefd->Flags |= FileFd::Compressed;
       return gz != nullptr;
    }
-   virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+   virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
    {
       return gzread(gz, To, Size);
    }
@@ -1070,7 +1125,7 @@ public:
         return filefd->FileFdError("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
       return FileFdPrivate::InternalReadError();
    }
-   virtual char * InternalReadLine(char * const To, unsigned long long const Size) override
+   virtual char * InternalReadLine(char * To, unsigned long long Size) override
    {
       return gzgets(gz, To, Size);
    }
@@ -1091,12 +1146,24 @@ public:
       off_t const res = gzseek(gz, To, SEEK_SET);
       if (res != (off_t)To)
         return filefd->FileFdError("Unable to seek to %llu", To);
-
       seekpos = To;
+      buffer.reset();
       return true;
    }
    virtual bool InternalSkip(unsigned long long Over) override
    {
+      if (Over >= buffer.size())
+      {
+        Over -= buffer.size();
+        buffer.reset();
+      }
+      else
+      {
+        buffer.bufferstart += Over;
+        return true;
+      }
+      if (Over == 0)
+        return true;
       off_t const res = gzseek(gz, Over, SEEK_CUR);
       if (res < 0)
         return filefd->FileFdError("Unable to seek ahead %llu",Over);
@@ -1105,7 +1172,7 @@ public:
    }
    virtual unsigned long long InternalTell() override
    {
-      return gztell(gz);
+      return gztell(gz) - buffer.size();
    }
    virtual unsigned long long InternalSize() override
    {
@@ -1153,12 +1220,12 @@ public:
       return true;
    }
 
-   GzipFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), gz(nullptr) {}
+   explicit GzipFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), gz(nullptr) {}
    virtual ~GzipFileFdPrivate() { InternalClose(""); }
 #endif
 };
                                                                        /*}}}*/
-class Bz2FileFdPrivate: public FileFdPrivate {                         /*{{{*/
+class APT_HIDDEN Bz2FileFdPrivate: public FileFdPrivate {                              /*{{{*/
 #ifdef HAVE_BZ2
    BZFILE* bz2;
 public:
@@ -1173,7 +1240,7 @@ public:
       filefd->Flags |= FileFd::Compressed;
       return bz2 != nullptr;
    }
-   virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+   virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
    {
       return BZ2_bzread(bz2, To, Size);
    }
@@ -1207,12 +1274,12 @@ public:
       return true;
    }
 
-   Bz2FileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), bz2(nullptr) {}
+   explicit Bz2FileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), bz2(nullptr) {}
    virtual ~Bz2FileFdPrivate() { InternalClose(""); }
 #endif
 };
                                                                        /*}}}*/
-class LzmaFileFdPrivate: public FileFdPrivate {                                /*{{{*/
+class APT_HIDDEN LzmaFileFdPrivate: public FileFdPrivate {                             /*{{{*/
 #ifdef HAVE_LZMA
    struct LZMAFILE {
       FILE* file;
@@ -1332,7 +1399,7 @@ public:
       }
       return true;
    }
-   virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+   virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
    {
       ssize_t Res;
       if (lzma->eof == true)
@@ -1400,12 +1467,12 @@ public:
       return true;
    }
 
-   LzmaFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), lzma(nullptr) {}
+   explicit LzmaFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), lzma(nullptr) {}
    virtual ~LzmaFileFdPrivate() { InternalClose(""); }
 #endif
 };
                                                                        /*}}}*/
-class PipedFileFdPrivate: public FileFdPrivate                         /*{{{*/
+class APT_HIDDEN PipedFileFdPrivate: public FileFdPrivate                              /*{{{*/
 /* if we don't have a specific class dealing with library calls, we (un)compress
    by executing a specified binary and pipe in/out what we need */
 {
@@ -1508,7 +1575,7 @@ public:
 
       return true;
    }
-   virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+   virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
    {
       return read(filefd->iFd, To, Size);
    }
@@ -1524,21 +1591,26 @@ public:
       compressor_pid = -1;
       return Ret;
    }
-   PipedFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
+   explicit PipedFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
    virtual ~PipedFileFdPrivate() { InternalClose(""); }
 };
                                                                        /*}}}*/
-class DirectFileFdPrivate: public FileFdPrivate                                /*{{{*/
+class APT_HIDDEN DirectFileFdPrivate: public FileFdPrivate                             /*{{{*/
 {
 public:
    virtual bool InternalOpen(int const, unsigned int const) override { return true; }
-   virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+   virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
    {
       return read(filefd->iFd, To, Size);
    }
-
    virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) override
    {
+      // files opened read+write are strange and only really "supported" for direct files
+      if (buffer.size() != 0)
+      {
+        lseek(filefd->iFd, -buffer.size(), SEEK_CUR);
+        buffer.reset();
+      }
       return write(filefd->iFd, From, Size);
    }
    virtual bool InternalSeek(unsigned long long const To) override
@@ -1547,10 +1619,23 @@ public:
       if (res != (off_t)To)
         return filefd->FileFdError("Unable to seek to %llu", To);
       seekpos = To;
+      buffer.reset();
       return true;
    }
    virtual bool InternalSkip(unsigned long long Over) override
    {
+      if (Over >= buffer.size())
+      {
+        Over -= buffer.size();
+        buffer.reset();
+      }
+      else
+      {
+        buffer.bufferstart += Over;
+        return true;
+      }
+      if (Over == 0)
+        return true;
       off_t const res = lseek(filefd->iFd, Over, SEEK_CUR);
       if (res < 0)
         return filefd->FileFdError("Unable to seek ahead %llu",Over);
@@ -1559,13 +1644,23 @@ public:
    }
    virtual bool InternalTruncate(unsigned long long const To) override
    {
+      if (buffer.size() != 0)
+      {
+        unsigned long long const seekpos = lseek(filefd->iFd, 0, SEEK_CUR);
+        if ((seekpos - buffer.size()) >= To)
+           buffer.reset();
+        else if (seekpos >= To)
+           buffer.bufferend = (To - seekpos) + buffer.bufferstart;
+        else
+           buffer.reset();
+      }
       if (ftruncate(filefd->iFd, To) != 0)
         return filefd->FileFdError("Unable to truncate to %llu",To);
       return true;
    }
    virtual unsigned long long InternalTell() override
    {
-      return lseek(filefd->iFd,0,SEEK_CUR);
+      return lseek(filefd->iFd,0,SEEK_CUR) - buffer.size();
    }
    virtual unsigned long long InternalSize() override
    {
@@ -1574,7 +1669,7 @@ public:
    virtual bool InternalClose(std::string const &) override { return true; }
    virtual bool InternalAlwaysAutoClose() const override { return false; }
 
-   DirectFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
+   explicit DirectFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
    virtual ~DirectFileFdPrivate() { InternalClose(""); }
 };
                                                                        /*}}}*/