]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/pkgcache.cc
Merge remote-tracking branch 'mvo/feature/acq-trans' into debian/experimental
[apt.git] / apt-pkg / pkgcache.cc
index f694a237e2435c446fef9cd0c413f6868c3b1829..572685ba5f14ec909683cd7c8c10b3c696e82cc2 100644 (file)
@@ -8,7 +8,7 @@
    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!!
    
-   This is the general utility functions for cache managment. They provide
+   This is the general utility functions for cache management. They provide
    a complete set of accessor functions for the cache. The cacheiterators
    header contains the STL-like iterators that can be used to easially
    navigate the cache as well as seemlessly dereference the mmap'd 
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/mmap.h>
 #include <apt-pkg/macros.h>
 
+#include <stddef.h>
+#include <string.h>
+#include <ostream>
+#include <vector>
 #include <string>
 #include <sys/stat.h>
-#include <unistd.h>
-#include <ctype.h>
 
 #include <apti18n.h>
                                                                        /*}}}*/
@@ -51,7 +54,7 @@ pkgCache::Header::Header()
    
    /* Whenever the structures change the major version should be bumped,
       whenever the generator changes the minor version should be bumped. */
-   MajorVersion = 8;
+   MajorVersion = 10;
    MinorVersion = 0;
    Dirty = false;
    
@@ -79,11 +82,10 @@ pkgCache::Header::Header()
    MaxDescFileSize = 0;
    
    FileList = 0;
-   StringList = 0;
    VerSysName = 0;
    Architecture = 0;
-   memset(PkgHashTable,0,sizeof(PkgHashTable));
-   memset(GrpHashTable,0,sizeof(GrpHashTable));
+   Architectures = 0;
+   HashTableSize = _config->FindI("APT::Cache-HashTableSize", 10 * 1048);
    memset(Pools,0,sizeof(Pools));
 
    CacheFileSize = 0;
@@ -138,7 +140,6 @@ bool pkgCache::ReMap(bool const &Errorchecks)
    DescP = (Description *)Map.Data();
    ProvideP = (Provides *)Map.Data();
    DepP = (Dependency *)Map.Data();
-   StringItemP = (StringItem *)Map.Data();
    StrP = (char *)Map.Data();
 
    if (Errorchecks == false)
@@ -161,15 +162,23 @@ bool pkgCache::ReMap(bool const &Errorchecks)
    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)
+      return _error->Error(_("The package cache file is corrupted"));
+
    // Locate our VS..
-   if (HeaderP->VerSysName == 0 ||
-       (VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
+   if ((VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
       return _error->Error(_("This APT does not support the versioning system '%s'"),StrP + HeaderP->VerSysName);
 
-   // Chcek the arhcitecture
-   if (HeaderP->Architecture == 0 ||
-       _config->Find("APT::Architecture") != StrP + HeaderP->Architecture)
-      return _error->Error(_("The package cache was built for a different architecture"));
+   // 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);
+   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());
+
    return true;
 }
                                                                        /*}}}*/
@@ -178,22 +187,21 @@ 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(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->PkgHashTable);
+      Hash = 41 * Hash + tolower_ascii(*I);
+   return Hash % HeaderP->HashTableSize;
 }
 
-unsigned long pkgCache::sHash(const char *Str) const
+map_id_t 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->PkgHashTable);
+   unsigned long Hash = tolower_ascii(*Str);
+   for (const char *I = Str + 1; *I != 0; ++I)
+      Hash = 41 * Hash + tolower_ascii(*I);
+   return Hash % HeaderP->HashTableSize;
 }
-
                                                                        /*}}}*/
 // Cache::SingleArchFindPkg - Locate a package by name                 /*{{{*/
 // ---------------------------------------------------------------------
@@ -203,12 +211,14 @@ unsigned long pkgCache::sHash(const char *Str) const
 pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name)
 {
    // Look at the hash bucket
-   Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)];
-   for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
+   Package *Pkg = PkgP + HeaderP->PkgHashTable()[Hash(Name)];
+   for (; Pkg != PkgP; Pkg = PkgP + Pkg->Next)
    {
-      if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
-          stringcasecmp(Name,StrP + Pkg->Name) == 0)
-         return PkgIterator(*this,Pkg);
+      int const cmp = strcmp(Name.c_str(), StrP + (GrpP + Pkg->Group)->Name);
+      if (cmp == 0)
+        return PkgIterator(*this, Pkg);
+      else if (cmp < 0)
+        break;
    }
    return PkgIterator(*this,0);
 }
@@ -238,7 +248,7 @@ 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) {
+       if (MultiArchCache() == false && Arch != "none") {
                if (Arch == "native" || Arch == "all" || Arch == "any" ||
                    Arch == NativeArch())
                        return SingleArchFindPkg(Name);
@@ -263,11 +273,13 @@ pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
                return GrpIterator(*this,0);
 
        // Look at the hash bucket for the group
-       Group *Grp = GrpP + HeaderP->GrpHashTable[sHash(Name)];
+       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)
+               int const cmp = strcmp(Name.c_str(), StrP + Grp->Name);
+               if (cmp == 0)
                        return GrpIterator(*this, Grp);
+               else if (cmp < 0)
+                       break;
        }
 
        return GrpIterator(*this,0);
