]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/pkgcache.cc
Bug #807012 also involves package dependencies :/.
[apt.git] / apt-pkg / pkgcache.cc
index 2b615363487ef34d6ebca301d9c75283f31769f1..1705f836b0635b33d49f8be73d62a094ce09e581 100644 (file)
 
 #include <stddef.h>
 #include <string.h>
-#include <ostream>
+#include <sstream>
+#include <algorithm>
 #include <vector>
 #include <string>
 #include <sys/stat.h>
+#include <zlib.h>
 
 #include <apti18n.h>
                                                                        /*}}}*/
 
 using std::string;
+using APT::StringView;
 
 
 // Cache::Header::Header - Constructor                                 /*{{{*/
@@ -50,47 +53,49 @@ using std::string;
 /* Simply initialize the header */
 pkgCache::Header::Header()
 {
-   Signature = 0x98FE76DC;
-   
+#define APT_HEADER_SET(X,Y) X = Y; static_assert(std::numeric_limits<decltype(X)>::max() > Y, "Size violation detected in pkgCache::Header")
+   APT_HEADER_SET(Signature, 0x98FE76DC);
+
    /* Whenever the structures change the major version should be bumped,
       whenever the generator changes the minor version should be bumped. */
-   MajorVersion = 9;
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
-   MinorVersion = 2;
-#else
-   MinorVersion = 1;
-#endif
-   Dirty = false;
-   
-   HeaderSz = sizeof(pkgCache::Header);
-   GroupSz = sizeof(pkgCache::Group);
-   PackageSz = sizeof(pkgCache::Package);
-   PackageFileSz = sizeof(pkgCache::PackageFile);
-   VersionSz = sizeof(pkgCache::Version);
-   DescriptionSz = sizeof(pkgCache::Description);
-   DependencySz = sizeof(pkgCache::Dependency);
-   ProvidesSz = sizeof(pkgCache::Provides);
-   VerFileSz = sizeof(pkgCache::VerFile);
-   DescFileSz = sizeof(pkgCache::DescFile);
-   
+   APT_HEADER_SET(MajorVersion, 11);
+   APT_HEADER_SET(MinorVersion, 0);
+   APT_HEADER_SET(Dirty, false);
+
+   APT_HEADER_SET(HeaderSz, sizeof(pkgCache::Header));
+   APT_HEADER_SET(GroupSz, sizeof(pkgCache::Group));
+   APT_HEADER_SET(PackageSz, sizeof(pkgCache::Package));
+   APT_HEADER_SET(ReleaseFileSz, sizeof(pkgCache::ReleaseFile));
+   APT_HEADER_SET(PackageFileSz, sizeof(pkgCache::PackageFile));
+   APT_HEADER_SET(VersionSz, sizeof(pkgCache::Version));
+   APT_HEADER_SET(DescriptionSz, sizeof(pkgCache::Description));
+   APT_HEADER_SET(DependencySz, sizeof(pkgCache::Dependency));
+   APT_HEADER_SET(DependencyDataSz, sizeof(pkgCache::DependencyData));
+   APT_HEADER_SET(ProvidesSz, sizeof(pkgCache::Provides));
+   APT_HEADER_SET(VerFileSz, sizeof(pkgCache::VerFile));
+   APT_HEADER_SET(DescFileSz, sizeof(pkgCache::DescFile));
+#undef APT_HEADER_SET
+
    GroupCount = 0;
    PackageCount = 0;
    VersionCount = 0;
    DescriptionCount = 0;
    DependsCount = 0;
+   DependsDataCount = 0;
+   ReleaseFileCount = 0;
    PackageFileCount = 0;
    VerFileCount = 0;
    DescFileCount = 0;
    ProvidesCount = 0;
    MaxVerFileSize = 0;
    MaxDescFileSize = 0;
-   
+
    FileList = 0;
-   StringList = 0;
+   RlsFileList = 0;
    VerSysName = 0;
    Architecture = 0;
-   memset(PkgHashTable,0,sizeof(PkgHashTable));
-   memset(GrpHashTable,0,sizeof(GrpHashTable));
+   SetArchitectures(0);
+   SetHashTableSize(_config->FindI("APT::Cache-HashTableSize", 50503));
    memset(Pools,0,sizeof(Pools));
 
    CacheFileSize = 0;
@@ -104,10 +109,12 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
    if (HeaderSz == Against.HeaderSz &&
        GroupSz == Against.GroupSz &&
        PackageSz == Against.PackageSz &&
+       ReleaseFileSz == Against.ReleaseFileSz &&
        PackageFileSz == Against.PackageFileSz &&
        VersionSz == Against.VersionSz &&
        DescriptionSz == Against.DescriptionSz &&
        DependencySz == Against.DependencySz &&
+       DependencyDataSz == Against.DependencyDataSz &&
        VerFileSz == Against.VerFileSz &&
        DescFileSz == Against.DescFileSz &&
        ProvidesSz == Against.ProvidesSz)
@@ -119,7 +126,8 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
 // Cache::pkgCache - Constructor                                       /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
+APT_IGNORE_DEPRECATED_PUSH
+pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map), VS(nullptr), d(NULL)
 {
    // call getArchitectures() with cached=false to ensure that the 
    // architectures cache is re-evaulated. this is needed in cases
@@ -128,6 +136,7 @@ pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
    if (DoMap == true)
       ReMap();
 }
