]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/algorithms.cc
Fix double free (closes: #711045)
[apt.git] / apt-pkg / algorithms.cc
index 5d9fefaa670f3fbe937c9227c0101665192358d3..6cde4d6cc1ddcc5a8ae0da730db74f270c513789 100644 (file)
@@ -14,6 +14,8 @@
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
+#include <config.h>
+
 #include <apt-pkg/algorithms.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/edsp.h>
+#include <apt-pkg/sourcelist.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/progress.h>
 
-#include <apti18n.h>
 #include <sys/types.h>
 #include <cstdlib>
 #include <algorithm>
 #include <iostream>
-
 #include <stdio.h>
+
+#include <apti18n.h>
                                                                        /*}}}*/
 using namespace std;
 
@@ -53,6 +58,12 @@ pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
       FileNames[I] = Jnk;
 }
                                                                        /*}}}*/
+// Simulate::~Simulate - Destructor                                    /*{{{*/
+pkgSimulate::~pkgSimulate()
+{
+   delete[] Flags;
+}
+                                                                       /*}}}*/
 // Simulate::Describe - Describe a package                             /*{{{*/
 // ---------------------------------------------------------------------
 /* Parameter Current == true displays the current package version,
@@ -94,7 +105,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    Sim.MarkInstall(Pkg,false);
 
    // Look for broken conflicts+predepends.
-   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; ++I)
    {
       if (Sim[I].InstallVer == 0)
         continue;
@@ -104,9 +115,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
         DepIterator Start;
         DepIterator End;
         D.GlobOr(Start,End);
-        if (Start->Type == pkgCache::Dep::Conflicts ||
-            Start->Type == pkgCache::Dep::DpkgBreaks ||
-            Start->Type == pkgCache::Dep::Obsoletes ||
+        if (Start.IsNegative() == true ||
             End->Type == pkgCache::Dep::PreDepends)
          {
            if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
@@ -145,7 +154,7 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
       Sim.Update();
       
       // Print out each package and the failed dependencies
-      for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; ++D)
       {
         if (Sim.IsImportantDep(D) == false || 
             (Sim[D] & pkgDepCache::DepInstall) != 0)
@@ -185,6 +194,11 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
+   if (Pkg.end() == true)
+   {
+      std::cerr << (Purge ? "Purg" : "Remv") << " invalid package " << iPkg.FullName() << std::endl;
+      return false;
+   }
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
@@ -209,7 +223,7 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 void pkgSimulate::ShortBreaks()
 {
    cout << " [";
-   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; ++I)
    {
       if (Sim[I].InstBroken() == true)
       {
@@ -231,7 +245,7 @@ bool pkgApplyStatus(pkgDepCache &Cache)
 {
    pkgDepCache::ActionGroup group(Cache);
 
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (I->VersionList == 0)
         continue;
@@ -273,13 +287,13 @@ bool pkgApplyStatus(pkgDepCache &Cache)
                 Cache[I].CandidateVerIter(Cache).Downloadable() == true)
               Cache.MarkInstall(I, true, 0, false);
            else
-              Cache.MarkDelete(I);
+              Cache.MarkDelete(I, false, 0, false);
         }
         break;
 
         // This means removal failed
         case pkgCache::State::HalfInstalled:
-        Cache.MarkDelete(I);
+        Cache.MarkDelete(I, false, 0, false);
         break;
         
         default:
@@ -300,13 +314,13 @@ bool pkgFixBroken(pkgDepCache &Cache)
    pkgDepCache::ActionGroup group(Cache);
 
    // Auto upgrade all broken packages
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (Cache[I].NowBroken() == true)
         Cache.MarkInstall(I, true, 0, false);
    
    /* Fix packages that are in a NeedArchive state but don't have a
       downloadable install version */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (I.State() != pkgCache::PkgIterator::NeedsUnpack ||
          Cache[I].Delete() == true)
