Просмотр исходного кода

Merge branch 'debian/sid' into debian/experimental

Conflicts:
	apt-pkg/contrib/strutl.cc
	apt-pkg/deb/dpkgpm.cc
	configure.ac
	debian/changelog
	doc/po/apt-doc.pot
	po/apt-all.pot
	po/ar.po
	po/ast.po
	po/bg.po
	po/bs.po
	po/ca.po
	po/cs.po
	po/cy.po
	po/da.po
	po/de.po
	po/dz.po
	po/el.po
	po/es.po
	po/eu.po
	po/fi.po
	po/fr.po
	po/gl.po
	po/hu.po
	po/it.po
	po/ja.po
	po/km.po
	po/ko.po
	po/ku.po
	po/lt.po
	po/mr.po
	po/nb.po
	po/ne.po
	po/nl.po
	po/nn.po
	po/pl.po
	po/pt.po
	po/pt_BR.po
	po/ro.po
	po/ru.po
	po/sk.po
	po/sl.po
	po/sv.po
	po/th.po
	po/tl.po
	po/uk.po
	po/vi.po
	po/zh_CN.po
	po/zh_TW.po
	test/integration/framework
	test/integration/test-bug-602412-dequote-redirect
	test/integration/test-ubuntu-bug-346386-apt-get-update-paywall
	test/interactive-helper/aptwebserver.cc
	test/interactive-helper/makefile
Michael Vogt лет назад: 13
Родитель
Сommit
d7a4635391
100 измененных файлов с 4669 добавлено и 10663 удалено
  1. 0 6
      .bzr-builddeb/default.conf
  2. 37 0
      .gitignore
  3. 5 0
      .travis.yml
  4. 1 1
      Makefile
  5. 0 7325
      abicheck/abi-compliance-checker.pl
  6. 6 1
      abicheck/run_abi_test
  7. 3 0
      apt-inst/contrib/arfile.cc
  8. 0 1
      apt-inst/contrib/extracttar.cc
  9. 1 0
      apt-inst/makefile
  10. 53 8
      apt-pkg/acquire-item.cc
  11. 2 0
      apt-pkg/acquire-item.h
  12. 10 3
      apt-pkg/acquire-worker.cc
  13. 16 7
      apt-pkg/algorithms.cc
  14. 4 3
      apt-pkg/algorithms.h
  15. 2 2
      apt-pkg/aptconfiguration.cc
  16. 1 0
      apt-pkg/cacheiterators.h
  17. 0 1
      apt-pkg/cacheset.h
  18. 8 0
      apt-pkg/cdrom.cc
  19. 1 1
      apt-pkg/cdrom.h
  20. 2 1
      apt-pkg/contrib/cdromutl.cc
  21. 1 1
      apt-pkg/contrib/configuration.cc
  22. 6 4
      apt-pkg/contrib/error.cc
  23. 35 6
      apt-pkg/contrib/error.h
  24. 114 106
      apt-pkg/contrib/fileutl.cc
  25. 4 0
      apt-pkg/contrib/fileutl.h
  26. 1 1
      apt-pkg/contrib/gpgv.cc
  27. 12 3
      apt-pkg/contrib/gpgv.h
  28. 3 1
      apt-pkg/contrib/sha2.h
  29. 6 6
      apt-pkg/contrib/sha2_internal.cc
  30. 10 9
      apt-pkg/contrib/strutl.cc
  31. 24 86
      apt-pkg/deb/deblistparser.cc
  32. 22 2
      apt-pkg/deb/debmetaindex.cc
  33. 73 34
      apt-pkg/deb/dpkgpm.cc
  34. 3 1
      apt-pkg/deb/dpkgpm.h
  35. 75 15
      apt-pkg/depcache.cc
  36. 17 13
      apt-pkg/depcache.h
  37. 17 6
      apt-pkg/indexcopy.cc
  38. 2 8
      apt-pkg/indexcopy.h
  39. 6 11
      apt-pkg/indexrecords.cc
  40. 105 119
      apt-pkg/orderlist.cc
  41. 73 48
      apt-pkg/packagemanager.cc
  42. 12 0
      apt-pkg/pkgcache.cc
  43. 3 1
      apt-pkg/pkgcachegen.cc
  44. 18 7
      apt-pkg/policy.cc
  45. 1 1
      apt-pkg/tagfile.h
  46. 1 1
      apt-pkg/vendorlist.cc
  47. 1 0
      buildlib/apti18n.h.in
  48. 2 2
      buildlib/configure.mak
  49. 1 1
      buildlib/copy.mak
  50. 8 9
      buildlib/defaults.mak
  51. 2 2
      buildlib/library.mak
  52. 7 5
      buildlib/po4a_manpage.mak
  53. 6 1
      buildlib/podomain.mak
  54. 123 53
      cmdline/apt-cache.cc
  55. 22 12
      cmdline/apt-cdrom.cc
  56. 39 10
      cmdline/apt-get.cc
  57. 145 47
      cmdline/apt-key
  58. 2 2
      cmdline/apt-mark.cc
  59. 1 1
      cmdline/makefile
  60. 3 7
      configure.in
  61. 93 0
      debian/apt.auto-removal.sh
  62. 0 3
      debian/apt.conf.autoremove
  63. 1 0
      debian/apt.dirs
  64. 13 5
      debian/apt.postinst
  65. 235 10
      debian/changelog
  66. 7 7
      debian/control
  67. 6 0
      debian/gbp.conf
  68. 1 5
      debian/libapt-inst1.5.symbols
  69. 52 69
      debian/libapt-pkg4.13.symbols
  70. 27 19
      debian/rules
  71. 522 146
      doc/Doxyfile.in
  72. 8 0
      doc/apt-cdrom.8.xml
  73. 1 1
      doc/apt-verbatim.ent
  74. 11 6
      doc/apt.conf.5.xml
  75. 38 0
      doc/en/makefile
  76. 1 1
      doc/examples/configure-index
  77. 19 53
      doc/makefile
  78. 147 138
      doc/po/apt-doc.pot
  79. 179 180
      doc/po/de.po
  80. 161 162
      doc/po/es.po
  81. 168 169
      doc/po/fr.po
  82. 213 186
      doc/po/it.po
  83. 160 160
      doc/po/ja.po
  84. 153 153
      doc/po/pl.po
  85. 167 166
      doc/po/pt.po
  86. 153 153
      doc/po/pt_BR.po
  87. 5 1
      doc/sources.list.5.xml
  88. 2 1
      ftparchive/writer.cc
  89. 1 0
      methods/ftp.cc
  90. 8 9
      methods/gpgv.cc
  91. 27 28
      methods/http.cc
  92. 1 1
      methods/http.h
  93. 25 2
      methods/https.cc
  94. 1 1
      methods/makefile
  95. 3 0
      methods/mirror.cc
  96. 2 0
      methods/rsh.cc
  97. 7 1
      po/LINGUAS
  98. 445 409
      po/apt-all.pot
  99. 448 416
      po/ar.po
  100. 0 0
      po/ast.po

+ 0 - 6
.bzr-builddeb/default.conf

@@ -1,6 +0,0 @@
-[BUILDDEB]
-native = true
-
-[HOOKS]
-pre-export = ./prepare-release pre-export
-post-build = ./prepare-release post-build

+ 37 - 0
.gitignore

@@ -0,0 +1,37 @@
+# build artifacts
+/aclocal.m4
+/autom4te.cache/
+/build/
+/buildlib/config.guess
+/buildlib/config.sub
+/configure
+
+# copy of COPYING
+/debian/copyright
+
+# generated files in the process to build all
+# apt man pages and other documentation
+/doc/*/
+!/doc/examples/
+!/doc/po/
+!/doc/en/makefile
+
+# package building artifacts
+/debian/*.log
+/debian/*.substvars
+/debian/*.debhelper
+/debian/files
+/debian/apt/
+/debian/apt-doc/
+/debian/apt-utils/
+/debian/libapt-pkg*/
+/debian/libapt-inst*/
+/debian/libapt-pkg-dev/
+/debian/libapt-pkg-doc/
+/debian/apt-transport-https/
+
+# generated from *.in files
+/doc/examples/sources.list
+/debian/libapt-pkg*.install
+/debian/libapt-inst*.install
+/debian/libapt-pkg-dev.install

+ 5 - 0
.travis.yml

@@ -0,0 +1,5 @@
+language: cpp
+before_install:
+ - sudo apt-get update -q
+ - sudo apt-get install -q dpkg-dev debhelper libdb-dev gettext libcurl4-gnutls-dev zlib1g-dev libbz2-dev xsltproc docbook-xsl docbook-xml po4a autotools-dev autoconf automake doxygen debiandoc-sgml
+script: make && make test && test/integration/run-tests

+ 1 - 1
Makefile

@@ -19,7 +19,7 @@ all headers library clean veryclean binary program doc manpages debiandoc test u
 	$(MAKE) -C dselect $@
 	$(MAKE) -C doc $@
 	$(MAKE) -C po $@
-	$(MAKE) -C test $@
+	$(MAKE) -C test $@ 
 
 all headers library clean veryclean binary program doc manpages debiandoc test update-po: startup dirs
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 7325
abicheck/abi-compliance-checker.pl


+ 6 - 1
abicheck/run_abi_test

@@ -5,10 +5,15 @@ if [ ! -d ../build ]; then
 	exit 1
 fi
 
+if [ ! -x "$(which abi-compliance-checker 2>/dev/null )" ]; then
+	echo "Please install the 'abi-compliance-checker' package"
+	exit 1
+fi
+
 LIBPATH=$(find /usr/lib/ -type f  -name "libapt-*.so.*" -printf %p\\\\n)
 sed s#@installed_libapt@#$LIBPATH# apt_installed.xml.in > apt_installed.xml
 
 BUILDPATH=$(readlink -f ../build)
 sed s#@build_path@#$BUILDPATH# apt_build.xml.in > apt_build.xml
 
-perl abi-compliance-checker.pl -l apt -d1 apt_installed.xml -d2 apt_build.xml
+abi-compliance-checker -l apt -d1 apt_installed.xml -d2 apt_build.xml

+ 3 - 0
apt-inst/contrib/arfile.cc

@@ -106,7 +106,10 @@ bool ARArchive::LoadHeaders()
 	    return _error->Error(_("Invalid archive member header"));
 	 }
 	 if (File.Read(S,Len) == false)
+	 {
+	    delete Memb;
 	    return false;
+	 }
 	 S[Len] = 0;
 	 Memb->Name = S;
 	 Memb->Size -= Len;

+ 0 - 1
apt-inst/contrib/extracttar.cc

@@ -63,7 +63,6 @@ ExtractTar::ExtractTar(FileFd &Fd,unsigned long Max,string DecompressionProgram)
 
 {
    GZPid = -1;
-   InFd = -1;
    Eof = false;
 }
 									/*}}}*/

+ 1 - 0
apt-inst/makefile

@@ -18,6 +18,7 @@ MAJOR=1.5
 MINOR=0
 SLIBS=$(PTHREADLIB) -lapt-pkg
 APT_DOMAIN:=libapt-inst$(MAJOR)
+LIBRARYDEPENDS=$(LIB)/libapt-pkg.so
 
 # Source code for the contributed non-core things
 SOURCE = contrib/extracttar.cc contrib/arfile.cc

+ 53 - 8
apt-pkg/acquire-item.cc

@@ -1067,8 +1067,7 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,				/*{{{*/
       
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
-   struct stat Buf;
-   if (stat(Final.c_str(),&Buf) == 0)
+   if (RealFileExists(Final) == true)
    {
       // File was already in place.  It needs to be re-downloaded/verified
       // because Release might have changed, we do give it a differnt
@@ -1080,6 +1079,19 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,				/*{{{*/
    }
 
    QueueURI(Desc);
+}
+									/*}}}*/
+pkgAcqMetaSig::~pkgAcqMetaSig()						/*{{{*/
+{
+   // if the file was never queued undo file-changes done in the constructor
+   if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false &&
+	 LastGoodSig.empty() == false)
+   {
+      string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
+      if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
+	 Rename(LastGoodSig, Final);
+   }
+
 }
 									/*}}}*/
 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers	/*{{{*/
@@ -1300,7 +1312,14 @@ void pkgAcqMetaIndex::RetrievalDone(string Message)			/*{{{*/
       string FinalFile = _config->FindDir("Dir::State::lists");
       FinalFile += URItoFileName(RealURI);
       if (SigFile == DestFile)
+      {
 	 SigFile = FinalFile;
+	 // constructor of pkgAcqMetaClearSig moved it out of the way,
+	 // now move it back in on IMS hit for the 'old' file
+	 string const OldClearSig = DestFile + ".reverify";
+	 if (RealFileExists(OldClearSig) == true)
+	    Rename(OldClearSig, FinalFile);
+      }
       DestFile = FinalFile;
    }
    Complete = true;
@@ -1373,9 +1392,20 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
    {
       HashString ExpectedIndexHash;
       const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
+      bool compressedAvailable = false;
       if (Record == NULL)
       {
-	 if (verify == true && (*Target)->IsOptional() == false)
+	 if ((*Target)->IsOptional() == true)
+	 {
+	    std::vector<std::string> types = APT::Configuration::getCompressionTypes();
+	    for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+	       if (MetaIndexParser->Exists(string((*Target)->MetaKey).append(".").append(*t)) == true)
+	       {
+		  compressedAvailable = true;
+		  break;
+	       }
+	 }
+	 else if (verify == true)
 	 {
 	    Status = StatAuthError;
 	    strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
@@ -1404,7 +1434,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
 	 if ((*Target)->IsSubIndex() == true)
 	    new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
 				(*Target)->ShortDesc, ExpectedIndexHash);
-	 else if (transInRelease == false || MetaIndexParser->Exists((*Target)->MetaKey) == true)
+	 else if (transInRelease == false || Record != NULL || compressedAvailable == true)
 	 {
 	    if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
 		MetaIndexParser->Exists(string((*Target)->MetaKey).append(".diff/Index")) == true)
@@ -1526,7 +1556,7 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 	    VerifiedSigFile.append(".gpg");
 	 Rename(LastGoodSigFile, VerifiedSigFile);
 	 Status = StatTransientNetworkError;
-	 _error->Warning(_("A error occurred during the signature "
+	 _error->Warning(_("An error occurred during the signature "
 			   "verification. The repository is not updated "
 			   "and the previous index files will be used. "
 			   "GPG error: %s: %s\n"),
@@ -1588,14 +1618,25 @@ pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner,		/*{{{*/
 
    // keep the old InRelease around in case of transistent network errors
    string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
-   struct stat Buf;
-   if (stat(Final.c_str(),&Buf) == 0)
+   if (RealFileExists(Final) == true)
    {
       string const LastGoodSig = DestFile + ".reverify";
       Rename(Final,LastGoodSig);
    }
 }
 									/*}}}*/
+pkgAcqMetaClearSig::~pkgAcqMetaClearSig()				/*{{{*/
+{
+   // if the file was never queued undo file-changes done in the constructor
+   if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false)
+   {
+      string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
+      string const LastGoodSig = DestFile + ".reverify";
+      if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
+	 Rename(LastGoodSig, Final);
+   }
+}
+									/*}}}*/
 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers	/*{{{*/
 // ---------------------------------------------------------------------
 // FIXME: this can go away once the InRelease file is used widely
@@ -1606,7 +1647,11 @@ string pkgAcqMetaClearSig::Custom600Headers()
 
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) != 0)
-      return "\nIndex-File: true\nFail-Ignore: true\n";
+   {
+      Final = DestFile + ".reverify";
+      if (stat(Final.c_str(),&Buf) != 0)
+	 return "\nIndex-File: true\nFail-Ignore: true\n";
+   }
 
    return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }

+ 2 - 0
apt-pkg/acquire-item.h

@@ -774,6 +774,7 @@ class pkgAcqMetaSig : public pkgAcquire::Item
 		 std::string MetaIndexURI, std::string MetaIndexURIDesc, std::string MetaIndexShortDesc,
 		 const std::vector<struct IndexTarget*>* IndexTargets,
 		 indexRecords* MetaIndexParser);
+   virtual ~pkgAcqMetaSig();
 };
 									/*}}}*/
 /** \brief An item that is responsible for downloading the meta-index	{{{
@@ -904,6 +905,7 @@ public:
 		std::string const &MetaSigURI, std::string const &MetaSigURIDesc, std::string const &MetaSigShortDesc,
 		const std::vector<struct IndexTarget*>* IndexTargets,
 		indexRecords* MetaIndexParser);
+   virtual ~pkgAcqMetaClearSig();
 };
 									/*}}}*/
 /** \brief An item that is responsible for fetching a package file.	{{{

+ 10 - 3
apt-pkg/acquire-worker.cc

@@ -305,7 +305,15 @@ bool pkgAcquire::Worker::RunMessages()
 	    
 	    OwnerQ->ItemDone(Itm);
 	    unsigned long long const ServerSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
-	    if (TotalSize != 0 && ServerSize != TotalSize)
+            bool isHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
+                         StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
+            // Using the https method the server might return 200, but the
+            // If-Modified-Since condition is not satsified, libcurl will
+            // discard the download. In this case, however, TotalSize will be
+            // set to the actual size of the file, while ServerSize will be set
+            // to 0. Therefore, if the item is marked as a hit and the
+            // downloaded size (ServerSize) is 0, we ignore TotalSize.
+	    if (TotalSize != 0 && (!isHit || ServerSize != 0) && ServerSize != TotalSize)
 	       _error->Warning("Size of file %s is not what the server reported %s %llu",
 			       Owner->DestFile.c_str(), LookupTag(Message,"Size","0").c_str(),TotalSize);
 
@@ -332,8 +340,7 @@ bool pkgAcquire::Worker::RunMessages()
 	    // Log that we are done
 	    if (Log != 0)
 	    {
-	       if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true ||
-		   StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
+	       if (isHit)
 	       {
 		  /* Hide 'hits' for local only sources - we also manage to
 		     hide gets */

+ 16 - 7
apt-pkg/algorithms.cc

@@ -646,7 +646,10 @@ 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];
       }      
    }
 
@@ -840,8 +843,10 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    }
    while (Again == true);
 
-   if (Debug == true)
-      clog << "Starting" << endl;
+   if (Debug == true) {
+      clog << "Starting pkgProblemResolver with broken count: " 
+           << Cache.BrokenCount() << endl;
+   }
    
    MakeScores();
 
@@ -869,8 +874,10 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
          }
    }
 
-   if (Debug == true)
-      clog << "Starting 2" << endl;
+   if (Debug == true) {
+      clog << "Starting 2 pkgProblemResolver with broken count: " 
+           << Cache.BrokenCount() << endl;
+   }
 
    /* Now consider all broken packages. For each broken package we either
       remove the package or fix it's problem. We do this once, it should
@@ -1435,9 +1442,11 @@ bool pkgProblemResolver::ResolveByKeepInternal()
    return true;
 }
 									/*}}}*/
-// ProblemResolver::InstallProtect - Install all protected packages	/*{{{*/
+// ProblemResolver::InstallProtect - deprecated cpu-eating no-op	/*{{{*/
 // ---------------------------------------------------------------------
-/* This is used to make sure protected packages are installed */
+/* Actions issued with FromUser bit set are protected from further
+   modification (expect by other calls with FromUser set) nowadays , so we
+   don't need to reissue actions here, they are already set in stone. */
 void pkgProblemResolver::InstallProtect()
 {
    pkgDepCache::ActionGroup group(Cache);

+ 4 - 3
apt-pkg/algorithms.h

@@ -36,6 +36,8 @@
 
 #include <iostream>
 
+#include <apt-pkg/macros.h>
+
 #ifndef APT_8_CLEANER_HEADERS
 #include <apt-pkg/acquire.h>
 using std::ostream;
@@ -132,9 +134,8 @@ class pkgProblemResolver						/*{{{*/
    // Try to resolve problems only by using keep
    bool ResolveByKeep();
 
-   // Install all protected packages   
-   void InstallProtect();   
-   
+   __deprecated void InstallProtect();
+
    pkgProblemResolver(pkgDepCache *Cache);
    ~pkgProblemResolver();
 };

+ 2 - 2
apt-pkg/aptconfiguration.cc

@@ -388,12 +388,12 @@ std::vector<std::string> const Configuration::getArchitectures(bool const &Cache
 		if (dpkgMultiArch == 0) {
 			close(external[0]);
 			std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory");
-			if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0)
-				_error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir.c_str());
 			int const nullfd = open("/dev/null", O_RDONLY);
 			dup2(nullfd, STDIN_FILENO);
 			dup2(external[1], STDOUT_FILENO);
 			dup2(nullfd, STDERR_FILENO);
+			if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0)
+				_error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir.c_str());
 			execvp(Args[0], (char**) &Args[0]);
 			_error->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
 			_exit(100);

+ 1 - 0
apt-pkg/cacheiterators.h

@@ -220,6 +220,7 @@ class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
 	inline VerFileIterator FileList() const;
 	bool Downloadable() const;
 	inline const char *PriorityType() const {return Owner->Priority(S->Priority);};
+	const char *MultiArchType() const;
 	std::string RelStr() const;
 
 	bool Automatic() const;

+ 0 - 1
apt-pkg/cacheset.h

@@ -11,7 +11,6 @@
 // Include Files							/*{{{*/
 #include <iostream>
 #include <fstream>
-#include <list>
 #include <map>
 #include <set>
 #include <list>

+ 8 - 0
apt-pkg/cdrom.cc

@@ -829,6 +829,14 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
       log->Update(msg.str());
       log->Update(_("Copying package lists..."), STEP_COPY);
    }
+
+   // check for existence and possibly create state directory for copying
+   string const listDir = _config->FindDir("Dir::State::lists");
+   string const partialListDir = listDir + "partial/";
+   if (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false &&
+       CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false)
+      return _error->Errno("cdrom", _("List directory %spartial is missing."), listDir.c_str());
+
    // take care of the signatures and copy them if they are ok
    // (we do this before PackageCopy as it modifies "List" and "SourceList")
    SigVerify SignVerify;

+ 1 - 1
apt-pkg/cdrom.h

@@ -18,7 +18,7 @@ class pkgCdromStatus							/*{{{*/
    int totalSteps;
 
  public:
-   pkgCdromStatus() {};
+   pkgCdromStatus() : totalSteps(0) {};
    virtual ~pkgCdromStatus() {};
 
    // total steps

+ 2 - 1
apt-pkg/contrib/cdromutl.cc