@@ -279,22 +291,22 @@ pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
    type in the weird debian style.. */
 const char *pkgCache::CompTypeDeb(unsigned char Comp)
 {
-   const char *Ops[] = {"","<=",">=","<<",">>","=","!="};
-   if ((unsigned)(Comp & 0xF) < 7)
-      return Ops[Comp & 0xF];
-   return "";   
+   const char * const Ops[] = {"","<=",">=","<<",">>","=","!="};
+   if (unlikely((unsigned)(Comp & 0xF) >= sizeof(Ops)/sizeof(Ops[0])))
+      return "";
+   return Ops[Comp & 0xF];
 }
                                                                        /*}}}*/
 // Cache::CompType - Return a string describing the compare type       /*{{{*/
 // ---------------------------------------------------------------------
-/* This returns a string representation of the dependency compare 
+/* This returns a string representation of the dependency compare
    type */
 const char *pkgCache::CompType(unsigned char Comp)
 {
-   const char *Ops[] = {"","<=",">=","<",">","=","!="};
-   if ((unsigned)(Comp & 0xF) < 7)
-      return Ops[Comp & 0xF];
-   return "";   
+   const char * const Ops[] = {"","<=",">=","<",">","=","!="};
+   if (unlikely((unsigned)(Comp & 0xF) >= sizeof(Ops)/sizeof(Ops[0])))
+      return "";
+   return Ops[Comp & 0xF];
 }
                                                                        /*}}}*/
 // Cache::DepType - Return a string describing the dep type            /*{{{*/
@@ -340,19 +352,15 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
           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)
+               if (strcmp(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)
+            Pkg = Owner->PkgP + Pkg->Next) {
+               if (stringcmp(Arch, Owner->StrP + Pkg->Arch) == 0)
                        return PkgIterator(*Owner, Pkg);
                if ((Owner->PkgP + S->LastPackage) == Pkg)
                        break;
@@ -376,6 +384,10 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &Prefer
                if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
                        return Pkg;
        }
+       // packages without an architecture
+       Pkg = FindPkg("none");
+       if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
+               return Pkg;
 
        if (PreferNonVirtual == true)
                return FindPreferredPkg(false);
@@ -395,42 +407,42 @@ pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const
        if (S->LastPackage == LastPkg.Index())
                return PkgIterator(*Owner, 0);
 
-       return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
+       return PkgIterator(*Owner, Owner->PkgP + LastPkg->Next);
 }
                                                                        /*}}}*/
 // GrpIterator::operator ++ - Postfix incr                             /*{{{*/
 // ---------------------------------------------------------------------
 /* This will advance to the next logical group in the hash table. */
-void pkgCache::GrpIterator::operator ++(int) 
+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))
+   while (S == Owner->GrpP && (HashIndex+1) < (signed)Owner->HeaderP->HashTableSize)
    {
       HashIndex++;
-      S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+      S = Owner->GrpP + Owner->HeaderP->GrpHashTable()[HashIndex];
    }
-};
+}
                                                                        /*}}}*/
 // PkgIterator::operator ++ - Postfix incr                             /*{{{*/
 // ---------------------------------------------------------------------
 /* This will advance to the next logical package in the hash table. */
-void pkgCache::PkgIterator::operator ++(int) 
+void pkgCache::PkgIterator::operator ++(int)
 {
    // Follow the current links
    if (S != Owner->PkgP)
-      S = Owner->PkgP + S->NextPackage;
+      S = Owner->PkgP + S->Next;
 
    // Follow the hash table
-   while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
+   while (S == Owner->PkgP && (HashIndex+1) < (signed)Owner->HeaderP->HashTableSize)
    {
       HashIndex++;
-      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTable()[HashIndex];
    }
-};
+}
                                                                        /*}}}*/
 // PkgIterator::State - Check the State of the package                 /*{{{*/
 // ---------------------------------------------------------------------
@@ -462,31 +474,31 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 // ---------------------------------------------------------------------
 /* Return string representing of the candidate version. */
 const char *
-pkgCache::PkgIterator::CandVersion() const 
+pkgCache::PkgIterator::CandVersion() const
 {
   //TargetVer is empty, so don't use it.
   VerIterator version = pkgPolicy(Owner).GetCandidateVer(*this);
   if (version.IsGood())
     return version.VerStr();
   return 0;
-};
+}
                                                                        /*}}}*/
 // PkgIterator::CurVersion - Returns the current version string                /*{{{*/
 // ---------------------------------------------------------------------
 /* Return string representing of the current version. */
 const char *