@@ -332,9 +346,11 @@ bool pkgFixBroken(pkgDepCache &Cache)
  */
 bool pkgDistUpgrade(pkgDepCache &Cache)
 {
-   std::string const solver = _config->Find("APT::Solver::Name", "internal");
-   if (solver != "internal")
-      return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false);
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false, &Prog);
+   }
 
    pkgDepCache::ActionGroup group(Cache);
 
@@ -347,19 +363,44 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
 
    /* Auto upgrade all installed packages, this provides the basis 
       for the installation */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
         Cache.MarkInstall(I, true, 0, false);
 
-   /* Now, auto upgrade all essential packages - this ensures that
-      the essential packages are present and working */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
-      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
-        Cache.MarkInstall(I, true, 0, false);
+   /* Now, install each essential package which is not installed
+      (and not provided by another package in the same name group) */
+   std::string essential = _config->Find("pkgCacheGen::Essential", "all");
+   if (essential == "all")
+   {
+      for (pkgCache::GrpIterator G = Cache.GrpBegin(); G.end() == false; ++G)
+      {
+        bool isEssential = false;
+        bool instEssential = false;
+        for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
+        {
+           if ((P->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
+              continue;
+           isEssential = true;
+           if (Cache[P].Install() == true)
+           {
+              instEssential = true;
+              break;
+           }
+        }
+        if (isEssential == false || instEssential == true)
+           continue;
+        pkgCache::PkgIterator P = G.FindPreferredPkg();
+        Cache.MarkInstall(P, true, 0, false);
+      }
+   }
+   else if (essential != "none")
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
+        if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+           Cache.MarkInstall(I, true, 0, false);
    
    /* We do it again over all previously installed packages to force 
       conflict resolution on them all. */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
         Cache.MarkInstall(I, false, 0, false);
 
@@ -368,7 +409,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
    // Hold back held packages.
    if (_config->FindB("APT::Ignore-Hold",false) == false)
    {
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         if (I->SelectedState == pkgCache::State::Hold)
         {
@@ -388,9 +429,11 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
    to install packages not marked for install */
 bool pkgAllUpgrade(pkgDepCache &Cache)
 {
-   std::string const solver = _config->Find("APT::Solver::Name", "internal");
-   if (solver != "internal")
-      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false);
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+   }
 
    pkgDepCache::ActionGroup group(Cache);
 
@@ -400,7 +443,7 @@ bool pkgAllUpgrade(pkgDepCache &Cache)
       return false;
    
    // Upgrade all installed packages
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].Install() == true)
         Fix.Protect(I);
@@ -434,7 +477,7 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
    do
    {
       Change = false;
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         // Not interesting
         if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
@@ -451,7 +494,7 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
               Change = true;
         }       
       }      
-      Count++;
+      ++Count;
    }
    while (Change == true && Count < 10);
 
@@ -464,11 +507,11 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
 // ProblemResolver::pkgProblemResolver - Constructor                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : Cache(*pCache)
+pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : d(NULL), Cache(*pCache)
 {
    // Allocate memory
    unsigned long Size = Cache.Head().PackageCount;
-   Scores = new signed short[Size];
+   Scores = new int[Size];
    Flags = new unsigned char[Size];
    memset(Flags,0,sizeof(*Flags)*Size);
    
@@ -507,29 +550,32 @@ void pkgProblemResolver::MakeScores()
    unsigned long Size = Cache.Head().PackageCount;
    memset(Scores,0,sizeof(*Scores)*Size);
 
-   // Important Required Standard Optional Extra
-   signed short PrioMap[] = {
+   // Maps to pkgCache::State::VerPriority
+   //   which is "Important Required Standard Optional Extra"
+   // (yes, that is confusing, the order of pkgCache::State::VerPriority
+   //  needs to be adjusted but that requires a ABI break)
+   int PrioMap[] = {
       0,
-      (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3),
-      (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2),
-      (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1),
-      (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1),
-      (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2)
+      _config->FindI("pkgProblemResolver::Scores::Important",2),
+      _config->FindI("pkgProblemResolver::Scores::Required",3),
+      _config->FindI("pkgProblemResolver::Scores::Standard",1),
+      _config->FindI("pkgProblemResolver::Scores::Optional",-1),
+      _config->FindI("pkgProblemResolver::Scores::Extra",-2)
    };
-   signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
-   signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
-   signed short PrioDepends = _config->FindI("pkgProblemResolver::Scores::Depends",1);
-   signed short PrioRecommends = _config->FindI("pkgProblemResolver::Scores::Recommends",1);
-   signed short AddProtected = _config->FindI("pkgProblemResolver::Scores::AddProtected",10000);
-   signed short AddEssential = _config->FindI("pkgProblemResolver::Scores::AddEssential",5000);
+   int PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
+   int PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
+   int PrioDepends = _config->FindI("pkgProblemResolver::Scores::Depends",1);
+   int PrioRecommends = _config->FindI("pkgProblemResolver::Scores::Recommends",1);
+   int AddProtected = _config->FindI("pkgProblemResolver::Scores::AddProtected",10000);
+   int AddEssential = _config->FindI("pkgProblemResolver::Scores::AddEssential",5000);
 
    if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
       clog << "Settings used to calculate pkgProblemResolver::Scores::" << endl
-         << "  Important => " << PrioMap[1] << endl
-         << "  Required => " << PrioMap[2] << endl
-         << "  Standard => " << PrioMap[3] << endl
-         << "  Optional => " << PrioMap[4] << endl
-         << "  Extra => " << PrioMap[5] << endl
+         << "  Required => " << PrioMap[pkgCache::State::Required] << endl
+         << "  Important => " << PrioMap[pkgCache::State::Important] << endl
+         << "  Standard => " << PrioMap[pkgCache::State::Standard] << endl
+         << "  Optional => " << PrioMap[pkgCache::State::Optional] << endl
+         << "  Extra => " << PrioMap[pkgCache::State::Extra] << endl
          << "  Essentials => " << PrioEssentials << endl
          << "  InstalledAndNotObsolete => " << PrioInstalledAndNotObsolete << endl
          << "  Depends => " << PrioDepends << endl
@@ -538,18 +584,19 @@ void pkgProblemResolver::MakeScores()
          << "  AddEssential => " << AddEssential << endl;
 
    // Generate the base scores for a package based on its properties
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      signed short &Score = Scores[I->ID];
+      int &Score = Scores[I->ID];
       
       /* This is arbitrary, it should be high enough to elevate an
          essantial package above most other packages but low enough
         to allow an obsolete essential packages to be removed by
         a conflicts on a powerfull normal package (ie libc6) */
-      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential
+         || (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
         Score += PrioEssentials;
 
       // We transform the priority
@@ -565,12 +612,12 @@ void pkgProblemResolver::MakeScores()
    }
 
    // Now that we have the base scores we go and propogate dependencies
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; ++D)
       {
         if (D->Type == pkgCache::Dep::Depends || 
             D->Type == pkgCache::Dep::PreDepends)
@@ -581,18 +628,18 @@ void pkgProblemResolver::MakeScores()
    }   
    
    // Copy the scores to advoid additive looping
-   SPtrArray<signed short> OldScores = new signed short[Size];
+   SPtrArray<int> OldScores = new int[Size];
    memcpy(OldScores,Scores,sizeof(*Scores)*Size);
       
    /* Now we cause 1 level of dependency inheritance, that is we add the 
       score of the packages that depend on the target Package. This 
       fortifies high scoring packages */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; ++D)
       {
         // Only do it for the install version
         if ((pkgCache::Version *)D.ParentVer() != Cache[D.ParentPkg()].InstallVer ||
@@ -601,15 +648,18 @@ void pkgProblemResolver::MakeScores()
              D->Type != pkgCache::Dep::Recommends))
            continue;    
         
-        Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
+        // Do not propagate negative scores otherwise
+        // an extra (-2) package might score better than an optional (-1)
+        if (OldScores[D.ParentPkg()->ID] > 0)
+            Scores[I->ID] += OldScores[D.ParentPkg()->ID];
       }      
    }
 
    /* Now we propogate along provides. This makes the packages that 
       provide important packages extremely important */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