@@ -122,8 +122,9 @@ bool MountCdrom(string Path, string DeviceName)
    if (Child == 0)
    {
       // Make all the fds /dev/null
+      int null_fd = open("/dev/null",O_RDWR);
       for (int I = 0; I != 3; I++)
-	 dup2(open("/dev/null",O_RDWR),I);
+	 dup2(null_fd, I);
       
       if (_config->Exists("Acquire::cdrom::"+Path+"::Mount") == true)
       {

+ 1 - 1
apt-pkg/contrib/configuration.cc

@@ -823,7 +823,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
 	    // Go down a level
 	    if (TermChar == '{')
 	    {
-	       if (StackPos <= 100)
+	       if (StackPos < sizeof(Stack)/sizeof(std::string))
 		  Stack[StackPos++] = ParentTag;
 	       
 	       /* Make sectional tags incorperate the section into the

+ 6 - 4
apt-pkg/contrib/error.cc

@@ -67,9 +67,10 @@ bool GlobalError::NAME (const char *Function, const char *Description,...) { \
 	int const errsv = errno; \
 	while (true) { \
 		va_start(args,Description); \
-		if (InsertErrno(TYPE, Function, Description, args, errsv, msgSize) == false) \
-			break; \
+		bool const retry = InsertErrno(TYPE, Function, Description, args, errsv, msgSize); \
 		va_end(args); \
+		if (retry == false) \
+			break; \
 	} \
 	return false; \
 }
@@ -88,9 +89,10 @@ bool GlobalError::InsertErrno(MsgType const &type, const char *Function,
 	int const errsv = errno;
 	while (true) {
 		va_start(args,Description);
-		if (InsertErrno(type, Function, Description, args, errsv, msgSize) == false)
-			break;
+		bool const retry = InsertErrno(type, Function, Description, args, errsv, msgSize);
 		va_end(args);
+		if (retry == false)
+		   break;
 	}
 	return false;
 }

+ 35 - 6
apt-pkg/contrib/error.h

@@ -123,6 +123,25 @@ public:									/*{{{*/
 	bool InsertErrno(MsgType const &type, const char* Function,
 			 const char* Description,...) __like_printf(4) __cold;
 
+	/** \brief adds an errno message with the given type
+	 *
+	 * args needs to be initialized with va_start and terminated
+	 * with va_end by the caller. msgSize is also an out-parameter
+	 * in case the msgSize was not enough to store the complete message.
+	 *
+	 * \param type of the error message
+	 * \param Function which failed
+	 * \param Description is the format string for args
+	 * \param args list from a printf-like function
+	 * \param errsv is the errno the error is for
+	 * \param msgSize is the size of the char[] used to store message
+	 * \return true if the message was added, false if not - the caller
+	 * should call this method again in that case
+	 */
+	bool InsertErrno(MsgType type, const char* Function,
+			 const char* Description, va_list &args,
+			 int const errsv, size_t &msgSize);
+
 	/** \brief add an fatal error message to the list
 	 *
 	 *  Most of the stuff we consider as "error" is also "fatal" for
@@ -185,6 +204,22 @@ public:									/*{{{*/
 	 */
 	bool Insert(MsgType const &type, const char* Description,...) __like_printf(3) __cold;
 
+	/** \brief adds an error message with the given type
+	 *
+	 * args needs to be initialized with va_start and terminated
+	 * with va_end by the caller. msgSize is also an out-parameter
+	 * in case the msgSize was not enough to store the complete message.
+	 *
+	 * \param type of the error message
+	 * \param Description is the format string for args
+	 * \param args list from a printf-like function
+	 * \param msgSize is the size of the char[] used to store message
+	 * \return true if the message was added, false if not - the caller
+	 * should call this method again in that case
+	 */
+	bool Insert(MsgType type, const char* Description,
+			 va_list &args, size_t &msgSize) __cold;
+
 	/** \brief is an error in the list?
 	 *
 	 *  \return \b true if an error is included in the list, \b false otherwise
@@ -305,12 +340,6 @@ private:								/*{{{*/
 	};
 
 	std::list<MsgStack> Stacks;
-
-	bool InsertErrno(MsgType type, const char* Function,
-			 const char* Description, va_list &args,
-			 int const errsv, size_t &msgSize);
-	bool Insert(MsgType type, const char* Description,
-			 va_list &args, size_t &msgSize);
 									/*}}}*/
 };
 									/*}}}*/

+ 114 - 106
apt-pkg/contrib/fileutl.cc

@@ -186,7 +186,8 @@ bool RunScripts(const char *Cnf)
 /* The caller is expected to set things so that failure causes erasure */
 bool CopyFile(FileFd &From,FileFd &To)
 {
-   if (From.IsOpen() == false || To.IsOpen() == false)
+   if (From.IsOpen() == false || To.IsOpen() == false ||
+	 From.Failed() == true || To.Failed() == true)
       return false;
    
    // Buffered copy between fds
@@ -245,17 +246,20 @@ int GetLock(string File,bool Errors)
    fl.l_len = 0;
    if (fcntl(FD,F_SETLK,&fl) == -1)
    {
+      // always close to not leak resources
+      int Tmp = errno;
+      close(FD);
+      errno = Tmp;
+
       if (errno == ENOLCK)
       {
 	 _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str());
 	 return dup(0);       // Need something for the caller to close	 
-      }      
+      }
+  
       if (Errors == true)
 	 _error->Errno("open",_("Could not get lock %s"),File.c_str());
       
-      int Tmp = errno;
-      close(FD);
-      errno = Tmp;
       return -1;
    }
 
@@ -883,7 +887,7 @@ bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress,
       return Open(FileName, ReadOnly, Gzip, Perms);
 
    if (Compress == Auto && (Mode & WriteOnly) == WriteOnly)
-      return _error->Error("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
+      return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
 
    std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
    std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
@@ -936,17 +940,17 @@ bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress,
       case Auto:
       case Extension:
 	 // Unreachable
-	 return _error->Error("Opening File %s in None, Auto or Extension should be already handled?!?", FileName.c_str());
+	 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName.c_str());
       }
       for (; compressor != compressors.end(); ++compressor)
 	 if (compressor->Name == name)
 	    break;
       if (compressor == compressors.end())
-	 return _error->Error("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
+	 return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
    }
 
    if (compressor == compressors.end())
-      return _error->Error("Can't find a match for specified compressor mode for file %s", FileName.c_str());
+      return FileFdError("Can't find a match for specified compressor mode for file %s", FileName.c_str());
    return Open(FileName, Mode, *compressor, Perms);
 }
 bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const Perms)
@@ -955,9 +959,9 @@ bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Co
    Flags = AutoClose;
 
    if ((Mode & WriteOnly) != WriteOnly && (Mode & (Atomic | Create | Empty | Exclusive)) != 0)
-      return _error->Error("ReadOnly mode for %s doesn't accept additional flags!", FileName.c_str());
+      return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName.c_str());
    if ((Mode & ReadWrite) == 0)
-      return _error->Error("No openmode provided in FileFd::Open for %s", FileName.c_str());
+      return FileFdError("No openmode provided in FileFd::Open for %s", FileName.c_str());
 
    if ((Mode & Atomic) == Atomic)
    {
@@ -1003,7 +1007,7 @@ bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Co
 	 close (iFd);
 	 iFd = -1;
       }
-      return _error->Errno("open",_("Could not open file %s"), FileName.c_str());
+      return FileFdErrno("open",_("Could not open file %s"), FileName.c_str());
    }
 
    SetCloseExec(iFd,true);
@@ -1032,14 +1036,19 @@ bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compre
    case Xz: name = "xz"; break;
    case Auto:
    case Extension:
-      return _error->Error("Opening Fd %d in Auto or Extension compression mode is not supported", Fd);
+      if (AutoClose == true && Fd != -1)
+	 close(Fd);
+      return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd);
    }
    for (; compressor != compressors.end(); ++compressor)
       if (compressor->Name == name)
 	 break;
    if (compressor == compressors.end())
-      return _error->Error("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
-
+   {
+      if (AutoClose == true && Fd != -1)
+	 close(Fd);
+      return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
+   }
    return OpenDescriptor(Fd, Mode, *compressor, AutoClose);
 }
 bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration::Compressor const &compressor, bool AutoClose)
@@ -1061,11 +1070,21 @@ bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration:
    else
       iFd = Fd;
    this->FileName = "";
-   if (OpenInternDescriptor(Mode, compressor) == false)
+   if (Fd == -1 || OpenInternDescriptor(Mode, compressor) == false)
    {
-      if (AutoClose)
+      if (iFd != -1 && (
+#ifdef HAVE_ZLIB
+	compressor.Name == "gzip" ||
+#endif
+#ifdef HAVE_BZ2
+	compressor.Name == "bzip2" ||
+#endif
+	AutoClose == true))
+      {
 	 close (iFd);
-      return _error->Errno("gzdopen",_("Could not open file descriptor %d"), Fd);
+	 iFd = -1;
+      }
+      return FileFdError(_("Could not open file descriptor %d"), Fd);
    }
    return true;
 }
@@ -1127,10 +1146,7 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
       ExecWait(d->compressor_pid, "FileFdCompressor", true);
 
    if ((Mode & ReadWrite) == ReadWrite)
-   {
-      Flags |= Fail;
-      return _error->Error("ReadWrite mode is not supported for file %s", FileName.c_str());
-   }
+      return FileFdError("ReadWrite mode is not supported for file %s", FileName.c_str());
 
    bool const Comp = (Mode & WriteOnly) == WriteOnly;
    if (Comp == false)
@@ -1153,10 +1169,7 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
    // Create a data pipe
    int Pipe[2] = {-1,-1};
    if (pipe(Pipe) != 0)
-   {
-      Flags |= Fail;
-      return _error->Errno("pipe",_("Failed to create subprocess IPC"));
-   }
+      return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
    for (int J = 0; J != 2; J++)
       SetCloseExec(Pipe[J],true);
 
@@ -1230,11 +1243,9 @@ FileFd::~FileFd()
 {
    Close();
    if (d != NULL)
-   {
       d->CloseDown(FileName);
-      delete d;
-      d = NULL;
-   }
+   delete d;
+   d = NULL;
 }
 									/*}}}*/
 // FileFd::Read - Read a bit of the file				/*{{{*/
@@ -1266,14 +1277,13 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
       {
 	 if (errno == EINTR)
 	    continue;
-	 Flags |= Fail;
 #ifdef HAVE_ZLIB
 	 if (d != NULL && d->gz != NULL)
 	 {
 	    int err;
 	    char const * const errmsg = gzerror(d->gz, &err);
 	    if (err != Z_ERRNO)
-	       return _error->Error("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
+	       return FileFdError("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
 	 }
 #endif
 #ifdef HAVE_BZ2
@@ -1282,10 +1292,10 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
 	    int err;
 	    char const * const errmsg = BZ2_bzerror(d->bz2, &err);
 	    if (err != BZ_IO_ERROR)
-	       return _error->Error("BZ2_bzread: %s (%d: %s)", _("Read error"), err, errmsg);
+	       return FileFdError("BZ2_bzread: %s (%d: %s)", _("Read error"), err, errmsg);
 	 }
 #endif
-	 return _error->Errno("read",_("Read error"));
+	 return FileFdErrno("read",_("Read error"));
       }
       
       To = (char *)To + Res;
@@ -1306,9 +1316,8 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
       Flags |= HitEof;
       return true;
    }
-   
-   Flags |= Fail;
-   return _error->Error(_("read, still have %llu to read but none left"), Size);
+
+   return FileFdError(_("read, still have %llu to read but none left"), Size);
 }
 									/*}}}*/
 // FileFd::ReadLine - Read a complete line from the file		/*{{{*/
@@ -1364,14 +1373,13 @@ bool FileFd::Write(const void *From,unsigned long long Size)
 	 continue;
       if (Res < 0)
       {
-	 Flags |= Fail;
 #ifdef HAVE_ZLIB
 	 if (d != NULL && d->gz != NULL)
 	 {
 	    int err;
 	    char const * const errmsg = gzerror(d->gz, &err);
 	    if (err != Z_ERRNO)
-	       return _error->Error("gzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
+	       return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
 	 }
 #endif
 #ifdef HAVE_BZ2
@@ -1380,10 +1388,10 @@ bool FileFd::Write(const void *From,unsigned long long Size)
 	    int err;
 	    char const * const errmsg = BZ2_bzerror(d->bz2, &err);
 	    if (err != BZ_IO_ERROR)
-	       return _error->Error("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
+	       return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
 	 }
 #endif
-	 return _error->Errno("write",_("Write error"));
+	 return FileFdErrno("write",_("Write error"));
       }
       
       From = (char *)From + Res;
@@ -1395,9 +1403,8 @@ bool FileFd::Write(const void *From,unsigned long long Size)
    
    if (Size == 0)
       return true;
-   
-   Flags |= Fail;
-   return _error->Error(_("write, still have %llu to write but couldn't"), Size);
+
+   return FileFdError(_("write, still have %llu to write but couldn't"), Size);
 }
 bool FileFd::Write(int Fd, const void *From, unsigned long long Size)
 {
@@ -1441,13 +1448,13 @@ bool FileFd::Seek(unsigned long long To)
 	 return Skip(To - seekpos);
 
       if ((d->openmode & ReadOnly) != ReadOnly)
-      {
-	 Flags |= Fail;
-	 return _error->Error("Reopen is only implemented for read-only files!");
-      }
+	 return FileFdError("Reopen is only implemented for read-only files!");
 #ifdef HAVE_BZ2
-      if (d->bz2 != NULL)
-	 BZ2_bzclose(d->bz2);
+     if (d->bz2 != NULL) 
+     {
+	BZ2_bzclose(d->bz2);
+	d->bz2 = NULL;
+     }
 #endif
       if (iFd != -1)
 	 close(iFd);
@@ -1462,17 +1469,11 @@ bool FileFd::Seek(unsigned long long To)
 	    if (lseek(d->compressed_fd, 0, SEEK_SET) != 0)
 	       iFd = d->compressed_fd;
 	 if (iFd < 0)
-	 {
-	    Flags |= Fail;
-	    return _error->Error("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
-	 }
+	    return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
       }
 
       if (OpenInternDescriptor(d->openmode, d->compressor) == false)
-      {
-	 Flags |= Fail;
-	 return _error->Error("Seek on file %s because it couldn't be reopened", FileName.c_str());
-      }
+	 return FileFdError("Seek on file %s because it couldn't be reopened", FileName.c_str());
 
       if (To != 0)
 	 return Skip(To);
@@ -1488,10 +1489,7 @@ bool FileFd::Seek(unsigned long long To)
 #endif
       res = lseek(iFd,To,SEEK_SET);
    if (res != (signed)To)
-   {
-      Flags |= Fail;
-      return _error->Error("Unable to seek to %llu", To);
-   }
+      return FileFdError("Unable to seek to %llu", To);
 
    if (d != NULL)
       d->seekpos = To;
@@ -1515,10 +1513,7 @@ bool FileFd::Skip(unsigned long long Over)
       {
 	 unsigned long long toread = std::min((unsigned long long) sizeof(buffer), Over);
 	 if (Read(buffer, toread) == false)
-	 {
-	    Flags |= Fail;
-	    return _error->Error("Unable to seek ahead %llu",Over);
-	 }
+	    return FileFdError("Unable to seek ahead %llu",Over);
 	 Over -= toread;
       }
       return true;
@@ -1532,10 +1527,7 @@ bool FileFd::Skip(unsigned long long Over)
 #endif
       res = lseek(iFd,Over,SEEK_CUR);
    if (res < 0)
-   {
-      Flags |= Fail;
-      return _error->Error("Unable to seek ahead %llu",Over);
-   }
+      return FileFdError("Unable to seek ahead %llu",Over);
    if (d != NULL)
       d->seekpos = res;
 
@@ -1549,17 +1541,11 @@ bool FileFd::Truncate(unsigned long long To)
 {
 #if defined HAVE_ZLIB || defined HAVE_BZ2
    if (d != NULL && (d->gz != NULL || d->bz2 != NULL))
-   {
-      Flags |= Fail;
-      return _error->Error("Truncating compressed files is not implemented (%s)", FileName.c_str());
-   }
+      return FileFdError("Truncating compressed files is not implemented (%s)", FileName.c_str());
 #endif
    if (ftruncate(iFd,To) != 0)
-   {
-      Flags |= Fail;
-      return _error->Error("Unable to truncate to %llu",To);
-   }
-   
+      return FileFdError("Unable to truncate to %llu",To);
+
    return true;
 }
 									/*}}}*/
@@ -1587,10 +1573,7 @@ unsigned long long FileFd::Tell()
 #endif
      Res = lseek(iFd,0,SEEK_CUR);
    if (Res == (off_t)-1)
-   {
-      Flags |= Fail;
-      _error->Errno("lseek","Failed to determine the current file position");
-   }
+      FileFdErrno("lseek","Failed to determine the current file position");
    if (d != NULL)
       d->seekpos = Res;
    return Res;
@@ -1603,10 +1586,7 @@ unsigned long long FileFd::FileSize()
 {
    struct stat Buf;
    if ((d == NULL || d->pipe == false) && fstat(iFd,&Buf) != 0)
-   {
-      Flags |= Fail;
-      return _error->Errno("fstat","Unable to determine the file size");
-   }
+      return FileFdErrno("fstat","Unable to determine the file size");
 
    // for compressor pipes st_size is undefined and at 'best' zero
    if ((d != NULL && d->pipe == true) || S_ISFIFO(Buf.st_mode))
@@ -1616,10 +1596,7 @@ unsigned long long FileFd::FileSize()
       if (d != NULL)
 	 d->pipe = true;
       if (stat(FileName.c_str(), &Buf) != 0)
-      {
-	 Flags |= Fail;
-	 return _error->Errno("stat","Unable to determine the file size");
-      }
+	 return FileFdErrno("stat","Unable to determine the file size");
    }
 
    return Buf.st_size;
@@ -1644,7 +1621,11 @@ unsigned long long FileFd::Size()
       char ignore[1000];
       unsigned long long read = 0;
       do {
-	 Read(ignore, sizeof(ignore), &read);
+	 if (Read(ignore, sizeof(ignore), &read) == false)
+	 {
+	    Seek(oldSeek);
+	    return 0;
+	 }
       } while(read != 0);
       size = Tell();
       Seek(oldSeek);
@@ -1662,14 +1643,14 @@ unsigned long long FileFd::Size()
        // FIXME: Size for gz-files is limited by 32bit… no largefile support
        if (lseek(iFd, -4, SEEK_END) < 0)
        {
-	  Flags |= Fail;
-	  return _error->Errno("lseek","Unable to seek to end of gzipped file");
+	  FileFdErrno("lseek","Unable to seek to end of gzipped file");
+	  return 0;
        }
-       size = 0L;
+       size = 0;
        if (read(iFd, &size, 4) != 4)
        {
-	  Flags |= Fail;
-	  return _error->Errno("read","Unable to read original size of gzipped file");
+	  FileFdErrno("read","Unable to read original size of gzipped file");
+	  return 0;
        }
 
 #ifdef WORDS_BIGENDIAN
@@ -1681,8 +1662,8 @@ unsigned long long FileFd::Size()
 
        if (lseek(iFd, oldPos, SEEK_SET) < 0)
        {
-	  Flags |= Fail;
-	  return _error->Errno("lseek","Unable to seek in gzipped file");
+	  FileFdErrno("lseek","Unable to seek in gzipped file");
+	  return 0;
        }
 
        return size;
@@ -1700,8 +1681,7 @@ time_t FileFd::ModificationTime()
    struct stat Buf;
    if ((d == NULL || d->pipe == false) && fstat(iFd,&Buf) != 0)
    {
-      Flags |= Fail;
-      _error->Errno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
+      FileFdErrno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
       return 0;
    }
 
@@ -1714,8 +1694,7 @@ time_t FileFd::ModificationTime()
 	 d->pipe = true;
       if (stat(FileName.c_str(), &Buf) != 0)
       {
-	 Flags |= Fail;
-	 _error->Errno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
+	 FileFdErrno("fstat","Unable to determine the modification time of file %s", FileName.c_str());
 	 return 0;
       }
    }
@@ -1771,11 +1750,40 @@ bool FileFd::Close()
 bool FileFd::Sync()
 {
    if (fsync(iFd) != 0)
+      return FileFdErrno("sync",_("Problem syncing the file"));
+   return true;
+}
+									/*}}}*/
+// FileFd::FileFdErrno - set Fail and call _error->Errno		*{{{*/
+bool FileFd::FileFdErrno(const char *Function, const char *Description,...)
+{
+   Flags |= Fail;
+   va_list args;
+   size_t msgSize = 400;
+   int const errsv = errno;
+   while (true)
    {
-      Flags |= Fail;
-      return _error->Errno("sync",_("Problem syncing the file"));
+      va_start(args,Description);
+      if (_error->InsertErrno(GlobalError::ERROR, Function, Description, args, errsv, msgSize) == false)
+	 break;
+      va_end(args);
    }
-   return true;
+   return false;
+}
+									/*}}}*/
+// FileFd::FileFdError - set Fail and call _error->Error		*{{{*/
+bool FileFd::FileFdError(const char *Description,...) {
+   Flags |= Fail;
+   va_list args;
+   size_t msgSize = 400;
+   while (true)
+   {
+      va_start(args,Description);
+      if (_error->Insert(GlobalError::ERROR, Description, args, msgSize) == false)
+	 break;
+      va_end(args);
+   }
+   return false;
 }
 									/*}}}*/
 

+ 4 - 0
apt-pkg/contrib/fileutl.h

@@ -149,6 +149,10 @@ class FileFd
    private:
    FileFdPrivate* d;
    bool OpenInternDescriptor(unsigned int const Mode, APT::Configuration::Compressor const &compressor);
+
+   // private helpers to set Fail flag and call _error->Error
+   bool FileFdErrno(const char* Function, const char* Description,...) __like_printf(3) __cold;
+   bool FileFdError(const char* Description,...) __like_printf(2) __cold;
 };
 
 bool RunScripts(const char *Cnf);

+ 1 - 1
apt-pkg/contrib/gpgv.cc

@@ -154,7 +154,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
 	 if (sigFd != -1)
 	    unlink(data);
 	 ioprintf(std::cerr, "Splitting up %s into data and signature failed", File.c_str());
-	 exit(EINTERNAL);
+	 exit(112);
       }
       Args.push_back(sig);
       Args.push_back(data);

+ 12 - 3
apt-pkg/contrib/gpgv.h

@@ -23,9 +23,18 @@
 /** \brief generates and run the command to verify a file with gpgv
  *
  * If File and FileSig specify the same file it is assumed that we
- * deal with a clear-signed message. In that case the file will be
- * rewritten to be in a good-known format without uneeded whitespaces
- * and additional messages (unsigned or signed).
+ * deal with a clear-signed message. Note that the method will accept
+ * and validate files which include additional (unsigned) messages
+ * without complaining. Do NOT open files accepted by this method
+ * for reading. Use #OpenMaybeClearSignedFile to access the message
+ * instead to ensure you are only reading signed data.
+ *
+ * The method does not return, but has some noteable exit-codes:
+ * 111 signals an internal error like the inability to execute gpgv,
+ * 112 indicates a clear-signed file which doesn't include a message,
+ *  which can happen if APT is run while on a network requiring
+ *  authentication before usage (e.g. in hotels)
+ * All other exit-codes are passed-through from gpgv.
  *
  * @param File is the message (unsigned or clear-signed)
  * @param FileSig is the signature (detached or clear-signed)

+ 3 - 1
apt-pkg/contrib/sha2.h

@@ -60,10 +60,11 @@ class SHA256Summation : public SHA2SummationBase
       res.Set(Sum);
       return res;
    };
-   SHA256Summation() 
+   SHA256Summation()
    {
       SHA256_Init(&ctx);
       Done = false;
+      memset(&Sum, 0, sizeof(Sum));
    };
 };
 
@@ -96,6 +97,7 @@ class SHA512Summation : public SHA2SummationBase
    {
       SHA512_Init(&ctx);
       Done = false;
+      memset(&Sum, 0, sizeof(Sum));
    };
 };
 

+ 6 - 6
apt-pkg/contrib/sha2_internal.cc

@@ -632,7 +632,7 @@ void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
 	}
 
 	/* Clean up state data: */
-	MEMSET_BZERO(context, sizeof(context));
+	MEMSET_BZERO(context, sizeof(*context));
 	usedspace = 0;
 }
 
@@ -653,7 +653,7 @@ char *SHA256_End(SHA256_CTX* context, char buffer[]) {
 		}
 		*buffer = (char)0;
 	} else {
-		MEMSET_BZERO(context, sizeof(context));
+		MEMSET_BZERO(context, sizeof(*context));
 	}
 	MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH);
 	return buffer;
