X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/0fffbc8ce4cb6357f59db63db5571f46a668a66b..ea606ec43a364a8e471fd9502d79fe2dfeb6e4ba:/apt-pkg/pkgcache.cc

diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc
index 40b99891a..58a63459f 100644
--- a/apt-pkg/pkgcache.cc
+++ b/apt-pkg/pkgcache.cc
@@ -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 
@@ -29,12 +29,15 @@
 #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>
 									/*}}}*/
@@ -52,7 +55,11 @@ 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;
-   MinorVersion = 0;
+#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
+   MinorVersion = 2;
+#else
+   MinorVersion = 1;
+#endif
    Dirty = false;
    
    HeaderSz = sizeof(pkgCache::Header);
@@ -182,18 +189,17 @@ 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);
+      Hash = 41 * Hash + tolower_ascii(*I);
    return Hash % _count(HeaderP->PkgHashTable);
 }
 
 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);
+   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);
 }
-
 									/*}}}*/
 // Cache::SingleArchFindPkg - Locate a package by name			/*{{{*/
 // ---------------------------------------------------------------------
@@ -206,9 +212,14 @@ pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &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);
+      if (unlikely(Pkg->Name == 0))
+	 continue;
+
+      int const cmp = strcasecmp(Name.c_str(), StrP + Pkg->Name);
+      if (cmp == 0)
+	 return PkgIterator(*this, Pkg);
+      else if (cmp < 0)
+	 break;
    }
    return PkgIterator(*this,0);
 }
@@ -238,7 +249,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);
@@ -265,9 +276,14 @@ pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
 	// 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)
+		if (unlikely(Grp->Name == 0))
+		   continue;
+
+		int const cmp = strcasecmp(Name.c_str(), StrP + Grp->Name);
+		if (cmp == 0)
 			return GrpIterator(*this, Grp);
+		else if (cmp < 0)
+			break;
 	}
 
 	return GrpIterator(*this,0);
@@ -279,22 +295,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		/*{{{*/
@@ -376,6 +392,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);
@@ -401,7 +421,7 @@ pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const
 // 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)
@@ -413,12 +433,12 @@ void pkgCache::GrpIterator::operator ++(int)
       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)
@@ -430,7 +450,7 @@ void pkgCache::PkgIterator::operator ++(int)
       HashIndex++;
       S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
    }
-};
+}
 									/*}}}*/
 // PkgIterator::State - Check the State of the package			/*{{{*/
 // ---------------------------------------------------------------------
@@ -462,31 +482,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& 
@@ -619,13 +639,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const
       // Walk along the actual package providing versions
       for (VerIterator I = DPkg.VersionList(); I.end() == false; ++I)
       {
-	 if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
+	 if (IsIgnorable(I.ParentPkg()) == true)
 	    continue;
-
-	 if (IsNegative() == true &&
-	     ParentPkg() == I.ParentPkg())
+	 if (IsSatisfied(I) == false)
 	    continue;
-	 
+
 	 Size++;
 	 if (Res != 0)
 	    *End++ = I;
@@ -634,13 +652,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const
       // Follow all provides
       for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; ++I)
       {
-	 if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
+	 if (IsIgnorable(I) == true)
 	    continue;
-	 
-	 if (IsNegative() == true &&
-	     ParentPkg()->Group == I.OwnerPkg()->Group)
+	 if (IsSatisfied(I) == false)
 	    continue;
-	 
+
 	 Size++;
 	 if (Res != 0)
 	    *End++ = I.OwnerVer();
@@ -682,6 +698,80 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
    }
 }
 									/*}}}*/
+// DepIterator::IsIgnorable - should this packag/providr be ignored?	/*{{{*/
+// ---------------------------------------------------------------------
+/* Deps like self-conflicts should be ignored as well as implicit conflicts
+   on virtual packages. */
+bool pkgCache::DepIterator::IsIgnorable(PkgIterator const &/*Pkg*/) const
+{
+   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;
+}
+bool pkgCache::DepIterator::IsIgnorable(PrvIterator const &Prv) const
+{
+   if (IsNegative() == false)
+      return false;
+
+   PkgIterator const Pkg = ParentPkg();
+   /* Provides may never be applied against the same package (or group)
+      if it is a conflicts. See the comment above. */
+   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)
+      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());
+}
+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	/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -732,7 +822,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)
@@ -745,7 +835,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)
@@ -841,6 +931,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
@@ -883,7 +985,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
@@ -894,11 +996,22 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
    {
       pkgCache::DescIterator Desc = DescriptionList();
       for (; Desc.end() == false; ++Desc)
-	 if (*l == Desc.LanguageCode() ||
-	     (*l == "en" && strcmp(Desc.LanguageCode(),"") == 0))
+	 if (*l == Desc.LanguageCode())
 	    break;
       if (Desc.end() == true)
-	 continue;
+      {
+	 if (*l == "en")
+	 {
+	    Desc = DescriptionList();
+	    for (; Desc.end() == false; ++Desc)
+	       if (strcmp(Desc.LanguageCode(), "") == 0)
+		  break;
+	    if (Desc.end() == true)
+	       continue;
+	 }
+	 else
+	    continue;
+      }
       return Desc;
    }
    for (pkgCache::DescIterator Desc = DescriptionList();
@@ -906,6 +1019,20 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
       if (strcmp(Desc.LanguageCode(), "") == 0)
 	 return Desc;
    return DescriptionList();
-};
+}
 
 									/*}}}*/
+// 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;
+}
+									/*}}}*/