X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/117551478551958d62d9555c595f2990805137c0..1f5062f656b4919ff1d3126c413c40e53fdd1ab2:/apt-pkg/contrib/fileutl.cc diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 496cdee42..7f3ed673a 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -919,53 +919,99 @@ bool ChangeOwnerAndPermissionOfFile(char const * const requester, char const * c } /*}}}*/ -class FileFdPrivate { /*{{{*/ +struct APT_HIDDEN simple_buffer { /*{{{*/ + static constexpr size_t buffersize_max = 4096; + unsigned long long bufferstart = 0; + unsigned long long bufferend = 0; + char buffer[buffersize_max]; + + const char *get() const { return buffer + bufferstart; } + char *get() { return buffer + bufferstart; } + bool empty() const { return bufferend <= bufferstart; } + bool full() const { return bufferend == buffersize_max; } + unsigned long long size() const { 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; + } + ssize_t write(const void *from, unsigned long long requested_size) APT_MUSTCHECK + { + if (buffersize_max - size() < requested_size) + requested_size = buffersize_max - size(); + memcpy(buffer + bufferend, from, requested_size); + bufferend += requested_size; + if (bufferstart == bufferend) + bufferstart = bufferend = 0; + return requested_size; + } +}; + /*}}}*/ + +class APT_HIDDEN FileFdPrivate { /*{{{*/ + friend class BufferedWriteFileFdPrivate; protected: FileFd * const filefd; - size_t buffersize_max = 0; - std::unique_ptr buffer; - unsigned long long buffersize = 0; -public: + simple_buffer buffer; int compressed_fd; pid_t compressor_pid; bool is_pipe; APT::Configuration::Compressor compressor; unsigned int openmode; unsigned long long seekpos; - explicit FileFdPrivate(FileFd * const pfilefd) : filefd(pfilefd), buffer(nullptr), +public: + + explicit FileFdPrivate(FileFd * const pfilefd) : filefd(pfilefd), compressed_fd(-1), compressor_pid(-1), is_pipe(false), openmode(0), seekpos(0) {}; + virtual APT::Configuration::Compressor get_compressor() const + { + return compressor; + } + virtual void set_compressor(APT::Configuration::Compressor const &compressor) + { + this->compressor = compressor; + } + virtual unsigned int get_openmode() const + { + return openmode; + } + virtual void set_openmode(unsigned int openmode) + { + this->openmode = openmode; + } + virtual bool get_is_pipe() const + { + return is_pipe; + } + virtual void set_is_pipe(bool is_pipe) + { + this->is_pipe = is_pipe; + } + virtual unsigned long long get_seekpos() const + { + return seekpos; + } + virtual void set_seekpos(unsigned long long seekpos) + { + this->seekpos = seekpos; + } virtual bool InternalOpen(int const iFd, unsigned int const Mode) = 0; ssize_t InternalRead(void * To, unsigned long long Size) { - unsigned long long tmp = 0; - if (buffersize != 0) + // Drain the buffer if needed. + if (buffer.empty() == false) { - if (buffersize >= Size) - { - memcpy(To, buffer.get(), Size); - if (buffersize == Size) - { - buffersize = 0; - } - else - { - buffersize -= Size; - memmove(buffer.get(), buffer.get() + Size, buffersize); - } - return Size; - } - else - { - memcpy(To, buffer.get(), buffersize); - Size -= buffersize; - To = static_cast(To) + buffersize; - tmp = buffersize; - buffersize = 0; - } + return buffer.read(To, Size); } - return InternalUnbufferedRead(To, Size) + tmp; + 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")); } @@ -973,28 +1019,21 @@ public: { if (unlikely(Size == 0)) return nullptr; + // Read one byte less than buffer size to have space for trailing 0. --Size; - To[0] = '\0'; - if (unlikely(Size == 0)) - return To; + char * const InitialTo = To; - do { - if (buffersize == 0) + while (Size > 0) { + if (buffer.empty() == true) { - if (buffer.get() == nullptr) - { - buffer.reset(new char[Size]); - buffersize_max = Size; - } + buffer.reset(); unsigned long long actualread = 0; - if (filefd->Read(buffer.get(), buffersize_max, &actualread) == false) + if (filefd->Read(buffer.get(), buffer.buffersize_max, &actualread) == false) return nullptr; - buffersize = actualread; - if (buffersize == 0) + buffer.bufferend = actualread; + if (buffer.size() == 0) { - buffer.reset(nullptr); - buffersize_max = 0; if (To == InitialTo) return nullptr; break; @@ -1002,35 +1041,25 @@ public: filefd->Flags &= ~FileFd::HitEof; } - unsigned long long const OutputSize = std::min(Size, buffersize); + 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) - { - size_t length = (newline - buffer.get()); - ++length; - memcpy(To, buffer.get(), length); - To += length; - if (length < buffersize) - { - buffersize -= length; - memmove(buffer.get(), buffer.get() + length, buffersize); - } - else - buffersize = 0; break; - } - else - { - memcpy(To, buffer.get(), OutputSize); - To += OutputSize; - Size -= OutputSize; - buffersize -= OutputSize; - memmove(buffer.get(), buffer.get() + OutputSize, buffersize); - } - } while (Size > 0); + } *To = '\0'; return InitialTo; } + virtual bool InternalFlush() + { + return true; + } virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) = 0; virtual bool InternalWriteError() { return filefd->FileFdErrno("write",_("Write error")); } virtual bool InternalSeek(unsigned long long const To) @@ -1064,7 +1093,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()); - buffersize = 0; + buffer.reset(); if (To != 0) return filefd->Skip(To); @@ -1094,7 +1123,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 - buffersize; + return seekpos - buffer.size(); } virtual unsigned long long InternalSize() { @@ -1121,7 +1150,153 @@ public: virtual ~FileFdPrivate() {} }; /*}}}*/ -class GzipFileFdPrivate: public FileFdPrivate { /*{{{*/ +class APT_HIDDEN BufferedWriteFileFdPrivate : public FileFdPrivate { /*{{{*/ +protected: + FileFdPrivate *wrapped; + simple_buffer writebuffer; + +public: + + explicit BufferedWriteFileFdPrivate(FileFdPrivate *Priv) : + FileFdPrivate(Priv->filefd), wrapped(Priv) {}; + + virtual APT::Configuration::Compressor get_compressor() const override + { + return wrapped->get_compressor(); + } + virtual void set_compressor(APT::Configuration::Compressor const &compressor) override + { + return wrapped->set_compressor(compressor); + } + virtual unsigned int get_openmode() const override + { + return wrapped->get_openmode(); + } + virtual void set_openmode(unsigned int openmode) override + { + return wrapped->set_openmode(openmode); + } + virtual bool get_is_pipe() const override + { + return wrapped->get_is_pipe(); + } + virtual void set_is_pipe(bool is_pipe) override + { + FileFdPrivate::set_is_pipe(is_pipe); + wrapped->set_is_pipe(is_pipe); + } + virtual unsigned long long get_seekpos() const override + { + return wrapped->get_seekpos(); + } + virtual void set_seekpos(unsigned long long seekpos) override + { + return wrapped->set_seekpos(seekpos); + } + virtual bool InternalOpen(int const iFd, unsigned int const Mode) override + { + if (InternalFlush() == false) + return false; + return wrapped->InternalOpen(iFd, Mode); + } + virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override + { + if (InternalFlush() == false) + return -1; + return wrapped->InternalUnbufferedRead(To, Size); + + } + virtual bool InternalReadError() override + { + return wrapped->InternalReadError(); + } + virtual char * InternalReadLine(char * To, unsigned long long Size) override + { + if (InternalFlush() == false) + return nullptr; + return wrapped->InternalReadLine(To, Size); + } + virtual bool InternalFlush() override + { + while (writebuffer.empty() == false) { + auto written = wrapped->InternalWrite(writebuffer.get(), + writebuffer.size()); + // Ignore interrupted syscalls + if (written < 0 && errno == EINTR) + continue; + if (written < 0) + return false; + + writebuffer.bufferstart += written; + } + + writebuffer.reset(); + return true; + } + virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) override + { + size_t written = 0; + + while (written < Size) { + auto buffered = writebuffer.write(static_cast(From) + written, Size - written); + + written += buffered; + + if (writebuffer.full() && InternalFlush() == false) + return -1; + } + + return written; + } + virtual bool InternalWriteError() + { + return wrapped->InternalWriteError(); + } + virtual bool InternalSeek(unsigned long long const To) + { + if (InternalFlush() == false) + return false; + return wrapped->InternalSeek(To); + } + virtual bool InternalSkip(unsigned long long Over) + { + if (InternalFlush() == false) + return false; + return wrapped->InternalSkip(Over); + } + virtual bool InternalTruncate(unsigned long long const Size) + { + if (InternalFlush() == false) + return false; + return wrapped->InternalTruncate(Size); + } + virtual unsigned long long InternalTell() + { + if (InternalFlush() == false) + return -1; + return wrapped->InternalTell(); + } + virtual unsigned long long InternalSize() + { + if (InternalFlush() == false) + return -1; + return wrapped->InternalSize(); + } + virtual bool InternalClose(std::string const &FileName) + { + return wrapped->InternalClose(FileName); + } + virtual bool InternalAlwaysAutoClose() const + { + return wrapped->InternalAlwaysAutoClose(); + } + virtual ~BufferedWriteFileFdPrivate() + { + delete wrapped; + } +}; + /*}}}*/ +class APT_HIDDEN GzipFileFdPrivate: public FileFdPrivate { /*{{{*/ #ifdef HAVE_ZLIB public: gzFile gz; @@ -1170,20 +1345,19 @@ public: if (res != (off_t)To) return filefd->FileFdError("Unable to seek to %llu", To); seekpos = To; - buffersize = 0; + buffer.reset(); return true; } virtual bool InternalSkip(unsigned long long Over) override { - if (Over >= buffersize) + if (Over >= buffer.size()) { - Over -= buffersize; - buffersize = 0; + Over -= buffer.size(); + buffer.reset(); } else { - buffersize -= Over; - memmove(buffer.get(), buffer.get() + Over, buffersize); + buffer.bufferstart += Over; return true; } if (Over == 0) @@ -1196,7 +1370,7 @@ public: } virtual unsigned long long InternalTell() override { - return gztell(gz) - buffersize; + return gztell(gz) - buffer.size(); } virtual unsigned long long InternalSize() override { @@ -1249,7 +1423,7 @@ public: #endif }; /*}}}*/ -class Bz2FileFdPrivate: public FileFdPrivate { /*{{{*/ +class APT_HIDDEN Bz2FileFdPrivate: public FileFdPrivate { /*{{{*/ #ifdef HAVE_BZ2 BZFILE* bz2; public: @@ -1303,7 +1477,7 @@ public: #endif }; /*}}}*/ -class LzmaFileFdPrivate: public FileFdPrivate { /*{{{*/ +class APT_HIDDEN LzmaFileFdPrivate: public FileFdPrivate { /*{{{*/ #ifdef HAVE_LZMA struct LZMAFILE { FILE* file; @@ -1496,7 +1670,7 @@ public: #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 */ { @@ -1536,7 +1710,7 @@ public: SetCloseExec(Pipe[J],true); compressed_fd = filefd->iFd; - is_pipe = true; + set_is_pipe(true); if (Comp == true) filefd->iFd = Pipe[1]; @@ -1619,7 +1793,7 @@ public: 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; } @@ -1630,10 +1804,10 @@ public: 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 (buffersize != 0) + if (buffer.size() != 0) { - lseek(filefd->iFd, -buffersize, SEEK_CUR); - buffersize = 0; + lseek(filefd->iFd, -buffer.size(), SEEK_CUR); + buffer.reset(); } return write(filefd->iFd, From, Size); } @@ -1643,20 +1817,19 @@ public: if (res != (off_t)To) return filefd->FileFdError("Unable to seek to %llu", To); seekpos = To; - buffersize = 0; + buffer.reset(); return true; } virtual bool InternalSkip(unsigned long long Over) override { - if (Over >= buffersize) + if (Over >= buffer.size()) { - Over -= buffersize; - buffersize = 0; + Over -= buffer.size(); + buffer.reset(); } else { - buffersize -= Over; - memmove(buffer.get(), buffer.get() + Over, buffersize); + buffer.bufferstart += Over; return true; } if (Over == 0) @@ -1669,15 +1842,15 @@ public: } virtual bool InternalTruncate(unsigned long long const To) override { - if (buffersize != 0) + if (buffer.size() != 0) { unsigned long long const seekpos = lseek(filefd->iFd, 0, SEEK_CUR); - if ((seekpos - buffersize) >= To) - buffersize = 0; + if ((seekpos - buffer.size()) >= To) + buffer.reset(); else if (seekpos >= To) - buffersize = (To - seekpos); + buffer.bufferend = (To - seekpos) + buffer.bufferstart; else - buffersize = 0; + buffer.reset(); } if (ftruncate(filefd->iFd, To) != 0) return filefd->FileFdError("Unable to truncate to %llu",To); @@ -1685,7 +1858,7 @@ public: } virtual unsigned long long InternalTell() override { - return lseek(filefd->iFd,0,SEEK_CUR) - buffersize; + return lseek(filefd->iFd,0,SEEK_CUR) - buffer.size(); } virtual unsigned long long InternalSize() override { @@ -1959,8 +2132,11 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C else d = new PipedFileFdPrivate(this); - d->openmode = Mode; - d->compressor = compressor; + if (Mode & BufferedWrite) + d = new BufferedWriteFileFdPrivate(d); + + d->set_openmode(Mode); + d->set_compressor(compressor); if ((Flags & AutoClose) != AutoClose && d->InternalAlwaysAutoClose()) { // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well @@ -2018,7 +2194,7 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual) To = (char *)To + Res; Size -= Res; if (d != NULL) - d->seekpos += Res; + d->set_seekpos(d->get_seekpos() + Res); if (Actual != 0) *Actual += Res; } @@ -2048,6 +2224,15 @@ char* FileFd::ReadLine(char *To, unsigned long long const Size) return d->InternalReadLine(To, Size); } /*}}}*/ +// FileFd::Flush - Flush the file /*{{{*/ +bool FileFd::Flush() +{ + if (d == nullptr) + return true; + + return d->InternalFlush(); +} + /*}}}*/ // FileFd::Write - Write to the file /*{{{*/ bool FileFd::Write(const void *From,unsigned long long Size) { @@ -2066,7 +2251,7 @@ bool FileFd::Write(const void *From,unsigned long long Size) From = (char const *)From + Res; Size -= Res; if (d != NULL) - d->seekpos += Res; + d->set_seekpos(d->get_seekpos() + Res); } if (Size == 0) @@ -2134,13 +2319,13 @@ unsigned long long FileFd::Tell() off_t const Res = d->InternalTell(); if (Res == (off_t)-1) FileFdErrno("lseek","Failed to determine the current file position"); - d->seekpos = Res; + d->set_seekpos(Res); return Res; } /*}}}*/ static bool StatFileFd(char const * const msg, int const iFd, std::string const &FileName, struct stat &Buf, FileFdPrivate * const d) /*{{{*/ { - bool ispipe = (d != NULL && d->is_pipe == true); + bool ispipe = (d != NULL && d->get_is_pipe() == true); if (ispipe == false) { if (fstat(iFd,&Buf) != 0) @@ -2157,7 +2342,7 @@ static bool StatFileFd(char const * const msg, int const iFd, std::string const // we set it here, too, as we get the info here for free // in theory the Open-methods should take care of it already if (d != NULL) - d->is_pipe = true; + d->set_is_pipe(true); if (stat(FileName.c_str(), &Buf) != 0) return _error->Errno("fstat", "Unable to determine %s for file %s", msg, FileName.c_str()); } @@ -2201,6 +2386,8 @@ unsigned long long FileFd::Size() /* */ bool FileFd::Close() { + if (Flush() == false) + return false; if (iFd == -1) return true;