@@ -969,7 +969,7 @@ void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
 	}
 
 	/* Zero out state data */
-	MEMSET_BZERO(context, sizeof(context));
+	MEMSET_BZERO(context, sizeof(*context));
 }
 
 char *SHA512_End(SHA512_CTX* context, char buffer[]) {
@@ -989,7 +989,7 @@ char *SHA512_End(SHA512_CTX* context, char buffer[]) {
 		}
 		*buffer = (char)0;
 	} else {
-		MEMSET_BZERO(context, sizeof(context));
+		MEMSET_BZERO(context, sizeof(*context));
 	}
 	MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH);
 	return buffer;
@@ -1044,7 +1044,7 @@ void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
 	}
 
 	/* Zero out state data */
-	MEMSET_BZERO(context, sizeof(context));
+	MEMSET_BZERO(context, sizeof(*context));
 }
 
 char *SHA384_End(SHA384_CTX* context, char buffer[]) {
@@ -1064,7 +1064,7 @@ char *SHA384_End(SHA384_CTX* context, char buffer[]) {
 		}
 		*buffer = (char)0;
 	} else {
-		MEMSET_BZERO(context, sizeof(context));
+		MEMSET_BZERO(context, sizeof(*context));
 	}
 	MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH);
 	return buffer;

+ 10 - 9
apt-pkg/contrib/strutl.cc

@@ -759,7 +759,7 @@ bool ReadMessages(int Fd, vector<string> &List)
       for (char *I = Buffer; I + 1 < End; I++)
       {
 	 if (I[1] != '\n' ||
-	     (strncmp(I, "\n\n", 2) != 0 && strncmp(I, "\r\n\r\n", 4) != 0))
+	       (I[0] != '\n' && strncmp(I, "\r\n\r\n", 4) != 0))
 	    continue;
 	 
 	 // Pull the message out
@@ -767,7 +767,7 @@ bool ReadMessages(int Fd, vector<string> &List)
 	 PartialMessage += Message;
 
 	 // Fix up the buffer
-	 for (; I < End && (*I == '\r' || *I == '\n'); ++I);
+	 for (; I < End && (*I == '\n' || *I == '\r'); ++I);
 	 End -= I-Buffer;	 
 	 memmove(Buffer,I,End-Buffer);
 	 I = Buffer;
@@ -1233,12 +1233,12 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
    va_list args;
    int Did;
 
-   va_start(args,Format);
-
    if (End <= Buffer)
       return End;
-
+   va_start(args,Format);
    Did = vsnprintf(Buffer,End - Buffer,Format,args);
+   va_end(args);
+
    if (Did < 0 || Buffer + Did > End)
       return End;
    return Buffer + Did;
@@ -1484,9 +1484,12 @@ URI::operator string()
           
       if (User.empty() == false)
       {
-	 Res +=  User;
+	 // FIXME: Technically userinfo is permitted even less
+	 // characters than these, but this is not conveniently
+	 // expressed with a blacklist.
+	 Res += QuoteString(User, ":/?#[]@");
 	 if (Password.empty() == false)
-	    Res += ":" + Password;
+	    Res += ":" + QuoteString(Password, ":/?#[]@");
 	 Res += "@";
       }
       
@@ -1525,7 +1528,6 @@ string URI::SiteOnly(const string &URI)
    U.User.clear();
    U.Password.clear();
    U.Path.clear();
-   U.Port = 0;
    return U;
 }
 									/*}}}*/
@@ -1537,7 +1539,6 @@ string URI::NoUserPassword(const string &URI)
    ::URI U(URI);
    U.User.clear();
    U.Password.clear();
-   U.Port = 0;
    return U;
 }
 									/*}}}*/

+ 24 - 86
apt-pkg/deb/deblistparser.cc

@@ -219,8 +219,12 @@ MD5SumValue debListParser::Description_md5()
    string const value = Section.FindS("Description-md5");
    if (value.empty() == true)
    {
+      std::string const desc = Description() + "\n";
+      if (desc == "\n")
+	 return MD5SumValue();
+
       MD5Summation md5;
-      md5.Add((Description() + "\n").c_str());
+      md5.Add(desc.c_str());
       return md5.Result();
    }
    else if (likely(value.size() == 32))
@@ -801,94 +805,28 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
    map_ptrloc const storage = WriteUniqString(component);
    FileI->Component = storage;
 
-   // FIXME: should use FileFd and TagSection
-   FILE* release = fdopen(dup(File.Fd()), "r");
-   if (release == NULL)
+   pkgTagFile TagFile(&File);
+   pkgTagSection Section;
+   if (_error->PendingError() == true || TagFile.Step(Section) == false)
       return false;
 
-   char buffer[101];
-   while (fgets(buffer, sizeof(buffer), release) != NULL)
-   {
-      size_t len = 0;
-
-      // Skip empty lines
-      for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
-         /* nothing */
-         ;
-      if (buffer[len] == '\0')
-	 continue;
-
-      // seperate the tag from the data
-      const char* dataStart = strchr(buffer + len, ':');
-      if (dataStart == NULL)
-	 continue;
-      len = dataStart - buffer;
-      for (++dataStart; *dataStart == ' '; ++dataStart)
-         /* nothing */
-         ;
-      const char* dataEnd = (const char*)rawmemchr(dataStart, '\0');
-      // The last char should be a newline, but we can never be sure: #633350
-      const char* lineEnd = dataEnd;
-      for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
-         /* nothing */
-         ;
-      ++lineEnd;
-
-      // which datastorage need to be updated
-      enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None;
-      if (buffer[0] == ' ')
-	 ;
-      #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X;
-      APT_PARSER_WRITETO(Suite)
-      APT_PARSER_WRITETO(Component)
-      APT_PARSER_WRITETO(Version)
-      APT_PARSER_WRITETO(Origin)
-      APT_PARSER_WRITETO(Codename)
-      APT_PARSER_WRITETO(Label)
-      #undef APT_PARSER_WRITETO
-      #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
-	 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
-      APT_PARSER_FLAGIT(NotAutomatic)
-      APT_PARSER_FLAGIT(ButAutomaticUpgrades)
-      #undef APT_PARSER_FLAGIT
-
-      // load all data from the line and save it
-      string data;
-      if (writeTo != None)
-	 data.append(dataStart, dataEnd);
-      if (sizeof(buffer) - 1 == (dataEnd - buffer))
-      {
-	 while (fgets(buffer, sizeof(buffer), release) != NULL)
-	 {
-	    if (writeTo != None)
-	       data.append(buffer);
-	    if (strlen(buffer) != sizeof(buffer) - 1)
-	       break;
-	 }
-      }
-      if (writeTo != None)
-      {
-	 // remove spaces and stuff from the end of the data line
-	 for (std::string::reverse_iterator s = data.rbegin();
-	      s != data.rend(); ++s)
-	 {
-	    if (*s != '\r' && *s != '\n' && *s != ' ')
-	       break;
-	    *s = '\0';
-	 }
-	 map_ptrloc const storage = WriteUniqString(data);
-	 switch (writeTo) {
-	 case Suite: FileI->Archive = storage; break;
-	 case Component: FileI->Component = storage; break;
-	 case Version: FileI->Version = storage; break;
-	 case Origin: FileI->Origin = storage; break;
-	 case Codename: FileI->Codename = storage; break;
-	 case Label: FileI->Label = storage; break;
-	 case None: break;
-	 }
-      }
+   std::string data;
+   #define APT_INRELEASE(TAG, STORE) \
+   data = Section.FindS(TAG); \
+   if (data.empty() == false) \
+   { \
+      map_ptrloc const storage = WriteUniqString(data); \
+      STORE = storage; \
    }
-   fclose(release);
+   APT_INRELEASE("Suite", FileI->Archive)
+   APT_INRELEASE("Component", FileI->Component)
+   APT_INRELEASE("Version", FileI->Version)
+   APT_INRELEASE("Origin", FileI->Origin)
+   APT_INRELEASE("Codename", FileI->Codename)
+   APT_INRELEASE("Label", FileI->Label)
+   #undef APT_INRELEASE
+   Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic);
+   Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades);
 
    return !_error->PendingError();
 }

+ 22 - 2
apt-pkg/deb/debmetaindex.cc

@@ -238,6 +238,7 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 	 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
 			 (*Target)->ShortDesc, HashString());
       }
+      delete targets;
 
       // this is normally created in pkgAcqMetaSig, but if we run
       // in --print-uris mode, we add it here
@@ -373,10 +374,29 @@ class debSLTypeDebian : public pkgSourceList::Type
 			   string const &Dist, string const &Section,
 			   bool const &IsSrc, map<string, string> const &Options) const
    {
-      map<string, string>::const_iterator const arch = Options.find("arch");
-      vector<string> const Archs =
+      // parse arch=, arch+= and arch-= settings
+      map<string, string>::const_iterator arch = Options.find("arch");
+      vector<string> Archs =
 		(arch != Options.end()) ? VectorizeString(arch->second, ',') :
 				APT::Configuration::getArchitectures();
+      if ((arch = Options.find("arch+")) != Options.end())
+      {
+	 std::vector<std::string> const plusArch = VectorizeString(arch->second, ',');
+	 for (std::vector<std::string>::const_iterator plus = plusArch.begin(); plus != plusArch.end(); ++plus)
+	    if (std::find(Archs.begin(), Archs.end(), *plus) == Archs.end())
+	       Archs.push_back(*plus);
+      }
+      if ((arch = Options.find("arch-")) != Options.end())
+      {
+	 std::vector<std::string> const minusArch = VectorizeString(arch->second, ',');
+	 for (std::vector<std::string>::const_iterator minus = minusArch.begin(); minus != minusArch.end(); ++minus)
+	 {
+	    std::vector<std::string>::iterator kill = std::find(Archs.begin(), Archs.end(), *minus);
+	    if (kill != Archs.end())
+	       Archs.erase(kill);
+	 }
+      }
+
       map<string, string>::const_iterator const trusted = Options.find("trusted");
 
       for (vector<metaIndex *>::const_iterator I = List.begin();

+ 73 - 34
apt-pkg/deb/dpkgpm.cc

@@ -134,6 +134,8 @@ static void dpkgChrootDirectory()
    std::cerr << "Chrooting into " << chrootDir << std::endl;
    if (chroot(chrootDir.c_str()) != 0)
       _exit(100);
+   if (chdir("/") != 0)
+      _exit(100);
 }
 									/*}}}*/
 
@@ -238,15 +240,23 @@ bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
    return true;
 }
 									/*}}}*/
-// DPkgPM::SendV2Pkgs - Send version 2 package info			/*{{{*/
+// DPkgPM::SendPkgInfo - Send info for install-pkgs hook		/*{{{*/
 // ---------------------------------------------------------------------
 /* This is part of the helper script communication interface, it sends
    very complete information down to the other end of the pipe.*/
 bool pkgDPkgPM::SendV2Pkgs(FILE *F)
 {
-   fprintf(F,"VERSION 2\n");
-   
-   /* Write out all of the configuration directives by walking the 
+   return SendPkgsInfo(F, 2);
+}
+bool pkgDPkgPM::SendPkgsInfo(FILE * const F, unsigned int const &Version)
+{
+   // This version of APT supports only v3, so don't sent higher versions
+   if (Version <= 3)
+      fprintf(F,"VERSION %u\n", Version);
+   else
+      fprintf(F,"VERSION 3\n");
+
+   /* Write out all of the configuration directives by walking the
       configuration tree */
    const Configuration::Item *Top = _config->Tree(0);
    for (; Top != 0;)
@@ -280,30 +290,51 @@ bool pkgDPkgPM::SendV2Pkgs(FILE *F)
       pkgDepCache::StateCache &S = Cache[I->Pkg];
       
       fprintf(F,"%s ",I->Pkg.Name());
-      // Current version
-      if (I->Pkg->CurrentVer == 0)
-	 fprintf(F,"- ");
+
+      // Current version which we are going to replace
+      pkgCache::VerIterator CurVer = I->Pkg.CurrentVer();
+      if (CurVer.end() == true && (I->Op == Item::Remove || I->Op == Item::Purge))
+	 CurVer = FindNowVersion(I->Pkg);
+
+      if (CurVer.end() == true)
+      {
+	 if (Version <= 2)
+	    fprintf(F, "- ");
+	 else
+	    fprintf(F, "- - none ");
+      }
       else
-	 fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr());
-      
-      // Show the compare operator
-      // Target version
+      {
+	 fprintf(F, "%s ", CurVer.VerStr());
+	 if (Version >= 3)
+	    fprintf(F, "%s %s ", CurVer.Arch(), CurVer.MultiArchType());
+      }
+
+      // Show the compare operator between current and install version
       if (S.InstallVer != 0)
       {
+	 pkgCache::VerIterator const InstVer = S.InstVerIter(Cache);
 	 int Comp = 2;
-	 if (I->Pkg->CurrentVer != 0)
-	    Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer());
+	 if (CurVer.end() == false)
+	    Comp = InstVer.CompareVer(CurVer);
 	 if (Comp < 0)
 	    fprintf(F,"> ");
-	 if (Comp == 0)
+	 else if (Comp == 0)
 	    fprintf(F,"= ");
-	 if (Comp > 0)
+	 else if (Comp > 0)
 	    fprintf(F,"< ");
-	 fprintf(F,"%s ",S.InstVerIter(Cache).VerStr());
+	 fprintf(F, "%s ", InstVer.VerStr());
+	 if (Version >= 3)
+	    fprintf(F, "%s %s ", InstVer.Arch(), InstVer.MultiArchType());
       }
       else
-	 fprintf(F,"> - ");
-      
+      {
+	 if (Version <= 2)
+	    fprintf(F, "> - ");
+	 else
+	    fprintf(F, "> - - none ");
+      }
+
       // Show the filename/operation
       if (I->Op == Item::Install)
       {
@@ -313,9 +344,9 @@ bool pkgDPkgPM::SendV2Pkgs(FILE *F)
 	 else
 	    fprintf(F,"%s\n",I->File.c_str());
       }      
-      if (I->Op == Item::Configure)
+      else if (I->Op == Item::Configure)
 	 fprintf(F,"**CONFIGURE**\n");
-      if (I->Op == Item::Remove ||
+      else if (I->Op == Item::Remove ||
 	  I->Op == Item::Purge)
 	 fprintf(F,"**REMOVE**\n");
       
@@ -404,7 +435,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
 	 }
       }
       else
-	 SendV2Pkgs(F);
+	 SendPkgsInfo(F, Version);
 
       fclose(F);
       
@@ -720,13 +751,15 @@ bool pkgDPkgPM::OpenLog()
 	 return _error->WarningE("OpenLog", _("Could not open file '%s'"), logfile_name.c_str());
       setvbuf(d->term_out, NULL, _IONBF, 0);
       SetCloseExec(fileno(d->term_out), true);
-      struct passwd *pw;
-      struct group *gr;
-      pw = getpwnam("root");
-      gr = getgrnam("adm");
-      if (pw != NULL && gr != NULL)
-	  chown(logfile_name.c_str(), pw->pw_uid, gr->gr_gid);
-      chmod(logfile_name.c_str(), 0640);
+      if (getuid() == 0) // if we aren't root, we can't chown a file, so don't try it
+      {
+	 struct passwd *pw = getpwnam("root");
+	 struct group *gr = getgrnam("adm");
+	 if (pw != NULL && gr != NULL && chown(logfile_name.c_str(), pw->pw_uid, gr->gr_gid) != 0)
+	    _error->WarningE("OpenLog", "chown to root:adm of file %s failed", logfile_name.c_str());
+      }
+      if (chmod(logfile_name.c_str(), 0640) != 0)
+	 _error->WarningE("OpenLog", "chmod 0640 of file %s failed", logfile_name.c_str());
       fprintf(d->term_out, "\nLog started: %s\n", timestr);
    }
 
@@ -1205,16 +1238,13 @@ bool pkgDPkgPM::Go(int OutStatusFd)
 
       // if tcgetattr does not return zero there was a error
       // and we do not do any pty magic
+      _error->PushToStack();
       if (tcgetattr(STDOUT_FILENO, &tt) == 0)
       {
 	 ioctl(0, TIOCGWINSZ, (char *)&win);
-	 if (openpty(&master, &slave, NULL, &tt, &win) < 0) 
+	 if (openpty(&master, &slave, NULL, &tt, &win) < 0)
 	 {
-	    const char *s = _("Can not write log, openpty() "
-	                      "failed (/dev/pts not mounted?)\n");
-	    fprintf(stderr, "%s",s);
-            if(d->term_out)
-              fprintf(d->term_out, "%s",s);
+	    _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
 	    master = slave = -1;
 	 }  else {
 	    struct termios rtt;
@@ -1237,6 +1267,15 @@ bool pkgDPkgPM::Go(int OutStatusFd)
          if(d->term_out)
             fprintf(d->term_out, "%s",s); 
       }
+      // complain only if stdout is either a terminal (but still failed) or is an invalid
+      // descriptor otherwise we would complain about redirection to e.g. /dev/null as well.
+      else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
+         _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
+
+      if (_error->PendingError() == true)
+	 _error->DumpErrors(std::cerr);
+      _error->RevertToStack();
+
        // Fork dpkg
       pid_t Child;
       _config->Set("APT::Keep-Fds::",fd[1]);

+ 3 - 1
apt-pkg/deb/dpkgpm.h

@@ -14,6 +14,7 @@
 #include <vector>
 #include <map>
 #include <stdio.h>
+#include <apt-pkg/macros.h>
 
 #ifndef APT_8_CLEANER_HEADERS
 using std::vector;
@@ -79,7 +80,8 @@ class pkgDPkgPM : public pkgPackageManager
 
    // Helpers
    bool RunScriptsWithPkgs(const char *Cnf);
-   bool SendV2Pkgs(FILE *F);
+   __deprecated bool SendV2Pkgs(FILE *F);
+   bool SendPkgsInfo(FILE * const F, unsigned int const &Version);
    void WriteHistoryTag(std::string const &tag, std::string value);
 
    // apport integration

+ 75 - 15
apt-pkg/depcache.cc

@@ -864,6 +864,11 @@ bool pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
    dpkg holds are enforced by the private IsModeChangeOk */
 bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge,
 			      unsigned long Depth, bool FromUser)
+{
+   return IsDeleteOkProtectInstallRequests(Pkg, rPurge, Depth, FromUser);
+}
+bool pkgDepCache::IsDeleteOkProtectInstallRequests(PkgIterator const &Pkg,
+      bool const rPurge, unsigned long const Depth, bool const FromUser)
 {
    if (FromUser == false && Pkg->CurrentVer == 0)
    {
@@ -1002,9 +1007,6 @@ struct CompareProviders {
 	 else if ((B->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
 	    return true;
       }
-      // higher priority seems like a good idea
-      if (AV->Priority != BV->Priority)
-	 return AV->Priority < BV->Priority;
       // prefer native architecture
       if (strcmp(A.Arch(), B.Arch()) != 0)
       {
@@ -1019,6 +1021,9 @@ struct CompareProviders {
 	    else if (*a == B.Arch())
 	       return true;
       }
+      // higher priority seems like a good idea
+      if (AV->Priority != BV->Priority)
+	 return AV->Priority > BV->Priority;
       // unable to decide…
       return A->ID < B->ID;
    }
@@ -1047,9 +1052,10 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
       return true;
    }
 
-   // check if we are allowed to install the package
-   if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false)
-      return false;
+   // check if we are allowed to install the package (if we haven't already)
+   if (P.Mode != ModeInstall || P.InstallVer != P.CandidateVer)
+      if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false)
+	 return false;
 
    ActionGroup group(*this);
    P.iFlags &= ~AutoKept;
@@ -1200,16 +1206,23 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 	    verlist.insert(Cand);
 	 }
 	 CompareProviders comp(Start);
-	 APT::VersionList::iterator InstVer = std::max_element(verlist.begin(), verlist.end(), comp);
 
-	 if (InstVer != verlist.end())
-	 {
+	 do {
+	    APT::VersionList::iterator InstVer = std::max_element(verlist.begin(), verlist.end(), comp);
+
+	    if (InstVer == verlist.end())
+	       break;
+
 	    pkgCache::PkgIterator InstPkg = InstVer.ParentPkg();
 	    if(DebugAutoInstall == true)
 	       std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name()
 			 << " as " << Start.DepType() << " of " << Pkg.Name()
 			 << std::endl;
-	    MarkInstall(InstPkg, true, Depth + 1, false, ForceImportantDeps);
+	    if (MarkInstall(InstPkg, true, Depth + 1, false, ForceImportantDeps) == false)
+	    {
+	       verlist.erase(InstVer);
+	       continue;
+	    }
 	    // now check if we should consider it a automatic dependency or not
 	    if(InstPkg->CurrentVer == 0 && Pkg->Section != 0 && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", Pkg.Section()))
 	    {
@@ -1218,7 +1231,8 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
                             << Start.DepType() << " of pkg in APT::Never-MarkAuto-Sections)" << std::endl;
 	       MarkAuto(InstPkg, false);
 	    }
-	 }
+	    break;
+	 } while(true);
 	 continue;
       }
       /* Negative dependencies have no or-group
@@ -1243,9 +1257,16 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 		PkgState[Pkg->ID].CandidateVer != *I &&
 		MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps) == true)
 	       continue;
-	    else if ((Start->Type == pkgCache::Dep::Conflicts || Start->Type == pkgCache::Dep::DpkgBreaks) &&
-		     MarkDelete(Pkg,false,Depth + 1, false) == false)
-	       break;
+	    else if (Start->Type == pkgCache::Dep::Conflicts || 
+                     Start->Type == pkgCache::Dep::DpkgBreaks) 
+            {
+               if(DebugAutoInstall == true)
+                  std::clog << OutputInDepth(Depth) 
+                            << " Removing: " << Pkg.Name()
+                            << std::endl;
+               if (MarkDelete(Pkg,false,Depth + 1, false) == false)
+                  break;
+            }
 	 }
 	 continue;
       }
@@ -1256,11 +1277,50 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 									/*}}}*/
 // DepCache::IsInstallOk - check if it is ok to install this package	/*{{{*/
 // ---------------------------------------------------------------------
