]> git.saurik.com Git - apt.git/commitdiff
Merge remote-tracking branch 'upstream/debian/sid' into debian/experimental
authorMichael Vogt <mvo@debian.org>
Thu, 29 May 2014 10:14:42 +0000 (12:14 +0200)
committerMichael Vogt <mvo@debian.org>
Thu, 29 May 2014 10:14:42 +0000 (12:14 +0200)
Conflicts:
test/integration/test-bug-747261-arch-specific-conflicts

1  2 
apt-pkg/deb/debindexfile.cc
apt-pkg/deb/deblistparser.h
apt-pkg/packagemanager.cc
apt-pkg/packagemanager.h
cmdline/apt-get.cc

index 7cb8e3b684cad61be7d36398d110641b74d13ff8,a0dd15cd831d1e5661e564ba1e173d10da97ef81..3bdc551b40c7623f2ec504f5cd6867a78615ddf7
@@@ -30,7 -30,6 +30,7 @@@
  #include <apt-pkg/pkgcachegen.h>
  #include <apt-pkg/pkgrecords.h>
  #include <apt-pkg/srcrecords.h>
 +#include <apt-pkg/sptr.h>
  
  #include <stdio.h>
  #include <iostream>
@@@ -526,7 -525,7 +526,7 @@@ bool debTranslationsIndex::Merge(pkgCac
     if (FileExists(TranslationFile))
     {
       FileFd Trans(TranslationFile,FileFd::ReadOnly, FileFd::Extension);
-      debListParser TransParser(&Trans);
+      debTranslationsParser TransParser(&Trans);
       if (_error->PendingError() == true)
         return false;
       
@@@ -668,133 -667,6 +668,133 @@@ APT_CONST bool debStatusIndex::Exists(
  }
                                                                        /*}}}*/
  
 +// debDebPkgFile - Single .deb file                                           /*{{{*/
 +// ---------------------------------------------------------------------
 +debDebPkgFileIndex::debDebPkgFileIndex(std::string DebFile)
 +   : pkgIndexFile(true), DebFile(DebFile)
 +{
 +   DebFileFullPath = flAbsPath(DebFile);
 +}
 +
 +std::string debDebPkgFileIndex::ArchiveURI(std::string /*File*/) const
 +{
 +   return "file:" + DebFileFullPath;
 +}
 +
 +bool debDebPkgFileIndex::Exists() const
 +{
 +   return FileExists(DebFile);
 +}
 +bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const
 +{
 +   if(Prog)
 +      Prog->SubProgress(0, "Reading deb file");
 +
 +   // get the control data out of the deb file vid dpkg -I
 +   // ... can I haz libdpkg?
 +   std::string dpkg = _config->Find("Dir::Bin::dpkg","dpkg");
 +   const char *Args[5] = {dpkg.c_str(),
 +                          "-I",
 +                          DebFile.c_str(),
 +                          "control",
 +                          NULL};
 +   FileFd PipeFd;
 +   pid_t Child;
 +   if(Popen(Args, PipeFd, Child, FileFd::ReadOnly) == false)
 +      return _error->Error("Popen failed");
 +   // FIXME: static buffer
 +   char buf[8*1024];
 +   unsigned long long n = 0;
 +   if(PipeFd.Read(buf, sizeof(buf)-1, &n) == false)
 +      return _error->Errno("read", "Failed to read dpkg pipe");
 +   ExecWait(Child, "Popen");
 +
 +   // now write the control data to a tempfile
 +   SPtr<FileFd> DebControl = GetTempFile("deb-file-" + DebFile);
 +   if(DebControl == NULL)
 +      return false;
 +   DebControl->Write(buf, n);
 +   // append size of the file
 +   FileFd Fd(DebFile, FileFd::ReadOnly);
 +   string Size;
 +   strprintf(Size, "Size: %llu\n", Fd.Size());
 +   DebControl->Write(Size.c_str(), Size.size());
 +   // and rewind for the listparser
 +   DebControl->Seek(0);
 +
 +   // and give it to the list parser
 +   debDebFileParser Parser(DebControl, DebFile);
 +   if(Gen.SelectFile(DebFile, "local", *this) == false)
 +      return _error->Error("Problem with SelectFile %s", DebFile.c_str());
 +
 +   pkgCache::PkgFileIterator File = Gen.GetCurFile();
 +   File->Size = DebControl->Size();
 +   File->mtime = DebControl->ModificationTime();
 +   
 +   if (Gen.MergeList(Parser) == false)
 +      return _error->Error("Problem with MergeLister for %s", DebFile.c_str());
 +
 +   return true;
 +}
 +pkgCache::PkgFileIterator debDebPkgFileIndex::FindInCache(pkgCache &Cache) const
 +{
 +   // FIXME: we could simply always return pkgCache::PkgFileIterator(Cache);
 +   //        to indicate its never in the cache which will force a Merge()
 +   pkgCache::PkgFileIterator File = Cache.FileBegin();
 +   for (; File.end() == false; ++File)
 +   {
 +       if (File.FileName() == NULL || DebFile != File.FileName())
 +       continue;
 +
 +       return File;
 +   }
 +   
 +   return File;
 +}
 +unsigned long debDebPkgFileIndex::Size() const
 +{
 +   struct stat buf;
 +   if(stat(DebFile.c_str(), &buf) != 0)
 +      return 0;
 +   return buf.st_size;
 +}
 +                                                                      /*}}}*/
 +
 +// debDscFileIndex stuff
 +debDscFileIndex::debDscFileIndex(std::string &DscFile) 
 +   : pkgIndexFile(true), DscFile(DscFile)
 +{
 +}
 +
 +bool debDscFileIndex::Exists() const
 +{
 +   return FileExists(DscFile);
 +}
 +
 +unsigned long debDscFileIndex::Size() const
 +{
 +   struct stat buf;
 +   if(stat(DscFile.c_str(), &buf) == 0)
 +      return buf.st_size;
 +   return 0;
 +}
 +
 +// DscFileIndex::CreateSrcParser - Get a parser for the .dsc file     /*{{{*/
 +// ---------------------------------------------------------------------
 +/* */
 +pkgSrcRecords::Parser *debDscFileIndex::CreateSrcParser() const
 +{
 +   if (!FileExists(DscFile))
 +      return NULL;
 +
 +   return new debDscRecordParser(DscFile,this);
 +}
 +                                                                      /*}}}*/
 +
 +
 +
 +
 +// ---------------------------------------------------------------------
  // Index File types for Debian                                                /*{{{*/
  class debIFTypeSrc : public pkgIndexFile::Type
  {
@@@ -827,42 -699,10 +827,42 @@@ class debIFTypeStatus : public pkgIndex
     };
     debIFTypeStatus() {Label = "Debian dpkg status file";};
  };
 +class debIFTypeDebPkgFile : public pkgIndexFile::Type
 +{
 +   public:
 +   virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const 
 +   {
 +      return new debDebFileRecordParser(File.FileName(),*File.Cache());
 +   };
 +   debIFTypeDebPkgFile() {Label = "deb Package file";};
 +};
 +class debIFTypeDscFile : public pkgIndexFile::Type
 +{
 +   public:
 +   virtual pkgSrcRecords::Parser *CreateSrcPkgParser(std::string DscFile) const
 +   {
 +      return new debDscRecordParser(DscFile, NULL);
 +   };
 +   debIFTypeDscFile() {Label = "dsc File Source Index";};
 +};
 +class debIFTypeDebianSourceDir : public pkgIndexFile::Type
 +{
 +   public:
 +   virtual pkgSrcRecords::Parser *CreateSrcPkgParser(std::string SourceDir) const
 +   {
 +      return new debDscRecordParser(SourceDir + string("/debian/control"), NULL);
 +   };
 +   debIFTypeDebianSourceDir() {Label = "debian/control File Source Index";};
 +};
 +
  static debIFTypeSrc _apt_Src;
  static debIFTypePkg _apt_Pkg;
  static debIFTypeTrans _apt_Trans;
  static debIFTypeStatus _apt_Status;
 +static debIFTypeDebPkgFile _apt_DebPkgFile;
 +// file based pseudo indexes
 +static debIFTypeDscFile _apt_DscFile;
 +static debIFTypeDebianSourceDir _apt_DebianSourceDir;
  
  const pkgIndexFile::Type *debSourcesIndex::GetType() const
  {
@@@ -880,16 -720,5 +880,16 @@@ const pkgIndexFile::Type *debStatusInde
  {
     return &_apt_Status;
  }
 -
 +const pkgIndexFile::Type *debDebPkgFileIndex::GetType() const
 +{
 +   return &_apt_DebPkgFile;
 +}
 +const pkgIndexFile::Type *debDscFileIndex::GetType() const
 +{
 +   return &_apt_DscFile;
 +}
 +const pkgIndexFile::Type *debDebianSourceDirIndex::GetType() const
 +{
 +   return &_apt_DebianSourceDir;
 +}
                                                                        /*}}}*/
index 5a2282f9c7c89d413c702ad4703ac43dc6c6aa60,3b6963211649d503454bab13a1b6c6e1a5f3f2de..56a83b36e41cc3232a9015bf1ea25ed1ae7db1a1
@@@ -56,8 -56,7 +56,8 @@@ class debListParser : public pkgCacheGe
     bool ParseProvides(pkgCache::VerIterator &Ver);
     bool NewProvidesAllArch(pkgCache::VerIterator &Ver, std::string const &Package, std::string const &Version);
     static bool GrabWord(std::string Word,WordList *List,unsigned char &Out);
 -   
 +   APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors);
 +
     public:
  
     static unsigned char GetPrio(std::string Str);
@@@ -68,8 -67,8 +68,8 @@@
     virtual bool ArchitectureAll();
     virtual std::string Version();
     virtual bool NewVersion(pkgCache::VerIterator &Ver);
 -   virtual std::string Description();
 -   virtual std::string DescriptionLanguage();
 +   virtual std::string Description(std::string const &lang);
 +   virtual std::vector<std::string> AvailableDescriptionLanguages();
     virtual MD5SumValue Description_md5();
     virtual unsigned short VersionHash();
  #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
  
     debListParser(FileFd *File, std::string const &Arch = "");
     virtual ~debListParser() {};
 +};
  
 -   private:
 -   APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors);
 +class debDebFileParser : public debListParser
 +{
 + private:
 +   std::string DebFile;
 +
 + public:
 +   debDebFileParser(FileFd *File, std::string const &DebFile);
 +   virtual bool UsePackage(pkgCache::PkgIterator &Pkg,
 +                         pkgCache::VerIterator &Ver);
  };
  
