]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/pkgcache.cc
merge patch from Daniel Hartwig to Show a error message if {,dist-}upgrade is used...
[apt.git] / apt-pkg / pkgcache.cc
index b63900adb94ca3bba06f13959b61f820ea5bff7a..bc6616839379cde9bf20531c21eb5ef48c0e0b40 100644 (file)
@@ -20,6 +20,8 @@
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
+#include<config.h>
+
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/policy.h>
 #include <apt-pkg/version.h>
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/macros.h>
 
-#include <apti18n.h>
-    
 #include <string>
 #include <sys/stat.h>
 #include <unistd.h>
-
 #include <ctype.h>
+
+#include <apti18n.h>
                                                                        /*}}}*/
 
 using std::string;
@@ -50,7 +51,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 = 9;
    MinorVersion = 0;
    Dirty = false;
    
@@ -84,6 +85,8 @@ pkgCache::Header::Header()
    memset(PkgHashTable,0,sizeof(PkgHashTable));
    memset(GrpHashTable,0,sizeof(GrpHashTable));
    memset(Pools,0,sizeof(Pools));
+
+   CacheFileSize = 0;
 }
                                                                        /*}}}*/
 // Cache::Header::CheckSizes - Check if the two headers have same *sz  /*{{{*/
@@ -155,6 +158,9 @@ 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"));
+
    // Locate our VS..
    if (HeaderP->VerSysName == 0 ||
        (VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
@@ -175,19 +181,18 @@ bool pkgCache::ReMap(bool const &Errorchecks)
 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);
+   for (string::const_iterator I = Str.begin(); I != Str.end(); ++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                 /*{{{*/
 // ---------------------------------------------------------------------
@@ -200,9 +205,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);
 }
@@ -211,11 +221,14 @@ pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &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");
+       {
+               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.
@@ -229,7 +242,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);
@@ -256,9 +269,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);
@@ -270,22 +288,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            /*{{{*/
@@ -367,6 +385,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);
@@ -481,7 +503,7 @@ pkgCache::PkgIterator::CurVersion() const
    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& 
-operator<<(ostream& out, pkgCache::PkgIterator Pkg) 
+operator<<(std::ostream& out, pkgCache::PkgIterator Pkg) 
 {
    if (Pkg.end() == true)
       return out << "invalid package";
@@ -518,15 +540,24 @@ std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
    conflicts (including dpkg's Breaks fields). */
 bool pkgCache::DepIterator::IsCritical() const
 {
-   if (S->Type == pkgCache::Dep::Conflicts ||
-       S->Type == pkgCache::Dep::DpkgBreaks ||
-       S->Type == pkgCache::Dep::Obsoletes ||
+   if (IsNegative() == true ||
        S->Type == pkgCache::Dep::Depends ||
        S->Type == pkgCache::Dep::PreDepends)
       return true;
    return false;
 }
                                                                        /*}}}*/
+// DepIterator::IsNegative - Returns true if the dep is a negative one /*{{{*/
+// ---------------------------------------------------------------------
+/* Some dependencies are positive like Depends and Recommends, others
+   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;
+}
+                                                                       /*}}}*/
 // DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides        /*{{{*/
 // ---------------------------------------------------------------------
 /* This intellegently looks at dep target packages and tries to figure
@@ -557,7 +588,7 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result) const
       virtual package libc-dev which is provided by libc5-dev and libc6-dev
       we must ignore libc5-dev when considering the provides list. */ 
    PrvIterator PStart = Result.ProvidesList();
-   for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); PStart++);
+   for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); ++PStart);
 
    // Nothing but indirect self provides
    if (PStart.end() == true)
@@ -565,7 +596,7 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result) const
    
    // Check for single packages in the provides list
    PrvIterator P = PStart;