-/* The default implementation does nothing.
+/* The default implementation checks if the installation of an M-A:same
+   package would lead us into a version-screw and if so forbids it.
    dpkg holds are enforced by the private IsModeChangeOk */
 bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst,
 			      unsigned long Depth, bool FromUser)
 {
+   return IsInstallOkMultiArchSameVersionSynced(Pkg,AutoInst, Depth, FromUser);
+}
+bool pkgDepCache::IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg,
+      bool const AutoInst, unsigned long const Depth, bool const FromUser)
+{
+   if (FromUser == true) // as always: user is always right
+      return true;
+
+   // ignore packages with none-M-A:same candidates
+   VerIterator const CandVer = PkgState[Pkg->ID].CandidateVerIter(*this);
+   if (unlikely(CandVer.end() == true) || CandVer == Pkg.CurrentVer() ||
+	 (CandVer->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same)
+      return true;
+
+   GrpIterator const Grp = Pkg.Group();
+   for (PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
+   {
+      // not installed or version synced: fine by definition
+      // (simple string-compare as stuff like '1' == '0:1-0' can't happen here)
+      if (P->CurrentVer == 0 || strcmp(Pkg.CandVersion(), P.CandVersion()) == 0)
+	 continue;
+      // packages loosing M-A:same can be out-of-sync
+      VerIterator CV = PkgState[P->ID].CandidateVerIter(*this);
+      if (unlikely(CV.end() == true) ||
+	    (CV->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same)
+	 continue;
+
+      // not downloadable means the package is obsolete, so allow out-of-sync
+      if (CV.Downloadable() == false)
+	 continue;
+
+      PkgState[Pkg->ID].iFlags |= AutoKept;
+      if (unlikely(DebugMarker == true))
+	 std::clog << OutputInDepth(Depth) << "Ignore MarkInstall of " << Pkg
+	    << " as its M-A:same siblings are not version-synced" << std::endl;
+      return false;
+   }
+
    return true;
 }
 									/*}}}*/

+ 17 - 13
apt-pkg/depcache.h

@@ -442,16 +442,15 @@ class pkgDepCache : protected pkgCache::Namespace
    /** \return \b true if it's OK for MarkInstall to install
     *  the given package.
     *
-    *  See the default implementation for a simple example how this
-    *  method can be used.
-    *  Overriding implementations should use the hold-state-flag to cache
-    *  results from previous checks of this package - also it should
-    *  be used if the default resolver implementation is also used to
-    *  ensure that these packages are handled like "normal" dpkg holds.
+    *  The default implementation simply calls all IsInstallOk*
+    *  method mentioned below.
+    *
+    *  Overriding implementations should use the hold-state-flag to
+    *  cache results from previous checks of this package - if possible.
     *
     *  The parameters are the same as in the calling MarkInstall:
     *  \param Pkg       the package that MarkInstall wants to install.
-    *  \param AutoInst  needs a previous MarkInstall this package?
+    *  \param AutoInst  install this and all its dependencies
     *  \param Depth     recursive deep of this Marker call
     *  \param FromUser  was the install requested by the user?
     */
@@ -461,12 +460,8 @@ class pkgDepCache : protected pkgCache::Namespace
    /** \return \b true if it's OK for MarkDelete to remove
     *  the given package.
     *
-    *  See the default implementation for a simple example how this
-    *  method can be used.
-    *  Overriding implementations should use the hold-state-flag to cache
-    *  results from previous checks of this package - also it should
-    *  be used if the default resolver implementation is also used to
-    *  ensure that these packages are handled like "normal" dpkg holds.
+    *  The default implementation simply calls all IsDeleteOk*
+    *  method mentioned below, see also #IsInstallOk.
     *
     *  The parameters are the same as in the calling MarkDelete:
     *  \param Pkg       the package that MarkDelete wants to remove.
@@ -498,6 +493,15 @@ class pkgDepCache : protected pkgCache::Namespace
    pkgDepCache(pkgCache *Cache,Policy *Plcy = 0);
    virtual ~pkgDepCache();
 
+   protected:
+   // methods call by IsInstallOk
+   bool IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg,
+	 bool const AutoInst, unsigned long const Depth, bool const FromUser);
+
+   // methods call by IsDeleteOk
+   bool IsDeleteOkProtectInstallRequests(PkgIterator const &Pkg,
+	 bool const rPurge, unsigned long const Depth, bool const FromUser);
+
    private:
    bool IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg,
 			unsigned long const Depth, bool const FromUser);

+ 17 - 6
apt-pkg/indexcopy.cc

@@ -106,9 +106,9 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
       } else {
          Target.Open(TargetF,FileFd::WriteAtomic);
       }
-      FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
       if (_error->PendingError() == true)
 	 return false;
+      FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
       if (TargetFl == 0)
 	 return _error->Errno("fdopen","Failed to reopen fd");
       
@@ -544,11 +544,9 @@ bool SigVerify::CopyMetaIndex(string CDROM, string CDName,		/*{{{*/
       FileFd Rel;
       Target.Open(TargetF,FileFd::WriteAtomic);
       Rel.Open(prefix + file,FileFd::ReadOnly);
-      if (_error->PendingError() == true)
-	 return false;
       if (CopyFile(Rel,Target) == false)
-	 return false;
-   
+	 return _error->Error("Copying of '%s' for '%s' from '%s' failed", file.c_str(), CDName.c_str(), prefix.c_str());
+
       return true;
 }
 									/*}}}*/
@@ -603,6 +601,7 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
 			 (useInRelease ? inrelease.c_str() : releasegpg.c_str()));
 	 // something went wrong, don't copy the Release.gpg
 	 // FIXME: delete any existing gpg file?
+	 delete MetaIndex;
 	 continue;
       }
 
@@ -642,6 +641,18 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
    return true;
 }
 									/*}}}*/
+// SigVerify::RunGPGV - deprecated wrapper calling ExecGPGV		/*{{{*/
+bool SigVerify::RunGPGV(std::string const &File, std::string const &FileOut,
+      int const &statusfd, int fd[2]) {
+   ExecGPGV(File, FileOut, statusfd, fd);
+   return false;
+};
+bool SigVerify::RunGPGV(std::string const &File, std::string const &FileOut,
+      int const &statusfd) {
+   ExecGPGV(File, FileOut, statusfd);
+   return false;
+};
+									/*}}}*/
 bool TranslationsCopy::CopyTranslations(string CDROM,string Name,	/*{{{*/
 				vector<string> &List, pkgCdromStatus *log)
 {
@@ -704,9 +715,9 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,	/*{{{*/
       } else {
 	 Target.Open(TargetF,FileFd::WriteAtomic);
       }
-      FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
       if (_error->PendingError() == true)
 	 return false;
+      FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
       if (TargetFl == 0)
 	 return _error->Errno("fdopen","Failed to reopen fd");
       

+ 2 - 8
apt-pkg/indexcopy.h

@@ -100,15 +100,9 @@ class SigVerify								/*{{{*/
 		      std::vector<std::string> PkgList,std::vector<std::string> SrcList);
 
    __deprecated static bool RunGPGV(std::string const &File, std::string const &FileOut,
-		       int const &statusfd, int fd[2]) {
-      ExecGPGV(File, FileOut, statusfd, fd);
-      return false;
-   };
+		       int const &statusfd, int fd[2]);
    __deprecated static bool RunGPGV(std::string const &File, std::string const &FileOut,
-			      int const &statusfd = -1) {
-      ExecGPGV(File, FileOut, statusfd);
-      return false;
-   };
+			      int const &statusfd = -1);
 };
 									/*}}}*/
 

+ 6 - 11
apt-pkg/indexrecords.cc

@@ -62,7 +62,7 @@ bool indexRecords::Load(const string Filename)				/*{{{*/
    if (OpenMaybeClearSignedFile(Filename, Fd) == false)
       return false;
 
-   pkgTagFile TagFile(&Fd, Fd.Size() + 256); // XXX
+   pkgTagFile TagFile(&Fd);
    if (_error->PendingError() == true)
    {
       strprintf(ErrorText, _("Unable to parse Release file %s"),Filename.c_str());
@@ -71,16 +71,11 @@ bool indexRecords::Load(const string Filename)				/*{{{*/
 
    pkgTagSection Section;
    const char *Start, *End;
-   // Skip over sections beginning with ----- as this is an idicator for clearsigns
-   do {
-      if (TagFile.Step(Section) == false)
-      {
-	 strprintf(ErrorText, _("No sections in Release file %s"), Filename.c_str());
-	 return false;
-      }
-
-      Section.Get (Start, End, 0);
-   } while (End - Start > 5 && strncmp(Start, "-----", 5) == 0);
+   if (TagFile.Step(Section) == false)
+   {
+      strprintf(ErrorText, _("No sections in Release file %s"), Filename.c_str());
+      return false;
+   }
 
    Suite = Section.FindS("Suite");
    Dist = Section.FindS("Codename");

+ 105 - 119
apt-pkg/orderlist.cc

@@ -301,9 +301,8 @@ bool pkgOrderList::OrderConfigure()
 /* Higher scores order earlier */
 int pkgOrderList::Score(PkgIterator Pkg)
 {
-   static int const ScoreDelete = _config->FindI("OrderList::Score::Delete", 500);
-
-   // Removal is always done first
+   // Removals should be done after we dealt with essentials
+   static int const ScoreDelete = _config->FindI("OrderList::Score::Delete", 100);
    if (Cache[Pkg].Delete() == true)
       return ScoreDelete;
 
@@ -893,149 +892,136 @@ bool pkgOrderList::DepConfigure(DepIterator D)
 									/*}}}*/
 // OrderList::DepRemove - Removal ordering				/*{{{*/
 // ---------------------------------------------------------------------
-/* Removal visits all reverse depends. It considers if the dependency
-   of the Now state version to see if it is okay with removing this
-   package. This check should always fail, but is provided for symetery
-   with the other critical handlers.
- 
-   Loops are preprocessed and logged. Removal loops can also be
-   detected in the critical handler. They are characterized by an
-   old version of A depending on B but the new version of A conflicting
-   with B, thus either A or B must break to install. */
-bool pkgOrderList::DepRemove(DepIterator D)
+/* Checks all given dependencies if they are broken by the remove of a
+   package and if so fix it by visiting another provider or or-group
+   member to ensure that the dependee keeps working which is especially
+   important for Immediate packages like e.g. those depending on an
+   awk implementation. If the dependency can't be fixed with another
+   package this means an upgrade of the package will solve the problem. */
+bool pkgOrderList::DepRemove(DepIterator Broken)
 {
-   if (D.Reverse() == false)
+   if (Broken.Reverse() == false)
       return true;
-   for (; D.end() == false; ++D)
-      if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
+
+   for (; Broken.end() == false; ++Broken)
+   {
+      if (Broken->Type != pkgCache::Dep::Depends &&
+	    Broken->Type != pkgCache::Dep::PreDepends)
+	 continue;
+
+      PkgIterator BrokenPkg = Broken.ParentPkg();
+      // uninstalled packages can't break via a remove
+      if (BrokenPkg->CurrentVer == 0)
+	 continue;
+
+      // if its already added, we can't do anything useful
+      if (IsFlag(BrokenPkg, AddPending) == true || IsFlag(BrokenPkg, Added) == true)
+	 continue;
+
+      // if the dependee is going to be removed, visit it now
+      if (Cache[BrokenPkg].Delete() == true)
+	 return VisitNode(BrokenPkg, "Remove-Dependee");
+
+      // The package stays around, so find out how this is possible
+      for (DepIterator D = BrokenPkg.CurrentVer().DependsList(); D.end() == false;)
       {
-	 // Duplication elimination, consider the current version only
-	 if (D.ParentPkg().CurrentVer() != D.ParentVer())
+	 // only important or-groups need fixing
+	 if (D->Type != pkgCache::Dep::Depends &&
+	       D->Type != pkgCache::Dep::PreDepends)
+	 {
+	    ++D;
 	    continue;
+	 }
 
-	 /* We wish to see if the dep on the parent package is okay
-	    in the removed (install) state of the target pkg. */
-	 bool tryFixDeps = false;
-	 if (CheckDep(D) == true)
+	 // Start is the beginning of the or-group, D is the first one after or
+	 DepIterator Start = D;
+	 bool foundBroken = false;
+	 for (bool LastOR = true; D.end() == false && LastOR == true; ++D)
 	 {
-	    // We want to catch loops with the code below.
-	    if (IsFlag(D.ParentPkg(),AddPending) == false)
-	       continue;
+	    LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+	    if (D == Broken)
+	       foundBroken = true;
 	 }
-	 else
-	    tryFixDeps = true;
 
-	 // This is the loop detection
-	 if (IsFlag(D.ParentPkg(),Added) == true || 
-	     IsFlag(D.ParentPkg(),AddPending) == true)
-	 {
-	    if (IsFlag(D.ParentPkg(),AddPending) == true)
-	       AddLoop(D);
+	 // this or-group isn't the broken one: keep searching
+	 if (foundBroken == false)
 	    continue;
+
+	 // iterate over all members of the or-group searching for a ready replacement
+	 bool readyReplacement = false;
+	 for (DepIterator OrMember = Start; OrMember != D && readyReplacement == false; ++OrMember)
+	 {
+	    Version ** Replacements = OrMember.AllTargets();
+	    for (Version **R = Replacements; *R != 0; ++R)
+	    {
+	       VerIterator Ver(Cache,*R);
+	       // only currently installed packages can be a replacement
+	       PkgIterator RPkg = Ver.ParentPkg();
+	       if (RPkg.CurrentVer() != Ver)
+		  continue;
+
+	       // packages going to be removed can't be a replacement
+	       if (Cache[RPkg].Delete() == true)
+		  continue;
+
+	       readyReplacement = true;
+	       break;
+	    }
+	    delete[] Replacements;
 	 }
 
-	 if (tryFixDeps == true)
+	 // something else is ready to take over, do nothing
+	 if (readyReplacement == true)
+	    continue;
+
+	 // see if we can visit a replacement
+	 bool visitReplacement = false;
+	 for (DepIterator OrMember = Start; OrMember != D && visitReplacement == false; ++OrMember)
 	 {
-	    for (pkgCache::DepIterator F = D.ParentPkg().CurrentVer().DependsList();
-		 F.end() == false; ++F)
+	    Version ** Replacements = OrMember.AllTargets();
+	    for (Version **R = Replacements; *R != 0; ++R)
 	    {
-	       if (F->Type != pkgCache::Dep::Depends && F->Type != pkgCache::Dep::PreDepends)
+	       VerIterator Ver(Cache,*R);
+	       // consider only versions we plan to install
+	       PkgIterator RPkg = Ver.ParentPkg();
+	       if (Cache[RPkg].Install() == false || Cache[RPkg].InstallVer != Ver)
 		  continue;
-	       // Check the Providers
-	       if (F.TargetPkg()->ProvidesList != 0)
-	       {
-		  pkgCache::PrvIterator Prov = F.TargetPkg().ProvidesList();
-		  for (; Prov.end() == false; ++Prov)
-		  {
-		     pkgCache::PkgIterator const P = Prov.OwnerPkg();
-		     if (IsFlag(P, InList) == true &&
-			 IsFlag(P, AddPending) == true &&
-			 IsFlag(P, Added) == false &&
-			 Cache[P].InstallVer == 0)
-			break;
-		  }
-		  if (Prov.end() == false)
-		     for (pkgCache::PrvIterator Prv = F.TargetPkg().ProvidesList();
-			  Prv.end() == false; ++Prv)
-		     {
-			pkgCache::PkgIterator const P = Prv.OwnerPkg();
-			if (IsFlag(P, InList) == true &&
-			    IsFlag(P, AddPending) == false &&
-			    Cache[P].InstallVer != 0 &&
-			    VisitNode(P, "Remove-P") == true)
-			{
-			   Flag(P, Immediate);
-			   tryFixDeps = false;
-			   break;
-			}
-		     }
-		  if (tryFixDeps == false)
-		     break;
-	       }
 
-	       // Check for Or groups
-	       if ((F->CompareOp & pkgCache::Dep::Or) != pkgCache::Dep::Or)
+	       // loops are not going to help us, so don't create them
+	       if (IsFlag(RPkg, AddPending) == true)
 		  continue;
-	       // Lets see if the package is part of the Or group
-	       pkgCache::DepIterator S = F;
-	       for (; S.end() == false; ++S)
+
+	       if (IsMissing(RPkg) == true)
+		  continue;
+
+	       visitReplacement = true;
+	       if (IsFlag(BrokenPkg, Immediate) == false)
 	       {
-		  if (S.TargetPkg() == D.TargetPkg())
+		  if (VisitNode(RPkg, "Remove-Rep") == true)
 		     break;
-		  if ((S->CompareOp & pkgCache::Dep::Or) != pkgCache::Dep::Or ||
-		      CheckDep(S)) // Or group is satisfied by another package
-		     for (;S.end() == false; ++S);
 	       }
-	       if (S.end() == true)
-		  continue;
-	       // skip to the end of the or group
-	       for (;S.end() == false && (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or; ++S);
-	       ++S;
-	       // The soon to be removed is part of the Or group
-	       // start again in the or group and find something which will serve as replacement
-	       for (; F.end() == false && F != S; ++F)
+	       else
 	       {
-		  if (IsFlag(F.TargetPkg(), InList) == true &&
-		      IsFlag(F.TargetPkg(), AddPending) == false &&
-		      Cache[F.TargetPkg()].InstallVer != 0 &&
-		      VisitNode(F.TargetPkg(), "Remove-Target") == true)
-		  {
-		     Flag(F.TargetPkg(), Immediate);
-		     tryFixDeps = false;
+		  Flag(RPkg, Immediate);
+		  if (VisitNode(RPkg, "Remove-ImmRep") == true)
 		     break;
-		  }
-		  else if (F.TargetPkg()->ProvidesList != 0)
-		  {
-		     pkgCache::PrvIterator Prv = F.TargetPkg().ProvidesList();
-		     for (; Prv.end() == false; ++Prv)
-		     {
-			if (IsFlag(Prv.OwnerPkg(), InList) == true &&
-			    IsFlag(Prv.OwnerPkg(), AddPending) == false &&
-			    Cache[Prv.OwnerPkg()].InstallVer != 0 &&
-			    VisitNode(Prv.OwnerPkg(), "Remove-Owner") == true)
-			{
-			   Flag(Prv.OwnerPkg(), Immediate);
-			   tryFixDeps = false;
-			   break;
-			}
-		     }
-		     if (Prv.end() == false)
-			break;
-		  }
 	       }
-	       if (tryFixDeps == false)
-		  break;
+	       visitReplacement = false;
 	    }
+	    delete[] Replacements;
 	 }
-
-	 // Skip over missing files
-	 if (IsMissing(D.ParentPkg()) == true)
+	 if (visitReplacement == true)
 	    continue;
-	 
-	 if (VisitNode(D.ParentPkg(), "Remove-Parent") == false)
+
+	 // the broken package in current version can't be fixed, so install new version
+	 if (IsMissing(BrokenPkg) == true)
+	    break;
+
+	 if (VisitNode(BrokenPkg, "Remove-Upgrade") == false)
 	    return false;
       }
-   
+   }
+
    return true;
 }
 									/*}}}*/

+ 73 - 48
apt-pkg/packagemanager.cc

@@ -338,8 +338,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
       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", 500);
+   const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
    unsigned int i=0;
+   std::list<DepIterator> needConfigure;
    do
    {
       Changed = false;
@@ -353,7 +354,7 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	    continue;
 	 Bad = true;
 
-	 // Search for dependencies which are unpacked but aren't configured yet (maybe loops)
+	 // Check for dependencies that have not been unpacked, probably due to loops.
 	 for (DepIterator Cur = Start; true; ++Cur)
 	 {
 	    SPtrArray<Version *> VList = Cur.AllTargets();
@@ -373,51 +374,66 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	       }
 
 	       // Check if the version that is going to be installed will satisfy the dependency
-	       if (Cache[DepPkg].InstallVer != *I)
+	       if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
 		  continue;
 
-	       if (List->IsFlag(DepPkg,pkgOrderList::UnPacked))
+	       if (PkgLoop == true)
 	       {
-		  if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop)
-		  {
-		    // This dependency has already been dealt with by another SmartConfigure on Pkg
-		    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 (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 (SmartConfigure(DepPkg, Depth + 1) == true)
+		  if (SmartUnPack(DepPkg, true, Depth + 1) == true)
 		  {
 		     Bad = false;
 		     if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-			Changed = true;
+		        Changed = true;
 		  }
 		  if (PkgLoop == false)
-		    List->RmFlag(Pkg,pkgOrderList::Loop);
-		  // If SmartConfigure was succesfull, Bad is false, so break
+		     List->RmFlag(Pkg,pkgOrderList::Loop);
 		  if (Bad == false)
 		     break;
 	       }
-	       else if (List->IsFlag(DepPkg,pkgOrderList::Configured))
-	       {
-		  Bad = false;
-		  break;
-	       }
 	    }
-	    if (Cur == End)
+
+	    if (Cur == End || Bad == false)
 	       break;
-         }
+	 }
 
 	 if (Bad == false)
 	    continue;
 
-	 // Check for dependencies that have not been unpacked, probably due to loops.
+	 needConfigure.push_back(Start);
+      }
+      if (i++ > max_loops)
+         return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (1) for %s, aborting", Pkg.FullName().c_str());
+   } while (Changed == true);
+
+   Bad = false, Changed = false, i = 0;
+   do
+   {
+      Changed = false;
+      for (std::list<DepIterator>::const_iterator D = needConfigure.begin(); D != needConfigure.end(); ++D)
+      {
+	 // Compute a single dependency element (glob or) without modifying D
+	 pkgCache::DepIterator Start, End;
+	 {
+	    pkgCache::DepIterator Discard = *D;
+	    Discard.GlobOr(Start,End);
+	 }
+
+	 if (End->Type != pkgCache::Dep::Depends)
+	    continue;
+	 Bad = true;
+
+	 // Search for dependencies which are unpacked but aren't configured yet (maybe loops)
 	 for (DepIterator Cur = Start; true; ++Cur)
 	 {
 	    SPtrArray<Version *> VList = Cur.AllTargets();
@@ -428,44 +444,53 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	       PkgIterator DepPkg = Ver.ParentPkg();
 
 	       // Check if the version that is going to be installed will satisfy the dependency
-	       if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
+	       if (Cache[DepPkg].InstallVer != *I)
 		  continue;
 
-	       if (PkgLoop == true)
-	       {
-		  if (Debug)
-		     std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl;
-	          Bad = false;
-		  break;
-	       }
-	       else
+	       if (List->IsFlag(DepPkg,pkgOrderList::UnPacked))
 	       {
-		  if (Debug)
-		     clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl;
+		  if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop)
+		  {
+		    // This dependency has already been dealt with by another SmartConfigure on Pkg
+		    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 (SmartUnPack(DepPkg, true, Depth + 1) == true)
+		  if (SmartConfigure(DepPkg, Depth + 1) == true)
 		  {
 		     Bad = false;
 		     if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-		        Changed = true;
+			Changed = true;
 		  }
 		  if (PkgLoop == false)
-		     List->RmFlag(Pkg,pkgOrderList::Loop);
+		    List->RmFlag(Pkg,pkgOrderList::Loop);
+		  // If SmartConfigure was succesfull, Bad is false, so break
 		  if (Bad == false)
 		     break;
 	       }
+	       else if (List->IsFlag(DepPkg,pkgOrderList::Configured))
+	       {
+		  Bad = false;
+		  break;
+	       }
 	    }
-
-	    if (Cur == End)
+	    if (Cur == End || Bad == false)
 	       break;
-	 }
+         }
+
 
 	 if (Bad == true && Changed == false && Debug == true)
-	    std::clog << OutputInDepth(Depth) << "Could not satisfy " << Start << std::endl;
+	    std::clog << OutputInDepth(Depth) << "Could not satisfy " << *D << std::endl;
       }
       if (i++ > max_loops)
-         return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack for %s, aborting", Pkg.FullName().c_str());
+         return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (2) for %s, aborting", Pkg.FullName().c_str());
    } while (Changed == true);
    
    if (Bad) {
@@ -603,7 +628,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
       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;
-   const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 500);
+   const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
    unsigned int i = 0;
    do 
    {

+ 12 - 0
apt-pkg/pkgcache.cc

@@ -924,6 +924,18 @@ string pkgCache::VerIterator::RelStr() const
    return Res;
 }
 									/*}}}*/