+ class debTranslationsParser : public debListParser
+ {
+  public:
+    // a translation can never be a real package
+    virtual std::string Architecture() { return ""; }
+    virtual std::string Version() { return ""; }
+    debTranslationsParser(FileFd *File, std::string const &Arch = "")
+       : debListParser(File, Arch) {};
+ };
  #endif
index 0ec9f33091e6294623fecdf527ece890fd8599d0,393f836f71c2af11895fa776728636d30f1a5253..d9df28ba3132b2c45481c5e29cc9cf11beaec3cb
@@@ -28,7 -28,6 +28,7 @@@
  #include <apt-pkg/pkgcache.h>
  #include <apt-pkg/cacheiterators.h>
  #include <apt-pkg/strutl.h>
 +#include <apt-pkg/install-progress.h>
  
  #include <stddef.h>
  #include <list>
@@@ -262,7 -261,7 +262,7 @@@ bool pkgPackageManager::CheckRConflicts
        if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false)
         continue;
  
-       if (EarlyRemove(D.ParentPkg()) == false)
+       if (EarlyRemove(D.ParentPkg(), &D) == false)
         return _error->Error("Reverse conflicts early remove for package '%s' failed",
                              Pkg.FullName().c_str());
     }
@@@ -314,18 -313,41 +314,41 @@@ bool pkgPackageManager::ConfigureAll(
     return true;
  }
                                                                        /*}}}*/