-      for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; P++)
+      for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; ++P)
       {
         // Only do it once per package
         if ((pkgCache::Version *)P.OwnerVer() != Cache[P.OwnerPkg()].InstallVer)
@@ -620,11 +670,12 @@ void pkgProblemResolver::MakeScores()
 
    /* Protected things are pushed really high up. This number should put them
       ahead of everything */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if ((Flags[I->ID] & Protected) != 0)
         Scores[I->ID] += AddProtected;
-      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential ||
+          (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
         Scores[I->ID] += AddEssential;
    }
 }
@@ -658,12 +709,10 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       // Compute a single dependency element (glob or)
       pkgCache::DepIterator Start = D;
       pkgCache::DepIterator End = D;
-      unsigned char State = 0;
       for (bool LastOR = true; D.end() == false && LastOR == true;)
       {
-        State |= Cache[D];
         LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
-        D++;
+        ++D;
         if (LastOR == true)
            End = D;
       }
@@ -708,9 +757,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
            {
               /* We let the algorithm deal with conflicts on its next iteration,
                it is much smarter than us */
-              if (Start->Type == pkgCache::Dep::Conflicts || 
-                  Start->Type == pkgCache::Dep::DpkgBreaks || 
-                  Start->Type == pkgCache::Dep::Obsoletes)
+              if (Start.IsNegative() == true)
                   break;
               
               if (Debug == true)
@@ -721,7 +768,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
         
         if (Start == End)
            break;
-        Start++;
+        ++Start;
       }
       if (Fail == true)
         break;
@@ -733,7 +780,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       if (WasKept == true)
         Cache.MarkKeep(Pkg, false, false);
       else
-        Cache.MarkDelete(Pkg);
+        Cache.MarkDelete(Pkg, false, 0, false);
       return false;
    }    
    
@@ -747,9 +794,11 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
 /* */
 bool pkgProblemResolver::Resolve(bool BrokenFix)
 {
-   std::string const solver = _config->Find("APT::Solver::Name", "internal");
-   if (solver != "internal")
-      return EDSP::ResolveExternal(solver.c_str(), Cache, false, false, false);
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, false, false, false, &Prog);
+   }
    return ResolveInternal(BrokenFix);
 }
                                                                        /*}}}*/
@@ -776,7 +825,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    do
    {
       Again = false;
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         if (Cache[I].Install() == true)
            Flags[I->ID] |= PreInstalled;
@@ -809,7 +858,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
       would cause the removal of even lower score packages. */
    SPtrArray<pkgCache::Package *> PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       *PEnd++ = I;
    This = this;
    qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
@@ -860,7 +909,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                OldBreaks < Cache.BrokenCount())
            {
               if (OldVer == 0)
-                 Cache.MarkDelete(I);
+                 Cache.MarkDelete(I, false, 0, false);
               else
                  Cache.MarkKeep(I, false, false);
            }       
@@ -899,7 +948,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                     {
                        if (Debug == true)
                           clog << "  Or group remove for " << I.FullName(false) << endl;
-                       Cache.MarkDelete(I);
+                       Cache.MarkDelete(I, false, 0, false);
                        Change = true;
                     }
                  }