+// VerIterator::MultiArchType - string representing MultiArch flag	/*{{{*/
+const char * pkgCache::VerIterator::MultiArchType() const
+{
+   if ((S->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
+      return "same";
+   else if ((S->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
+      return "foreign";
+   else if ((S->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
+      return "allowed";
+   return "none";
+}
+									/*}}}*/
 // PkgFileIterator::IsOk - Checks if the cache is in sync with the file	/*{{{*/
 // ---------------------------------------------------------------------
 /* This stats the file and compares its stats with the ones that were

+ 3 - 1
apt-pkg/pkgcachegen.cc

@@ -296,6 +296,8 @@ bool pkgCacheGenerator::MergeListPackage(ListParser &List, pkgCache::PkgIterator
 
    // Find the right version to write the description
    MD5SumValue CurMd5 = List.Description_md5();
+   if (CurMd5.Value().empty() == true || List.Description().empty() == true)
+      return true;
    std::string CurLang = List.DescriptionLanguage();
 
    for (Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
@@ -480,7 +482,7 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
 
    /* Record the Description (it is not translated) */
    MD5SumValue CurMd5 = List.Description_md5();
-   if (CurMd5.Value().empty() == true)
+   if (CurMd5.Value().empty() == true || List.Description().empty() == true)
       return true;
    std::string CurLang = List.DescriptionLanguage();
 

+ 18 - 7
apt-pkg/policy.cc

@@ -166,11 +166,15 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator const &Pk
       tracks the default when the default is taken away, and a permanent
       pin that stays at that setting.
     */
+   bool PrefSeen = false;
    for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
    {
       /* Lets see if this version is the installed version */
       bool instVer = (Pkg.CurrentVer() == Ver);
 
+      if (Pref == Ver)
+	 PrefSeen = true;
+
       for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; ++VF)
       {
 	 /* If this is the status file, and the current version is not the
@@ -187,26 +191,33 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator const &Pk
 	 {
 	    Pref = Ver;
 	    Max = Prio;
+	    PrefSeen = true;
 	 }
 	 if (Prio > MaxAlt)
 	 {
 	    PrefAlt = Ver;
 	    MaxAlt = Prio;
-	 }	 
-      }      
-      
+	 }
+      }
+
       if (instVer == true && Max < 1000)
       {
+	 /* Not having seen the Pref yet means we have a specific pin below 1000
+	    on a version below the current installed one, so ignore the specific pin
+	    as this would be a downgrade otherwise */
+	 if (PrefSeen == false || Pref.end() == true)
+	 {
+	    Pref = Ver;
+	    PrefSeen = true;
+	 }
 	 /* Elevate our current selection (or the status file itself)
 	    to the Pseudo-status priority. */
-	 if (Pref.end() == true)
-	    Pref = Ver;
 	 Max = 1000;
-	 
+
 	 // Fast path optimize.
 	 if (StatusOverride == false)
 	    break;
-      }            
+      }
    }
    // If we do not find our candidate, use the one with the highest pin.
    // This means that if there is a version available with pin > 0; there

+ 1 - 1
apt-pkg/tagfile.h

@@ -84,7 +84,7 @@ class pkgTagSection
       Stop = this->Stop;
    };
    
-   pkgTagSection() : Section(0), TagCount(0), Stop(0) {};
+   pkgTagSection() : Section(0), TagCount(0), d(NULL), Stop(0) {};
    virtual ~pkgTagSection() {};
 };
 

+ 1 - 1
apt-pkg/vendorlist.cc

@@ -66,7 +66,7 @@ bool pkgVendorList::CreateList(Configuration& Cnf)			/*{{{*/
       Configuration Block(Top);
       string VendorID = Top->Tag;
       vector <struct Vendor::Fingerprint *> *Fingerprints = new vector<Vendor::Fingerprint *>;
-      struct Vendor::Fingerprint *Fingerprint = new struct Vendor::Fingerprint;
+      struct Vendor::Fingerprint *Fingerprint = new struct Vendor::Fingerprint();
       string Origin = Block.Find("Origin");
 
       Fingerprint->Print = Block.Find("Fingerprint");

+ 1 - 0
buildlib/apti18n.h.in

@@ -25,4 +25,5 @@
 # define _(x) x
 # define P_(msg,plural,n) (n == 1 ? msg : plural)
 # define N_(x) x
+# define dgettext(d, m) m
 #endif

+ 2 - 2
buildlib/configure.mak

@@ -2,7 +2,7 @@
 
 # This make fragment is included by the toplevel make to handle configure
 # and setup. It defines a target called startup that when run will init
-# the build directory, generate configure from configure.in, create aclocal
+# the build directory, generate configure from configure.ac, create aclocal
 # and has rules to run config.status should one of the .in files change.
 
 # Input
@@ -48,7 +48,7 @@ missing-config-files:
 	@echo "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD"
 	exit 100
 
-configure: aclocal.m4 configure.in buildlib/config.guess buildlib/config.sub
+configure: aclocal.m4 configure.ac buildlib/config.guess buildlib/config.sub
 	autoconf
 
 aclocal.m4: $(wildcard buildlib/*.m4)

+ 1 - 1
buildlib/copy.mak

@@ -21,7 +21,7 @@ veryclean: veryclean/$(LOCAL)
 
 MKDIRS += $(dir $($(LOCAL)-LIST))
 
-$($(LOCAL)-LIST) : $(TO)/% : % dirs
+$($(LOCAL)-LIST) : $(TO)/% : %
 	echo Installing $< to $(@D)
 	cp $< $(@D)
 

+ 8 - 9
buildlib/defaults.mak

@@ -172,12 +172,11 @@ ifeq ($(NUM_PROCS),1)
   PARALLEL_RUN=no
 endif
 
-# mvo: commented out, lead to build failures in the arch-build target
-#ifndef PARALLEL_RUN
-# PARALLEL_RUN=yes
-# .EXPORT: PARALLEL_RUN
-# # handle recursion
-# ifneq ($(NUM_PROCS),)
-#  MAKEFLAGS += -j $(NUM_PROCS)
-# endif
-#endif
+ifndef PARALLEL_RUN
+ PARALLEL_RUN=yes
+ export PARALLEL_RUN
+ # handle recursion
+ ifneq ($(NUM_PROCS),)
+  MAKEFLAGS += -j $(NUM_PROCS)
+ endif
+endif

+ 2 - 2
buildlib/library.mak

@@ -51,7 +51,7 @@ $(LIB)/lib$(LIBRARY).so: $(LIB)/lib$(LIBRARY).so.$(MAJOR).$(MINOR)
 	ln -sf $(<F) $@
 
 # The binary build rule
-$(LIB)/lib$(LIBRARY).so.$(MAJOR).$(MINOR): $($(LOCAL)-HEADERS) $($(LOCAL)-OBJS)
+$(LIB)/lib$(LIBRARY).so.$(MAJOR).$(MINOR): $($(LOCAL)-HEADERS) $($(LOCAL)-OBJS) $(LIBRARYDEPENDS)
 	-rm -f $(LIB)/lib$($(@F)-LIBRARY)*.so* 2> /dev/null
 	echo Building shared library $@
 	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(PICFLAGS) $(LFLAGS) $(LFLAGS_SO)\
@@ -61,7 +61,7 @@ $(LIB)/lib$(LIBRARY).so.$(MAJOR).$(MINOR): $($(LOCAL)-HEADERS) $($(LOCAL)-OBJS)
 
 # Compilation rules
 vpath %.cc $(SUBDIRS)
-$(OBJ)/%.opic: %.cc
+$(OBJ)/%.opic: %.cc $(LIBRARYDEPENDS)
 	echo Compiling $< to $@
 	$(CXX) -c $(INLINEDEPFLAG) $(CPPFLAGS) $(CXXFLAGS) $(PICFLAGS) -o $@ $<
 	$(DoDep)

+ 7 - 5
buildlib/po4a_manpage.mak

@@ -25,6 +25,7 @@ $(LOCAL)-LIST := $(SOURCE)
 
 # Install generation hooks
 manpages: $($(LOCAL)-LIST)
+clean: clean/$(LOCAL)
 veryclean: veryclean/$(LOCAL)
 
 apt-verbatim.ent: ../apt-verbatim.ent
@@ -37,15 +38,16 @@ manpage-style.xsl: ../manpage-style.xsl
 $($(LOCAL)-LIST) :: % : %.xml $(STYLESHEET) $(INCLUDES)
 	echo Creating man page $@
 	$(XSLTPROC) -o $@ $(STYLESHEET) $< || exit 200 # why xsltproc doesn't respect the -o flag here???
-	test -f $(subst .$(LC),,$@) || echo FIXME: xsltproc respect the -o flag now, workaround can be removed
+	test -f $(subst .$(LC),,$@) || echo 'FIXME: xsltproc respects the -o flag now, workaround can be removed'
 	mv -f $(subst .$(LC),,$@) $@
 
 # Clean rule
-.PHONY: veryclean/$(LOCAL)
+.PHONY: clean/$(LOCAL) veryclean/$(LOCAL)
+clean/$(LOCAL):
+	rm -f $($(@F)-LIST) apt.ent apt-verbatim.ent
 veryclean/$(LOCAL):
-	-rm -rf $($(@F)-LIST) apt.ent apt-verbatim.ent apt.$(LC).8 \
-		$(addsuffix .xml,$($(@F)-LIST)) \
-		offline.$(LC).sgml guide.$(LC).sgml
+	# we are nuking the directory we are working in as it is auto-generated
+	rm -rf $(shell readlink -f .)
 
 HAVE_PO4A=yes
 endif

+ 6 - 1
buildlib/podomain.mak

@@ -4,6 +4,8 @@
 # declared domain of the make file. It also arranges to set the DOMAIN 
 # CPPFLAG for the compilation.
 
+ifneq ($(APT_DOMAIN),none)
+
 MY_DOMAIN := $(PACKAGE)
 ifdef APT_DOMAIN
 $($(LOCAL)-OBJS): CPPFLAGS := $(CPPFLAGS) -DAPT_DOMAIN='"$(APT_DOMAIN)"'
@@ -13,10 +15,13 @@ endif
 MKDIRS += $(PO_DOMAINS)/$(MY_DOMAIN)
 $(PO_DOMAINS)/$(MY_DOMAIN)/$(LOCAL).$(TYPE)list: SRC := $(addprefix $(SUBDIR)/,$(SOURCE))
 $(PO_DOMAINS)/$(MY_DOMAIN)/$(LOCAL).$(TYPE)list: makefile dirs
-	(echo $(SRC) | xargs -n1 echo) > $@
+	(echo $(SRC) | xargs -n1 echo) > $@.tmp
+	cmp --silent $@.tmp $@ || mv $@.tmp $@
 startup binary program clean update-po: $(PO_DOMAINS)/$(MY_DOMAIN)/$(LOCAL).$(TYPE)list
 
 veryclean: veryclean/$(LOCAL)
 veryclean/po/$(LOCAL): LIST := $(PO_DOMAINS)/$(MY_DOMAIN)/$(LOCAL).$(TYPE)list
 veryclean/po/$(LOCAL):
 	rm -f $(LIST)
+
+endif

+ 123 - 53
cmdline/apt-cache.cc

@@ -1127,6 +1127,24 @@ bool Dotty(CommandLine &CmdL)
 // ---------------------------------------------------------------------
 /* This displays the package record from the proper package index file. 
    It is not used by DumpAvail for performance reasons. */
+
+static unsigned char const* skipDescriptionFields(unsigned char const * DescP)
+{
+   char const * const TagName = "\nDescription";
+   size_t const TagLen = strlen(TagName);
+   while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL)
+   {
+      if (DescP[1] == ' ')
+	 DescP += 2;
+      else if (strncmp((char*)DescP, TagName, TagLen) == 0)
+	 DescP += TagLen;
+      else
+	 break;
+   }
+   if (DescP != NULL)
+      ++DescP;
+   return DescP;
+}
 bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V)
 {
    pkgCache *Cache = CacheFile.GetPkgCache();
@@ -1150,21 +1168,27 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V)
    if (PkgF.Open(I.FileName(), FileFd::ReadOnly, FileFd::Extension) == false)
       return false;
 
-   // Read the record
-   unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+1];
-   Buffer[V.FileList()->Size] = '\n';
-   if (PkgF.Seek(V.FileList()->Offset) == false ||
-       PkgF.Read(Buffer,V.FileList()->Size) == false)
+   // Read the record (and ensure that it ends with a newline and NUL)
+   unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+2];
+   Buffer[Vf->Size] = '\n';
+   Buffer[Vf->Size+1] = '\0';
+   if (PkgF.Seek(Vf->Offset) == false ||
+       PkgF.Read(Buffer,Vf->Size) == false)
    {
       delete [] Buffer;
       return false;
    }
 
    // Get a pointer to start of Description field
-   const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "Description:");
+   const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "\nDescription");
+   if (DescP != NULL)
+      ++DescP;
+   else
+      DescP = Buffer + Vf->Size;
 
    // Write all but Description
-   if (fwrite(Buffer,1,DescP - Buffer,stdout) < (size_t)(DescP - Buffer))
+   size_t const length = DescP - Buffer;
+   if (length != 0 && FileFd::Write(STDOUT_FILENO, Buffer, length) == false)
    {
       delete [] Buffer;
       return false;
@@ -1173,29 +1197,44 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V)
    // Show the right description
    pkgRecords Recs(*Cache);
    pkgCache::DescIterator Desc = V.TranslatedDescription();
-   pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
-   cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc();
+   if (Desc.end() == false)
+   {
+      pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
+      cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc();
+      cout << std::endl << "Description-md5: " << Desc.md5() << std::endl;
+
+      // Find the first field after the description (if there is any)
+      DescP = skipDescriptionFields(DescP);
+   }
+   // else we have no translation, so we found a lonely Description-md5 -> don't skip it
 
-   // Find the first field after the description (if there is any)
-   for(DescP++;DescP != &Buffer[V.FileList()->Size];DescP++) 
+   // write the rest of the buffer, but skip mixed in Descriptions* fields
+   while (DescP != NULL)
    {
-      if(*DescP == '\n' && *(DescP+1) != ' ') 
+      const unsigned char * const Start = DescP;
+      const unsigned char *End = (unsigned char*)strstr((char*)DescP, "\nDescription");
+      if (End == NULL)
       {
-	 // write the rest of the buffer
-	 const unsigned char *end=&Buffer[V.FileList()->Size];
-	 if (fwrite(DescP,1,end-DescP,stdout) < (size_t)(end-DescP)) 
-	 {
-	    delete [] Buffer;
-	    return false;
-	 }
-
-	 break;
+	 End = &Buffer[Vf->Size];
+	 DescP = NULL;
+      }
+      else
+      {
+	 ++End; // get the newline into the output
+	 DescP = skipDescriptionFields(End + strlen("Description"));
+      }
+      size_t const length = End - Start;
+      if (length != 0 && FileFd::Write(STDOUT_FILENO, Start, length) == false)
+      {
+	 delete [] Buffer;
+	 return false;
       }
    }
-   // write a final newline (after the description)
+
+   // write a final newline after the last field
    cout<<endl;
-   delete [] Buffer;
 
+   delete [] Buffer;
    return true;
 }
 									/*}}}*/
@@ -1203,7 +1242,7 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V)
 struct ExDescFile
 {
    pkgCache::DescFile *Df;
-   bool NameMatch;
+   map_ptrloc ID;
 };
 
 // Search - Perform a search						/*{{{*/
@@ -1246,37 +1285,52 @@ bool Search(CommandLine &CmdL)
       return false;
    }
    
-   ExDescFile *DFList = new ExDescFile[Cache->HeaderP->GroupCount+1];
-   memset(DFList,0,sizeof(*DFList)*Cache->HeaderP->GroupCount+1);
+   size_t const descCount = Cache->HeaderP->GroupCount + 1;
+   ExDescFile *DFList = new ExDescFile[descCount];
+   memset(DFList,0,sizeof(*DFList) * descCount);
+
+   bool PatternMatch[descCount * NumPatterns];
+   memset(PatternMatch,false,sizeof(PatternMatch));
 
    // Map versions that we want to write out onto the VerList array.
    for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G)
    {
-      if (DFList[G->ID].NameMatch == true)
-	 continue;
-
-      DFList[G->ID].NameMatch = true;
-      for (unsigned I = 0; I != NumPatterns; I++)
+      size_t const PatternOffset = G->ID * NumPatterns;
+      size_t unmatched = 0, matched = 0;
+      for (unsigned I = 0; I < NumPatterns; ++I)
       {
-	 if (regexec(&Patterns[I],G.Name(),0,0,0) == 0)
-	    continue;
-	 DFList[G->ID].NameMatch = false;
-	 break;
+	 if (PatternMatch[PatternOffset + I] == true)
+	    ++matched;
+	 else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0)
+	    PatternMatch[PatternOffset + I] = true;
+	 else
+	    ++unmatched;
       }
-        
-      // Doing names only, drop any that dont match..
-      if (NamesOnly == true && DFList[G->ID].NameMatch == false)
+
+      // already dealt with this package?
+      if (matched == NumPatterns)
 	 continue;
-	 
+
+      // Doing names only, drop any that don't match..
+      if (NamesOnly == true && unmatched == NumPatterns)
+	 continue;
+
       // Find the proper version to use
       pkgCache::PkgIterator P = G.FindPreferredPkg();
       if (P.end() == true)
 	 continue;
       pkgCache::VerIterator V = Plcy->GetCandidateVer(P);
       if (V.end() == false)
-	 DFList[G->ID].Df = V.TranslatedDescription().FileList();
+      {
+	 pkgCache::DescIterator const D = V.TranslatedDescription();
+	 //FIXME: packages without a description can't be found
+	 if (D.end() == true)
+	    continue;
+	 DFList[G->ID].Df = D.FileList();
+	 DFList[G->ID].ID = G->ID;
+      }
 
-      if (DFList[G->ID].NameMatch == false)
+      if (unmatched == NumPatterns)
 	 continue;
 
       // Include all the packages that provide matching names too
@@ -1287,34 +1341,50 @@ bool Search(CommandLine &CmdL)
 	    continue;
 
 	 unsigned long id = Prv.OwnerPkg().Group()->ID;
-	 DFList[id].Df = V.TranslatedDescription().FileList();
-	 DFList[id].NameMatch = true;
+	 pkgCache::DescIterator const D = V.TranslatedDescription();
+	 //FIXME: packages without a description can't be found
+	 if (D.end() == true)
+	    continue;
+	 DFList[id].Df = D.FileList();
+	 DFList[id].ID = id;
+
+	 size_t const PrvPatternOffset = id * NumPatterns;
+	 for (unsigned I = 0; I < NumPatterns; ++I)
+	    PatternMatch[PrvPatternOffset + I] = PatternMatch[PatternOffset + I];
       }
    }
-   
+
    LocalitySort(&DFList->Df,Cache->HeaderP->GroupCount,sizeof(*DFList));
 
    // Create the text record parser
    pkgRecords Recs(*Cache);
    // Iterate over all the version records and check them
-   for (ExDescFile *J = DFList; J->Df != 0; J++)
+   for (ExDescFile *J = DFList; J->Df != 0; ++J)
    {
       pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache,J->Df));
+      size_t const PatternOffset = J->ID * NumPatterns;
 
-      if (J->NameMatch == false && NamesOnly == false)
+      if (NamesOnly == false)
       {
 	 string const LongDesc = P.LongDesc();
-	 J->NameMatch = true;
-	 for (unsigned I = 0; I != NumPatterns; I++)
+	 for (unsigned I = 0; I < NumPatterns; ++I)
 	 {
-	    if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
+	    if (PatternMatch[PatternOffset + I] == true)
 	       continue;
-	    J->NameMatch = false;
-	    break;
+	    else if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
+	       PatternMatch[PatternOffset + I] = true;
 	 }
       }