+ // PM::NonLoopingSmart - helper to avoid loops while calling Smart methods /*{{{*/
+ // -----------------------------------------------------------------------
+ /* ensures that a loop of the form A depends B, B depends A (and similar)
+    is not leading us down into infinite recursion segfault land */
+ bool pkgPackageManager::NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg,
+       pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop,
+       bool * const Bad, bool * const Changed)
+ {
+    if (PkgLoop == false)
+       List->Flag(Pkg,pkgOrderList::Loop);
+    bool success = false;
+    switch(action)
+    {
+       case UNPACK_IMMEDIATE: success = SmartUnPack(DepPkg, true, Depth + 1); break;
+       case UNPACK: success = SmartUnPack(DepPkg, false, Depth + 1); break;
+       case CONFIGURE: success = SmartConfigure(DepPkg, Depth + 1); break;
+    }
+    if (PkgLoop == false)
+       List->RmFlag(Pkg,pkgOrderList::Loop);
+    if (success == false)
+       return false;
+    if (Bad != NULL)
+       *Bad = false;
+    if (Changed != NULL && List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
+       *Changed = true;
+    return true;
+ }
+                                                                       /*}}}*/
  // PM::SmartConfigure - Perform immediate configuration of the pkg    /*{{{*/
  // ---------------------------------------------------------------------
  /* This function tries to put the system in a state where Pkg can be configured.
-    This involves checking each of Pkg's dependanies and unpacking and 
-    configuring packages where needed. 
-    
-    Note on failure: This method can fail, without causing any problems. 
-    This can happen when using Immediate-Configure-All, SmartUnPack may call
-    SmartConfigure, it may fail because of a complex dependency situation, but
-    a error will only be reported if ConfigureAll fails. This is why some of the
-    messages this function reports on failure (return false;) as just warnings
-    only shown when debuging*/
+    This involves checking each of Pkg's dependencies and unpacking and
+    configuring packages where needed. */
  bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
  {
     // If this is true, only check and correct and dependencies without the Loop flag
     }
  
     VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
-       
-    /* Because of the ordered list, most dependencies should be unpacked, 
-       however if there is a loop (A depends on B, B depends on A) this will not 
+    /* Because of the ordered list, most dependencies should be unpacked,
+       however if there is a loop (A depends on B, B depends on A) this will not
        be the case, so check for dependencies before configuring. */
     bool Bad = false, Changed = false;
     const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
                  if (Debug)
                     std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl;
                  Bad = false;
-                 break;
               }
               else
               {
                  if (Debug)
                     clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl;
-                 if (PkgLoop == false)
-                    List->Flag(Pkg,pkgOrderList::Loop);
-                 if (SmartUnPack(DepPkg, true, Depth + 1) == true)
-                 {
-                    Bad = false;
-                    if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-                       Changed = true;
-                 }
-                 if (PkgLoop == false)
-                    List->RmFlag(Pkg,pkgOrderList::Loop);
-                 if (Bad == false)
-                    break;
+                 if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+                    return false;
               }