@@ -929,7 +978,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
            }
            else
             {
-              Start++;
+              ++Start;
               // We only worry about critical deps.
               if (Start.IsCritical() != true)
                   continue;
@@ -950,9 +999,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
               if a package has a dep on another package that cant be found */
            SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
            if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
-               Start->Type != pkgCache::Dep::Conflicts &&
-               Start->Type != pkgCache::Dep::DpkgBreaks &&
-               Start->Type != pkgCache::Dep::Obsoletes &&
+               Start.IsNegative() == false &&
                Cache[I].NowBroken() == false)
            {          
               if (InOr == true)
@@ -977,10 +1024,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                   at is not the currently selected version of the 
                   package, which means it is not necessary to 
                   remove/keep */
-               if (Cache[Pkg].InstallVer != Ver &&
-                   (Start->Type == pkgCache::Dep::Conflicts ||
-                    Start->Type == pkgCache::Dep::DpkgBreaks ||
-                    Start->Type == pkgCache::Dep::Obsoletes)) 
+               if (Cache[Pkg].InstallVer != Ver && Start.IsNegative() == true)
                {
                   if (Debug) 
                      clog << "  Conflicts//Breaks against version " 
@@ -998,9 +1042,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                  fiddle with the VList package */
               if (Scores[I->ID] <= Scores[Pkg->ID] ||
                   ((Cache[Start] & pkgDepCache::DepNow) == 0 &&
-                   End->Type != pkgCache::Dep::Conflicts &&
-                   End->Type != pkgCache::Dep::DpkgBreaks &&
-                   End->Type != pkgCache::Dep::Obsoletes))
+                   End.IsNegative() == false))
               {
                  // Try a little harder to fix protected packages..
                  if ((Flags[I->ID] & Protected) == Protected)
@@ -1037,11 +1079,11 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                     if (BrokenFix == false || DoUpgrade(I) == false)
                     {
                        // Consider other options
-                       if (InOr == false)
+                       if (InOr == false || Cache[I].Garbage == true)
                        {
                           if (Debug == true)
                              clog << "  Removing " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
-                          Cache.MarkDelete(I);
+                          Cache.MarkDelete(I, false, 0, false);
                           if (Counter > 1 && Scores[Pkg->ID] > Scores[I->ID])
                              Scores[I->ID] = Scores[Pkg->ID];
                        }
@@ -1100,17 +1142,14 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                  LEnd->Dep = End;
                  LEnd++;
                  
-                 if (Start->Type != pkgCache::Dep::Conflicts &&
-                     Start->Type != pkgCache::Dep::Obsoletes)
+                 if (Start.IsNegative() == false)
                     break;
               }
            }
 
            // Hm, nothing can possibly satisify this dep. Nuke it.