+APT_IGNORE_DEPRECATED_POP
                                                                        /*}}}*/
 // Cache::ReMap - Reopen the cache file                                        /*{{{*/
 // ---------------------------------------------------------------------
@@ -140,12 +149,14 @@ bool pkgCache::ReMap(bool const &Errorchecks)
    PkgP = (Package *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
+   RlsFileP = (ReleaseFile *)Map.Data();
    PkgFileP = (PackageFile *)Map.Data();
    VerP = (Version *)Map.Data();
    DescP = (Description *)Map.Data();
    ProvideP = (Provides *)Map.Data();
+   TagP = (Tag *)Map.Data();
    DepP = (Dependency *)Map.Data();
-   StringItemP = (StringItem *)Map.Data();
+   DepDataP = (DependencyData *)Map.Data();
    StrP = (char *)Map.Data();
 
    if (Errorchecks == false)
@@ -165,10 +176,7 @@ bool pkgCache::ReMap(bool const &Errorchecks)
        HeaderP->CheckSizes(DefHeader) == false)
       return _error->Error(_("The package cache file is an incompatible version"));
 
-   if (Map.Size() < HeaderP->CacheFileSize)
-      return _error->Error(_("The package cache file is corrupted, it is too small"));
-
-   if (HeaderP->VerSysName == 0 || HeaderP->Architecture == 0 || HeaderP->Architectures == 0)
+   if (HeaderP->VerSysName == 0 || HeaderP->Architecture == 0 || HeaderP->GetArchitectures() == 0)
       return _error->Error(_("The package cache file is corrupted"));
 
    // Locate our VS..
@@ -177,13 +185,22 @@ bool pkgCache::ReMap(bool const &Errorchecks)
 
    // Check the architecture
    std::vector<std::string> archs = APT::Configuration::getArchitectures();
-   std::vector<std::string>::const_iterator a = archs.begin();
-   std::string list = *a;
-   for (++a; a != archs.end(); ++a)
-      list.append(",").append(*a);
+   std::string list = "";
+   for (auto const & arch : archs) {
+      if (!list.empty())
+         list.append(",");
+      list.append(arch);
+   }
    if (_config->Find("APT::Architecture") != StrP + HeaderP->Architecture ||
-        list != StrP + HeaderP->Architectures)
-      return _error->Error(_("The package cache was built for different architectures: %s vs %s"), StrP + HeaderP->Architectures, list.c_str());
+        list != StrP + HeaderP->GetArchitectures())
+      return _error->Error(_("The package cache was built for different architectures: %s vs %s"), StrP + HeaderP->GetArchitectures(), list.c_str());
+
+
+   auto hash = CacheHash();
+   if (_config->FindB("Debug::pkgCacheGen", false))
+      std::clog << "Opened cache with hash " << hash << ", expecting " <<  HeaderP->CacheFileSize << "\n";
+   if (hash != HeaderP->CacheFileSize)
+      return _error->Error(_("The package cache file is corrupted, it has the wrong hash"));
 
    return true;
 }
@@ -193,61 +210,69 @@ bool pkgCache::ReMap(bool const &Errorchecks)
 /* This is used to generate the hash entries for the HashTable. With my
    package list from bo this function gets 94% table usage on a 512 item
    table (480 used items) */