+              break;
            }
  
            if (Cur == End || Bad == false)
                    Bad = false;
                    break;
                  }
-                 /* Check for a loop to prevent one forming
-                      If A depends on B and B depends on A, SmartConfigure will
-                      just hop between them if this is not checked. Dont remove the
-                      loop flag after finishing however as loop is already set.
-                      This means that there is another SmartConfigure call for this
-                      package and it will remove the loop flag */
-                 if (PkgLoop == false)
-                    List->Flag(Pkg,pkgOrderList::Loop);
-                 if (SmartConfigure(DepPkg, Depth + 1) == true)
-                 {
-                    Bad = false;
-                    if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-                       Changed = true;
-                 }
-                 if (PkgLoop == false)
-                   List->RmFlag(Pkg,pkgOrderList::Loop);
-                 // If SmartConfigure was succesfull, Bad is false, so break
-                 if (Bad == false)
-                    break;
+                 if (Debug)
+                    std::clog << OutputInDepth(Depth) << "Configure already unpacked " << DepPkg << std::endl;
+                 if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+                    return false;
+                 break;
               }
               else if (List->IsFlag(DepPkg,pkgOrderList::Configured))
               {
        if (i++ > max_loops)
           return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (2) for %s, aborting", Pkg.FullName().c_str());
     } while (Changed == true);
-    
-    if (Bad) {
-       if (Debug)
-          _error->Warning(_("Could not configure '%s'. "),Pkg.FullName().c_str());
-       return false;
-    }
-    
+    if (Bad == true)
+       return _error->Error(_("Could not configure '%s'. "),Pkg.FullName().c_str());
     if (PkgLoop) return true;
  
     static std::string const conf = _config->Find("PackageManager::Configure","all");
     static bool const ConfigurePkgs = (conf == "all" || conf == "smart");
  
-    if (List->IsFlag(Pkg,pkgOrderList::Configured)) 
+    if (List->IsFlag(Pkg,pkgOrderList::Configured))
        return _error->Error("Internal configure error on '%s'.", Pkg.FullName().c_str());
  
     if (ConfigurePkgs == true && Configure(Pkg) == false)
             Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
              (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
            continue;
-        SmartConfigure(P, (Depth +1));
+        if (SmartConfigure(P, (Depth +1)) == false)
+           return false;
        }
  
     // Sanity Check
  // ---------------------------------------------------------------------
  /* This is called to deal with conflicts arising from unpacking */
  bool pkgPackageManager::EarlyRemove(PkgIterator Pkg)
+ {
+    return EarlyRemove(Pkg, NULL);
+ }
+ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep)
  {
     if (List->IsNow(Pkg) == false)
        return true;
-        
     // Already removed it
     if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
        return true;
-    
     // Woops, it will not be re-installed!
     if (List->IsFlag(Pkg,pkgOrderList::InList) == false)
        return false;
  
+    // these breaks on M-A:same packages can be dealt with. They 'loop' by design
+    if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks && Dep->IsMultiArchImplicit() == true)
+       return true;
     // Essential packages get special treatment
     bool IsEssential = false;
     if ((Pkg->Flags & pkgCache::Flag::Essential) != 0 ||
         (Pkg->Flags & pkgCache::Flag::Important) != 0)
        IsEssential = true;
  
-    /* Check for packages that are the dependents of essential packages and 
+    /* Check for packages that are the dependents of essential packages and
        promote them too */
     if (Pkg->CurrentVer != 0)
     {
-       for (DepIterator D = Pkg.RevDependsList(); D.end() == false &&
+       for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false &&
           IsEssential == false; ++D)
         if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
            if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0 ||
                                "but if you really want to do it, activate the "
                                "APT::Force-LoopBreak option."),Pkg.FullName().c_str());
     }