-           if (VList[0] == 0 && 
-               Start->Type != pkgCache::Dep::Conflicts &&
-               Start->Type != pkgCache::Dep::DpkgBreaks &&
-               Start->Type != pkgCache::Dep::Obsoletes &&
+           if (VList[0] == 0 &&
+               Start.IsNegative() == false &&
                (Flags[I->ID] & Protected) != Protected)
            {
               bool Installed = Cache[I].Install();
@@ -1133,7 +1172,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                  if (Debug == true)
                     clog << "  Removing " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
                  if (InOr == false)
-                    Cache.MarkDelete(I);
+                    Cache.MarkDelete(I, false, 0, false);
               }
 
               Change = true;
@@ -1156,13 +1195,11 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
               Change = true;
               if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
               {
-                 if (J->Dep->Type == pkgCache::Dep::Conflicts || 
-                     J->Dep->Type == pkgCache::Dep::DpkgBreaks ||
-                     J->Dep->Type == pkgCache::Dep::Obsoletes)
+                 if (J->Dep.IsNegative() == true)
                  {
                     if (Debug == true)
                        clog << "  Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
-                    Cache.MarkDelete(J->Pkg);
+                    Cache.MarkDelete(J->Pkg, false, 0, false);
                  }
               }
               else
@@ -1189,7 +1226,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    {
       // See if this is the result of a hold
       pkgCache::PkgIterator I = Cache.PkgBegin();
-      for (;I.end() != true; I++)
+      for (;I.end() != true; ++I)
       {
         if (Cache[I].InstBroken() == false)
            continue;
@@ -1201,7 +1238,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    
    // set the auto-flags (mvo: I'm not sure if we _really_ need this)
    pkgCache::PkgIterator I = Cache.PkgBegin();
-   for (;I.end() != true; I++) {
+   for (;I.end() != true; ++I) {
       if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
         if(_config->FindI("Debug::pkgAutoRemove",false)) {
            std::clog << "Resolve installed new pkg: " << I.FullName(false) 
@@ -1215,6 +1252,37 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    return true;
 }
                                                                        /*}}}*/
+// ProblemResolver::BreaksInstOrPolicy - Check if the given pkg is broken/*{{{*/
+// ---------------------------------------------------------------------
+/* This checks if the given package is broken either by a hard dependency
+   (InstBroken()) or by introducing a new policy breakage e.g. new
+   unsatisfied recommends for a package that was in "policy-good" state
+
+   Note that this is not perfect as it will ignore further breakage
+   for already broken policy (recommends)
+*/
+bool pkgProblemResolver::InstOrNewPolicyBroken(pkgCache::PkgIterator I)
+{
+   // a broken install is always a problem
+   if (Cache[I].InstBroken() == true)
+   {
+      if (Debug == true)
+        std::clog << "  Dependencies are not satisfied for " << I << std::endl;
+      return true;
+   }
+
+   // a newly broken policy (recommends/suggests) is a problem
+   if (Cache[I].NowPolicyBroken() == false &&
+       Cache[I].InstPolicyBroken() == true)
+   {
+      if (Debug == true)
+        std::clog << "  Policy breaks with upgrade of " << I << std::endl;
+      return true;
+   }
+
+   return false;
+}
+                                                                       /*}}}*/
 // ProblemResolver::ResolveByKeep - Resolve problems using keep                /*{{{*/
 // ---------------------------------------------------------------------
 /* This is the work horse of the soft upgrade routine. It is very gental 
@@ -1222,9 +1290,11 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    system was non-broken previously. */
 bool pkgProblemResolver::ResolveByKeep()
 {
-   std::string const solver = _config->Find("APT::Solver::Name", "internal");
-   if (solver != "internal")
-      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false);
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+   }
    return ResolveByKeepInternal();
 }
                                                                        /*}}}*/
@@ -1247,7 +1317,7 @@ bool pkgProblemResolver::ResolveByKeepInternal()
       would cause the removal of even lower score packages. */
    pkgCache::Package **PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       *PEnd++ = I;
    This = this;
    qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
@@ -1272,9 +1342,12 @@ bool pkgProblemResolver::ResolveByKeepInternal()
    {
       pkgCache::PkgIterator I(Cache,*K);
 
-      if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
+      if (Cache[I].InstallVer == 0)
         continue;
 
+      if (InstOrNewPolicyBroken(I) == false)
+         continue;
+
       /* Keep the package. If this works then great, otherwise we have
                 to be significantly more agressive and manipulate its dependencies */
       if ((Flags[I->ID] & Protected) == 0)
@@ -1282,7 +1355,7 @@ bool pkgProblemResolver::ResolveByKeepInternal()
         if (Debug == true)
            clog << "Keeping package " << I.FullName(false) << endl;
         Cache.MarkKeep(I, false, false);
-        if (Cache[I].InstBroken() == false)
+        if (InstOrNewPolicyBroken(I) == false)
         {
            K = PList - 1;
            continue;
@@ -1332,32 +1405,38 @@ bool pkgProblemResolver::ResolveByKeepInternal()
                  Cache.MarkKeep(Pkg, false, false);
               }
               
-              if (Cache[I].InstBroken() == false)
+              if (InstOrNewPolicyBroken(I) == false)
                  break;
            }
            
-           if (Cache[I].InstBroken() == false)
+           if (InstOrNewPolicyBroken(I) == false)
               break;
 
            if (Start == End)
               break;
-           Start++;
+           ++Start;
         }
              
-        if (Cache[I].InstBroken() == false)
+        if (InstOrNewPolicyBroken(I) == false)
            break;
       }
 
-      if (Cache[I].InstBroken() == true)
+      if (InstOrNewPolicyBroken(I) == true)
         continue;
       
       // Restart again.
-      if (K == LastStop)
-        return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.FullName(false).c_str());
+      if (K == LastStop) {
+          // I is an iterator based off our temporary package list,
+          // so copy the name we need before deleting the temporary list
+          std::string const LoopingPackage = I.FullName(false);
+          delete[] PList;
+          return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.", LoopingPackage.c_str());
+      }
       LastStop = K;
       K = PList - 1;
-   }   
+   }
 
+   delete[] PList;
    return true;
 }
                                                                        /*}}}*/