-unsigned long pkgCache::sHash(const string &Str) const
+map_id_t pkgCache::sHash(StringView Str) const
+{
+   uint32_t Hash = 5381;
+   for (auto I = Str.begin(); I != Str.end(); ++I)
+      Hash = 33 * Hash + tolower_ascii_unsafe(*I);
+   return Hash % HeaderP->GetHashTableSize();
+}
+map_id_t pkgCache::sHash(const string &Str) const
 {
-   unsigned long Hash = 0;
+   uint32_t Hash = 5381;
    for (string::const_iterator I = Str.begin(); I != Str.end(); ++I)
-      Hash = 41 * Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->PkgHashTable);
+      Hash = 33 * Hash + tolower_ascii_unsafe((signed char)*I);
+   return Hash % HeaderP->GetHashTableSize();
 }
 
-unsigned long pkgCache::sHash(const char *Str) const
+map_id_t pkgCache::sHash(const char *Str) const
 {
-   unsigned long Hash = tolower_ascii(*Str);
-   for (const char *I = Str + 1; *I != 0; ++I)
-      Hash = 41 * Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->PkgHashTable);
+   uint32_t Hash = 5381;
+   for (const char *I = Str; *I != 0; ++I)
+      Hash = 33 * Hash + tolower_ascii_unsafe((signed char)*I);
+   return Hash % HeaderP->GetHashTableSize();
 }
-                                                                       /*}}}*/
-// Cache::SingleArchFindPkg - Locate a package by 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)
+
+uint32_t pkgCache::CacheHash()
 {
-   // Look at the hash bucket
-   Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)];
-   for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
-   {
-      if (unlikely(Pkg->Name == 0))
-        continue;
+   pkgCache::Header header = {};
+   uLong adler = adler32(0L, Z_NULL, 0);
 
-      int const cmp = strcasecmp(Name.c_str(), StrP + Pkg->Name);
-      if (cmp == 0)
-        return PkgIterator(*this, Pkg);
-      else if (cmp < 0)
-        break;
+   if (Map.Size() < sizeof(header))
+      return adler;
+   memcpy(&header, GetMap().Data(), sizeof(header));
+
+   header.Dirty = false;
+   header.CacheFileSize = 0;
+
+   adler = adler32(adler,
+                  reinterpret_cast<const unsigned char *>(&header),
+                  sizeof(header));
+
+   if (Map.Size() > sizeof(header)) {
+      adler = adler32(adler,
+                     static_cast<const unsigned char *>(GetMap().Data()) + sizeof(header),
+                     GetMap().Size() - sizeof(header));
    }
-   return PkgIterator(*this,0);
+
+   return adler;
 }
                                                                        /*}}}*/
 // Cache::FindPkg - Locate a package by name                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Returns 0 on error, pointer to the package otherwise */
 pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
-       size_t const found = Name.find(':');
+   return FindPkg(StringView(Name));
+}
+
+pkgCache::PkgIterator pkgCache::FindPkg(StringView Name) {
+       auto const found = Name.rfind(':');
        if (found == string::npos)
-       {
-               if (MultiArchCache() == false)
-                       return SingleArchFindPkg(Name);
-               else
-                       return FindPkg(Name, "native");
-       }
-       string const Arch = Name.substr(found+1);
-       /* Beware: This is specialcased to handle pkg:any in dependencies as
-          these are linked to virtual pkg:any named packages with all archs.
-          If you want any arch from a given pkg, use FindPkg(pkg,arch) */
+          return FindPkg(Name, "native");
+       auto const Arch = Name.substr(found+1);
+       /* Beware: This is specialcased to handle pkg:any in dependencies
+          as these are linked to virtual pkg:any named packages.
+          If you want any arch from a pkg, use FindPkg(pkg,"any") */
        if (Arch == "any")
                return FindPkg(Name, "any");
        return FindPkg(Name.substr(0, found), Arch);
@@ -257,13 +282,10 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
 // ---------------------------------------------------------------------
 /* Returns 0 on error, pointer to the package otherwise */
 pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) {
-       if (MultiArchCache() == false && Arch != "none") {
-               if (Arch == "native" || Arch == "all" || Arch == "any" ||
-                   Arch == NativeArch())
-                       return SingleArchFindPkg(Name);
-               else
-                       return PkgIterator(*this,0);
-       }
+   return FindPkg(StringView(Name), StringView(Arch));
+}
+
+pkgCache::PkgIterator pkgCache::FindPkg(StringView Name, StringView Arch) {
        /* 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) */
@@ -278,16 +300,17 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch)
 // ---------------------------------------------------------------------
 /* Returns End-Pointer on error, pointer to the group otherwise */
 pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