-    
+    // dpkg will auto-deconfigure it, no need for the big remove hammer
+    else if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks)
+       return true;
     bool Res = SmartRemove(Pkg);
     if (Cache[Pkg].Delete() == false)
        List->Flag(Pkg,pkgOrderList::Removed,pkgOrderList::States);
-    
     return Res;
  }
                                                                        /*}}}*/
@@@ -630,13 -638,14 +639,14 @@@ bool pkgPackageManager::SmartUnPack(Pkg
  
     VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
  
-    /* PreUnpack Checks: This loop checks and attempts to rectify and problems that would prevent the package being unpacked.
+    /* PreUnpack Checks: This loop checks and attempts to rectify any problems that would prevent the package being unpacked.
        It addresses: PreDepends, Conflicts, Obsoletes and Breaks (DpkgBreaks). Any resolutions that do not require it should
        avoid configuration (calling SmartUnpack with Immediate=true), this is because when unpacking some packages with
-       complex dependency structures, trying to configure some packages while breaking the loops can complicate things .
+       complex dependency structures, trying to configure some packages while breaking the loops can complicate things.
        This will be either dealt with if the package is configured as a dependency of Pkg (if and when Pkg is configured),
        or by the ConfigureAll call at the end of the for loop in OrderInstall. */
-    bool Changed = false;
+    bool SomethingBad = false, Changed = false;
+    bool couldBeTemporaryRemoved = Depth != 0 && List->IsFlag(Pkg,pkgOrderList::Removed) == false;
     const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
     unsigned int i = 0;
     do 
               for (Version **I = VList; *I != 0; ++I)
               {
                  VerIterator Ver(Cache,*I);
-                 PkgIterator Pkg = Ver.ParentPkg();
+                 PkgIterator DepPkg = Ver.ParentPkg();
  
                  // Not the install version
-                 if (Cache[Pkg].InstallVer != *I ||
-                     (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
+                 if (Cache[DepPkg].InstallVer != *I ||
+                     (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing))
                     continue;
  
-                 if (List->IsFlag(Pkg,pkgOrderList::Configured))
+                 if (List->IsFlag(DepPkg,pkgOrderList::Configured))
                  {
                     Bad = false;
                     break;
                  }
  
                  // check if it needs unpack or if if configure is enough
-                 if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false)
+                 if (List->IsFlag(DepPkg,pkgOrderList::UnPacked) == false)
                  {
                     if (Debug)
-                       clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << Pkg.FullName() << endl;
-                    // SmartUnpack with the ImmediateFlag to ensure its really ready
-                    if (SmartUnPack(Pkg, true, Depth + 1) == true)
-                    {
-                       Bad = false;
-                       if (List->IsFlag(Pkg,pkgOrderList::Loop) == false)
-                          Changed = true;
-                       break;
-                    }
+                       clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << DepPkg.FullName() << endl;
+                    if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+                       return false;
                  }
                  else
                  {
                     if (Debug)
-                       clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << Pkg.FullName() << endl;
-                    if (SmartConfigure(Pkg, Depth + 1) == true)
-                    {
-                       Bad = false;
-                       if (List->IsFlag(Pkg,pkgOrderList::Loop) == false)
-                          Changed = true;
-                       break;
-                    }
+                       clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << DepPkg.FullName() << endl;
+                    if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+                       return false;
                  }
+                 break;
               }
            }
  
            if (Bad == true)
-           {
-              if (Start == End)
-                 return _error->Error("Couldn't configure pre-depend %s for %s, "
-                                       "probably a dependency cycle.",
-                                       End.TargetPkg().FullName().c_str(),Pkg.FullName().c_str());
-           }
-           else
-              continue;
+              SomethingBad = true;
         }
         else if (End->Type == pkgCache::Dep::Conflicts ||
-                 End->Type == pkgCache::Dep::Obsoletes)
+                 End->Type == pkgCache::Dep::Obsoletes ||
+                 End->Type == pkgCache::Dep::DpkgBreaks)
         {
-           /* Look for conflicts. Two packages that are both in the install
-              state cannot conflict so we don't check.. */
            SPtrArray<Version *> VList = End.AllTargets();
-           for (Version **I = VList; *I != 0; I++)
+           for (Version **I = VList; *I != 0; ++I)
            {
               VerIterator Ver(Cache,*I);
               PkgIterator ConflictPkg = Ver.ParentPkg();
-              VerIterator InstallVer(Cache,Cache[ConflictPkg].InstallVer);
+              if (ConflictPkg.CurrentVer() != Ver)
+              {
+                 if (Debug)
+                    std::clog << OutputInDepth(Depth) << "Ignore not-installed version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl;
+                 continue;
+              }
  
-              // See if the current version is conflicting
-              if (ConflictPkg.CurrentVer() == Ver && List->IsNow(ConflictPkg))
+              if (List->IsNow(ConflictPkg) == false)
               {
                  if (Debug)
-                    clog << OutputInDepth(Depth) << Pkg.FullName() << " conflicts with " << ConflictPkg.FullName() << endl;
-                 /* If a loop is not present or has not yet been detected, attempt to unpack packages
-                    to resolve this conflict. If there is a loop present, remove packages to resolve this conflict */
-                 if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false)
-                 {
-                    if (Cache[ConflictPkg].Keep() == 0 && Cache[ConflictPkg].InstallVer != 0)
-                    {
-                       if (Debug)
-                          clog << OutputInDepth(Depth) << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to prevent conflict" << endl;
-                       List->Flag(Pkg,pkgOrderList::Loop);
-                       if (SmartUnPack(ConflictPkg,false, Depth + 1) == true)
-                          if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false)
-                             Changed = true;
-                       // Remove loop to allow it to be used later if needed
-                       List->RmFlag(Pkg,pkgOrderList::Loop);
-                    }
-                    else if (EarlyRemove(ConflictPkg) == false)
-                       return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str());
-                 }
-                 else if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == false)
+                    std::clog << OutputInDepth(Depth) << "Ignore already dealt-with version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl;
+                 continue;
+              }
+              if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true)
+              {
+                 if (Debug)
+                    clog << OutputInDepth(Depth) << "Ignoring " << End << " as " << ConflictPkg.FullName() << "was temporarily removed" << endl;
+                 continue;
+              }
+              if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) && PkgLoop)
+              {
+                 if (End->Type == pkgCache::Dep::DpkgBreaks && End.IsMultiArchImplicit() == true)
                  {
                     if (Debug)
-                       clog << OutputInDepth(Depth) << "Because of conficts knot, removing " << ConflictPkg.FullName() << " to conflict violation" << endl;
-                    if (EarlyRemove(ConflictPkg) == false)
-                       return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str());
+                       clog << OutputInDepth(Depth) << "Because dependency is MultiArchImplicit we ignored looping on: " << ConflictPkg << endl;
+                    continue;
                  }