@@ -1368,7 +1447,7 @@ void pkgProblemResolver::InstallProtect()
 {
    pkgDepCache::ActionGroup group(Cache);
 
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if ((Flags[I->ID] & Protected) == Protected)
       {
@@ -1401,6 +1480,13 @@ static int PrioComp(const void *A,const void *B)
    if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
        (R.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
      return -1;
+
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important &&
+       (R.ParentPkg()->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
+     return 1;
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important &&
+       (R.ParentPkg()->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
+     return -1;
    
    if (L->Priority != R->Priority)
       return R->Priority - L->Priority;
@@ -1415,7 +1501,7 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
    qsort(List,Count,sizeof(*List),PrioComp);
 }
                                                                        /*}}}*/
-// CacheFile::ListUpdate - update the cache files                      /*{{{*/
+// ListUpdate - construct Fetcher and update the cache files           /*{{{*/
 // ---------------------------------------------------------------------
 /* This is a simple wrapper to update the cache. it will fetch stuff
  * from the network (or any other sources defined in sources.list)
@@ -1424,7 +1510,6 @@ bool ListUpdate(pkgAcquireStatus &Stat,
                pkgSourceList &List, 
                int PulseInterval)
 {
-   pkgAcquire::RunResult res;
    pkgAcquire Fetcher;
    if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
       return false;
@@ -1433,11 +1518,24 @@ bool ListUpdate(pkgAcquireStatus &Stat,
    if (List.GetIndexes(&Fetcher) == false)
         return false;
 
+   return AcquireUpdate(Fetcher, PulseInterval, true);
+}
+                                                                       /*}}}*/
+// AcquireUpdate - take Fetcher and update the cache files             /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a simple wrapper to update the cache with a provided acquire
+ * If you only need control over Status and the used SourcesList use
+ * ListUpdate method instead.
+ */
+bool AcquireUpdate(pkgAcquire &Fetcher, int const PulseInterval,
+                  bool const RunUpdateScripts, bool const ListCleanup)
+{
    // Run scripts
-   RunScripts("APT::Update::Pre-Invoke");
-   
-   // check arguments
-   if(PulseInterval>0)
+   if (RunUpdateScripts == true)
+      RunScripts("APT::Update::Pre-Invoke");
+
+   pkgAcquire::RunResult res;
+   if(PulseInterval > 0)
       res = Fetcher.Run(PulseInterval);
    else
       res = Fetcher.Run();
@@ -1448,7 +1546,7 @@ bool ListUpdate(pkgAcquireStatus &Stat,
    bool Failed = false;
    bool TransientNetworkFailure = false;
    for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); 
-       I != Fetcher.ItemsEnd(); I++)
+       I != Fetcher.ItemsEnd(); ++I)
    {
       if ((*I)->Status == pkgAcquire::Item::StatDone)
         continue;
@@ -1474,7 +1572,7 @@ bool ListUpdate(pkgAcquireStatus &Stat,
    // Clean out any old list files
    // Keep "APT::Get::List-Cleanup" name for compatibility, but
    // this is really a global option for the APT library now
-   if (!TransientNetworkFailure && !Failed &&
+   if (!TransientNetworkFailure && !Failed && ListCleanup == true &&
        (_config->FindB("APT::Get::List-Cleanup",true) == true &&
        _config->FindB("APT::List-Cleanup",true) == true))
    {
@@ -1491,11 +1589,14 @@ bool ListUpdate(pkgAcquireStatus &Stat,
 
 
    // Run the success scripts if all was fine
-   if(!TransientNetworkFailure && !Failed)
-      RunScripts("APT::Update::Post-Invoke-Success");
+   if (RunUpdateScripts == true)
+   {
+      if(!TransientNetworkFailure && !Failed)
+        RunScripts("APT::Update::Post-Invoke-Success");
 
-   // Run the other scripts
-   RunScripts("APT::Update::Post-Invoke");
+      // Run the other scripts
+      RunScripts("APT::Update::Post-Invoke");
+   }
    return true;
 }
                                                                        /*}}}*/