summaryrefslogtreecommitdiff
path: root/apt-pkg/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg/contrib')
-rw-r--r--apt-pkg/contrib/cmndline.cc42
-rw-r--r--apt-pkg/contrib/cmndline.h1
-rw-r--r--apt-pkg/contrib/configuration.cc67
-rw-r--r--apt-pkg/contrib/configuration.h56
-rw-r--r--apt-pkg/contrib/error.cc380
-rw-r--r--apt-pkg/contrib/error.h292
-rw-r--r--apt-pkg/contrib/fileutl.cc164
-rw-r--r--apt-pkg/contrib/fileutl.h28
-rw-r--r--apt-pkg/contrib/macros.h34
-rw-r--r--apt-pkg/contrib/mmap.cc214
-rw-r--r--apt-pkg/contrib/mmap.h15
-rw-r--r--apt-pkg/contrib/strutl.cc143
-rw-r--r--apt-pkg/contrib/strutl.h26
-rw-r--r--apt-pkg/contrib/weakptr.h62
14 files changed, 1123 insertions, 401 deletions
diff --git a/apt-pkg/contrib/cmndline.cc b/apt-pkg/contrib/cmndline.cc
index bfd53695e..5a9944096 100644
--- a/apt-pkg/contrib/cmndline.cc
+++ b/apt-pkg/contrib/cmndline.cc
@@ -135,7 +135,9 @@ bool CommandLine::Parse(int argc,const char **argv)
for (; I != argc; I++)
*Files++ = argv[I];
*Files = 0;
-
+
+ SaveInConfig(argc, argv);
+
return true;
}
/*}}}*/
@@ -351,3 +353,41 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch)
return false;
}
/*}}}*/
+// CommandLine::SaveInConfig - for output later in a logfile or so /*{{{*/
+// ---------------------------------------------------------------------
+/* We save the commandline here to have it around later for e.g. logging.
+ It feels a bit like a hack here and isn't bulletproof, but it is better
+ than nothing after all. */
+void CommandLine::SaveInConfig(unsigned int const &argc, char const * const * const argv)
+{
+ char cmdline[100 + argc * 50];
+ unsigned int length = 0;
+ bool lastWasOption = false;
+ bool closeQuote = false;
+ for (unsigned int i = 0; i < argc && length < sizeof(cmdline); ++i, ++length)
+ {
+ for (unsigned int j = 0; argv[i][j] != '\0' && length < sizeof(cmdline)-1; ++j, ++length)
+ {
+ cmdline[length] = argv[i][j];
+ if (lastWasOption == true && argv[i][j] == '=')
+ {
+ // That is possibly an option: Quote it if it includes spaces,
+ // the benefit is that this will eliminate also most false positives
+ const char* c = &argv[i][j+1];
+ for (; *c != '\0' && *c != ' '; ++c);
+ if (*c == '\0') continue;
+ cmdline[++length] = '"';
+ closeQuote = true;
+ }
+ }
+ if (closeQuote == true)
+ cmdline[length++] = '"';
+ // Problem: detects also --hello
+ if (cmdline[length-1] == 'o')
+ lastWasOption = true;
+ cmdline[length] = ' ';
+ }
+ cmdline[--length] = '\0';
+ _config->Set("CommandLine::AsString", cmdline);
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/cmndline.h b/apt-pkg/contrib/cmndline.h
index e28071e81..7c0c71aa7 100644
--- a/apt-pkg/contrib/cmndline.h
+++ b/apt-pkg/contrib/cmndline.h
@@ -60,6 +60,7 @@ class CommandLine
Configuration *Conf;
bool HandleOpt(int &I,int argc,const char *argv[],
const char *&Opt,Args *A,bool PreceedeMatch = false);
+ void static SaveInConfig(unsigned int const &argc, char const * const * const argv);
public:
diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc
index 8e3b84499..81cc87d15 100644
--- a/apt-pkg/contrib/configuration.cc
+++ b/apt-pkg/contrib/configuration.cc
@@ -79,7 +79,7 @@ Configuration::~Configuration()
/* This will lookup a single item by name below another item. It is a
helper function for the main lookup function */
Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
- unsigned long Len,bool Create)
+ unsigned long const &Len,bool const &Create)
{
int Res = 1;
Item *I = Head->Child;
@@ -112,7 +112,7 @@ Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
// ---------------------------------------------------------------------
/* This performs a fully scoped lookup of a given name, possibly creating
new items */
-Configuration::Item *Configuration::Lookup(const char *Name,bool Create)
+Configuration::Item *Configuration::Lookup(const char *Name,bool const &Create)
{
if (Name == 0)
return Root->Child;
@@ -239,7 +239,7 @@ vector<string> Configuration::FindVector(const char *Name) const
// Configuration::FindI - Find an integer value /*{{{*/
// ---------------------------------------------------------------------
/* */
-int Configuration::FindI(const char *Name,int Default) const
+int Configuration::FindI(const char *Name,int const &Default) const
{
const Item *Itm = Lookup(Name);
if (Itm == 0 || Itm->Value.empty() == true)
@@ -256,7 +256,7 @@ int Configuration::FindI(const char *Name,int Default) const
// Configuration::FindB - Find a boolean type /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool Configuration::FindB(const char *Name,bool Default) const
+bool Configuration::FindB(const char *Name,bool const &Default) const
{
const Item *Itm = Lookup(Name);
if (Itm == 0 || Itm->Value.empty() == true)
@@ -332,7 +332,7 @@ void Configuration::Set(const char *Name,const string &Value)
// Configuration::Set - Set an integer value /*{{{*/
// ---------------------------------------------------------------------
/* */
-void Configuration::Set(const char *Name,int Value)
+void Configuration::Set(const char *Name,int const &Value)
{
Item *Itm = Lookup(Name,true);
if (Itm == 0)
@@ -345,7 +345,7 @@ void Configuration::Set(const char *Name,int Value)
// Configuration::Clear - Clear an single value from a list /*{{{*/
// ---------------------------------------------------------------------
/* */
-void Configuration::Clear(const string Name, int Value)
+void Configuration::Clear(string const &Name, int const &Value)
{
char S[300];
snprintf(S,sizeof(S),"%i",Value);
@@ -355,7 +355,7 @@ void Configuration::Clear(const string Name, int Value)
// Configuration::Clear - Clear an single value from a list /*{{{*/
// ---------------------------------------------------------------------
/* */
-void Configuration::Clear(const string Name, string Value)
+void Configuration::Clear(string const &Name, string const &Value)
{
Item *Top = Lookup(Name.c_str(),false);
if (Top == 0 || Top->Child == 0)
@@ -386,7 +386,7 @@ void Configuration::Clear(const string Name, string Value)
// Configuration::Clear - Clear an entire tree /*{{{*/
// ---------------------------------------------------------------------
/* */
-void Configuration::Clear(string Name)
+void Configuration::Clear(string const &Name)
{
Item *Top = Lookup(Name.c_str(),false);
if (Top == 0)
@@ -501,8 +501,8 @@ string Configuration::Item::FullTag(const Item *Stop) const
sections like 'zone "foo.org" { .. };' This causes each section to be
added in with a tag like "zone::foo.org" instead of being split
tag/value. AsSectional enables Sectional parsing.*/
-bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
- unsigned Depth)
+bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectional,
+ unsigned const &Depth)
{
// Open the stream for reading
ifstream F(FName.c_str(),ios::in);
@@ -773,6 +773,8 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
else
return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str());
}
+ else if (Tag.empty() == true && NoWord == false && Word == "#clear")
+ return _error->Error(_("Syntax error %s:%u: clear directive requires an option tree as argument"),FName.c_str(),CurLine);
else
{
// Set the item in the configuration class
@@ -830,7 +832,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
// ---------------------------------------------------------------------
/* */
bool ReadConfigDir(Configuration &Conf,const string &Dir,
- bool AsSectional, unsigned Depth)
+ bool const &AsSectional, unsigned const &Depth)
{
vector<string> const List = GetListOfFilesInDir(Dir, "conf", true, true);
@@ -841,3 +843,46 @@ bool ReadConfigDir(Configuration &Conf,const string &Dir,
return true;
}
/*}}}*/
+// MatchAgainstConfig Constructor /*{{{*/
+Configuration::MatchAgainstConfig::MatchAgainstConfig(char const * Config)
+{
+ std::vector<std::string> const strings = _config->FindVector(Config);
+ for (std::vector<std::string>::const_iterator s = strings.begin();
+ s != strings.end(); ++s)
+ {
+ regex_t *p = new regex_t;
+ if (regcomp(p, s->c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB) == 0)
+ patterns.push_back(p);
+ else
+ {
+ regfree(p);
+ delete p;
+ _error->Warning("Regex compilation error for '%s' in configuration option '%s'",
+ s->c_str(), Config);
+ }
+ }
+
+}
+ /*}}}*/
+// MatchAgainstConfig Destructor /*{{{*/
+Configuration::MatchAgainstConfig::~MatchAgainstConfig()
+{
+ for(std::vector<regex_t *>::const_iterator p = patterns.begin();
+ p != patterns.end(); ++p)
+ {
+ regfree(*p);
+ delete *p;
+ }
+}
+ /*}}}*/
+// MatchAgainstConfig::Match - returns true if a pattern matches /*{{{*/
+bool Configuration::MatchAgainstConfig::Match(char const * str) const
+{
+ for(std::vector<regex_t *>::const_iterator p = patterns.begin();
+ p != patterns.end(); ++p)
+ if (regexec(*p, str, 0, 0, 0) == 0)
+ return true;
+
+ return false;
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h
index e2da83f5b..cbe18e4e5 100644
--- a/apt-pkg/contrib/configuration.h
+++ b/apt-pkg/contrib/configuration.h
@@ -28,7 +28,7 @@
#ifndef PKGLIB_CONFIGURATION_H
#define PKGLIB_CONFIGURATION_H
-
+#include <regex.h>
#include <string>
#include <vector>
@@ -58,8 +58,8 @@ class Configuration
Item *Root;
bool ToFree;
- Item *Lookup(Item *Head,const char *S,unsigned long Len,bool Create);
- Item *Lookup(const char *Name,bool Create);
+ Item *Lookup(Item *Head,const char *S,unsigned long const &Len,bool const &Create);
+ Item *Lookup(const char *Name,const bool &Create);
inline const Item *Lookup(const char *Name) const
{
return ((Configuration *)this)->Lookup(Name,false);
@@ -68,32 +68,33 @@ class Configuration
public:
string Find(const char *Name,const char *Default = 0) const;
- string Find(const string Name,const char *Default = 0) const {return Find(Name.c_str(),Default);};
+ string Find(string const &Name,const char *Default = 0) const {return Find(Name.c_str(),Default);};
+ string Find(string const &Name, string const &Default) const {return Find(Name.c_str(),Default.c_str());};
string FindFile(const char *Name,const char *Default = 0) const;
string FindDir(const char *Name,const char *Default = 0) const;
- std::vector<string> FindVector(const string &Name) const;
+ std::vector<string> FindVector(string const &Name) const;
std::vector<string> FindVector(const char *Name) const;
- int FindI(const char *Name,int Default = 0) const;
- int FindI(const string Name,int Default = 0) const {return FindI(Name.c_str(),Default);};
- bool FindB(const char *Name,bool Default = false) const;
- bool FindB(const string Name,bool Default = false) const {return FindB(Name.c_str(),Default);};
+ int FindI(const char *Name,int const &Default = 0) const;
+ int FindI(string const &Name,int const &Default = 0) const {return FindI(Name.c_str(),Default);};
+ bool FindB(const char *Name,bool const &Default = false) const;
+ bool FindB(string const &Name,bool const &Default = false) const {return FindB(Name.c_str(),Default);};
string FindAny(const char *Name,const char *Default = 0) const;
- inline void Set(const string Name,string Value) {Set(Name.c_str(),Value);};
+ inline void Set(const string &Name,const string &Value) {Set(Name.c_str(),Value);};
void CndSet(const char *Name,const string &Value);
void Set(const char *Name,const string &Value);
- void Set(const char *Name,int Value);
+ void Set(const char *Name,const int &Value);
- inline bool Exists(const string Name) const {return Exists(Name.c_str());};
+ inline bool Exists(const string &Name) const {return Exists(Name.c_str());};
bool Exists(const char *Name) const;
bool ExistsAny(const char *Name) const;
// clear a whole tree
- void Clear(const string Name);
+ void Clear(const string &Name);
// remove a certain value from a list (e.g. the list of "APT::Keep-Fds")
- void Clear(const string List, string Value);
- void Clear(const string List, int Value);
+ void Clear(string const &List, string const &Value);
+ void Clear(string const &List, int const &Value);
inline const Item *Tree(const char *Name) const {return Lookup(Name);};
@@ -103,16 +104,33 @@ class Configuration
Configuration(const Item *Root);
Configuration();
~Configuration();
+
+ /** \brief match a string against a configurable list of patterns */
+ class MatchAgainstConfig
+ {
+ std::vector<regex_t *> patterns;
+
+ public:
+ MatchAgainstConfig(char const * Config);
+ virtual ~MatchAgainstConfig();
+
+ /** \brief Returns \b true for a string matching one of the patterns */
+ bool Match(char const * str) const;
+ bool Match(std::string const &str) const { return Match(str.c_str()); };
+
+ /** \brief returns if the matcher setup was successful */
+ bool wasConstructedSuccessfully() const { return patterns.empty() == false; }
+ };
};
extern Configuration *_config;
bool ReadConfigFile(Configuration &Conf,const string &FName,
- bool AsSectional = false,
- unsigned Depth = 0);
+ bool const &AsSectional = false,
+ unsigned const &Depth = 0);
bool ReadConfigDir(Configuration &Conf,const string &Dir,
- bool AsSectional = false,
- unsigned Depth = 0);
+ bool const &AsSectional = false,
+ unsigned const &Depth = 0);
#endif
diff --git a/apt-pkg/contrib/error.cc b/apt-pkg/contrib/error.cc
index 927b7e05c..e2e8d6e57 100644
--- a/apt-pkg/contrib/error.cc
+++ b/apt-pkg/contrib/error.cc
@@ -1,16 +1,15 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: error.cc,v 1.11 2002/03/26 07:38:58 jgg Exp $
/* ######################################################################
-
- Global Erorr Class - Global error mechanism
+
+ Global Error Class - Global error mechanism
We use a simple STL vector to store each error record. A PendingFlag
is kept which indicates when the vector contains a Sever error.
-
+
This source is placed in the Public Domain, do with it what you will
It was originally written by Jason Gunthorpe.
-
+
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
@@ -19,7 +18,6 @@
#include <iostream>
#include <errno.h>
#include <stdio.h>
-#include <stdarg.h>
#include <unistd.h>
#include <string>
@@ -28,209 +26,233 @@
#include "config.h"
/*}}}*/
-using namespace std;
-
// Global Error Object /*{{{*/
/* If the implementation supports posix threads then the accessor function
is compiled to be thread safe otherwise a non-safe version is used. A
Per-Thread error object is maintained in much the same manner as libc
manages errno */
#if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
- #include <pthread.h>
-
- static pthread_key_t ErrorKey;
- static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
- static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
-
- GlobalError *_GetErrorObj()
- {
- static pthread_once_t Once = PTHREAD_ONCE_INIT;
- pthread_once(&Once,KeyAlloc);
-
- void *Res = pthread_getspecific(ErrorKey);
- if (Res == 0)
- pthread_setspecific(ErrorKey,Res = new GlobalError);
- return (GlobalError *)Res;
- }
+ #include <pthread.h>
+
+ static pthread_key_t ErrorKey;
+ static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
+ static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
+
+ GlobalError *_GetErrorObj() {
+ static pthread_once_t Once = PTHREAD_ONCE_INIT;
+ pthread_once(&Once,KeyAlloc);
+
+ void *Res = pthread_getspecific(ErrorKey);
+ if (Res == 0)
+ pthread_setspecific(ErrorKey,Res = new GlobalError);
+ return (GlobalError *)Res;
+ }
#else
- GlobalError *_GetErrorObj()
- {
- static GlobalError *Obj = new GlobalError;
- return Obj;
- }
+ GlobalError *_GetErrorObj() {
+ static GlobalError *Obj = new GlobalError;
+ return Obj;
+ }
#endif
/*}}}*/
-
// GlobalError::GlobalError - Constructor /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-GlobalError::GlobalError() : List(0), PendingFlag(false)
-{
+GlobalError::GlobalError() : PendingFlag(false) {}
+ /*}}}*/
+// GlobalError::FatalE - Get part of the error string from errno /*{{{*/
+bool GlobalError::FatalE(const char *Function,const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return InsertErrno(FATAL, Function, Description, args);
}
/*}}}*/
// GlobalError::Errno - Get part of the error string from errno /*{{{*/
-// ---------------------------------------------------------------------
-/* Function indicates the stdlib function that failed and Description is
- a user string that leads the text. Form is:
- Description - Function (errno: strerror)
- Carefull of the buffer overrun, sprintf.
- */
-bool GlobalError::Errno(const char *Function,const char *Description,...)
+bool GlobalError::Errno(const char *Function,const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return InsertErrno(ERROR, Function, Description, args);
+}
+ /*}}}*/
+// GlobalError::WarningE - Get part of the warning string from errno /*{{{*/
+bool GlobalError::WarningE(const char *Function,const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return InsertErrno(WARNING, Function, Description, args);
+}
+ /*}}}*/
+// GlobalError::NoticeE - Get part of the notice string from errno /*{{{*/
+bool GlobalError::NoticeE(const char *Function,const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return InsertErrno(NOTICE, Function, Description, args);
+}
+ /*}}}*/
+// GlobalError::DebugE - Get part of the debug string from errno /*{{{*/
+bool GlobalError::DebugE(const char *Function,const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return InsertErrno(DEBUG, Function, Description, args);
+}
+ /*}}}*/
+// GlobalError::InsertErrno - Get part of the errortype string from errno/*{{{*/
+bool GlobalError::InsertErrno(MsgType const &type, const char *Function,
+ const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return InsertErrno(type, Function, Description, args);
+}
+ /*}}}*/
+// GlobalError::InsertErrno - formats an error message with the errno /*{{{*/
+bool GlobalError::InsertErrno(MsgType type, const char* Function,
+ const char* Description, va_list &args) {
+ char S[400];
+ snprintf(S, sizeof(S), "%s - %s (%i: %s)", Description,
+ Function, errno, strerror(errno));
+ return Insert(type, S, args);
+}
+ /*}}}*/
+// GlobalError::Fatal - Add a fatal error to the list /*{{{*/
+bool GlobalError::Fatal(const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return Insert(FATAL, Description, args);
+}
+ /*}}}*/
+// GlobalError::Error - Add an error to the list /*{{{*/
+bool GlobalError::Error(const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return Insert(ERROR, Description, args);
+}
+ /*}}}*/
+// GlobalError::Warning - Add a warning to the list /*{{{*/
+bool GlobalError::Warning(const char *Description,...) {
+ va_list args;
+ va_start(args,Description);
+ return Insert(WARNING, Description, args);
+}
+ /*}}}*/
+// GlobalError::Notice - Add a notice to the list /*{{{*/
+bool GlobalError::Notice(const char *Description,...)
+{
+ va_list args;
+ va_start(args,Description);
+ return Insert(NOTICE, Description, args);
+}
+ /*}}}*/
+// GlobalError::Debug - Add a debug to the list /*{{{*/
+bool GlobalError::Debug(const char *Description,...)
{
- va_list args;
- va_start(args,Description);
-
- // sprintf the description
- char S[400];
- vsnprintf(S,sizeof(S),Description,args);
- snprintf(S + strlen(S),sizeof(S) - strlen(S),
- " - %s (%i: %s)",Function,errno,strerror(errno));
-
- // Put it on the list
- Item *Itm = new Item;
- Itm->Text = S;
- Itm->Error = true;
- Insert(Itm);
-
- PendingFlag = true;
-
- return false;
-}
- /*}}}*/
-// GlobalError::WarningE - Get part of the warn string from errno /*{{{*/
-// ---------------------------------------------------------------------
-/* Function indicates the stdlib function that failed and Description is
- a user string that leads the text. Form is:
- Description - Function (errno: strerror)
- Carefull of the buffer overrun, sprintf.
- */
-bool GlobalError::WarningE(const char *Function,const char *Description,...)
+ va_list args;
+ va_start(args,Description);
+ return Insert(DEBUG, Description, args);
+}
+ /*}}}*/
+// GlobalError::Insert - Add a errotype message to the list /*{{{*/
+bool GlobalError::Insert(MsgType const &type, const char *Description,...)
{
- va_list args;
- va_start(args,Description);
+ va_list args;
+ va_start(args,Description);
+ return Insert(type, Description, args);
+}
+ /*}}}*/
+// GlobalError::Insert - Insert a new item at the end /*{{{*/
+bool GlobalError::Insert(MsgType type, const char* Description,
+ va_list &args) {
+ char S[400];
+ vsnprintf(S,sizeof(S),Description,args);
+
+ Item const m(S, type);
+ Messages.push_back(m);
- // sprintf the description
- char S[400];
- vsnprintf(S,sizeof(S),Description,args);
- snprintf(S + strlen(S),sizeof(S) - strlen(S),
- " - %s (%i: %s)",Function,errno,strerror(errno));
+ if (type == ERROR || type == FATAL)
+ PendingFlag = true;
- // Put it on the list
- Item *Itm = new Item;
- Itm->Text = S;
- Itm->Error = false;
- Insert(Itm);
+ if (type == FATAL || type == DEBUG)
+ std::clog << m << std::endl;
- return false;
+ return false;
}
/*}}}*/
-// GlobalError::Error - Add an error to the list /*{{{*/
-// ---------------------------------------------------------------------
-/* Just vsprintfs and pushes */
-bool GlobalError::Error(const char *Description,...)
-{
- va_list args;
- va_start(args,Description);
+// GlobalError::PopMessage - Pulls a single message out /*{{{*/
+bool GlobalError::PopMessage(std::string &Text) {
+ if (Messages.empty() == true)
+ return false;
+
+ Item const msg = Messages.front();
+ Messages.pop_front();
- // sprintf the description
- char S[400];
- vsnprintf(S,sizeof(S),Description,args);
+ bool const Ret = (msg.Type == ERROR || msg.Type == FATAL);
+ Text = msg.Text;
+ if (PendingFlag == false || Ret == false)
+ return Ret;
- // Put it on the list
- Item *Itm = new Item;
- Itm->Text = S;
- Itm->Error = true;
- Insert(Itm);
-
- PendingFlag = true;
-
- return false;
+ // check if another error message is pending
+ for (std::list<Item>::const_iterator m = Messages.begin();
+ m != Messages.end(); m++)
+ if (m->Type == ERROR || m->Type == FATAL)
+ return Ret;
+
+ PendingFlag = false;
+ return Ret;
}
/*}}}*/
-// GlobalError::Warning - Add a warning to the list /*{{{*/
-// ---------------------------------------------------------------------
-/* This doesn't set the pending error flag */
-bool GlobalError::Warning(const char *Description,...)
-{
- va_list args;
- va_start(args,Description);
+// GlobalError::DumpErrors - Dump all of the errors/warns to cerr /*{{{*/
+void GlobalError::DumpErrors(std::ostream &out, MsgType const &threshold,
+ bool const &mergeStack) {
+ if (mergeStack == true)
+ for (std::list<MsgStack>::const_reverse_iterator s = Stacks.rbegin();
+ s != Stacks.rend(); ++s)
+ Messages.insert(Messages.begin(), s->Messages.begin(), s->Messages.end());
- // sprintf the description
- char S[400];
- vsnprintf(S,sizeof(S),Description,args);
+ for (std::list<Item>::const_iterator m = Messages.begin();
+ m != Messages.end(); m++)
+ if (m->Type >= threshold)
+ out << (*m) << std::endl;
+ Discard();
+}
+ /*}}}*/
+// GlobalError::Discard - Discard /*{{{*/
+void GlobalError::Discard() {
+ Messages.clear();
+ PendingFlag = false;
+};
+ /*}}}*/
+// GlobalError::empty - does our error list include anything? /*{{{*/
+bool GlobalError::empty(MsgType const &trashhold) const {
+ if (PendingFlag == true)
+ return false;
- // Put it on the list
- Item *Itm = new Item;
- Itm->Text = S;
- Itm->Error = false;
- Insert(Itm);
-
- return false;
+ if (Messages.empty() == true)
+ return true;
+
+ for (std::list<Item>::const_iterator m = Messages.begin();
+ m != Messages.end(); m++)
+ if (m->Type >= trashhold)
+ return false;
+
+ return true;
}
/*}}}*/
-// GlobalError::PopMessage - Pulls a single message out /*{{{*/
-// ---------------------------------------------------------------------
-/* This should be used in a loop checking empty() each cycle. It returns
- true if the message is an error. */
-bool GlobalError::PopMessage(string &Text)
-{
- if (List == 0)
- return false;
-
- bool Ret = List->Error;
- Text = List->Text;
- Item *Old = List;
- List = List->Next;
- delete Old;
-
- // This really should check the list to see if only warnings are left..
- if (List == 0)
- PendingFlag = false;
-
- return Ret;
+// GlobalError::PushToStack /*{{{*/
+void GlobalError::PushToStack() {
+ MsgStack pack(Messages, PendingFlag);
+ Stacks.push_back(pack);
+ Discard();
}
/*}}}*/
-// GlobalError::DumpErrors - Dump all of the errors/warns to cerr /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::DumpErrors()
-{
- // Print any errors or warnings found
- string Err;
- while (empty() == false)
- {
- bool Type = PopMessage(Err);
- if (Type == true)
- cerr << "E: " << Err << endl;
- else
- cerr << "W: " << Err << endl;
- }
-}
- /*}}}*/
-// GlobalError::Discard - Discard /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::Discard()
-{
- while (List != 0)
- {
- Item *Old = List;
- List = List->Next;
- delete Old;
- }
-
- PendingFlag = false;
-};
+// GlobalError::RevertToStack /*{{{*/
+void GlobalError::RevertToStack() {
+ Discard();
+ MsgStack pack = Stacks.back();
+ Messages = pack.Messages;
+ PendingFlag = pack.PendingFlag;
+ Stacks.pop_back();
+}
/*}}}*/
-// GlobalError::Insert - Insert a new item at the end /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::Insert(Item *Itm)
-{
- Item **End = &List;
- for (Item *I = List; I != 0; I = I->Next)
- End = &I->Next;
- Itm->Next = *End;
- *End = Itm;
+// GlobalError::MergeWithStack /*{{{*/
+void GlobalError::MergeWithStack() {
+ MsgStack pack = Stacks.back();
+ Messages.insert(Messages.begin(), pack.Messages.begin(), pack.Messages.end());
+ PendingFlag = PendingFlag || pack.PendingFlag;
+ Stacks.pop_back();
}
/*}}}*/
diff --git a/apt-pkg/contrib/error.h b/apt-pkg/contrib/error.h
index 90747ff7e..ae756dbc4 100644
--- a/apt-pkg/contrib/error.h
+++ b/apt-pkg/contrib/error.h
@@ -42,43 +42,277 @@
#include <apt-pkg/macros.h>
+#include <iostream>
+#include <list>
#include <string>
-class GlobalError
+#include <stdarg.h>
+
+class GlobalError /*{{{*/
{
- struct Item
- {
- std::string Text;
- bool Error;
- Item *Next;
- };
-
- Item *List;
- bool PendingFlag;
- void Insert(Item *I);
-
- public:
+public: /*{{{*/
+ /** \brief a message can have one of following severity */
+ enum MsgType {
+ /** \brief Message will be printed instantly as it is likely that
+ this error will lead to a complete crash */
+ FATAL = 40,
+ /** \brief An error does hinder the correct execution and should be corrected */
+ ERROR = 30,
+ /** \brief indicates problem that can lead to errors later on */
+ WARNING = 20,
+ /** \brief deprecation warnings, old fallback behavior, … */
+ NOTICE = 10,
+ /** \brief for developers only in areas it is hard to print something directly */
+ DEBUG = 0
+ };
- // Call to generate an error from a library call.
- bool Errno(const char *Function,const char *Description,...) __like_printf_2 __cold;
- bool WarningE(const char *Function,const char *Description,...) __like_printf_2 __cold;
+ /** \brief add a fatal error message with errno to the list
+ *
+ * \param Function name of the function generating the error
+ * \param Description format string for the error message
+ *
+ * \return \b false
+ */
+ bool FatalE(const char *Function,const char *Description,...) __like_printf(3) __cold;
- /* A warning should be considered less severe than an error, and may be
- ignored by the client. */
- bool Error(const char *Description,...) __like_printf_1 __cold;
- bool Warning(const char *Description,...) __like_printf_1 __cold;
+ /** \brief add an Error message with errno to the list
+ *
+ * \param Function name of the function generating the error
+ * \param Description format string for the error message
+ *
+ * \return \b false
+ */
+ bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold;
- // Simple accessors
- inline bool PendingError() {return PendingFlag;};
- inline bool empty() {return List == 0;};
- bool PopMessage(std::string &Text);
- void Discard();
+ /** \brief add a warning message with errno to the list
+ *
+ * A warning should be considered less severe than an error and
+ * may be ignored by the client.
+ *
+ * \param Function Name of the function generates the warning.
+ * \param Description Format string for the warning message.
+ *
+ * \return \b false
+ */
+ bool WarningE(const char *Function,const char *Description,...) __like_printf(3) __cold;
- // Usefull routine to dump to cerr
- void DumpErrors();
-
- GlobalError();
+ /** \brief add a notice message with errno to the list
+ *
+ * \param Function name of the function generating the error
+ * \param Description format string for the error message
+ *
+ * \return \b false
+ */
+ bool NoticeE(const char *Function,const char *Description,...) __like_printf(3) __cold;
+
+ /** \brief add a debug message with errno to the list
+ *
+ * \param Function name of the function generating the error
+ * \param Description format string for the error message
+ *
+ * \return \b false
+ */
+ bool DebugE(const char *Function,const char *Description,...) __like_printf(3) __cold;
+
+ /** \brief adds an errno message with the given type
+ *
+ * \param type of the error message
+ * \param Function which failed
+ * \param Description of the error
+ */
+ bool InsertErrno(MsgType const &type, const char* Function,
+ const char* Description,...) __like_printf(4) __cold;
+
+ /** \brief add an fatal error message to the list
+ *
+ * Most of the stuff we consider as "error" is also "fatal" for
+ * the user as the application will not have the expected result,
+ * but a fatal message here means that it gets printed directly
+ * to stderr in addiction to adding it to the list as the error
+ * leads sometimes to crashes and a maybe duplicated message
+ * is better than "Segfault" as the only displayed text
+ *
+ * \param Description Format string for the fatal error message.
+ *
+ * \return \b false
+ */
+ bool Fatal(const char *Description,...) __like_printf(2) __cold;
+
+ /** \brief add an Error message to the list
+ *
+ * \param Description Format string for the error message.
+ *
+ * \return \b false
+ */
+ bool Error(const char *Description,...) __like_printf(2) __cold;
+
+ /** \brief add a warning message to the list
+ *
+ * A warning should be considered less severe than an error and
+ * may be ignored by the client.
+ *
+ * \param Description Format string for the message
+ *
+ * \return \b false
+ */
+ bool Warning(const char *Description,...) __like_printf(2) __cold;
+
+ /** \brief add a notice message to the list
+ *
+ * A notice should be considered less severe than an error or a
+ * warning and can be ignored by the client without further problems
+ * for some times, but he should consider fixing the problem.
+ * This error type can be used for e.g. deprecation warnings of options.
+ *
+ * \param Description Format string for the message
+ *
+ * \return \b false
+ */
+ bool Notice(const char *Description,...) __like_printf(2) __cold;
+
+ /** \brief add a debug message to the list
+ *
+ * \param Description Format string for the message
+ *
+ * \return \b false
+ */
+ bool Debug(const char *Description,...) __like_printf(2) __cold;
+
+ /** \brief adds an error message with the given type
+ *
+ * \param type of the error message
+ * \param Description of the error
+ */
+ bool Insert(MsgType const &type, const char* Description,...) __like_printf(3) __cold;
+
+ /** \brief is an error in the list?
+ *
+ * \return \b true if an error is included in the list, \b false otherwise
+ */
+ inline bool PendingError() const {return PendingFlag;};
+
+ /** \brief is the list empty?
+ *
+ * The default checks if the list is empty or contains only notices,
+ * if you want to check if also no notices happend set the parameter
+ * flag to \b false.
+ *
+ * \param WithoutNotice does notices count, default is \b true, so no
+ *
+ * \return \b true if an the list is empty, \b false otherwise
+ */
+ bool empty(MsgType const &trashhold = WARNING) const;
+
+ /** \brief returns and removes the first (or last) message in the list
+ *
+ * \param[out] Text message of the first/last item
+ *
+ * \return \b true if the message was an error, \b false otherwise
+ */
+ bool PopMessage(std::string &Text);
+
+ /** \brief clears the list of messages */
+ void Discard();
+
+ /** \brief outputs the list of messages to the given stream
+ *
+ * Note that all messages are discarded, also the notices
+ * displayed or not.
+ *
+ * \param[out] out output stream to write the messages in
+ * \param threshold minimim level considered
+ * \param mergeStack
+ */
+ void DumpErrors(std::ostream &out, MsgType const &threshold = WARNING,
+ bool const &mergeStack = true);
+
+ /** \brief dumps the list of messages to std::cerr
+ *
+ * Note that all messages are discarded, also the notices
+ * displayed or not.
+ *
+ * \param threshold minimum level printed
+ */
+ void inline DumpErrors(MsgType const &threshold) {
+ DumpErrors(std::cerr, threshold);
+ }
+
+ // mvo: we do this instead of using a default parameter in the
+ // previous declaration to avoid a (subtle) API break for
+ // e.g. sigc++ and mem_fun0
+ /** \brief dumps the messages of type WARNING or higher to std::cerr
+ *
+ * Note that all messages are discarded, displayed or not.
+ *
+ */
+ void inline DumpErrors() {
+ DumpErrors(WARNING);
+ }
+
+ /** \brief put the current Messages into the stack
+ *
+ * All "old" messages will be pushed into a stack to
+ * them later back, but for now the Message query will be
+ * empty and performs as no messages were present before.
+ *
+ * The stack can be as deep as you want - all stack operations
+ * will only operate on the last element in the stack.
+ */
+ void PushToStack();
+
+ /** \brief throw away all current messages */
+ void RevertToStack();
+
+ /** \brief merge current and stack together */
+ void MergeWithStack();
+
+ /** \brief return the deep of the stack */
+ size_t StackCount() const {
+ return Stacks.size();
+ }
+
+ GlobalError();
+ /*}}}*/
+private: /*{{{*/
+ struct Item {
+ std::string Text;
+ MsgType Type;
+
+ Item(char const *Text, MsgType const &Type) :
+ Text(Text), Type(Type) {};
+
+ friend std::ostream& operator<< (std::ostream &out, Item i) {
+ switch(i.Type) {
+ case FATAL:
+ case ERROR: out << "E"; break;
+ case WARNING: out << "W"; break;
+ case NOTICE: out << "N"; break;
+ case DEBUG: out << "D"; break;
+ }
+ return out << ": " << i.Text;
+ }
+ };
+
+ std::list<Item> Messages;
+ bool PendingFlag;
+
+ struct MsgStack {
+ std::list<Item> const Messages;
+ bool const PendingFlag;
+
+ MsgStack(std::list<Item> const &Messages, bool const &Pending) :
+ Messages(Messages), PendingFlag(Pending) {};
+ };
+
+ std::list<MsgStack> Stacks;
+
+ bool InsertErrno(MsgType type, const char* Function,
+ const char* Description, va_list &args);
+ bool Insert(MsgType type, const char* Description,
+ va_list &args);
+ /*}}}*/
};
+ /*}}}*/
// The 'extra-ansi' syntax is used to help with collisions.
GlobalError *_GetErrorObj();
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index da32983f1..2a3b8a87d 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/apt-pkg/contrib/fileutl.cc
@@ -11,6 +11,7 @@
Most of this source is placed in the Public Domain, do with it what
you will
It was originally written by Jason Gunthorpe <jgg@debian.org>.
+ FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com>
The exception is RunScripts() it is under the GPLv2
@@ -18,6 +19,7 @@
/*}}}*/
// Include Files /*{{{*/
#include <apt-pkg/fileutl.h>
+#include <apt-pkg/strutl.h>
#include <apt-pkg/error.h>
#include <apt-pkg/sptr.h>
#include <apt-pkg/configuration.h>
@@ -26,6 +28,7 @@
#include <cstdlib>
#include <cstring>
+#include <cstdio>
#include <iostream>
#include <unistd.h>
@@ -197,16 +200,62 @@ bool FileExists(string File)
return true;
}
/*}}}*/
+// DirectoryExists - Check if a directory exists and is really one /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool DirectoryExists(string const &Path)
+{
+ struct stat Buf;
+ if (stat(Path.c_str(),&Buf) != 0)
+ return false;
+ return ((Buf.st_mode & S_IFDIR) != 0);
+}
+ /*}}}*/
+// CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
+// ---------------------------------------------------------------------
+/* This method will create all directories needed for path in good old
+ mkdir -p style but refuses to do this if Parent is not a prefix of
+ this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
+ so it will create apt/archives if /var/cache exists - on the other
+ hand if the parent is /var/lib the creation will fail as this path
+ is not a parent of the path to be generated. */
+bool CreateDirectory(string const &Parent, string const &Path)
+{
+ if (Parent.empty() == true || Path.empty() == true)
+ return false;
+
+ if (DirectoryExists(Path) == true)
+ return true;
+
+ if (DirectoryExists(Parent) == false)
+ return false;
+
+ // we are not going to create directories "into the blue"
+ if (Path.find(Parent, 0) != 0)
+ return false;
+
+ vector<string> const dirs = VectorizeString(Path.substr(Parent.size()), '/');
+ string progress = Parent;
+ for (vector<string>::const_iterator d = dirs.begin(); d != dirs.end(); ++d)
+ {
+ if (d->empty() == true)
+ continue;
+
+ progress.append("/").append(*d);
+ if (DirectoryExists(progress) == true)
+ continue;
+
+ if (mkdir(progress.c_str(), 0755) != 0)
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
// GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
// ---------------------------------------------------------------------
/* If an extension is given only files with this extension are included
in the returned vector, otherwise every "normal" file is included. */
std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
- bool const &SortList)
-{
- return GetListOfFilesInDir(Dir, Ext, SortList, false);
-}
-std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
bool const &SortList, bool const &AllowNoExt)
{
std::vector<string> ext;
@@ -234,6 +283,7 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
}
std::vector<string> List;
+ Configuration::MatchAgainstConfig SilentIgnore("Dir::Ignore-Files-Silently");
DIR *D = opendir(Dir.c_str());
if (D == 0)
{
@@ -259,6 +309,7 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
{
if (Debug == true)
std::clog << "Bad file: " << Ent->d_name << " → no extension" << std::endl;
+ _error->Notice("Ignoring file '%s' in directory '%s' as it has no filename extension", Ent->d_name, Dir.c_str());
continue;
}
}
@@ -266,6 +317,8 @@ std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> c
{
if (Debug == true)
std::clog << "Bad file: " << Ent->d_name << " → bad extension »" << flExtension(Ent->d_name) << "«" << std::endl;
+ if (SilentIgnore.Match(Ent->d_name) == false)
+ _error->Notice("Ignoring file '%s' in directory '%s' as it has an invalid filename extension", Ent->d_name, Dir.c_str());
continue;
}
}
@@ -604,13 +657,25 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
case ReadOnly:
iFd = open(FileName.c_str(),O_RDONLY);
break;
+
+ case ReadOnlyGzip:
+ iFd = open(FileName.c_str(),O_RDONLY);
+ if (iFd > 0) {
+ gz = gzdopen (iFd, "r");
+ if (gz == NULL) {
+ close (iFd);
+ iFd = -1;
+ }
+ }
+ break;
case WriteEmpty:
{
- struct stat Buf;
- if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
- unlink(FileName.c_str());
- iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
+ Flags |= Replace;
+ char *name = strdup((FileName + ".XXXXXX").c_str());
+ TemporaryFileName = string(mktemp(name));
+ iFd = open(TemporaryFileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
+ free(name);
break;
}
@@ -635,6 +700,24 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
SetCloseExec(iFd,true);
return true;
}
+
+bool FileFd::OpenDescriptor(int Fd, OpenMode Mode, bool AutoClose)
+{
+ Close();
+ Flags = (AutoClose) ? FileFd::AutoClose : 0;
+ iFd = Fd;
+ if (Mode == ReadOnlyGzip) {
+ gz = gzdopen (iFd, "r");
+ if (gz == NULL) {
+ if (AutoClose)
+ close (iFd);
+ return _error->Errno("gzdopen",_("Could not open file descriptor %d"),
+ Fd);
+ }
+ }
+ this->FileName = "";
+ return true;
+}
/*}}}*/
// FileFd::~File - Closes the file /*{{{*/
// ---------------------------------------------------------------------
@@ -658,7 +741,10 @@ bool FileFd::Read(void *To,unsigned long Size,unsigned long *Actual)
do
{
- Res = read(iFd,To,Size);
+ if (gz != NULL)
+ Res = gzread(gz,To,Size);
+ else
+ Res = read(iFd,To,Size);
if (Res < 0 && errno == EINTR)
continue;
if (Res < 0)
@@ -697,7 +783,10 @@ bool FileFd::Write(const void *From,unsigned long Size)
errno = 0;
do
{
- Res = write(iFd,From,Size);
+ if (gz != NULL)
+ Res = gzwrite(gz,From,Size);
+ else
+ Res = write(iFd,From,Size);
if (Res < 0 && errno == EINTR)
continue;
if (Res < 0)
@@ -723,7 +812,12 @@ bool FileFd::Write(const void *From,unsigned long Size)
/* */
bool FileFd::Seek(unsigned long To)
{
- if (lseek(iFd,To,SEEK_SET) != (signed)To)
+ int res;
+ if (gz)
+ res = gzseek(gz,To,SEEK_SET);
+ else
+ res = lseek(iFd,To,SEEK_SET);
+ if (res != (signed)To)
{
Flags |= Fail;
return _error->Error("Unable to seek to %lu",To);
@@ -737,7 +831,12 @@ bool FileFd::Seek(unsigned long To)
/* */
bool FileFd::Skip(unsigned long Over)
{
- if (lseek(iFd,Over,SEEK_CUR) < 0)
+ int res;
+ if (gz)
+ res = gzseek(gz,Over,SEEK_CUR);
+ else
+ res = lseek(iFd,Over,SEEK_CUR);
+ if (res < 0)
{
Flags |= Fail;
return _error->Error("Unable to seek ahead %lu",Over);
@@ -751,6 +850,11 @@ bool FileFd::Skip(unsigned long Over)
/* */
bool FileFd::Truncate(unsigned long To)
{
+ if (gz)
+ {
+ Flags |= Fail;
+ return _error->Error("Truncating gzipped files is not implemented (%s)", FileName.c_str());
+ }
if (ftruncate(iFd,To) != 0)
{
Flags |= Fail;
@@ -765,7 +869,11 @@ bool FileFd::Truncate(unsigned long To)
/* */
unsigned long FileFd::Tell()
{
- off_t Res = lseek(iFd,0,SEEK_CUR);
+ off_t Res;
+ if (gz)
+ Res = gztell(gz);
+ else
+ Res = lseek(iFd,0,SEEK_CUR);
if (Res == (off_t)-1)
_error->Errno("lseek","Failed to determine the current file position");
return Res;
@@ -776,6 +884,7 @@ unsigned long FileFd::Tell()
/* */
unsigned long FileFd::Size()
{
+ //TODO: For gz, do we need the actual file size here or the uncompressed length?
struct stat Buf;
if (fstat(iFd,&Buf) != 0)
return _error->Errno("fstat","Unable to determine the file size");
@@ -789,14 +898,33 @@ bool FileFd::Close()
{
bool Res = true;
if ((Flags & AutoClose) == AutoClose)
- if (iFd >= 0 && close(iFd) != 0)
- Res &= _error->Errno("close",_("Problem closing the file"));
+ {
+ if (gz != NULL) {
+ int const e = gzclose(gz);
+ // gzdopen() on empty files always fails with "buffer error" here, ignore that
+ if (e != 0 && e != Z_BUF_ERROR)
+ Res &= _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str());
+ } else
+ if (iFd > 0 && close(iFd) != 0)
+ Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str());
+ }
+
+ if ((Flags & Replace) == Replace && iFd >= 0) {
+ if (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.
+ }
+
iFd = -1;
-
+ gz = NULL;
+
if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
FileName.empty() == false)
if (unlink(FileName.c_str()) != 0)
- Res &= _error->WarningE("unlnk",_("Problem unlinking the file"));
+ Res &= _error->WarningE("unlnk",_("Problem unlinking the file %s"), FileName.c_str());
+
+
return Res;
}
/*}}}*/
diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h
index 85a94898c..62705478d 100644
--- a/apt-pkg/contrib/fileutl.h
+++ b/apt-pkg/contrib/fileutl.h
@@ -21,10 +21,16 @@
#ifndef PKGLIB_FILEUTL_H
#define PKGLIB_FILEUTL_H
+#include <apt-pkg/macros.h>
#include <string>
#include <vector>
+#include <zlib.h>
+
+/* Define this for python-apt */
+#define APT_HAS_GZIP 1
+
using std::string;
class FileFd
@@ -33,12 +39,14 @@ class FileFd
int iFd;
enum LocalFlags {AutoClose = (1<<0),Fail = (1<<1),DelOnFail = (1<<2),
- HitEof = (1<<3)};
+ HitEof = (1<<3), Replace = (1<<4) };
unsigned long Flags;
string FileName;
-
+ string TemporaryFileName;
+ gzFile gz;
+
public:
- enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,WriteTemp};
+ enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,WriteTemp,ReadOnlyGzip};
inline bool Read(void *To,unsigned long Size,bool AllowEof)
{
@@ -55,6 +63,7 @@ class FileFd
unsigned long Tell();
unsigned long Size();
bool Open(string FileName,OpenMode Mode,unsigned long Perms = 0666);
+ bool OpenDescriptor(int Fd, OpenMode Mode, bool AutoClose=false);
bool Close();
bool Sync();
@@ -69,12 +78,12 @@ class FileFd
inline string &Name() {return FileName;};
FileFd(string FileName,OpenMode Mode,unsigned long Perms = 0666) : iFd(-1),
- Flags(0)
+ Flags(0), gz(NULL)
{
Open(FileName,Mode,Perms);
};
- FileFd(int Fd = -1) : iFd(Fd), Flags(AutoClose) {};
- FileFd(int Fd,bool) : iFd(Fd), Flags(0) {};
+ FileFd(int Fd = -1) : iFd(Fd), Flags(AutoClose), gz(NULL) {};
+ FileFd(int Fd,bool) : iFd(Fd), Flags(0), gz(NULL) {};
virtual ~FileFd();
};
@@ -82,11 +91,10 @@ bool RunScripts(const char *Cnf);
bool CopyFile(FileFd &From,FileFd &To);
int GetLock(string File,bool Errors = true);
bool FileExists(string File);
-// FIXME: next ABI-Break: merge the two method-headers
-std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
- bool const &SortList);
+bool DirectoryExists(string const &Path) __attrib_const;
+bool CreateDirectory(string const &Parent, string const &Path);
std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
- bool const &SortList, bool const &AllowNoExt);
+ bool const &SortList, bool const &AllowNoExt=false);
std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> const &Ext,
bool const &SortList);
string SafeGetCWD();
diff --git a/apt-pkg/contrib/macros.h b/apt-pkg/contrib/macros.h
index 9aeb77b81..62e7b65db 100644
--- a/apt-pkg/contrib/macros.h
+++ b/apt-pkg/contrib/macros.h
@@ -56,33 +56,35 @@
// some nice optional GNUC features
#if __GNUC__ >= 3
- #define __must_check __attribute__ ((warn_unused_result))
- #define __deprecated __attribute__ ((deprecated))
- /* likely() and unlikely() can be used to mark boolean expressions
- as (not) likely true which will help the compiler to optimise */
- #define likely(x) __builtin_expect (!!(x), 1)
- #define unlikely(x) __builtin_expect (!!(x), 0)
+ #define __must_check __attribute__ ((warn_unused_result))
+ #define __deprecated __attribute__ ((deprecated))
+ #define __attrib_const __attribute__ ((__const__))
+ /* likely() and unlikely() can be used to mark boolean expressions
+ as (not) likely true which will help the compiler to optimise */
+ #define likely(x) __builtin_expect (!!(x), 1)
+ #define unlikely(x) __builtin_expect (!!(x), 0)
#else
- #define __must_check /* no warn_unused_result */
- #define __deprecated /* no deprecated */
- #define likely(x) (x)
- #define unlikely(x) (x)
+ #define __must_check /* no warn_unused_result */
+ #define __deprecated /* no deprecated */
+ #define __attrib_const /* no const attribute */
+ #define likely(x) (x)
+ #define unlikely(x) (x)
#endif
// cold functions are unlikely() to be called
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
- #define __cold __attribute__ ((__cold__))
+ #define __cold __attribute__ ((__cold__))
+ #define __hot __attribute__ ((__hot__))
#else
- #define __cold /* no cold marker */
+ #define __cold /* no cold marker */
+ #define __hot /* no hot marker */
#endif
#ifdef __GNUG__
// Methods have a hidden this parameter that is visible to this attribute
- #define __like_printf_1 __attribute__ ((format (printf, 2, 3)))
- #define __like_printf_2 __attribute__ ((format (printf, 3, 4)))
+ #define __like_printf(n) __attribute__((format(printf, n, n + 1)))
#else
- #define __like_printf_1
- #define __like_printf_2
+ #define __like_printf(n) /* no like-printf */
#endif
#endif
diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc
index 4d5fcf71e..69fb61fca 100644
--- a/apt-pkg/contrib/mmap.cc
+++ b/apt-pkg/contrib/mmap.cc
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
+#include <errno.h>
#include <cstring>
/*}}}*/
@@ -35,7 +36,7 @@
// ---------------------------------------------------------------------
/* */
MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
- Base(0)
+ Base(0), SyncToFd(NULL)
{
if ((Flags & NoImmMap) != NoImmMap)
Map(F);
@@ -45,7 +46,7 @@ MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
// ---------------------------------------------------------------------
/* */
MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
- Base(0)
+ Base(0), SyncToFd(NULL)
{
}
/*}}}*/
@@ -78,7 +79,24 @@ bool MMap::Map(FileFd &Fd)
// Map it.
Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
if (Base == (void *)-1)
- return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize);
+ {
+ if (errno == ENODEV || errno == EINVAL)
+ {
+ // The filesystem doesn't support this particular kind of mmap.
+ // So we allocate a buffer and read the whole file into it.
+ int const dupped_fd = dup(Fd.Fd());
+ if (dupped_fd == -1)
+ return _error->Errno("mmap", _("Couldn't duplicate file descriptor %i"), Fd.Fd());
+
+ Base = new unsigned char[iSize];
+ SyncToFd = new FileFd (dupped_fd);
+ if (!SyncToFd->Seek(0L) || !SyncToFd->Read(Base, iSize))
+ return false;
+ }
+ else
+ return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),
+ iSize);
+ }
return true;
}
@@ -93,10 +111,19 @@ bool MMap::Close(bool DoSync)
if (DoSync == true)
Sync();
-
- if (munmap((char *)Base,iSize) != 0)
- _error->Warning("Unable to munmap");
-
+
+ if (SyncToFd != NULL)
+ {
+ delete[] (char *)Base;
+ delete SyncToFd;
+ SyncToFd = NULL;
+ }
+ else
+ {
+ if (munmap((char *)Base, iSize) != 0)
+ _error->WarningE("mmap", _("Unable to close mmap"));
+ }
+
iSize = 0;
Base = 0;
return true;
@@ -113,8 +140,18 @@ bool MMap::Sync()
#ifdef _POSIX_SYNCHRONIZED_IO
if ((Flags & ReadOnly) != ReadOnly)
- if (msync((char *)Base,iSize,MS_SYNC) < 0)
- return _error->Errno("msync","Unable to write mmap");
+ {
+ if (SyncToFd != NULL)
+ {
+ if (!SyncToFd->Seek(0) || !SyncToFd->Write(Base, iSize))
+ return false;
+ }
+ else
+ {
+ if (msync((char *)Base, iSize, MS_SYNC) < 0)
+ return _error->Errno("msync", _("Unable to synchronize mmap"));
+ }
+ }
#endif
return true;
}
@@ -130,8 +167,19 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop)
#ifdef _POSIX_SYNCHRONIZED_IO
unsigned long PSize = sysconf(_SC_PAGESIZE);
if ((Flags & ReadOnly) != ReadOnly)
- if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
- return _error->Errno("msync","Unable to write mmap");
+ {
+ if (SyncToFd != 0)
+ {
+ if (!SyncToFd->Seek(0) ||
+ !SyncToFd->Write (((char *)Base)+Start, Stop-Start))
+ return false;
+ }
+ else
+ {
+ if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
+ return _error->Errno("msync", _("Unable to synchronize mmap"));
+ }
+ }
#endif
return true;
}
@@ -140,8 +188,10 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop)
// DynamicMMap::DynamicMMap - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) :
- MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(WorkSpace)
+DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long const &Workspace,
+ unsigned long const &Grow, unsigned long const &Limit) :
+ MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(Workspace),
+ GrowFactor(Grow), Limit(Limit)
{
if (_error->PendingError() == true)
return;
@@ -165,32 +215,48 @@ DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace)
/* We try here to use mmap to reserve some space - this is much more
cooler than the fallback solution to simply allocate a char array
and could come in handy later than we are able to grow such an mmap */
-DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long WorkSpace) :
- MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace)
+DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace,
+ unsigned long const &Grow, unsigned long const &Limit) :
+ MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace),
+ GrowFactor(Grow), Limit(Limit)
{
- if (_error->PendingError() == true)
- return;
+ if (_error->PendingError() == true)
+ return;
+
+ // disable Moveable if we don't grow
+ if (Grow == 0)
+ this->Flags &= ~Moveable;
+
+#ifndef __linux__
+ // kfreebsd doesn't have mremap, so we use the fallback
+ if ((this->Flags & Moveable) == Moveable)
+ this->Flags |= Fallback;
+#endif
#ifdef _POSIX_MAPPED_FILES
- // Set the permissions.
- int Prot = PROT_READ;
- int Map = MAP_PRIVATE | MAP_ANONYMOUS;
- if ((Flags & ReadOnly) != ReadOnly)
- Prot |= PROT_WRITE;
- if ((Flags & Public) == Public)
- Map = MAP_SHARED | MAP_ANONYMOUS;
+ if ((this->Flags & Fallback) != Fallback) {
+ // Set the permissions.
+ int Prot = PROT_READ;
+ int Map = MAP_PRIVATE | MAP_ANONYMOUS;
+ if ((this->Flags & ReadOnly) != ReadOnly)
+ Prot |= PROT_WRITE;
+ if ((this->Flags & Public) == Public)
+ Map = MAP_SHARED | MAP_ANONYMOUS;
- // use anonymous mmap() to get the memory
- Base = (unsigned char*) mmap(0, WorkSpace, Prot, Map, -1, 0);
+ // use anonymous mmap() to get the memory
+ Base = (unsigned char*) mmap(0, WorkSpace, Prot, Map, -1, 0);
- if(Base == MAP_FAILED)
- _error->Errno("DynamicMMap",_("Couldn't make mmap of %lu bytes"),WorkSpace);
-#else
- // fallback to a static allocated space
- Base = new unsigned char[WorkSpace];
- memset(Base,0,WorkSpace);
+ if(Base == MAP_FAILED)
+ _error->Errno("DynamicMMap",_("Couldn't make mmap of %lu bytes"),WorkSpace);
+
+ iSize = 0;
+ return;
+ }
#endif
- iSize = 0;
+ // fallback to a static allocated space
+ Base = new unsigned char[WorkSpace];
+ memset(Base,0,WorkSpace);
+ iSize = 0;
}
/*}}}*/
// DynamicMMap::~DynamicMMap - Destructor /*{{{*/
@@ -231,7 +297,7 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
{
if(!Grow())
{
- _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
+ _error->Fatal(_("Dynamic MMap ran out of room. Please increase the size "
"of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
return 0;
}
@@ -248,7 +314,7 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
// Look for a matching pool entry
Pool *I;
Pool *Empty = 0;
- for (I = Pools; I != Pools + PoolCount; I++)
+ for (I = Pools; I != Pools + PoolCount; ++I)
{
if (I->ItemSize == 0)
Empty = I;
@@ -276,7 +342,11 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
{
const unsigned long size = 20*1024;
I->Count = size/ItemSize;
+ Pool* oldPools = Pools;
Result = RawAllocate(size,ItemSize);
+ if (Pools != oldPools)
+ I += Pools - oldPools;
+
// Does the allocation failed ?
if (Result == 0 && _error->PendingError())
return 0;
@@ -299,7 +369,7 @@ unsigned long DynamicMMap::WriteString(const char *String,
if (Len == (unsigned long)-1)
Len = strlen(String);
- unsigned long Result = RawAllocate(Len+1,0);
+ unsigned long const Result = RawAllocate(Len+1,0);
if (Result == 0 && _error->PendingError())
return 0;
@@ -311,30 +381,62 @@ unsigned long DynamicMMap::WriteString(const char *String,
/*}}}*/
// DynamicMMap::Grow - Grow the mmap /*{{{*/
// ---------------------------------------------------------------------
-/* This method will try to grow the mmap we currently use. This doesn't
- work most of the time because we can't move the mmap around in the
- memory for now as this would require to adjust quite a lot of pointers
- but why we should not at least try to grow it before we give up? */
-bool DynamicMMap::Grow()
-{
-#if defined(_POSIX_MAPPED_FILES) && defined(__linux__)
- unsigned long newSize = WorkSpace + 1024*1024;
+/* This method is a wrapper around different methods to (try to) grow
+ a mmap (or our char[]-fallback). Encounterable environments:
+ 1. Moveable + !Fallback + linux -> mremap with MREMAP_MAYMOVE
+ 2. Moveable + !Fallback + !linux -> not possible (forbidden by constructor)
+ 3. Moveable + Fallback -> realloc
+ 4. !Moveable + !Fallback + linux -> mremap alone - which will fail in 99,9%
+ 5. !Moveable + !Fallback + !linux -> not possible (forbidden by constructor)
+ 6. !Moveable + Fallback -> not possible
+ [ While Moveable and Fallback stands for the equally named flags and
+ "linux" indicates a linux kernel instead of a freebsd kernel. ]
+ So what you can see here is, that a MMAP which want to be growable need
+ to be moveable to have a real chance but that this method will at least try
+ the nearly impossible 4 to grow it before it finally give up: Never say never. */
+bool DynamicMMap::Grow() {
+ if (Limit != 0 && WorkSpace >= Limit)
+ return _error->Error(_("Unable to increase the size of the MMap as the "
+ "limit of %lu bytes is already reached."), Limit);
+ if (GrowFactor <= 0)
+ return _error->Error(_("Unable to increase size of the MMap as automatic growing is disabled by user."));
- if(Fd != 0)
- {
- Fd->Seek(newSize - 1);
- char C = 0;
- Fd->Write(&C,sizeof(C));
- }
+ unsigned long const newSize = WorkSpace + GrowFactor;
- Base = mremap(Base, WorkSpace, newSize, 0);
- if(Base == MAP_FAILED)
- return false;
+ if(Fd != 0) {
+ Fd->Seek(newSize - 1);
+ char C = 0;
+ Fd->Write(&C,sizeof(C));
+ }
- WorkSpace = newSize;
- return true;
+ unsigned long const poolOffset = Pools - ((Pool*) Base);
+
+ if ((Flags & Fallback) != Fallback) {
+#if defined(_POSIX_MAPPED_FILES) && defined(__linux__)
+ #ifdef MREMAP_MAYMOVE
+
+ if ((Flags & Moveable) == Moveable)
+ Base = mremap(Base, WorkSpace, newSize, MREMAP_MAYMOVE);
+ else
+ #endif
+ Base = mremap(Base, WorkSpace, newSize, 0);
+
+ if(Base == MAP_FAILED)
+ return false;
#else
- return false;
+ return false;
#endif
+ } else {
+ if ((Flags & Moveable) != Moveable)
+ return false;
+
+ Base = realloc(Base, newSize);
+ if (Base == NULL)
+ return false;
+ }
+
+ Pools =(Pool*) Base + poolOffset;
+ WorkSpace = newSize;
+ return true;
}
/*}}}*/
diff --git a/apt-pkg/contrib/mmap.h b/apt-pkg/contrib/mmap.h
index bde62217d..5ca951204 100644
--- a/apt-pkg/contrib/mmap.h
+++ b/apt-pkg/contrib/mmap.h
@@ -44,13 +44,18 @@ class MMap
unsigned long iSize;
void *Base;
+ // In case mmap can not be used, we keep a dup of the file
+ // descriptor that should have been mmaped so that we can write to
+ // the file in Sync().
+ FileFd *SyncToFd;
+
bool Map(FileFd &Fd);
bool Close(bool DoSync = true);
public:
enum OpenFlags {NoImmMap = (1<<0),Public = (1<<1),ReadOnly = (1<<2),
- UnMapped = (1<<3)};
+ UnMapped = (1<<3), Moveable = (1<<4), Fallback = (1 << 5)};
// Simple accessors
inline operator void *() {return Base;};
@@ -82,6 +87,8 @@ class DynamicMMap : public MMap
FileFd *Fd;
unsigned long WorkSpace;
+ unsigned long const GrowFactor;
+ unsigned long const Limit;
Pool *Pools;
unsigned int PoolCount;
@@ -96,8 +103,10 @@ class DynamicMMap : public MMap
inline unsigned long WriteString(const string &S) {return WriteString(S.c_str(),S.length());};
void UsePools(Pool &P,unsigned int Count) {Pools = &P; PoolCount = Count;};
- DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace = 2*1024*1024);
- DynamicMMap(unsigned long Flags,unsigned long WorkSpace = 2*1024*1024);
+ DynamicMMap(FileFd &F,unsigned long Flags,unsigned long const &WorkSpace = 2*1024*1024,
+ unsigned long const &Grow = 1024*1024, unsigned long const &Limit = 0);
+ DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace = 2*1024*1024,
+ unsigned long const &Grow = 1024*1024, unsigned long const &Limit = 0);
virtual ~DynamicMMap();
};
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index b54758632..ace74cb37 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -574,7 +574,7 @@ int stringcmp(string::const_iterator A,string::const_iterator AEnd,
int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
{
for (; A != AEnd && B != BEnd; A++, B++)
- if (toupper(*A) != toupper(*B))
+ if (tolower_ascii(*A) != tolower_ascii(*B))
break;
if (A == AEnd && B == BEnd)
@@ -583,7 +583,7 @@ int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
return 1;
if (B == BEnd)
return -1;
- if (toupper(*A) < toupper(*B))
+ if (tolower_ascii(*A) < tolower_ascii(*B))
return -1;
return 1;
}
@@ -592,7 +592,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
const char *B,const char *BEnd)
{
for (; A != AEnd && B != BEnd; A++, B++)
- if (toupper(*A) != toupper(*B))
+ if (tolower_ascii(*A) != tolower_ascii(*B))
break;
if (A == AEnd && B == BEnd)
@@ -601,7 +601,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
return 1;
if (B == BEnd)
return -1;
- if (toupper(*A) < toupper(*B))
+ if (tolower_ascii(*A) < tolower_ascii(*B))
return -1;
return 1;
}
@@ -609,7 +609,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
string::const_iterator B,string::const_iterator BEnd)
{
for (; A != AEnd && B != BEnd; A++, B++)
- if (toupper(*A) != toupper(*B))
+ if (tolower_ascii(*A) != tolower_ascii(*B))
break;
if (A == AEnd && B == BEnd)
@@ -618,7 +618,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
return 1;
if (B == BEnd)
return -1;
- if (toupper(*A) < toupper(*B))
+ if (tolower_ascii(*A) < tolower_ascii(*B))
return -1;
return 1;
}
@@ -797,28 +797,28 @@ bool ReadMessages(int Fd, vector<string> &List)
// MonthConv - Converts a month string into a number /*{{{*/
// ---------------------------------------------------------------------
/* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
- Made it a bit more robust with a few touppers though. */
+ Made it a bit more robust with a few tolower_ascii though. */
static int MonthConv(char *Month)
{
- switch (toupper(*Month))
+ switch (tolower_ascii(*Month))
{
- case 'A':
- return toupper(Month[1]) == 'P'?3:7;
- case 'D':
+ case 'a':
+ return tolower_ascii(Month[1]) == 'p'?3:7;
+ case 'd':
return 11;
- case 'F':
+ case 'f':
return 1;
- case 'J':
- if (toupper(Month[1]) == 'A')
+ case 'j':
+ if (tolower_ascii(Month[1]) == 'a')
return 0;
- return toupper(Month[2]) == 'N'?5:6;
- case 'M':
- return toupper(Month[2]) == 'R'?2:4;
- case 'N':
+ return tolower_ascii(Month[2]) == 'n'?5:6;
+ case 'm':
+ return tolower_ascii(Month[2]) == 'r'?2:4;
+ case 'n':
return 10;
- case 'O':
+ case 'o':
return 9;
- case 'S':
+ case 's':
return 8;
// Pretend it is January..
@@ -827,34 +827,70 @@ static int MonthConv(char *Month)
}
}
/*}}}*/
-// timegm - Internal timegm function if gnu is not available /*{{{*/
+// timegm - Internal timegm if the gnu version is not available /*{{{*/
// ---------------------------------------------------------------------
-/* Ripped this evil little function from wget - I prefer the use of
- GNU timegm if possible as this technique will have interesting problems
- with leap seconds, timezones and other.
-
- Converts struct tm to time_t, assuming the data in tm is UTC rather
+/* Converts struct tm to time_t, assuming the data in tm is UTC rather
than local timezone (mktime assumes the latter).
-
- Contributed by Roger Beeman <beeman@cisco.com>, with the help of
- Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
-/* Turned it into an autoconf check, because GNU is not the only thing which
- can provide timegm. -- 2002-09-22, Joel Baker */
-
-#ifndef HAVE_TIMEGM // Now with autoconf!
+ This function is a nonstandard GNU extension that is also present on
+ the BSDs and maybe other systems. For others we follow the advice of
+ the manpage of timegm and use his portable replacement. */
+#ifndef HAVE_TIMEGM
static time_t timegm(struct tm *t)
{
- time_t tl, tb;
-
- tl = mktime (t);
- if (tl == -1)
- return -1;
- tb = mktime (gmtime (&tl));
- return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
+ char *tz = getenv("TZ");
+ setenv("TZ", "", 1);
+ tzset();
+ time_t ret = mktime(t);
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ return ret;
}
#endif
/*}}}*/
+// FullDateToTime - Converts a HTTP1.1 full date strings into a time_t /*{{{*/
+// ---------------------------------------------------------------------
+/* tries to parses a full date as specified in RFC2616 Section 3.3.1
+ with one exception: All timezones (%Z) are accepted but the protocol
+ says that it MUST be GMT, but this one is equal to UTC which we will
+ encounter from time to time (e.g. in Release files) so we accept all
+ here and just assume it is GMT (or UTC) later on */
+bool RFC1123StrToTime(const char* const str,time_t &time)
+{
+ struct tm Tm;
+ setlocale (LC_ALL,"C");
+ bool const invalid =
+ // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ (strptime(str, "%a, %d %b %Y %H:%M:%S %Z", &Tm) == NULL &&
+ // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ strptime(str, "%A, %d-%b-%y %H:%M:%S %Z", &Tm) == NULL &&
+ // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+ strptime(str, "%a %b %d %H:%M:%S %Y", &Tm) == NULL);
+ setlocale (LC_ALL,"");
+ if (invalid == true)
+ return false;
+
+ time = timegm(&Tm);
+ return true;
+}
+ /*}}}*/
+// FTPMDTMStrToTime - Converts a ftp modification date into a time_t /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FTPMDTMStrToTime(const char* const str,time_t &time)
+{
+ struct tm Tm;
+ // MDTM includes no whitespaces but recommend and ignored by strptime
+ if (strptime(str, "%Y %m %d %H %M %S", &Tm) == NULL)
+ return false;
+
+ time = timegm(&Tm);
+ return true;
+}
+ /*}}}*/
// StrToTime - Converts a string into a time_t /*{{{*/
// ---------------------------------------------------------------------
/* This handles all 3 populare time formats including RFC 1123, RFC 1036
@@ -1008,6 +1044,24 @@ bool TokSplitString(char Tok,char *Input,char **List,
return true;
}
/*}}}*/
+// VectorizeString - Split a string up into a vector of strings /*{{{*/
+// ---------------------------------------------------------------------
+/* This can be used to split a given string up into a vector, so the
+ propose is the same as in the method above and this one is a bit slower
+ also, but the advantage is that we have an iteratable vector */
+vector<string> VectorizeString(string const &haystack, char const &split)
+{
+ string::const_iterator start = haystack.begin();
+ string::const_iterator end = start;
+ vector<string> exploded;
+ do {
+ for (; end != haystack.end() && *end != split; ++end);
+ exploded.push_back(string(start, end));
+ start = end + 1;
+ } while (end != haystack.end() && (++end) != haystack.end());
+ return exploded;
+}
+ /*}}}*/
// RegexChoice - Simple regex list/list matcher /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -1123,10 +1177,13 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
// tolower_ascii - tolower() function that ignores the locale /*{{{*/
// ---------------------------------------------------------------------
-/* */
-int tolower_ascii(int c)
+/* This little function is the most called method we have and tries
+ therefore to do the absolut minimum - and is noteable faster than
+ standard tolower/toupper and as a bonus avoids problems with different
+ locales - we only operate on ascii chars anyway. */
+int tolower_ascii(int const c)
{
- if (c >= 'A' and c <= 'Z')
+ if (c >= 'A' && c <= 'Z')
return c + 32;
return c;
}
diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h
index a92c0a78f..a457ff047 100644
--- a/apt-pkg/contrib/strutl.h
+++ b/apt-pkg/contrib/strutl.h
@@ -25,19 +25,12 @@
#include <iostream>
#include <time.h>
+#include "macros.h"
+
using std::string;
using std::vector;
using std::ostream;
-#ifdef __GNUG__
-// Methods have a hidden this parameter that is visible to this attribute
-#define APT_FORMAT2 __attribute__ ((format (printf, 2, 3)))
-#define APT_FORMAT3 __attribute__ ((format (printf, 3, 4)))
-#else
-#define APT_FORMAT2
-#define APT_FORMAT3
-#endif
-
bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest);
char *_strstrip(char *String);
char *_strtabexpand(char *String,size_t Len);
@@ -52,7 +45,9 @@ string Base64Encode(const string &Str);
string OutputInDepth(const unsigned long Depth, const char* Separator=" ");
string URItoFileName(const string &URI);
string TimeRFC1123(time_t Date);
-bool StrToTime(const string &Val,time_t &Result);
+bool RFC1123StrToTime(const char* const str,time_t &time) __must_check;
+bool FTPMDTMStrToTime(const char* const str,time_t &time) __must_check;
+__deprecated bool StrToTime(const string &Val,time_t &Result);
string LookupTag(const string &Message,const char *Tag,const char *Default = 0);
int StringToBool(const string &Text,int Default = -1);
bool ReadMessages(int Fd, vector<string> &List);
@@ -60,11 +55,12 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0)
bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length);
bool TokSplitString(char Tok,char *Input,char **List,
unsigned long ListMax);
-void ioprintf(ostream &out,const char *format,...) APT_FORMAT2;
-void strprintf(string &out,const char *format,...) APT_FORMAT2;
-char *safe_snprintf(char *Buffer,char *End,const char *Format,...) APT_FORMAT3;
+vector<string> VectorizeString(string const &haystack, char const &split) __attrib_const;
+void ioprintf(ostream &out,const char *format,...) __like_printf(2);
+void strprintf(string &out,const char *format,...) __like_printf(2);
+char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3);
bool CheckDomainList(const string &Host, const string &List);
-int tolower_ascii(int c);
+int tolower_ascii(int const c) __attrib_const __hot;
#define APT_MKSTRCMP(name,func) \
inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \
@@ -144,6 +140,4 @@ struct RxChoiceList
unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
const char **ListEnd);
-#undef APT_FORMAT2
-
#endif
diff --git a/apt-pkg/contrib/weakptr.h b/apt-pkg/contrib/weakptr.h
new file mode 100644
index 000000000..5158e393c
--- /dev/null
+++ b/apt-pkg/contrib/weakptr.h
@@ -0,0 +1,62 @@
+/* weakptr.h - An object which supports weak pointers.
+ *
+ * Copyright (C) 2010 Julian Andres Klode <jak@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef WEAK_POINTER_H
+#define WEAK_POINTER_H
+
+#include <set>
+/**
+ * Class for objects providing support for weak pointers.
+ *
+ * This class allows for the registration of certain pointers as weak,
+ * which will cause them to be set to NULL when the destructor of the
+ * object is called.
+ */
+class WeakPointable {
+private:
+ std::set<WeakPointable**> pointers;
+
+public:
+
+ /**
+ * Add a new weak pointer.
+ */
+ inline void AddWeakPointer(WeakPointable** weakptr) {
+ pointers.insert(weakptr);
+ }
+
+ /**
+ * Remove the weak pointer from the list of weak pointers.
+ */
+ inline void RemoveWeakPointer(WeakPointable **weakptr) {
+ pointers.erase(weakptr);
+ }
+
+ /**
+ * Deconstruct the object, set all weak pointers to NULL.
+ */
+ ~WeakPointable() {
+ std::set<WeakPointable**>::iterator iter = pointers.begin();
+ while (iter != pointers.end())
+ **(iter++) = NULL;
+ }
+};
+
+#endif // WEAK_POINTER_H