#include <dirent.h>
#include <signal.h>
#include <errno.h>
+#include <glob.h>
+
#include <set>
#include <algorithm>
/* The caller is expected to set things so that failure causes erasure */
bool CopyFile(FileFd &From,FileFd &To)
{
- if (From.IsOpen() == false || To.IsOpen() == false)
+ if (From.IsOpen() == false || To.IsOpen() == false ||
+ From.Failed() == true || To.Failed() == true)
return false;
// Buffered copy between fds
fl.l_len = 0;
if (fcntl(FD,F_SETLK,&fl) == -1)
{
+ // always close to not leak resources
+ int Tmp = errno;
+ close(FD);
+ errno = Tmp;
+
if (errno == ENOLCK)
{
_error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str());
return dup(0); // Need something for the caller to close
- }
+ }
+
if (Errors == true)
_error->Errno("open",_("Could not get lock %s"),File.c_str());
- int Tmp = errno;
- close(FD);
- errno = Tmp;
return -1;
}
while (1)
{
// Read the link
- int Res;
+ ssize_t Res;
if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 ||
- (unsigned)Res >= sizeof(Buffer))
+ (size_t)Res >= sizeof(Buffer))
return File;
// Append or replace the previous path
child, it fixes up the important signals and nukes all of the fds,
otherwise acts like normal fork. */
pid_t ExecFork()
+{
+ set<int> KeepFDs;
+
+ // FIXME: remove looking at APT::Keep-Fds eventually, its a hack
+ Configuration::Item const *Opts = _config->Tree("APT::Keep-Fds");
+ if (Opts != 0 && Opts->Child != 0)
+ {
+ Opts = Opts->Child;
+ for (; Opts != 0; Opts = Opts->Next)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+ int fd = atoi(Opts->Value.c_str());
+ KeepFDs.insert(fd);
+ }
+ }
+ return ExecFork(KeepFDs);
+}
+
+pid_t ExecFork(std::set<int> KeepFDs)
{
// Fork off the process
pid_t Process = fork();
signal(SIGCONT,SIG_DFL);
signal(SIGTSTP,SIG_DFL);
- set<int> KeepFDs;
- Configuration::Item const *Opts = _config->Tree("APT::Keep-Fds");
- if (Opts != 0 && Opts->Child != 0)
- {
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
- int fd = atoi(Opts->Value.c_str());
- KeepFDs.insert(fd);
- }
- }
-
// Close all of our FDs - just in case
- for (int K = 3; K != 40; K++)
+ for (int K = 3; K != sysconf(_SC_OPEN_MAX); K++)
{
if(KeepFDs.find(K) == KeepFDs.end())
fcntl(K,F_SETFD,FD_CLOEXEC);
return Open(FileName, ReadOnly, Gzip, Perms);
if (Compress == Auto && (Mode & WriteOnly) == WriteOnly)
- return _error->Error("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
+ return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
case Auto:
case Extension:
// Unreachable
- return _error->Error("Opening File %s in None, Auto or Extension should be already handled?!?", FileName.c_str());
+ return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName.c_str());
}
for (; compressor != compressors.end(); ++compressor)
if (compressor->Name == name)
break;
if (compressor == compressors.end())
- return _error->Error("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
+ return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
}
if (compressor == compressors.end())
- return _error->Error("Can't find a match for specified compressor mode for file %s", FileName.c_str());
+ return FileFdError("Can't find a match for specified compressor mode for file %s", FileName.c_str());
return Open(FileName, Mode, *compressor, Perms);
}
bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const Perms)
Flags = AutoClose;
if ((Mode & WriteOnly) != WriteOnly && (Mode & (Atomic | Create | Empty | Exclusive)) != 0)
- return _error->Error("ReadOnly mode for %s doesn't accept additional flags!", FileName.c_str());
+ return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName.c_str());
if ((Mode & ReadWrite) == 0)
- return _error->Error("No openmode provided in FileFd::Open for %s", FileName.c_str());
+ return FileFdError("No openmode provided in FileFd::Open for %s", FileName.c_str());
if ((Mode & Atomic) == Atomic)
{
Flags |= Replace;
- char *name = strdup((FileName + ".XXXXXX").c_str());
- TemporaryFileName = string(mktemp(name));
- free(name);
}
else if ((Mode & (Exclusive | Create)) == (Exclusive | Create))
{
if_FLAGGED_SET(Create, O_CREAT);
if_FLAGGED_SET(Empty, O_TRUNC);
if_FLAGGED_SET(Exclusive, O_EXCL);
- else if_FLAGGED_SET(Atomic, O_EXCL);
#undef if_FLAGGED_SET
- if (TemporaryFileName.empty() == false)
- iFd = open(TemporaryFileName.c_str(), fileflags, Perms);
+ if ((Mode & Atomic) == Atomic)
+ {
+ char *name = strdup((FileName + ".XXXXXX").c_str());
+
+ if((iFd = mkstemp(name)) == -1)
+ {
+ free(name);
+ return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName.c_str());
+ }
+
+ TemporaryFileName = string(name);
+ free(name);
+
+ if(Perms != 600 && fchmod(iFd, Perms) == -1)
+ return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName.c_str());
+ }
else
iFd = open(FileName.c_str(), fileflags, Perms);
close (iFd);
iFd = -1;
}
- return _error->Errno("open",_("Could not open file %s"), FileName.c_str());
+ return FileFdErrno("open",_("Could not open file %s"), FileName.c_str());
}
SetCloseExec(iFd,true);
case Xz: name = "xz"; break;
case Auto:
case Extension:
- return _error->Error("Opening Fd %d in Auto or Extension compression mode is not supported", Fd);
+ if (AutoClose == true && Fd != -1)
+ close(Fd);
+ return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd);
}
for (; compressor != compressors.end(); ++compressor)
if (compressor->Name == name)
break;
if (compressor == compressors.end())
- return _error->Error("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
-
+ {
+ if (AutoClose == true && Fd != -1)
+ close(Fd);
+ return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
+ }
return OpenDescriptor(Fd, Mode, *compressor, AutoClose);
}
bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration::Compressor const &compressor, bool AutoClose)
else
iFd = Fd;
this->FileName = "";
- if (OpenInternDescriptor(Mode, compressor) == false)
+ if (Fd == -1 || OpenInternDescriptor(Mode, compressor) == false)
{
- if (AutoClose)
+ if (iFd != -1 && (
+#ifdef HAVE_ZLIB
+ compressor.Name == "gzip" ||
+#endif
+#ifdef HAVE_BZ2
+ compressor.Name == "bzip2" ||
+#endif
+ AutoClose == true))
+ {
close (iFd);
- return _error->Errno("gzdopen",_("Could not open file descriptor %d"), Fd);
+ iFd = -1;
+ }
+ return FileFdError(_("Could not open file descriptor %d"), Fd);
}
return true;
}
ExecWait(d->compressor_pid, "FileFdCompressor", true);
if ((Mode & ReadWrite) == ReadWrite)
- {
- Flags |= Fail;
- return _error->Error("ReadWrite mode is not supported for file %s", FileName.c_str());
- }
+ return FileFdError("ReadWrite mode is not supported for file %s", FileName.c_str());
bool const Comp = (Mode & WriteOnly) == WriteOnly;
if (Comp == false)
// Create a data pipe
int Pipe[2] = {-1,-1};
if (pipe(Pipe) != 0)
- {
- Flags |= Fail;
- return _error->Errno("pipe",_("Failed to create subprocess IPC"));
- }
+ return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
for (int J = 0; J != 2; J++)
SetCloseExec(Pipe[J],true);
{
Close();
if (d != NULL)
- {
d->CloseDown(FileName);
- delete d;
- d = NULL;
- }
+ delete d;
+ d = NULL;
}
/*}}}*/
// FileFd::Read - Read a bit of the file /*{{{*/
gracefully. */
bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
{
- int Res;
+ ssize_t Res;
errno = 0;
if (Actual != 0)
*Actual = 0;
{
if (errno == EINTR)
continue;
- Flags |= Fail;
#ifdef HAVE_ZLIB
if (d != NULL && d->gz != NULL)
{
int err;
char const * const errmsg = gzerror(d->gz, &err);
if (err != Z_ERRNO)
- return _error->Error("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
+ return FileFdError("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
}
#endif
#ifdef HAVE_BZ2
int err;
char const * const errmsg = BZ2_bzerror(d->bz2, &err);
if (err != BZ_IO_ERROR)
- return _error->Error("BZ2_bzread: %s (%d: %s)", _("Read error"), err, errmsg);
+ return FileFdError("BZ2_bzread: %s (%d: %s)", _("Read error"), err, errmsg);
}
#endif
- return _error->Errno("read",_("Read error"));
+ return FileFdErrno("read",_("Read error"));
}
To = (char *)To + Res;
Flags |= HitEof;
return true;
}
-
- Flags |= Fail;
- return _error->Error(_("read, still have %llu to read but none left"), Size);
+
+ return FileFdError(_("read, still have %llu to read but none left"), Size);
}
/*}}}*/
// FileFd::ReadLine - Read a complete line from the file /*{{{*/
/* */
bool FileFd::Write(const void *From,unsigned long long Size)
{
- int Res;
+ ssize_t Res;
errno = 0;
do
{
continue;
if (Res < 0)
{
- Flags |= Fail;
#ifdef HAVE_ZLIB
if (d != NULL && d->gz != NULL)
{
int err;
char const * const errmsg = gzerror(d->gz, &err);
if (err != Z_ERRNO)
- return _error->Error("gzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
+ return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
}
#endif
#ifdef HAVE_BZ2
int err;
char const * const errmsg = BZ2_bzerror(d->bz2, &err);
if (err != BZ_IO_ERROR)
- return _error->Error("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
+ return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
}
#endif
- return _error->Errno("write",_("Write error"));
+ return FileFdErrno("write",_("Write error"));
}
From = (char *)From + Res;
if (Size == 0)
return true;
-
- Flags |= Fail;
- return _error->Error(_("write, still have %llu to write but couldn't"), Size);
+
+ return FileFdError(_("write, still have %llu to write but couldn't"), Size);
}
bool FileFd::Write(int Fd, const void *From, unsigned long long Size)
{
- int Res;
+ ssize_t Res;
errno = 0;
do
{
return Skip(To - seekpos);
if ((d->openmode & ReadOnly) != ReadOnly)
- {
- Flags |= Fail;
- return _error->Error("Reopen is only implemented for read-only files!");
- }
+ return FileFdError("Reopen is only implemented for read-only files!");
#ifdef HAVE_BZ2
if (d->bz2 != NULL)
{
if (lseek(d->compressed_fd, 0, SEEK_SET) != 0)
iFd = d->compressed_fd;
if (iFd < 0)
- {
- Flags |= Fail;
- return _error->Error("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
- }
+ return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
}
if (OpenInternDescriptor(d->openmode, d->compressor) == false)
- {
- Flags |= Fail;
- return _error->Error("Seek on file %s because it couldn't be reopened", FileName.c_str());
- }
+ return FileFdError("Seek on file %s because it couldn't be reopened", FileName.c_str());
if (To != 0)
return Skip(To);
d->seekpos = To;
return true;
}
- int res;
+ off_t res;
#ifdef HAVE_ZLIB
if (d != NULL && d->gz)
res = gzseek(d->gz,To,SEEK_SET);
else
#endif
res = lseek(iFd,To,SEEK_SET);
- if (res != (signed)To)
- {
- Flags |= Fail;
- return _error->Error("Unable to seek to %llu", To);
- }
+ if (res != (off_t)To)
+ return FileFdError("Unable to seek to %llu", To);
if (d != NULL)
d->seekpos = To;
{
unsigned long long toread = std::min((unsigned long long) sizeof(buffer), Over);
if (Read(buffer, toread) == false)
- {
- Flags |= Fail;
- return _error->Error("Unable to seek ahead %llu",Over);
- }
+ return FileFdError("Unable to seek ahead %llu",Over);
Over -= toread;
}
return true;
}
- int res;
+ off_t res;
#ifdef HAVE_ZLIB
if (d != NULL && d->gz != NULL)
res = gzseek(d->gz,Over,SEEK_CUR);
#endif
res = lseek(iFd,Over,SEEK_CUR);
if (res < 0)
- {
- Flags |= Fail;
- return _error->Error("Unable to seek ahead %llu",Over);
- }
+ return FileFdError("Unable to seek ahead %llu",Over);
if (d != NULL)
d->seekpos = res;
{
#if defined HAVE_ZLIB || defined HAVE_BZ2
if (d != NULL && (d->gz != NULL || d->bz2 != NULL))
- {
- Flags |= Fail;
- return _error->Error("Truncating compressed files is not implemented (%s)", FileName.c_str());
- }
+ return FileFdError("Truncating compressed files is not implemented (%s)", FileName.c_str());
#endif
if (ftruncate(iFd,To) != 0)
- {
- Flags |= Fail;
- return _error->Error("Unable to truncate to %llu",To);
- }
-
+ return FileFdError("Unable to truncate to %llu",To);
+
return true;
}
/*}}}*/
#endif
Res = lseek(iFd,0,SEEK_CUR);
if (Res == (off_t)-1)
- {
- Flags |= Fail;
- _error->Errno("lseek","Failed to determine the current file position");
- }
+ FileFdErrno("lseek","Failed to determine the current file position");
if (d != NULL)
d->seekpos = Res;
return Res;
{
struct stat Buf;
if ((d == NULL || d->pipe == false) && fstat(iFd,&Buf) != 0)
- {
- Flags |= Fail;
- return _error->Errno("fstat","Unable to determine the file size");
- }
+ return FileFdErrno("fstat","Unable to determine the file size");
// for compressor pipes st_size is undefined and at 'best' zero
if ((d != NULL && d->pipe == true) || S_ISFIFO(Buf.st_mode))
if (d != NULL)
d->pipe = true;
if (stat(FileName.c_str(), &Buf) != 0)
- {
- Flags |= Fail;
- return _error->Errno("stat","Unable to determine the file size");
- }
+ return FileFdErrno("stat","Unable to determine the file size");
}
return Buf.st_size;
char ignore[1000];
unsigned long long read = 0;
do {
- Read(ignore, sizeof(ignore), &read);
+ if (Read(ignore, sizeof(ignore), &read) == false)
+ {
+ Seek(oldSeek);
+ return 0;
+ }
} while(read != 0);
size = Tell();
Seek(oldSeek);
// FIXME: Size for gz-files is limited by 32bit… no largefile support
if (lseek(iFd, -4, SEEK_END) < 0)
{
- Flags |= Fail;
- return _error->Errno("lseek","Unable to seek to end of gzipped file");
+ FileFdErrno("lseek","Unable to seek to end of gzipped file");
+ return 0;
}
- size = 0L;
+ size = 0;
if (read(iFd, &size, 4) != 4)
{
- Flags |= Fail;
- return _error->Errno("read","Unable to read original size of gzipped file");
+ FileFdErrno("read","Unable to read original size of gzipped file");
+ return 0;
}
#ifdef WORDS_BIGENDIAN
if (lseek(iFd, oldPos, SEEK_SET) < 0)
{
- Flags |= Fail;
- return _error->Errno("lseek","Unable to seek in gzipped file");
+ FileFdErrno("lseek","Unable to seek in gzipped file");
+ return 0;
}
return size;
struct stat Buf;
if ((d == NULL || d->pipe == false) && fstat(iFd,&Buf) != 0)
{
- Flags |= Fail;
- _error->Errno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
+ FileFdErrno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
return 0;
}
d->pipe = true;
if (stat(FileName.c_str(), &Buf) != 0)
{
- Flags |= Fail;
- _error->Errno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
+ FileFdErrno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
return 0;
}
}
bool FileFd::Sync()
{
if (fsync(iFd) != 0)
+ return FileFdErrno("sync",_("Problem syncing the file"));
+ return true;
+}
+ /*}}}*/
+// FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
+bool FileFd::FileFdErrno(const char *Function, const char *Description,...)
+{
+ Flags |= Fail;
+ va_list args;
+ size_t msgSize = 400;
+ int const errsv = errno;
+ while (true)
{
- Flags |= Fail;
- return _error->Errno("sync",_("Problem syncing the file"));
+ va_start(args,Description);
+ if (_error->InsertErrno(GlobalError::ERROR, Function, Description, args, errsv, msgSize) == false)
+ break;
+ va_end(args);
}
- return true;
+ return false;
+}
+ /*}}}*/
+// FileFd::FileFdError - set Fail and call _error->Error *{{{*/
+bool FileFd::FileFdError(const char *Description,...) {
+ Flags |= Fail;
+ va_list args;
+ size_t msgSize = 400;
+ while (true)
+ {
+ va_start(args,Description);
+ if (_error->Insert(GlobalError::ERROR, Description, args, msgSize) == false)
+ break;
+ va_end(args);
+ }
+ return false;
}
/*}}}*/
gzFile FileFd::gzFd() { return (gzFile) d->gz; }
+
+
+// Glob - wrapper around "glob()" /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+std::vector<std::string> Glob(std::string const &pattern, int flags)
+{
+ std::vector<std::string> result;
+ glob_t globbuf;
+ int glob_res;
+ unsigned int i;
+
+ glob_res = glob(pattern.c_str(), flags, NULL, &globbuf);
+
+ if (glob_res != 0)
+ {
+ if(glob_res != GLOB_NOMATCH) {
+ _error->Errno("glob", "Problem with glob");
+ return result;
+ }
+ }
+
+ // append results
+ for(i=0;i<globbuf.gl_pathc;i++)
+ result.push_back(string(globbuf.gl_pathv[i]));
+
+ globfree(&globbuf);
+ return result;
+}
+ /*}}}*/