-              }
-           }
-        }
-        else if (End->Type == pkgCache::Dep::DpkgBreaks)
-        {
-           SPtrArray<Version *> VList = End.AllTargets();
-           for (Version **I = VList; *I != 0; ++I)
-           {
-              VerIterator Ver(Cache,*I);
-              PkgIterator BrokenPkg = Ver.ParentPkg();
-              if (BrokenPkg.CurrentVer() != Ver)
-              {
                  if (Debug)
-                    std::clog << OutputInDepth(Depth) << "  Ignore not-installed version " << Ver.VerStr() << " of " << Pkg.FullName() << " for " << End << std::endl;
+                 {
+                    if (End->Type == pkgCache::Dep::DpkgBreaks)
+                       clog << OutputInDepth(Depth) << "Because of breaks knot, deconfigure " << ConflictPkg.FullName() << " temporarily" << endl;
+                    else
+                       clog << OutputInDepth(Depth) << "Because of conflict knot, removing " << ConflictPkg.FullName() << " temporarily" << endl;
+                 }
+                 if (EarlyRemove(ConflictPkg, &End) == false)
+                    return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str());
+                 SomethingBad = true;
                  continue;
               }
  
-              // Check if it needs to be unpacked
-              if (List->IsFlag(BrokenPkg,pkgOrderList::InList) && Cache[BrokenPkg].Delete() == false &&
-                  List->IsNow(BrokenPkg))
+              if (Cache[ConflictPkg].Delete() == false)
               {
-                 if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) && PkgLoop)
+                 if (Debug)
                  {
-                    // This dependency has already been dealt with by another SmartUnPack on Pkg
-                    break;
+                    clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to avoid " << End;
+                    if (PkgLoop == true)
+                       clog << " (Looping)";
+                    clog << std::endl;
                  }