+   return FindGrp(StringView(Name));
+}
+
+pkgCache::GrpIterator pkgCache::FindGrp(StringView 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)];
+       Group *Grp = GrpP + HeaderP->GrpHashTableP()[sHash(Name)];
        for (; Grp != GrpP; Grp = GrpP + Grp->Next) {
-               if (unlikely(Grp->Name == 0))
-                  continue;
-
-               int const cmp = strcasecmp(Name.c_str(), StrP + Grp->Name);
+               int const cmp = StringViewCompareFast(Name, ViewString(Grp->Name));
                if (cmp == 0)
                        return GrpIterator(*this, Grp);
                else if (cmp < 0)
@@ -339,7 +362,7 @@ const char *pkgCache::DepType(unsigned char Type)
 /* */
 const char *pkgCache::Priority(unsigned char Prio)
 {
-   const char *Mapping[] = {0,_("important"),_("required"),_("standard"),
+   const char *Mapping[] = {0,_("required"),_("important"),_("standard"),
                             _("optional"),_("extra")};
    if (Prio < _count(Mapping))
       return Mapping[Prio];
@@ -350,33 +373,26 @@ const char *pkgCache::Priority(unsigned char Prio)
 // ---------------------------------------------------------------------
 /* Returns an End-Pointer on error, pointer to the package otherwise */
 pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
+   return FindPkg(StringView(Arch));
+}
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(const char *Arch) const {
+   return FindPkg(StringView(Arch));
+}
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(StringView Arch) const {
        if (unlikely(IsGood() == false || S->FirstPackage == 0))
                return PkgIterator(*Owner, 0);
 
        /* If we accept any package we simply return the "first"
-          package in this group (the last one added). */
+          package in this group */
        if (Arch == "any")
                return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage);
+       if (Arch == "native" || Arch == "all")
+               Arch = Owner->NativeArch();
 
-       char const* const myArch = Owner->NativeArch();
-       /* 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 == "all") {
-               pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
-               if (strcasecmp(myArch, Owner->StrP + Pkg->Arch) == 0)
-                       return PkgIterator(*Owner, Pkg);
-               Arch = myArch;
-       }
-
-       /* 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 */
+       // Iterate over the list to find the matching arch
        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)
+               if (Arch == Owner->ViewString(Pkg->Arch))
                        return PkgIterator(*Owner, Pkg);
                if ((Owner->PkgP + S->LastPackage) == Pkg)
                        break;
@@ -389,7 +405,7 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
 // ---------------------------------------------------------------------
 /* Returns an End-Pointer on error, pointer to the package otherwise */
 pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &PreferNonVirtual) const {
-       pkgCache::PkgIterator Pkg = FindPkg("native");
+       pkgCache::PkgIterator Pkg = FindPkg(StringView("native", 6));
        if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
                return Pkg;
 
@@ -401,7 +417,7 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &Prefer
                        return Pkg;
        }
        // packages without an architecture
-       Pkg = FindPkg("none");
+       Pkg = FindPkg(StringView("none", 4));
        if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
                return Pkg;
 
@@ -426,38 +442,52 @@ pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const
        return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
 }
                                                                        /*}}}*/
-// GrpIterator::operator ++ - Postfix incr                             /*{{{*/
+// GrpIterator::operator++ - Prefix incr                               /*{{{*/
 // ---------------------------------------------------------------------
 /* This will advance to the next logical group in the hash table. */
-void pkgCache::GrpIterator::operator ++(int)
+pkgCache::GrpIterator& pkgCache::GrpIterator::operator++()
 {
    // 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))
+   while (S == Owner->GrpP && (HashIndex+1) < (signed)Owner->HeaderP->GetHashTableSize())
    {
-      HashIndex++;
-      S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+      ++HashIndex;
+      S = Owner->GrpP + Owner->HeaderP->GrpHashTableP()[HashIndex];
    }
+   return *this;
 }
                                                                        /*}}}*/