-      
-      if (J->NameMatch == true)
+
+      bool matchedAll = true;
+      for (unsigned I = 0; I < NumPatterns; ++I)
+	 if (PatternMatch[PatternOffset + I] == false)
+	 {
+	    matchedAll = false;
+	    break;
+	 }
+
+      if (matchedAll == true)
       {
 	 if (ShowFull == true)
 	 {

+ 22 - 12
cmdline/apt-cdrom.cc

@@ -39,6 +39,12 @@
 
 #include <apti18n.h>
 									/*}}}*/
+static const char *W_NO_CDROM_FOUND = \
+   N_("No CD-ROM could be auto-detected or found using "
+      "the default mount point.\n"
+      "You may try the --cdrom option to set the CD-ROM mount point. "
+      "See 'man apt-cdrom' for more "
+      "information about the CD-ROM auto-detection and mount point.");
 
 using namespace std;
 
@@ -60,7 +66,9 @@ void pkgCdromTextStatus::Prompt(const char *Text)
 {
    char C;
    cout << Text << ' ' << flush;
-   read(STDIN_FILENO,&C,1);
+   if (read(STDIN_FILENO,&C,1) < 0)
+      _error->Errno("pkgCdromTextStatus::Prompt", 
+                    "Failed to read from standard input (not a terminal?)");
    if (C != '\n')
       cout << endl;
 }
@@ -135,7 +143,6 @@ bool AutoDetectCdrom(pkgUdevCdromDevices &UdevCdroms, unsigned int &i)
    return true;
 }
 									/*}}}*/
-
 // DoAdd - Add a new CDROM						/*{{{*/
 // ---------------------------------------------------------------------
 /* This does the main add bit.. We show some status and things. The
@@ -150,13 +157,15 @@ bool DoAdd(CommandLine &)
    bool res = true;
 
    bool AutoDetect = _config->FindB("Acquire::cdrom::AutoDetect", true);
+   unsigned int count = 0;
    if (AutoDetect && UdevCdroms.Dlopen())
-   {
-      unsigned int count = 0;
       while (AutoDetectCdrom(UdevCdroms, count))
 	 res &= cdrom.Add(&log);
-   } else {
+   if (count == 0) {
       res = cdrom.Add(&log);
+      if (res == false) {
+         _error->Error("%s", _(W_NO_CDROM_FOUND));
+      }
    }
 
    if(res)
@@ -178,15 +187,16 @@ bool DoIdent(CommandLine &)
 
    bool AutoDetect = _config->FindB("Acquire::cdrom::AutoDetect");
 
+   unsigned int count = 0;
    if (AutoDetect && UdevCdroms.Dlopen())
-   {
-      unsigned int count = 0;
       while (AutoDetectCdrom(UdevCdroms, count))
 	 res &= cdrom.Ident(ident, &log);
-   } else {
-      return cdrom.Ident(ident, &log);
+   if (count == 0) {
+      res = cdrom.Ident(ident, &log);
+      if (res == false) {
+         _error->Error("%s", _(W_NO_CDROM_FOUND));
+      }
    }
- 
    return res;
 }
 									/*}}}*/
@@ -218,7 +228,7 @@ int ShowHelp()
       "  -m   No mounting\n"
       "  -f   Fast mode, don't check package files\n"
       "  -a   Thorough scan mode\n"
-      "  --auto-detect Auto detect drive and mount point\n"
+      "  --no-auto-detect Do not try to auto detect drive and mount point\n"
       "  -c=? Read this configuration file\n"
       "  -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n"
       "See fstab(5)\n";
@@ -229,7 +239,7 @@ int main(int argc,const char *argv[])					/*{{{*/
 {
    CommandLine::Args Args[] = {
       {'h',"help","help",0},
-      {  0,"auto-detect","Acquire::cdrom::AutoDetect",0},
+      {  0,"auto-detect","Acquire::cdrom::AutoDetect", CommandLine::Boolean},
       {'v',"version","version",0},
       {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg},
       {'r',"rename","APT::CDROM::Rename",0},

+ 39 - 10
cmdline/apt-get.cc

@@ -130,13 +130,42 @@ class CacheFile : public pkgCacheFile
 /* Returns true on a Yes.*/
 bool YnPrompt(bool Default=true)
 {
+   /* nl_langinfo does not support LANGUAGE setting, so we unset it here
+      to have the help-message (hopefully) match the expected characters */
+   char * language = getenv("LANGUAGE");
+   if (language != NULL)
+      language = strdup(language);
+   if (language != NULL)
+      unsetenv("LANGUAGE");
+
+   if (Default == true)
+      // TRANSLATOR: Yes/No question help-text: defaulting to Y[es]
+      //             e.g. "Do you want to continue? [Y/n] "
+      //             The user has to answer with an input matching the
+      //             YESEXPR/NOEXPR defined in your l10n.
+      c2out << " " << _("[Y/n]") << " " << std::flush;
+   else
+      // TRANSLATOR: Yes/No question help-text: defaulting to N[o]
+      //             e.g. "Should this file be removed? [y/N] "
+      //             The user has to answer with an input matching the
+      //             YESEXPR/NOEXPR defined in your l10n.
+      c2out << " " << _("[y/N]") << " " << std::flush;
+
+   if (language != NULL)
+   {
+      setenv("LANGUAGE", language, 0);
+      free(language);
+   }
+
    if (_config->FindB("APT::Get::Assume-Yes",false) == true)
    {
+      // TRANSLATOR: "Yes" answer printed for a yes/no question if --assume-yes is set
       c1out << _("Y") << endl;
       return true;
    }
    else if (_config->FindB("APT::Get::Assume-No",false) == true)
    {
+      // TRANSLATOR: "No" answer printed for a yes/no question if --assume-no is set
       c1out << _("N") << endl;
       return false;
    }
@@ -1076,7 +1105,7 @@ static bool CheckAuth(pkgAcquire& Fetcher)
    if (_config->FindI("quiet",0) < 2
        && _config->FindB("APT::Get::Assume-Yes",false) == false)
    {
-      c2out << _("Install these packages without verification [y/N]? ") << flush;
+      c2out << _("Install these packages without verification?") << flush;
       if (!YnPrompt(false))
          return _error->Error(_("Some packages could not be authenticated"));
 
@@ -1281,8 +1310,8 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
 	 if (_config->FindI("quiet",0) < 2 &&
 	     _config->FindB("APT::Get::Assume-Yes",false) == false)
 	 {
-	    c2out << _("Do you want to continue [Y/n]? ") << flush;
-	 
+	    c2out << _("Do you want to continue?") << flush;
+
 	    if (YnPrompt() == false)
 	    {
 	       c2out << _("Abort.") << endl;
@@ -1965,7 +1994,6 @@ bool DoInstall(CommandLine &CmdL)
       if (Fix != NULL)
       {
 	 // Call the scored problem resolver
-	 Fix->InstallProtect();
 	 Fix->Resolve(true);
 	 delete Fix;
       }
@@ -2297,9 +2325,10 @@ bool DoClean(CommandLine &CmdL)
    FileFd Lock;
    if (_config->FindB("Debug::NoLocking",false) == false)
    {
-      Lock.Fd(GetLock(archivedir + "lock"));
-      if (_error->PendingError() == true)
+      int lock_fd = GetLock(archivedir + "lock");
+      if (lock_fd < 0)
 	 return _error->Error(_("Unable to lock the download directory"));
+      Lock.Fd(lock_fd);
    }
    
    pkgAcquire Fetcher;
@@ -2333,9 +2362,10 @@ bool DoAutoClean(CommandLine &CmdL)
    FileFd Lock;
    if (_config->FindB("Debug::NoLocking",false) == false)
    {
-      Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
-      if (_error->PendingError() == true)
+      int lock_fd = GetLock(_config->FindDir("Dir::Cache::Archives") + "lock");
+      if (lock_fd < 0)
 	 return _error->Error(_("Unable to lock the download directory"));
+      Lock.Fd(lock_fd);
    }
    
    CacheFile Cache;
@@ -3126,8 +3156,7 @@ bool DoBuildDep(CommandLine &CmdL)
             }
 	 }	       
       }
-      
-      Fix.InstallProtect();
+
       if (Fix.Resolve(true) == false)
 	 _error->Discard();
       

+ 145 - 47
cmdline/apt-key

@@ -3,27 +3,39 @@
 set -e
 unset GREP_OPTIONS
 
-# We don't use a secret keyring, of course, but gpg panics and
-# implodes if there isn't one available
-SECRETKEYRING="$(mktemp)"
-trap "rm -f '${SECRETKEYRING}'" 0 HUP INT QUIT ILL ABRT FPE SEGV PIPE TERM
-GPG_CMD="gpg --ignore-time-conflict --no-options --no-default-keyring --secret-keyring ${SECRETKEYRING}"
-
-if [ "$(id -u)" -eq 0 ]; then
-	# we could use a tmpfile here too, but creation of this tends to be time-consuming
-	eval $(apt-config shell TRUSTDBDIR Dir::Etc/d)
-	GPG_CMD="$GPG_CMD --trustdb-name ${TRUSTDBDIR}/trustdb.gpg"
-fi
+GPG_CMD="gpg --ignore-time-conflict --no-options --no-default-keyring"
+
+# gpg needs a trustdb to function, but it can't be invalid (not even empty)
+# so we create a temporary directory to store our fresh readable trustdb in
+TRUSTDBDIR="$(mktemp -d)"
+CURRENTTRAP="${CURRENTTRAP} rm -rf '${TRUSTDBDIR}';"
+trap "${CURRENTTRAP}" 0 HUP INT QUIT ILL ABRT FPE SEGV PIPE TERM
+chmod 700 "$TRUSTDBDIR"
+# We also don't use a secret keyring, of course, but gpg panics and
+# implodes if there isn't one available - and writeable for imports
+SECRETKEYRING="${TRUSTDBDIR}/secring.gpg"
+touch $SECRETKEYRING
+GPG_CMD="$GPG_CMD --secret-keyring $SECRETKEYRING"
+GPG_CMD="$GPG_CMD --trustdb-name ${TRUSTDBDIR}/trustdb.gpg"
+
+# now create the trustdb with an (empty) dummy keyring
+$GPG_CMD --quiet --check-trustdb --keyring $SECRETKEYRING
+# and make sure that gpg isn't trying to update the file
+GPG_CMD="$GPG_CMD --no-auto-check-trustdb --trust-model always"
 
 GPG="$GPG_CMD"
 
 MASTER_KEYRING=""
-ARCHIVE_KEYRING_URI=""
 #MASTER_KEYRING=/usr/share/keyrings/debian-master-keyring.gpg
+eval $(apt-config shell MASTER_KEYRING APT::Key::MasterKeyring)
+ARCHIVE_KEYRING_URI=""
 #ARCHIVE_KEYRING_URI=http://ftp.debian.org/debian/debian-archive-keyring.gpg
+eval $(apt-config shell ARCHIVE_KEYRING_URI APT::Key::ArchiveKeyringURI)
 
 ARCHIVE_KEYRING=/usr/share/keyrings/debian-archive-keyring.gpg
+eval $(apt-config shell ARCHIVE_KEYRING APT::Key::ArchiveKeyring)
 REMOVED_KEYS=/usr/share/keyrings/debian-archive-removed-keys.gpg
+eval $(apt-config shell REMOVED_KEYS APT::Key::RemovedKeys)
 
 requires_root() {
 	if [ "$(id -u)" -ne 0 ]; then
@@ -32,6 +44,16 @@ requires_root() {
 	fi
 }
 
+# gpg defaults to mode 0600 for new keyrings. Create one with 0644 instead.
+init_keyring() {
+    for path; do
+        if ! [ -e "$path" ]; then
+            touch -- "$path"
+            chmod 0644 -- "$path"
+        fi
+    done
+}
+
 add_keys_with_verify_against_master_keyring() {
     ADD_KEYRING=$1
     MASTER=$2
@@ -129,6 +151,60 @@ update() {
     fi
 }
 
+remove_key_from_keyring() {
+    local GPG="$GPG_CMD --keyring $1"
+    # check if the key is in this keyring: the key id is in the 5 column at the end
+    if ! $GPG --with-colons --list-keys 2>&1 | grep -q "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]\+$2:"; then
+	return
+    fi
+    if [ ! -w "$1" ]; then
+	echo >&2 "Key ${2} is in keyring ${1}, but can't be removed as it is read only."
+	return
+    fi
+    # check if it is the only key in the keyring and if so remove the keyring alltogether
+    if [ '1' = "$($GPG --with-colons --list-keys | grep "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]\+:" | wc -l)" ]; then
+	mv -f "$1" "${1}~" # behave like gpg
+	return
+    fi
+    # we can't just modify pointed to files as these might be in /usr or something
+    local REALTARGET
+    if [ -L "$1" ]; then
+	REALTARGET="$(readlink -f "$1")"
+	mv -f "$1" "${1}.dpkg-tmp"
+	cp -a "$REALTARGET" "$1"
+	ls "$(dirname $1)"
+    fi
+    # delete the key from the keyring
+    $GPG --batch --delete-key --yes "$2"
+    if [ -n "$REALTARGET" ]; then
+	# the real backup is the old link, not the copy we made
+	mv -f "${1}.dpkg-tmp" "${1}~"
+    fi
+}
+
+remove_key() {
+    requires_root
+
+    # if a --keyring was given, just remove from there
+    if [ -n "$FORCED_KEYRING" ]; then
+	remove_key_from_keyring "$FORCED_KEYRING" "$1"
+    else
+	# otherwise all known keyrings are up for inspection
+	local TRUSTEDFILE="/etc/apt/trusted.gpg"
+	eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring)
+	eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f)
+	remove_key_from_keyring "$TRUSTEDFILE" "$1"
+	TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
+	eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
+	if [ -d "$TRUSTEDPARTS" ]; then
+	    for trusted in $(run-parts --list "$TRUSTEDPARTS" --regex '^.*\.gpg$'); do
+		remove_key_from_keyring "$trusted" "$1"
+	    done
+	fi
+    fi
+    echo "OK"
+}
+
 
 usage() {
     echo "Usage: apt-key [--keyring file] [command] [arguments]"
@@ -148,39 +224,54 @@ usage() {
     echo "If no specific keyring file is given the command applies to all keyring files."
 }
 
-# Determine on which keyring we want to work
-if [ "$1" = "--keyring" ]; then
-        #echo "keyfile given"
-	shift
-	TRUSTEDFILE="$1"
-	if [ -r "$TRUSTEDFILE" ] || [ "$2" = 'add' ]; then
-		GPG="$GPG --keyring $TRUSTEDFILE --primary-keyring $TRUSTEDFILE"
-	else
-		echo >&2 "Error: The specified keyring »$TRUSTEDFILE« is missing or not readable"
-		exit 1
-	fi
-	shift
-# otherwise use the default
-else
-	#echo "generate list"
-	TRUSTEDFILE="/etc/apt/trusted.gpg"
-	eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring)
-	eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f)
-	if [ -r "$TRUSTEDFILE" ]; then
-		GPG="$GPG --keyring $TRUSTEDFILE"
-	fi
-	GPG="$GPG --primary-keyring $TRUSTEDFILE"
-	TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
-	eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
-	if [ -d "$TRUSTEDPARTS" ]; then
-		#echo "parts active"
-		for trusted in $(run-parts --list $TRUSTEDPARTS --regex '^.*\.gpg$'); do
-			#echo "part -> $trusted"
-			GPG="$GPG --keyring $trusted"
-		done
-	fi
+while [ -n "$1" ]; do
+   case "$1" in
+      --keyring)
+	 shift
+	 TRUSTEDFILE="$1"
+	 FORCED_KEYRING="$1"
+	 if [ -r "$TRUSTEDFILE" ] || [ "$2" = 'add' ] || [ "$2" = 'adv' ]; then
+	    GPG="$GPG --keyring $TRUSTEDFILE --primary-keyring $TRUSTEDFILE"
+	 else
+	    echo >&2 "Error: The specified keyring »$TRUSTEDFILE« is missing or not readable"
+	    exit 1
+	 fi
+	 shift
+	 ;;
+      --fakeroot)
+	 requires_root() { true; }
+	 shift
+	 ;;
+      --*)
+	 echo >&2 "Unknown option: $1"
+	 usage
+	 exit 1;;
+      *)
+	 break;;
+   esac
+done
+
+if [ -z "$TRUSTEDFILE" ]; then
+   TRUSTEDFILE="/etc/apt/trusted.gpg"
+   eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring)
+   eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f)
+   if [ -r "$TRUSTEDFILE" ]; then
+      GPG="$GPG --keyring $TRUSTEDFILE"
+   fi
+   GPG="$GPG --primary-keyring $TRUSTEDFILE"
+   TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
+   eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
+   if [ -d "$TRUSTEDPARTS" ]; then
+      # strip / suffix as gpg will double-slash in that case (#665411)
+      STRIPPED_TRUSTEDPARTS="${TRUSTEDPARTS%/}"
+      if [ "${STRIPPED_TRUSTEDPARTS}/" = "$TRUSTEDPARTS" ]; then
+	 TRUSTEDPARTS="$STRIPPED_TRUSTEDPARTS"
+      fi
+      for trusted in $(run-parts --list "$TRUSTEDPARTS" --regex '^.*\.gpg$'); do
+	 GPG="$GPG --keyring $trusted"
+      done
+   fi
 fi
-#echo "COMMAND: $GPG"
 
 command="$1"
 if [ -z "$command" ]; then
@@ -198,33 +289,40 @@ fi
 case "$command" in
     add)
         requires_root
+        init_keyring "$TRUSTEDFILE"
         $GPG --quiet --batch --import "$1"
         echo "OK"
         ;;
     del|rm|remove)
-        requires_root
-        $GPG --quiet --batch --delete-key --yes "$1"
-        echo "OK"
+        init_keyring "$TRUSTEDFILE"
+	remove_key "$1"
         ;;
     update)
+        init_keyring "$TRUSTEDFILE"
 	update
 	;;
     net-update)
+        init_keyring "$TRUSTEDFILE"
 	net_update
 	;;
     list)
+        init_keyring "$TRUSTEDFILE"
         $GPG --batch --list-keys
         ;;
     finger*)
+        init_keyring "$TRUSTEDFILE"
         $GPG --batch --fingerprint
         ;;
     export)
+        init_keyring "$TRUSTEDFILE"
         $GPG --armor --export "$1"
         ;;
     exportall)
+        init_keyring "$TRUSTEDFILE"
         $GPG --armor --export
         ;;
     adv*)
+        init_keyring "$TRUSTEDFILE"
         echo "Executing: $GPG $*"
         $GPG $*
         ;;

+ 2 - 2
cmdline/apt-mark.cc

@@ -202,13 +202,13 @@ bool DoHold(CommandLine &CmdL)
    if (dpkgAssertMultiArch == 0)
    {
       std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory");
-      if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0)
-	 _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --assert-multi-arch", chrootDir.c_str());
       // redirect everything to the ultimate sink as we only need the exit-status
       int const nullfd = open("/dev/null", O_RDONLY);
       dup2(nullfd, STDIN_FILENO);
       dup2(nullfd, STDOUT_FILENO);
       dup2(nullfd, STDERR_FILENO);
+      if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0)
+	 _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --assert-multi-arch", chrootDir.c_str());
       execvp(Args[0], (char**) &Args[0]);
       _error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!");
       _exit(2);

+ 1 - 1
cmdline/makefile

@@ -14,7 +14,7 @@ include $(PROGRAM_H)
 
 # The apt-get program
 PROGRAM=apt-get
-SLIBS = -lapt-pkg -lutil $(INTLLIBS)
+SLIBS = -lapt-pkg $(INTLLIBS)
 LIB_MAKES = apt-pkg/makefile
 SOURCE = apt-get.cc acqprogress.cc
 include $(PROGRAM_H)

+ 3 - 7
configure.in

@@ -10,15 +10,15 @@ dnl need a C++ compiler that is semi-standard conformant, exceptions are
 dnl not used but STL is.
 
 dnl 'make -f Makefile startup' will generate the configure file from 
-dnl configure.in correctly and can be run at any time
+dnl configure.ac correctly and can be run at any time
 
 AC_PREREQ(2.50)
-AC_INIT(configure.in)
+AC_INIT(configure.ac)
 AC_CONFIG_AUX_DIR(buildlib)
 AC_CONFIG_HEADER(include/config.h:buildlib/config.h.in include/apti18n.h:buildlib/apti18n.h.in)
 
 PACKAGE="apt"
-PACKAGE_VERSION="0.9.8~exp1~20130301"
+PACKAGE_VERSION="0.9.10"
 PACKAGE_MAIL="APT Development Team <deity@lists.debian.org>"
 AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE")
 AC_DEFINE_UNQUOTED(PACKAGE_VERSION,"$PACKAGE_VERSION")
@@ -180,10 +180,6 @@ AC_SUBST(DOTDIR)
 ah_NUM_PROCS
 ah_GCC3DEP
 
-dnl It used to be that the user could select translations and that could get
-dnl passed to the makefiles, but now that can only work if you use special
-dnl gettext approved makefiles, so this feature is unsupported by this.
-ALL_LINGUAS="bg bs ca cs cy da de dz el es eu fi fr gl hu it ja ko ku nb nl nn pl pt_BR pt ro ru sk sl sv th tl uk vi zn_CN zh_TW"
 AM_GNU_GETTEXT(external)
 if test x"$USE_NLS" = "xyes"; then
    AC_DEFINE(USE_NLS)

+ 93 - 0
debian/apt.auto-removal.sh

@@ -0,0 +1,93 @@
+#!/bin/sh
+
+set -e
+
+# Author: Steve Langasek <steve.langasek@canonical.com>
+#
+# Mark as not-for-autoremoval those kernel packages that are:
+#  - the currently booted version
+#  - the kernel version we've been called for
+#  - the latest kernel version (determined using rules copied from the grub
+#    package for deciding which kernel to boot)
+#  - the second-latest kernel version, if the booted kernel version is
+#    already the latest and this script is called for that same version,
+#    to ensure a fallback remains available in the event the newly-installed
+#    kernel at this ABI fails to boot
+# In the common case, this results in exactly two kernels saved, but it can
+# result in three kernels being saved.  It's better to err on the side of
+# saving too many kernels than saving too few.
+#
+# We generate this list and save it to /etc/apt/apt.conf.d instead of marking
+# packages in the database because this runs from a postinst script, and apt
+# will overwrite the db when it exits.
+
+
+eval $(apt-config shell APT_CONF_D Dir::Etc::parts/d)
+test -n "${APT_CONF_D}" || APT_CONF_D="/etc/apt/apt.conf.d"
+config_file=${APT_CONF_D}/01autoremove-kernels
+
+eval $(apt-config shell DPKG Dir::bin::dpkg/f)
+test -n "$DPKG" || DPKG="/usr/bin/dpkg"
+
+installed_version="$1"
+running_version="$(uname -r)"
+
+
+version_test_gt ()
+{
+	local version_test_gt_sedexp="s/[._-]\(pre\|rc\|test\|git\|old\|trunk\)/~\1/g"
+	local version_a="`echo "$1" | sed -e "$version_test_gt_sedexp"`"
+	local version_b="`echo "$2" | sed -e "$version_test_gt_sedexp"`"
+	$DPKG --compare-versions "$version_a" gt "$version_b"
+	return "$?"
+}
+
+list=$(${DPKG} -l 'linux-image-[0-9]*'|awk '/^ii/ && $2 !~ /-dbg$/ { print $2 }' | sed -e's/linux-image-//')
+
+latest_version=""
+previous_version=""
+for i in $list; do
+	if version_test_gt "$i" "$latest_version"; then
+		previous_version="$latest_version"
+		latest_version="$i"
+	elif version_test_gt "$i" "$previous_version"; then
+		previous_version="$i"
+	fi
+done
+
+if [ "$latest_version" != "$installed_version" ] \
+   || [ "$latest_version" != "$running_version" ] \
+   || [ "$installed_version" != "$running_version" ]
+then
+	# We have at least two kernels that we have reason to think the
+	# user wants, so don't save the second-newest version.
+	previous_version=
+fi
+
+kernels=$(sort -u <<EOF
+$latest_version
+$installed_version
+$running_version
+$previous_version
+EOF
+)
+
+cat > "$config_file".dpkg-new <<EOF
+// File autogenerated by $0, do not edit
+APT
+{
+  NeverAutoRemove
+  {
+EOF
+for kernel in $kernels; do
+	echo "    \"^linux-image-${kernel}$\";" >> "$config_file".dpkg-new
+	echo "    \"^linux-image-extra-${kernel}$\";" >> "$config_file".dpkg-new
+	echo "    \"^linux-signed-image-${kernel}$\";" >> "$config_file".dpkg-new
+	echo "    \"^linux-backports-modules-.*-${kernel}$\";" >> "$config_file".dpkg-new
+	echo "    \"^linux-headers-${kernel}$\";" >> "$config_file".dpkg-new
+done
+cat >> "$config_file".dpkg-new <<EOF
+  };
+};
+EOF
+mv "$config_file".dpkg-new "$config_file"

+ 0 - 3
debian/apt.conf.autoremove

@@ -4,10 +4,7 @@ APT
   {
 	"^firmware-linux.*";
 	"^linux-firmware$";
-	"^linux-image.*";
 	"^kfreebsd-image.*";
-	"^linux-restricted-modules.*";
-	"^linux-ubuntu-modules-.*";
 	"^gnumach$";
 	"^gnumach-image.*";
   };

+ 1 - 0
debian/apt.dirs

@@ -7,6 +7,7 @@ etc/apt/apt.conf.d
 etc/apt/preferences.d
 etc/apt/sources.list.d
 etc/apt/trusted.gpg.d
+etc/kernel/postinst.d
 etc/logrotate.d
 var/cache/apt/archives/partial
 var/lib/apt/lists/partial

+ 13 - 5
debian/apt.postinst

@@ -15,12 +15,16 @@ set -e
 
 case "$1" in
     configure)
-	SECRING='/etc/apt/secring.gpg'
-	# test if secring is an empty normal file
-	if test -f $SECRING -a ! -s $SECRING; then
-		rm -f $SECRING
+	if dpkg --compare-versions "$2" lt-nl 0.9.9.5; then
+	    # we are using tmpfiles for both
+	    rm -f /etc/apt/trustdb.gpg
+	    # this removal was done unconditional since 0.8.15.3
+	    SECRING='/etc/apt/secring.gpg'
+	    # test if secring is an empty normal file
+	    if test -f $SECRING -a ! -s $SECRING; then
+	        rm -f $SECRING
+	    fi
 	fi
-	apt-key update
 
         # ensure tighter permissons on the logs, see LP: #975199
         if dpkg --compare-versions "$2" lt-nl 0.9.7.7; then
@@ -28,6 +32,10 @@ case "$1" in
             chmod -f 0640 /var/log/apt/term.log* || true
         fi
 
+        # create kernel autoremoval blacklist on update
+        if dpkg --compare-versions "$2" lt-nl 0.9.9.3; then
+            /etc/kernel/postinst.d/apt-auto-removal
+        fi
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)

+ 235 - 10
debian/changelog

@@ -1,9 +1,5 @@
-apt (0.9.8~exp1) UNRELEASED; urgency=low
+apt (0.9.10~exp1) UNRELEASED; urgency=low
 
