summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/acquire-item.cc28
-rw-r--r--apt-pkg/acquire-item.h3
-rw-r--r--apt-pkg/acquire-worker.h3
-rw-r--r--apt-pkg/acquire.cc98
-rw-r--r--apt-pkg/acquire.h34
-rw-r--r--apt-pkg/algorithms.cc66
-rw-r--r--apt-pkg/aptconfiguration.cc27
-rw-r--r--apt-pkg/aptconfiguration.h16
-rw-r--r--apt-pkg/cacheiterators.h723
-rw-r--r--apt-pkg/cdrom.cc37
-rw-r--r--apt-pkg/clean.cc6
-rw-r--r--apt-pkg/contrib/cmndline.cc42
-rw-r--r--apt-pkg/contrib/cmndline.h1
-rw-r--r--apt-pkg/contrib/configuration.cc2
-rw-r--r--apt-pkg/contrib/error.h8
-rw-r--r--apt-pkg/contrib/fileutl.cc57
-rw-r--r--apt-pkg/contrib/fileutl.h8
-rw-r--r--apt-pkg/contrib/macros.h34
-rw-r--r--apt-pkg/contrib/mmap.cc70
-rw-r--r--apt-pkg/contrib/mmap.h5
-rw-r--r--apt-pkg/contrib/strutl.cc76
-rw-r--r--apt-pkg/contrib/strutl.h24
-rw-r--r--apt-pkg/contrib/weakptr.h62
-rw-r--r--apt-pkg/deb/debindexfile.cc15
-rw-r--r--apt-pkg/deb/debindexfile.h4
-rw-r--r--apt-pkg/deb/deblistparser.cc219
-rw-r--r--apt-pkg/deb/deblistparser.h4
-rw-r--r--apt-pkg/deb/debmetaindex.cc298
-rw-r--r--apt-pkg/deb/debmetaindex.h28
-rw-r--r--apt-pkg/deb/debversion.cc18
-rw-r--r--apt-pkg/deb/dpkgpm.cc35
-rw-r--r--apt-pkg/depcache.cc446
-rw-r--r--apt-pkg/depcache.h23
-rw-r--r--apt-pkg/makefile2
-rw-r--r--apt-pkg/metaindex.h4
-rw-r--r--apt-pkg/orderlist.cc13
-rw-r--r--apt-pkg/packagemanager.cc42
-rw-r--r--apt-pkg/pkgcache.cc243
-rw-r--r--apt-pkg/pkgcache.h507
-rw-r--r--apt-pkg/pkgcachegen.cc326
-rw-r--r--apt-pkg/pkgcachegen.h17
-rw-r--r--apt-pkg/policy.cc41
-rw-r--r--apt-pkg/sourcelist.cc88
-rw-r--r--apt-pkg/sourcelist.h8
-rw-r--r--apt-pkg/tagfile.cc13
-rw-r--r--apt-pkg/tagfile.h15
-rw-r--r--apt-pkg/versionmatch.cc8
-rw-r--r--apt-pkg/versionmatch.h2
48 files changed, 2751 insertions, 1098 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc
index 6d4336425..1f253bb81 100644
--- a/apt-pkg/acquire-item.cc
+++ b/apt-pkg/acquire-item.cc
@@ -1327,7 +1327,8 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
the archive is already available in the cache and stashs the MD5 for
checking later. */
bool pkgAcqArchive::QueueNext()
-{
+{
+ string const ForceHash = _config->Find("Acquire::ForceHash");
for (; Vf.end() == false; Vf++)
{
// Ignore not source sources
@@ -1350,12 +1351,25 @@ bool pkgAcqArchive::QueueNext()
return false;
string PkgFile = Parse.FileName();
- if(Parse.SHA256Hash() != "")
- ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
- else if (Parse.SHA1Hash() != "")
- ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
- else
- ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
+ if (ForceHash.empty() == false)
+ {
+ if(stringcasecmp(ForceHash, "sha256") == 0)
+ ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
+ else if (stringcasecmp(ForceHash, "sha1") == 0)
+ ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
+ else
+ ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
+ }
+ else
+ {
+ string Hash;
+ if ((Hash = Parse.SHA256Hash()).empty() == false)
+ ExpectedHash = HashString("SHA256", Hash);
+ else if ((Hash = Parse.SHA1Hash()).empty() == false)
+ ExpectedHash = HashString("SHA1", Hash);
+ else
+ ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
+ }
if (PkgFile.empty() == true)
return _error->Error(_("The package index files are corrupted. No Filename: "
"field for package %s."),
diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h
index bafa8263a..b338b2a41 100644
--- a/apt-pkg/acquire-item.h
+++ b/apt-pkg/acquire-item.h
@@ -27,6 +27,7 @@
#include <apt-pkg/pkgrecords.h>
#include <apt-pkg/indexrecords.h>
#include <apt-pkg/hashes.h>
+#include <apt-pkg/weakptr.h>
/** \addtogroup acquire
* @{
@@ -46,7 +47,7 @@
*
* \see pkgAcquire
*/
-class pkgAcquire::Item
+class pkgAcquire::Item : public WeakPointable
{
protected:
diff --git a/apt-pkg/acquire-worker.h b/apt-pkg/acquire-worker.h
index 2942df69f..06283922e 100644
--- a/apt-pkg/acquire-worker.h
+++ b/apt-pkg/acquire-worker.h
@@ -20,6 +20,7 @@
#define PKGLIB_ACQUIRE_WORKER_H
#include <apt-pkg/acquire.h>
+#include <apt-pkg/weakptr.h>
/** \brief A fetch subprocess.
@@ -41,7 +42,7 @@
*
* \sa pkgAcqMethod, pkgAcquire::Item, pkgAcquire
*/
-class pkgAcquire::Worker
+class pkgAcquire::Worker : public WeakPointable
{
friend class pkgAcquire;
diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc
index 74510ae21..832eaa02c 100644
--- a/apt-pkg/acquire.cc
+++ b/apt-pkg/acquire.cc
@@ -19,6 +19,7 @@
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
#include <apt-pkg/strutl.h>
+#include <apt-pkg/fileutl.h>
#include <apti18n.h>
@@ -29,7 +30,6 @@
#include <dirent.h>
#include <sys/time.h>
#include <errno.h>
-#include <sys/stat.h>
/*}}}*/
using namespace std;
@@ -37,32 +37,81 @@ using namespace std;
// Acquire::pkgAcquire - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* We grab some runtime state from the configuration space */
-pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
+pkgAcquire::pkgAcquire() : Queues(0), Workers(0), Configs(0), Log(NULL), ToFetch(0),
+ Debug(_config->FindB("Debug::pkgAcquire",false)),
+ Running(false), LockFD(-1)
{
- Queues = 0;
- Configs = 0;
- Workers = 0;
- ToFetch = 0;
- Running = false;
-
- string Mode = _config->Find("Acquire::Queue-Mode","host");
+ string const Mode = _config->Find("Acquire::Queue-Mode","host");
if (strcasecmp(Mode.c_str(),"host") == 0)
QueueMode = QueueHost;
if (strcasecmp(Mode.c_str(),"access") == 0)
- QueueMode = QueueAccess;
+ QueueMode = QueueAccess;
+}
+pkgAcquire::pkgAcquire(pkgAcquireStatus *Progress) : Queues(0), Workers(0),
+ Configs(0), Log(Progress), ToFetch(0),
+ Debug(_config->FindB("Debug::pkgAcquire",false)),
+ Running(false), LockFD(-1)
+{
+ string const Mode = _config->Find("Acquire::Queue-Mode","host");
+ if (strcasecmp(Mode.c_str(),"host") == 0)
+ QueueMode = QueueHost;
+ if (strcasecmp(Mode.c_str(),"access") == 0)
+ QueueMode = QueueAccess;
+ Setup(Progress, "");
+}
+ /*}}}*/
+// Acquire::Setup - Delayed Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* Do everything needed to be a complete Acquire object and report the
+ success (or failure) back so the user knows that something is wrong… */
+bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock)
+{
+ Log = Progress;
- Debug = _config->FindB("Debug::pkgAcquire",false);
-
- // This is really a stupid place for this
- struct stat St;
- if (stat((_config->FindDir("Dir::State::lists") + "partial/").c_str(),&St) != 0 ||
- S_ISDIR(St.st_mode) == 0)
- _error->Error(_("Lists directory %spartial is missing."),
- _config->FindDir("Dir::State::lists").c_str());
- if (stat((_config->FindDir("Dir::Cache::Archives") + "partial/").c_str(),&St) != 0 ||
- S_ISDIR(St.st_mode) == 0)
- _error->Error(_("Archive directory %spartial is missing."),
- _config->FindDir("Dir::Cache::Archives").c_str());
+ // check for existence and possibly create auxiliary directories
+ string const listDir = _config->FindDir("Dir::State::lists");
+ string const partialListDir = listDir + "partial/";
+ string const archivesDir = _config->FindDir("Dir::Cache::Archives");
+ string const partialArchivesDir = archivesDir + "partial/";
+
+ if (CheckDirectory(_config->FindDir("Dir::State"), partialListDir) == false &&
+ CheckDirectory(listDir, partialListDir) == false)
+ return _error->Errno("Acquire", _("List directory %spartial is missing."), listDir.c_str());
+
+ if (CheckDirectory(_config->FindDir("Dir::Cache"), partialArchivesDir) == false &&
+ CheckDirectory(archivesDir, partialArchivesDir) == false)
+ return _error->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir.c_str());
+
+ if (Lock.empty() == true || _config->FindB("Debug::NoLocking", false) == true)
+ return true;
+
+ // Lock the directory this acquire object will work in
+ LockFD = GetLock(flCombine(Lock, "lock"));
+ if (LockFD == -1)
+ return _error->Error(_("Unable to lock directory %s"), Lock.c_str());
+
+ return true;
+}
+ /*}}}*/
+// Acquire::CheckDirectory - ensure that the given directory exists /*{{{*/
+// ---------------------------------------------------------------------
+/* a small wrapper around CreateDirectory to check if it exists and to
+ remove the trailing "/apt/" from the parent directory if needed */
+bool pkgAcquire::CheckDirectory(string const &Parent, string const &Path) const
+{
+ if (DirectoryExists(Path) == true)
+ return true;
+
+ size_t const len = Parent.size();
+ if (len > 5 && Parent.find("/apt/", len - 6, 5) == len - 5)
+ {
+ if (CreateDirectory(Parent.substr(0,len-5), Path) == true)
+ return true;
+ }
+ else if (CreateDirectory(Parent, Path) == true)
+ return true;
+
+ return false;
}
/*}}}*/
// Acquire::~pkgAcquire - Destructor /*{{{*/
@@ -71,7 +120,10 @@ pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
pkgAcquire::~pkgAcquire()
{
Shutdown();
-
+
+ if (LockFD != -1)
+ close(LockFD);
+
while (Configs != 0)
{
MethodConfig *Jnk = Configs;
diff --git a/apt-pkg/acquire.h b/apt-pkg/acquire.h
index 6c130c1b3..8e2c21151 100644
--- a/apt-pkg/acquire.h
+++ b/apt-pkg/acquire.h
@@ -66,6 +66,9 @@
#ifndef PKGLIB_ACQUIRE_H
#define PKGLIB_ACQUIRE_H
+#include <apt-pkg/macros.h>
+#include <apt-pkg/weakptr.h>
+
#include <vector>
#include <string>
@@ -161,7 +164,7 @@ class pkgAcquire
QueueAccess} QueueMode;
/** \brief If \b true, debugging information will be dumped to std::clog. */
- bool Debug;
+ bool const Debug;
/** \brief If \b true, a download is currently in progress. */
bool Running;
@@ -332,15 +335,22 @@ class pkgAcquire
*/
double PartialPresent();
- /** \brief Construct a new pkgAcquire.
+ /** \brief Delayed constructor
*
- * \param Log The progress indicator associated with this
- * download, or \b NULL for none. This object is not owned by the
+ * \param Progress indicator associated with this download or
+ * \b NULL for none. This object is not owned by the
* download process and will not be deleted when the pkgAcquire
* object is destroyed. Naturally, it should live for at least as
* long as the pkgAcquire object does.
+ * \param Lock defines a lock file that should be acquired to ensure
+ * only one Acquire class is in action at the time or an empty string
+ * if no lock file should be used.
*/
- pkgAcquire(pkgAcquireStatus *Log = 0);
+ bool Setup(pkgAcquireStatus *Progress = NULL, string const &Lock = "");
+
+ /** \brief Construct a new pkgAcquire. */
+ pkgAcquire(pkgAcquireStatus *Log) __deprecated;
+ pkgAcquire();
/** \brief Destroy this pkgAcquire object.
*
@@ -348,6 +358,18 @@ class pkgAcquire
* this download.
*/
virtual ~pkgAcquire();
+
+ private:
+ /** \brief FD of the Lock file we acquire in Setup (if any) */
+ int LockFD;
+
+ /** \brief Ensure the existence of the given Path
+ *
+ * \param Parent directory of the Path directory - a trailing
+ * /apt/ will be removed before CreateDirectory call.
+ * \param Path which should exist after (successful) call
+ */
+ bool CheckDirectory(string const &Parent, string const &Path) const;
};
/** \brief Represents a single download source from which an item
@@ -355,7 +377,7 @@ class pkgAcquire
*
* An item may have several assocated ItemDescs over its lifetime.
*/
-struct pkgAcquire::ItemDesc
+struct pkgAcquire::ItemDesc : public WeakPointable
{
/** \brief The URI from which to download this item. */
string URI;
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc
index 34da745de..f1e51131a 100644
--- a/apt-pkg/algorithms.cc
+++ b/apt-pkg/algorithms.cc
@@ -83,13 +83,28 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid
bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
{
// Adapt the iterator
- PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
Flags[Pkg->ID] = 1;
cout << "Inst ";
Describe(Pkg,cout,true,true);
Sim.MarkInstall(Pkg,false);
-
+
+ if (strcmp(Pkg.Arch(),"all") == 0)
+ {
+ pkgCache::GrpIterator G = Pkg.Group();
+ pkgCache::GrpIterator iG = iPkg.Group();
+ for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(), "all") == 0)
+ continue;
+ if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+ continue;
+ Flags[P->ID] = 1;
+ Sim.MarkInstall(P, false);
+ }
+ }
+
// Look for broken conflicts+predepends.
for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
{
@@ -131,9 +146,22 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
bool pkgSimulate::Configure(PkgIterator iPkg)
{
// Adapt the iterator
- PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
Flags[Pkg->ID] = 2;
+
+ if (strcmp(Pkg.Arch(),"all") == 0)
+ {
+ pkgCache::GrpIterator G = Pkg.Group();
+ for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(), "all") == 0)
+ continue;
+ if (Flags[P->ID] == 1)
+ Flags[P->ID] = 2;
+ }
+ }
+
// Sim.MarkInstall(Pkg,false);
if (Sim[Pkg].InstBroken() == true)
{
@@ -181,10 +209,26 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
{
// Adapt the iterator
- PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
Flags[Pkg->ID] = 3;
Sim.MarkDelete(Pkg);
+
+ if (strcmp(Pkg.Arch(),"all") == 0)
+ {
+ pkgCache::GrpIterator G = Pkg.Group();
+ pkgCache::GrpIterator iG = iPkg.Group();
+ for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(), "all") == 0)
+ continue;
+ if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+ continue;
+ Flags[P->ID] = 3;
+ Sim.MarkDelete(P);
+ }
+ }
+
if (Purge == true)
cout << "Purg ";
else
@@ -491,11 +535,11 @@ void pkgProblemResolver::MakeScores()
// Important Required Standard Optional Extra
signed short PrioMap[] = {
0,
- _config->FindI("pkgProblemResolver::Scores::Important",3),
- _config->FindI("pkgProblemResolver::Scores::Required",2),
- _config->FindI("pkgProblemResolver::Scores::Standard",1),
- _config->FindI("pkgProblemResolver::Scores::Optional",-1),
- _config->FindI("pkgProblemResolver::Scores::Extra",-2)
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2)
};
signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
@@ -1354,7 +1398,9 @@ bool ListUpdate(pkgAcquireStatus &Stat,
int PulseInterval)
{
pkgAcquire::RunResult res;
- pkgAcquire Fetcher(&Stat);
+ pkgAcquire Fetcher;
+ if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
+ return false;
// Populate it with the source selection
if (List.GetIndexes(&Fetcher) == false)
diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc
index 10613f11d..2acf8dd9f 100644
--- a/apt-pkg/aptconfiguration.cc
+++ b/apt-pkg/aptconfiguration.cc
@@ -152,6 +152,7 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
builtin.push_back(c);
}
}
+ closedir(D);
// get the environment language codes: LC_MESSAGES (and later LANGUAGE)
// we extract both, a long and a short code and then we will
@@ -220,7 +221,7 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
string envLang = Locale == 0 ? language_env : *(Locale+1);
if (envLang.empty() == false) {
- std::vector<string> env = ExplodeString(envLang,':');
+ std::vector<string> env = VectorizeString(envLang,':');
short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
for (std::vector<string>::const_iterator e = env.begin();
e != env.end() && addedLangs < 3; ++e) {
@@ -318,4 +319,28 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
return codes;
}
/*}}}*/
+// getArchitectures - Return Vector of prefered Architectures /*{{{*/
+std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
+ using std::string;
+
+ std::vector<string> static archs;
+ if (likely(Cached == true) && archs.empty() == false)
+ return archs;
+
+ string const arch = _config->Find("APT::Architecture");
+ archs = _config->FindVector("APT::Architectures");
+ if (archs.empty() == true ||
+ std::find(archs.begin(), archs.end(), arch) == archs.end())
+ archs.push_back(arch);
+ return archs;
+}
+ /*}}}*/
+// checkArchitecture - are we interested in the given Architecture? /*{{{*/
+bool const Configuration::checkArchitecture(std::string const &Arch) {
+ if (Arch == "all")
+ return true;
+ std::vector<std::string> const archs = getArchitectures(true);
+ return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
+}
+ /*}}}*/
}
diff --git a/apt-pkg/aptconfiguration.h b/apt-pkg/aptconfiguration.h
index 2ba1b3825..dd339d841 100644
--- a/apt-pkg/aptconfiguration.h
+++ b/apt-pkg/aptconfiguration.h
@@ -66,6 +66,22 @@ public: /*{{{*/
std::vector<std::string> static const getLanguages(bool const &All = false,
bool const &Cached = true, char const ** const Locale = 0);
+ /** \brief Returns a vector of Architectures we support
+ *
+ * \param Cached saves the result so we need to calculated it only once
+ * this parameter should ony be used for testing purposes.
+ *
+ * \return a vector of Architectures in prefered order
+ */
+ std::vector<std::string> static const getArchitectures(bool const &Cached = true);
+
+ /** \brief Are we interested in the given Architecture?
+ *
+ * \param Arch we want to check
+ * \return true if we are interested, false otherwise
+ */
+ bool static const checkArchitecture(std::string const &Arch);
+
/*}}}*/
};
/*}}}*/
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index 28466cd40..e2ca74683 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -1,6 +1,5 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: cacheiterators.h,v 1.18.2.1 2004/05/08 22:44:27 mdz Exp $
/* ######################################################################
Cache Iterators - Iterators for navigating the cache structure
@@ -30,417 +29,385 @@
/*}}}*/
#ifndef PKGLIB_CACHEITERATORS_H
#define PKGLIB_CACHEITERATORS_H
+// abstract Iterator template /*{{{*/
+/* This template provides the very basic iterator methods we
+ need to have for doing some walk-over-the-cache magic */
+template<typename Str, typename Itr> class pkgCache::Iterator {
+ protected:
+ Str *S;
+ pkgCache *Owner;
+
+ /** \brief Returns the Pointer for this struct in the owner
+ * The implementation of this method should be pretty short
+ * as it will only return the Pointer into the mmap stored
+ * in the owner but the name of this pointer is different for
+ * each stucture and we want to abstract here at least for the
+ * basic methods from the actual structure.
+ * \return Pointer to the first structure of this type
+ */
+ virtual Str* OwnerPointer() const = 0;
+
+ public:
+ // Iteration
+ virtual void operator ++(int) = 0;
+ virtual void operator ++() = 0; // Should be {operator ++(0);};
+ inline bool end() const {return Owner == 0 || S == OwnerPointer();};
+
+ // Comparison
+ inline bool operator ==(const Itr &B) const {return S == B.S;};
+ inline bool operator !=(const Itr &B) const {return S != B.S;};
+
+ // Accessors
+ inline Str *operator ->() {return S;};
+ inline Str const *operator ->() const {return S;};
+ inline operator Str *() {return S == OwnerPointer() ? 0 : S;};
+ inline operator Str const *() const {return S == OwnerPointer() ? 0 : S;};
+ inline Str &operator *() {return *S;};
+ inline Str const &operator *() const {return *S;};
+ inline pkgCache *Cache() {return Owner;};
+
+ // Mixed stuff
+ inline void operator =(const Itr &B) {S = B.S; Owner = B.Owner;};
+ inline bool IsGood() const { return S && Owner && ! end();};
+ inline unsigned long Index() const {return S - OwnerPointer();};
+
+ // Constructors - look out for the variable assigning
+ inline Iterator() : S(0), Owner(0) {};
+ inline Iterator(pkgCache &Owner,Str *T = 0) : S(T), Owner(&Owner) {};
+};
+ /*}}}*/
+// Group Iterator /*{{{*/
+/* Packages with the same name are collected in a Group so someone only
+ interest in package names can iterate easily over the names, so the
+ different architectures can be treated as of the "same" package
+ (apt internally treat them as totally different packages) */
+class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
+ long HashIndex;
+
+ protected:
+ inline Group* OwnerPointer() const {
+ return Owner->GrpP;
+ };
+
+ public:
+ // This constructor is the 'begin' constructor, never use it.
+ inline GrpIterator(pkgCache &Owner) : Iterator<Group, GrpIterator>(Owner), HashIndex(-1) {
+ S = OwnerPointer();
+ operator ++(0);
+ };
+
+ virtual void operator ++(int);
+ virtual void operator ++() {operator ++(0);};
+
+ inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
+ inline PkgIterator PackageList() const;
+ PkgIterator FindPkg(string Arch = "any");
+ PkgIterator NextPkg(PkgIterator const &Pkg);
+
+ // Constructors
+ inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) {
+ if (S == 0)
+ S = OwnerPointer();
+ };
+ inline GrpIterator() : Iterator<Group, GrpIterator>(), HashIndex(0) {};
-
+};
+ /*}}}*/
// Package Iterator /*{{{*/
-class pkgCache::PkgIterator
-{
- friend class pkgCache;
- Package *Pkg;
- pkgCache *Owner;
- long HashIndex;
-
- protected:
-
- // This constructor is the 'begin' constructor, never use it.
- inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1)
- {
- Pkg = Owner.PkgP;
- operator ++(0);
- };
-
- public:
-
- enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
-
- // Iteration
- void operator ++(int);
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;};
-
- // Comparison
- inline bool operator ==(const PkgIterator &B) const {return Pkg == B.Pkg;};
- inline bool operator !=(const PkgIterator &B) const {return Pkg != B.Pkg;};
-
- // Accessors
- inline Package *operator ->() {return Pkg;};
- inline Package const *operator ->() const {return Pkg;};
- inline Package const &operator *() const {return *Pkg;};
- inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
- inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;};
- inline pkgCache *Cache() {return Owner;};
-
- inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;};
- inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;};
- inline bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge ||
- (Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);};
- inline VerIterator VersionList() const;
- inline VerIterator CurrentVer() const;
- inline DepIterator RevDependsList() const;
- inline PrvIterator ProvidesList() const;
- inline unsigned long Index() const {return Pkg - Owner->PkgP;};
- OkState State() const;
-
- //Nice printable representation
- friend std::ostream& operator<<(std::ostream& out, pkgCache::PkgIterator Pkg);
-
- const char *CandVersion() const;
- const char *CurVersion() const;
-
- // Constructors
- inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner),
- HashIndex(0)
- {
- if (Pkg == 0)
- Pkg = Owner.PkgP;
- };
- inline PkgIterator() : Pkg(0), Owner(0), HashIndex(0) {};
+class pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
+ long HashIndex;
+
+ protected:
+ inline Package* OwnerPointer() const {
+ return Owner->PkgP;
+ };
+
+ public:
+ // This constructor is the 'begin' constructor, never use it.
+ inline PkgIterator(pkgCache &Owner) : Iterator<Package, PkgIterator>(Owner), HashIndex(-1) {
+ S = OwnerPointer();
+ operator ++(0);
+ };
+
+ virtual void operator ++(int);
+ virtual void operator ++() {operator ++(0);};
+
+ enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
+
+ // Accessors
+ inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
+ inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;};
+ inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge ||
+ (S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);};
+ inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;};
+ inline GrpIterator Group() const { return GrpIterator(*Owner, Owner->GrpP + S->Group);};
+
+ inline VerIterator VersionList() const;
+ inline VerIterator CurrentVer() const;
+ inline DepIterator RevDependsList() const;
+ inline PrvIterator ProvidesList() const;
+ OkState State() const;
+ const char *CandVersion() const;
+ const char *CurVersion() const;
+
+ //Nice printable representation
+ friend std::ostream& operator <<(std::ostream& out, PkgIterator i);
+ std::string FullName(bool const &Pretty = false) const;
+
+ // Constructors
+ inline PkgIterator(pkgCache &Owner,Package *Trg) : Iterator<Package, PkgIterator>(Owner, Trg), HashIndex(0) {
+ if (S == 0)
+ S = OwnerPointer();
+ };
+ inline PkgIterator() : Iterator<Package, PkgIterator>(), HashIndex(0) {};
};
/*}}}*/
// Version Iterator /*{{{*/
-class pkgCache::VerIterator
-{
- Version *Ver;
- pkgCache *Owner;
-
- void _dummy();
-
- public:
-
- // Iteration
- void operator ++(int) {if (Ver != Owner->VerP) Ver = Owner->VerP + Ver->NextVer;};
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || (Ver == Owner->VerP?true:false);};
- inline void operator =(const VerIterator &B) {Ver = B.Ver; Owner = B.Owner;};
-
- // Comparison
- inline bool operator ==(const VerIterator &B) const {return Ver == B.Ver;};
- inline bool operator !=(const VerIterator &B) const {return Ver != B.Ver;};
- int CompareVer(const VerIterator &B) const;
-
- // Testing
- inline bool IsGood() const { return Ver && Owner && ! end();};
-
- // Accessors
- inline Version *operator ->() {return Ver;};
- inline Version const *operator ->() const {return Ver;};
- inline Version &operator *() {return *Ver;};
- inline Version const &operator *() const {return *Ver;};
- inline operator Version *() {return Ver == Owner->VerP?0:Ver;};
- inline operator Version const *() const {return Ver == Owner->VerP?0:Ver;};
- inline pkgCache *Cache() {return Owner;};
-
- inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner->StrP + Ver->VerStr;};
- inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;};
- inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
- inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);};
- inline DescIterator DescriptionList() const;
- DescIterator TranslatedDescription() const;
- inline DepIterator DependsList() const;
- inline PrvIterator ProvidesList() const;
- inline VerFileIterator FileList() const;
- inline unsigned long Index() const {return Ver - Owner->VerP;};
- bool Downloadable() const;
- inline const char *PriorityType() {return Owner->Priority(Ver->Priority);};
- string RelStr();
-
- bool Automatic() const;
- VerFileIterator NewestFile() const;
-
- inline VerIterator() : Ver(0), Owner(0) {};
- inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Ver(Trg),
- Owner(&Owner)
- {
- if (Ver == 0)
- Ver = Owner.VerP;
- };
+class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
+ protected:
+ inline Version* OwnerPointer() const {
+ return Owner->VerP;
+ };
+
+ public:
+ // Iteration
+ void operator ++(int) {if (S != Owner->VerP) S = Owner->VerP + S->NextVer;};
+ inline void operator ++() {operator ++(0);};
+
+ // Comparison
+ int CompareVer(const VerIterator &B) const;
+
+ // Accessors
+ inline const char *VerStr() const {return S->VerStr == 0?0:Owner->StrP + S->VerStr;};
+ inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;};
+ inline const char *Arch() const {
+ if(S->MultiArch == pkgCache::Version::All)
+ return "all";
+ return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+ };
+ inline const char *Arch(bool const pseudo) const {
+ if(pseudo == false)
+ return Arch();
+ return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+ };
+ inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+
+ inline DescIterator DescriptionList() const;
+ DescIterator TranslatedDescription() const;
+ inline DepIterator DependsList() const;
+ inline PrvIterator ProvidesList() const;
+ inline VerFileIterator FileList() const;
+ bool Downloadable() const;
+ inline const char *PriorityType() {return Owner->Priority(S->Priority);};
+ string RelStr();
+
+ bool Automatic() const;
+ bool Pseudo() const;
+ VerFileIterator NewestFile() const;
+
+ inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) {
+ if (S == 0)
+ S = OwnerPointer();
+ };
+ inline VerIterator() : Iterator<Version, VerIterator>() {};
};
/*}}}*/
// Description Iterator /*{{{*/
-class pkgCache::DescIterator
-{
- Description *Desc;
- pkgCache *Owner;
-
- void _dummy();
-
- public:
-
- // Iteration
- void operator ++(int) {if (Desc != Owner->DescP) Desc = Owner->DescP + Desc->NextDesc;};
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || Desc == Owner->DescP?true:false;};
- inline void operator =(const DescIterator &B) {Desc = B.Desc; Owner = B.Owner;};
-
- // Comparison
- inline bool operator ==(const DescIterator &B) const {return Desc == B.Desc;};
- inline bool operator !=(const DescIterator &B) const {return Desc != B.Desc;};
- int CompareDesc(const DescIterator &B) const;
-
- // Accessors
- inline Description *operator ->() {return Desc;};
- inline Description const *operator ->() const {return Desc;};
- inline Description &operator *() {return *Desc;};
- inline Description const &operator *() const {return *Desc;};
- inline operator Description *() {return Desc == Owner->DescP?0:Desc;};
- inline operator Description const *() const {return Desc == Owner->DescP?0:Desc;};
- inline pkgCache *Cache() {return Owner;};
-
- inline const char *LanguageCode() const {return Owner->StrP + Desc->language_code;};
- inline const char *md5() const {return Owner->StrP + Desc->md5sum;};
- inline DescFileIterator FileList() const;
- inline unsigned long Index() const {return Desc - Owner->DescP;};
-
- inline DescIterator() : Desc(0), Owner(0) {};
- inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Desc(Trg),
- Owner(&Owner)
- {
- if (Desc == 0)
- Desc = Owner.DescP;
- };
+class pkgCache::DescIterator : public Iterator<Description, DescIterator> {
+ protected:
+ inline Description* OwnerPointer() const {
+ return Owner->DescP;
+ };
+
+ public:
+ // Iteration
+ void operator ++(int) {if (S != Owner->DescP) S = Owner->DescP + S->NextDesc;};
+ inline void operator ++() {operator ++(0);};
+
+ // Comparison
+ int CompareDesc(const DescIterator &B) const;
+
+ // Accessors
+ inline const char *LanguageCode() const {return Owner->StrP + S->language_code;};
+ inline const char *md5() const {return Owner->StrP + S->md5sum;};
+ inline DescFileIterator FileList() const;
+
+ inline DescIterator() : Iterator<Description, DescIterator>() {};
+ inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Iterator<Description, DescIterator>(Owner, Trg) {
+ if (S == 0)
+ S = Owner.DescP;
+ };
};
/*}}}*/
// Dependency iterator /*{{{*/
-class pkgCache::DepIterator
-{
- Dependency *Dep;
- enum {DepVer, DepRev} Type;
- pkgCache *Owner;
-
- void _dummy();
-
- public:
-
- // Iteration
- void operator ++(int) {if (Dep != Owner->DepP) Dep = Owner->DepP +
- (Type == DepVer?Dep->NextDepends:Dep->NextRevDepends);};
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || Dep == Owner->DepP?true:false;};
-
- // Comparison
- inline bool operator ==(const DepIterator &B) const {return Dep == B.Dep;};
- inline bool operator !=(const DepIterator &B) const {return Dep != B.Dep;};
-
- // Accessors
- inline Dependency *operator ->() {return Dep;};
- inline Dependency const *operator ->() const {return Dep;};
- inline Dependency &operator *() {return *Dep;};
- inline Dependency const &operator *() const {return *Dep;};
- inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
- inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;};
- inline pkgCache *Cache() {return Owner;};
-
- inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;};
- inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);};
- inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
- inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
- inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
- inline bool Reverse() {return Type == DepRev;};
- inline unsigned long Index() const {return Dep - Owner->DepP;};
- bool IsCritical();
- void GlobOr(DepIterator &Start,DepIterator &End);
- Version **AllTargets();
- bool SmartTargetPkg(PkgIterator &Result);
- inline const char *CompType() {return Owner->CompType(Dep->CompareOp);};
- inline const char *DepType() {return Owner->DepType(Dep->Type);};
-
- inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
- Dep(Trg), Type(DepVer), Owner(&Owner)
- {
- if (Dep == 0)
- Dep = Owner.DepP;
- };
- inline DepIterator(pkgCache &Owner,Dependency *Trg,Package *) :
- Dep(Trg), Type(DepRev), Owner(&Owner)
- {
- if (Dep == 0)
- Dep = Owner.DepP;
- };
- inline DepIterator() : Dep(0), Type(DepVer), Owner(0) {};
+class pkgCache::DepIterator : public Iterator<Dependency, DepIterator> {
+ enum {DepVer, DepRev} Type;
+
+ protected:
+ inline Dependency* OwnerPointer() const {
+ return Owner->DepP;
+ };
+
+ public:
+ // Iteration
+ void operator ++(int) {if (S != Owner->DepP) S = Owner->DepP +
+ (Type == DepVer ? S->NextDepends : S->NextRevDepends);};
+ inline void operator ++() {operator ++(0);};
+
+ // Accessors
+ inline const char *TargetVer() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+ inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + S->Package);};
+ inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
+ inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + S->ParentVer);};
+ inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->ParentVer].ParentPkg);};
+ inline bool Reverse() {return Type == DepRev;};
+ bool IsCritical();
+ void GlobOr(DepIterator &Start,DepIterator &End);
+ Version **AllTargets();
+ bool SmartTargetPkg(PkgIterator &Result);
+ inline const char *CompType() {return Owner->CompType(S->CompareOp);};
+ inline const char *DepType() {return Owner->DepType(S->Type);};
+
+ inline DepIterator(pkgCache &Owner, Dependency *Trg, Version* = 0) :
+ Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepVer) {
+ if (S == 0)
+ S = Owner.DepP;
+ };
+ inline DepIterator(pkgCache &Owner, Dependency *Trg, Package*) :
+ Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepRev) {
+ if (S == 0)
+ S = Owner.DepP;
+ };
+ inline DepIterator() : Iterator<Dependency, DepIterator>(), Type(DepVer) {};
};
/*}}}*/
// Provides iterator /*{{{*/
-class pkgCache::PrvIterator
-{
- Provides *Prv;
- enum {PrvVer, PrvPkg} Type;
- pkgCache *Owner;
-
- void _dummy();
-
- public:
-
- // Iteration
- void operator ++(int) {if (Prv != Owner->ProvideP) Prv = Owner->ProvideP +
- (Type == PrvVer?Prv->NextPkgProv:Prv->NextProvides);};
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || Prv == Owner->ProvideP?true:false;};
-
- // Comparison
- inline bool operator ==(const PrvIterator &B) const {return Prv == B.Prv;};
- inline bool operator !=(const PrvIterator &B) const {return Prv != B.Prv;};
-
- // Accessors
- inline Provides *operator ->() {return Prv;};
- inline Provides const *operator ->() const {return Prv;};
- inline Provides &operator *() {return *Prv;};
- inline Provides const &operator *() const {return *Prv;};
- inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
- inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;};
- inline pkgCache *Cache() {return Owner;};
-
- inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;};
- inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;};
- inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};
- inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + Prv->Version);};
- inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Prv->Version].ParentPkg);};
- inline unsigned long Index() const {return Prv - Owner->ProvideP;};
-
- inline PrvIterator() : Prv(0), Type(PrvVer), Owner(0) {};
-
- inline PrvIterator(pkgCache &Owner,Provides *Trg,Version *) :
- Prv(Trg), Type(PrvVer), Owner(&Owner)
- {
- if (Prv == 0)
- Prv = Owner.ProvideP;
- };
- inline PrvIterator(pkgCache &Owner,Provides *Trg,Package *) :
- Prv(Trg), Type(PrvPkg), Owner(&Owner)
- {
- if (Prv == 0)
- Prv = Owner.ProvideP;
- };
+class pkgCache::PrvIterator : public Iterator<Provides, PrvIterator> {
+ enum {PrvVer, PrvPkg} Type;
+
+ protected:
+ inline Provides* OwnerPointer() const {
+ return Owner->ProvideP;
+ };
+
+ public:
+ // Iteration
+ void operator ++(int) {if (S != Owner->ProvideP) S = Owner->ProvideP +
+ (Type == PrvVer?S->NextPkgProv:S->NextProvides);};
+ inline void operator ++() {operator ++(0);};
+
+ // Accessors
+ inline const char *Name() const {return Owner->StrP + Owner->PkgP[S->ParentPkg].Name;};
+ inline const char *ProvideVersion() const {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;};
+ inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+ inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + S->Version);};
+ inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->Version].ParentPkg);};
+
+ inline PrvIterator() : Iterator<Provides, PrvIterator>(), Type(PrvVer) {};
+
+ inline PrvIterator(pkgCache &Owner, Provides *Trg, Version*) :
+ Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvVer) {
+ if (S == 0)
+ S = Owner.ProvideP;
+ };
+ inline PrvIterator(pkgCache &Owner, Provides *Trg, Package*) :
+ Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvPkg) {
+ if (S == 0)
+ S = Owner.ProvideP;
+ };
};
/*}}}*/
// Package file /*{{{*/
-class pkgCache::PkgFileIterator
-{
- pkgCache *Owner;
- PackageFile *File;
-
- public:
-
- // Iteration
- void operator ++(int) {if (File!= Owner->PkgFileP) File = Owner->PkgFileP + File->NextFile;};
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || File == Owner->PkgFileP?true:false;};
-
- // Comparison
- inline bool operator ==(const PkgFileIterator &B) const {return File == B.File;};
- inline bool operator !=(const PkgFileIterator &B) const {return File != B.File;};
-
- // Accessors
- inline PackageFile *operator ->() {return File;};
- inline PackageFile const *operator ->() const {return File;};
- inline PackageFile const &operator *() const {return *File;};
- inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;};
- inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;};
- inline pkgCache *Cache() {return Owner;};
-
- inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;};
- inline const char *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;};
- inline const char *Component() const {return File->Component == 0?0:Owner->StrP + File->Component;};
- inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;};
- inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;};
- inline const char *Codename() const {return File->Codename ==0?0:Owner->StrP + File->Codename;};
- inline const char *Label() const {return File->Label == 0?0:Owner->StrP + File->Label;};
- inline const char *Site() const {return File->Site == 0?0:Owner->StrP + File->Site;};
- inline const char *Architecture() const {return File->Architecture == 0?0:Owner->StrP + File->Architecture;};
- inline const char *IndexType() const {return File->IndexType == 0?0:Owner->StrP + File->IndexType;};
-
- inline unsigned long Index() const {return File - Owner->PkgFileP;};
-
- bool IsOk();
- string RelStr();
-
- // Constructors
- inline PkgFileIterator() : Owner(0), File(0) {};
- inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP) {};
- inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {};
+class pkgCache::PkgFileIterator : public Iterator<PackageFile, PkgFileIterator> {
+ protected:
+ inline PackageFile* OwnerPointer() const {
+ return Owner->PkgFileP;
+ };
+
+ public:
+ // Iteration
+ void operator ++(int) {if (S != Owner->PkgFileP) S = Owner->PkgFileP + S->NextFile;};
+ inline void operator ++() {operator ++(0);};
+
+ // Accessors
+ inline const char *FileName() const {return S->FileName == 0?0:Owner->StrP + S->FileName;};
+ inline const char *Archive() const {return S->Archive == 0?0:Owner->StrP + S->Archive;};
+ inline const char *Component() const {return S->Component == 0?0:Owner->StrP + S->Component;};
+ inline const char *Version() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+ inline const char *Origin() const {return S->Origin == 0?0:Owner->StrP + S->Origin;};
+ inline const char *Codename() const {return S->Codename ==0?0:Owner->StrP + S->Codename;};
+ inline const char *Label() const {return S->Label == 0?0:Owner->StrP + S->Label;};
+ inline const char *Site() const {return S->Site == 0?0:Owner->StrP + S->Site;};
+ inline const char *Architecture() const {return S->Architecture == 0?0:Owner->StrP + S->Architecture;};
+ inline const char *IndexType() const {return S->IndexType == 0?0:Owner->StrP + S->IndexType;};
+
+ bool IsOk();
+ string RelStr();
+
+ // Constructors
+ inline PkgFileIterator() : Iterator<PackageFile, PkgFileIterator>() {};
+ inline PkgFileIterator(pkgCache &Owner) : Iterator<PackageFile, PkgFileIterator>(Owner, Owner.PkgFileP) {};
+ inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Iterator<PackageFile, PkgFileIterator>(Owner, Trg) {};
};
/*}}}*/
// Version File /*{{{*/
-class pkgCache::VerFileIterator
-{
- pkgCache *Owner;
- VerFile *FileP;
-
- public:
-
- // Iteration
- void operator ++(int) {if (FileP != Owner->VerFileP) FileP = Owner->VerFileP + FileP->NextFile;};
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || FileP == Owner->VerFileP?true:false;};
-
- // Comparison
- inline bool operator ==(const VerFileIterator &B) const {return FileP == B.FileP;};
- inline bool operator !=(const VerFileIterator &B) const {return FileP != B.FileP;};
-
- // Accessors
- inline VerFile *operator ->() {return FileP;};
- inline VerFile const *operator ->() const {return FileP;};
- inline VerFile const &operator *() const {return *FileP;};
- inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;};
- inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;};
- inline pkgCache *Cache() {return Owner;};
-
- inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
- inline unsigned long Index() const {return FileP - Owner->VerFileP;};
-
- inline VerFileIterator() : Owner(0), FileP(0) {};
- inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::VerFileIterator : public pkgCache::Iterator<VerFile, VerFileIterator> {
+ protected:
+ inline VerFile* OwnerPointer() const {
+ return Owner->VerFileP;
+ };
+
+ public:
+ // Iteration
+ void operator ++(int) {if (S != Owner->VerFileP) S = Owner->VerFileP + S->NextFile;};
+ inline void operator ++() {operator ++(0);};
+
+ // Accessors
+ inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+ inline VerFileIterator() : Iterator<VerFile, VerFileIterator>() {};
+ inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Iterator<VerFile, VerFileIterator>(Owner, Trg) {};
};
/*}}}*/
// Description File /*{{{*/
-class pkgCache::DescFileIterator
-{
- pkgCache *Owner;
- DescFile *FileP;
-
- public:
-
- // Iteration
- void operator ++(int) {if (FileP != Owner->DescFileP) FileP = Owner->DescFileP + FileP->NextFile;};
- inline void operator ++() {operator ++(0);};
- inline bool end() const {return Owner == 0 || FileP == Owner->DescFileP?true:false;};
-
- // Comparison
- inline bool operator ==(const DescFileIterator &B) const {return FileP == B.FileP;};
- inline bool operator !=(const DescFileIterator &B) const {return FileP != B.FileP;};
-
- // Accessors
- inline DescFile *operator ->() {return FileP;};
- inline DescFile const *operator ->() const {return FileP;};
- inline DescFile const &operator *() const {return *FileP;};
- inline operator DescFile *() {return FileP == Owner->DescFileP?0:FileP;};
- inline operator DescFile const *() const {return FileP == Owner->DescFileP?0:FileP;};
- inline pkgCache *Cache() {return Owner;};
-
- inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
- inline unsigned long Index() const {return FileP - Owner->DescFileP;};
-
- inline DescFileIterator() : Owner(0), FileP(0) {};
- inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::DescFileIterator : public Iterator<DescFile, DescFileIterator> {
+ protected:
+ inline DescFile* OwnerPointer() const {
+ return Owner->DescFileP;
+ };
+
+ public:
+ // Iteration
+ void operator ++(int) {if (S != Owner->DescFileP) S = Owner->DescFileP + S->NextFile;};
+ inline void operator ++() {operator ++(0);};
+
+ // Accessors
+ inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+ inline DescFileIterator() : Iterator<DescFile, DescFileIterator>() {};
+ inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Iterator<DescFile, DescFileIterator>(Owner, Trg) {};
};
/*}}}*/
// Inlined Begin functions cant be in the class because of order problems /*{{{*/
+inline pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const
+ {return PkgIterator(*Owner,Owner->PkgP + S->FirstPackage);};
inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
- {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);};
+ {return VerIterator(*Owner,Owner->VerP + S->VersionList);};
inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const
- {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);};
+ {return VerIterator(*Owner,Owner->VerP + S->CurrentVer);};
inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
- {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);};
+ {return DepIterator(*Owner,Owner->DepP + S->RevDepends,S);};
inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
- {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);};
+ {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const
- {return DescIterator(*Owner,Owner->DescP + Ver->DescriptionList);};
+ {return DescIterator(*Owner,Owner->DescP + S->DescriptionList);};
inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
- {return PrvIterator(*Owner,Owner->ProvideP + Ver->ProvidesList,Ver);};
+ {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
- {return DepIterator(*Owner,Owner->DepP + Ver->DependsList,Ver);};
+ {return DepIterator(*Owner,Owner->DepP + S->DependsList,S);};
inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
- {return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);};
+ {return VerFileIterator(*Owner,Owner->VerFileP + S->FileList);};
inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
- {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);};
+ {return DescFileIterator(*Owner,Owner->DescFileP + S->FileList);};
/*}}}*/
#endif
diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc
index 96d4e9c91..93deb49c4 100644
--- a/apt-pkg/cdrom.cc
+++ b/apt-pkg/cdrom.cc
@@ -6,6 +6,8 @@
#include<apt-pkg/cdromutl.h>
#include<apt-pkg/strutl.h>
#include<apt-pkg/cdrom.h>
+#include<apt-pkg/aptconfiguration.h>
+
#include<sstream>
#include<fstream>
#include<config.h>
@@ -216,33 +218,23 @@ int pkgCdrom::Score(string Path)
/* Here we drop everything that is not this machines arch */
bool pkgCdrom::DropBinaryArch(vector<string> &List)
{
- char S[300];
- snprintf(S,sizeof(S),"/binary-%s/",
- _config->Find("Apt::Architecture").c_str());
-
+
for (unsigned int I = 0; I < List.size(); I++)
{
const char *Str = List[I].c_str();
-
- const char *Res;
- if ((Res = strstr(Str,"/binary-")) == 0)
+ const char *Start, *End;
+ if ((Start = strstr(Str,"/binary-")) == 0)
continue;
- // Weird, remove it.
- if (strlen(Res) < strlen(S))
- {
- List.erase(List.begin() + I);
- I--;
- continue;
- }
-
- // See if it is our arch
- if (stringcmp(Res,Res + strlen(S),S) == 0)
- continue;
-
- // Erase it
+ // Between Start and End is the architecture
+ Start += 8;
+ if ((End = strstr(Start,"/")) != 0 && Start != End &&
+ APT::Configuration::checkArchitecture(string(Start, --End)) == true)
+ continue; // okay, architecture is accepted
+
+ // not accepted -> Erase it
List.erase(List.begin() + I);
- I--;
+ --I; // the next entry is at the same index after the erase
}
return true;
@@ -289,7 +281,8 @@ bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
List[J] = string();
}
}
-
+ delete[] Inodes;
+
// Wipe erased entries
for (unsigned int I = 0; I < List.size();)
{
diff --git a/apt-pkg/clean.cc b/apt-pkg/clean.cc
index 0d1dfbf74..629afd7cf 100644
--- a/apt-pkg/clean.cc
+++ b/apt-pkg/clean.cc
@@ -12,6 +12,7 @@
#include <apt-pkg/strutl.h>
#include <apt-pkg/error.h>
#include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apti18n.h>
@@ -26,7 +27,6 @@
bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
{
bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
- string MyArch = _config->Find("APT::Architecture");
DIR *D = opendir(Dir.c_str());
if (D == 0)
@@ -75,9 +75,9 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
for (I = Start; *I != 0 && *I != '.' ;I++);
if (*I != '.')
continue;
- string Arch = DeQuoteString(string(Start,I-Start));
+ string const Arch = DeQuoteString(string(Start,I-Start));
- if (Arch != "all" && Arch != MyArch)
+ if (APT::Configuration::checkArchitecture(Arch) == false)
continue;
// Lookup the package
diff --git a/apt-pkg/contrib/cmndline.cc b/apt-pkg/contrib/cmndline.cc
index bfd53695e..0b16bf51a 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[300];
+ unsigned int length = 0;
+ bool lastWasOption = false;
+ bool closeQuote = false;
+ for (unsigned int i = 0; i < argc; ++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 7588b041c..9129d92f0 100644
--- a/apt-pkg/contrib/configuration.cc
+++ b/apt-pkg/contrib/configuration.cc
@@ -773,6 +773,8 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
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
diff --git a/apt-pkg/contrib/error.h b/apt-pkg/contrib/error.h
index 90747ff7e..8d5ec05ea 100644
--- a/apt-pkg/contrib/error.h
+++ b/apt-pkg/contrib/error.h
@@ -60,13 +60,13 @@ class GlobalError
public:
// 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;
+ bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold;
+ bool WarningE(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;
+ bool Error(const char *Description,...) __like_printf(2) __cold;
+ bool Warning(const char *Description,...) __like_printf(2) __cold;
// Simple accessors
inline bool PendingError() {return PendingFlag;};
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index da32983f1..16f7ce929 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/apt-pkg/contrib/fileutl.cc
@@ -18,6 +18,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>
@@ -197,16 +198,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;
diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h
index 85a94898c..003bd9b83 100644
--- a/apt-pkg/contrib/fileutl.h
+++ b/apt-pkg/contrib/fileutl.h
@@ -21,6 +21,7 @@
#ifndef PKGLIB_FILEUTL_H
#define PKGLIB_FILEUTL_H
+#include <apt-pkg/macros.h>
#include <string>
#include <vector>
@@ -82,11 +83,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
+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);
-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 f440f9489..b3f29032c 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;
}
diff --git a/apt-pkg/contrib/mmap.h b/apt-pkg/contrib/mmap.h
index cd2b15ba2..5ca951204 100644
--- a/apt-pkg/contrib/mmap.h
+++ b/apt-pkg/contrib/mmap.h
@@ -44,6 +44,11 @@ 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);
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index 1b9922a31..c7d63ce8a 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -198,7 +198,8 @@ bool ParseQuoteWord(const char *&String,string &Res)
char *I;
for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
{
- if (*Start == '%' && Start + 2 < C)
+ if (*Start == '%' && Start + 2 < C &&
+ isxdigit(Start[1]) && isxdigit(Start[2]))
{
Tmp[0] = Start[1];
Tmp[1] = Start[2];
@@ -273,7 +274,8 @@ string QuoteString(const string &Str, const char *Bad)
for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
{
if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
- *I <= 0x20 || *I >= 0x7F)
+ *I == 0x25 || // percent '%' char
+ *I <= 0x20 || *I >= 0x7F) // control chars
{
char Buf[10];
sprintf(Buf,"%%%02x",(int)*I);
@@ -290,10 +292,16 @@ string QuoteString(const string &Str, const char *Bad)
/* This undoes QuoteString */
string DeQuoteString(const string &Str)
{
+ return DeQuoteString(Str.begin(),Str.end());
+}
+string DeQuoteString(string::const_iterator const &begin,
+ string::const_iterator const &end)
+{
string Res;
- for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
+ for (string::const_iterator I = begin; I != end; I++)
{
- if (*I == '%' && I + 2 < Str.end())
+ if (*I == '%' && I + 2 < end &&
+ isxdigit(I[1]) && isxdigit(I[2]))
{
char Tmp[3];
Tmp[0] = I[1];
@@ -566,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)
@@ -575,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;
}
@@ -584,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)
@@ -593,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;
}
@@ -601,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)
@@ -610,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;
}
@@ -789,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..
@@ -1000,12 +1008,12 @@ bool TokSplitString(char Tok,char *Input,char **List,
return true;
}
/*}}}*/
-// ExplodeString - Split a string up into a vector /*{{{*/
+// 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 an iteratable vector */
-vector<string> ExplodeString(string const &haystack, char const &split)
+ 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;
@@ -1133,10 +1141,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;
}
@@ -1235,9 +1246,10 @@ void URI::CopyFrom(const string &U)
else
{
Host.assign(At+1,SingleSlash);
- User.assign(FirstColon,SecondColon);
+ // username and password must be encoded (RFC 3986)
+ User.assign(DeQuoteString(FirstColon,SecondColon));
if (SecondColon < At)
- Password.assign(SecondColon+1,At);
+ Password.assign(DeQuoteString(SecondColon+1,At));
}
// Now we parse the RFC 2732 [] hostnames.
diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h
index e72288f4c..e509145f9 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);
@@ -45,6 +38,7 @@ bool ParseQuoteWord(const char *&String,string &Res);
bool ParseCWord(const char *&String,string &Res);
string QuoteString(const string &Str,const char *Bad);
string DeQuoteString(const string &Str);
+string DeQuoteString(string::const_iterator const &begin, string::const_iterator const &end);
string SizeToStr(double Bytes);
string TimeToStr(unsigned long Sec);
string Base64Encode(const string &Str);
@@ -59,12 +53,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);
-vector<string> ExplodeString(string const &haystack, char const &split);
-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 +138,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
diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc
index 7379ca997..b89429d86 100644
--- a/apt-pkg/deb/debindexfile.cc
+++ b/apt-pkg/deb/debindexfile.cc
@@ -149,9 +149,12 @@ unsigned long debSourcesIndex::Size() const
// PackagesIndex::debPackagesIndex - Contructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-debPackagesIndex::debPackagesIndex(string URI,string Dist,string Section,bool Trusted) :
- pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section)
+debPackagesIndex::debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+ bool const &Trusted, string const &Arch) :
+ pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section), Architecture(Arch)
{
+ if (Architecture == "native")
+ Architecture = _config->Find("APT::Architecture");
}
/*}}}*/
// PackagesIndex::ArchiveInfo - Short version of the archive url /*{{{*/
@@ -171,6 +174,8 @@ string debPackagesIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
Res += " ";
Res += Ver.ParentPkg().Name();
Res += " ";
+ Res += Ver.Arch();
+ Res += " ";
Res += Ver.VerStr();
return Res;
}
@@ -204,6 +209,8 @@ string debPackagesIndex::Info(const char *Type) const
else
Info += Dist + '/' + Section;
Info += " ";
+ Info += Architecture;
+ Info += " ";
Info += Type;
return Info;
}
@@ -227,7 +234,7 @@ string debPackagesIndex::IndexURI(const char *Type) const
}
else
Res = URI + "dists/" + Dist + '/' + Section +
- "/binary-" + _config->Find("APT::Architecture") + '/';
+ "/binary-" + Architecture + '/';
Res += Type;
return Res;
@@ -259,7 +266,7 @@ bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
{
string PackageFile = IndexFile("Packages");
FileFd Pkg(PackageFile,FileFd::ReadOnly);
- debListParser Parser(&Pkg);
+ debListParser Parser(&Pkg, Architecture);
if (_error->PendingError() == true)
return _error->Error("Problem opening %s",PackageFile.c_str());
diff --git a/apt-pkg/deb/debindexfile.h b/apt-pkg/deb/debindexfile.h
index c0e8d7d8e..766e8b214 100644
--- a/apt-pkg/deb/debindexfile.h
+++ b/apt-pkg/deb/debindexfile.h
@@ -46,6 +46,7 @@ class debPackagesIndex : public pkgIndexFile
string URI;
string Dist;
string Section;
+ string Architecture;
string Info(const char *Type) const;
string IndexFile(const char *Type) const;
@@ -69,7 +70,8 @@ class debPackagesIndex : public pkgIndexFile
virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
- debPackagesIndex(string URI,string Dist,string Section,bool Trusted);
+ debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+ bool const &Trusted, string const &Arch = "native");
};
class debTranslationsIndex : public pkgIndexFile
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 66108d822..0551a5f7c 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -31,10 +31,13 @@ static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Impor
// ListParser::debListParser - Constructor /*{{{*/
// ---------------------------------------------------------------------
-/* */
-debListParser::debListParser(FileFd *File) : Tags(File)
-{
- Arch = _config->Find("APT::architecture");
+/* Provide an architecture and only this one and "all" will be accepted
+ in Step(), if no Architecture is given we will accept every arch
+ we would accept in general with checkArchitecture() */
+debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
+ Arch(Arch) {
+ if (Arch == "native")
+ this->Arch = _config->Find("APT::Architecture");
}
/*}}}*/
// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
@@ -52,14 +55,41 @@ unsigned long debListParser::UniqFindTagWrite(const char *Tag)
// ListParser::Package - Return the package name /*{{{*/
// ---------------------------------------------------------------------
/* This is to return the name of the package this section describes */
-string debListParser::Package()
-{
- string Result = Section.FindS("Package");
- if (Result.empty() == true)
+string debListParser::Package() {
+ string const Result = Section.FindS("Package");
+ if(unlikely(Result.empty() == true))
_error->Error("Encountered a section with no Package: header");
return Result;
}
/*}}}*/
+// ListParser::Architecture - Return the package arch /*{{{*/
+// ---------------------------------------------------------------------
+/* This will return the Architecture of the package this section describes
+ Note that architecture "all" packages will get the architecture of the
+ Packages file parsed here. */
+string debListParser::Architecture() {
+ string const Result = Section.FindS("Architecture");
+ if (Result.empty() == true || Result == "all")
+ {
+ if (Arch.empty() == true)
+ /* FIXME: this is a problem for installed arch all
+ packages as we don't know from which arch this
+ package was installed - and therefore which
+ dependency this package resolves. */
+ return _config->Find("APT::Architecture");
+ else
+ return Arch;
+ }
+ return Result;
+}
+ /*}}}*/
+// ListParser::ArchitectureAll /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debListParser::ArchitectureAll() {
+ return Section.FindS("Architecture") == "all";
+}
+ /*}}}*/
// ListParser::Version - Return the version string /*{{{*/
// ---------------------------------------------------------------------
/* This is to return the string describing the version in debian form,
@@ -77,8 +107,31 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
{
// Parse the section
Ver->Section = UniqFindTagWrite("Section");
- Ver->Arch = UniqFindTagWrite("Architecture");
-
+
+ // Parse multi-arch
+ if (Section.FindS("Architecture") == "all")
+ /* Arch all packages can't have a Multi-Arch field,
+ but we need a special treatment for them nonetheless */
+ Ver->MultiArch = pkgCache::Version::All;
+ else
+ {
+ string const MultiArch = Section.FindS("Multi-Arch");
+ if (MultiArch.empty() == true)
+ Ver->MultiArch = pkgCache::Version::None;
+ else if (MultiArch == "same")
+ Ver->MultiArch = pkgCache::Version::Same;
+ else if (MultiArch == "foreign")
+ Ver->MultiArch = pkgCache::Version::Foreign;
+ else if (MultiArch == "allowed")
+ Ver->MultiArch = pkgCache::Version::Allowed;
+ else
+ {
+ _error->Warning("Unknown Multi-Arch type »%s« for package »%s«",
+ MultiArch.c_str(), Section.FindS("Package").c_str());
+ Ver->MultiArch = pkgCache::Version::None;
+ }
+ }
+
// Archive Size
Ver->Size = (unsigned)Section.FindI("Size");
@@ -95,6 +148,25 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
Ver->Priority = pkgCache::State::Extra;
}
+ if (Ver->MultiArch == pkgCache::Version::All)
+ {
+ /* We maintain a "pseudo" arch=all package for architecture all versions
+ on which these versions can depend on. This pseudo package is many used
+ for downloading/installing: The other pseudo-packages will degenerate
+ to a NOP in the download/install step - this package will ensure that
+ it is downloaded only one time and installed only one time -- even if
+ the architecture bound versions coming in and out on regular basis. */
+ bool const static multiArch = APT::Configuration::getArchitectures().size() > 1;
+ if (strcmp(Ver.Arch(true),"all") == 0)
+ return true;
+ else if (multiArch == true)
+ {
+ // our pseudo packages have no size to not confuse the fetcher
+ Ver->Size = 0;
+ Ver->InstalledSize = 0;
+ }
+ }
+
if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
return false;
if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
@@ -183,8 +255,16 @@ bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
{
if (Pkg->Section == 0)
Pkg->Section = UniqFindTagWrite("Section");
- if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
- return false;
+
+ // Packages which are not from the "native" arch doesn't get the essential flag
+ // in the default "native" mode - it is also possible to mark "all" or "none".
+ // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
+ string const static myArch = _config->Find("APT::Architecture");
+ string const static essential = _config->Find("pkgCacheGen::Essential", "native");
+ if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
+ essential == "all")
+ if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+ return false;
if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
return false;
@@ -258,7 +338,13 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
const char *Stop;
if (Section.Find("Status",Start,Stop) == false)
return true;
-
+
+ // UsePackage() is responsible for setting the flag in the default case
+ bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
+ if (essential == true &&
+ Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+ return false;
+
// Isolate the first word
const char *I = Start;
for(; I < Stop && *I != ' '; I++);
@@ -534,8 +620,12 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
const char *Stop;
if (Section.Find(Tag,Start,Stop) == false)
return true;
-
+
+ static std::vector<std::string> const archs = APT::Configuration::getArchitectures();
+ static bool const multiArch = archs.size() <= 1;
+
string Package;
+ string const pkgArch = Ver.Arch(true);
string Version;
unsigned int Op;
@@ -544,8 +634,18 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
Start = ParseDepends(Start,Stop,Package,Version,Op);
if (Start == 0)
return _error->Error("Problem parsing dependency %s",Tag);
-
- if (NewDepends(Ver,Package,Version,Op,Type) == false)
+
+ if (multiArch == true &&
+ (Type == pkgCache::Dep::Conflicts ||
+ Type == pkgCache::Dep::DpkgBreaks ||
+ Type == pkgCache::Dep::Replaces))
+ {
+ for (std::vector<std::string>::const_iterator a = archs.begin();
+ a != archs.end(); ++a)
+ if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
+ return false;
+ }
+ else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
return false;
if (Start == Stop)
break;
@@ -560,29 +660,52 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
{
const char *Start;
const char *Stop;
- if (Section.Find("Provides",Start,Stop) == false)
- return true;
-
- string Package;
- string Version;
- unsigned int Op;
-
- while (1)
+ if (Section.Find("Provides",Start,Stop) == true)
{
- Start = ParseDepends(Start,Stop,Package,Version,Op);
- if (Start == 0)
- return _error->Error("Problem parsing Provides line");
- if (Op != pkgCache::Dep::NoOp) {
- _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
- } else {
- if (NewProvides(Ver,Package,Version) == false)
- return false;
+ string Package;
+ string Version;
+ string const Arch = Ver.Arch(true);
+ unsigned int Op;
+
+ while (1)
+ {
+ Start = ParseDepends(Start,Stop,Package,Version,Op);
+ if (Start == 0)
+ return _error->Error("Problem parsing Provides line");
+ if (Op != pkgCache::Dep::NoOp) {
+ _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
+ } else {
+ if (NewProvides(Ver, Package, Arch, Version) == false)
+ return false;
+ }
+
+ if (Start == Stop)
+ break;
}
+ }
- if (Start == Stop)
- break;
+ if (Ver->MultiArch == pkgCache::Version::Allowed)
+ {
+ string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
+ NewProvides(Ver, Package, "any", Ver.VerStr());
}
-
+
+ if (Ver->MultiArch != pkgCache::Version::Foreign)
+ return true;
+
+ std::vector<string> const archs = APT::Configuration::getArchitectures();
+ if (archs.size() <= 1)
+ return true;
+
+ string const Package = Ver.ParentPkg().Name();
+ string const Version = Ver.VerStr();
+ for (std::vector<string>::const_iterator a = archs.begin();
+ a != archs.end(); ++a)
+ {
+ if (NewProvides(Ver, Package, *a, Version) == false)
+ return false;
+ }
+
return true;
}
/*}}}*/
@@ -613,16 +736,23 @@ bool debListParser::Step()
/* See if this is the correct Architecture, if it isn't then we
drop the whole section. A missing arch tag only happens (in theory)
inside the Status file, so that is a positive return */
- const char *Start;
- const char *Stop;
- if (Section.Find("Architecture",Start,Stop) == false)
+ string const Architecture = Section.FindS("Architecture");
+ if (Architecture.empty() == true)
return true;
- if (stringcmp(Arch,Start,Stop) == 0)
- return true;
+ if (Arch.empty() == true)
+ {
+ if (APT::Configuration::checkArchitecture(Architecture) == true)
+ return true;
+ }
+ else
+ {
+ if (Architecture == Arch)
+ return true;
- if (stringcmp(Start,Stop,"all") == 0)
- return true;
+ if (Architecture == "all")
+ return true;
+ }
iOffset = Tags.Offset();
}
@@ -640,8 +770,9 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
if (Tags.Step(Section) == false)
return false;
- //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
- //FileI->Architecture = WriteUniqString(Arch);
+ // FIXME: Do we need it now for multi-arch?
+ // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
+// FileI->Architecture = WriteUniqString(Arch);
// apt-secure does no longer download individual (per-section) Release
// file. to provide Component pinning we use the section name now
diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h
index 1c709229f..8da051530 100644
--- a/apt-pkg/deb/deblistparser.h
+++ b/apt-pkg/deb/deblistparser.h
@@ -46,6 +46,8 @@ class debListParser : public pkgCacheGenerator::ListParser
// These all operate against the current section
virtual string Package();
+ virtual string Architecture();
+ virtual bool ArchitectureAll();
virtual string Version();
virtual bool NewVersion(pkgCache::VerIterator Ver);
virtual string Description();
@@ -68,7 +70,7 @@ class debListParser : public pkgCacheGenerator::ListParser
bool const &StripMultiArch = false);
static const char *ConvertRelation(const char *I,unsigned int &Op);
- debListParser(FileFd *File);
+ debListParser(FileFd *File, string const &Arch = "");
};
#endif
diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc
index 520e94a80..8df3ed18d 100644
--- a/apt-pkg/deb/debmetaindex.cc
+++ b/apt-pkg/deb/debmetaindex.cc
@@ -8,9 +8,11 @@
#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/error.h>
+#include <set>
+
using namespace std;
-string debReleaseIndex::Info(const char *Type, const string Section) const
+string debReleaseIndex::Info(const char *Type, string const &Section, string const &Arch) const
{
string Info = ::URI::SiteOnly(URI) + ' ';
if (Dist[Dist.size() - 1] == '/')
@@ -19,7 +21,11 @@ string debReleaseIndex::Info(const char *Type, const string Section) const
Info += Dist;
}
else
- Info += Dist + '/' + Section;
+ {
+ Info += Dist + '/' + Section;
+ if (Arch.empty() == true)
+ Info += " " + Arch;
+ }
Info += " ";
Info += Type;
return Info;
@@ -61,16 +67,21 @@ string debReleaseIndex::MetaIndexURI(const char *Type) const
return Res;
}
-string debReleaseIndex::IndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::IndexURISuffix(const char *Type, string const &Section, string const &Arch) const
{
string Res ="";
if (Dist[Dist.size() - 1] != '/')
- Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+ {
+ if (Arch == "native")
+ Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+ else
+ Res += Section + "/binary-" + Arch + '/';
+ }
return Res + Type;
}
-string debReleaseIndex::IndexURI(const char *Type, const string Section) const
+string debReleaseIndex::IndexURI(const char *Type, string const &Section, string const &Arch) const
{
if (Dist[Dist.size() - 1] == '/')
{
@@ -82,10 +93,10 @@ string debReleaseIndex::IndexURI(const char *Type, const string Section) const
return Res + Type;
}
else
- return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section);
+ return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section, Arch);
}
-string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string &Section) const
{
string Res ="";
if (Dist[Dist.size() - 1] != '/')
@@ -93,7 +104,7 @@ string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Sect
return Res + Type;
}
-string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURI(const char *Type, const string &Section) const
{
string Res;
if (Dist[Dist.size() - 1] == '/')
@@ -108,44 +119,61 @@ string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) c
return URI + "dists/" + Dist + "/" + SourceIndexURISuffix(Type, Section);
}
-debReleaseIndex::debReleaseIndex(string URI,string Dist)
-{
- this->URI = URI;
- this->Dist = Dist;
- this->Indexes = NULL;
- this->Type = "deb";
+debReleaseIndex::debReleaseIndex(string const &URI, string const &Dist) {
+ this->URI = URI;
+ this->Dist = Dist;
+ this->Indexes = NULL;
+ this->Type = "deb";
}
-debReleaseIndex::~debReleaseIndex()
-{
- for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
- I != SectionEntries.end(); I++)
- delete *I;
+debReleaseIndex::~debReleaseIndex() {
+ for (map<string, vector<debSectionEntry const*> >::const_iterator A = ArchEntries.begin();
+ A != ArchEntries.end(); ++A)
+ for (vector<const debSectionEntry *>::const_iterator S = A->second.begin();
+ S != A->second.end(); ++S)
+ delete *S;
}
-vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const
-{
- vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
- for (vector <const debSectionEntry *>::const_iterator I = SectionEntries.begin();
- I != SectionEntries.end();
- I++)
- {
- IndexTarget * Target = new IndexTarget();
- Target->ShortDesc = (*I)->IsSrc ? "Sources" : "Packages";
- Target->MetaKey
- = (*I)->IsSrc ? SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section)
- : IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
- Target->URI
- = (*I)->IsSrc ? SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section)
- : IndexURI(Target->ShortDesc.c_str(), (*I)->Section);
-
- Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
- IndexTargets->push_back (Target);
- }
- return IndexTargets;
+vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
+ vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
+
+ map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+ if (src != ArchEntries.end()) {
+ vector<debSectionEntry const*> const SectionEntries = src->second;
+ for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+ I != SectionEntries.end(); ++I) {
+ IndexTarget * Target = new IndexTarget();
+ Target->ShortDesc = "Sources";
+ Target->MetaKey = SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
+ Target->URI = SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section);
+ Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
+ IndexTargets->push_back (Target);
+ }
+ }
+
+ // Only source release
+ if (IndexTargets->empty() == false && ArchEntries.size() == 1)
+ return IndexTargets;
+
+ for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+ a != ArchEntries.end(); ++a) {
+ if (a->first == "source")
+ continue;
+ for (vector <const debSectionEntry *>::const_iterator I = a->second.begin();
+ I != a->second.end(); ++I) {
+ IndexTarget * Target = new IndexTarget();
+ Target->ShortDesc = "Packages";
+ Target->MetaKey = IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+ Target->URI = IndexURI(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+ Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section, a->first);
+ IndexTargets->push_back (Target);
+ }
+ }
+
+ return IndexTargets;
}
/*}}}*/
-bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
+bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
{
// special case for --print-uris
if (GetAll) {
@@ -170,24 +198,28 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
ComputeIndexTargets(),
new indexRecords (Dist));
- // Queue the translations
- std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
- for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
- I != SectionEntries.end(); I++) {
-
- if((*I)->IsSrc)
- continue;
-
- for (vector<string>::const_iterator l = lang.begin();
- l != lang.end(); l++)
- {
- if (*l == "none") continue;
- debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str());
- i.GetIndexes(Owner);
- }
- }
-
- return true;
+ // Queue the translations
+ std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+ map<string, set<string> > sections;
+ for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+ a != ArchEntries.end(); ++a) {
+ if (a->first == "source")
+ continue;
+ for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+ I != a->second.end(); I++)
+ sections[(*I)->Section].insert(lang.begin(), lang.end());
+ }
+
+ for (map<string, set<string> >::const_iterator s = sections.begin();
+ s != sections.end(); ++s)
+ for (set<string>::const_iterator l = s->second.begin();
+ l != s->second.end(); l++) {
+ if (*l == "none") continue;
+ debTranslationsIndex i = debTranslationsIndex(URI,Dist,s->first,(*l).c_str());
+ i.GetIndexes(Owner);
+ }
+
+ return true;
}
bool debReleaseIndex::IsTrusted() const
@@ -204,73 +236,113 @@ bool debReleaseIndex::IsTrusted() const
return false;
}
-vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
-{
- if (Indexes != NULL)
- return Indexes;
-
- Indexes = new vector <pkgIndexFile*>;
- std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
- for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
- I != SectionEntries.end(); I++) {
- if ((*I)->IsSrc)
- Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
- else
- {
- Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-
- for (vector<string>::const_iterator l = lang.begin();
- l != lang.end(); l++) {
- if (*l == "none") continue;
- Indexes->push_back(new debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str()));
- }
- }
- }
+vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() {
+ if (Indexes != NULL)
+ return Indexes;
+
+ Indexes = new vector <pkgIndexFile*>;
+ map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+ if (src != ArchEntries.end()) {
+ vector<debSectionEntry const*> const SectionEntries = src->second;
+ for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+ I != SectionEntries.end(); I++)
+ Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
+ }
+
+ // Only source release
+ if (Indexes->empty() == false && ArchEntries.size() == 1)
+ return Indexes;
+
+ std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+ map<string, set<string> > sections;
+ for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+ a != ArchEntries.end(); ++a) {
+ if (a->first == "source")
+ continue;
+ for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+ I != a->second.end(); I++) {
+ Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted(), a->first));
+ sections[(*I)->Section].insert(lang.begin(), lang.end());
+ }
+ }
+
+ for (map<string, set<string> >::const_iterator s = sections.begin();
+ s != sections.end(); ++s)
+ for (set<string>::const_iterator l = s->second.begin();
+ l != s->second.end(); l++) {
+ if (*l == "none") continue;
+ Indexes->push_back(new debTranslationsIndex(URI,Dist,s->first,(*l).c_str()));
+ }
+
+ return Indexes;
+}
- return Indexes;
+void debReleaseIndex::PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry) {
+ for (vector<string>::const_iterator a = Archs.begin();
+ a != Archs.end(); ++a)
+ ArchEntries[*a].push_back(new debSectionEntry(Entry->Section, Entry->IsSrc));
+ delete Entry;
}
-void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry)
-{
- SectionEntries.push_back(Entry);
+void debReleaseIndex::PushSectionEntry(string const &Arch, const debSectionEntry *Entry) {
+ ArchEntries[Arch].push_back(Entry);
}
-debReleaseIndex::debSectionEntry::debSectionEntry (string Section, bool IsSrc): Section(Section)
-{
- this->IsSrc = IsSrc;
+void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry) {
+ if (Entry->IsSrc == true)
+ PushSectionEntry("source", Entry);
+ else {
+ for (map<string, vector<const debSectionEntry *> >::iterator a = ArchEntries.begin();
+ a != ArchEntries.end(); ++a) {
+ a->second.push_back(Entry);
+ }
+ }
}
+debReleaseIndex::debSectionEntry::debSectionEntry (string const &Section,
+ bool const &IsSrc): Section(Section), IsSrc(IsSrc)
+{}
+
class debSLTypeDebian : public pkgSourceList::Type
{
protected:
- bool CreateItemInternal(vector<metaIndex *> &List,string URI,
- string Dist,string Section,
- bool IsSrc) const
+ bool CreateItemInternal(vector<metaIndex *> &List, string const &URI,
+ string const &Dist, string const &Section,
+ bool const &IsSrc, map<string, string> const &Options) const
{
- for (vector<metaIndex *>::const_iterator I = List.begin();
+ map<string, string>::const_iterator const arch = Options.find("arch");
+ vector<string> const Archs =
+ (arch != Options.end()) ? VectorizeString(arch->second, ',') :
+ APT::Configuration::getArchitectures();
+
+ for (vector<metaIndex *>::const_iterator I = List.begin();
I != List.end(); I++)
{
- // This check insures that there will be only one Release file
- // queued for all the Packages files and Sources files it
- // corresponds to.
- if (strcmp((*I)->GetType(), "deb") == 0)
+ // We only worry about debian entries here
+ if (strcmp((*I)->GetType(), "deb") != 0)
+ continue;
+
+ debReleaseIndex *Deb = (debReleaseIndex *) (*I);
+ /* This check insures that there will be only one Release file
+ queued for all the Packages files and Sources files it
+ corresponds to. */
+ if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
{
- debReleaseIndex *Deb = (debReleaseIndex *) (*I);
- // This check insures that there will be only one Release file
- // queued for all the Packages files and Sources files it
- // corresponds to.
- if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
- {
- Deb->PushSectionEntry(new debReleaseIndex::debSectionEntry(Section, IsSrc));
- return true;
- }
+ if (IsSrc == true)
+ Deb->PushSectionEntry("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+ else
+ Deb->PushSectionEntry(Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
+ return true;
}
}
// No currently created Release file indexes this entry, so we create a new one.
// XXX determine whether this release is trusted or not
- debReleaseIndex *Deb = new debReleaseIndex(URI,Dist);
- Deb->PushSectionEntry (new debReleaseIndex::debSectionEntry(Section, IsSrc));
+ debReleaseIndex *Deb = new debReleaseIndex(URI, Dist);
+ if (IsSrc == true)
+ Deb->PushSectionEntry ("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+ else
+ Deb->PushSectionEntry (Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
List.push_back(Deb);
return true;
}
@@ -280,10 +352,11 @@ class debSLTypeDeb : public debSLTypeDebian
{
public:
- bool CreateItem(vector<metaIndex *> &List,string URI,
- string Dist,string Section) const
+ bool CreateItem(vector<metaIndex *> &List, string const &URI,
+ string const &Dist, string const &Section,
+ std::map<string, string> const &Options) const
{
- return CreateItemInternal(List, URI, Dist, Section, false);
+ return CreateItemInternal(List, URI, Dist, Section, false, Options);
}
debSLTypeDeb()
@@ -297,10 +370,11 @@ class debSLTypeDebSrc : public debSLTypeDebian
{
public:
- bool CreateItem(vector<metaIndex *> &List,string URI,
- string Dist,string Section) const
+ bool CreateItem(vector<metaIndex *> &List, string const &URI,
+ string const &Dist, string const &Section,
+ std::map<string, string> const &Options) const
{
- return CreateItemInternal(List, URI, Dist, Section, true);
+ return CreateItemInternal(List, URI, Dist, Section, true, Options);
}
debSLTypeDebSrc()
diff --git a/apt-pkg/deb/debmetaindex.h b/apt-pkg/deb/debmetaindex.h
index 8e6a1463b..360fa5419 100644
--- a/apt-pkg/deb/debmetaindex.h
+++ b/apt-pkg/deb/debmetaindex.h
@@ -5,40 +5,44 @@
#include <apt-pkg/metaindex.h>
#include <apt-pkg/sourcelist.h>
+#include <map>
+
class debReleaseIndex : public metaIndex {
public:
class debSectionEntry
{
public:
- debSectionEntry (string Section, bool IsSrc);
- bool IsSrc;
- string Section;
+ debSectionEntry (string const &Section, bool const &IsSrc);
+ string const Section;
+ bool const IsSrc;
};
private:
- vector <const debSectionEntry *> SectionEntries;
+ std::map<string, vector<debSectionEntry const*> > ArchEntries;
public:
- debReleaseIndex(string URI, string Dist);
+ debReleaseIndex(string const &URI, string const &Dist);
~debReleaseIndex();
- virtual string ArchiveURI(string File) const {return URI + File;};
- virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const;
+ virtual string ArchiveURI(string const &File) const {return URI + File;};
+ virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const;
vector <struct IndexTarget *>* ComputeIndexTargets() const;
- string Info(const char *Type, const string Section) const;
+ string Info(const char *Type, string const &Section, string const &Arch="") const;
string MetaIndexInfo(const char *Type) const;
string MetaIndexFile(const char *Types) const;
string MetaIndexURI(const char *Type) const;
- string IndexURI(const char *Type, const string Section) const;
- string IndexURISuffix(const char *Type, const string Section) const;
- string SourceIndexURI(const char *Type, const string Section) const;
- string SourceIndexURISuffix(const char *Type, const string Section) const;
+ string IndexURI(const char *Type, string const &Section, string const &Arch="native") const;
+ string IndexURISuffix(const char *Type, string const &Section, string const &Arch="native") const;
+ string SourceIndexURI(const char *Type, const string &Section) const;
+ string SourceIndexURISuffix(const char *Type, const string &Section) const;
virtual vector <pkgIndexFile *> *GetIndexFiles();
virtual bool IsTrusted() const;
+ void PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry);
+ void PushSectionEntry(string const &Arch, const debSectionEntry *Entry);
void PushSectionEntry(const debSectionEntry *Entry);
};
diff --git a/apt-pkg/deb/debversion.cc b/apt-pkg/deb/debversion.cc
index ad45e9a44..755ffbe96 100644
--- a/apt-pkg/deb/debversion.cc
+++ b/apt-pkg/deb/debversion.cc
@@ -190,8 +190,22 @@ int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
dlhs++;
if (drhs != rhs)
drhs++;
-
- return CmpFragment(dlhs,AEnd,drhs,BEnd);
+
+ // no debian revision need to be treated like -0
+ if (*(dlhs-1) == '-' && *(drhs-1) == '-')
+ return CmpFragment(dlhs,AEnd,drhs,BEnd);
+ else if (*(dlhs-1) == '-')
+ {
+ const char* null = "0";
+ return CmpFragment(dlhs,AEnd,null, null+1);
+ }
+ else if (*(drhs-1) == '-')
+ {
+ const char* null = "0";
+ return CmpFragment(null, null+1, drhs, BEnd);
+ }
+ else
+ return 0;
}
/*}}}*/
// debVS::CheckDep - Check a single dependency /*{{{*/
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc
index 5b02cae1d..ca8faa8a5 100644
--- a/apt-pkg/deb/dpkgpm.cc
+++ b/apt-pkg/deb/dpkgpm.cc
@@ -105,7 +105,7 @@ ionice(int PID)
/* */
pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache)
: pkgPackageManager(Cache), dpkgbuf_pos(0),
- term_out(NULL), PackagesDone(0), PackagesTotal(0)
+ term_out(NULL), history_out(NULL), PackagesDone(0), PackagesTotal(0)
{
}
/*}}}*/
@@ -124,7 +124,19 @@ bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
if (File.empty() == true || Pkg.end() == true)
return _error->Error("Internal Error, No file name for %s",Pkg.Name());
- List.push_back(Item(Item::Install,Pkg,File));
+ // If the filename string begins with DPkg::Chroot-Directory, return the
+ // substr that is within the chroot so dpkg can access it.
+ string const chrootdir = _config->FindDir("DPkg::Chroot-Directory","/");
+ if (chrootdir != "/" && File.find(chrootdir) == 0)
+ {
+ size_t len = chrootdir.length();
+ if (chrootdir.at(len - 1) == '/')
+ len--;
+ List.push_back(Item(Item::Install,Pkg,File.substr(len)));
+ }
+ else
+ List.push_back(Item(Item::Install,Pkg,File));
+
return true;
}
/*}}}*/
@@ -564,35 +576,37 @@ void pkgDPkgPM::WriteHistoryTag(string tag, string value)
// DPkgPM::OpenLog /*{{{*/
bool pkgDPkgPM::OpenLog()
{
- string logdir = _config->FindDir("Dir::Log");
+ string const logdir = _config->FindDir("Dir::Log");
if(not FileExists(logdir))
return _error->Error(_("Directory '%s' missing"), logdir.c_str());
// get current time
char timestr[200];
- time_t t = time(NULL);
- struct tm *tmp = localtime(&t);
+ time_t const t = time(NULL);
+ struct tm const * const tmp = localtime(&t);
strftime(timestr, sizeof(timestr), "%F %T", tmp);
// open terminal log
- string logfile_name = flCombine(logdir,
+ string const logfile_name = flCombine(logdir,
_config->Find("Dir::Log::Terminal"));
if (!logfile_name.empty())
{
term_out = fopen(logfile_name.c_str(),"a");
if (term_out == NULL)
- return _error->WarningE(_("Could not open file '%s'"), logfile_name.c_str());
+ return _error->WarningE("OpenLog", _("Could not open file '%s'"), logfile_name.c_str());
chmod(logfile_name.c_str(), 0600);
fprintf(term_out, "\nLog started: %s\n", timestr);
}
- // write
- string history_name = flCombine(logdir,
+ // write your history
+ string const history_name = flCombine(logdir,
_config->Find("Dir::Log::History"));
if (!history_name.empty())
{
history_out = fopen(history_name.c_str(),"a");
+ if (history_out == NULL)
+ return _error->WarningE("OpenLog", _("Could not open file '%s'"), history_name.c_str());
chmod(history_name.c_str(), 0644);
fprintf(history_out, "\nStart-Date: %s\n", timestr);
string remove, purge, install, upgrade, downgrade;
@@ -612,6 +626,8 @@ bool pkgDPkgPM::OpenLog()
remove += I.Name() + string(" (") + Cache[I].CurVersion + string("), ");
}
}
+ if (_config->Exists("Commandline::AsString") == true)
+ WriteHistoryTag("Commandline", _config->Find("Commandline::AsString"));
WriteHistoryTag("Install", install);
WriteHistoryTag("Upgrade", upgrade);
WriteHistoryTag("Downgrade",downgrade);
@@ -647,6 +663,7 @@ bool pkgDPkgPM::CloseLog()
fprintf(history_out, "End-Date: %s\n", timestr);
fclose(history_out);
}
+ history_out = NULL;
return true;
}
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index 0f30f13c2..4d1a08eb6 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -17,6 +17,7 @@
#include <apt-pkg/fileutl.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/tagfile.h>
@@ -164,34 +165,46 @@ bool pkgDepCache::Init(OpProgress *Prog)
bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/
{
FileFd state_file;
- string state = _config->FindDir("Dir::State") + "extended_states";
+ string const state = _config->FindDir("Dir::State") + "extended_states";
if(FileExists(state)) {
state_file.Open(state, FileFd::ReadOnly);
- int file_size = state_file.Size();
+ int const file_size = state_file.Size();
if(Prog != NULL)
Prog->OverallProgress(0, file_size, 1,
_("Reading state information"));
pkgTagFile tagfile(&state_file);
pkgTagSection section;
- int amt=0;
- bool debug_autoremove=_config->FindB("Debug::pkgAutoRemove",false);
+ int amt = 0;
+ bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
while(tagfile.Step(section)) {
- string pkgname = section.FindS("Package");
- pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
- // Silently ignore unknown packages and packages with no actual
- // version.
- if(!pkg.end() && !pkg.VersionList().end()) {
- short reason = section.FindI("Auto-Installed", 0);
- if(reason > 0)
- PkgState[pkg->ID].Flags |= Flag::Auto;
- if(debug_autoremove)
- std::clog << "Auto-Installed : " << pkgname << std::endl;
- amt+=section.size();
- if(Prog != NULL)
- Prog->OverallProgress(amt, file_size, 1,
- _("Reading state information"));
+ string const pkgname = section.FindS("Package");
+ string pkgarch = section.FindS("Architecture");
+ if (pkgarch.empty() == true)
+ pkgarch = "any";
+ pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
+ // Silently ignore unknown packages and packages with no actual version.
+ if(pkg.end() == true || pkg->VersionList == 0)
+ continue;
+
+ short const reason = section.FindI("Auto-Installed", 0);
+ if(reason > 0)
+ {
+ PkgState[pkg->ID].Flags |= Flag::Auto;
+ if (unlikely(debug_autoremove))
+ std::clog << "Auto-Installed : " << pkg.FullName() << std::endl;
+ if (pkgarch == "any")
+ {
+ pkgCache::GrpIterator G = pkg.Group();
+ for (pkg = G.NextPkg(pkg); pkg.end() != true; pkg = G.NextPkg(pkg))
+ if (pkg->VersionList != 0)
+ PkgState[pkg->ID].Flags |= Flag::Auto;
+ }
}
+ amt += section.size();
+ if(Prog != NULL)
+ Prog->OverallProgress(amt, file_size, 1,
+ _("Reading state information"));
}
if(Prog != NULL)
Prog->OverallProgress(file_size, file_size, 1,
@@ -203,13 +216,13 @@ bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/
/*}}}*/
bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/
{
- bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+ bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
if(debug_autoremove)
std::clog << "pkgDepCache::writeStateFile()" << std::endl;
FileFd StateFile;
- string state = _config->FindDir("Dir::State") + "extended_states";
+ string const state = _config->FindDir("Dir::State") + "extended_states";
// if it does not exist, create a empty one
if(!FileExists(state))
@@ -224,7 +237,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/
state.c_str());
FILE *OutFile;
- string outfile = state + ".tmp";
+ string const outfile = state + ".tmp";
if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
return _error->Error(_("Failed to write temporary StateFile %s"),
outfile.c_str());
@@ -235,46 +248,72 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/
std::set<string> pkgs_seen;
const char *nullreorderlist[] = {0};
while(tagfile.Step(section)) {
- string pkgname = section.FindS("Package");
+ string const pkgname = section.FindS("Package");
+ string pkgarch = section.FindS("Architecture");
+ if (pkgarch.empty() == true)
+ pkgarch = "native";
// Silently ignore unknown packages and packages with no actual
// version.
- pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
+ pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
if(pkg.end() || pkg.VersionList().end())
continue;
- bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto);
+ StateCache const &P = PkgState[pkg->ID];
+ bool newAuto = (P.Flags & Flag::Auto);
+ // skip not installed or now-removed ones if requested
+ if (InstalledOnly && (
+ (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+ (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+ {
+ // The section is obsolete if it contains no other tag
+ unsigned int const count = section.Count();
+ if (count < 2 ||
+ (count == 2 && section.Exists("Auto-Installed")) ||
+ (count == 3 && section.Exists("Auto-Installed") && section.Exists("Architecture")))
+ continue;
+ else
+ newAuto = false;
+ }
if(_config->FindB("Debug::pkgAutoRemove",false))
std::clog << "Update existing AutoInstall info: "
- << pkg.Name() << std::endl;
- TFRewriteData rewrite[2];
- rewrite[0].Tag = "Auto-Installed";
- rewrite[0].Rewrite = newAuto ? "1" : "0";
+ << pkg.FullName() << std::endl;
+ TFRewriteData rewrite[3];
+ rewrite[0].Tag = "Architecture";
+ rewrite[0].Rewrite = pkg.Arch();
rewrite[0].NewTag = 0;
- rewrite[1].Tag = 0;
+ rewrite[1].Tag = "Auto-Installed";
+ rewrite[1].Rewrite = newAuto ? "1" : "0";
+ rewrite[1].NewTag = 0;
+ rewrite[2].Tag = 0;
TFRewrite(OutFile, section, nullreorderlist, rewrite);
fprintf(OutFile,"\n");
- pkgs_seen.insert(pkgname);
+ pkgs_seen.insert(pkg.FullName());
}
// then write the ones we have not seen yet
std::ostringstream ostr;
for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
- if(PkgState[pkg->ID].Flags & Flag::Auto) {
- if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) {
+ StateCache const &P = PkgState[pkg->ID];
+ if(P.Flags & Flag::Auto) {
+ if (pkgs_seen.find(pkg.FullName()) != pkgs_seen.end()) {
if(debug_autoremove)
- std::clog << "Skipping already written " << pkg.Name() << std::endl;
+ std::clog << "Skipping already written " << pkg.FullName() << std::endl;
continue;
}
- // skip not installed ones if requested
- if(InstalledOnly && pkg->CurrentVer == 0)
- continue;
+ // skip not installed ones if requested
+ if (InstalledOnly && (
+ (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+ (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+ continue;
+ const char* const pkgarch = pkg.Arch();
+ if (strcmp(pkgarch, "all") == 0)
+ continue;
if(debug_autoremove)
- std::clog << "Writing new AutoInstall: "
- << pkg.Name() << std::endl;
+ std::clog << "Writing new AutoInstall: " << pkg.FullName() << std::endl;
ostr.str(string(""));
- ostr << "Package: " << pkg.Name()
+ ostr << "Package: " << pkg.Name()
+ << "\nArchitecture: " << pkgarch
<< "\nAuto-Installed: 1\n\n";
fprintf(OutFile,"%s",ostr.str().c_str());
- fprintf(OutFile,"\n");
}
}
fclose(OutFile);
@@ -596,6 +635,107 @@ void pkgDepCache::UpdateVerState(PkgIterator Pkg)
}
}
/*}}}*/
+// DepCache::RemovePseudoInstalledPkg - MultiArch helper for Update() /*{{{*/
+// ---------------------------------------------------------------------
+/* We "install" arch all packages for all archs if it is installed. Many
+ of these will be broken. This method will look at these broken Pkg and
+ "remove" it. */
+bool pkgDepCache::RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck) {
+ if (unlikely(Pkg->CurrentVer == 0))
+ return false;
+
+ VerIterator V = Pkg.CurrentVer();
+ if (V->MultiArch != Version::All)
+ return false;
+
+ // Never ever kill an "all" package - they have no dependency so they can't be broken
+ if (strcmp(Pkg.Arch(),"all") == 0)
+ return false;
+
+ unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+ if ((CurDepState & DepInstMin) == DepInstMin) {
+ // okay, the package isn't broken, but is the package also required?
+ // If it has no real dependencies, no installed rdepends and doesn't
+ // provide something of value, we will kill it as not required.
+ // These pseudopackages have otherwise interesting effects if they get
+ // a new dependency in a newer version…
+ for (pkgCache::DepIterator D = V.DependsList();
+ D.end() != true; ++D)
+ if (D.IsCritical() == true && D.ParentPkg()->Group != Pkg->Group)
+ return false;
+ for (DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D)
+ {
+ if (D.IsCritical() == false)
+ continue;
+ PkgIterator const P = D.ParentPkg();
+ if (P->Group == Pkg->Group)
+ continue;
+ if (P->CurrentVer != 0)
+ return false;
+ }
+ for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
+ for (DepIterator d = Prv.ParentPkg().RevDependsList();
+ d.end() != true; ++d)
+ {
+ PkgIterator const P = d.ParentPkg();
+ if (P->CurrentVer != 0 &&
+ P->Group != Pkg->Group)
+ return false;
+ }
+ }
+
+ // Dependencies for this arch all package are not statisfied
+ // so we installed it only for our convenience: get right of it now.
+ RemoveSizes(Pkg);
+ RemoveStates(Pkg);
+
+ Pkg->CurrentVer = 0;
+ PkgState[Pkg->ID].InstallVer = 0;
+
+ AddStates(Pkg);
+ Update(Pkg);
+ AddSizes(Pkg);
+
+ // After the remove previously satisfied pseudo pkg could be now
+ // no longer satisfied, so we need to recheck the reverse dependencies
+ for (DepIterator d = Pkg.RevDependsList(); d.end() != true; ++d)
+ {
+ PkgIterator const P = d.ParentPkg();
+ if (P->CurrentVer != 0)
+ recheck.insert(P.Index());
+ }
+
+ for (DepIterator d = V.DependsList(); d.end() != true; ++d)
+ {
+ PkgIterator const P = d.TargetPkg();
+ for (PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
+ {
+ PkgIterator const O = Prv.OwnerPkg();
+ if (O->CurrentVer != 0)
+ recheck.insert(O.Index());
+ }
+
+ if (P->CurrentVer != 0)
+ recheck.insert(P.Index());
+ }
+
+ for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
+ {
+ for (DepIterator d = Prv.ParentPkg().RevDependsList();
+ d.end() != true; ++d)
+ {
+ PkgIterator const P = d.ParentPkg();
+ if (P->CurrentVer == 0)
+ continue;
+
+ recheck.insert(P.Index());
+ }
+ }
+
+
+ return true;
+}
+ /*}}}*/
// DepCache::Update - Figure out all the state information /*{{{*/
// ---------------------------------------------------------------------
/* This will figure out the state of all the packages and all the
@@ -609,9 +749,13 @@ void pkgDepCache::Update(OpProgress *Prog)
iKeepCount = 0;
iBrokenCount = 0;
iBadCount = 0;
-
+
+ std::set<unsigned long> recheck;
+
// Perform the depends pass
int Done = 0;
+ bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1;
+ unsigned long killed = 0;
for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
{
if (Prog != 0 && Done%20 == 0)
@@ -619,7 +763,7 @@ void pkgDepCache::Update(OpProgress *Prog)
for (VerIterator V = I.VersionList(); V.end() != true; V++)
{
unsigned char Group = 0;
-
+
for (DepIterator D = V.DependsList(); D.end() != true; D++)
{
// Build the dependency state.
@@ -637,21 +781,157 @@ void pkgDepCache::Update(OpProgress *Prog)
D->Type == Dep::DpkgBreaks ||
D->Type == Dep::Obsoletes)
State = ~State;
- }
+ }
}
- // Compute the pacakge dependency state and size additions
+ // Compute the package dependency state and size additions
AddSizes(I);
UpdateVerState(I);
AddStates(I);
+
+ if (checkMultiArch != true || I->CurrentVer == 0)
+ continue;
+
+ VerIterator const V = I.CurrentVer();
+ if (V->MultiArch != Version::All)
+ continue;
+
+ recheck.insert(I.Index());
+ --Done; // no progress if we need to recheck the package
+ }
+
+ if (checkMultiArch == true) {
+ /* FIXME: recheck breaks proper progress reporting as we don't know
+ how many packages we need to recheck. To lower the effect
+ a bit we increase with a kill, but we should do something more clever… */
+ for(std::set<unsigned long>::const_iterator p = recheck.begin();
+ p != recheck.end(); ++p) {
+ if (Prog != 0 && Done%20 == 0)
+ Prog->Progress(Done);
+ PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
+ if (RemovePseudoInstalledPkg(P, recheck) == true) {
+ ++killed;
+ ++Done;
+ }
+ recheck.erase(p);
+ }
+
+ /* Okay, we have killed a great amount of pseudopackages -
+ we have killed so many that we have now arch "all" packages
+ without an installed pseudo package, but we NEED an installed
+ pseudo package, so we will search now for a pseudo package
+ we can install without breaking everything. */
+ for (GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G)
+ {
+ PkgIterator P = G.FindPkg("all");
+ if (P.end() == true)
+ continue;
+ if (P->CurrentVer == 0)
+ continue;
+ bool installed = false;
+ for (P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(), "all") == 0)
+ continue;
+ if (P->CurrentVer == 0)
+ continue;
+ installed = true;
+ break;
+ }
+ if (installed == false)
+ recheck.insert(G.Index());
+ }
+
+ while (recheck.empty() != true)
+ {
+ std::set<unsigned long>::const_iterator g = recheck.begin();
+ unsigned long const G = *g;
+ recheck.erase(g);
+ if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
+ _error->Warning(_("Internal error, group '%s' has no installable pseudo package"), GrpIterator(*Cache, Cache->GrpP + *g).Name());
+ }
}
- if (Prog != 0)
+ if (Prog != 0)
Prog->Progress(Done);
readStateFile(Prog);
}
/*}}}*/
+// DepCache::ReInstallPseudoForGroup - MultiArch helper for Update() /*{{{*/
+// ---------------------------------------------------------------------
+/* RemovePseudoInstalledPkg() is very successful. It even kills packages
+ to an amount that no pseudo package is left, but we need a pseudo package
+ for upgrading senarios so we need to reinstall one pseudopackage which
+ doesn't break everything. Thankfully we can't have architecture depending
+ negative dependencies so this problem is already eliminated */
+bool pkgDepCache::ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck)
+{
+ if (P->CurrentVer != 0)
+ return true;
+ // recursive call for packages which provide this package
+ for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
+ ReInstallPseudoForGroup(Prv.OwnerPkg(), recheck);
+ // check if we actually need to look at this group
+ unsigned long const G = P->Group;
+ std::set<unsigned long>::const_iterator Pi = recheck.find(G);
+ if (Pi == recheck.end())
+ return true;
+ recheck.erase(Pi); // remove here, so we can't fall into an endless loop
+ if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
+ {
+ recheck.insert(G);
+ return false;
+ }
+ return true;
+}
+bool pkgDepCache::ReInstallPseudoForGroup(unsigned long const &G, std::set<unsigned long> &recheck)
+{
+ std::vector<std::string> static const Archs = APT::Configuration::getArchitectures();
+ pkgCache::GrpIterator Grp(*Cache, Cache->GrpP + G);
+ if (unlikely(Grp.end() == true))
+ return false;
+ for (std::vector<std::string>::const_iterator a = Archs.begin();
+ a != Archs.end(); ++a)
+ {
+ pkgCache::PkgIterator P = Grp.FindPkg(*a);
+ if (P.end() == true)
+ continue;
+ pkgCache::VerIterator allV = Grp.FindPkg("all").CurrentVer();
+ for (VerIterator V = P.VersionList(); V.end() != true; ++V)
+ {
+ // search for the same version as the all package
+ if (allV->Hash != V->Hash || strcmp(allV.VerStr(),V.VerStr()) != 0)
+ continue;
+ unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+ // If it is broken, try to install dependencies first before retry
+ if ((CurDepState & DepInstMin) != DepInstMin)
+ {
+ for (pkgCache::DepIterator D = V.DependsList(); D.end() != true; ++D)
+ {
+ if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends)
+ continue;
+ ReInstallPseudoForGroup(D.TargetPkg(), recheck);
+ }
+ unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+ // if package ist still broken… try another arch
+ if ((CurDepState & DepInstMin) != DepInstMin)
+ break;
+ }
+ // dependencies satisfied: reinstall the package
+ RemoveSizes(P);
+ RemoveStates(P);
+ P->CurrentVer = V.Index();
+ PkgState[P->ID].InstallVer = V;
+ AddStates(P);
+ Update(P);
+ AddSizes(P);
+ return true;
+ }
+ }
+ return false;
+}
+ /*}}}*/
// DepCache::Update - Update the deps list of a package /*{{{*/
// ---------------------------------------------------------------------
/* This is a helper for update that only does the dep portion of the scan.
@@ -813,6 +1093,10 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
AddStates(Pkg);
Update(Pkg);
AddSizes(Pkg);
+
+ // if we remove the pseudo package, we also need to remove the "real"
+ if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true)
+ MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser);
}
/*}}}*/
// DepCache::IsDeleteOk - check if it is ok to remove this package /*{{{*/
@@ -1339,7 +1623,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
// debug output
if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
- std::clog << "AutoDep: " << p.Name() << std::endl;
+ std::clog << "AutoDep: " << p.FullName() << std::endl;
}
// init vars
@@ -1373,13 +1657,18 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
// MarkPackage - mark a single package in Mark-and-Sweep /*{{{*/
void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
const pkgCache::VerIterator &ver,
- bool follow_recommends,
- bool follow_suggests)
+ bool const &follow_recommends,
+ bool const &follow_suggests)
{
pkgDepCache::StateCache &state = PkgState[pkg->ID];
- VerIterator currver = pkg.CurrentVer();
- VerIterator candver = state.CandidateVerIter(*this);
- VerIterator instver = state.InstVerIter(*this);
+
+ // if we are marked already we are done
+ if(state.Marked)
+ return;
+
+ VerIterator const currver = pkg.CurrentVer();
+ VerIterator const candver = state.CandidateVerIter(*this);
+ VerIterator const instver = state.InstVerIter(*this);
#if 0
// If a package was garbage-collected but is now being marked, we
@@ -1405,15 +1694,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
!(ver == currver && instver.end() && !ver.end()))
return;
- // if we are marked already we are done
- if(state.Marked)
- return;
+ bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
- bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
-
if(debug_autoremove)
{
- std::clog << "Marking: " << pkg.Name();
+ std::clog << "Marking: " << pkg.FullName();
if(!ver.end())
std::clog << " " << ver.VerStr();
if(!currver.end())
@@ -1425,8 +1710,34 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
state.Marked=true;
- if(!ver.end())
+ if(ver.end() == true)
+ return;
+
+ // If the version belongs to a Multi-Arch all package
+ // we will mark all others in this Group with this version also
+ // Beware: We compare versions here the lazy way: string comparision
+ // this is bad if multiple repositories provide different versions
+ // of the package with an identical version number - but even in this
+ // case the dependencies are likely the same.
+ if (ver->MultiArch == pkgCache::Version::All &&
+ strcmp(ver.Arch(true), "all") == 0)
{
+ GrpIterator G = pkg.Group();
+ const char* const VerStr = ver.VerStr();
+ for (PkgIterator P = G.FindPkg("any");
+ P.end() != true; P = G.NextPkg(P))
+ {
+ for (VerIterator V = P.VersionList();
+ V.end() != true; ++V)
+ {
+ if (strcmp(VerStr, V.VerStr()) != 0)
+ continue;
+ MarkPackage(P, V, follow_recommends, follow_suggests);
+ break;
+ }
+ }
+ }
+
for(DepIterator d = ver.DependsList(); !d.end(); ++d)
{
if(d->Type == Dep::Depends ||
@@ -1444,10 +1755,9 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
{
if(debug_autoremove)
{
- std::clog << "Following dep: " << d.ParentPkg().Name()
+ std::clog << "Following dep: " << d.ParentPkg().FullName()
<< " " << d.ParentVer().VerStr() << " "
- << d.DepType() << " "
- << d.TargetPkg().Name();
+ << d.DepType() << " " << d.TargetPkg().FullName();
if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
{
std::clog << " (" << d.CompType() << " "
@@ -1455,7 +1765,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
}
std::clog << std::endl;
}
- MarkPackage(V.ParentPkg(), V,
+ MarkPackage(V.ParentPkg(), V,
follow_recommends, follow_suggests);
}
}
@@ -1468,17 +1778,16 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
{
if(debug_autoremove)
{
- std::clog << "Following dep: " << d.ParentPkg().Name()
- << " " << d.ParentVer().VerStr() << " "
- << d.DepType() << " "
- << d.TargetPkg().Name();
+ std::clog << "Following dep: " << d.ParentPkg().FullName() << " "
+ << d.ParentVer().VerStr() << " "
+ << d.DepType() << " " << d.TargetPkg().FullName() << " ";
if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
{
std::clog << " (" << d.CompType() << " "
<< d.TargetVer() << ")";
}
std::clog << ", provided by "
- << prv.OwnerPkg().Name() << " "
+ << prv.OwnerPkg().FullName() << " "
<< prv.OwnerVer().VerStr()
<< std::endl;
}
@@ -1489,7 +1798,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
}
}
}
- }
}
/*}}}*/
bool pkgDepCache::Sweep() /*{{{*/
@@ -1511,7 +1819,7 @@ bool pkgDepCache::Sweep() /*{{{*/
{
state.Garbage=true;
if(debug_autoremove)
- std::clog << "Garbage: " << p.Name() << std::endl;
+ std::clog << "Garbage: " << p.FullName() << std::endl;
}
}
diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h
index 0306861a1..3decc7a5f 100644
--- a/apt-pkg/depcache.h
+++ b/apt-pkg/depcache.h
@@ -46,6 +46,7 @@
#include <vector>
#include <memory>
+#include <set>
class pkgDepCache : protected pkgCache::Namespace
{
@@ -78,8 +79,8 @@ class pkgDepCache : protected pkgCache::Namespace
*/
void MarkPackage(const pkgCache::PkgIterator &pkg,
const pkgCache::VerIterator &ver,
- bool follow_recommends,
- bool follow_suggests);
+ bool const &follow_recommends,
+ bool const &follow_suggests);
/** \brief Update the Marked field of all packages.
*
@@ -330,8 +331,11 @@ class pkgDepCache : protected pkgCache::Namespace
// Legacy.. We look like a pkgCache
inline operator pkgCache &() {return *Cache;};
inline Header &Head() {return *Cache->HeaderP;};
+ inline GrpIterator GrpBegin() {return Cache->GrpBegin();};
inline PkgIterator PkgBegin() {return Cache->PkgBegin();};
+ inline GrpIterator FindGrp(string const &Name) {return Cache->FindGrp(Name);};
inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);};
+ inline PkgIterator FindPkg(string const &Name, string const &Arch) {return Cache->FindPkg(Name, Arch);};
inline pkgCache &GetCache() {return *Cache;};
inline pkgVersioningSystem &VS() {return *Cache->VS;};
@@ -442,12 +446,9 @@ class pkgDepCache : protected pkgCache::Namespace
virtual bool IsDeleteOk(const PkgIterator &Pkg,bool Purge = false,
unsigned long Depth = 0, bool FromUser = true);
- // This is for debuging
- void Update(OpProgress *Prog = 0);
-
// read persistent states
bool readStateFile(OpProgress *prog);
- bool writeStateFile(OpProgress *prog, bool InstalledOnly=false);
+ bool writeStateFile(OpProgress *prog, bool InstalledOnly=true);
// Size queries
inline double UsrSize() {return iUsrSize;};
@@ -460,9 +461,17 @@ class pkgDepCache : protected pkgCache::Namespace
inline unsigned long BadCount() {return iBadCount;};
bool Init(OpProgress *Prog);
-
+ // Generate all state information
+ void Update(OpProgress *Prog = 0);
+
pkgDepCache(pkgCache *Cache,Policy *Plcy = 0);
virtual ~pkgDepCache();
+
+ private:
+ // Helper for Update(OpProgress) to remove pseudoinstalled arch all packages
+ bool RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck);
+ bool ReInstallPseudoForGroup(unsigned long const &Grp, std::set<unsigned long> &recheck);
+ bool ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck);
};
#endif
diff --git a/apt-pkg/makefile b/apt-pkg/makefile
index bdd49c089..148ad581b 100644
--- a/apt-pkg/makefile
+++ b/apt-pkg/makefile
@@ -25,7 +25,7 @@ SOURCE = contrib/mmap.cc contrib/error.cc contrib/strutl.cc \
contrib/fileutl.cc
HEADERS = mmap.h error.h configuration.h fileutl.h cmndline.h netrc.h\
md5.h crc-16.h cdromutl.h strutl.h sptr.h sha1.h sha256.h hashes.h \
- macros.h
+ macros.h weakptr.h
# Source code for the core main library
SOURCE+= pkgcache.cc version.cc depcache.cc \
diff --git a/apt-pkg/metaindex.h b/apt-pkg/metaindex.h
index 779b6ab14..1d2140799 100644
--- a/apt-pkg/metaindex.h
+++ b/apt-pkg/metaindex.h
@@ -33,8 +33,8 @@ class metaIndex
virtual const char* GetType() const {return Type;}
// Interface for acquire
- virtual string ArchiveURI(string /*File*/) const = 0;
- virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const = 0;
+ virtual string ArchiveURI(string const& /*File*/) const = 0;
+ virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const = 0;
virtual vector<pkgIndexFile *> *GetIndexFiles() = 0;
virtual bool IsTrusted() const = 0;
diff --git a/apt-pkg/orderlist.cc b/apt-pkg/orderlist.cc
index 0ee2e2bc8..7c950292a 100644
--- a/apt-pkg/orderlist.cc
+++ b/apt-pkg/orderlist.cc
@@ -126,6 +126,11 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg)
if (FileList[Pkg->ID].empty() == false)
return false;
+
+ // Missing Pseudo packages are missing if the real package is missing
+ if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+ return IsMissing(Pkg.Group().FindPkg("all"));
+
return true;
}
/*}}}*/
@@ -199,7 +204,7 @@ bool pkgOrderList::OrderCritical()
{
PkgIterator P(Cache,*I);
if (IsNow(P) == true)
- clog << " " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+ clog << " " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
}
}
@@ -272,7 +277,7 @@ bool pkgOrderList::OrderUnpack(string *FileList)
{
PkgIterator P(Cache,*I);
if (IsNow(P) == true)
- clog << " " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+ clog << " " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
}
}
@@ -543,7 +548,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
if (Debug == true)
{
for (int j = 0; j != Depth; j++) clog << ' ';
- clog << "Visit " << Pkg.Name() << endl;
+ clog << "Visit " << Pkg.FullName() << endl;
}
Depth++;
@@ -602,7 +607,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
if (Debug == true)
{
for (int j = 0; j != Depth; j++) clog << ' ';
- clog << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
+ clog << "Leave " << Pkg.FullName() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
}
return true;
diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc
index b747fa78a..eef79cccd 100644
--- a/apt-pkg/packagemanager.cc
+++ b/apt-pkg/packagemanager.cc
@@ -80,7 +80,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
// Skip already processed packages
if (List->IsNow(Pkg) == false)
continue;
-
+
+ if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+ continue;
+
new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
FileNames[Pkg->ID]);
}
@@ -277,8 +280,10 @@ bool pkgPackageManager::ConfigureAll()
for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
{
PkgIterator Pkg(Cache,*I);
-
- if (ConfigurePkgs == true && Configure(Pkg) == false)
+
+ if (ConfigurePkgs == true &&
+ pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+ Configure(Pkg) == false)
return false;
List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -313,7 +318,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
{
PkgIterator Pkg(Cache,*I);
- if (ConfigurePkgs == true && Configure(Pkg) == false)
+ if (ConfigurePkgs == true &&
+ pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+ Configure(Pkg) == false)
return false;
List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -465,7 +472,12 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
return true;
List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
- return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+
+ if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false)
+ return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+ else
+ return SmartRemove(Pkg.Group().FindPkg("all"));
+ return true;
}
/*}}}*/
// PM::SmartUnPack - Install helper /*{{{*/
@@ -579,10 +591,22 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList();
P.end() == false; P++)
CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
-
- if (Install(Pkg,FileNames[Pkg->ID]) == false)
- return false;
-
+
+ if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false)
+ {
+ if(Install(Pkg,FileNames[Pkg->ID]) == false)
+ return false;
+ } else {
+ // Pseudo packages will not be unpacked - instead we will do this
+ // for the "real" package, but only once and if it is already
+ // configured we don't need to unpack it again…
+ PkgIterator const P = Pkg.Group().FindPkg("all");
+ if (List->IsFlag(P,pkgOrderList::UnPacked) != true &&
+ List->IsFlag(P,pkgOrderList::Configured) != true) {
+ if (SmartUnPack(P) == false)
+ return false;
+ }
+ }
List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
// Perform immedate configuration of the package.
diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc
index 038bd7ec4..a59a06d65 100644
--- a/apt-pkg/pkgcache.cc
+++ b/apt-pkg/pkgcache.cc
@@ -55,6 +55,7 @@ pkgCache::Header::Header()
Dirty = false;
HeaderSz = sizeof(pkgCache::Header);
+ GroupSz = sizeof(pkgCache::Group);
PackageSz = sizeof(pkgCache::Package);
PackageFileSz = sizeof(pkgCache::PackageFile);
VersionSz = sizeof(pkgCache::Version);
@@ -64,6 +65,7 @@ pkgCache::Header::Header()
VerFileSz = sizeof(pkgCache::VerFile);
DescFileSz = sizeof(pkgCache::DescFile);
+ GroupCount = 0;
PackageCount = 0;
VersionCount = 0;
DescriptionCount = 0;
@@ -79,7 +81,8 @@ pkgCache::Header::Header()
StringList = 0;
VerSysName = 0;
Architecture = 0;
- memset(HashTable,0,sizeof(HashTable));
+ memset(PkgHashTable,0,sizeof(PkgHashTable));
+ memset(GrpHashTable,0,sizeof(GrpHashTable));
memset(Pools,0,sizeof(Pools));
}
/*}}}*/
@@ -89,6 +92,7 @@ pkgCache::Header::Header()
bool pkgCache::Header::CheckSizes(Header &Against) const
{
if (HeaderSz == Against.HeaderSz &&
+ GroupSz == Against.GroupSz &&
PackageSz == Against.PackageSz &&
PackageFileSz == Against.PackageFileSz &&
VersionSz == Against.VersionSz &&
@@ -107,6 +111,7 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
/* */
pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
{
+ MultiArchEnabled = APT::Configuration::getArchitectures().size() > 1;
if (DoMap == true)
ReMap();
}
@@ -118,6 +123,7 @@ bool pkgCache::ReMap()
{
// Apply the typecasts.
HeaderP = (Header *)Map.Data();
+ GrpP = (Group *)Map.Data();
PkgP = (Package *)Map.Data();
VerFileP = (VerFile *)Map.Data();
DescFileP = (DescFile *)Map.Data();
@@ -165,7 +171,7 @@ unsigned long pkgCache::sHash(const string &Str) const
unsigned long Hash = 0;
for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
Hash = 5*Hash + tolower_ascii(*I);
- return Hash % _count(HeaderP->HashTable);
+ return Hash % _count(HeaderP->PkgHashTable);
}
unsigned long pkgCache::sHash(const char *Str) const
@@ -173,26 +179,82 @@ unsigned long pkgCache::sHash(const char *Str) const
unsigned long Hash = 0;
for (const char *I = Str; *I != 0; I++)
Hash = 5*Hash + tolower_ascii(*I);
- return Hash % _count(HeaderP->HashTable);
+ return Hash % _count(HeaderP->PkgHashTable);
}
/*}}}*/
-// Cache::FindPkg - Locate a package by name /*{{{*/
+// Cache::SingleArchFindPkg - Locate a package by name /*{{{*/
// ---------------------------------------------------------------------
-/* Returns 0 on error, pointer to the package otherwise */
-pkgCache::PkgIterator pkgCache::FindPkg(const string &Name)
+/* Returns 0 on error, pointer to the package otherwise
+ The multiArch enabled methods will fallback to this one as it is (a bit)
+ faster for single arch environments and realworld is mostly singlearch… */
+pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name)
{
// Look at the hash bucket
- Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
+ Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)];
for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
{
if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
- stringcasecmp(Name,StrP + Pkg->Name) == 0)
- return PkgIterator(*this,Pkg);
+ stringcasecmp(Name,StrP + Pkg->Name) == 0)
+ return PkgIterator(*this,Pkg);
}
return PkgIterator(*this,0);
}
/*}}}*/
+// Cache::FindPkg - Locate a package by name /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
+ if (MultiArchCache() == false)
+ return SingleArchFindPkg(Name);
+ size_t const found = Name.find(':');
+ if (found == string::npos)
+ return FindPkg(Name, "native");
+ string const Arch = Name.substr(found+1);
+ if (Arch == "any")
+ return FindPkg(Name, "any");
+ return FindPkg(Name.substr(0, found), Arch);
+}
+ /*}}}*/
+// Cache::FindPkg - Locate a package by name /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) {
+ if (MultiArchCache() == false) {
+ if (Arch == "native" || Arch == "all" || Arch == "any" ||
+ Arch == _config->Find("APT::Architecture"))
+ return SingleArchFindPkg(Name);
+ else
+ return PkgIterator(*this,0);
+ }
+ /* We make a detour via the GrpIterator here as
+ on a multi-arch environment a group is easier to
+ find than a package (less entries in the buckets) */
+ pkgCache::GrpIterator Grp = FindGrp(Name);
+ if (Grp.end() == true)
+ return PkgIterator(*this,0);
+
+ return Grp.FindPkg(Arch);
+}
+ /*}}}*/
+// Cache::FindGrp - Locate a group by name /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns End-Pointer on error, pointer to the group otherwise */
+pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
+ if (unlikely(Name.empty() == true))
+ return GrpIterator(*this,0);
+
+ // Look at the hash bucket for the group
+ Group *Grp = GrpP + HeaderP->GrpHashTable[sHash(Name)];
+ for (; Grp != GrpP; Grp = GrpP + Grp->Next) {
+ if (Grp->Name != 0 && StrP[Grp->Name] == Name[0] &&
+ stringcasecmp(Name, StrP + Grp->Name) == 0)
+ return GrpIterator(*this, Grp);
+ }
+
+ return GrpIterator(*this,0);
+}
+ /*}}}*/
// Cache::CompTypeDeb - Return a string describing the compare type /*{{{*/
// ---------------------------------------------------------------------
/* This returns a string representation of the dependency compare
@@ -242,11 +304,77 @@ const char *pkgCache::Priority(unsigned char Prio)
return 0;
}
/*}}}*/
-// Bases for iterator classes /*{{{*/
-void pkgCache::VerIterator::_dummy() {}
-void pkgCache::DepIterator::_dummy() {}
-void pkgCache::PrvIterator::_dummy() {}
-void pkgCache::DescIterator::_dummy() {}
+// GrpIterator::FindPkg - Locate a package by arch /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) {
+ if (unlikely(IsGood() == false || S->FirstPackage == 0))
+ return PkgIterator(*Owner, 0);
+
+ static string const myArch = _config->Find("APT::Architecture");
+ /* Most of the time the package for our native architecture is
+ the one we add at first to the cache, but this would be the
+ last one we check, so we do it now. */
+ if (Arch == "native" || Arch == myArch) {
+ Arch = myArch;
+ pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
+ if (stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+ return PkgIterator(*Owner, Pkg);
+ }
+
+ /* If we accept any package we simply return the "first"
+ package in this group (the last one added). */
+ if (Arch == "any")
+ return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage);
+
+ /* Iterate over the list to find the matching arch
+ unfortunately this list includes "package noise"
+ (= different packages with same calculated hash),
+ so we need to check the name also */
+ for (pkgCache::Package *Pkg = PackageList(); Pkg != Owner->PkgP;
+ Pkg = Owner->PkgP + Pkg->NextPackage) {
+ if (S->Name == Pkg->Name &&
+ stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+ return PkgIterator(*Owner, Pkg);
+ if ((Owner->PkgP + S->LastPackage) == Pkg)
+ break;
+ }
+
+ return PkgIterator(*Owner, 0);
+}
+ /*}}}*/
+// GrpIterator::NextPkg - Locate the next package in the group /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise.
+ We can't simply ++ to the next as the next package of the last will
+ be from a different group (with the same hash value) */
+pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const &LastPkg) {
+ if (unlikely(IsGood() == false || S->FirstPackage == 0 ||
+ LastPkg.end() == true))
+ return PkgIterator(*Owner, 0);
+
+ if (S->LastPackage == LastPkg.Index())
+ return PkgIterator(*Owner, 0);
+
+ return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
+}
+ /*}}}*/
+// GrpIterator::operator ++ - Postfix incr /*{{{*/
+// ---------------------------------------------------------------------
+/* This will advance to the next logical group in the hash table. */
+void pkgCache::GrpIterator::operator ++(int)
+{
+ // Follow the current links
+ if (S != Owner->GrpP)
+ S = Owner->GrpP + S->Next;
+
+ // Follow the hash table
+ while (S == Owner->GrpP && (HashIndex+1) < (signed)_count(Owner->HeaderP->GrpHashTable))
+ {
+ HashIndex++;
+ S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+ }
+};
/*}}}*/
// PkgIterator::operator ++ - Postfix incr /*{{{*/
// ---------------------------------------------------------------------
@@ -254,14 +382,14 @@ void pkgCache::DescIterator::_dummy() {}
void pkgCache::PkgIterator::operator ++(int)
{
// Follow the current links
- if (Pkg != Owner->PkgP)
- Pkg = Owner->PkgP + Pkg->NextPackage;
+ if (S != Owner->PkgP)
+ S = Owner->PkgP + S->NextPackage;
// Follow the hash table
- while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable))
+ while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
{
HashIndex++;
- Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
+ S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
}
};
/*}}}*/
@@ -270,12 +398,12 @@ void pkgCache::PkgIterator::operator ++(int)
/* By this we mean if it is either cleanly installed or cleanly removed. */
pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
{
- if (Pkg->InstState == pkgCache::State::ReInstReq ||
- Pkg->InstState == pkgCache::State::HoldReInstReq)
+ if (S->InstState == pkgCache::State::ReInstReq ||
+ S->InstState == pkgCache::State::HoldReInstReq)
return NeedsUnpack;
- if (Pkg->CurrentState == pkgCache::State::UnPacked ||
- Pkg->CurrentState == pkgCache::State::HalfConfigured)
+ if (S->CurrentState == pkgCache::State::UnPacked ||
+ S->CurrentState == pkgCache::State::HalfConfigured)
// we leave triggers alone complettely. dpkg deals with
// them in a hard-to-predict manner and if they get
// resolved by dpkg before apt run dpkg --configure on
@@ -284,8 +412,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
//Pkg->CurrentState == pkgCache::State::TriggersPending)
return NeedsConfigure;
- if (Pkg->CurrentState == pkgCache::State::HalfInstalled ||
- Pkg->InstState != pkgCache::State::Ok)
+ if (S->CurrentState == pkgCache::State::HalfInstalled ||
+ S->InstState != pkgCache::State::Ok)
return NeedsUnpack;
return NeedsNothing;
@@ -332,7 +460,7 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
- out << Pkg.Name() << " < " << current;
+ out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
if (current != candidate)
out << " -> " << candidate;
if ( newest != "none" && candidate != newest)
@@ -341,17 +469,29 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
return out;
}
/*}}}*/
+// PkgIterator::FullName - Returns Name and (maybe) Architecture /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns a name:arch string */
+std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
+{
+ string fullname = Name();
+ if (Pretty == false ||
+ (strcmp(Arch(), "all") != 0 && _config->Find("APT::Architecture") != Arch()))
+ return fullname.append(":").append(Arch());
+ return fullname;
+}
+ /*}}}*/
// DepIterator::IsCritical - Returns true if the dep is important /*{{{*/
// ---------------------------------------------------------------------
/* Currently critical deps are defined as depends, predepends and
conflicts (including dpkg's Breaks fields). */
bool pkgCache::DepIterator::IsCritical()
{
- if (Dep->Type == pkgCache::Dep::Conflicts ||
- Dep->Type == pkgCache::Dep::DpkgBreaks ||
- Dep->Type == pkgCache::Dep::Obsoletes ||
- Dep->Type == pkgCache::Dep::Depends ||
- Dep->Type == pkgCache::Dep::PreDepends)
+ if (S->Type == pkgCache::Dep::Conflicts ||
+ S->Type == pkgCache::Dep::DpkgBreaks ||
+ S->Type == pkgCache::Dep::Obsoletes ||
+ S->Type == pkgCache::Dep::Depends ||
+ S->Type == pkgCache::Dep::PreDepends)
return true;
return false;
}
@@ -430,12 +570,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
// Walk along the actual package providing versions
for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
{
- if (Owner->VS->CheckDep(I.VerStr(),Dep->CompareOp,TargetVer()) == false)
+ if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
continue;
- if ((Dep->Type == pkgCache::Dep::Conflicts ||
- Dep->Type == pkgCache::Dep::DpkgBreaks ||
- Dep->Type == pkgCache::Dep::Obsoletes) &&
+ if ((S->Type == pkgCache::Dep::Conflicts ||
+ S->Type == pkgCache::Dep::DpkgBreaks ||
+ S->Type == pkgCache::Dep::Obsoletes) &&
ParentPkg() == I.ParentPkg())
continue;
@@ -447,12 +587,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
// Follow all provides
for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
{
- if (Owner->VS->CheckDep(I.ProvideVersion(),Dep->CompareOp,TargetVer()) == false)
+ if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
continue;
- if ((Dep->Type == pkgCache::Dep::Conflicts ||
- Dep->Type == pkgCache::Dep::DpkgBreaks ||
- Dep->Type == pkgCache::Dep::Obsoletes) &&
+ if ((S->Type == pkgCache::Dep::Conflicts ||
+ S->Type == pkgCache::Dep::DpkgBreaks ||
+ S->Type == pkgCache::Dep::Obsoletes) &&
ParentPkg() == I.OwnerPkg())
continue;
@@ -490,7 +630,7 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
End = *this;
for (bool LastOR = true; end() == false && LastOR == true;)
{
- LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+ LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
(*this)++;
if (LastOR == true)
End = (*this);
@@ -545,6 +685,23 @@ bool pkgCache::VerIterator::Automatic() const
return false;
}
/*}}}*/
+// VerIterator::Pseudo - Check if this version is a pseudo one /*{{{*/
+// ---------------------------------------------------------------------
+/* Sometimes you have the need to express dependencies with versions
+ which doesn't really exist or exist multiply times for "different"
+ packages. We need these versions for dependency resolution but they
+ are a problem everytime we need to download/install something. */
+bool pkgCache::VerIterator::Pseudo() const
+{
+ if (S->MultiArch == pkgCache::Version::All &&
+ strcmp(Arch(true),"all") != 0)
+ {
+ GrpIterator const Grp = ParentPkg().Group();
+ return (Grp->LastPackage != Grp->FirstPackage);
+ }
+ return false;
+}
+ /*}}}*/
// VerIterator::NewestFile - Return the newest file version relation /*{{{*/
// ---------------------------------------------------------------------
/* This looks at the version numbers associated with all of the sources
@@ -625,7 +782,9 @@ string pkgCache::VerIterator::RelStr()
else
Res += File.Site();
}
- }
+ }
+ if (S->ParentPkg != 0)
+ Res.append(" [").append(Arch()).append("]");
return Res;
}
/*}}}*/
@@ -640,7 +799,7 @@ bool pkgCache::PkgFileIterator::IsOk()
if (stat(FileName(),&Buf) != 0)
return false;
- if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime)
+ if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime)
return false;
return true;
@@ -664,6 +823,8 @@ string pkgCache::PkgFileIterator::RelStr()
Res = Res + (Res.empty() == true?"l=":",l=") + Label();
if (Component() != 0)
Res = Res + (Res.empty() == true?"c=":",c=") + Component();
+ if (Architecture() != 0)
+ Res = Res + (Res.empty() == true?"b=":",b=") + Architecture();
return Res;
}
/*}}}*/
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
index e8a3e1064..643f240b0 100644
--- a/apt-pkg/pkgcache.h
+++ b/apt-pkg/pkgcache.h
@@ -1,20 +1,75 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: pkgcache.h,v 1.25 2001/07/01 22:28:24 jgg Exp $
-/* ######################################################################
-
- Cache - Structure definitions for the cache file
-
- Please see doc/apt-pkg/cache.sgml for a more detailed description of
- this format. Also be sure to keep that file up-to-date!!
-
+/**\file pkgcache.h
+ \brief pkgCache - Structure definitions for the cache file
+
+ The goal of the cache file is two fold:
+ Firstly to speed loading and processing of the package file array and
+ secondly to reduce memory consumption of the package file array.
+
+ The implementation is aimed at an environment with many primary package
+ files, for instance someone that has a Package file for their CD-ROM, a
+ Package file for the latest version of the distribution on the CD-ROM and a
+ package file for the development version. Always present is the information
+ contained in the status file which might be considered a separate package
+ file.
+
+ Please understand, this is designed as a <b>Cache file</b> it is not meant to be
+ used on any system other than the one it was created for. It is not meant to
+ be authoritative either, i.e. if a system crash or software failure occurs it
+ must be perfectly acceptable for the cache file to be in an inconsistent
+ state. Furthermore at any time the cache file may be erased without losing
+ any information.
+
+ Also the structures and storage layout is optimized for use by the APT
+ and may not be suitable for all purposes. However it should be possible
+ to extend it with associate cache files that contain other information.
+
+ To keep memory use down the cache file only contains often used fields and
+ fields that are inexpensive to store, the Package file has a full list of
+ fields. Also the client may assume that all items are perfectly valid and
+ need not perform checks against their correctness. Removal of information
+ from the cache is possible, but blanks will be left in the file, and
+ unused strings will also be present. The recommended implementation is to
+ simply rebuild the cache each time any of the data files change. It is
+ possible to add a new package file to the cache without any negative side
+ effects.
+
+ <b>Note on Pointer access</b>
Clients should always use the CacheIterators classes for access to the
- cache. They provide a simple STL-like method for traversing the links
- of the datastructure.
-
- See pkgcachegen.h for information about generating cache structures.
-
- ##################################################################### */
+ cache and the data in it. They also provide a simple STL-like method for
+ traversing the links of the datastructure.
+
+ Every item in every structure is stored as the index to that structure.
+ What this means is that once the files is mmaped every data access has to
+ go through a fix up stage to get a real memory pointer. This is done
+ by taking the index, multiplying it by the type size and then adding
+ it to the start address of the memory block. This sounds complex, but
+ in C it is a single array dereference. Because all items are aligned to
+ their size and indexes are stored as multiples of the size of the structure
+ the format is immediately portable to all possible architectures - BUT the
+ generated files are -NOT-.
+
+ This scheme allows code like this to be written:
+ <example>
+ void *Map = mmap(...);
+ Package *PkgList = (Package *)Map;
+ Header *Head = (Header *)Map;
+ char *Strings = (char *)Map;
+ cout << (Strings + PkgList[Head->HashTable[0]]->Name) << endl;
+ </example>
+ Notice the lack of casting or multiplication. The net result is to return
+ the name of the first package in the first hash bucket, without error
+ checks.
+
+ The generator uses allocation pools to group similarly sized structures in
+ large blocks to eliminate any alignment overhead. The generator also
+ assures that no structures overlap and all indexes are unique. Although
+ at first glance it may seem like there is the potential for two structures
+ to exist at the same point the generator never allows this to happen.
+ (See the discussion of free space pools)
+
+ See \ref pkgcachegen.h for more information about generating cache structures. */
/*}}}*/
#ifndef PKGLIB_PKGCACHE_H
#define PKGLIB_PKGCACHE_H
@@ -32,6 +87,7 @@ class pkgCache /*{{{*/
public:
// Cache element predeclarations
struct Header;
+ struct Group;
struct Package;
struct PackageFile;
struct Version;
@@ -43,6 +99,8 @@ class pkgCache /*{{{*/
struct DescFile;
// Iterators
+ template<typename Str, typename Itr> class Iterator;
+ class GrpIterator;
class PkgIterator;
class VerIterator;
class DescIterator;
@@ -51,14 +109,6 @@ class pkgCache /*{{{*/
class PkgFileIterator;
class VerFileIterator;
class DescFileIterator;
- friend class PkgIterator;
- friend class VerIterator;
- friend class DescInterator;
- friend class DepIterator;
- friend class PrvIterator;
- friend class PkgFileIterator;
- friend class VerFileIterator;
- friend class DescFileIterator;
class Namespace;
@@ -71,12 +121,20 @@ class pkgCache /*{{{*/
{
enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4,
Conflicts=5,Replaces=6,Obsoletes=7,DpkgBreaks=8,Enhances=9};
+ /** \brief available compare operators
+
+ The lower 4 bits are used to indicate what operator is being specified and
+ the upper 4 bits are flags. OR indicates that the next package is
+ or'd with the current package. */
enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3,
Greater=0x4,Equals=0x5,NotEquals=0x6};
};
struct State
{
+ /** \brief priority of a package version
+
+ Zero is used for unparsable or absent Priority fields. */
enum VerPriority {Important=1,Required=2,Standard=3,Optional=4,Extra=5};
enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4};
enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3};
@@ -104,6 +162,7 @@ class pkgCache /*{{{*/
// Pointers to the arrays of items
Header *HeaderP;
+ Group *GrpP;
Package *PkgP;
VerFile *VerFileP;
DescFile *DescFileP;
@@ -124,17 +183,24 @@ class pkgCache /*{{{*/
inline unsigned long Hash(const string &S) const {return sHash(S);};
inline unsigned long Hash(const char *S) const {return sHash(S);};
- // Usefull transformation things
+ // Useful transformation things
const char *Priority(unsigned char Priority);
// Accessors
+ GrpIterator FindGrp(const string &Name);
PkgIterator FindPkg(const string &Name);
+ PkgIterator FindPkg(const string &Name, const string &Arch);
+
Header &Head() {return *HeaderP;};
+ inline GrpIterator GrpBegin();
+ inline GrpIterator GrpEnd();
inline PkgIterator PkgBegin();
inline PkgIterator PkgEnd();
inline PkgFileIterator FileBegin();
inline PkgFileIterator FileEnd();
+ inline bool MultiArchCache() const { return MultiArchEnabled; };
+
// Make me a function
pkgVersioningSystem *VS;
@@ -145,19 +211,40 @@ class pkgCache /*{{{*/
pkgCache(MMap *Map,bool DoMap = true);
virtual ~pkgCache() {};
+
+private:
+ bool MultiArchEnabled;
+ PkgIterator SingleArchFindPkg(const string &Name);
};
/*}}}*/
// Header structure /*{{{*/
struct pkgCache::Header
{
- // Signature information
+ /** \brief Signature information
+
+ This must contain the hex value 0x98FE76DC which is designed to
+ verify that the system loading the image has the same byte order
+ and byte size as the system saving the image */
unsigned long Signature;
+ /** These contain the version of the cache file */
short MajorVersion;
short MinorVersion;
+ /** \brief indicates if the cache should be erased
+
+ Dirty is true if the cache file was opened for reading, the client
+ expects to have written things to it and have not fully synced it.
+ The file should be erased and rebuilt if it is true. */
bool Dirty;
-
- // Size of structure values
+
+ /** \brief Size of structure values
+
+ All *Sz variables contains the sizeof() that particular structure.
+ It is used as an extra consistency check on the structure of the file.
+
+ If any of the size values do not exactly match what the client expects
+ then the client should refuse the load the file. */
unsigned short HeaderSz;
+ unsigned short GroupSz;
unsigned short PackageSz;
unsigned short PackageFileSz;
unsigned short VersionSz;
@@ -166,8 +253,13 @@ struct pkgCache::Header
unsigned short ProvidesSz;
unsigned short VerFileSz;
unsigned short DescFileSz;
-
- // Structure counts
+
+ /** \brief Structure counts
+
+ These indicate the number of each structure contained in the cache.
+ PackageCount is especially useful for generating user state structures.
+ See Package::Id for more info. */
+ unsigned long GroupCount;
unsigned long PackageCount;
unsigned long VersionCount;
unsigned long DescriptionCount;
@@ -176,154 +268,393 @@ struct pkgCache::Header
unsigned long VerFileCount;
unsigned long DescFileCount;
unsigned long ProvidesCount;
-
- // Offsets
- map_ptrloc FileList; // struct PackageFile
- map_ptrloc StringList; // struct StringItem
- map_ptrloc VerSysName; // StringTable
- map_ptrloc Architecture; // StringTable
+
+ /** \brief index of the first PackageFile structure
+
+ The PackageFile structures are singly linked lists that represent
+ all package files that have been merged into the cache. */
+ map_ptrloc FileList;
+ /** \brief index of the first StringItem structure
+
+ The cache contains a list of all the unique strings (StringItems).
+ The parser reads this list into memory so it can match strings
+ against it.*/
+ map_ptrloc StringList;
+ /** \brief String representing the version system used */
+ map_ptrloc VerSysName;
+ /** \brief Architecture(s) the cache was built against */
+ map_ptrloc Architecture;
+ /** \brief The maximum size of a raw entry from the original Package file */
unsigned long MaxVerFileSize;
+ /** \brief The maximum size of a raw entry from the original Translation file */
unsigned long MaxDescFileSize;
- /* Allocation pools, there should be one of these for each structure
- excluding the header */
- DynamicMMap::Pool Pools[8];
+ /** \brief The Pool structures manage the allocation pools that the generator uses
+
+ Start indicates the first byte of the pool, Count is the number of objects
+ remaining in the pool and ItemSize is the structure size (alignment factor)
+ of the pool. An ItemSize of 0 indicates the pool is empty. There should be
+ the same number of pools as there are structure types. The generator
+ stores this information so future additions can make use of any unused pool
+ blocks. */
+ DynamicMMap::Pool Pools[9];
- // Rapid package name lookup
- map_ptrloc HashTable[2*1048];
+ /** \brief hash tables providing rapid group/package name lookup
+
+ Each group/package name is inserted into the hash table using pkgCache::Hash(const &string)
+ By iterating over each entry in the hash table it is possible to iterate over
+ the entire list of packages. Hash Collisions are handled with a singly linked
+ list of packages based at the hash item. The linked list contains only
+ packages that match the hashing function.
+ In the PkgHashTable is it possible that multiple packages have the same name -
+ these packages are stored as a sequence in the list.
+
+ Beware: The Hashmethod assumes that the hash table sizes are equal */
+ map_ptrloc PkgHashTable[2*1048];
+ map_ptrloc GrpHashTable[2*1048];
bool CheckSizes(Header &Against) const;
Header();
};
/*}}}*/
-struct pkgCache::Package /*{{{*/
+// Group structure /*{{{*/
+/** \brief groups architecture depending packages together
+
+ On or more packages with the same name form a group, so we have
+ a simple way to access a package built for different architectures
+ Group exists in a singly linked list of group records starting at
+ the hash index of the name in the pkgCache::Header::GrpHashTable */
+struct pkgCache::Group
{
- // Pointers
- map_ptrloc Name; // Stringtable
+ /** \brief Name of the group */
+ map_ptrloc Name; // StringItem
+
+ // Linked List
+ /** \brief Link to the first package which belongs to the group */
+ map_ptrloc FirstPackage; // Package
+ /** \brief Link to the last package which belongs to the group */
+ map_ptrloc LastPackage; // Package
+ /** \brief Link to the next Group */
+ map_ptrloc Next; // Group
+ /** \brief unique sequel ID */
+ unsigned int ID;
+
+};
+ /*}}}*/
+// Package structure /*{{{*/
+/** \brief contains information for a single unique package
+
+ There can be any number of versions of a given package.
+ Package exists in a singly linked list of package records starting at
+ the hash index of the name in the pkgCache::Header::PkgHashTable
+
+ A package can be created for every architecture so package names are
+ not unique, but it is garanteed that packages with the same name
+ are sequencel ordered in the list. Packages with the same name can be
+ accessed with the Group.
+*/
+struct pkgCache::Package
+{
+ /** \brief Name of the package */
+ map_ptrloc Name; // StringItem
+ /** \brief Architecture of the package */
+ map_ptrloc Arch; // StringItem
+ /** \brief Base of a singly linked list of versions
+
+ Each structure represents a unique version of the package.
+ The version structures contain links into PackageFile and the
+ original text file as well as detailed information about the size
+ and dependencies of the specific package. In this way multiple
+ versions of a package can be cleanly handled by the system.
+ Furthermore, this linked list is guaranteed to be sorted
+ from Highest version to lowest version with no duplicate entries. */
map_ptrloc VersionList; // Version
+ /** \brief index to the installed version */
map_ptrloc CurrentVer; // Version
- map_ptrloc Section; // StringTable (StringItem)
-
- // Linked list
+ /** \brief indicates the deduced section
+
+ Should be the index to the string "Unknown" or to the section
+ of the last parsed item. */
+ map_ptrloc Section; // StringItem
+ /** \brief index of the group this package belongs to */
+ map_ptrloc Group; // Group the Package belongs to
+
+ // Linked list
+ /** \brief Link to the next package in the same bucket */
map_ptrloc NextPackage; // Package
+ /** \brief List of all dependencies on this package */
map_ptrloc RevDepends; // Dependency
+ /** \brief List of all "packages" this package provide */
map_ptrloc ProvidesList; // Provides
// Install/Remove/Purge etc
+ /** \brief state that the user wishes the package to be in */
unsigned char SelectedState; // What
+ /** \brief installation state of the package
+
+ This should be "ok" but in case the installation failed
+ it will be different.
+ */
unsigned char InstState; // Flags
+ /** \brief indicates if the package is installed */
unsigned char CurrentState; // State
-
+
+ /** \brief unique sequel ID
+
+ ID is a unique value from 0 to Header->PackageCount assigned by the generator.
+ This allows clients to create an array of size PackageCount and use it to store
+ state information for the package map. For instance the status file emitter uses
+ this to track which packages have been emitted already. */
unsigned int ID;
+ /** \brief some useful indicators of the package's state */
unsigned long Flags;
};
/*}}}*/
-struct pkgCache::PackageFile /*{{{*/
+// Package File structure /*{{{*/
+/** \brief stores information about the files used to generate the cache
+
+ Package files are referenced by Version structures to be able to know
+ after the generation still from which Packages file includes this Version
+ as we need this information later on e.g. for pinning. */
+struct pkgCache::PackageFile
{
- // Names
- map_ptrloc FileName; // Stringtable
- map_ptrloc Archive; // Stringtable
- map_ptrloc Codename; // Stringtable
- map_ptrloc Component; // Stringtable
- map_ptrloc Version; // Stringtable
- map_ptrloc Origin; // Stringtable
- map_ptrloc Label; // Stringtable
- map_ptrloc Architecture; // Stringtable
- map_ptrloc Site; // Stringtable
- map_ptrloc IndexType; // Stringtable
- unsigned long Size;
+ /** \brief physical disk file that this PackageFile represents */
+ map_ptrloc FileName; // StringItem
+ /** \brief the release information
+
+ Please see the files document for a description of what the
+ release information means. */
+ map_ptrloc Archive; // StringItem
+ map_ptrloc Codename; // StringItem
+ map_ptrloc Component; // StringItem
+ map_ptrloc Version; // StringItem
+ map_ptrloc Origin; // StringItem
+ map_ptrloc Label; // StringItem
+ map_ptrloc Architecture; // StringItem
+ /** \brief The site the index file was fetched from */
+ map_ptrloc Site; // StringItem
+ /** \brief indicates what sort of index file this is
+
+ @TODO enumerate at least the possible indexes */
+ map_ptrloc IndexType; // StringItem
+ /** \brief Size of the file
+
+ Used together with the modification time as a
+ simple check to ensure that the Packages
+ file has not been altered since Cache generation. */
+ unsigned long Size;
+ /** \brief Modification time for the file */
+ time_t mtime;
+
+ /* @TODO document PackageFile::Flags */
unsigned long Flags;
-
+
// Linked list
+ /** \brief Link to the next PackageFile in the Cache */
map_ptrloc NextFile; // PackageFile
+ /** \brief unique sequel ID */
unsigned int ID;
- time_t mtime; // Modification time for the file
};
/*}}}*/
-struct pkgCache::VerFile /*{{{*/
+// VerFile structure /*{{{*/
+/** \brief associates a version with a PackageFile
+
+ This allows a full description of all Versions in all files
+ (and hence all sources) under consideration. */
+struct pkgCache::VerFile
{
+ /** \brief index of the package file that this version was found in */
map_ptrloc File; // PackageFile
+ /** \brief next step in the linked list */
map_ptrloc NextFile; // PkgVerFile
+ /** \brief position in the package file */
map_ptrloc Offset; // File offset
+ /* @TODO document pkgCache::VerFile::Size */
unsigned long Size;
};
/*}}}*/
-struct pkgCache::DescFile /*{{{*/
+// DescFile structure /*{{{*/
+/** \brief associates a description with a Translation file */
+struct pkgCache::DescFile
{
+ /** \brief index of the file that this description was found in */
map_ptrloc File; // PackageFile
+ /** \brief next step in the linked list */
map_ptrloc NextFile; // PkgVerFile
+ /** \brief position in the file */
map_ptrloc Offset; // File offset
+ /* @TODO document pkgCache::DescFile::Size */
unsigned long Size;
};
/*}}}*/
-struct pkgCache::Version /*{{{*/
+// Version structure /*{{{*/
+/** \brief information for a single version of a package
+
+ The version list is always sorted from highest version to lowest
+ version by the generator. Equal version numbers are either merged
+ or handled as separate versions based on the Hash value. */
+struct pkgCache::Version
{
- map_ptrloc VerStr; // Stringtable
- map_ptrloc Section; // StringTable (StringItem)
- map_ptrloc Arch; // StringTable
-
- // Lists
+ /** \brief complete version string */
+ map_ptrloc VerStr; // StringItem
+ /** \brief section this version is filled in */
+ map_ptrloc Section; // StringItem
+ /** \brief stores the MultiArch capabilities of this version
+
+ None is the default and doesn't trigger special behaviour,
+ Foreign means that this version can fulfill dependencies even
+ if it is built for another architecture as the requester.
+ Same indicates that builds for different architectures can
+ be co-installed on the system and All is the marker for a
+ version with the Architecture: all. */
+ enum {None, All, Foreign, Same, Allowed} MultiArch;
+
+ /** \brief references all the PackageFile's that this version came from
+
+ FileList can be used to determine what distribution(s) the Version
+ applies to. If FileList is 0 then this is a blank version.
+ The structure should also have a 0 in all other fields excluding
+ pkgCache::Version::VerStr and Possibly pkgCache::Version::NextVer. */
map_ptrloc FileList; // VerFile
+ /** \brief next (lower or equal) version in the linked list */
map_ptrloc NextVer; // Version
+ /** \brief next description in the linked list */
map_ptrloc DescriptionList; // Description
+ /** \brief base of the dependency list */
map_ptrloc DependsList; // Dependency
+ /** \brief links to the owning package
+
+ This allows reverse dependencies to determine the package */
map_ptrloc ParentPkg; // Package
+ /** \brief list of pkgCache::Provides */
map_ptrloc ProvidesList; // Provides
-
+
+ /** \brief archive size for this version
+
+ For Debian this is the size of the .deb file. */
map_ptrloc Size; // These are the .deb size
+ /** \brief uncompressed size for this version */
map_ptrloc InstalledSize;
+ /** \brief characteristic value representing this version
+
+ No two packages in existence should have the same VerStr
+ and Hash with different contents. */
unsigned short Hash;
+ /** \brief unique sequel ID */
unsigned int ID;
+ /** \brief parsed priority value */
unsigned char Priority;
};
/*}}}*/
-struct pkgCache::Description /*{{{*/
+// Description structure /*{{{*/
+/** \brief datamember of a linked list of available description for a version */
+struct pkgCache::Description
{
- // Language Code store the description translation language code. If
- // the value has a 0 lenght then this is readed using the Package
- // file else the Translation-CODE are used.
- map_ptrloc language_code; // StringTable
- map_ptrloc md5sum; // StringTable
+ /** \brief Language code of this description (translation)
+
+ If the value has a 0 length then this is read using the Package
+ file else the Translation-CODE file is used. */
+ map_ptrloc language_code; // StringItem
+ /** \brief MD5sum of the original description
+
+ Used to map Translations of a description to a version
+ and to check that the Translation is up-to-date. */
+ map_ptrloc md5sum; // StringItem
- // Linked list
+ /* @TODO document pkgCache::Description::FileList */
map_ptrloc FileList; // DescFile
+ /** \brief next translation for this description */
map_ptrloc NextDesc; // Description
+ /** \brief the text is a description of this package */
map_ptrloc ParentPkg; // Package
+ /** \brief unique sequel ID */
unsigned int ID;
};
/*}}}*/
-struct pkgCache::Dependency /*{{{*/
+// Dependency structure /*{{{*/
+/** \brief information for a single dependency record
+
+ The records are split up like this to ease processing by the client.
+ The base of the linked list is pkgCache::Version::DependsList.
+ All forms of dependencies are recorded here including Depends,
+ Recommends, Suggests, Enhances, Conflicts, Replaces and Breaks. */
+struct pkgCache::Dependency
{
- map_ptrloc Version; // Stringtable
+ /** \brief string of the version the dependency is applied against */
+ map_ptrloc Version; // StringItem
+ /** \brief index of the package this depends applies to
+
+ The generator will - if the package does not already exist -
+ create a blank (no version records) package. */
map_ptrloc Package; // Package
+ /** \brief next dependency of this version */
map_ptrloc NextDepends; // Dependency
+ /** \brief next reverse dependency of this package */
map_ptrloc NextRevDepends; // Dependency
+ /** \brief version of the package which has the reverse depends */
map_ptrloc ParentVer; // Version
-
- // Specific types of depends
- map_ptrloc ID;
+
+ /** \brief unique sequel ID */
+ map_ptrloc ID;
+ /** \brief Dependency type - Depends, Recommends, Conflicts, etc */
unsigned char Type;
+ /** \brief comparison operator specified on the depends line
+
+ If the high bit is set then it is a logical OR with the previous record. */
unsigned char CompareOp;
};
/*}}}*/
-struct pkgCache::Provides /*{{{*/
+// Provides structure /*{{{*/
+/** \brief handles virtual packages
+
+ When a Provides: line is encountered a new provides record is added
+ associating the package with a virtual package name.
+ The provides structures are linked off the package structures.
+ This simplifies the analysis of dependencies and other aspects A provides
+ refers to a specific version of a specific package, not all versions need to
+ provide that provides.*/
+struct pkgCache::Provides
{
- map_ptrloc ParentPkg; // Pacakge
+ /** \brief index of the package providing this */
+ map_ptrloc ParentPkg; // Package
+ /** \brief index of the version this provide line applies to */
map_ptrloc Version; // Version
- map_ptrloc ProvideVersion; // Stringtable
+ /** \brief version in the provides line (if any)
+
+ This version allows dependencies to depend on specific versions of a
+ Provides, as well as allowing Provides to override existing packages.
+ This is experimental. Note that Debian doesn't allow versioned provides */
+ map_ptrloc ProvideVersion; // StringItem
+ /** \brief next provides (based of package) */
map_ptrloc NextProvides; // Provides
+ /** \brief next provides (based of version) */
map_ptrloc NextPkgProv; // Provides
};
/*}}}*/
-struct pkgCache::StringItem /*{{{*/
+// StringItem structure /*{{{*/
+/** \brief used for generating single instances of strings
+
+ Some things like Section Name are are useful to have as unique tags.
+ It is part of a linked list based at pkgCache::Header::StringList
+
+ All strings are simply inlined any place in the file that is natural
+ for the writer. The client should make no assumptions about the positioning
+ of strings. All StringItems should be null-terminated. */
+struct pkgCache::StringItem
{
- map_ptrloc String; // Stringtable
+ /** \brief string this refers to */
+ map_ptrloc String; // StringItem
+ /** \brief Next link in the chain */
map_ptrloc NextItem; // StringItem
};
/*}}}*/
#include <apt-pkg/cacheiterators.h>
+inline pkgCache::GrpIterator pkgCache::GrpBegin()
+ {return GrpIterator(*this);};
+inline pkgCache::GrpIterator pkgCache::GrpEnd()
+ {return GrpIterator(*this,GrpP);};
inline pkgCache::PkgIterator pkgCache::PkgBegin()
{return PkgIterator(*this);};
inline pkgCache::PkgIterator pkgCache::PkgEnd()
@@ -337,7 +668,7 @@ inline pkgCache::PkgFileIterator pkgCache::FileEnd()
class pkgCache::Namespace /*{{{*/
{
public:
-
+ typedef pkgCache::GrpIterator GrpIterator;
typedef pkgCache::PkgIterator PkgIterator;
typedef pkgCache::VerIterator VerIterator;
typedef pkgCache::DescIterator DescIterator;
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index 3eeb18cae..d96d3370f 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -18,6 +18,7 @@
#include <apt-pkg/progress.h>
#include <apt-pkg/sourcelist.h>
#include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/sptr.h>
#include <apt-pkg/pkgsystem.h>
@@ -38,7 +39,7 @@ typedef vector<pkgIndexFile *>::iterator FileIterator;
// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
// ---------------------------------------------------------------------
-/* We set the diry flag and make sure that is written to the disk */
+/* We set the dirty flag and make sure that is written to the disk */
pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
Map(*pMap), Cache(pMap,false), Progress(Prog),
FoundFileDeps(0)
@@ -107,13 +108,26 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
unsigned int Counter = 0;
while (List.Step() == true)
{
- // Get a pointer to the package structure
- string PackageName = List.Package();
+ string const PackageName = List.Package();
if (PackageName.empty() == true)
return false;
-
+
+ /* As we handle Arch all packages as architecture bounded
+ we add all information to every (simulated) arch package */
+ std::vector<string> genArch;
+ if (List.ArchitectureAll() == true) {
+ genArch = APT::Configuration::getArchitectures();
+ if (genArch.size() != 1)
+ genArch.push_back("all");
+ } else
+ genArch.push_back(List.Architecture());
+
+ for (std::vector<string>::const_iterator arch = genArch.begin();
+ arch != genArch.end(); ++arch)
+ {
+ // Get a pointer to the package structure
pkgCache::PkgIterator Pkg;
- if (NewPackage(Pkg,PackageName) == false)
+ if (NewPackage(Pkg, PackageName, *arch) == false)
return _error->Error(_("Error occurred while processing %s (NewPackage)"),PackageName.c_str());
Counter++;
if (Counter % 100 == 0 && Progress != 0)
@@ -175,17 +189,22 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
pkgCache::VerIterator Ver = Pkg.VersionList();
map_ptrloc *LastVer = &Pkg->VersionList;
int Res = 1;
+ unsigned long const Hash = List.VersionHash();
for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
{
Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
- if (Res >= 0)
+ // Version is higher as current version - insert here
+ if (Res > 0)
+ break;
+ // Versionstrings are equal - is hash also equal?
+ if (Res == 0 && Ver->Hash == Hash)
break;
+ // proceed with the next till we have either the right
+ // or we found another version (which will be lower)
}
-
- /* We already have a version for this item, record that we
- saw it */
- unsigned long Hash = List.VersionHash();
- if (Res == 0 && Ver->Hash == Hash)
+
+ /* We already have a version for this item, record that we saw it */
+ if (Res == 0 && Ver.end() == false && Ver->Hash == Hash)
{
if (List.UsePackage(Pkg,Ver) == false)
return _error->Error(_("Error occurred while processing %s (UsePackage2)"),
@@ -204,17 +223,6 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
}
continue;
- }
-
- // Skip to the end of the same version set.
- if (Res == 0)
- {
- for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
- {
- Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
- if (Res != 0)
- break;
- }
}
// Add a new version
@@ -256,6 +264,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false)
return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str());
+ }
}
FoundFileDeps |= List.HasFileDeps();
@@ -323,33 +332,79 @@ bool pkgCacheGenerator::MergeFileProvides(ListParser &List)
return true;
}
/*}}}*/
-// CacheGenerator::NewPackage - Add a new package /*{{{*/
+// CacheGenerator::NewGroup - Add a new group /*{{{*/
// ---------------------------------------------------------------------
-/* This creates a new package structure and adds it to the hash table */
-bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name)
+/* This creates a new group structure and adds it to the hash table */
+bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name)
{
- Pkg = Cache.FindPkg(Name);
- if (Pkg.end() == false)
+ Grp = Cache.FindGrp(Name);
+ if (Grp.end() == false)
return true;
// Get a structure
- unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
- if (Package == 0)
+ unsigned long const Group = Map.Allocate(sizeof(pkgCache::Group));
+ if (unlikely(Group == 0))
return false;
-
- Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
-
+
+ Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
+ Grp->Name = Map.WriteString(Name);
+ if (unlikely(Grp->Name == 0))
+ return false;
+
// Insert it into the hash table
- unsigned long Hash = Cache.Hash(Name);
- Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
- Cache.HeaderP->HashTable[Hash] = Package;
-
- // Set the name and the ID
- Pkg->Name = Map.WriteString(Name);
- if (Pkg->Name == 0)
+ unsigned long const Hash = Cache.Hash(Name);
+ Grp->Next = Cache.HeaderP->GrpHashTable[Hash];
+ Cache.HeaderP->GrpHashTable[Hash] = Group;
+
+ Grp->ID = Cache.HeaderP->GroupCount++;
+ return true;
+}
+ /*}}}*/
+// CacheGenerator::NewPackage - Add a new package /*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a new package structure and adds it to the hash table */
+bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name,
+ const string &Arch) {
+ pkgCache::GrpIterator Grp;
+ if (unlikely(NewGroup(Grp, Name) == false))
+ return false;
+
+ Pkg = Grp.FindPkg(Arch);
+ if (Pkg.end() == false)
+ return true;
+
+ // Get a structure
+ unsigned long const Package = Map.Allocate(sizeof(pkgCache::Package));
+ if (unlikely(Package == 0))
+ return false;
+ Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
+
+ // Insert the package into our package list
+ if (Grp->FirstPackage == 0) // the group is new
+ {
+ // Insert it into the hash table
+ unsigned long const Hash = Cache.Hash(Name);
+ Pkg->NextPackage = Cache.HeaderP->PkgHashTable[Hash];
+ Cache.HeaderP->PkgHashTable[Hash] = Package;
+ Grp->FirstPackage = Package;
+ }
+ else // Group the Packages together
+ {
+ // this package is the new last package
+ pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
+ Pkg->NextPackage = LastPkg->NextPackage;
+ LastPkg->NextPackage = Package;
+ }
+ Grp->LastPackage = Package;
+
+ // Set the name, arch and the ID
+ Pkg->Name = Grp->Name;
+ Pkg->Group = Grp.Index();
+ Pkg->Arch = WriteUniqString(Arch.c_str());
+ if (unlikely(Pkg->Arch == 0))
return false;
Pkg->ID = Cache.HeaderP->PackageCount++;
-
+
return true;
}
/*}}}*/
@@ -468,21 +523,95 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
return Description;
}
/*}}}*/
-// ListParser::NewDepends - Create a dependency element /*{{{*/
+// CacheGenerator::FinishCache - do various finish operations /*{{{*/
+// ---------------------------------------------------------------------
+/* This prepares the Cache for delivery */
+bool pkgCacheGenerator::FinishCache(OpProgress &Progress)
+{
+ // FIXME: add progress reporting for this operation
+ // Do we have different architectures in your groups ?
+ vector<string> archs = APT::Configuration::getArchitectures();
+ if (archs.size() > 1)
+ {
+ // Create Conflicts in between the group
+ for (pkgCache::GrpIterator G = GetCache().GrpBegin(); G.end() != true; G++)
+ {
+ string const PkgName = G.Name();
+ for (pkgCache::PkgIterator P = G.PackageList(); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(),"all") == 0)
+ continue;
+ pkgCache::PkgIterator allPkg;
+ for (pkgCache::VerIterator V = P.VersionList(); V.end() != true; V++)
+ {
+ string const Arch = V.Arch(true);
+ map_ptrloc *OldDepLast = NULL;
+ /* MultiArch handling introduces a lot of implicit Dependencies:
+ - MultiArch: same → Co-Installable if they have the same version
+ - Architecture: all → Need to be Co-Installable for internal reasons
+ - All others conflict with all other group members */
+ bool const coInstall = (V->MultiArch == pkgCache::Version::All ||
+ V->MultiArch == pkgCache::Version::Same);
+ if (V->MultiArch == pkgCache::Version::All && allPkg.end() == true)
+ allPkg = G.FindPkg("all");
+ for (vector<string>::const_iterator A = archs.begin(); A != archs.end(); ++A)
+ {
+ if (*A == Arch)
+ continue;
+ /* We allow only one installed arch at the time
+ per group, therefore each group member conflicts
+ with all other group members */
+ pkgCache::PkgIterator D = G.FindPkg(*A);
+ if (D.end() == true)
+ continue;
+ if (coInstall == true)
+ {
+ // Replaces: ${self}:other ( << ${binary:Version})
+ NewDepends(D, V, V.VerStr(),
+ pkgCache::Dep::Less, pkgCache::Dep::Replaces,
+ OldDepLast);
+ // Breaks: ${self}:other (!= ${binary:Version})
+ NewDepends(D, V, V.VerStr(),
+ pkgCache::Dep::Less, pkgCache::Dep::DpkgBreaks,
+ OldDepLast);
+ NewDepends(D, V, V.VerStr(),
+ pkgCache::Dep::Greater, pkgCache::Dep::DpkgBreaks,
+ OldDepLast);
+ if (V->MultiArch == pkgCache::Version::All)
+ {
+ // Depend on ${self}:all which does depend on nothing
+ NewDepends(allPkg, V, V.VerStr(),
+ pkgCache::Dep::Equals, pkgCache::Dep::Depends,
+ OldDepLast);
+ }
+ } else {
+ // Conflicts: ${self}:other
+ NewDepends(D, V, "",
+ pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
+ OldDepLast);
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+ /*}}}*/
+// CacheGenerator::NewDepends - Create a dependency element /*{{{*/
// ---------------------------------------------------------------------
/* This creates a dependency element in the tree. It is linked to the
version and to the package that it is pointing to. */
-bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
- const string &PackageName,
- const string &Version,
- unsigned int Op,
- unsigned int Type)
+bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
+ pkgCache::VerIterator &Ver,
+ string const &Version,
+ unsigned int const &Op,
+ unsigned int const &Type,
+ map_ptrloc *OldDepLast)
{
- pkgCache &Cache = Owner->Cache;
-
// Get a structure
- unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
- if (Dependency == 0)
+ unsigned long const Dependency = Map.Allocate(sizeof(pkgCache::Dependency));
+ if (unlikely(Dependency == 0))
return false;
// Fill it in
@@ -491,12 +620,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
Dep->Type = Type;
Dep->CompareOp = Op;
Dep->ID = Cache.HeaderP->DependsCount++;
-
- // Locate the target package
- pkgCache::PkgIterator Pkg;
- if (Owner->NewPackage(Pkg,PackageName) == false)
- return false;
-
+
// Probe the reverse dependency list for a version string that matches
if (Version.empty() == false)
{
@@ -504,29 +628,23 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
if (I->Version != 0 && I.TargetVer() == Version)
Dep->Version = I->Version;*/
if (Dep->Version == 0)
- if ((Dep->Version = WriteString(Version)) == 0)
+ if (unlikely((Dep->Version = Map.WriteString(Version)) == 0))
return false;
}
-
+
// Link it to the package
Dep->Package = Pkg.Index();
Dep->NextRevDepends = Pkg->RevDepends;
Pkg->RevDepends = Dep.Index();
-
- /* Link it to the version (at the end of the list)
- Caching the old end point speeds up generation substantially */
- if (OldDepVer != Ver)
+
+ // Do we know where to link the Dependency to?
+ if (OldDepLast == NULL)
{
OldDepLast = &Ver->DependsList;
for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
OldDepLast = &D->NextDepends;
- OldDepVer = Ver;
}
- // Is it a file dependency?
- if (PackageName[0] == '/')
- FoundFileDeps = true;
-
Dep->NextDepends = *OldDepLast;
*OldDepLast = Dep.Index();
OldDepLast = &Dep->NextDepends;
@@ -534,22 +652,58 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
return true;
}
/*}}}*/
+// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a Group and the Package to link this dependency to if
+ needed and handles also the caching of the old endpoint */
+bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
+ const string &PackageName,
+ const string &Arch,
+ const string &Version,
+ unsigned int Op,
+ unsigned int Type)
+{
+ pkgCache::GrpIterator Grp;
+ if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
+ return false;
+
+ // Locate the target package
+ pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
+ if (Pkg.end() == true) {
+ if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
+ return false;
+ }
+
+ // Is it a file dependency?
+ if (unlikely(PackageName[0] == '/'))
+ FoundFileDeps = true;
+
+ /* Caching the old end point speeds up generation substantially */
+ if (OldDepVer != Ver) {
+ OldDepLast = NULL;
+ OldDepVer = Ver;
+ }
+
+ return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
+}
+ /*}}}*/
// ListParser::NewProvides - Create a Provides element /*{{{*/
// ---------------------------------------------------------------------
/* */
bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
- const string &PackageName,
+ const string &PkgName,
+ const string &PkgArch,
const string &Version)
{
pkgCache &Cache = Owner->Cache;
// We do not add self referencing provides
- if (Ver.ParentPkg().Name() == PackageName)
+ if (Ver.ParentPkg().Name() == PkgName && PkgArch == Ver.Arch(true))
return true;
// Get a structure
- unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
- if (Provides == 0)
+ unsigned long const Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
+ if (unlikely(Provides == 0))
return false;
Cache.HeaderP->ProvidesCount++;
@@ -558,12 +712,12 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
Prv->Version = Ver.Index();
Prv->NextPkgProv = Ver->ProvidesList;
Ver->ProvidesList = Prv.Index();
- if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
+ if (Version.empty() == false && unlikely((Prv->ProvideVersion = WriteString(Version)) == 0))
return false;
// Locate the target package
pkgCache::PkgIterator Pkg;
- if (Owner->NewPackage(Pkg,PackageName) == false)
+ if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
return false;
// Link it to the package
@@ -848,7 +1002,20 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
// Decide if we can write to the files..
string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
-
+
+ // ensure the cache directory exists
+ if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
+ {
+ string dir = _config->FindDir("Dir::Cache");
+ size_t const len = dir.size();
+ if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
+ dir = dir.substr(0, len - 5);
+ if (CacheFile.empty() == false)
+ CreateDirectory(dir, flNotFile(CacheFile));
+ if (SrcCacheFile.empty() == false)
+ CreateDirectory(dir, flNotFile(SrcCacheFile));
+ }
+
// Decide if we can write to the cache
bool Writeable = false;
if (CacheFile.empty() == false)
@@ -923,6 +1090,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
Files.begin()+EndOfSource,Files.end()) == false)
return false;
+
+ // FIXME: move me to a better place
+ Gen.FinishCache(Progress);
}
else
{
@@ -965,6 +1135,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
Files.begin()+EndOfSource,Files.end()) == false)
return false;
+
+ // FIXME: move me to a better place
+ Gen.FinishCache(Progress);
}
if (Debug == true)
std::clog << "Caches are ready for shipping" << std::endl;
@@ -1012,7 +1185,10 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
Files.begin()+EndOfSource,Files.end()) == false)
return false;
-
+
+ // FIXME: move me to a better place
+ Gen.FinishCache(Progress);
+
if (_error->PendingError() == true)
return false;
*OutMap = Map.UnGuard();
diff --git a/apt-pkg/pkgcachegen.h b/apt-pkg/pkgcachegen.h
index 108b34207..46d0cd893 100644
--- a/apt-pkg/pkgcachegen.h
+++ b/apt-pkg/pkgcachegen.h
@@ -51,9 +51,13 @@ class pkgCacheGenerator /*{{{*/
// Flag file dependencies
bool FoundFileDeps;
- bool NewPackage(pkgCache::PkgIterator &Pkg,const string &PkgName);
+ bool NewGroup(pkgCache::GrpIterator &Grp,const string &Name);
+ bool NewPackage(pkgCache::PkgIterator &Pkg,const string &Name, const string &Arch);
bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
+ bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
+ string const &Version, unsigned int const &Op,
+ unsigned int const &Type, map_ptrloc *OldDepLast);
unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next);
map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
@@ -72,7 +76,8 @@ class pkgCacheGenerator /*{{{*/
bool HasFileDeps() {return FoundFileDeps;};
bool MergeFileProvides(ListParser &List);
-
+ bool FinishCache(OpProgress &Progress);
+
pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
~pkgCacheGenerator();
};
@@ -96,16 +101,18 @@ class pkgCacheGenerator::ListParser
inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);};
inline unsigned long WriteString(const string &S) {return Owner->Map.WriteString(S);};
inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);};
- bool NewDepends(pkgCache::VerIterator Ver,const string &Package,
+ bool NewDepends(pkgCache::VerIterator Ver,const string &Package, const string &Arch,
const string &Version,unsigned int Op,
unsigned int Type);
- bool NewProvides(pkgCache::VerIterator Ver,const string &Package,
- const string &Version);
+ bool NewProvides(pkgCache::VerIterator Ver,const string &PkgName,
+ const string &PkgArch, const string &Version);
public:
// These all operate against the current section
virtual string Package() = 0;
+ virtual string Architecture() = 0;
+ virtual bool ArchitectureAll() = 0;
virtual string Version() = 0;
virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
virtual string Description() = 0;
diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc
index 4996007a3..479cf3935 100644
--- a/apt-pkg/policy.cc
+++ b/apt-pkg/policy.cc
@@ -201,35 +201,38 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
string Data,signed short Priority)
{
- Pin *P = 0;
-
if (Name.empty() == true)
- P = &*Defaults.insert(Defaults.end(),PkgPin());
- else
{
- // Get a spot to put the pin
- pkgCache::PkgIterator Pkg = Cache->FindPkg(Name);
- if (Pkg.end() == true)
+ Pin *P = &*Defaults.insert(Defaults.end(),PkgPin());
+ P->Type = Type;
+ P->Priority = Priority;
+ P->Data = Data;
+ return;
+ }
+
+ // Get a spot to put the pin
+ pkgCache::GrpIterator Grp = Cache->FindGrp(Name);
+ for (pkgCache::PkgIterator Pkg = Grp.FindPkg("any");
+ Pkg.end() != true; Pkg = Grp.NextPkg(Pkg))
+ {
+ Pin *P = 0;
+ if (Pkg.end() == false)
+ P = Pins + Pkg->ID;
+ else
{
// Check the unmatched table
- for (vector<PkgPin>::iterator I = Unmatched.begin();
+ for (vector<PkgPin>::iterator I = Unmatched.begin();
I != Unmatched.end() && P == 0; I++)
if (I->Pkg == Name)
P = &*I;
-
+
if (P == 0)
- P = &*Unmatched.insert(Unmatched.end(),PkgPin());
+ P = &*Unmatched.insert(Unmatched.end(),PkgPin());
}
- else
- {
- P = Pins + Pkg->ID;
- }
+ P->Type = Type;
+ P->Priority = Priority;
+ P->Data = Data;
}
-
- // Set..
- P->Type = Type;
- P->Priority = Priority;
- P->Data = Data;
}
/*}}}*/
// Policy::GetMatch - Get the matching version for a package pin /*{{{*/
diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc
index 929259961..e13472fa6 100644
--- a/apt-pkg/sourcelist.cc
+++ b/apt-pkg/sourcelist.cc
@@ -72,13 +72,58 @@ bool pkgSourceList::Type::FixupURI(string &URI) const
Weird types may override this. */
bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
const char *Buffer,
- unsigned long CurLine,
- string File) const
+ unsigned long const &CurLine,
+ string const &File) const
{
+ for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+
+ // Parse option field if it exists
+ // e.g.: [ option1=value1 option2=value2 ]
+ map<string, string> Options;
+ if (Buffer != 0 && Buffer[0] == '[')
+ {
+ ++Buffer; // ignore the [
+ for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+ while (*Buffer != ']')
+ {
+ // get one option, e.g. option1=value1
+ string option;
+ if (ParseQuoteWord(Buffer,option) == false)
+ return _error->Error(_("Malformed line %lu in source list %s ([option] unparseable)"),CurLine,File.c_str());
+
+ if (option.length() < 3)
+ return _error->Error(_("Malformed line %lu in source list %s ([option] too short)"),CurLine,File.c_str());
+
+ // accept options even if the last has no space before the ]-end marker
+ if (option.at(option.length()-1) == ']')
+ {
+ for (; *Buffer != ']'; --Buffer);
+ option.resize(option.length()-1);
+ }
+
+ size_t const needle = option.find('=');
+ if (needle == string::npos)
+ return _error->Error(_("Malformed line %lu in source list %s ([%s] is not an assignment)"),CurLine,File.c_str(), option.c_str());
+
+ string const key = string(option, 0, needle);
+ string const value = string(option, needle + 1, option.length());
+
+ if (key.empty() == true)
+ return _error->Error(_("Malformed line %lu in source list %s ([%s] has no key)"),CurLine,File.c_str(), option.c_str());
+
+ if (value.empty() == true)
+ return _error->Error(_("Malformed line %lu in source list %s ([%s] key %s has no value)"),CurLine,File.c_str(),option.c_str(),key.c_str());
+
+ Options[key] = value;
+ }
+ ++Buffer; // ignore the ]
+ for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+ }
+
string URI;
string Dist;
- string Section;
-
+ string Section;
+
if (ParseQuoteWord(Buffer,URI) == false)
return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
if (ParseQuoteWord(Buffer,Dist) == false)
@@ -93,7 +138,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
if (ParseQuoteWord(Buffer,Section) == true)
return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
- return CreateItem(List,URI,Dist,Section);
+ return CreateItem(List, URI, Dist, Section, Options);
}
// Grab the rest of the dists
@@ -102,7 +147,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
do
{
- if (CreateItem(List,URI,Dist,Section) == false)
+ if (CreateItem(List, URI, Dist, Section, Options) == false)
return false;
}
while (ParseQuoteWord(Buffer,Section) == true);
@@ -239,36 +284,7 @@ bool pkgSourceList::ReadAppend(string File)
if (Parse == 0)
return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
- // Vendor name specified
- if (C[0] == '[')
- {
- string VendorID;
-
- if (ParseQuoteWord(C,VendorID) == false)
- return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
-
- if (VendorID.length() < 2 || VendorID.end()[-1] != ']')
- return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
- VendorID = string(VendorID,1,VendorID.size()-2);
-
-// for (vector<const Vendor *>::const_iterator iter = VendorList.begin();
-// iter != VendorList.end(); iter++)
-// {
-// if ((*iter)->GetVendorID() == VendorID)
-// {
-// if (_config->FindB("Debug::sourceList", false))
-// std::cerr << "Comparing VendorID \"" << VendorID << "\" with \"" << (*iter)->GetVendorID() << '"' << std::endl;
-// Verifier = *iter;
-// break;
-// }
-// }
-
-// if (Verifier == 0)
-// return _error->Error(_("Unknown vendor ID '%s' in line %u of source list %s"),
-// VendorID.c_str(),CurLine,File.c_str());
- }
-
- if (Parse->ParseLine(SrcList,C,CurLine,File) == false)
+ if (Parse->ParseLine(SrcList, C, CurLine, File) == false)
return false;
}
return true;
diff --git a/apt-pkg/sourcelist.h b/apt-pkg/sourcelist.h
index b9e4389ed..e15314a5e 100644
--- a/apt-pkg/sourcelist.h
+++ b/apt-pkg/sourcelist.h
@@ -29,6 +29,7 @@
#include <string>
#include <vector>
+#include <map>
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/metaindex.h>
@@ -57,9 +58,10 @@ class pkgSourceList
bool FixupURI(string &URI) const;
virtual bool ParseLine(vector<metaIndex *> &List,
const char *Buffer,
- unsigned long CurLine,string File) const;
- virtual bool CreateItem(vector<metaIndex *> &List,string URI,
- string Dist,string Section) const = 0;
+ unsigned long const &CurLine,string const &File) const;
+ virtual bool CreateItem(vector<metaIndex *> &List,string const &URI,
+ string const &Dist,string const &Section,
+ std::map<string, string> const &Options) const = 0;
Type();
virtual ~Type() {};
};
diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc
index 7c5d15a58..0d4999ee7 100644
--- a/apt-pkg/tagfile.cc
+++ b/apt-pkg/tagfile.cc
@@ -193,17 +193,8 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
/*}}}*/
// TagSection::Scan - Scan for the end of the header information /*{{{*/
// ---------------------------------------------------------------------
-/* This looks for the first double new line in the data stream. It also
- indexes the tags in the section. This very simple hash function for the
- last 8 letters gives very good performance on the debian package files */
-inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
-{
- unsigned long Res = 0;
- for (; Text != End && *Text != ':' && *Text != 0; Text++)
- Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1);
- return Res & 0xFF;
-}
-
+/* This looks for the first double new line in the data stream.
+ It also indexes the tags in the section. */
bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
{
const char *End = Start + MaxLength;
diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h
index 321329a23..f63a51d07 100644
--- a/apt-pkg/tagfile.h
+++ b/apt-pkg/tagfile.h
@@ -33,7 +33,18 @@ class pkgTagSection
unsigned int AlphaIndexes[0x100];
unsigned int TagCount;
-
+
+ /* This very simple hash function for the last 8 letters gives
+ very good performance on the debian package files */
+ inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
+ {
+ unsigned long Res = 0;
+ for (; Text != End && *Text != ':' && *Text != 0; Text++)
+ Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1);
+ return Res & 0xFF;
+ }
+
+
protected:
const char *Stop;
@@ -54,6 +65,8 @@ class pkgTagSection
virtual void TrimRecord(bool BeforeRecord, const char* &End);
inline unsigned int Count() const {return TagCount;};
+ inline bool Exists(const char* const Tag) {return AlphaIndexes[AlphaHash(Tag)] != 0;}
+
inline void Get(const char *&Start,const char *&Stop,unsigned int I) const
{Start = Section + Indexes[I]; Stop = Section + Indexes[I+1];}
diff --git a/apt-pkg/versionmatch.cc b/apt-pkg/versionmatch.cc
index b4d1d4696..e5f0fafd2 100644
--- a/apt-pkg/versionmatch.cc
+++ b/apt-pkg/versionmatch.cc
@@ -100,6 +100,8 @@ pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type)
RelLabel = Fragments[J]+2;
else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0)
RelComponent = Fragments[J]+2;
+ else if (stringcasecmp(Fragments[J],Fragments[J]+2,"b=") == 0)
+ RelArchitecture = Fragments[J]+2;
}
if (RelVerStr.end()[-1] == '*')
@@ -178,7 +180,7 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
RelArchive.empty() == true && RelLabel.empty() == true &&
RelRelease.empty() == true && RelCodename.empty() == true &&
- RelComponent.empty() == true)
+ RelComponent.empty() == true && RelArchitecture.empty() == true)
return false;
if (RelVerStr.empty() == false)
@@ -211,6 +213,10 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
if (File->Component == 0 ||
stringcasecmp(RelComponent,File.Component()) != 0)
return false;
+ if (RelArchitecture.empty() == false)
+ if (File->Architecture == 0 ||
+ stringcasecmp(RelArchitecture,File.Architecture()) != 0)
+ return false;
return true;
}
diff --git a/apt-pkg/versionmatch.h b/apt-pkg/versionmatch.h
index a8f3c84ac..a8da072ae 100644
--- a/apt-pkg/versionmatch.h
+++ b/apt-pkg/versionmatch.h
@@ -23,6 +23,7 @@
Codename (n=) e.g. etch, lenny, squeeze, sid
Label (l=)
Component (c=)
+ Binary Architecture (b=)
If there are no equals signs in the string then it is scanned in short
form - if it starts with a number it is Version otherwise it is an
Archive or a Codename.
@@ -55,6 +56,7 @@ class pkgVersionMatch
string RelArchive;
string RelLabel;
string RelComponent;
+ string RelArchitecture;
bool MatchAll;
// Origin Matching