-// PkgIterator::operator ++ - Postfix incr                             /*{{{*/
+// PkgIterator::operator++ - Prefix incr                               /*{{{*/
 // ---------------------------------------------------------------------
 /* This will advance to the next logical package in the hash table. */
-void pkgCache::PkgIterator::operator ++(int)
+pkgCache::PkgIterator& pkgCache::PkgIterator::operator++()
 {
    // Follow the current links
    if (S != Owner->PkgP)
       S = Owner->PkgP + S->NextPackage;
 
    // Follow the hash table
-   while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
+   while (S == Owner->PkgP && (HashIndex+1) < (signed)Owner->HeaderP->GetHashTableSize())
    {
-      HashIndex++;
-      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
+      ++HashIndex;
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTableP()[HashIndex];
    }
+   return *this;
+}
+                                                                       /*}}}*/
+pkgCache::DepIterator& pkgCache::DepIterator::operator++()             /*{{{*/
+{
+   if (S == Owner->DepP)
+      return *this;
+   S = Owner->DepP + (Type == DepVer ? S->NextDepends : S->NextRevDepends);
+   if (S == Owner->DepP)
+      S2 = Owner->DepDataP;
+   else
+      S2 = Owner->DepDataP + S->DependencyData;
+   return *this;
 }
                                                                        /*}}}*/
 // PkgIterator::State - Check the State of the package                 /*{{{*/
@@ -471,7 +501,7 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
    
    if (S->CurrentState == pkgCache::State::UnPacked ||
        S->CurrentState == pkgCache::State::HalfConfigured)
-      // we leave triggers alone complettely. dpkg deals with
+      // we leave triggers alone completely. dpkg deals with
       // them in a hard-to-predict manner and if they get 
       // resolved by dpkg before apt run dpkg --configure on 
       // the TriggersPending package dpkg returns a error
@@ -524,7 +554,9 @@ operator<<(std::ostream& out, pkgCache::PkgIterator Pkg)
       return out << "invalid package";
 
    string current = string(Pkg.CurVersion() == 0 ? "none" : Pkg.CurVersion());
+APT_IGNORE_DEPRECATED_PUSH
    string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
+APT_IGNORE_DEPRECATED_POP
    string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
 
    out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
@@ -532,7 +564,10 @@ operator<<(std::ostream& out, pkgCache::PkgIterator Pkg)
       out << " -> " << candidate;
    if ( newest != "none" && candidate != newest)
       out << " | " << newest;
-   out << " > ( " << string(Pkg.Section()==0?"none":Pkg.Section()) << " )";
+   if (Pkg->VersionList == 0)
+      out << " > ( none )";
+   else
+      out << " > ( " << string(Pkg.VersionList().Section()==0?"unknown":Pkg.VersionList().Section()) << " )";
    return out;
 }
                                                                        /*}}}*/
