class APT_HIDDEN FileFdPrivate { /*{{{*/
protected:
FileFd * const filefd;
- const size_t buffersize_max = 4096;
- std::unique_ptr<char[]> buffer;
- unsigned long long buffersize = 0;
+ 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)
+ {
+ 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;
APT::Configuration::Compressor compressor;
unsigned int openmode;
unsigned long long seekpos;
- explicit FileFdPrivate(FileFd * const pfilefd) : filefd(pfilefd), buffer(nullptr),
+ 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;
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<char *>(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")); }
char * const InitialTo = To;
do {
- if (buffersize == 0)
+ if (buffer.empty() == true)
{
- if (buffer.get() == nullptr)
- {
- buffer.reset(new char[buffersize_max]);
- }
+ 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);
if (To == InitialTo)
return nullptr;
break;
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<char const * const>(memchr(buffer.get(), '\n', OutputSize));
if (newline != nullptr)
{
- size_t length = (newline - buffer.get());
- ++length;
- memcpy(To, buffer.get(), length);
+ size_t length = (newline - buffer.get()) + 1;
+ buffer.read(To, 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);
+ buffer.read(To, OutputSize);
To += OutputSize;
Size -= OutputSize;
- buffersize -= OutputSize;
- memmove(buffer.get(), buffer.get() + OutputSize, buffersize);
}
} while (Size > 0);
*To = '\0';
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);
// 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()
{
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)
}
virtual unsigned long long InternalTell() override
{
- return gztell(gz) - buffersize;
+ return gztell(gz) - buffer.size();
}
virtual unsigned long long InternalSize() override
{
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);
}
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)
}
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);
}
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
{