-   for (; P.end() != true; P++)
+   for (; P.end() != true; ++P)
    {
       // Skip over self provides
       if (P.OwnerPkg() == ParentPkg())
@@ -599,34 +630,26 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const
       PkgIterator DPkg = TargetPkg();
 
       // Walk along the actual package providing versions
-      for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
+      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 ((S->Type == pkgCache::Dep::Conflicts ||
-             S->Type == pkgCache::Dep::DpkgBreaks ||
-             S->Type == pkgCache::Dep::Obsoletes) &&
-            ParentPkg() == I.ParentPkg())
+        if (IsSatisfied(I) == false)
            continue;
-        
+
         Size++;
         if (Res != 0)
            *End++ = I;
       }
       
       // Follow all provides
-      for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
+      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 ((S->Type == pkgCache::Dep::Conflicts ||
-             S->Type == pkgCache::Dep::DpkgBreaks ||
-             S->Type == pkgCache::Dep::Obsoletes) &&
-            ParentPkg() == I.OwnerPkg())
+        if (IsSatisfied(I) == false)
            continue;
-        
+
         Size++;
         if (Res != 0)
            *End++ = I.OwnerVer();
@@ -668,10 +691,84 @@ 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     /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-std::ostream& operator<<(ostream& out, pkgCache::DepIterator D)
+std::ostream& operator<<(std::ostream& out, pkgCache::DepIterator D)
 {
    if (D.end() == true)
       return out << "invalid dependency";
@@ -709,7 +806,7 @@ int pkgCache::VerIterator::CompareVer(const VerIterator &B) const
    /* Start at A and look for B. If B is found then A > B otherwise
       B was before A so A < B */
    VerIterator I = *this;
-   for (;I.end() == false; I++)
+   for (;I.end() == false; ++I)
       if (I == B)
         return 1;
    return -1;
@@ -721,7 +818,7 @@ int pkgCache::VerIterator::CompareVer(const VerIterator &B) const
 bool pkgCache::VerIterator::Downloadable() const
 {
    VerFileIterator Files = FileList();
-   for (; Files.end() == false; Files++)
+   for (; Files.end() == false; ++Files)
       if ((Files.File()->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource)
         return true;
    return false;
@@ -734,16 +831,13 @@ bool pkgCache::VerIterator::Downloadable() const
 bool pkgCache::VerIterator::Automatic() const
 {
    VerFileIterator Files = FileList();
-   for (; Files.end() == false; Files++)
+   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)
         return true;
    return false;
 }
                                                                        /*}}}*/
-// VerIterator::Pseudo - deprecated no-op method                       /*{{{*/
-bool pkgCache::VerIterator::Pseudo() const { return false; }
-                                                                       /*}}}*/
 // VerIterator::NewestFile - Return the newest file version relation   /*{{{*/
 // ---------------------------------------------------------------------
 /* This looks at the version numbers associated with all of the sources
@@ -752,7 +846,7 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
 {
    VerFileIterator Files = FileList();
    VerFileIterator Highest = Files;
-   for (; Files.end() == false; Files++)
+   for (; Files.end() == false; ++Files)
    {
       if (Owner->VS->CmpReleaseVer(Files.File().Version(),Highest.File().Version()) > 0)
         Highest = Files;
@@ -769,7 +863,7 @@ string pkgCache::VerIterator::RelStr() const
 {
    bool First = true;
    string Res;
-   for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; I++)
+   for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; ++I)
    {
       // Do not print 'not source' entries'
       pkgCache::PkgFileIterator File = I.File();
@@ -778,7 +872,7 @@ string pkgCache::VerIterator::RelStr() const
 
       // See if we have already printed this out..
       bool Seen = false;
-      for (pkgCache::VerFileIterator J = this->FileList(); I != J; J++)
+      for (pkgCache::VerFileIterator J = this->FileList(); I != J; ++J)
       {
         pkgCache::PkgFileIterator File2 = J.File();
         if (File2->Label == 0 || File->Label == 0)
@@ -879,15 +973,26 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
 {
    std::vector<string> const lang = APT::Configuration::getLanguages();
    for (std::vector<string>::const_iterator l = lang.begin();
-       l != lang.end(); l++)
+       l != lang.end(); ++l)
    {
       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();
@@ -898,3 +1003,17 @@ 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;
+}
+                                                                       /*}}}*/