-                 else
+                 // we would like to avoid temporary removals and all that at best via a simple unpack
+                 _error->PushToStack();
+                 if (NonLoopingSmart(UNPACK, Pkg, ConflictPkg, Depth, PkgLoop, NULL, &Changed) == false)
                  {
-                    // Found a break, so see if we can unpack the package to avoid it
-                    // but do not set loop if another SmartUnPack already deals with it
-                    // Also, avoid it if the package we would unpack pre-depends on this one
-                    VerIterator InstallVer(Cache,Cache[BrokenPkg].InstallVer);
-                    bool circle = false;
-                    for (pkgCache::DepIterator D = InstallVer.DependsList(); D.end() == false; ++D)
+                    // but if it fails ignore this failure and look for alternative ways of solving
+                    if (Debug)
+                    {
+                       clog << OutputInDepth(Depth) << "Avoidance unpack of " << ConflictPkg.FullName() << " failed for " << End << std::endl;
+                       _error->DumpErrors(std::clog);
+                    }
+                    _error->RevertToStack();
+                    // ignorance can only happen if a) one of the offenders is already gone
+                    if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true)
                     {
-                       if (D->Type != pkgCache::Dep::PreDepends)
-                          continue;
-                       SPtrArray<Version *> VL = D.AllTargets();
-                       for (Version **I = VL; *I != 0; ++I)
-                       {
-                          VerIterator V(Cache,*I);
-                          PkgIterator P = V.ParentPkg();
-                          // we are checking for installation as an easy 'protection' against or-groups and (unchosen) providers
-                          if (P != Pkg || (P.CurrentVer() != V && Cache[P].InstallVer != V))
-                             continue;
-                          circle = true;
-                          break;
-                       }
-                       if (circle == true)
-                          break;
+                       if (Debug)
+                          clog << OutputInDepth(Depth) << "But " << ConflictPkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl;
                     }
-                    if (circle == true)
+                    else if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
                     {
                        if (Debug)
-                          clog << OutputInDepth(Depth) << "  Avoiding " << End << " avoided as " << BrokenPkg.FullName() << " has a pre-depends on " << Pkg.FullName() << std::endl;
-                       continue;
+                          clog << OutputInDepth(Depth) << "But " << Pkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl;
                     }
+                    // or b) we can make one go (removal or dpkg auto-deconfigure)
                     else
                     {
                        if (Debug)
-                       {
-                          clog << OutputInDepth(Depth) << "  Unpacking " << BrokenPkg.FullName() << " to avoid " << End;
-                          if (PkgLoop == true)
-                             clog << " (Looping)";
-                          clog << std::endl;
-                       }
-                       if (PkgLoop == false)
-                          List->Flag(Pkg,pkgOrderList::Loop);
-                       if (SmartUnPack(BrokenPkg, false, Depth + 1) == true)
-                       {
-                          if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) == false)
-                             Changed = true;
-                       }
-                       if (PkgLoop == false)
-                          List->RmFlag(Pkg,pkgOrderList::Loop);
+                          clog << OutputInDepth(Depth) << "So temprorary remove/deconfigure " << ConflictPkg.FullName() << " to satisfy " << End << endl;
+                       if (EarlyRemove(ConflictPkg, &End) == false)
+                          return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str());
                     }
                  }
+                 else
+                    _error->MergeWithStack();
               }
-              // Check if a package needs to be removed
-              else if (Cache[BrokenPkg].Delete() == true && List->IsFlag(BrokenPkg,pkgOrderList::Configured) == false)
+              else
               {
                  if (Debug)
-                    clog << OutputInDepth(Depth) << "  Removing " << BrokenPkg.FullName() << " to avoid " << End << endl;
-                 SmartRemove(BrokenPkg);
+                    clog << OutputInDepth(Depth) << "Removing " << ConflictPkg.FullName() << " now to avoid " << End << endl;
+                 // no earlyremove() here as user has already agreed to the permanent removal
+                 if (SmartRemove(Pkg) == false)
+                    return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str());
               }
            }
         }
        if (i++ > max_loops)
           return _error->Error("Internal error: APT::pkgPackageManager::MaxLoopCount reached in SmartConfigure for %s, aborting", Pkg.FullName().c_str());
     } while (Changed == true);