-pkgCache::PkgIterator::CurVersion() const 
+pkgCache::PkgIterator::CurVersion() const
 {
   VerIterator version = CurrentVer();
   if (version.IsGood())
     return CurrentVer().VerStr();
   return 0;
-};
+}
                                                                        /*}}}*/
 // ostream operator to handle string representation of a package       /*{{{*/
 // ---------------------------------------------------------------------
 /* Output name < cur.rent.version -> candid.ate.version | new.est.version > (section)
-   Note that the characters <|>() are all literal above. Versions will be ommited
+   Note that the characters <|>() are all literal above. Versions will be omitted
    if they provide no new information (e.g. there is no newer version than candidate)
    If no version and/or section can be found "none" is used. */
 std::ostream& 
@@ -504,7 +516,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;
 }
                                                                        /*}}}*/
@@ -621,8 +636,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const
       {
         if (IsIgnorable(I.ParentPkg()) == true)
            continue;
-
-        if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
+        if (IsSatisfied(I) == false)
            continue;
 
         Size++;
@@ -635,8 +649,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const
       {
         if (IsIgnorable(I) == true)
            continue;
-
-        if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
+        if (IsSatisfied(I) == false)
            continue;
 
         Size++;
@@ -684,10 +697,31 @@ 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 &/*Pkg*/) const
 {
-   if (ParentPkg() == TargetPkg())
-      return IsNegative();
+   if (IsNegative() == false)
+      return false;
+
+   pkgCache::PkgIterator PP = ParentPkg();
+   pkgCache::PkgIterator PT = TargetPkg();
+   if (PP->Group != PT->Group)
+      return false;
+   // self-conflict
+   if (PP == PT)
+      return true;
+   pkgCache::VerIterator 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 false;
 }
@@ -723,6 +757,16 @@ bool pkgCache::DepIterator::IsMultiArchImplicit() const
    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());
+}
+bool pkgCache::DepIterator::IsSatisfied(PrvIterator const &Prv) const
+{
+   return Owner->VS->CheckDep(Prv.ProvideVersion(),S->CompareOp,TargetVer());
+}
+                                                                       /*}}}*/
 // ostream operator to handle string representation of a dependecy     /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -773,7 +817,7 @@ int pkgCache::VerIterator::CompareVer(const VerIterator &B) const
 // VerIterator::Downloadable - Checks if the version is downloadable   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgCache::VerIterator::Downloadable() const
+APT_PURE bool pkgCache::VerIterator::Downloadable() const
 {
    VerFileIterator Files = FileList();
    for (; Files.end() == false; ++Files)
@@ -786,7 +830,7 @@ bool pkgCache::VerIterator::Downloadable() const
 // ---------------------------------------------------------------------
 /* This checks to see if any of the versions files are not NotAutomatic. 
    True if this version is selectable for automatic installation. */
-bool pkgCache::VerIterator::Automatic() const
+APT_PURE bool pkgCache::VerIterator::Automatic() const
 {
    VerFileIterator Files = FileList();
    for (; Files.end() == false; ++Files)
@@ -882,6 +926,18 @@ string pkgCache::VerIterator::RelStr() const
    return Res;
 }
                                                                        /*}}}*/
+// VerIterator::MultiArchType - string representing MultiArch flag     /*{{{*/
+const char * pkgCache::VerIterator::MultiArchType() const
+{
+   if ((S->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
+      return "same";
+   else if ((S->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
+      return "foreign";
+   else if ((S->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
+      return "allowed";
+   return "none";
+}
+                                                                       /*}}}*/
 // 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
@@ -924,7 +980,7 @@ string pkgCache::PkgFileIterator::RelStr()
                                                                        /*}}}*/
 // VerIterator::TranslatedDescription - Return the a DescIter for locale/*{{{*/
 // ---------------------------------------------------------------------
-/* return a DescIter for the current locale or the default if none is 
+/* return a DescIter for the current locale or the default if none is
  * found
  */
 pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
@@ -958,7 +1014,7 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
       if (strcmp(Desc.LanguageCode(), "") == 0)
         return Desc;
    return DescriptionList();
-};
+}
 
                                                                        /*}}}*/
 // PrvIterator::IsMultiArchImplicit - added by the cache generation    /*{{{*/
@@ -970,8 +1026,14 @@ bool pkgCache::PrvIterator::IsMultiArchImplicit() const
 {
    pkgCache::PkgIterator const Owner = OwnerPkg();
    pkgCache::PkgIterator const Parent = ParentPkg();
-   if (Owner->Arch != Parent->Arch || Owner->Name == Parent->Name)
+   if (strcmp(Owner.Arch(), Parent.Arch()) != 0 || Owner.Group()->Name == Parent.Group()->Name)
       return true;
    return false;
 }
                                                                        /*}}}*/
+APT_DEPRECATED APT_PURE const char * pkgCache::PkgIterator::Section() const {/*{{{*/
+   if (S->VersionList == 0)
+      return 0;
+   return VersionList().Section();
+}
+                                                                       /*}}}*/