-  [ David Kalnischkies ]
-  * apt-pkg/contrib/strutl.cc:
-    - support \n and \r\n line endings in ReadMessages
-  
   [ Daniel Hartwig ]
   * Clarify units of Acquire::http::Dl-Limit (closes: #705445)
   * Show a error message if {,dist-}upgrade is used with additional
@@ -27,14 +23,216 @@ apt (0.9.8~exp1) UNRELEASED; urgency=low
   * use sha512 when available (LP: #1098752)
   * [ABI-Break] lp:~mvo/apt/source-hashes:
     - use sha{512,256,1} for deb-src when available LP: #1098738
- 
-  [ Marc Deslauriers ]
-  * make apt-ftparchive generate missing deb-src hashes (LP: #1078697)
 
  -- Michael Vogt <mvo@debian.org>  Fri, 01 Mar 2013 12:12:39 +0100
 
-apt (0.9.7.9~exp3) UNRELEASED; urgency=low
+apt (0.9.10) unstable; urgency=low
+
+  The "Hello to Debconf" upload
+  
+  [ Christian Perrier ]
+  * Vietnamese translation update. Closes: #718615
+  * Japanese translation update. Closes: #719279
 
+  [ Michael Vogt ]
+  * work on fixing coverity scan results:
+    - fix some off-by-one errors
+    - fix some resource leaks
+    - fixes in chroot() handling
+    - fix some missing va_end()
+  * make the code -Wall clean again
+  * remove duplicated #include<list>
+  * add .travis.yml
+  * use the 'abi-complicance-checker' package and remove the buildin 
+    copy for the abi checks
+
+  [ David Kalnischkies ]
+  * ensure that FileFd::Size returns 0 in error cases
+  * add missing Turkish (tr) to po/LINGUAS
+  * correct management-typo in description found by lintian
+  * implement debian/rules build-{arch,indep} as required by policy 3.9.4
+  * reenable automatic parallel build of APT
+  * exclude config.{sub,guess} from source package
+  * update the symbol files to reflect current state
+  * unset LANGUAGE for showing [Y/n] answer hints
+  * fix some unitialized data members
+  * specific pins below 1000 cause downgrades (Closes: 543966)
+  * use pkgTagFile to parse "header" of Release files
+  * fix: --print-uris removes authentication (Closes: 719263)
+  * always use our own trustdb.gpg in apt-key
+  * use a tmpfile for trustdb.gpg in apt-key.
+    Thanks to Andreas Beckmann for the initial patch! (Closes: #687611)
+  * do not double-slash paths in apt-key (Closes: 665411)
+  * make the keyring locations in apt-key configurable
+  * let apt-key del work better with softlink and single key keyrings
+  * do not call 'apt-key update' in apt.postinst
+
+  [ Colin Watson ]
+  * prefer native arch over higher priority for providers (Closes: #718482)
+
+ -- Michael Vogt <mvo@debian.org>  Mon, 12 Aug 2013 21:45:07 +0200
+
+apt (0.9.9.4) unstable; urgency=low
+
+  [ David Kalnischkies ]
+  * pick up Translation-* even if only compressed available (Closes: 717665)
+  * request absolute URIs from proxies again (0.9.9.3 regession)
+    (Closes: 717891)
+  
+  [ Michael vogt ]
+  * fix missing changelog entry for 0.9.9.3 (git-dch issue)
+
+ -- Michael Vogt <mvo@debian.org>  Fri, 26 Jul 2013 09:58:17 +0200
+
+apt (0.9.9.3) unstable; urgency=low
+
+  [ Ben Hutchings ]
+  * debian/apt.auto-removal.sh:
+    - do not include debug symbol packages for the kernel in the 
+      blacklist (closes: #717616)
+  
+  [ Michael Vogt ]
+  * debian/apt.postinst:
+    - run /etc/kernel/postinst.d/apt-auto-removal once on upgrade
+      to ensure that the correct auto-removal list is generated
+      (closes: #717615)
+
+  [ David Kalnischkies ]
+  * skip all Description fields in apt-cache, not just first (Closes: 717254)
+  * fix 'apt-cache search' crash with missing description (Closes: 647590)
+
+  [ Raphael Geissert ]
+  * Do not send a connection: keep-alive, at all
+  
+ -- Michael Vogt <mvo@debian.org>  Thu, 25 Jul 2013 17:14:58 +0200
+
+apt (0.9.9.2) unstable; urgency=low
+
+  [ Programs translations ]
+  * Vietnamese updated by Tran Ngoc Quan. Closes: #717016
+
+  [ David Kalnischkies ]
+  * fix if-clause to generate hook-info for 'rc' packages (Closes: 717006)
+
+ -- Michael Vogt <mvo@debian.org>  Wed, 17 Jul 2013 14:56:34 +0200
+
+apt (0.9.9.1) unstable; urgency=low
+
+  [ Michael Vogt ]
+  * debian/rules:
+    - call dh_clean in clean (closes: #714980)
+  * apt-pkg/packagemanager.cc:
+    - increate APT::pkgPackageManager::MaxLoopCount to 5000
+  * cherry pick debian/apt.auto-removal.sh feature from the
+    ubuntu/master branch
+
+  [ Steve Langasek ]
+  * debian/apt.conf.autoremove: don't include linux-image*,
+    linux-restricted-modules*, and linux-ubuntu-modules* packages in the
+    list to never be autoremoved.
+  * debian/apt.auto-removal.sh, debian/rules, debian/apt.dirs: install new
+    script to /etc/kernel/postinst.d/ which ensures we only automatically
+    keep the currently-running kernel, the being-installed kernel, and the
+    newest kernel, so we don't fill /boot up with an unlimited number of
+    kernels.  LP: #923876.
+
+  [ Adam Conrad ]
+  * Fix up two things in debian/apt.auto-removal.sh:
+    - Use exact matches with $-terminated regexes, so we don't get
+      confusion between similarly-named kernel flavours.
+    - Keep linux-backports-modules in sync with installed kernels.
+
+  [ David Kalnischkies ]
+  * Version 3 for DPkg::Pre-Install-Pkgs with MultiArch info (Closes: #712116)
+  * implement arch+= and arch-= for sources.list
+  * prevent MarkInstall of unsynced Multi-Arch:same siblings
+
+ -- Michael Vogt <mvo@debian.org>  Thu, 11 Jul 2013 20:44:31 +0200
+
+apt (0.9.9) unstable; urgency=low
+
+  [ Michael Vogt ]
+  * improve debug output for the Debug::pkgProblemResolver and
+    Debug::pkgDepCache::AutoInstall
+  * improve apt-cdrom output when no CD-ROM can be auto-detected
+  * document --no-auto-detect in apt-cdrom
+
+  [ David Kalnischkies ]
+  * build the en manpages in subdirectory doc/en
+  * remove -ldl from cdrom and -lutil from apt-get linkage
+  * rewrite pkgOrderList::DepRemove to stop incorrect immediate setting
+    (Closes: 645713)
+  * prefer Essentials over Removals in ordering score
+  * fix priority sorting by prefering higher in MarkInstall
+  * try all providers in order if uninstallable in MarkInstall
+  * do unpacks before configures in SmartConfigure (Closes: #707578)
+  * fix support for multiple patterns in apt-cache search (Closes: #691453)
+  * set Fail flag in FileFd on all errors consistently
+  * don't explicitly init ExtractTar InFd with invalid fd
+  * OpenDescriptor should autoclose fd always on error (Closes: #704608)
+  * fail in CopyFile if the FileFds have error flag set
+  * ensure state-dir exists before coyping cdrom files
+  * fix file location for configure-index.gz in apt.conf(5) (Closes: #711921)
+  * handle missing "Description" in apt-cache show (Closes: #712435)
+  * try defaults if auto-detection failed in apt-cdrom (Closes: #712433)
+  * support \n and \r\n line endings in ReadMessages
+  * do not redownload unchanged InRelease files
+  * trigger NODATA error for invalid InRelease files (Closes: #712486)
+
+ -- Michael Vogt <mvo@debian.org>  Tue, 02 Jul 2013 08:58:33 +0200
+
+apt (0.9.8.2) unstable; urgency=low
+
+  [ Programs translations ]
+  * French translation : typo fix. Closes: #677272
+
+  [ Guillem Jover ]
+  * Update Vcs fields (Closes: #708562)
+  
+  [ Michael Vogt ]
+  * buildlib/apti18n.h.in:
+    - fix build failure when building without NLS (closes: #671587)
+  
+  [ Gregoire Menuel ]
+  * Fix double free (closes: #711045)
+  
+  [ Raphael Geissert ]
+  * Fix crash when the "mirror" method does not find any entry
+    (closes: #699303)
+
+  [ Johan Kiviniemi ]
+  * cmdline/apt-key:
+    - Create new keyrings with mode 0644 instead of 0600.
+    - Accept a nonexistent --keyring file with the adv subcommand as well.
+
+ -- Michael Vogt <mvo@debian.org>  Thu, 06 Jun 2013 19:15:14 +0200
+
+apt (0.9.8.1) unstable; urgency=low
+
+  [ David Kalnischkies ]
+  * apt-pkg/indexcopy.cc:
+    - non-inline RunGPGV methods to restore ABI compatibility with previous
+      versions to fix partial upgrades (Closes: #707771)
+  
+  [ Michael Vogt ]
+  * moved source to http://git.debian.org/apt/apt.git
+  * updated gbp.conf to match what bzr-buildpackage is doing
+  * remove .bzr-buildpackage/default.conf (superseeded by gbp.conf)
+
+ -- Michael Vogt <mvo@debian.org>  Thu, 16 May 2013 14:50:43 +0200
+
+apt (0.9.8) unstable; urgency=low
+
+  [ Ludovico Cavedon ]
+  * properly handle if-modfied-since with libcurl/https 
+    (closes: #705648)
+  
+  [ Andreas Beckman ]
+  * apt-pkg/algorithms.cc:
+    - Do not propagate negative scores from rdepends. Propagating the absolute
+      value of a negative score may boost obsolete packages and keep them
+      installed instead of installing their successors.  (Closes: #699759)
+  
   [ Michael Vogt ]
   * apt-pkg/sourcelist.cc:
     - fix segfault when a hostname contains a [, thanks to 
@@ -64,8 +262,35 @@ apt (0.9.7.9~exp3) UNRELEASED; urgency=low
 
   [ Marc Deslauriers ]
   * make apt-ftparchive generate missing deb-src hashes (LP: #1078697)
+  
+  [ Yaroslav Halchenko ]
+  * Fix English spelling error in a message ('A error'). Unfuzzy
+    translations. Closes: #705087
 
- -- Michael Vogt <mvo@debian.org>  Mon, 08 Apr 2013 08:43:21 +0200
+  [ Programs translations ]
+  * French translation completed (Christian Perrier)
+  
+  [ Manpages translations ]
+  * French translation completed (Christian Perrier)
+
+  [ Daniel Hartwig ]
+  * apt-pkg/contrib/strutl.cc:
+    - include port in shortened URIs (e.g. with apt-cache policy, progress
+      display) thanks to James McCoy (Closes: #154868, #322074)
+    - percent-encode username and password when writing URIs
+  * methods/http.cc:
+    - properly escape IP-literals (e.g. IPv6 address) when building
+      Host headers and URIs (Closes: #620344)
+  * methods/https.cc:
+    - use https_proxy environment variable if present, falling back to
+      http_proxy otherwise
+    - use authentication credentials from proxy URI
+      (Closes: #651640, LP: #1087512)
+    - environment variables do not override an explicit no proxy
+      directive ("DIRECT") in apt.conf
+    - disregard all_proxy environment variable, like other methods
+  
+ -- Michael Vogt <mvo@debian.org>  Wed, 08 May 2013 18:43:28 +0200
 
 apt (0.9.7.9~exp2) experimental; urgency=low
 

+ 7 - 7
debian/control

@@ -5,15 +5,15 @@ Maintainer: APT Development Team <deity@lists.debian.org>
 Uploaders: Michael Vogt <mvo@debian.org>, Otavio Salvador <otavio@debian.org>,
  Christian Perrier <bubulle@debian.org>, Daniel Burrows <dburrows@debian.org>,
  Julian Andres Klode <jak@debian.org>
-Standards-Version: 3.9.3
+Standards-Version: 3.9.4
 Build-Depends: dpkg-dev (>= 1.15.8), debhelper (>= 8.1.3~), libdb-dev,
- gettext (>= 0.12), libcurl4-gnutls-dev (>= 7.19.0),
+ gettext (>= 0.12), libcurl4-gnutls-dev (>= 7.19.4~),
  zlib1g-dev, libbz2-dev, xsltproc, docbook-xsl, docbook-xml,
  po4a (>= 0.34-2), autotools-dev, autoconf, automake
 Build-Depends-Indep: doxygen, debiandoc-sgml
 Build-Conflicts: autoconf2.13, automake1.4
-Vcs-Bzr: http://bzr.debian.org/apt/debian-sid/
-Vcs-Browser: http://bzr.debian.org/loggerhead/apt/debian-sid/
+Vcs-Git: git://anonscm.debian.org/apt/apt.git
+Vcs-Browser: http://anonscm.debian.org/gitweb/?p=apt/apt.git
 
 Package: apt
 Architecture: any
@@ -43,7 +43,7 @@ Pre-Depends: ${misc:Pre-Depends}
 Depends: ${shlibs:Depends}, ${misc:Depends}
 Breaks: apt (<< 0.9.4~)
 Section: libs
-Description: package managment runtime library
+Description: package management runtime library
  This library provides the common functionality for searching and
  managing packages as well as information about packages.
  Higher-level package managers can depend upon this library.
@@ -107,9 +107,9 @@ Package: apt-utils
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}
 Suggests: xz-utils
-Description: package managment related utility programs
+Description: package management related utility programs
  This package contains some less used commandline utilities related
- to package managment with APT.
+ to package management with APT.
  .
   * apt-extracttemplates is used by debconf to prompt for configuration
     questions before installation.

+ 6 - 0
debian/gbp.conf

@@ -0,0 +1,6 @@
+[DEFAULT]
+prebuild = ./prepare-release pre-export
+postbuild = ./prepare-release post-build
+export-dir = ../build-area
+debian-branch = debian/sid
+debian-tag = %(version)s

+ 1 - 5
debian/libapt-inst1.5.symbols

@@ -81,12 +81,8 @@ libapt-inst.so.1.5 libapt-inst1.5 #MINVER#
  (c++|optional)"vtable for pkgCache::VerIterator@Base" 0.8.0
  (c++|optional)"vtable for pkgCache::Iterator<pkgCache::Dependency, pkgCache::DepIterator>@Base" 0.8.0
  (c++|optional)"vtable for pkgCache::Iterator<pkgCache::Version, pkgCache::VerIterator>@Base" 0.8.0
-### gcc-4.4 specific
-# (c++|regex|optional=std)"^char\* std::[^ ]+<.+ >::_.+@Base$" 0.8.0
-# (c++|optional=std)"std::basic_string<char, std::char_traits<char>, std::allocator<char> >& std::basic_string<char, std::char_traits<char>, std::allocator<char> >::append<unsigned char*>(unsigned char*, unsigned char*)@Base" 0.8.0
-### gcc-4.6 specific
+### gcc artefacts
  (c++|optional=std)"std::vector<APT::Configuration::Compressor, std::allocator<APT::Configuration::Compressor> >::~vector()@Base" 0.8.12
- (c++|optional=std)"std::basic_string<char, std::char_traits<char>, std::allocator<char> >& std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace_dispatch<unsigned char*>(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, unsigned char*, unsigned char*, std::__false_type)@Base" 0.8.0
 ### try to ignore std:: template instances
  (c++|regex|optional=std)"^std::basic_string<.+ >\(.+\)@Base$" 0.8.0
  (c++|regex|optional=std)"^typeinfo name for std::iterator<.*>@Base$" 0.8.0

Разница между файлами не показана из-за своего большого размера
+ 52 - 69
debian/libapt-pkg4.13.symbols


+ 27 - 19
debian/rules

@@ -66,7 +66,7 @@ LIBAPT_INST=libapt-inst$(LIBAPTINST_MAJOR)
 # do not fail as we are just experimenting with symbol files for now
 export DPKG_GENSYMBOLS_CHECK_LEVEL=0
 
-build: build/build-stamp
+build-binary: build/build-binary-stamp
 build-debiandoc: build/build-debiandoc-stamp
 build-manpages: build/build-manpages-stamp
 
@@ -76,15 +76,15 @@ build-manpages: build/build-manpages-stamp
 build/environment.mak: build/configure-stamp
 	@true
 
-configure: configure.in
-build/configure-stamp: configure
+configure: configure.ac
+build/configure-stamp: configure buildlib/config.sub buildlib/config.guess
 	dh_testdir
 	-mkdir build
 	cp COPYING debian/copyright
 	cd build && CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" CPPFLAGS="$(CPPFLAGS)" ../configure $(confflags)
 	touch $@
 
-build/build-stamp: build/configure-stamp
+build/build-binary-stamp: build/configure-stamp
 	# Add here commands to compile the package.
 	$(MAKE) binary
 	# compat symlink for the locale split
@@ -110,16 +110,18 @@ build/build-manpages-stamp: build/configure-stamp
 
 clean:
 	dh_testdir
+	dh_clean
 
 	[ ! -f Makefile ] || $(MAKE) clean distclean
 	rm -rf build
 	rm -f debian/$(LIBAPT_PKG).install debian/$(LIBAPT_INST).install \
 	      debian/libapt-pkg-dev.install
+	test ! -L buildlib/config.guess || rm -f buildlib/config.guess
+	test ! -L buildlib/config.sub || rm -f buildlib/config.sub
 
 debian/%.install: debian/%.install.in
 	sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' $< > $@
 
-binary-indep: apt-doc libapt-pkg-doc
 # Build architecture-independent files here.
 libapt-pkg-doc: build-debiandoc
 	dh_testdir -p$@
@@ -171,9 +173,8 @@ apt-doc: build-debiandoc
 
 # Build architecture-dependent files here.
 
-binary-arch: $(LIBAPT_PKG) $(LIBAPT_INST) apt libapt-pkg-dev apt-utils apt-transport-https
 apt_MANPAGES = apt apt-cache apt-cdrom apt-config apt-get apt-key apt-mark apt-secure apt apt.conf apt_preferences sources.list
-apt: build build-manpages
+apt: build-binary build-manpages
 	dh_testdir -p$@
 	dh_testroot -p$@
 	dh_prep -p$@
@@ -182,6 +183,8 @@ apt: build build-manpages
 # apt install
 #
 	cp debian/apt.conf.autoremove debian/$@/etc/apt/apt.conf.d/01autoremove
+	cp debian/apt.auto-removal.sh debian/$@/etc/kernel/postinst.d/apt-auto-removal
+	chmod 755 debian/$@/etc/kernel/postinst.d/apt-auto-removal
 
 	# make rosetta happy and remove pot files in po/ (but leave stuff
 	# in po/domains/* untouched) and cp *.po into each domain dir
@@ -203,7 +206,7 @@ apt: build build-manpages
 	dh_bugfiles -p$@
 	dh_lintian -p$@
 	dh_installexamples -p$@ $(BLD)/docs/examples/*
-	dh_installman -p$@ $(wildcard $(patsubst %,doc/%.[158],$(apt_MANPAGES)) $(patsubst %,doc/*/%.*.[158],$(apt_MANPAGES)))
+	dh_installman -p$@ $(wildcard $(patsubst %,doc/en/%.[158],$(apt_MANPAGES)) $(patsubst %,doc/*/%.*.[158],$(apt_MANPAGES)))
 	dh_installcron -p$@
 	dh_installdocs -p$@
 	dh_installchangelogs -p$@
@@ -217,7 +220,7 @@ apt: build build-manpages
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 
-libapt-pkg-dev: build debian/libapt-pkg-dev.install
+libapt-pkg-dev: build-binary debian/libapt-pkg-dev.install
 	dh_testdir -p$@
 	dh_testroot -p$@
 	dh_prep -p$@
@@ -237,7 +240,7 @@ libapt-pkg-dev: build debian/libapt-pkg-dev.install
 	dh_builddeb -p$@
 
 apt-utils_MANPAGES = apt-sortpkgs apt-ftparchive apt-extracttemplates
-apt-utils: build build-manpages
+apt-utils: build-binary build-manpages
 	dh_testdir -p$@
 	dh_testroot -p$@
 	dh_prep -p$@
@@ -253,7 +256,7 @@ apt-utils: build build-manpages
 	dh_installexamples -p$@
 
 	# Install the man pages..
-	dh_installman -p$@ $(wildcard $(patsubst %,doc/%.[158],$(apt-utils_MANPAGES)) $(patsubst %,doc/*/%.*.[158],$(apt-utils_MANPAGES)))
+	dh_installman -p$@ $(wildcard $(patsubst %,doc/en/%.[158],$(apt-utils_MANPAGES)) $(patsubst %,doc/*/%.*.[158],$(apt-utils_MANPAGES)))
 
 	dh_installchangelogs -p$@
 	dh_strip -p$@
@@ -266,7 +269,7 @@ apt-utils: build build-manpages
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 
-$(LIBAPT_PKG): build debian/$(LIBAPT_PKG).install
+$(LIBAPT_PKG): build-binary debian/$(LIBAPT_PKG).install
 	dh_testdir -p$@
 	dh_testroot -p$@
 	dh_prep -p$@
@@ -285,7 +288,7 @@ $(LIBAPT_PKG): build debian/$(LIBAPT_PKG).install
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 
-$(LIBAPT_INST): build debian/$(LIBAPT_INST).install
+$(LIBAPT_INST): build-binary debian/$(LIBAPT_INST).install
 	dh_testdir -p$@
 	dh_testroot -p$@
 	dh_prep -p$@
@@ -304,7 +307,7 @@ $(LIBAPT_INST): build debian/$(LIBAPT_INST).install
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 
-apt-transport-https: build libapt-pkg-dev
+apt-transport-https: build-binary libapt-pkg-dev
 	dh_testdir -p$@
 	dh_testroot -p$@
 	dh_prep -p$@
@@ -327,13 +330,18 @@ apt-transport-https: build libapt-pkg-dev
 	dh_md5sums -p$@
 	dh_builddeb -p$@
 
+buildlib/config.guess buildlib/config.sub:
+	$(MAKE) "$@"
+
 configure:
 	$(MAKE) configure
 
-really-clean: clean
-	-find . -name Makefile.in -print0 | xargs --null --no-run-if-empty -- rm -f
-	find -name ChangeLog | xargs rm -f
-	rm -f l33ch-stamp
-
+# translate targets to targets required by debian-policy
+binary-arch: $(LIBAPT_PKG) $(LIBAPT_INST) apt libapt-pkg-dev apt-utils apt-transport-https
+binary-indep: apt-doc libapt-pkg-doc
 binary: binary-indep binary-arch
+build-arch: build-binary
+build-indep: build-manpages build-debiandoc
+build: build-indep build-arch
+
 .PHONY: build clean binary-indep binary-arch binary

Разница между файлами не показана из-за своего большого размера
+ 522 - 146
doc/Doxyfile.in


+ 8 - 0
doc/apt-cdrom.8.xml

@@ -81,6 +81,14 @@
    &apt-cmdblurb;
    
    <variablelist>
+     <varlistentry><term><option>--no-auto-detect</option></term><term><option>--cdrom</option></term>
+     <listitem><para>Do not try to auto-detect the CD-ROM path. Usually combined with the <option>--cdrom</option> option.
+      Configuration Item: <literal>Acquire::cdrom::AutoDetect</literal>.
+     </para>
+     </listitem>
+     </varlistentry>
+     
+
      <varlistentry><term><option>-d</option></term><term><option>--cdrom</option></term>
      <listitem><para>Mount point; specify the location to mount the CD-ROM. This
       mount point must be listed in <filename>/etc/fstab</filename> and

+ 1 - 1
doc/apt-verbatim.ent

@@ -213,7 +213,7 @@
 ">
 
 <!-- this will be updated by 'prepare-release' -->
-<!ENTITY apt-product-version "0.9.7.9~exp2">
+<!ENTITY apt-product-version "0.9.7.6ubuntu2">
 
 <!-- Codenames for debian releases -->
 <!ENTITY oldstable-codename "squeeze">

+ 11 - 6
doc/apt.conf.5.xml

@@ -98,8 +98,7 @@ APT {
 DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
 </programlisting></informalexample>
 
-   <para>In general the sample configuration file in 
-   <filename>&docdir;examples/apt.conf</filename> &configureindex;
+   <para>In general the sample configuration file &configureindex;
    is a good guide for how it should look.</para>
 
    <para>Case is not significant in names of configuration items, so in the
@@ -691,11 +690,17 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      will abort. APT will pass the filenames of all .deb files it is going to
      install to the commands, one per line on standard input.</para>
 
-     <para>Version 2 of this protocol dumps more information, including the 
+     <para>Version 2 of this protocol dumps more information, including the
      protocol version, the APT configuration space and the packages, files
-     and versions being changed. Version 2 is enabled by setting 
-     <literal>DPkg::Tools::options::cmd::Version</literal> to 2. <literal>cmd</literal> is a
-     command given to <literal>Pre-Install-Pkgs</literal>.</para></listitem>
+     and versions being changed. Version 3 adds the architecture and <literal>MultiArch</literal>
+     flag to each version being dumped.</para>
+
+     <para>The version of the protocol to be used for the command
+     <literal><replaceable>cmd</replaceable></literal> can be chosen by setting
+     <literal>DPkg::Tools::options::<replaceable>cmd</replaceable>::Version</literal>
+     accordingly, the default being version 1. If APT isn't supporting the requested
+     version it will send the information in the highest version it has support for instead.
+     </para></listitem>
      </varlistentry>
 
      <varlistentry><term><option>Run-Directory</option></term>

+ 38 - 0
doc/en/makefile

@@ -0,0 +1,38 @@
+# -*- make -*-
+BASE=../..
+SUBDIR=doc/en
+
+# Bring in the default rules
+include ../../buildlib/defaults.mak
+
+# Do not use XMLTO, build the manpages directly with XSLTPROC
+ifdef XSLTPROC
+# generate a list of accepted man page translations
+SOURCE = $(patsubst ../%.xml,%,$(wildcard ../*.?.xml))
+INCLUDES = ../apt.ent ../apt-verbatim.ent
+STYLESHEET=../manpage-style.xsl
+
+LOCAL := manpage-$(firstword $(SOURCE))
+$(LOCAL)-LIST := $(SOURCE)
+
+# Install generation hooks
+manpages: $($(LOCAL)-LIST) apt.8
+
+$($(LOCAL)-LIST) :: % : ../%.xml $(STYLESHEET) $(INCLUDES)
+	echo Creating man page $@
+	$(XSLTPROC) -o $@ $(STYLESHEET) $<
+
+apt.8: ../apt.8
+	cp -a ../apt.8 apt.8
+
+# Clean rule
+.PHONY: clean/$(LOCAL)
+veryclean: clean/$(LOCAL)
+clean: clean/$(LOCAL)
+clean/$(LOCAL):
+	-rm -rf $($(@F)-LIST) apt.8
+endif
+
+# Chain to the manpage rule
+SOURCE = apt.8
+include $(MANPAGE_H)

+ 1 - 1
doc/examples/configure-index

@@ -225,7 +225,7 @@ Acquire
 	Verify-Peer "false";
 	SslCert "/etc/apt/some.pem";
 	CaPath  "/etc/ssl/certs";
-	Verify-Host" "true";
+	Verify-Host "true";
 	AllowRedirect  "true";
 
 	Timeout "120";

+ 19 - 53
doc/makefile

@@ -1,7 +1,6 @@
 # -*- make -*-
 BASE=..
 SUBDIR=doc
-SUBDIRS= $(dir $(wildcard */makefile))
 
 # Bring in the default rules
 include ../buildlib/defaults.mak
@@ -13,34 +12,6 @@ include $(DEBIANDOC_H)
 
 doc: manpages debiandoc
 
-# Do not use XMLTO, build the manpages directly with XSLTPROC
-ifdef XSLTPROC
-# generate a list of accepted man page translations
-SOURCE = $(patsubst %.xml,%,$(wildcard *.?.xml))
-INCLUDES = apt.ent apt-verbatim.ent
-STYLESHEET=manpage-style.xsl
-
-LOCAL := manpage-$(firstword $(SOURCE))
-$(LOCAL)-LIST := $(SOURCE)
-
-# Install generation hooks
-manpages: $($(LOCAL)-LIST)
-
-$($(LOCAL)-LIST) :: % : %.xml $(STYLESHEET) $(INCLUDES)
-	echo Creating man page $@
-	$(XSLTPROC) -o $@ $(STYLESHEET) $<
-
-# Clean rule
-.PHONY: veryclean/$(LOCAL)
-veryclean: veryclean/$(LOCAL)
-veryclean/$(LOCAL):
-	-rm -rf $($(@F)-LIST)
-endif
-
-# Chain to the manpage rule
-SOURCE = apt.8
-include $(MANPAGE_H)
-
 examples/sources.list: examples/sources.list.in apt-verbatim.ent
 	sed -e 's#&stable-codename;#$(shell grep --max-count=1 '^<!ENTITY stable-codename "' apt-verbatim.ent | cut -d'"' -f 2)#g' examples/sources.list.in > examples/sources.list
 
@@ -50,42 +21,43 @@ TO = $(DOC)
 TARGET = binary
 include $(COPY_H)
 
-.PHONY: clean clean-subdirs veryclean veryclean-subdirs all binary doc stats
+.PHONY: clean clean/subdirs veryclean veryclean/subdirs manpages/subdirs debiandoc/subdirs all binary doc stats
 
-clean: clean-subdirs
-veryclean: veryclean-subdirs
+clean: clean/subdirs
+veryclean: veryclean/subdirs
+manpages: manpages/subdirs
+debiandoc: debiandoc/subdirs
 
-clean-subdirs:
-	for dir in $(SUBDIRS); do\
-		$(MAKE) -C $$dir clean; \
-	done
+DOCUMENTATIONPO = $(patsubst %.po,%,$(notdir $(wildcard po/*.po)))
+DOCDIRLIST = $(addsuffix /makefile,$(DOCUMENTATIONPO))
 
-veryclean-subdirs:
-	for dir in $(SUBDIRS); do\
-		rm -rf $$dir; \
+dirs: $(DOCDIRLIST)
+$(DOCDIRLIST) :: %/makefile : lang.makefile
+	test -d $(dir $@) || mkdir $(dir $@)
+	sed "s#@@LANG@@#$(subst /,,$(dir $@))#" $< > $@
+
+debiandoc/subdirs manpages/subdirs clean/subdirs veryclean/subdirs:
+	for dir in en $(dir $(DOCDIRLIST)); do \
+		$(MAKE) -C $$dir $(patsubst %/subdirs,%,$@); \
 	done
 
 stats:
 	for i in po/*.po; do echo -n "$$i: "; msgfmt --output-file=/dev/null --statistics $$i; done
 
 ifdef PO4A
-DOCUMENTATIONPO = $(patsubst %.po,%,$(notdir $(wildcard po/*.po)))
 MANPAGEPOLIST = $(addprefix manpages-translation-,$(DOCUMENTATIONPO))
 DEBIANDOCPOLIST = $(addprefix debiandoc-translation-,$(DOCUMENTATIONPO))
 
-MANPAGEDIRLIST = $(addsuffix /makefile,$(DOCUMENTATIONPO))
+.PHONY: update-po po4a $(MANPAGEPOLIST) $(DEBIANDOCPOLIST) $(DOCDIRLIST)
 
-.PHONY: update-po po4a $(MANPAGEPOLIST) $(MANPAGEDIRLIST)
-
-manpages: $(MANPAGEPOLIST)
-debiandoc: $(DEBIANDOCPOLIST)
-po4a: $(MANPAGEPOLIST) $(DEBIANDOCPOLIST)
+po4a: manpages/subdirs debiandoc/subdirs
 
 update-po:
 	po4a --previous --no-backups --force --no-translations \
 		--package-name='$(PACKAGE)-doc' --package-version='$(PACKAGE_VERSION)' \
 		--msgid-bugs-address='$(PACKAGE_MAIL)' po4a.conf
 
+manpages/subdirs: $(MANPAGEPOLIST)
 $(MANPAGEPOLIST) :: manpages-translation-% : %/makefile po4a.conf
 	# first line is for apt.8 (see Bug#696923)
 	po4a --previous --no-backups --translate-only $(dir $<)apt.ent \
@@ -100,19 +72,13 @@ $(MANPAGEPOLIST) :: manpages-translation-% : %/makefile po4a.conf
 		$(patsubst %,--translate-only $(dir $<)%,$(patsubst %.8.xml,%.$(subst /,,$(dir $<)).8.xml,$(wildcard *.8.xml))) \
 		--package-name='$(PACKAGE)-doc' --package-version='$(PACKAGE_VERSION)' \
 		--msgid-bugs-address='$(PACKAGE_MAIL)' po4a.conf
-	$(MAKE) -C $(dir $<) manpages
 
+debiandoc/subdirs: $(DEBIANDOCPOLIST)
 $(DEBIANDOCPOLIST) :: debiandoc-translation-% : %/makefile po4a.conf
 	po4a --previous --no-backups --translate-only $(dir $<)apt.ent \
 		$(patsubst %,--translate-only $(dir $<)%,$(patsubst %.sgml,%.$(subst /,,$(dir $<)).sgml,$(wildcard *.sgml))) \
 		--package-name='$(PACKAGE)-doc' --package-version='$(PACKAGE_VERSION)' \
 		--msgid-bugs-address='$(PACKAGE_MAIL)' po4a.conf
-	$(MAKE) -C $(dir $<) debiandoc
-
-dirs: $(MANPAGEDIRLIST)
-$(MANPAGEDIRLIST) :: %/makefile : lang.makefile
-	test -d $(dir $@) || mkdir $(dir $@)
-	sed "s#@@LANG@@#$(subst /,,$(dir $@))#" $< > $@
 endif
 
 ifdef DOXYGEN

Разница между файлами не показана из-за своего большого размера
+ 147 - 138
doc/po/apt-doc.pot


Разница между файлами не показана из-за своего большого размера
+ 179 - 180
doc/po/de.po


Разница между файлами не показана из-за своего большого размера
+ 161 - 162
doc/po/es.po


Разница между файлами не показана из-за своего большого размера
+ 168 - 169
doc/po/fr.po


Разница между файлами не показана из-за своего большого размера
+ 213 - 186
doc/po/it.po


Разница между файлами не показана из-за своего большого размера
+ 160 - 160
doc/po/ja.po


Разница между файлами не показана из-за своего большого размера
+ 153 - 153
doc/po/pl.po


Разница между файлами не показана из-за своего большого размера
+ 167 - 166
doc/po/pt.po


Разница между файлами не показана из-за своего большого размера
+ 153 - 153
doc/po/pt_BR.po


+ 5 - 1
doc/sources.list.5.xml

@@ -114,10 +114,14 @@
    <literal><replaceable>setting</replaceable>=<replaceable>value</replaceable></literal>.
    Multiple settings are separated by spaces. The following settings are supported by APT
    (note however that unsupported settings will be ignored silently):
-   <itemizedlist><listitem><para><literal>arch=<replaceable>arch1</replaceable>,<replaceable>arch2</replaceable>,…</literal>
+   <itemizedlist>
+   <listitem><para><literal>arch=<replaceable>arch1</replaceable>,<replaceable>arch2</replaceable>,…</literal>
    can be used to specify for which architectures information should
    be downloaded. If this option is not set all architectures defined by the
    <literal>APT::Architectures</literal> option will be downloaded.</para></listitem>
+   <listitem><para><literal>arch+=<replaceable>arch1</replaceable>,<replaceable>arch2</replaceable>,…</literal>
+   and <literal>arch-=<replaceable>arch1</replaceable>,<replaceable>arch2</replaceable>,…</literal>
+   which can be used to add/remove architectures from the set which will be downloaded.</para></listitem>
    <listitem><para><literal>trusted=yes</literal> can be set to indicate that packages
    from this source are always authenticated even if the <filename>Release</filename> file
    is not signed or the signature can't be checked. This disables parts of &apt-secure;

+ 2 - 1
ftparchive/writer.cc

@@ -284,7 +284,8 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
 		  if (link(FileName.c_str(),OriginalPath) != 0)
 		  {
 		     // Panic! Restore the symlink
-		     symlink(OldLink,OriginalPath);
+		     if (symlink(OldLink,OriginalPath) != 0)
+                        _error->Errno("symlink", "failed to restore symlink");
 		     return _error->Errno("link",_("*** Failed to link %s to %s"),
 					  FileName.c_str(),
 					  OriginalPath);

+ 1 - 0
methods/ftp.cc

@@ -436,6 +436,7 @@ bool FTPConn::WriteMsg(unsigned int &Ret,string &Text,const char *Fmt,...)
    char S[400];
    vsnprintf(S,sizeof(S) - 4,Fmt,args);
    strcat(S,"\r\n");
+   va_end(args);
  
    if (Debug == true)
       cerr << "-> '" << QuoteString(S,"") << "'" << endl;

+ 8 - 9
methods/gpgv.cc

@@ -55,9 +55,6 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
 					 vector<string> &NoPubKeySigners)
 {
    bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
-   // setup a (empty) stringstream for formating the return value
-   std::stringstream ret;
-   ret.str("");
 
    if (Debug == true)
       std::clog << "inside VerifyGetSigners" << std::endl;
@@ -155,6 +152,7 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
       }
    }
    fclose(pipein);
+   free(buffer);
 
    int status;
    waitpid(pid, &status, 0);
@@ -170,18 +168,19 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
       return "";
    }
    else if (WEXITSTATUS(status) == 1)
-   {
       return _("At least one invalid signature was encountered.");
-   }
    else if (WEXITSTATUS(status) == 111)
+      return _("Could not execute 'gpgv' to verify signature (is gpgv installed?)");
+   else if (WEXITSTATUS(status) == 112)
    {
-      ioprintf(ret, _("Could not execute 'gpgv' to verify signature (is gpgv installed?)"));
-      return ret.str();
+      // acquire system checks for "NODATA" to generate GPG errors (the others are only warnings)
+      std::string errmsg;
+      //TRANSLATORS: %s is a single techy word like 'NODATA'
+      strprintf(errmsg, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NODATA");
+      return errmsg;
    }
    else
-   {
       return _("Unknown error executing gpgv");
-   }
 }
 
 bool GPGVMethod::Fetch(FetchItem *Itm)

+ 27 - 28
methods/http.cc

@@ -667,7 +667,12 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
 
    // The HTTP server expects a hostname with a trailing :port
    char Buf[1000];
-   string ProperHost = Uri.Host;
+   string ProperHost;
+
+   if (Uri.Host.find(':') != string::npos)
+      ProperHost = '[' + Uri.Host + ']';
+   else
+      ProperHost = Uri.Host;
    if (Uri.Port != 0)
    {
       sprintf(Buf,":%u",Uri.Port);
@@ -677,28 +682,27 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
    // Just in case.
    if (Itm->Uri.length() >= sizeof(Buf))
        abort();
-       
-   /* Build the request. We include a keep-alive header only for non-proxy
-      requests. This is to tweak old http/1.0 servers that do support keep-alive
-      but not HTTP/1.1 automatic keep-alive. Doing this with a proxy server 
-      will glitch HTTP/1.0 proxies because they do not filter it out and 
-      pass it on, HTTP/1.1 says the connection should default to keep alive
-      and we expect the proxy to do this */
+
+   /* RFC 2616 §5.1.2 requires absolute URIs for requests to proxies,
+      but while its a must for all servers to accept absolute URIs,
+      it is assumed clients will sent an absolute path for non-proxies */
+   std::string requesturi;
    if (Proxy.empty() == true || Proxy.Host.empty())
-   {
-      // see LP bugs #1003633 and #1086997. The "+" is encoded as a workaround
-      // for a amazon S3 bug
-      sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
-	      QuoteString(Uri.Path,"+~ ").c_str(),ProperHost.c_str());
-   }
+      requesturi = Uri.Path;
    else
-   {
-      /* Generate a cache control header if necessary. We place a max
-       	 cache age on index files, optionally set a no-cache directive
-       	 and a no-store directive for archives. */
-      sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\n",
-	      Itm->Uri.c_str(),ProperHost.c_str());
-   }
+      requesturi = Itm->Uri;
+
+   // The "+" is encoded as a workaround for a amazon S3 bug
+   // see LP bugs #1003633 and #1086997.
+   requesturi = QuoteString(requesturi, "+~ ");
+
+   /* Build the request. No keep-alive is included as it is the default
+      in 1.1, can cause problems with proxies, and we are an HTTP/1.1
+      client anyway.
+      C.f. https://tools.ietf.org/wg/httpbis/trac/ticket/158 */
+   sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\n",
+	   requesturi.c_str(),ProperHost.c_str());
+
    // generate a cache control header (if needed)
    if (_config->FindB("Acquire::http::No-Cache",false) == true) 
    {
@@ -975,12 +979,7 @@ HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
       {
 	 URI Uri = Queue->Uri;
 	 if (Uri.Host.empty() == false)
-	 {
-	    if (Uri.Port != 0)
-	       strprintf(NextURI, "http://%s:%u", Uri.Host.c_str(), Uri.Port);
-	    else
-	       NextURI = "http://" + Uri.Host;
-	 }
+            NextURI = URI::SiteOnly(Uri);
 	 else
 	    NextURI.clear();
 	 NextURI.append(DeQuoteString(Srv->Location));
@@ -1401,7 +1400,7 @@ bool HttpMethod::AutoDetectProxy()
    char buf[512];
    int InFd = Pipes[0];
    close(Pipes[1]);
-   int res = read(InFd, buf, sizeof(buf));
+   int res = read(InFd, buf, sizeof(buf)-1);
    ExecWait(Process, "ProxyAutoDetect", true);
 
    if (res < 0)

+ 1 - 1
methods/http.h

@@ -158,7 +158,7 @@ class HttpMethod : public pkgAcqMethod
       ERROR_UNRECOVERABLE,
       /** \brief The server reported a error with a error content page */
       ERROR_WITH_CONTENT_PAGE,
-      /** \brief A error on the client side */
+      /** \brief An error on the client side */
       ERROR_NOT_FROM_SERVER,
       /** \brief A redirect or retry request */
       TRY_AGAIN_OR_REDIRECT 

+ 25 - 2
methods/https.cc

@@ -63,6 +63,12 @@ void HttpsMethod::SetupProxy()  					/*{{{*/
 {
    URI ServerName = Queue->Uri;
 
+   // Curl should never read proxy settings from the environment, as
+   // we determine which proxy to use.  Do this for consistency among
+   // methods and prevent an environment variable overriding a
+   // no-proxy ("DIRECT") setting in apt.conf.
+   curl_easy_setopt(curl, CURLOPT_PROXY, "");
+
    // Determine the proxy setting - try https first, fallback to http and use env at last
    string UseProxy = _config->Find("Acquire::https::Proxy::" + ServerName.Host,
 				   _config->Find("Acquire::http::Proxy::" + ServerName.Host).c_str());
@@ -81,7 +87,14 @@ void HttpsMethod::SetupProxy()  					/*{{{*/
       if (getenv("no_proxy") != 0 && CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
 	 return;
    } else {
-      const char* result = getenv("http_proxy");
+      const char* result = getenv("https_proxy");
+      // FIXME: Fall back to http_proxy is to remain compatible with
+      // existing setups and behaviour of apt.conf.  This should be
+      // deprecated in the future (including apt.conf).  Most other
+      // programs do not fall back to http proxy settings and neither
+      // should Apt.
+      if (result == NULL)
+         result = getenv("http_proxy");
       UseProxy = result == NULL ? "" : result;
    }
 
@@ -92,6 +105,11 @@ void HttpsMethod::SetupProxy()  					/*{{{*/
       if (Proxy.Port != 1)
 	 curl_easy_setopt(curl, CURLOPT_PROXYPORT, Proxy.Port);
       curl_easy_setopt(curl, CURLOPT_PROXY, Proxy.Host.c_str());
+      if (Proxy.User.empty() == false || Proxy.Password.empty() == false)
+      {
+         curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, Proxy.User.c_str());
+         curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, Proxy.Password.c_str());
+      }
    }
 }									/*}}}*/
 // HttpsMethod::Fetch - Fetch an item					/*{{{*/
@@ -285,6 +303,11 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    long curl_servdate;
    curl_easy_getinfo(curl, CURLINFO_FILETIME, &curl_servdate);
 
+   // If the server returns 200 OK but the If-Modified-Since condition is not
+   // met, CURLINFO_CONDITION_UNMET will be set to 1
+   long curl_condition_unmet = 0;
+   curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &curl_condition_unmet);
+
    File->Close();
 
    // cleanup
@@ -312,7 +335,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
       Res.Filename = File->Name();
       Res.LastModified = Buf.st_mtime;
       Res.IMSHit = false;
-      if (curl_responsecode == 304)
+      if (curl_responsecode == 304 || curl_condition_unmet)
       {
 	 unlink(File->Name().c_str());
 	 Res.IMSHit = true;

+ 1 - 1
methods/makefile

@@ -39,7 +39,7 @@ include $(PROGRAM_H)
 
 # The cdrom method
 PROGRAM=cdrom
-SLIBS = -lapt-pkg -ldl $(INTLLIBS)
+SLIBS = -lapt-pkg $(INTLLIBS)
 LIB_MAKES = apt-pkg/makefile
 SOURCE = cdrom.cc
 include $(PROGRAM_H)

+ 3 - 0
methods/mirror.cc

@@ -311,6 +311,9 @@ bool MirrorMethod::InitMirrors()
 
       AllMirrors.push_back(s);
    }
+   if (AllMirrors.empty()) {
+	return _error->Error(_("No entry found in mirror file '%s'"), MirrorFile.c_str());
+   }
    Mirror = AllMirrors[0];
    UsedMirror = Mirror;
    return true;

+ 2 - 0
methods/rsh.cc

@@ -218,6 +218,8 @@ bool RSHConn::WriteMsg(std::string &Text,bool Sync,const char *Fmt,...)
    // sprintf the description
    char S[512];
    vsnprintf(S,sizeof(S) - 4,Fmt,args);
+   va_end(args);
+
    if (Sync == true)
       strcat(S," 2> /dev/null || echo\n");
    else

+ 7 - 1
po/LINGUAS

@@ -1 +1,7 @@
-ar ast bg bs ca cs cy da de dz el es eu fi fr gl hu it ja km ko ku lt mr nb ne nl nn pl pt pt_BR ro ru sk sl sv th tl uk vi zh_CN zh_TW
+## If a language isn't listed here but a po file is available the build will fail.
+## If a language is disabled deliberately, list it in a line starting with a single '#'
+
+ar ast bg bs ca cs cy da de dz el es eu fi fr gl hu it ja km ko ku lt mr nb ne nl nn pl pt pt_BR ro ru sk sl sv th tl tr uk vi zh_CN zh_TW
+
+## disabled by translator request #313283:
+# he

Разница между файлами не показана из-за своего большого размера
+ 445 - 409
po/apt-all.pot


Разница между файлами не показана из-за своего большого размера
+ 448 - 416
po/ar.po



Некоторые файлы не были показаны из-за большого количества измененных файлов