summaryrefslogtreecommitdiff
path: root/apt-pkg/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg/contrib')
-rw-r--r--apt-pkg/contrib/fileutl.cc167
1 files changed, 140 insertions, 27 deletions
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index ca2710a79..1e0f4dc34 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/apt-pkg/contrib/fileutl.cc
@@ -922,6 +922,9 @@ bool ChangeOwnerAndPermissionOfFile(char const * const requester, char const * c
class FileFdPrivate { /*{{{*/
protected:
FileFd * const filefd;
+ static size_t constexpr buffersize_max = 1024;
+ char buffer[buffersize_max];
+ unsigned long long buffersize = 0;
public:
int compressed_fd;
pid_t compressor_pid;
@@ -934,25 +937,92 @@ public:
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)
+ unsigned long long tmp = 0;
+ if (buffersize != 0)
{
- unsigned long long done = 0;
- if (filefd->Read(To + read, 1, &done) == false)
- return NULL;
- if (done == 0)
- break;
- if (To[read++] == '\n')
- break;
+ if (buffersize >= Size)
+ {
+ memcpy(To, buffer, Size);
+ if (buffersize == Size)
+ {
+ buffersize = 0;
+ }
+ else
+ {
+ buffersize -= Size;
+ memmove(buffer, buffer + Size, buffersize);
+ }
+ return Size;
+ }
+ else
+ {
+ memcpy(To, buffer, buffersize);
+ Size -= buffersize;
+ To = static_cast<char *>(To) + buffersize;
+ tmp = buffersize;
+ buffersize = 0;
+ }
}
- if (read == 0)
- return NULL;
- To[read] = '\0';
- return To;
+ return InternalUnbufferedRead(To, Size) + tmp;
+ }
+ 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 (buffersize == 0)
+ {
+ unsigned long long actualread = 0;
+ if (filefd->Read(buffer, buffersize_max, &actualread) == false)
+ return nullptr;
+ buffersize = actualread;
+ if (buffersize == 0)
+ {
+ if (To == InitialTo)
+ return nullptr;
+ break;
+ }
+ filefd->Flags &= ~FileFd::HitEof;
+ }
+
+ unsigned long long const OutputSize = std::min(Size, buffersize);
+ char const * const newline = static_cast<char const * const>(memchr(buffer, '\n', OutputSize));
+ if (newline != nullptr)
+ {
+ size_t length = (newline - buffer);
+ ++length;
+ memcpy(To, buffer, length);
+ To += length;
+ if (length < buffersize)
+ {
+ buffersize -= length;
+ memmove(buffer, buffer + length, buffersize);
+ }
+ else
+ buffersize = 0;
+ break;
+ }
+ else
+ {
+ memcpy(To, buffer, OutputSize);
+ To += OutputSize;
+ Size -= OutputSize;
+ buffersize -= OutputSize;
+ memmove(buffer, buffer + OutputSize, buffersize);
+ }
+ } 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 +1057,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;
if (To != 0)
return filefd->Skip(To);
@@ -1016,7 +1087,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 - buffersize;
}
virtual unsigned long long InternalSize()
{
@@ -1058,7 +1129,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 +1141,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 +1162,25 @@ 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;
+ buffersize = 0;
return true;
}
virtual bool InternalSkip(unsigned long long Over) override
{
+ if (Over >= buffersize)
+ {
+ Over -= buffersize;
+ buffersize = 0;
+ }
+ else
+ {
+ buffersize -= Over;
+ memmove(buffer, buffer + Over, buffersize);
+ 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 +1189,7 @@ public:
}
virtual unsigned long long InternalTell() override
{
- return gztell(gz);
+ return gztell(gz) - buffersize;
}
virtual unsigned long long InternalSize() override
{
@@ -1173,7 +1257,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);
}
@@ -1332,7 +1416,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)
@@ -1508,7 +1592,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);
}
@@ -1532,13 +1616,18 @@ class 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 (buffersize != 0)
+ {
+ lseek(filefd->iFd, -buffersize, SEEK_CUR);
+ buffersize = 0;
+ }
return write(filefd->iFd, From, Size);
}
virtual bool InternalSeek(unsigned long long const To) override
@@ -1547,10 +1636,24 @@ public:
if (res != (off_t)To)
return filefd->FileFdError("Unable to seek to %llu", To);
seekpos = To;
+ buffersize = 0;
return true;
}
virtual bool InternalSkip(unsigned long long Over) override
{
+ if (Over >= buffersize)
+ {
+ Over -= buffersize;
+ buffersize = 0;
+ }
+ else
+ {
+ buffersize -= Over;
+ memmove(buffer, buffer + Over, buffersize);
+ 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 +1662,23 @@ public:
}
virtual bool InternalTruncate(unsigned long long const To) override
{
+ if (buffersize != 0)
+ {
+ unsigned long long const seekpos = lseek(filefd->iFd, 0, SEEK_CUR);
+ if ((seekpos - buffersize) >= To)
+ buffersize = 0;
+ else if (seekpos >= To)
+ buffersize = (To - seekpos);
+ else
+ buffersize = 0;
+ }
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) - buffersize;
}
virtual unsigned long long InternalSize() override
{