return AbsPath;
}
/*}}}*/
+std::string flNormalize(std::string file) /*{{{*/
+{
+ if (file.empty())
+ return file;
+ // do some normalisation by removing // and /./ from the path
+ size_t found = string::npos;
+ while ((found = file.find("/./")) != string::npos)
+ file.replace(found, 3, "/");
+ while ((found = file.find("//")) != string::npos)
+ file.replace(found, 2, "/");
+
+ if (APT::String::Startswith(file, "/dev/null"))
+ {
+ file.erase(strlen("/dev/null"));
+ return file;
+ }
+ return file;
+}
+ /*}}}*/
// SetCloseExec - Set the close on exec flag /*{{{*/
// ---------------------------------------------------------------------
/* */
// ensure the file is owned by root and has good permissions
struct passwd const * const pw = getpwnam(user);
struct group const * const gr = getgrnam(group);
- if (pw != NULL && gr != NULL && chown(file, pw->pw_uid, gr->gr_gid) != 0)
+ if (pw != NULL && gr != NULL && lchown(file, pw->pw_uid, gr->gr_gid) != 0)
Res &= _error->WarningE(requester, "chown to %s:%s of file %s failed", user, group, file);
}
+ struct stat Buf;
+ if (lstat(file, &Buf) != 0 || S_ISLNK(Buf.st_mode))
+ return Res;
if (chmod(file, mode) != 0)
Res &= _error->WarningE(requester, "chmod 0%o of file %s failed", mode, file);
return Res;
writebuffer.bufferstart += written;
}
-
writebuffer.reset();
- return true;
+ return wrapped->InternalFlush();
}
virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
{
return false;
unsigned int flags = (Mode & (FileFd::WriteOnly|FileFd::ReadOnly));
- if (backend.OpenDescriptor(iFd, flags) == false)
+ if (backend.OpenDescriptor(iFd, flags, FileFd::None, true) == false)
return false;
// Write the file header
if (cctx != nullptr)
{
- res = LZ4F_compressEnd(cctx, lz4_buffer.buffer, lz4_buffer.buffersize_max, nullptr);
- if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
- return false;
- if (!backend.Flush())
- return false;
+ if (filefd->Failed() == false)
+ {
+ res = LZ4F_compressEnd(cctx, lz4_buffer.buffer, lz4_buffer.buffersize_max, nullptr);
+ if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
+ return false;
+ if (!backend.Flush())
+ return false;
+ }
if (!backend.Close())
return false;
res = LZ4F_freeDecompressionContext(dctx);
dctx = nullptr;
}
+ if (backend.IsOpen())
+ {
+ backend.Close();
+ filefd->iFd = -1;
+ }
return LZ4F_isError(res) == false;
}
#ifdef HAVE_LZMA
struct LZMAFILE {
FILE* file;
+ FileFd * const filefd;
uint8_t buffer[4096];
lzma_stream stream;
lzma_ret err;
bool eof;
bool compressing;
- LZMAFILE() : file(nullptr), eof(false), compressing(false) { buffer[0] = '\0'; }
+ LZMAFILE(FileFd * const fd) : file(nullptr), filefd(fd), eof(false), compressing(false) { buffer[0] = '\0'; }
~LZMAFILE()
{
- if (compressing == true)
+ if (compressing == true && filefd->Failed() == false)
{
size_t constexpr buffersize = sizeof(buffer)/sizeof(buffer[0]);
while(true)
return filefd->FileFdError("ReadWrite mode is not supported for lzma/xz files %s", filefd->FileName.c_str());
if (lzma == nullptr)
- lzma = new LzmaFileFdPrivate::LZMAFILE;
+ lzma = new LzmaFileFdPrivate::LZMAFILE(filefd);
if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
lzma->file = fdopen(iFd, "w");
else
if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
return filefd->FileFdError("ReadWrite mode is not supported for file %s", filefd->FileName.c_str());
+ if (compressor.Binary == "false")
+ return filefd->FileFdError("libapt has inbuilt support for the %s compression,"
+ " but was forced to ignore it in favor of an external binary – which isn't installed.", compressor.Name.c_str());
bool const Comp = (Mode & FileFd::WriteOnly) == FileFd::WriteOnly;
if (Comp == false)
virtual bool InternalClose(std::string const &) APT_OVERRIDE
{
bool Ret = true;
+ if (filefd->iFd != -1)
+ {
+ close(filefd->iFd);
+ filefd->iFd = -1;
+ }
if (compressor_pid > 0)
Ret &= ExecWait(compressor_pid, "FileFdCompressor", true);
compressor_pid = -1;
gracefully. */
bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
{
- if (d == nullptr)
+ if (d == nullptr || Failed())
return false;
ssize_t Res = 1;
errno = 0;
}
return FileFdError(_("read, still have %llu to read but none left"), Size);
+}
+bool FileFd::Read(int const Fd, void *To, unsigned long long Size, unsigned long long * const Actual)
+{
+ ssize_t Res = 1;
+ errno = 0;
+ if (Actual != nullptr)
+ *Actual = 0;
+ *static_cast<char *>(To) = '\0';
+ while (Res > 0 && Size > 0)
+ {
+ Res = read(Fd, To, Size);
+ if (Res < 0)
+ {
+ if (errno == EINTR)
+ {
+ Res = 1;
+ errno = 0;
+ continue;
+ }
+ return _error->Errno("read", _("Read error"));
+ }
+ To = static_cast<char *>(To) + Res;
+ Size -= Res;
+ if (Actual != 0)
+ *Actual += Res;
+ }
+ if (Size == 0)
+ return true;
+ if (Actual != nullptr)
+ return true;
+ return _error->Error(_("read, still have %llu to read but none left"), Size);
}
/*}}}*/
// FileFd::ReadLine - Read a complete line from the file /*{{{*/
char* FileFd::ReadLine(char *To, unsigned long long const Size)
{
*To = '\0';
- if (d == nullptr)
+ if (d == nullptr || Failed())
return nullptr;
return d->InternalReadLine(To, Size);
}
// FileFd::Flush - Flush the file /*{{{*/
bool FileFd::Flush()
{
+ if (Failed())
+ return false;
if (d == nullptr)
return true;
// FileFd::Write - Write to the file /*{{{*/
bool FileFd::Write(const void *From,unsigned long long Size)
{
- if (d == nullptr)
+ if (d == nullptr || Failed())
return false;
ssize_t Res = 1;
errno = 0;
// FileFd::Seek - Seek in the file /*{{{*/
bool FileFd::Seek(unsigned long long To)
{
- if (d == nullptr)
+ if (d == nullptr || Failed())
return false;
Flags &= ~HitEof;
return d->InternalSeek(To);
// FileFd::Skip - Skip over data in the file /*{{{*/
bool FileFd::Skip(unsigned long long Over)
{
- if (d == nullptr)
+ if (d == nullptr || Failed())
return false;
return d->InternalSkip(Over);
}
// FileFd::Truncate - Truncate the file /*{{{*/
bool FileFd::Truncate(unsigned long long To)
{
- if (d == nullptr)
+ if (d == nullptr || Failed())
return false;
// truncating /dev/null is always successful - as we get an error otherwise
if (To == 0 && FileName == "/dev/null")
/* */
unsigned long long FileFd::Tell()
{
- if (d == nullptr)
+ if (d == nullptr || Failed())
return false;
off_t const Res = d->InternalTell();
if (Res == (off_t)-1)
unsigned long long FileFd::Size()
{
if (d == nullptr)
- return false;
+ return 0;
return d->InternalSize();
}
/*}}}*/
/* */
bool FileFd::Close()
{
- if (Flush() == false)
+ if (Failed() == false && Flush() == false)
return false;
if (iFd == -1)
return true;
}
if ((Flags & Replace) == Replace) {
- if (rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
+ if (Failed() == false && rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
Res &= _error->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName.c_str(), FileName.c_str());
FileName = TemporaryFileName; // for the unlink() below.
va_list args;
size_t msgSize = 400;
int const errsv = errno;
- while (true)
- {
+ bool retry;
+ do {
va_start(args,Description);
- if (_error->InsertErrno(GlobalError::ERROR, Function, Description, args, errsv, msgSize) == false)
- break;
+ retry = _error->InsertErrno(GlobalError::ERROR, Function, Description, args, errsv, msgSize);
va_end(args);
- }
+ } while (retry);
return false;
}
/*}}}*/
Flags |= Fail;
va_list args;
size_t msgSize = 400;
- while (true)
- {
+ bool retry;
+ do {
va_start(args,Description);
- if (_error->Insert(GlobalError::ERROR, Description, args, msgSize) == false)
- break;
+ retry = _error->Insert(GlobalError::ERROR, Description, args, msgSize);
va_end(args);
- }
+ } while (retry);
return false;
}
/*}}}*/