@@ -543,7 +578,7 @@ std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
 {
    string fullname = Name();
    if (Pretty == false ||
-       (strcmp(Arch(), "all") != 0 &&
+       (strcmp(Arch(), "all") != 0 && strcmp(Arch(), "any") != 0 &&
        strcmp(Owner->NativeArch(), Arch()) != 0))
       return fullname.append(":").append(Arch());
    return fullname;
@@ -556,8 +591,8 @@ std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
 bool pkgCache::DepIterator::IsCritical() const
 {
    if (IsNegative() == true ||
-       S->Type == pkgCache::Dep::Depends ||
-       S->Type == pkgCache::Dep::PreDepends)
+       S2->Type == pkgCache::Dep::Depends ||
+       S2->Type == pkgCache::Dep::PreDepends)
       return true;
    return false;
 }
@@ -568,9 +603,9 @@ bool pkgCache::DepIterator::IsCritical() const
    are negative like Conflicts which can and should be handled differently */
 bool pkgCache::DepIterator::IsNegative() const
 {
-   return S->Type == Dep::DpkgBreaks ||
-         S->Type == Dep::Conflicts ||
-         S->Type == Dep::Obsoletes;
+   return S2->Type == Dep::DpkgBreaks ||
+         S2->Type == Dep::Conflicts ||
+         S2->Type == Dep::Obsoletes;
 }
                                                                        /*}}}*/
 // DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides        /*{{{*/
@@ -699,8 +734,8 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
    End = *this;
    for (bool LastOR = true; end() == false && LastOR == true;)
    {
-      LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
-      (*this)++;
+      LastOR = (S2->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+      ++(*this);
       if (LastOR == true)
         End = (*this);
    }
@@ -710,31 +745,22 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
 // ---------------------------------------------------------------------
 /* Deps like self-conflicts should be ignored as well as implicit conflicts
    on virtual packages. */
-bool pkgCache::DepIterator::IsIgnorable(PkgIterator const &/*Pkg*/) const
+bool pkgCache::DepIterator::IsIgnorable(PkgIterator const &PT) const
 {
    if (IsNegative() == false)
       return false;
 
-   pkgCache::PkgIterator PP = ParentPkg();
-   pkgCache::PkgIterator PT = TargetPkg();
+   pkgCache::PkgIterator const PP = ParentPkg();
    if (PP->Group != PT->Group)
       return false;
    // self-conflict
    if (PP == PT)
       return true;
-   pkgCache::VerIterator PV = ParentVer();
+   pkgCache::VerIterator const PV = ParentVer();
    // ignore group-conflict on a M-A:same package - but not our implicit dependencies
    // so that we can have M-A:same packages conflicting with their own real name
    if ((PV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
-   {
-      // Replaces: ${self}:other ( << ${binary:Version})
-      if (S->Type == pkgCache::Dep::Replaces && S->CompareOp == pkgCache::Dep::Less && strcmp(PV.VerStr(), TargetVer()) == 0)
-        return false;
-      // Breaks: ${self}:other (!= ${binary:Version})
-      if (S->Type == pkgCache::Dep::DpkgBreaks && S->CompareOp == pkgCache::Dep::NotEquals && strcmp(PV.VerStr(), TargetVer()) == 0)
-        return false;
-      return true;
-   }
+      return IsMultiArchImplicit() == false;
 
    return false;
 }
@@ -749,38 +775,37 @@ bool pkgCache::DepIterator::IsIgnorable(PrvIterator const &Prv) const
    if (Prv.OwnerPkg()->Group == Pkg->Group)
       return true;
    // Implicit group-conflicts should not be applied on providers of other groups
-   if (Pkg->Group == TargetPkg()->Group && Prv.OwnerPkg()->Group != Pkg->Group)
+   if (IsMultiArchImplicit() && Prv.OwnerPkg()->Group != Pkg->Group)
       return true;
 
    return false;
 }
                                                                        /*}}}*/
-// DepIterator::IsMultiArchImplicit - added by the cache generation    /*{{{*/
-// ---------------------------------------------------------------------
-/* MultiArch can be translated to SingleArch for an resolver and we did so,
-   by adding dependencies to help the resolver understand the problem, but
-   sometimes it is needed to identify these to ignore them… */
-bool pkgCache::DepIterator::IsMultiArchImplicit() const
-{
-   if (ParentPkg()->Arch != TargetPkg()->Arch &&
-       (S->Type == pkgCache::Dep::Replaces ||
-       S->Type == pkgCache::Dep::DpkgBreaks ||
-       S->Type == pkgCache::Dep::Conflicts))
-      return true;
-   return false;
-}
-                                                                       /*}}}*/
 // DepIterator::IsSatisfied - check if a version satisfied the dependency /*{{{*/
 bool pkgCache::DepIterator::IsSatisfied(VerIterator const &Ver) const
 {
-   return Owner->VS->CheckDep(Ver.VerStr(),S->CompareOp,TargetVer());
+   return Owner->VS->CheckDep(Ver.VerStr(),S2->CompareOp,TargetVer());
 }
 bool pkgCache::DepIterator::IsSatisfied(PrvIterator const &Prv) const
 {
-   return Owner->VS->CheckDep(Prv.ProvideVersion(),S->CompareOp,TargetVer());
+   return Owner->VS->CheckDep(Prv.ProvideVersion(),S2->CompareOp,TargetVer());
+}
+                                                                       /*}}}*/
+// DepIterator::IsImplicit - added by the cache generation             /*{{{*/
+bool pkgCache::DepIterator::IsImplicit() const
+{
+   if (IsMultiArchImplicit() == true)
+      return true;
+   if (IsNegative() || S2->Type == pkgCache::Dep::Replaces)
+   {
+      if ((S2->CompareOp & pkgCache::Dep::ArchSpecific) != pkgCache::Dep::ArchSpecific &&
+           strcmp(ParentPkg().Arch(), TargetPkg().Arch()) != 0)
+        return true;
+   }
+   return false;
 }
                                                                        /*}}}*/
-// ostream operator to handle string representation of a dependecy     /*{{{*/
+// ostream operator to handle string representation of a dependency    /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 std::ostream& operator<<(std::ostream& out, pkgCache::DepIterator D)
@@ -793,10 +818,12 @@ std::ostream& operator<<(std::ostream& out, pkgCache::DepIterator D)
 
    out << (P.end() ? "invalid pkg" : P.FullName(false)) << " " << D.DepType()
        << " on ";
+APT_IGNORE_DEPRECATED_PUSH
    if (T.end() == true)
       out << "invalid pkg";
    else
       out << T;
+APT_IGNORE_DEPRECATED_POP
 
    if (D->Version != 0)
       out << " (" << D.CompType() << " " << D.TargetVer() << ")";
@@ -834,7 +861,7 @@ APT_PURE bool pkgCache::VerIterator::Downloadable() const
 {
    VerFileIterator Files = FileList();
    for (; Files.end() == false; ++Files)
-      if ((Files.File()->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource)
+      if (Files.File().Flagged(pkgCache::Flag::NotSource) == false)
         return true;
    return false;
 }
@@ -848,7 +875,7 @@ APT_PURE bool pkgCache::VerIterator::Automatic() const
    VerFileIterator Files = FileList();
    for (; Files.end() == false; ++Files)
       // Do not check ButAutomaticUpgrades here as it is kind of automatic…
-      if ((Files.File()->Flags & pkgCache::Flag::NotAutomatic) != pkgCache::Flag::NotAutomatic)
+      if (Files.File().Flagged(pkgCache::Flag::NotAutomatic) == false)
         return true;
    return false;
 }
@@ -874,69 +901,54 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
 // ---------------------------------------------------------------------
 /* This describes the version from a release-centric manner. The output is a 
    list of Label:Version/Archive */
+static std::string PkgFileIteratorToRelString(pkgCache::PkgFileIterator const &File)
+{
+   std::string Res;
+   if (File.Label() != 0)
+      Res = Res + File.Label() + ':';
+
+   if (File.Archive() != 0)
+   {
+      if (File.Version() == 0)
+        Res += File.Archive();
+      else
+        Res = Res + File.Version() + '/' +  File.Archive();
+   }
+   else
+   {
+      // No release file, print the host name that this came from
+      if (File.Site() == 0 || File.Site()[0] == 0)
+        Res += "localhost";
+      else
+        Res += File.Site();
+   }
+   return Res;
+}
 string pkgCache::VerIterator::RelStr() const
 {
-   bool First = true;
-   string Res;
+   std::vector<std::string> RelStrs;
    for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; ++I)
    {
       // Do not print 'not source' entries'
-      pkgCache::PkgFileIterator File = I.File();
-      if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
+      pkgCache::PkgFileIterator const File = I.File();
+      if (File.Flagged(pkgCache::Flag::NotSource))
         continue;
 
-      // See if we have already printed this out..
-      bool Seen = false;
-      for (pkgCache::VerFileIterator J = this->FileList(); I != J; ++J)
-      {
-        pkgCache::PkgFileIterator File2 = J.File();
-        if (File2->Label == 0 || File->Label == 0)
-           continue;
-
-        if (strcmp(File.Label(),File2.Label()) != 0)
-           continue;
-        
-        if (File2->Version == File->Version)
-        {
-           Seen = true;
-           break;
-        }
-        if (File2->Version == 0 || File->Version == 0)
-           break;
-        if (strcmp(File.Version(),File2.Version()) == 0)
-           Seen = true;
-      }
-      
-      if (Seen == true)
+      std::string const RS = PkgFileIteratorToRelString(File);
+      if (std::find(RelStrs.begin(), RelStrs.end(), RS) != RelStrs.end())
         continue;
-      
-      if (First == false)
-        Res += ", ";
-      else
-        First = false;
-      
-      if (File->Label != 0)
-        Res = Res + File.Label() + ':';
 
-      if (File->Archive != 0)
-      {
-        if (File->Version == 0)
-           Res += File.Archive();
-        else
-           Res = Res + File.Version() + '/' +  File.Archive();
-      }
-      else
-      {
-        // No release file, print the host name that this came from
-        if (File->Site == 0 || File.Site()[0] == 0)
-           Res += "localhost";
-        else
-           Res += File.Site();
-      }      
+      RelStrs.push_back(RS);
+   }
+   std::ostringstream os;
+   if (likely(RelStrs.empty() == false))
+   {
+      std::copy(RelStrs.begin(), RelStrs.end()-1, std::ostream_iterator<std::string>(os, ", "));
+      os << *RelStrs.rbegin();
    }
    if (S->ParentPkg != 0)
-      Res.append(" [").append(Arch()).append("]");
-   return Res;
+      os << " [" << Arch() << "]";
+   return os.str();
 }
                                                                        /*}}}*/
 // VerIterator::MultiArchType - string representing MultiArch flag     /*{{{*/
@@ -951,12 +963,12 @@ const char * pkgCache::VerIterator::MultiArchType() const
    return "none";
 }
                                                                        /*}}}*/
-// PkgFileIterator::IsOk - Checks if the cache is in sync with the file        /*{{{*/
+// RlsFileIterator::IsOk - Checks if the cache is in sync with the file        /*{{{*/
 // ---------------------------------------------------------------------
 /* This stats the file and compares its stats with the ones that were
-   stored during generation. Date checks should probably also be 
+   stored during generation. Date checks should probably also be
    included here. */
-bool pkgCache::PkgFileIterator::IsOk()
+bool pkgCache::RlsFileIterator::IsOk()
 {
    struct stat Buf;
    if (stat(FileName(),&Buf) != 0)
@@ -968,10 +980,8 @@ bool pkgCache::PkgFileIterator::IsOk()
    return true;
 }
                                                                        /*}}}*/
-// PkgFileIterator::RelStr - Return the release string                 /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string pkgCache::PkgFileIterator::RelStr()
+// RlsFileIterator::RelStr - Return the release string                 /*{{{*/
+string pkgCache::RlsFileIterator::RelStr()
 {
    string Res;
    if (Version() != 0)
@@ -984,8 +994,40 @@ string pkgCache::PkgFileIterator::RelStr()
       Res = Res + (Res.empty() == true?"n=":",n=")  + Codename();
    if (Label() != 0)
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
-   if (Component() != 0)
-      Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
+   return Res;
+}
+                                                                       /*}}}*/
+// PkgFileIterator::IsOk - Checks if the cache is in sync with the file        /*{{{*/
+// ---------------------------------------------------------------------
+/* This stats the file and compares its stats with the ones that were
+   stored during generation. Date checks should probably also be
+   included here. */
+bool pkgCache::PkgFileIterator::IsOk()
+{
+   struct stat Buf;
+   if (stat(FileName(),&Buf) != 0)
+      return false;
+
+   if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime)
+      return false;
+
+   return true;
+}
+                                                                       /*}}}*/
+string pkgCache::PkgFileIterator::RelStr()                             /*{{{*/
+{
+   std::string Res;
+   if (ReleaseFile() == 0)
+   {
+      if (Component() != 0)
+        Res = Res + (Res.empty() == true?"a=":",a=")  + Component();
+   }
+   else
+   {
+      Res = ReleaseFile().RelStr();
+      if (Component() != 0)
+        Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
+   }
    if (Architecture() != 0)
       Res = Res + (Res.empty() == true?"b=":",b=")  + Architecture();
    return Res;
@@ -1030,17 +1072,5 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
 }
 
                                                                        /*}}}*/
-// PrvIterator::IsMultiArchImplicit - added by the cache generation    /*{{{*/
-// ---------------------------------------------------------------------
-/* MultiArch can be translated to SingleArch for an resolver and we did so,
-   by adding provides to help the resolver understand the problem, but
-   sometimes it is needed to identify these to ignore them… */
-bool pkgCache::PrvIterator::IsMultiArchImplicit() const
-{
-   pkgCache::PkgIterator const Owner = OwnerPkg();
-   pkgCache::PkgIterator const Parent = ParentPkg();
-   if (strcmp(Owner.Arch(), Parent.Arch()) != 0 || Owner->Name == Parent->Name)
-      return true;
-   return false;
-}
-                                                                       /*}}}*/
+
+pkgCache::~pkgCache() {}