X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/7a68effcb904b4424b54a30e448b6f2560cd1078..a9024b1be2e26c3c6b1f67093ddbf7602636ec9f:/apt-pkg/contrib/fileutl.cc?ds=sidebyside diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index ca2710a79..aa5831f58 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -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(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(""); } }; /*}}}*/