-    
+    if (SomethingBad == true)
+       return _error->Error("Couldn't configure %s, probably a dependency cycle.", Pkg.FullName().c_str());
+    if (couldBeTemporaryRemoved == true && List->IsFlag(Pkg,pkgOrderList::Removed) == true)
+    {
+       if (Debug)
+        std::clog << OutputInDepth(Depth) << "Prevent unpack as " << Pkg << " is currently temporarily removed" << std::endl;
+       return true;
+    }
     // Check for reverse conflicts.
     if (CheckRConflicts(Pkg,Pkg.RevDependsList(),
                   instVer.VerStr()) == false)
     if (Immediate == true) {
        // Perform immedate configuration of the package. 
           if (SmartConfigure(Pkg, Depth + 1) == false)
-             _error->Warning(_("Could not perform immediate configuration on '%s'. "
+             _error->Error(_("Could not perform immediate configuration on '%s'. "
                 "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.FullName().c_str(),2);
     }
     
diff --combined apt-pkg/packagemanager.h
index 8a51a455c0263e9f93c6acd390a11c266b492697,d72790b6ec01cf1c2ad229059d4f0a8c053320a9..558132ceb2a42eb7073db4f06195a014f31a5bbe
@@@ -44,11 -44,6 +44,11 @@@ class pkgDepCache
  class pkgSourceList;
  class pkgOrderList;
  class pkgRecords;
 +namespace APT {
 +   namespace Progress {
 +      class PackageManager;
 +   };
 +};
  
  
  class pkgPackageManager : protected pkgCache::Namespace
     
     // Install helpers
     bool ConfigureAll();
-    bool SmartConfigure(PkgIterator Pkg, int const Depth);
+    bool SmartConfigure(PkgIterator Pkg, int const Depth) APT_MUSTCHECK;
     //FIXME: merge on abi break
-    bool SmartUnPack(PkgIterator Pkg);
-    bool SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth);
-    bool SmartRemove(PkgIterator Pkg);
-    bool EarlyRemove(PkgIterator Pkg);  
-    
+    bool SmartUnPack(PkgIterator Pkg) APT_MUSTCHECK;
+    bool SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth) APT_MUSTCHECK;
+    bool SmartRemove(PkgIterator Pkg) APT_MUSTCHECK;
+    bool EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep) APT_MUSTCHECK;
+    APT_DEPRECATED bool EarlyRemove(PkgIterator Pkg) APT_MUSTCHECK;
     // The Actual installation implementation
     virtual bool Install(PkgIterator /*Pkg*/,std::string /*File*/) {return false;};
     virtual bool Configure(PkgIterator /*Pkg*/) {return false;};
  
     pkgPackageManager(pkgDepCache *Cache);
     virtual ~pkgPackageManager();
+    private:
+    enum APT_HIDDEN SmartAction { UNPACK_IMMEDIATE, UNPACK, CONFIGURE };
+    APT_HIDDEN bool NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg,
+       pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop,
+       bool * const Bad, bool * const Changed) APT_MUSTCHECK;
  };
  
  #endif
diff --combined cmdline/apt-get.cc
index 3388351d9b29cf9a435ec0c4068d55e4a0517ede,0f18b0e7ce72c3a69906d5730ee3ada42374fe07..1943a0fa76d6ae7455ca061529967e1d06c878da
@@@ -76,7 -76,6 +76,6 @@@
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
- #include <sys/ioctl.h>
  #include <sys/stat.h>
  #include <sys/statfs.h>
  #include <sys/statvfs.h>
@@@ -828,25 -827,23 +827,25 @@@ static bool DoSource(CommandLine &CmdL
         queued.insert(Last->Index().ArchiveURI(I->Path));
  
         // check if we have a file with that md5 sum already localy
 -       if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path)))  
 -       {
 -          FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly);
 -          MD5Summation sum;
 -          sum.AddFD(Fd.Fd(), Fd.Size());
 -          Fd.Close();
 -          if((string)sum.Result() == I->MD5Hash) 
 +       std::string localFile = flNotDir(I->Path);
 +       if (FileExists(localFile) == true)
 +          if(I->Hashes.VerifyFile(localFile) == true)
            {
               ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
 -                      flNotDir(I->Path).c_str());
 +                      localFile.c_str());
               continue;
            }
 +
 +       // see if we have a hash (Acquire::ForceHash is the only way to have none)
 +       if (I->Hashes.usable() == false && _config->FindB("APT::Get::AllowUnauthenticated",false) == false)
 +       {
 +          ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n",
 +                   localFile.c_str());
 +          continue;
         }
  
         new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
 -                      I->MD5Hash,I->Size,
 -                      Last->Index().SourceInfo(*Last,*I),Src);
 +                      I->Hashes, I->Size, Last->Index().SourceInfo(*Last,*I), Src);
        }
     }
     
@@@ -1055,30 -1052,7 +1054,30 @@@ static bool DoBuildDep(CommandLine &Cmd
     for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
     {
        string Src;
 -      pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,Cache);
 +      pkgSrcRecords::Parser *Last = 0;
 +
 +      // a unpacked debian source tree
 +      if (DirectoryExists(*I))
 +      {
 +         // FIXME: how can we make this more elegant?
 +         std::string TypeName = "debian/control File Source Index";
 +         pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(TypeName.c_str());
 +         if(Type != NULL)
 +            Last = Type->CreateSrcPkgParser(*I);
 +      }
 +      // if its a local file (e.g. .dsc) use this
 +      else if (FileExists(*I))
 +      {
 +         // see if we can get a parser for this pkgIndexFile type
 +         string TypeName = flExtension(*I) + " File Source Index";
 +         pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(TypeName.c_str());
 +         if(Type != NULL)
 +            Last = Type->CreateSrcPkgParser(*I);
 +      } else {
 +         // normal case, search the cache for the source file
 +         Last = FindSrc(*I,Recs,SrcRecs,Src,Cache);
 +      }
 +
        if (Last == 0)
         return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
              
        }
        else if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false)
            return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str());
 -   
 +
        // Also ensure that build-essential packages are present
        Configuration::Item const *Opts = _config->Tree("APT::Build-Essential");
        if (Opts)