Explorar el Código

Merge remote-tracking branch 'upstream/debian/sid' into debian/sid

Michael Vogt hace 11 años
padre
commit
68be2fbb25
Se han modificado 97 ficheros con 59786 adiciones y 58596 borrados
  1. 1 1
      apt-pkg/algorithms.cc
  2. 3 1
      apt-pkg/cacheiterators.h
  3. 10 1
      apt-pkg/cacheset.h
  4. 11 8
      apt-pkg/contrib/cmndline.cc
  5. 2 1
      apt-pkg/contrib/fileutl.cc
  6. 104 14
      apt-pkg/contrib/hashes.cc
  7. 83 1
      apt-pkg/contrib/hashes.h
  8. 118 44
      apt-pkg/deb/debsrcrecords.cc
  9. 1 0
      apt-pkg/deb/debsrcrecords.h
  10. 91 54
      apt-pkg/deb/dpkgpm.cc
  11. 1 1
      apt-pkg/depcache.cc
  12. 4 1
      apt-pkg/pkgcache.cc
  13. 30 1
      apt-pkg/srcrecords.cc
  14. 18 3
      apt-pkg/srcrecords.h
  15. 1 1
      apt-private/private-cmndline.cc
  16. 16 12
      cmdline/apt-get.cc
  17. 23 12
      cmdline/apt-helper.cc
  18. 1 1
      cmdline/apt-key.in
  19. 1 1
      configure.ac
  20. 1 1
      debian/apt.auto-removal.sh
  21. 86 0
      debian/changelog
  22. 10 0
      debian/libapt-pkg4.12.symbols
  23. 5 5
      doc/apt-verbatim.ent
  24. 2 2
      doc/po/apt-doc.pot
  25. 186 250
      doc/po/fr.po
  26. 3 3
      ftparchive/cachedb.cc
  27. 27 14
      ftparchive/sources.cc
  28. 9 17
      ftparchive/sources.h
  29. 2 10
      ftparchive/writer.cc
  30. 2 0
      methods/http.cc
  31. 17 4
      methods/https.cc
  32. 1 0
      methods/https.h
  33. 16 12
      methods/server.cc
  34. 3 2
      methods/server.h
  35. 1008 1013
      po/apt-all.pot
  36. 1212 1217
      po/ar.po
  37. 1310 1315
      po/ast.po
  38. 1311 1316
      po/bg.po
  39. 1111 1116
      po/bs.po
  40. 1318 1323
      po/ca.po
  41. 1309 1311
      po/cs.po
  42. 1309 1314
      po/cy.po
  43. 1296 1298
      po/da.po
  44. 1328 1330
      po/de.po
  45. 1303 1308
      po/dz.po
  46. 1296 1301
      po/el.po
  47. 1624 1559
      po/es.po
  48. 1295 1300
      po/eu.po
  49. 1296 1301
      po/fi.po
  50. 1520 1509
      po/fr.po
  51. 1311 1316
      po/gl.po
  52. 1306 1311
      po/hu.po
  53. 1326 1328
      po/it.po
  54. 1330 1325
      po/ja.po
  55. 1299 1304
      po/km.po
  56. 1305 1310
      po/ko.po
  57. 1136 1141
      po/ku.po
  58. 1250 1255
      po/lt.po
  59. 1301 1306
      po/mr.po
  60. 1310 1315
      po/nb.po
  61. 1304 1309
      po/ne.po
  62. 1700 1622
      po/nl.po
  63. 1299 1304
      po/nn.po
  64. 1311 1316
      po/pl.po
  65. 1316 1321
      po/pt.po
  66. 1302 1307
      po/pt_BR.po
  67. 1298 1303
      po/ro.po
  68. 1316 1321
      po/ru.po
  69. 1301 1306
      po/sk.po
  70. 1299 1304
      po/sl.po
  71. 1314 1319
      po/sv.po
  72. 1292 1294
      po/th.po
  73. 1302 1307
      po/tl.po
  74. 1369 1374
      po/tr.po
  75. 1326 1331
      po/uk.po
  76. 1326 1328
      po/vi.po
  77. 1545 1504
      po/zh_CN.po
  78. 1285 1290
      po/zh_TW.po
  79. 81 32
      test/integration/framework
  80. 28 0
      test/integration/test-allow-scores-for-all-dependency-types
  81. 43 0
      test/integration/test-apt-download-progress
  82. 0 4
      test/integration/test-apt-ftparchive-src-cachedb
  83. 4 0
      test/integration/test-apt-get-source
  84. 13 11
      test/integration/test-apt-helper
  85. 6 0
      test/integration/test-apt-key
  86. 36 31
      test/integration/test-apt-progress-fd
  87. 11 7
      test/integration/test-apt-progress-fd-deb822
  88. 1 1
      test/integration/test-apt-progress-fd-error
  89. 75 0
      test/integration/test-bug-769609-triggers-still-pending-after-run
  90. 1 45
      test/integration/test-failing-maintainer-scripts
  91. 119 0
      test/integration/test-no-fds-leaked-to-maintainer-scripts
  92. 56 6
      test/integration/test-partial-file-support
  93. 260 0
      test/integration/test-ubuntu-bug-1098738-apt-get-source-md5sum
  94. 116 65
      test/interactive-helper/aptwebserver.cc
  95. 68 0
      test/libapt/commandline_test.cc
  96. 52 12
      test/libapt/hashsums_test.cc
  97. 2 2
      test/libapt/makefile

+ 1 - 1
apt-pkg/algorithms.cc

@@ -468,7 +468,7 @@ void pkgProblemResolver::MakeScores()
 	 if (D->Version != 0)
 	 if (D->Version != 0)
 	 {
 	 {
 	    pkgCache::VerIterator const IV = Cache[T].InstVerIter(Cache);
 	    pkgCache::VerIterator const IV = Cache[T].InstVerIter(Cache);
-	    if (IV.end() == true || D.IsSatisfied(IV) != D.IsNegative())
+	    if (IV.end() == true || D.IsSatisfied(IV) == false)
 	       continue;
 	       continue;
 	 }
 	 }
 	 Scores[T->ID] += DepMap[D->Type];
 	 Scores[T->ID] += DepMap[D->Type];

+ 3 - 1
apt-pkg/cacheiterators.h

@@ -160,7 +160,9 @@ class pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
 
 
 	// Accessors
 	// Accessors
 	inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;}
 	inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;}
-	inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;}
+	// Versions have sections - and packages can have different versions with different sections
+	// so this interface is broken by design. Run as fast as you can to Version.Section().
+	APT_DEPRECATED inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;}
 	inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge ||
 	inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge ||
 		(S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);}
 		(S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);}
 	inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;}
 	inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;}

+ 10 - 1
apt-pkg/cacheset.h

@@ -118,7 +118,16 @@ public:
 		inline const char *Name() const {return getPkg().Name(); }
 		inline const char *Name() const {return getPkg().Name(); }
 		inline std::string FullName(bool const Pretty) const { return getPkg().FullName(Pretty); }
 		inline std::string FullName(bool const Pretty) const { return getPkg().FullName(Pretty); }
 		inline std::string FullName() const { return getPkg().FullName(); }
 		inline std::string FullName() const { return getPkg().FullName(); }
-		inline const char *Section() const {return getPkg().Section(); }
+		APT_DEPRECATED inline const char *Section() const {
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	   return getPkg().Section();
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+		}
 		inline bool Purge() const {return getPkg().Purge(); }
 		inline bool Purge() const {return getPkg().Purge(); }
 		inline const char *Arch() const {return getPkg().Arch(); }
 		inline const char *Arch() const {return getPkg().Arch(); }
 		inline pkgCache::GrpIterator Group() const { return getPkg().Group(); }
 		inline pkgCache::GrpIterator Group() const { return getPkg().Group(); }

+ 11 - 8
apt-pkg/contrib/cmndline.cc

@@ -47,23 +47,26 @@ CommandLine::~CommandLine()
 char const * CommandLine::GetCommand(Dispatch const * const Map,
 char const * CommandLine::GetCommand(Dispatch const * const Map,
       unsigned int const argc, char const * const * const argv)
       unsigned int const argc, char const * const * const argv)
 {
 {
-   // if there is a -- on the line there must be the word we search for around it
-   // as -- marks the end of the options, just not sure if the command can be
-   // considered an option or not, so accept both
+   // if there is a -- on the line there must be the word we search for either
+   // before it (as -- marks the end of the options) or right after it (as we can't
+   // decide if the command is actually an option, given that in theory, you could
+   // have parameters named like commands)
    for (size_t i = 1; i < argc; ++i)
    for (size_t i = 1; i < argc; ++i)
    {
    {
       if (strcmp(argv[i], "--") != 0)
       if (strcmp(argv[i], "--") != 0)
 	 continue;
 	 continue;
-      ++i;
-      if (i < argc)
+      // check if command is before --
+      for (size_t k = 1; k < i; ++k)
 	 for (size_t j = 0; Map[j].Match != NULL; ++j)
 	 for (size_t j = 0; Map[j].Match != NULL; ++j)
-	    if (strcmp(argv[i], Map[j].Match) == 0)
+	    if (strcmp(argv[k], Map[j].Match) == 0)
 	       return Map[j].Match;
 	       return Map[j].Match;
-      i -= 2;
-      if (i != 0)
+      // see if the next token after -- is the command
+      ++i;
+      if (i < argc)
 	 for (size_t j = 0; Map[j].Match != NULL; ++j)
 	 for (size_t j = 0; Map[j].Match != NULL; ++j)
 	    if (strcmp(argv[i], Map[j].Match) == 0)
 	    if (strcmp(argv[i], Map[j].Match) == 0)
 	       return Map[j].Match;
 	       return Map[j].Match;
+      // we found a --, but not a command
       return NULL;
       return NULL;
    }
    }
    // no --, so search for the first word matching a command
    // no --, so search for the first word matching a command

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

@@ -778,8 +778,9 @@ pid_t ExecFork(std::set<int> KeepFDs)
       signal(SIGCONT,SIG_DFL);
       signal(SIGCONT,SIG_DFL);
       signal(SIGTSTP,SIG_DFL);
       signal(SIGTSTP,SIG_DFL);
 
 
+      long ScOpenMax = sysconf(_SC_OPEN_MAX);
       // Close all of our FDs - just in case
       // Close all of our FDs - just in case
-      for (int K = 3; K != sysconf(_SC_OPEN_MAX); K++)
+      for (int K = 3; K != ScOpenMax; K++)
       {
       {
 	 if(KeepFDs.find(K) == KeepFDs.end())
 	 if(KeepFDs.find(K) == KeepFDs.end())
 	    fcntl(K,F_SETFD,FD_CLOEXEC);
 	    fcntl(K,F_SETFD,FD_CLOEXEC);

+ 104 - 14
apt-pkg/contrib/hashes.cc

@@ -27,7 +27,7 @@
 #include <iostream>
 #include <iostream>
 									/*}}}*/
 									/*}}}*/
 
 
-const char* HashString::_SupportedHashes[] = 
+const char * HashString::_SupportedHashes[] =
 {
 {
    "SHA512", "SHA256", "SHA1", "MD5Sum", NULL
    "SHA512", "SHA256", "SHA1", "MD5Sum", NULL
 };
 };
@@ -42,11 +42,16 @@ HashString::HashString(std::string Type, std::string Hash) : Type(Type), Hash(Ha
 
 
 HashString::HashString(std::string StringedHash)			/*{{{*/
 HashString::HashString(std::string StringedHash)			/*{{{*/
 {
 {
-   // legacy: md5sum without "MD5Sum:" prefix
-   if (StringedHash.find(":") == std::string::npos && StringedHash.size() == 32)
+   if (StringedHash.find(":") == std::string::npos)
    {
    {
-      Type = "MD5Sum";
-      Hash = StringedHash;
+      // legacy: md5sum without "MD5Sum:" prefix
+      if (StringedHash.size() == 32)
+      {
+	 Type = "MD5Sum";
+	 Hash = StringedHash;
+      }
+      if(_config->FindB("Debug::Hashes",false) == true)
+	 std::clog << "HashString(string): invalid StringedHash " << StringedHash << std::endl;
       return;
       return;
    }
    }
    std::string::size_type pos = StringedHash.find(":");
    std::string::size_type pos = StringedHash.find(":");
@@ -82,25 +87,25 @@ std::string HashString::GetHashForFile(std::string filename) const      /*{{{*/
    std::string fileHash;
    std::string fileHash;
 
 
    FileFd Fd(filename, FileFd::ReadOnly);
    FileFd Fd(filename, FileFd::ReadOnly);
-   if(Type == "MD5Sum")
+   if(strcasecmp(Type.c_str(), "MD5Sum") == 0)
    {
    {
       MD5Summation MD5;
       MD5Summation MD5;
       MD5.AddFD(Fd);
       MD5.AddFD(Fd);
       fileHash = (std::string)MD5.Result();
       fileHash = (std::string)MD5.Result();
    }
    }
-   else if (Type == "SHA1")
+   else if (strcasecmp(Type.c_str(), "SHA1") == 0)
    {
    {
       SHA1Summation SHA1;
       SHA1Summation SHA1;
       SHA1.AddFD(Fd);
       SHA1.AddFD(Fd);
       fileHash = (std::string)SHA1.Result();
       fileHash = (std::string)SHA1.Result();
    }
    }
-   else if (Type == "SHA256")
+   else if (strcasecmp(Type.c_str(), "SHA256") == 0)
    {
    {
       SHA256Summation SHA256;
       SHA256Summation SHA256;
       SHA256.AddFD(Fd);
       SHA256.AddFD(Fd);
       fileHash = (std::string)SHA256.Result();
       fileHash = (std::string)SHA256.Result();
    }
    }
-   else if (Type == "SHA512")
+   else if (strcasecmp(Type.c_str(), "SHA512") == 0)
    {
    {
       SHA512Summation SHA512;
       SHA512Summation SHA512;
       SHA512.AddFD(Fd);
       SHA512.AddFD(Fd);
@@ -111,20 +116,105 @@ std::string HashString::GetHashForFile(std::string filename) const      /*{{{*/
    return fileHash;
    return fileHash;
 }
 }
 									/*}}}*/
 									/*}}}*/
-const char** HashString::SupportedHashes()
+const char** HashString::SupportedHashes()				/*{{{*/
 {
 {
    return _SupportedHashes;
    return _SupportedHashes;
 }
 }
-
-APT_PURE bool HashString::empty() const
+									/*}}}*/
+APT_PURE bool HashString::empty() const					/*{{{*/
 {
 {
    return (Type.empty() || Hash.empty());
    return (Type.empty() || Hash.empty());
 }
 }
+									/*}}}*/
+std::string HashString::toStr() const					/*{{{*/
+{
+   return Type + ":" + Hash;
+}
+									/*}}}*/
+APT_PURE bool HashString::operator==(HashString const &other) const	/*{{{*/
+{
+   return (strcasecmp(Type.c_str(), other.Type.c_str()) == 0 && Hash == other.Hash);
+}
+APT_PURE bool HashString::operator!=(HashString const &other) const
+{
+   return !(*this == other);
+}
+									/*}}}*/
+
+HashString const * HashStringList::find(char const * const type) const /*{{{*/
+{
+   if (type == NULL || type[0] == '\0')
+   {
+      std::string forcedType = _config->Find("Acquire::ForceHash", "");
+      if (forcedType.empty() == false)
+	 return find(forcedType.c_str());
+      for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t)
+	 for (std::vector<HashString>::const_iterator hs = list.begin(); hs != list.end(); ++hs)
+	    if (strcasecmp(hs->HashType().c_str(), *t) == 0)
+	       return &*hs;
+      return NULL;
+   }
+   for (std::vector<HashString>::const_iterator hs = list.begin(); hs != list.end(); ++hs)
+      if (strcasecmp(hs->HashType().c_str(), type) == 0)
+	 return &*hs;
+   return NULL;
+}
+									/*}}}*/
+bool HashStringList::supported(char const * const type)			/*{{{*/
+{
+   for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t)
+      if (strcasecmp(*t, type) == 0)
+	 return true;
+   return false;
+}
+									/*}}}*/
+bool HashStringList::push_back(const HashString &hashString)		/*{{{*/
+{
+   if (hashString.HashType().empty() == true ||
+	 hashString.HashValue().empty() == true ||
+	 supported(hashString.HashType().c_str()) == false)
+      return false;
+
+   // ensure that each type is added only once
+   HashString const * const hs = find(hashString.HashType().c_str());
+   if (hs != NULL)
+      return *hs == hashString;
 
 
-std::string HashString::toStr() const
+   list.push_back(hashString);
+   return true;
+}
+									/*}}}*/
+bool HashStringList::VerifyFile(std::string filename) const		/*{{{*/
 {
 {
-   return Type + std::string(":") + Hash;
+   if (list.empty() == true)
+      return false;
+   HashString const * const hs = find(NULL);
+   if (hs == NULL || hs->VerifyFile(filename) == false)
+      return false;
+   return true;
 }
 }
+									/*}}}*/
+bool HashStringList::operator==(HashStringList const &other) const	/*{{{*/
+{
+   short matches = 0;
+   for (const_iterator hs = begin(); hs != end(); ++hs)
+   {
+      HashString const * const ohs = other.find(hs->HashType());
+      if (ohs == NULL)
+	 continue;
+      if (*hs != *ohs)
+	 return false;
+      ++matches;
+   }
+   if (matches == 0)
+      return false;
+   return true;
+}
+bool HashStringList::operator!=(HashStringList const &other) const
+{
+   return !(*this == other);
+}
+									/*}}}*/
 
 
 // Hashes::AddFD - Add the contents of the FD				/*{{{*/
 // Hashes::AddFD - Add the contents of the FD				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------

+ 83 - 1
apt-pkg/contrib/hashes.h

@@ -17,6 +17,7 @@
 #include <apt-pkg/md5.h>
 #include <apt-pkg/md5.h>
 #include <apt-pkg/sha1.h>
 #include <apt-pkg/sha1.h>
 #include <apt-pkg/sha2.h>
 #include <apt-pkg/sha2.h>
+#include <apt-pkg/macros.h>
 
 
 #include <cstring>
 #include <cstring>
 #include <string>
 #include <string>
@@ -41,7 +42,7 @@ class HashString
  protected:
  protected:
    std::string Type;
    std::string Type;
    std::string Hash;
    std::string Hash;
-   static const char* _SupportedHashes[10];
+   static const char * _SupportedHashes[10];
 
 
    // internal helper
    // internal helper
    std::string GetHashForFile(std::string filename) const;
    std::string GetHashForFile(std::string filename) const;
@@ -53,6 +54,8 @@ class HashString
 
 
    // get hash type used
    // get hash type used
    std::string HashType() { return Type; };
    std::string HashType() { return Type; };
+   std::string HashType() const { return Type; };
+   std::string HashValue() const { return Hash; };
 
 
    // verify the given filename against the currently loaded hash
    // verify the given filename against the currently loaded hash
    bool VerifyFile(std::string filename) const;
    bool VerifyFile(std::string filename) const;
@@ -64,11 +67,90 @@ class HashString
    // helper
    // helper
    std::string toStr() const;                    // convert to str as "type:hash"
    std::string toStr() const;                    // convert to str as "type:hash"
    bool empty() const;
    bool empty() const;
+   bool operator==(HashString const &other) const;
+   bool operator!=(HashString const &other) const;
 
 
    // return the list of hashes we support
    // return the list of hashes we support
    static APT_CONST const char** SupportedHashes();
    static APT_CONST const char** SupportedHashes();
 };
 };
 
 
+class HashStringList
+{
+   public:
+   /** find best hash if no specific one is requested
+    *
+    * @param type of the checksum to return, can be \b NULL
+    * @return If type is \b NULL (or the empty string) it will
+    *  return the 'best' hash; otherwise the hash which was
+    *  specifically requested. If no hash is found \b NULL will be returned.
+    */
+   HashString const * find(char const * const type) const;
+   HashString const * find(std::string const &type) const { return find(type.c_str()); }
+   /** check if the given hash type is supported
+    *
+    * @param type to check
+    * @return true if supported, otherwise false
+    */
+   static APT_PURE bool supported(char const * const type);
+   /** add the given #HashString to the list
+    *
+    * @param hashString to add
+    * @return true if the hash is added because it is supported and
+    *  not already a different hash of the same type included, otherwise false
+    */
+   bool push_back(const HashString &hashString);
+   /** @return size of the list of HashStrings */
+   size_t size() const { return list.size(); }
+
+   /** take the 'best' hash and verify file with it
+    *
+    * @param filename to verify
+    * @return true if the file matches the hashsum, otherwise false
+    */
+   bool VerifyFile(std::string filename) const;
+
+   /** is the list empty ?
+    *
+    * @return \b true if the list is empty, otherwise \b false
+    */
+   bool empty() const { return list.empty(); }
+
+   typedef std::vector<HashString>::const_iterator const_iterator;
+
+   /** iterator to the first element */
+   const_iterator begin() const { return list.begin(); }
+
+   /** iterator to the end element */
+   const_iterator end() const { return list.end(); }
+
+   /** start fresh with a clear list */
+   void clear() { list.clear(); }
+
+   /** compare two HashStringList for similarity.
+    *
+    * Two lists are similar if at least one hashtype is in both lists
+    * and the hashsum matches. All hashes are checked, if one doesn't
+    * match false is returned regardless of how many matched before.
+    */
+   bool operator==(HashStringList const &other) const;
+   bool operator!=(HashStringList const &other) const;
+
+   HashStringList() {}
+
+   // simplifying API-compatibility constructors
+   HashStringList(std::string const &hash) {
+      if (hash.empty() == false)
+	 list.push_back(HashString(hash));
+   }
+   HashStringList(char const * const hash) {
+      if (hash != NULL && hash[0] != '\0')
+	 list.push_back(HashString(hash));
+   }
+
+   private:
+   std::vector<HashString> list;
+};
+
 class Hashes
 class Hashes
 {
 {
    public:
    public:

+ 118 - 44
apt-pkg/deb/debsrcrecords.cc

@@ -118,13 +118,32 @@ bool debSrcRecordParser::BuildDepends(std::vector<pkgSrcRecords::Parser::BuildDe
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This parses the list of files and returns it, each file is required to have
 /* This parses the list of files and returns it, each file is required to have
    a complete source package */
    a complete source package */
-bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &List)
+bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &F)
 {
 {
-   List.erase(List.begin(),List.end());
-   
-   string Files = Sect.FindS("Files");
-   if (Files.empty() == true)
+   std::vector<pkgSrcRecords::File2> F2;
+   if (Files2(F2) == false)
       return false;
       return false;
+   for (std::vector<pkgSrcRecords::File2>::const_iterator f2 = F2.begin(); f2 != F2.end(); ++f2)
+   {
+      pkgSrcRecords::File2 f;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+      f.MD5Hash = f2->MD5Hash;
+      f.Size = f2->Size;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+      f.Path = f2->Path;
+      f.Type = f2->Type;
+      F.push_back(f);
+   }
+   return true;
+}
+bool debSrcRecordParser::Files2(std::vector<pkgSrcRecords::File2> &List)
+{
+   List.clear();
 
 
    // Stash the / terminated directory prefix
    // Stash the / terminated directory prefix
    string Base = Sect.FindS("Directory");
    string Base = Sect.FindS("Directory");
@@ -133,51 +152,106 @@ bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &List)
 
 
    std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions();
    std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions();
 
 
-   // Iterate over the entire list grabbing each triplet
-   const char *C = Files.c_str();
-   while (*C != 0)
-   {   
-      pkgSrcRecords::File F;
-      string Size;
-      
-      // Parse each of the elements
-      if (ParseQuoteWord(C,F.MD5Hash) == false ||
-	  ParseQuoteWord(C,Size) == false ||
-	  ParseQuoteWord(C,F.Path) == false)
-	 return _error->Error("Error parsing file record");
-      
-      // Parse the size and append the directory
-      F.Size = atoi(Size.c_str());
-      F.Path = Base + F.Path;
-      
-      // Try to guess what sort of file it is we are getting.
-      string::size_type Pos = F.Path.length()-1;
-      while (1)
+   for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+   {
+      // derive field from checksum type
+      std::string checksumField("Checksums-");
+      if (strcmp(*type, "MD5Sum") == 0)
+	 checksumField = "Files"; // historic name for MD5 checksums
+      else
+	 checksumField.append(*type);
+
+      string const Files = Sect.FindS(checksumField.c_str());
+      if (Files.empty() == true)
+	 continue;
+
+      // Iterate over the entire list grabbing each triplet
+      const char *C = Files.c_str();
+      while (*C != 0)
       {
       {
-	 string::size_type Tmp = F.Path.rfind('.',Pos);
-	 if (Tmp == string::npos)
-	    break;
-	 if (F.Type == "tar") {
-	    // source v3 has extension 'debian.tar.*' instead of 'diff.*'
-	    if (string(F.Path, Tmp+1, Pos-Tmp) == "debian")
-	       F.Type = "diff";
-	    break;
-	 }
-	 F.Type = string(F.Path,Tmp+1,Pos-Tmp);
-	 
-	 if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() ||
-	     F.Type == "tar")
+	 string hash, size, path;
+
+	 // Parse each of the elements
+	 if (ParseQuoteWord(C, hash) == false ||
+	       ParseQuoteWord(C, size) == false ||
+	       ParseQuoteWord(C, path) == false)
+	    return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
+
+	 HashString const hashString(*type, hash);
+	 if (Base.empty() == false)
+	    path = Base + path;
+
+	 // look if we have a record for this file already
+	 std::vector<pkgSrcRecords::File2>::iterator file = List.begin();
+	 for (; file != List.end(); ++file)
+	    if (file->Path == path)
+	       break;
+
+	 // we have it already, store the new hash and be done
+	 if (file != List.end())
 	 {
 	 {
-	    Pos = Tmp-1;
+#if __GNUC__ >= 4
+	// set for compatibility only, so warn users not us
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	    if (checksumField == "Files")
+	       file->MD5Hash = hash;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+	    // an error here indicates that we have two different hashes for the same file
+	    if (file->Hashes.push_back(hashString) == false)
+	       return _error->Error("Error parsing checksum in %s of source package %s", checksumField.c_str(), Package().c_str());
 	    continue;
 	    continue;
 	 }
 	 }
-	 
-	 break;
+
+	 // we haven't seen this file yet
+	 pkgSrcRecords::File2 F;
+	 F.Path = path;
+	 F.FileSize = strtoull(size.c_str(), NULL, 10);
+	 F.Hashes.push_back(hashString);
+
+#if __GNUC__ >= 4
+	// set for compatibility only, so warn users not us
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	 F.Size = F.FileSize;
+	 if (checksumField == "Files")
+	    F.MD5Hash = hash;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+
+	 // Try to guess what sort of file it is we are getting.
+	 string::size_type Pos = F.Path.length()-1;
+	 while (1)
+	 {
+	    string::size_type Tmp = F.Path.rfind('.',Pos);
+	    if (Tmp == string::npos)
+	       break;
+	    if (F.Type == "tar") {
+	       // source v3 has extension 'debian.tar.*' instead of 'diff.*'
+	       if (string(F.Path, Tmp+1, Pos-Tmp) == "debian")
+		  F.Type = "diff";
+	       break;
+	    }
+	    F.Type = string(F.Path,Tmp+1,Pos-Tmp);
+
+	    if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() ||
+		  F.Type == "tar")
+	    {
+	       Pos = Tmp-1;
+	       continue;
+	    }
+
+	    break;
+	 }
+	 List.push_back(F);
       }
       }
-      
-      List.push_back(F);
    }
    }
-   
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 1 - 0
apt-pkg/deb/debsrcrecords.h

@@ -53,6 +53,7 @@ class debSrcRecordParser : public pkgSrcRecords::Parser
       return std::string(Start,Stop);
       return std::string(Start,Stop);
    };
    };
    virtual bool Files(std::vector<pkgSrcRecords::File> &F);
    virtual bool Files(std::vector<pkgSrcRecords::File> &F);
+   bool Files2(std::vector<pkgSrcRecords::File2> &F);
 
 
    debSrcRecordParser(std::string const &File,pkgIndexFile const *Index) 
    debSrcRecordParser(std::string const &File,pkgIndexFile const *Index) 
       : Parser(Index), Fd(File,FileFd::ReadOnly, FileFd::Extension), Tags(&Fd,102400),
       : Parser(Index), Fd(File,FileFd::ReadOnly, FileFd::Extension), Tags(&Fd,102400),

+ 91 - 54
apt-pkg/deb/dpkgpm.cc

@@ -72,7 +72,9 @@ class pkgDPkgPMPrivate
 public:
 public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
 			term_out(NULL), history_out(NULL),
 			term_out(NULL), history_out(NULL),
-                        progress(NULL), master(-1), slave(NULL)
+			progress(NULL), tt_is_valid(false), master(-1),
+			slave(NULL), protect_slave_from_dying(-1),
+			direct_stdin(false)
    {
    {
       dpkgbuf[0] = '\0';
       dpkgbuf[0] = '\0';
    }
    }
@@ -90,13 +92,16 @@ public:
 
 
    // pty stuff
    // pty stuff
    struct termios tt;
    struct termios tt;
+   bool tt_is_valid;
    int master;
    int master;
    char * slave;
    char * slave;
+   int protect_slave_from_dying;
 
 
    // signals
    // signals
    sigset_t sigmask;
    sigset_t sigmask;
    sigset_t original_sigmask;
    sigset_t original_sigmask;
 
 
+   bool direct_stdin;
 };
 };
 
 
 namespace
 namespace
@@ -1044,6 +1049,12 @@ void pkgDPkgPM::BuildPackagesProgressMap()
 	 PackagesTotal++;
 	 PackagesTotal++;
       }
       }
    }
    }
+   /* one extra: We don't want the progress bar to reach 100%, especially not
+      if we call dpkg --configure --pending and process a bunch of triggers
+      while showing 100%. Also, spindown takes a while, so never reaching 100%
+      is way more correct than reaching 100% while still doing stuff even if
+      doing it this way is slightly bending the rules */
+   ++PackagesTotal;
 }
 }
                                                                         /*}}}*/
                                                                         /*}}}*/
 #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
 #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
@@ -1070,48 +1081,44 @@ void pkgDPkgPM::StartPtyMagic()
       return;
       return;
    }
    }
 
 
+   if (isatty(STDIN_FILENO) == 0)
+      d->direct_stdin = true;
+
    _error->PushToStack();
    _error->PushToStack();
-   // if tcgetattr for both stdin/stdout returns 0 (no error)
-   // we do the pty magic
-   if (tcgetattr(STDOUT_FILENO, &d->tt) == 0 &&
-	 tcgetattr(STDIN_FILENO, &d->tt) == 0)
+
+   d->master = posix_openpt(O_RDWR | O_NOCTTY);
+   if (d->master == -1)
+      _error->Errno("posix_openpt", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+   else if (unlockpt(d->master) == -1)
+      _error->Errno("unlockpt", "Unlocking the slave of master fd %d failed!", d->master);
+   else
    {
    {
-      d->master = posix_openpt(O_RDWR | O_NOCTTY);
-      if (d->master == -1)
-	 _error->Errno("posix_openpt", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
-      else if (unlockpt(d->master) == -1)
-      {
-	 _error->Errno("unlockpt", "Unlocking the slave of master fd %d failed!", d->master);
-	 close(d->master);
-	 d->master = -1;
-      }
+      char const * const slave_name = ptsname(d->master);
+      if (slave_name == NULL)
+	 _error->Errno("ptsname", "Getting name for slave of master fd %d failed!", d->master);
       else
       else
       {
       {
-	 char const * const slave_name = ptsname(d->master);
-	 if (slave_name == NULL)
+	 d->slave = strdup(slave_name);
+	 if (d->slave == NULL)
+	    _error->Errno("strdup", "Copying name %s for slave of master fd %d failed!", slave_name, d->master);
+	 else if (grantpt(d->master) == -1)
+	    _error->Errno("grantpt", "Granting access to slave %s based on master fd %d failed!", slave_name, d->master);
+	 else if (tcgetattr(STDIN_FILENO, &d->tt) == 0)
 	 {
 	 {
-	    _error->Errno("unlockpt", "Getting name for slave of master fd %d failed!", d->master);
-	    close(d->master);
-	    d->master = -1;
-	 }
-	 else
-	 {
-	    d->slave = strdup(slave_name);
-	    if (d->slave == NULL)
+	    d->tt_is_valid = true;
+	    struct termios raw_tt;
+	    // copy window size of stdout if its a 'good' terminal
+	    if (tcgetattr(STDOUT_FILENO, &raw_tt) == 0)
 	    {
 	    {
-	       _error->Errno("strdup", "Copying name %s for slave of master fd %d failed!", slave_name, d->master);
-	       close(d->master);
-	       d->master = -1;
+	       struct winsize win;
+	       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) < 0)
+		  _error->Errno("ioctl", "Getting TIOCGWINSZ from stdout failed!");
+	       if (ioctl(d->master, TIOCSWINSZ, &win) < 0)
+		  _error->Errno("ioctl", "Setting TIOCSWINSZ for master fd %d failed!", d->master);
 	    }
 	    }
-	    struct winsize win;
-	    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) < 0)
-	       _error->Errno("ioctl", "Getting TIOCGWINSZ from stdout failed!");
-	    if (ioctl(d->master, TIOCSWINSZ, &win) < 0)
-	       _error->Errno("ioctl", "Setting TIOCSWINSZ for master fd %d failed!", d->master);
 	    if (tcsetattr(d->master, TCSANOW, &d->tt) == -1)
 	    if (tcsetattr(d->master, TCSANOW, &d->tt) == -1)
 	       _error->Errno("tcsetattr", "Setting in Start via TCSANOW for master fd %d failed!", d->master);
 	       _error->Errno("tcsetattr", "Setting in Start via TCSANOW for master fd %d failed!", d->master);
 
 
-	    struct termios raw_tt;
 	    raw_tt = d->tt;
 	    raw_tt = d->tt;
 	    cfmakeraw(&raw_tt);
 	    cfmakeraw(&raw_tt);
 	    raw_tt.c_lflag &= ~ECHO;
 	    raw_tt.c_lflag &= ~ECHO;
@@ -1123,18 +1130,22 @@ void pkgDPkgPM::StartPtyMagic()
 	    sigaddset(&d->sigmask, SIGTTOU);
 	    sigaddset(&d->sigmask, SIGTTOU);
 	    sigprocmask(SIG_BLOCK,&d->sigmask, &d->original_sigmask);
 	    sigprocmask(SIG_BLOCK,&d->sigmask, &d->original_sigmask);
 	    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_tt) == -1)
 	    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_tt) == -1)
-	       _error->Errno("tcsetattr", "Setting in Start via TCSAFLUSH for stdout failed!");
+	       _error->Errno("tcsetattr", "Setting in Start via TCSAFLUSH for stdin failed!");
 	    sigprocmask(SIG_SETMASK, &d->original_sigmask, NULL);
 	    sigprocmask(SIG_SETMASK, &d->original_sigmask, NULL);
+
+	 }
+	 if (d->slave != NULL)
+	 {
+	    /* on linux, closing (and later reopening) all references to the slave
+	       makes the slave a death end, so we open it here to have one open all
+	       the time. We could use this fd in SetupSlavePtyMagic() for linux, but
+	       on kfreebsd we get an incorrect ("step like") output then while it has
+	       no problem with closing all references… so to avoid platform specific
+	       code here we combine both and be happy once more */
+	    d->protect_slave_from_dying = open(d->slave, O_RDWR | O_CLOEXEC | O_NOCTTY);
 	 }
 	 }
       }
       }
    }
    }
-   else
-   {
-      // 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.
-      if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
-	 _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
-   }
 
 
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
    {
    {
@@ -1143,44 +1154,60 @@ void pkgDPkgPM::StartPtyMagic()
 	 close(d->master);
 	 close(d->master);
 	 d->master = -1;
 	 d->master = -1;
       }
       }
+      if (d->slave != NULL)
+      {
+	 free(d->slave);
+	 d->slave = NULL;
+      }
       _error->DumpErrors(std::cerr);
       _error->DumpErrors(std::cerr);
    }
    }
    _error->RevertToStack();
    _error->RevertToStack();
 }
 }
 void pkgDPkgPM::SetupSlavePtyMagic()
 void pkgDPkgPM::SetupSlavePtyMagic()
 {
 {
-   if(d->master == -1)
+   if(d->master == -1 || d->slave == NULL)
       return;
       return;
 
 
    if (close(d->master) == -1)
    if (close(d->master) == -1)
       _error->FatalE("close", "Closing master %d in child failed!", d->master);
       _error->FatalE("close", "Closing master %d in child failed!", d->master);
+   d->master = -1;
    if (setsid() == -1)
    if (setsid() == -1)
       _error->FatalE("setsid", "Starting a new session for child failed!");
       _error->FatalE("setsid", "Starting a new session for child failed!");
 
 
-   int const slaveFd = open(d->slave, O_RDWR);
+   int const slaveFd = open(d->slave, O_RDWR | O_NOCTTY);
    if (slaveFd == -1)
    if (slaveFd == -1)
       _error->FatalE("open", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
       _error->FatalE("open", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
-
-   if (ioctl(slaveFd, TIOCSCTTY, 0) < 0)
+   else if (ioctl(slaveFd, TIOCSCTTY, 0) < 0)
       _error->FatalE("ioctl", "Setting TIOCSCTTY for slave fd %d failed!", slaveFd);
       _error->FatalE("ioctl", "Setting TIOCSCTTY for slave fd %d failed!", slaveFd);
    else
    else
    {
    {
-      for (unsigned short i = 0; i < 3; ++i)
+      unsigned short i = 0;
+      if (d->direct_stdin == true)
+	 ++i;
+      for (; i < 3; ++i)
 	 if (dup2(slaveFd, i) == -1)
 	 if (dup2(slaveFd, i) == -1)
 	    _error->FatalE("dup2", "Dupping %d to %d in child failed!", slaveFd, i);
 	    _error->FatalE("dup2", "Dupping %d to %d in child failed!", slaveFd, i);
 
 
-      if (tcsetattr(0, TCSANOW, &d->tt) < 0)
+      if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSANOW, &d->tt) < 0)
 	 _error->FatalE("tcsetattr", "Setting in Setup via TCSANOW for slave fd %d failed!", slaveFd);
 	 _error->FatalE("tcsetattr", "Setting in Setup via TCSANOW for slave fd %d failed!", slaveFd);
    }
    }
+
+   if (slaveFd != -1)
+      close(slaveFd);
 }
 }
 void pkgDPkgPM::StopPtyMagic()
 void pkgDPkgPM::StopPtyMagic()
 {
 {
    if (d->slave != NULL)
    if (d->slave != NULL)
       free(d->slave);
       free(d->slave);
    d->slave = NULL;
    d->slave = NULL;
+   if (d->protect_slave_from_dying != -1)
+   {
+      close(d->protect_slave_from_dying);
+      d->protect_slave_from_dying = -1;
+   }
    if(d->master >= 0) 
    if(d->master >= 0) 
    {
    {
-      if (tcsetattr(0, TCSAFLUSH, &d->tt) == -1)
+      if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSAFLUSH, &d->tt) == -1)
 	 _error->FatalE("tcsetattr", "Setting in Stop via TCSAFLUSH for stdin failed!");
 	 _error->FatalE("tcsetattr", "Setting in Stop via TCSAFLUSH for stdin failed!");
       close(d->master);
       close(d->master);
       d->master = -1;
       d->master = -1;
@@ -1267,9 +1294,8 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 
 
    // support subpressing of triggers processing for special
    // support subpressing of triggers processing for special
    // cases like d-i that runs the triggers handling manually
    // cases like d-i that runs the triggers handling manually
-   bool const SmartConf = (_config->Find("PackageManager::Configure", "all") != "all");
    bool const TriggersPending = _config->FindB("DPkg::TriggersPending", false);
    bool const TriggersPending = _config->FindB("DPkg::TriggersPending", false);
-   if (_config->FindB("DPkg::ConfigurePending", SmartConf) == true)
+   if (_config->FindB("DPkg::ConfigurePending", true) == true)
       List.push_back(Item(Item::ConfigurePending, PkgIterator()));
       List.push_back(Item(Item::ConfigurePending, PkgIterator()));
 
 
    // for the progress
    // for the progress
@@ -1578,8 +1604,8 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 
 
 	 // wait for input or output here
 	 // wait for input or output here
 	 FD_ZERO(&rfds);
 	 FD_ZERO(&rfds);
-	 if (d->master >= 0 && !d->stdin_is_dev_null)
-	    FD_SET(0, &rfds); 
+	 if (d->master >= 0 && d->direct_stdin == false && d->stdin_is_dev_null == false)
+	    FD_SET(STDIN_FILENO, &rfds);
 	 FD_SET(_dpkgin, &rfds);
 	 FD_SET(_dpkgin, &rfds);
 	 if(d->master >= 0)
 	 if(d->master >= 0)
 	    FD_SET(d->master, &rfds);
 	    FD_SET(d->master, &rfds);
@@ -1874,8 +1900,19 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
       }
       }
    }
    }
 
 
-   // log the ordering 
-   const char *ops_str[] = {"Install", "Configure","Remove","Purge"};
+   // log the ordering, see dpkgpm.h and the "Ops" enum there
+   const char *ops_str[] = {
+      "Install",
+      "Configure",
+      "Remove",
+      "Purge",
+      "ConfigurePending",
+      "TriggersPending",
+      "reserved-1",
+      "reserved-2",
+      "reserved-3",
+      "reserved-4",
+   };
    fprintf(report, "AptOrdering:\n");
    fprintf(report, "AptOrdering:\n");
    for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
    for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
       if ((*I).Pkg != NULL)
       if ((*I).Pkg != NULL)

+ 1 - 1
apt-pkg/depcache.cc

@@ -1226,7 +1226,7 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 	       continue;
 	       continue;
 	    }
 	    }
 	    // now check if we should consider it a automatic dependency or not
 	    // 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()))
+	    if(InstPkg->CurrentVer == 0 && InstVer->Section != 0 && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", InstVer.Section()))
 	    {
 	    {
 	       if(DebugAutoInstall == true)
 	       if(DebugAutoInstall == true)
 		  std::clog << OutputInDepth(Depth) << "Setting NOT as auto-installed (direct "
 		  std::clog << OutputInDepth(Depth) << "Setting NOT as auto-installed (direct "

+ 4 - 1
apt-pkg/pkgcache.cc

@@ -524,7 +524,10 @@ operator<<(std::ostream& out, pkgCache::PkgIterator Pkg)
       out << " -> " << candidate;
       out << " -> " << candidate;
    if ( newest != "none" && candidate != newest)
    if ( newest != "none" && candidate != newest)
       out << " | " << newest;
       out << " | " << newest;
-   out << " > ( " << string(Pkg.Section()==0?"none":Pkg.Section()) << " )";
+   if (Pkg->VersionList == 0)
+      out << " > ( none )";
+   else
+      out << " > ( " << string(Pkg.VersionList().Section()==0?"unknown":Pkg.VersionList().Section()) << " )";
    return out;
    return out;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 30 - 1
apt-pkg/srcrecords.cc

@@ -14,6 +14,7 @@
 #include<config.h>
 #include<config.h>
 
 
 #include <apt-pkg/srcrecords.h>
 #include <apt-pkg/srcrecords.h>
+#include <apt-pkg/debsrcrecords.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/metaindex.h>
@@ -147,5 +148,33 @@ const char *pkgSrcRecords::Parser::BuildDepType(unsigned char const &Type)
    return fields[Type];
    return fields[Type];
 }
 }
 									/*}}}*/
 									/*}}}*/
+bool pkgSrcRecords::Parser::Files2(std::vector<pkgSrcRecords::File2> &F2)/*{{{*/
+{
+   debSrcRecordParser * const deb = dynamic_cast<debSrcRecordParser*>(this);
+   if (deb != NULL)
+      return deb->Files2(F2);
 
 
-
+   std::vector<pkgSrcRecords::File> F;
+   if (Files(F) == false)
+      return false;
+   for (std::vector<pkgSrcRecords::File>::const_iterator f = F.begin(); f != F.end(); ++f)
+   {
+      pkgSrcRecords::File2 f2;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+      f2.MD5Hash = f->MD5Hash;
+      f2.Size = f->Size;
+      f2.Hashes.push_back(HashString("MD5Sum", f->MD5Hash));
+      f2.FileSize = f->Size;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+      f2.Path = f->Path;
+      f2.Type = f->Type;
+      F2.push_back(f2);
+   }
+   return true;
+}
+									/*}}}*/

+ 18 - 3
apt-pkg/srcrecords.h

@@ -14,6 +14,7 @@
 #define PKGLIB_SRCRECORDS_H
 #define PKGLIB_SRCRECORDS_H
 
 
 #include <apt-pkg/macros.h>
 #include <apt-pkg/macros.h>
+#include <apt-pkg/hashes.h>
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
@@ -29,15 +30,28 @@ class pkgSrcRecords
 {
 {
    public:
    public:
 
 
+#if __GNUC__ >= 4
+	// ensure that con- & de-structor don't trigger this warning
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
    // Describes a single file
    // Describes a single file
    struct File
    struct File
    {
    {
-      std::string MD5Hash;
-      unsigned long Size;
+      APT_DEPRECATED std::string MD5Hash;
+      APT_DEPRECATED unsigned long Size;
       std::string Path;
       std::string Path;
       std::string Type;
       std::string Type;
    };
    };
-   
+   struct File2 : public File
+   {
+      unsigned long long FileSize;
+      HashStringList Hashes;
+   };
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+
    // Abstract parser for each source record
    // Abstract parser for each source record
    class Parser
    class Parser
    {
    {
@@ -77,6 +91,7 @@ class pkgSrcRecords
       static const char *BuildDepType(unsigned char const &Type) APT_PURE;
       static const char *BuildDepType(unsigned char const &Type) APT_PURE;
 
 
       virtual bool Files(std::vector<pkgSrcRecords::File> &F) = 0;
       virtual bool Files(std::vector<pkgSrcRecords::File> &F) = 0;
+      bool Files2(std::vector<pkgSrcRecords::File2> &F);
       
       
       Parser(const pkgIndexFile *Index) : iIndex(Index) {};
       Parser(const pkgIndexFile *Index) : iIndex(Index) {};
       virtual ~Parser() {};
       virtual ~Parser() {};

+ 1 - 1
apt-private/private-cmndline.cc

@@ -166,7 +166,7 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
 
 
    if (CmdMatches("install", "remove", "purge", "upgrade", "dist-upgrade",
    if (CmdMatches("install", "remove", "purge", "upgrade", "dist-upgrade",
 	    "deselect-upgrade", "autoremove", "clean", "autoclean", "check",
 	    "deselect-upgrade", "autoremove", "clean", "autoclean", "check",
-	    "build-dep", "full-upgrade"))
+	    "build-dep", "full-upgrade", "source"))
    {
    {
       addArg('s', "simulate", "APT::Get::Simulate", 0);
       addArg('s', "simulate", "APT::Get::Simulate", 0);
       addArg('s', "just-print", "APT::Get::Simulate", 0);
       addArg('s', "just-print", "APT::Get::Simulate", 0);

+ 16 - 12
cmdline/apt-get.cc

@@ -797,13 +797,13 @@ static bool DoSource(CommandLine &CmdL)
       }
       }
 
 
       // Back track
       // Back track
-      vector<pkgSrcRecords::File> Lst;
-      if (Last->Files(Lst) == false) {
+      vector<pkgSrcRecords::File2> Lst;
+      if (Last->Files2(Lst) == false) {
 	 return false;
 	 return false;
       }
       }
 
 
       // Load them into the fetcher
       // Load them into the fetcher
-      for (vector<pkgSrcRecords::File>::const_iterator I = Lst.begin();
+      for (vector<pkgSrcRecords::File2>::const_iterator I = Lst.begin();
 	   I != Lst.end(); ++I)
 	   I != Lst.end(); ++I)
       {
       {
 	 // Try to guess what sort of file it is we are getting.
 	 // Try to guess what sort of file it is we are getting.
@@ -832,22 +832,26 @@ static bool DoSource(CommandLine &CmdL)
 	 queued.insert(Last->Index().ArchiveURI(I->Path));
 	 queued.insert(Last->Index().ArchiveURI(I->Path));
 
 
 	 // check if we have a file with that md5 sum already localy
 	 // check if we have a file with that md5 sum already localy
-	 if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path)))  
-	 {
-	    FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly);
-	    MD5Summation sum;
-	    sum.AddFD(Fd.Fd(), Fd.Size());
-	    Fd.Close();
-	    if((string)sum.Result() == I->MD5Hash) 
+	 std::string localFile = flNotDir(I->Path);
+	 if (FileExists(localFile) == true)
+	    if(I->Hashes.VerifyFile(localFile) == true)
 	    {
 	    {
 	       ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
 	       ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
-			flNotDir(I->Path).c_str());
+			localFile.c_str());
 	       continue;
 	       continue;
 	    }
 	    }
+
+	 // see if we have a hash (Acquire::ForceHash is the only way to have none)
+	 HashString const * const hs = I->Hashes.find(NULL);
+	 if (hs == NULL && _config->FindB("APT::Get::AllowUnauthenticated",false) == false)
+	 {
+	    ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n",
+		     localFile.c_str());
+	    continue;
 	 }
 	 }
 
 
 	 new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
 	 new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
-			I->MD5Hash,I->Size,
+			hs != NULL ? hs->toStr() : "", I->FileSize,
 			Last->Index().SourceInfo(*Last,*I),Src);
 			Last->Index().SourceInfo(*Last,*I),Src);
       }
       }
    }
    }

+ 23 - 12
cmdline/apt-helper.cc

@@ -48,23 +48,34 @@ static bool DoDownloadFile(CommandLine &CmdL)
    if (CmdL.FileSize() <= 2)
    if (CmdL.FileSize() <= 2)
       return _error->Error(_("Must specify at least one pair url/filename"));
       return _error->Error(_("Must specify at least one pair url/filename"));
 
 
-
    pkgAcquire Fetcher;
    pkgAcquire Fetcher;
    AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0));
    AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0));
    Fetcher.Setup(&Stat);
    Fetcher.Setup(&Stat);
-   std::string download_uri = CmdL.FileList[1];
-   std::string targetfile = CmdL.FileList[2];
-   std::string hash;
-   if (CmdL.FileSize() > 3)
-      hash = CmdL.FileList[3];
-   // we use download_uri as descr and targetfile as short-descr
-   new pkgAcqFile(&Fetcher, download_uri, hash, 0, download_uri, targetfile, 
-                  "dest-dir-ignored", targetfile);
-   Fetcher.Run();
+
+   size_t fileind = 0;
+   std::vector<std::string> targetfiles;
+   while (fileind + 2 <= CmdL.FileSize())
+   {
+      std::string download_uri = CmdL.FileList[fileind + 1];
+      std::string targetfile = CmdL.FileList[fileind + 2];
+      std::string hash;
+      if (CmdL.FileSize() > fileind + 3)
+	 hash = CmdL.FileList[fileind + 3];
+      // we use download_uri as descr and targetfile as short-descr
+      new pkgAcqFile(&Fetcher, download_uri, hash, 0, download_uri, targetfile,
+	    "dest-dir-ignored", targetfile);
+      targetfiles.push_back(targetfile);
+      fileind += 3;
+   }
+
    bool Failed = false;
    bool Failed = false;
-   if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true ||
-	 FileExists(targetfile) == false)
+   if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true)
       return _error->Error(_("Download Failed"));
       return _error->Error(_("Download Failed"));
+   if (targetfiles.empty() == false)
+      for (std::vector<std::string>::const_iterator f = targetfiles.begin(); f != targetfiles.end(); ++f)
+	 if (FileExists(*f) == false)
+	    return _error->Error(_("Download Failed"));
+
    return true;
    return true;
 }
 }
 
 

+ 1 - 1
cmdline/apt-key.in

@@ -180,7 +180,7 @@ update() {
 remove_key_from_keyring() {
 remove_key_from_keyring() {
     local GPG="$GPG_CMD --keyring $1"
     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
     # 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
+    if ! $GPG --with-colons --list-keys 2>&1 | grep -q "^pub:[^:]*:[^:]*:[^:]*:[0-9A-F]*$2:"; then
 	return
 	return
     fi
     fi
     if [ ! -w "$1" ]; then
     if [ ! -w "$1" ]; then

+ 1 - 1
configure.ac

@@ -18,7 +18,7 @@ AC_CONFIG_AUX_DIR(buildlib)
 AC_CONFIG_HEADER(include/config.h:buildlib/config.h.in include/apti18n.h:buildlib/apti18n.h.in)
 AC_CONFIG_HEADER(include/config.h:buildlib/config.h.in include/apti18n.h:buildlib/apti18n.h.in)
 
 
 PACKAGE="apt"
 PACKAGE="apt"
-PACKAGE_VERSION="1.0.9.1"
+PACKAGE_VERSION="1.0.9.6"
 PACKAGE_MAIL="APT Development Team <deity@lists.debian.org>"
 PACKAGE_MAIL="APT Development Team <deity@lists.debian.org>"
 AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE")
 AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE")
 AC_DEFINE_UNQUOTED(PACKAGE_VERSION,"$PACKAGE_VERSION")
 AC_DEFINE_UNQUOTED(PACKAGE_VERSION,"$PACKAGE_VERSION")

+ 1 - 1
debian/apt.auto-removal.sh

@@ -41,7 +41,7 @@ version_test_gt ()
 	return "$?"
 	return "$?"
 }
 }
 
 
-list="$(${DPKG} -l | awk '/^ii[ ]+(linux|kfreebsd|gnumach)-image-[0-9]/ && $2 !~ /-dbg$/ { print $2 }' | sed -e 's#\(linux\|kfreebsd\|gnumach\)-image-##')"
+list="$(${DPKG} -l | awk '/^ii[ ]+(linux|kfreebsd|gnumach)-image-[0-9]+\./ && $2 !~ /-dbg$/ { print $2 }' | sed -e 's#\(linux\|kfreebsd\|gnumach\)-image-##')"
 
 
 latest_version=""
 latest_version=""
 previous_version=""
 previous_version=""

+ 86 - 0
debian/changelog

@@ -1,3 +1,89 @@
+apt (1.0.9.7) unstable; urgency=medium
+
+  [ Tomasz Buchert ]
+  * Fix crash in the apt-transport-https when Owner is NULL (Closes: #778375)
+
+ -- Michael Vogt <mvo@debian.org>  Mon, 23 Feb 2015 12:54:03 +0100
+
+apt (1.0.9.6) unstable; urgency=medium
+
+  [ Michael Vogt ]
+  * Fix missing URIStart() for https downloads
+  * Add regression test for the previous commit
+
+  [ David Kalnischkies ]
+  * 128 KiB DSC files ought to be enough for everyone (Closes: 774893)
+  * award points for positive dependencies again (Closes: 774924)
+
+ -- Michael Vogt <mvo@ubuntu.com>  Fri, 16 Jan 2015 08:37:25 +0100
+
+apt (1.0.9.5) unstable; urgency=medium
+
+  [ David Kalnischkies ]
+  * dispose http(s) 416 error page as non-content (Closes: 768797)
+  * do not make PTY slave the controlling terminal (Closes: 772641)
+  * always run 'dpkg --configure -a' at the end of our dpkg callings
+    (Closes: 769609)
+  * pass-through stdin fd instead of content if not a terminal (Closes: 773061)
+
+  [ James McCoy ]
+  * tighten filtering of kernel images in apt.auto-removal (Closes: 772732)
+
+  [ Jean-Pierre Giraud ]
+  * French manpages translation update (Closes: 771967)
+
+  [ Zhou Mo ]
+  * Chinese (simplified) program translation update (Closes: 771982)
+
+  [ Kenshi Muto ]
+  * Japanese program translation update (Closes: 772678)
+
+  [ Theppitak Karoonboonyanan ]
+  * Thai program translation update (Closes: 772913)
+
+ -- David Kalnischkies <david@kalnischkies.de>  Tue, 23 Dec 2014 13:22:42 +0100
+
+apt (1.0.9.4) unstable; urgency=medium
+
+  [ David Kalnischkies ]
+  * use 'best' hash for source authentication (LP: 1098738)
+  * deprecate the Section member from package struct
+  * allow options between command and -- on commandline
+  * re-enable support for -s (and co) in apt-get source (Closes: 742578)
+  * change codenames to jessie as stable POV in docs
+  * close leaking slave fd after setting up pty magic (Closes: 767774)
+  * fix PTY interaction on linux and kfreebsd (Closes: 765687)
+
+  [ James McCoy ]
+  * support long keyids in "apt-key del" instead of ignoring them
+    (Closes: 754436)
+
+  [ Michael Vogt ]
+  * Use sysconf(_SC_ARG_MAX) to find the size of Dpkg::MaxArgBytes
+
+  [ Frans Spiesschaert ]
+  * Dutch program translation update (Closes: 771039)
+
+  [ Julien Patriarca ]
+  * French program translation update (Closes: 766755)
+
+  [ Zhou Mo ]
+  * Chinese (simplified) program translation update (Closes: 766170)
+
+  [ Miroslav Kure ]
+  * Czech program translation update (Closes: 764055)
+
+  [ Mert Dirik ]
+  * Turkish program translation update (Closes: 763379)
+
+  [ Kenshi Muto ]
+  * Japanese program translation update (Closes: 763033)
+
+  [ Manuel "Venturi" Porras Peralta ]
+  * Spanish program translation update (Closes: 771815)
+
+ -- David Kalnischkies <david@kalnischkies.de>  Wed, 03 Dec 2014 14:26:04 +0100
+
 apt (1.0.9.3) unstable; urgency=medium
 apt (1.0.9.3) unstable; urgency=medium
 
 
   [ josch ]
   [ josch ]

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 10 - 0
debian/libapt-pkg4.12.symbols


+ 5 - 5
doc/apt-verbatim.ent

@@ -225,13 +225,13 @@
 ">
 ">
 
 
 <!-- this will be updated by 'prepare-release' -->
 <!-- this will be updated by 'prepare-release' -->
-<!ENTITY apt-product-version "1.0.9.1">
+<!ENTITY apt-product-version "1.0.9.6">
 
 
 <!-- (Code)names for various things used all over the place -->
 <!-- (Code)names for various things used all over the place -->
-<!ENTITY oldstable-codename "squeeze">
-<!ENTITY stable-codename "wheezy">
-<!ENTITY testing-codename "jessie">
-<!ENTITY stable-version "7">
+<!ENTITY oldstable-codename "wheezy">
+<!ENTITY stable-codename "jessie">
+<!ENTITY testing-codename "stretch">
+<!ENTITY stable-version "8">
 <!ENTITY ubuntu-codename "trusty">
 <!ENTITY ubuntu-codename "trusty">
 
 
 <!-- good and bad just refers to matching and not matching a pattern…
 <!-- good and bad just refers to matching and not matching a pattern…

+ 2 - 2
doc/po/apt-doc.pot

@@ -6,9 +6,9 @@
 #, fuzzy
 #, fuzzy
 msgid ""
 msgid ""
 msgstr ""
 msgstr ""
-"Project-Id-Version: apt-doc 1.0.8\n"
+"Project-Id-Version: apt-doc 1.0.9.5\n"
 "Report-Msgid-Bugs-To: APT Development Team <deity@lists.debian.org>\n"
 "Report-Msgid-Bugs-To: APT Development Team <deity@lists.debian.org>\n"
-"POT-Creation-Date: 2014-09-18 07:57+0200\n"
+"POT-Creation-Date: 2015-01-16 04:37-0500\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"

+ 186 - 250
doc/po/fr.po

@@ -6,19 +6,20 @@
 # Jérôme Marant, 2000.
 # Jérôme Marant, 2000.
 # Philippe Batailler, 2005.
 # Philippe Batailler, 2005.
 # Christian Perrier <bubulle@debian.org>, 2009, 2010, 2011, 2012, 2013.
 # Christian Perrier <bubulle@debian.org>, 2009, 2010, 2011, 2012, 2013.
+# Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>, 2014.
 msgid ""
 msgid ""
 msgstr ""
 msgstr ""
 "Project-Id-Version: \n"
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: APT Development Team <deity@lists.debian.org>\n"
 "Report-Msgid-Bugs-To: APT Development Team <deity@lists.debian.org>\n"
-"POT-Creation-Date: 2014-08-28 00:20+0000\n"
-"PO-Revision-Date: 2014-07-04 01:28+0200\n"
-"Last-Translator: Christian Perrier <bubulle@debian.org>\n"
+"POT-Creation-Date: 2014-12-23 13:24+0100\n"
+"PO-Revision-Date: 2014-11-15 17:26+0100\n"
+"Last-Translator: Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>\n"
 "Language-Team: French <debian-l10n-french@lists.debian.org>\n"
 "Language-Team: French <debian-l10n-french@lists.debian.org>\n"
 "Language: fr\n"
 "Language: fr\n"
 "MIME-Version: 1.0\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Lokalize 1.4\n"
+"X-Generator: Lokalize 1.5\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
 
 #. type: Plain text
 #. type: Plain text
@@ -628,7 +629,7 @@ msgstr "APT"
 #. type: Content of: <refentry><refnamediv><refpurpose>
 #. type: Content of: <refentry><refnamediv><refpurpose>
 #: apt.8.xml:28
 #: apt.8.xml:28
 msgid "command-line interface"
 msgid "command-line interface"
-msgstr ""
+msgstr "interface en ligne de commande"
 
 
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt.8.xml:33 apt-get.8.xml:34 apt-cache.8.xml:34 apt-key.8.xml:33
 #: apt.8.xml:33 apt-get.8.xml:34 apt-cache.8.xml:34 apt-key.8.xml:33
@@ -647,6 +648,10 @@ msgid ""
 "management of the system.  See also &apt-get; and &apt-cache; for more low-"
 "management of the system.  See also &apt-get; and &apt-cache; for more low-"
 "level command options."
 "level command options."
 msgstr ""
 msgstr ""
+"<command>apt</command> (Advanced Package Tool) est un outil en ligne de "
+"commande pour gérer les paquets. Il fournit une interface en ligne de "
+"commande au système de gestion de paquets. Voir également &apt-get; et &apt-"
+"cache; pour davantage d'options en ligne de commande."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:43
 #: apt.8.xml:43
@@ -656,6 +661,10 @@ msgid ""
 "<option>--installed</option>, <option>--upgradable</option>, <option>--all-"
 "<option>--installed</option>, <option>--upgradable</option>, <option>--all-"
 "versions</option> are supported."
 "versions</option> are supported."
 msgstr ""
 msgstr ""
+"La commande <literal>list</literal> est utilisée pour afficher une liste de "
+"paquets. Il gère les motifs du shell pour chercher les noms de paquets, "
+"ainsi que les options suivantes : <option>--installed</option>, <option>--"
+"upgradable</option>, <option>--all-versions</option>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:54
 #: apt.8.xml:54
@@ -663,19 +672,17 @@ msgid ""
 "<literal>search</literal> searches for the given term(s) and display "
 "<literal>search</literal> searches for the given term(s) and display "
 "matching packages."
 "matching packages."
 msgstr ""
 msgstr ""
+"La commande <literal>search</literal> recherche le(s) terme(s) donnée(s) et "
+"affiche les paquets correspondants."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:60
 #: apt.8.xml:60
-#, fuzzy
-#| msgid ""
-#| "<literal>rdepends</literal> shows a listing of each reverse dependency a "
-#| "package has."
 msgid ""
 msgid ""
 "<literal>show</literal> shows the package information for the given "
 "<literal>show</literal> shows the package information for the given "
 "package(s)."
 "package(s)."
 msgstr ""
 msgstr ""
-"La commande <literal>rdepends</literal> affiche la liste de toutes les "
-"dépendances inverses d'un paquet."
+"La commande <literal>show</literal> affiche les informations sur le(s) "
+"paquet(s) donné(s)."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:67
 #: apt.8.xml:67
@@ -683,6 +690,8 @@ msgid ""
 "<literal>install</literal> is followed by one or more package names desired "
 "<literal>install</literal> is followed by one or more package names desired "
 "for installation or upgrading."
 "for installation or upgrading."
 msgstr ""
 msgstr ""
+"La commande <literal>install</literal> est suivie du nom de un ou plusieurs "
+"paquets dont l'installation ou la mise à jour est souhaitée."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:71 apt-get.8.xml:112
 #: apt.8.xml:71 apt-get.8.xml:112
@@ -723,19 +732,17 @@ msgid ""
 "<literal>edit-sources</literal> lets you edit your sources.list file and "
 "<literal>edit-sources</literal> lets you edit your sources.list file and "
 "provides basic sanity checks."
 "provides basic sanity checks."
 msgstr ""
 msgstr ""
+"La commande <literal>edit-sources</literal> permet de modifier le fichier "
+"sources.list et fournit des vérifications de sécurité de base."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:95
 #: apt.8.xml:95
-#, fuzzy
-#| msgid ""
-#| "<literal>showhold</literal> is used to print a list of packages on hold "
-#| "in the same way as for the other show commands."
 msgid ""
 msgid ""
 "<literal>update</literal> is used to resynchronize the package index files "
 "<literal>update</literal> is used to resynchronize the package index files "
 "from their sources."
 "from their sources."
 msgstr ""
 msgstr ""
-"<literal>showhold</literal> permet d'afficher la liste des paquets conservés "
-"de manière analogue aux commandes de même type."
+"La commande <literal>update</literal> permet de resynchroniser un fichier "
+"d'index répertoriant les paquets disponibles et sa source."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:101
 #: apt.8.xml:101
@@ -745,6 +752,11 @@ msgid ""
 "<filename>/etc/apt/sources.list</filename>. New packages will be installed, "
 "<filename>/etc/apt/sources.list</filename>. New packages will be installed, "
 "but existing packages will never be removed."
 "but existing packages will never be removed."
 msgstr ""
 msgstr ""
+"La commande <literal>upgrade</literal> permet d'installer les versions les "
+"plus récentes de tous les paquets présents sur le système en utilisant les "
+"sources énumérées dans <filename>/etc/apt/sources.list</filename>. De "
+"nouveaux paquets seront installés, mais les paquets installés ne seront "
+"jamais supprimés."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.8.xml:110
 #: apt.8.xml:110
@@ -753,6 +765,9 @@ msgid ""
 "also remove installed packages if that is required in order to resolve a "
 "also remove installed packages if that is required in order to resolve a "
 "package conflict."
 "package conflict."
 msgstr ""
 msgstr ""
+"La commande <literal>full-upgrade</literal> remplit la même fonction que "
+"upgrade mais peut aussi supprimer des paquets installés si cela est "
+"nécessaire pour résoudre un conflit entre des paquets."
 
 
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt.8.xml:120 apt-get.8.xml:251 apt-cache.8.xml:244 apt-mark.8.xml:104
 #: apt.8.xml:120 apt-get.8.xml:251 apt-cache.8.xml:244 apt-mark.8.xml:104
@@ -764,7 +779,7 @@ msgstr "options"
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt.8.xml:130
 #: apt.8.xml:130
 msgid "Script usage"
 msgid "Script usage"
-msgstr ""
+msgstr "Utilisation de scripts"
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt.8.xml:132
 #: apt.8.xml:132
@@ -775,11 +790,17 @@ msgid ""
 "&apt-cache; and &apt-get; via APT options. Please prefer using these "
 "&apt-cache; and &apt-get; via APT options. Please prefer using these "
 "commands in your scripts."
 "commands in your scripts."
 msgstr ""
 msgstr ""
+"La ligne de commande de &apt; est conçue comme un outil pour l'utilisateur "
+"et les sorties peuvent varier selon ses versions. Bien qu'il s'efforce de ne "
+"pas casser les compatibilités ascendantes, cela ne peut pas non plus être "
+"garanti. Toutes les fonctionnalités de &apt; existent dans &apt-cache; et "
+"&apt-get; grâce aux options de APT. Il est conseillé d'utiliser ces "
+"commandes dans vos scripts."
 
 
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt.8.xml:140
 #: apt.8.xml:140
 msgid "Differences to &apt-get;"
 msgid "Differences to &apt-get;"
-msgstr ""
+msgstr "Différences avec &apt-get;"
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt.8.xml:141
 #: apt.8.xml:141
@@ -788,20 +809,19 @@ msgid ""
 "does not need to be backward compatible like &apt-get;. Therefore some "
 "does not need to be backward compatible like &apt-get;. Therefore some "
 "options are different:"
 "options are different:"
 msgstr ""
 msgstr ""
+"La commande <command>apt</command> est sensée être agréable à l'utilisateur "
+"et ne pas avoir besoin de compatibilité ascendante comme &apt-get;. Par "
+"conséquent, certaines options sont différentes :"
 
 
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #: apt.8.xml:147
 #: apt.8.xml:147
-#, fuzzy
-#| msgid "the <literal>Package:</literal> line"
 msgid "The option <literal>DPkg::Progress-Fancy</literal> is enabled."
 msgid "The option <literal>DPkg::Progress-Fancy</literal> is enabled."
-msgstr "la ligne <literal>Package:</literal>"
+msgstr "L'option <literal>DPkg::Progress-Fancy</literal> est activée."
 
 
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #: apt.8.xml:151
 #: apt.8.xml:151
-#, fuzzy
-#| msgid "the <literal>Component:</literal> line"
 msgid "The option <literal>APT::Color</literal> is enabled."
 msgid "The option <literal>APT::Color</literal> is enabled."
-msgstr "La ligne <literal>Component:</literal>"
+msgstr "L'option <literal>APT::Color</literal> est activée."
 
 
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #: apt.8.xml:155
 #: apt.8.xml:155
@@ -809,15 +829,17 @@ msgid ""
 "A new <literal>list</literal> command is available similar to <literal>dpkg "
 "A new <literal>list</literal> command is available similar to <literal>dpkg "
 "--list</literal>."
 "--list</literal>."
 msgstr ""
 msgstr ""
+"Une nouvelle commande <literal>list</literal> est disponible, semblable à la "
+"commande <literal>dpkg --list</literal>."
 
 
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #: apt.8.xml:160
 #: apt.8.xml:160
-#, fuzzy
-#| msgid "the <literal>Archive:</literal> or <literal>Suite:</literal> line"
 msgid ""
 msgid ""
 "The option <literal>upgrade</literal> has <literal>--with-new-pkgs</literal> "
 "The option <literal>upgrade</literal> has <literal>--with-new-pkgs</literal> "
 "enabled by default."
 "enabled by default."
-msgstr "La ligne <literal>Archive:</literal> ou <literal>Suite:</literal>"
+msgstr ""
+"La commande <literal>upgrade</literal> a l'option <literal>--with-new-pkgs</"
+"literal> activée par défaut."
 
 
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt.8.xml:170 apt-get.8.xml:552 apt-cache.8.xml:346 apt-key.8.xml:191
 #: apt.8.xml:170 apt-get.8.xml:552 apt-cache.8.xml:346 apt-key.8.xml:191
@@ -830,18 +852,12 @@ msgstr "Voir aussi"
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt.8.xml:171
 #: apt.8.xml:171
-#, fuzzy
-#| msgid ""
-#| "&apt-cache;, &apt-cdrom;, &dpkg;, &dselect;, &sources-list;, &apt-conf;, "
-#| "&apt-config;, &apt-secure;, The APT User's guide in &guidesdir;, &apt-"
-#| "preferences;, the APT Howto."
 msgid ""
 msgid ""
 "&apt-get;, &apt-cache;, &sources-list;, &apt-conf;, &apt-config;, The APT "
 "&apt-get;, &apt-cache;, &sources-list;, &apt-conf;, &apt-config;, The APT "
 "User's guide in &guidesdir;, &apt-preferences;, the APT Howto."
 "User's guide in &guidesdir;, &apt-preferences;, the APT Howto."
 msgstr ""
 msgstr ""
-"&apt-cache;, &apt-cdrom;, &dpkg;, &dselect;, &sources-list;, &apt-conf;, "
-"&apt-config;, le guide d'APT dans &guidesdir;, &apt-preferences;, le "
-"« HOWTO » d'APT."
+"&apt-get;, &apt-cache;, &sources-list;, &apt-conf;, &apt-config;, le guide "
+"d'APT dans &guidesdir;, &apt-preferences;, le « HOWTO » d'APT."
 
 
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt.8.xml:176 apt-get.8.xml:558 apt-cache.8.xml:351 apt-mark.8.xml:131
 #: apt.8.xml:176 apt-get.8.xml:558 apt-cache.8.xml:351 apt-mark.8.xml:131
@@ -852,15 +868,11 @@ msgstr "Diagnostics"
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt.8.xml:177
 #: apt.8.xml:177
-#, fuzzy
-#| msgid ""
-#| "<command>apt-get</command> returns zero on normal operation, decimal 100 "
-#| "on error."
 msgid ""
 msgid ""
 "<command>apt</command> returns zero on normal operation, decimal 100 on "
 "<command>apt</command> returns zero on normal operation, decimal 100 on "
 "error."
 "error."
 msgstr ""
 msgstr ""
-"<command>apt-get</command> renvoie zéro après une opération normale, le "
+"<command>apt</command> renvoie zéro après une opération normale, et le "
 "décimal 100 en cas d'erreur."
 "décimal 100 en cas d'erreur."
 
 
 #. type: Content of: <refentry><refnamediv><refpurpose>
 #. type: Content of: <refentry><refnamediv><refpurpose>
@@ -871,22 +883,16 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt-get.8.xml:35
 #: apt-get.8.xml:35
-#, fuzzy
-#| msgid ""
-#| "<command>apt-get</command> is the command-line tool for handling "
-#| "packages, and may be considered the user's \"back-end\" to other tools "
-#| "using the APT library.  Several \"front-end\" interfaces exist, such as "
-#| "&dselect;, &aptitude;, &synaptic; and &wajig;."
 msgid ""
 msgid ""
 "<command>apt-get</command> is the command-line tool for handling packages, "
 "<command>apt-get</command> is the command-line tool for handling packages, "
 "and may be considered the user's \"back-end\" to other tools using the APT "
 "and may be considered the user's \"back-end\" to other tools using the APT "
 "library.  Several \"front-end\" interfaces exist, such as &aptitude;, "
 "library.  Several \"front-end\" interfaces exist, such as &aptitude;, "
 "&synaptic; and &wajig;."
 "&synaptic; and &wajig;."
 msgstr ""
 msgstr ""
-"<command>Apt-get</command> est le programme en ligne de commande pour la "
+"<command>apt-get</command> est le programme en ligne de commande pour la "
 "gestion des paquets. Il peut être considéré comme l'outil de base pour les "
 "gestion des paquets. Il peut être considéré comme l'outil de base pour les "
-"autres programmes de la bibliothèque APT.  Plusieurs interfaces utilisateur "
-"existent, comme &dselect;, &aptitude;, &synaptic; and &wajig;."
+"autres programmes de la bibliothèque APT. Plusieurs interfaces utilisateur "
+"existent, comme &aptitude;, &synaptic; and &wajig;."
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt-get.8.xml:40 apt-cache.8.xml:40 apt-cdrom.8.xml:47 apt-config.8.xml:40
 #: apt-get.8.xml:40 apt-cache.8.xml:40 apt-cdrom.8.xml:47 apt-config.8.xml:40
@@ -1203,15 +1209,6 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-get.8.xml:211
 #: apt-get.8.xml:211
-#, fuzzy
-#| msgid ""
-#| "<literal>clean</literal> clears out the local repository of retrieved "
-#| "package files. It removes everything but the lock file from "
-#| "<filename>&cachedir;/archives/</filename> and <filename>&cachedir;/"
-#| "archives/partial/</filename>. When APT is used as a &dselect; method, "
-#| "<literal>clean</literal> is run automatically.  Those who do not use "
-#| "dselect will likely want to run <literal>apt-get clean</literal> from "
-#| "time to time to free up disk space."
 msgid ""
 msgid ""
 "<literal>clean</literal> clears out the local repository of retrieved "
 "<literal>clean</literal> clears out the local repository of retrieved "
 "package files. It removes everything but the lock file from "
 "package files. It removes everything but the lock file from "
@@ -1221,10 +1218,7 @@ msgstr ""
 "La commande <literal>clean</literal> nettoie le référentiel local des "
 "La commande <literal>clean</literal> nettoie le référentiel local des "
 "paquets récupérés. Elle supprime tout, excepté le fichier de verrou situé "
 "paquets récupérés. Elle supprime tout, excepté le fichier de verrou situé "
 "dans <filename>&cachedir;/archives/</filename> et <filename>&cachedir;/"
 "dans <filename>&cachedir;/archives/</filename> et <filename>&cachedir;/"
-"archives/partial/</filename>.  Quand APT est utilisé comme mode de "
-"&dselect;, <literal>clean</literal> est exécuté automatiquement. Quand on "
-"n'utilise pas dselect, il faut exécuter <literal>apt-get clean</literal> de "
-"temps en temps si l'on veut libérer de l'espace disque."
+"archives/partial/</filename>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-get.8.xml:218
 #: apt-get.8.xml:218
@@ -1310,19 +1304,6 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-get.8.xml:271
 #: apt-get.8.xml:271
-#, fuzzy
-#| msgid ""
-#| "Fix; attempt to correct a system with broken dependencies in place. This "
-#| "option, when used with install/remove, can omit any packages to permit "
-#| "APT to deduce a likely solution. If packages are specified, these have to "
-#| "completely correct the problem. The option is sometimes necessary when "
-#| "running APT for the first time; APT itself does not allow broken package "
-#| "dependencies to exist on a system. It is possible that a system's "
-#| "dependency structure can be so corrupt as to require manual intervention "
-#| "(which usually means using &dselect; or <command>dpkg --remove</command> "
-#| "to eliminate some of the offending packages). Use of this option together "
-#| "with <option>-m</option> may produce an error in some situations.  "
-#| "Configuration Item: <literal>APT::Get::Fix-Broken</literal>."
 msgid ""
 msgid ""
 "Fix; attempt to correct a system with broken dependencies in place. This "
 "Fix; attempt to correct a system with broken dependencies in place. This "
 "option, when used with install/remove, can omit any packages to permit APT "
 "option, when used with install/remove, can omit any packages to permit APT "
@@ -1344,9 +1325,9 @@ msgstr ""
 "interdit les dépendances défectueuses dans un système. Il est possible que "
 "interdit les dépendances défectueuses dans un système. Il est possible que "
 "la structure de dépendances d'un système soit tellement corrompue qu'elle "
 "la structure de dépendances d'un système soit tellement corrompue qu'elle "
 "requiert une intervention manuelle (ce qui veut dire la plupart du temps "
 "requiert une intervention manuelle (ce qui veut dire la plupart du temps "
-"utiliser &dselect; ou <command>dpkg --remove</command> pour éliminer les "
-"paquets en cause). L'utilisation de cette option conjointement avec <option>-"
-"m</option> peut produire une erreur dans certaines situations. Élément de "
+"utiliser <command>dpkg --remove</command> pour éliminer les paquets en "
+"cause). L'utilisation de cette option conjointement avec <option>-m</option> "
+"peut produire une erreur dans certaines situations. Élément de "
 "configuration : <literal>APT::Get::Fix-Broken</literal>."
 "configuration : <literal>APT::Get::Fix-Broken</literal>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
@@ -1496,14 +1477,6 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-get.8.xml:364
 #: apt-get.8.xml:364
-#, fuzzy
-#| msgid ""
-#| "This option controls the architecture packages are built for by "
-#| "<command>apt-get source --compile</command> and how cross-"
-#| "builddependencies are satisfied. By default is it not set which means "
-#| "that the host architecture is the same as the build architecture (which "
-#| "is defined by <literal>APT::Architecture</literal>).  Configuration Item: "
-#| "<literal>APT::Get::Host-Architecture</literal>"
 msgid ""
 msgid ""
 "This option controls the architecture packages are built for by <command>apt-"
 "This option controls the architecture packages are built for by <command>apt-"
 "get source --compile</command> and how cross-builddependencies are "
 "get source --compile</command> and how cross-builddependencies are "
@@ -1517,19 +1490,11 @@ msgstr ""
 "de construction transverses sont respectées. Elle n'est pas positionnée par "
 "de construction transverses sont respectées. Elle n'est pas positionnée par "
 "défaut ce qui signifie que l'architecture hôte est la même que "
 "défaut ce qui signifie que l'architecture hôte est la même que "
 "l'architecture de construction (définie par <literal>APT::Architecture</"
 "l'architecture de construction (définie par <literal>APT::Architecture</"
-"literal>).  Élément de configuration : <literal>APT::Get::Host-Architecture</"
-"literal>"
+"literal>). Élément de configuration : <literal>APT::Get::Host-Architecture</"
+"literal>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-get.8.xml:374
 #: apt-get.8.xml:374
-#, fuzzy
-#| msgid ""
-#| "This option controls the architecture packages are built for by "
-#| "<command>apt-get source --compile</command> and how cross-"
-#| "builddependencies are satisfied. By default is it not set which means "
-#| "that the host architecture is the same as the build architecture (which "
-#| "is defined by <literal>APT::Architecture</literal>).  Configuration Item: "
-#| "<literal>APT::Get::Host-Architecture</literal>"
 msgid ""
 msgid ""
 "This option controls the activated build profiles for which a source package "
 "This option controls the activated build profiles for which a source package "
 "is built by <command>apt-get source --compile</command> and how build "
 "is built by <command>apt-get source --compile</command> and how build "
@@ -1537,13 +1502,12 @@ msgid ""
 "than one build profile can be activated at a time by concatenating them with "
 "than one build profile can be activated at a time by concatenating them with "
 "a comma.  Configuration Item: <literal>APT::Build-Profiles</literal>."
 "a comma.  Configuration Item: <literal>APT::Build-Profiles</literal>."
 msgstr ""
 msgstr ""
-"Cette option contrôle comment les paquets d'architectures sont construits "
-"par <command>apt-get source --compile</command> et comment les dépendances "
-"de construction transverses sont respectées. Elle n'est pas positionnée par "
-"défaut ce qui signifie que l'architecture hôte est la même que "
-"l'architecture de construction (définie par <literal>APT::Architecture</"
-"literal>).  Élément de configuration : <literal>APT::Get::Host-Architecture</"
-"literal>"
+"Cette option contrôle les profils de construction actifs pour lesquels un "
+"paquet source est construit par <command>apt-get source --compile</command> "
+"et comment les dépendances sont respectées. Par défaut, aucun profil de "
+"construction n'est actif. Plus d'un profil peut être activé en même temps en "
+"les concaténant par une virgule. Élément de configuration : <literal>APT::"
+"Build-Profiles</literal>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-get.8.xml:385
 #: apt-get.8.xml:385
@@ -1579,6 +1543,14 @@ msgid ""
 "will never remove packages, only allow adding new ones.  Configuration Item: "
 "will never remove packages, only allow adding new ones.  Configuration Item: "
 "<literal>APT::Get::Upgrade-Allow-New</literal>."
 "<literal>APT::Get::Upgrade-Allow-New</literal>."
 msgstr ""
 msgstr ""
+"Cette commande permet d'installer de nouveaux paquets lorsqu'elle est "
+"utilisée en conjonction avec la commande <literal>upgrade</literal>. C'est "
+"utile si la mise à jour d'un paquet installé exige l'installation de "
+"nouveaux paquets. Plutôt que de conserver le paquet, <literal>upgrade</"
+"literal> mettra à jour le paquet et installera les nouvelles dépendances. "
+"Remarquez que la commande <literal>upgrade</literal> avec cette option ne "
+"retirera jamais de paquets : elle ne permettra que l'ajout de nouveaux. "
+"Élément de configuration : <literal>APT::Get::Upgrade-Allow-New</literal>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-get.8.xml:409
 #: apt-get.8.xml:409
@@ -1807,6 +1779,12 @@ msgid ""
 "Item: <literal>Dpkg::Progress</literal> and <literal>Dpkg::Progress-Fancy</"
 "Item: <literal>Dpkg::Progress</literal> and <literal>Dpkg::Progress-Fancy</"
 "literal>."
 "literal>."
 msgstr ""
 msgstr ""
+"Cette commande montre les informations de progression conviviales dans la "
+"fenêtre du terminal quand des paquets sont installés, mis à jour ou "
+"supprimés. Pour une version exploitable par une machine de ces données, voir "
+"README.progress-reporting dans le répertoire doc de apt. Élément de "
+"configuration : <literal>Dpkg::Progress</literal> et <literal>Dpkg::Progress-"
+"Fancy</literal>."
 
 
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt-get.8.xml:542 apt-cache.8.xml:339 apt-key.8.xml:170 apt-mark.8.xml:121
 #: apt-get.8.xml:542 apt-cache.8.xml:339 apt-key.8.xml:170 apt-mark.8.xml:121
@@ -1816,18 +1794,13 @@ msgstr "Fichiers"
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt-get.8.xml:553
 #: apt-get.8.xml:553
-#, fuzzy
-#| msgid ""
-#| "&apt-cache;, &apt-cdrom;, &dpkg;, &dselect;, &sources-list;, &apt-conf;, "
-#| "&apt-config;, &apt-secure;, The APT User's guide in &guidesdir;, &apt-"
-#| "preferences;, the APT Howto."
 msgid ""
 msgid ""
 "&apt-cache;, &apt-cdrom;, &dpkg;, &sources-list;, &apt-conf;, &apt-config;, "
 "&apt-cache;, &apt-cdrom;, &dpkg;, &sources-list;, &apt-conf;, &apt-config;, "
 "&apt-secure;, The APT User's guide in &guidesdir;, &apt-preferences;, the "
 "&apt-secure;, The APT User's guide in &guidesdir;, &apt-preferences;, the "
 "APT Howto."
 "APT Howto."
 msgstr ""
 msgstr ""
-"&apt-cache;, &apt-cdrom;, &dpkg;, &dselect;, &sources-list;, &apt-conf;, "
-"&apt-config;, le guide d'APT dans &guidesdir;, &apt-preferences;, le "
+"&apt-cache;, &apt-cdrom;, &dpkg;, &sources-list;, &apt-conf;, &apt-config;, "
+"&apt-secure;, le guide d'APT dans &guidesdir;, &apt-preferences;, le "
 "« HOWTO » d'APT."
 "« HOWTO » d'APT."
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
@@ -2845,7 +2818,6 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt-secure.8.xml:98
 #: apt-secure.8.xml:98
-#, fuzzy
 msgid ""
 msgid ""
 "Once the uploaded package is verified and included in the archive, the "
 "Once the uploaded package is verified and included in the archive, the "
 "maintainer signature is stripped off, and checksums of the package are "
 "maintainer signature is stripped off, and checksums of the package are "
@@ -2862,7 +2834,8 @@ msgstr ""
 "paquets est ensuite calculée et mise dans le fichier Release. Ce fichier est "
 "paquets est ensuite calculée et mise dans le fichier Release. Ce fichier est "
 "signé par la clé de l'archive pour la version courante de la distribution et "
 "signé par la clé de l'archive pour la version courante de la distribution et "
 "distribuée en même temps que les paquets et les fichiers Packages sur les "
 "distribuée en même temps que les paquets et les fichiers Packages sur les "
-"miroirs. Les clés sont fournies par le paquet &keyring-package;."
+"miroirs. Les clés sont dans le trousseau de clés de l'archive fournies par "
+"le paquet &keyring-package;."
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt-secure.8.xml:109
 #: apt-secure.8.xml:109
@@ -3125,20 +3098,14 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-cdrom.8.xml:81
 #: apt-cdrom.8.xml:81
-#, fuzzy
-#| msgid ""
-#| "Mount point; specify the location to mount the CD-ROM. This mount point "
-#| "must be listed in <filename>/etc/fstab</filename> and properly "
-#| "configured.  Configuration Item: <literal>Acquire::cdrom::mount</literal>."
 msgid ""
 msgid ""
 "Do not try to auto-detect the CD-ROM path. Usually combined with the "
 "Do not try to auto-detect the CD-ROM path. Usually combined with the "
 "<option>--cdrom</option> option.  Configuration Item: <literal>Acquire::"
 "<option>--cdrom</option> option.  Configuration Item: <literal>Acquire::"
 "cdrom::AutoDetect</literal>."
 "cdrom::AutoDetect</literal>."
 msgstr ""
 msgstr ""
-"Point de montage ; spécifie l'emplacement de montage du CD. Ce point de "
-"montage doit être spécifié dans <filename>/etc/fstab</filename> et "
-"correctement configuré. Élément de configuration : <literal>Acquire::cdrom::"
-"mount</literal>."
+"Ne pas essayer de détecter automatiquement le chemin du CD-ROM. "
+"Habituellement combiné avec l'option <option>--cdrom</option>. Élément de "
+"configuration : <literal>Acquire::cdrom::AutoDetect</literal>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt-cdrom.8.xml:89
 #: apt-cdrom.8.xml:89
@@ -3453,7 +3420,7 @@ msgid ""
 msgstr ""
 msgstr ""
 "Le fichier de configuration est construit comme un arbre d'options "
 "Le fichier de configuration est construit comme un arbre d'options "
 "organisées en groupes fonctionnels. On se sert du double deux points "
 "organisées en groupes fonctionnels. On se sert du double deux points "
-"(« :: »)  pour indiquer une option ; par exemple, <literal>APT::Get::Assume-"
+"(« :: ») pour indiquer une option ; par exemple, <literal>APT::Get::Assume-"
 "Yes</literal> est une option pour le groupe d'outils APT, destinée à l'outil "
 "Yes</literal> est une option pour le groupe d'outils APT, destinée à l'outil "
 "Get. Il n'y a pas d'héritage des options des groupes parents."
 "Get. Il n'y a pas d'héritage des options des groupes parents."
 
 
@@ -3697,6 +3664,11 @@ msgid ""
 "is empty. The <envar>DEB_BUILD_PROFILES</envar> as used by &dpkg-"
 "is empty. The <envar>DEB_BUILD_PROFILES</envar> as used by &dpkg-"
 "buildpackage; overrides the list notation."
 "buildpackage; overrides the list notation."
 msgstr ""
 msgstr ""
+"Liste de tous les profils de construction activés pour la résolution de "
+"dépendances de construction, sans le préfixe de l'espace de nommage du "
+"\"<literal>profile.</literal>\". Par défaut, cette liste est vide. La "
+"variable <envar>DEB_BUILD_PROFILES</envar> comme l'utilise &dpkg-"
+"buildpackage; annule la notation de liste."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:184
 #: apt.conf.5.xml:184
@@ -4133,13 +4105,6 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:394
 #: apt.conf.5.xml:394
-#, fuzzy
-#| msgid ""
-#| "The used bandwidth can be limited with <literal>Acquire::http::Dl-Limit</"
-#| "literal> which accepts integer values in kilobytes. The default value is "
-#| "0 which deactivates the limit and tries to use all available bandwidth "
-#| "(note that this option implicitly disables downloading from multiple "
-#| "servers at the same time.)"
 msgid ""
 msgid ""
 "The used bandwidth can be limited with <literal>Acquire::http::Dl-Limit</"
 "The used bandwidth can be limited with <literal>Acquire::http::Dl-Limit</"
 "literal> which accepts integer values in kilobytes per second. The default "
 "literal> which accepts integer values in kilobytes per second. The default "
@@ -4149,9 +4114,10 @@ msgid ""
 msgstr ""
 msgstr ""
 "La bande passante utilisée peut être limité avec <literal>Acquire::http::Dl-"
 "La bande passante utilisée peut être limité avec <literal>Acquire::http::Dl-"
 "Limit</literal> qui peut prendre une valeur entière, l'unité utilisée étant "
 "Limit</literal> qui peut prendre une valeur entière, l'unité utilisée étant "
-"le kilo-octet. La valeur par défaut est 0, ce qui correspond à aucune "
-"limitation de bande passante. Veuillez noter que cette option désactive "
-"implicitement le téléchargement simultané depuis plusieurs serveurs."
+"le kilo-octet par seconde. La valeur par défaut est 0, ce qui correspond à "
+"aucune limitation de bande passante. Veuillez noter que cette option "
+"désactive implicitement le téléchargement simultané depuis plusieurs "
+"serveurs."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:401
 #: apt.conf.5.xml:401
@@ -4178,6 +4144,15 @@ msgid ""
 "takes precedence over the legacy option name <literal>ProxyAutoDetect</"
 "takes precedence over the legacy option name <literal>ProxyAutoDetect</"
 "literal>."
 "literal>."
 msgstr ""
 msgstr ""
+"L'option <literal>Acquire::http::Proxy-Auto-Detect</literal> peut être "
+"utilisée pour indiquer une commande externe pour découvrir le mandataire "
+"HTTP à utiliser. Apt s'attend à ce que la commande sorte le mandataire sur "
+"la sortie standard dans le style <literal>http://proxy:port/</literal>. Cela "
+"annulera le <literal>Acquire::http::Proxy</literal> générique, mais pas une "
+"configuration spécifique de mandataire hôte établie par <literal>Acquire::"
+"http::Proxy::$HOST</literal>. Voir le paquet &squid-deb-proxy-client; pour "
+"un exemple d'implémentation qui utilise avahi. Cette option l'emporte sur "
+"l'ancien nom d'option <literal>ProxyAutoDetect</literal>."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:423
 #: apt.conf.5.xml:423
@@ -4598,17 +4573,6 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt.conf.5.xml:601
 #: apt.conf.5.xml:601
-#, fuzzy
-#| msgid ""
-#| "<literal>Dir::Cache</literal> contains locations pertaining to local "
-#| "cache information, such as the two package caches <literal>srcpkgcache</"
-#| "literal> and <literal>pkgcache</literal> as well as the location to place "
-#| "downloaded archives, <literal>Dir::Cache::archives</literal>. Generation "
-#| "of caches can be turned off by setting their names to the empty string. "
-#| "This will slow down startup but save disk space. It is probably "
-#| "preferable to turn off the pkgcache rather than the srcpkgcache. Like "
-#| "<literal>Dir::State</literal> the default directory is contained in "
-#| "<literal>Dir::Cache</literal>"
 msgid ""
 msgid ""
 "<literal>Dir::Cache</literal> contains locations pertaining to local cache "
 "<literal>Dir::Cache</literal> contains locations pertaining to local cache "
 "information, such as the two package caches <literal>srcpkgcache</literal> "
 "information, such as the two package caches <literal>srcpkgcache</literal> "
@@ -4624,12 +4588,13 @@ msgstr ""
 "le cache local : par exemple, les deux caches de paquets "
 "le cache local : par exemple, les deux caches de paquets "
 "<literal>srcpkgcache</literal> et <literal>pkgcache</literal>, ainsi que "
 "<literal>srcpkgcache</literal> et <literal>pkgcache</literal>, ainsi que "
 "l'endroit où sont placées les archives téléchargées, <literal>Dir::Cache::"
 "l'endroit où sont placées les archives téléchargées, <literal>Dir::Cache::"
-"archives</literal>. On peut empêcher la création des caches en saisissant un "
-"nom vide. Cela ralentit le démarrage mais économise de l'espace disque. Il "
-"vaut mieux se passer du cache <literal>pkgcache</literal> plutôt que se "
-"passer du cache <literal>srcpkgcache</literal>.  Comme pour <literal>Dir::"
-"State</literal>, le répertoire par défaut est contenu dans <literal>Dir::"
-"Cache</literal>."
+"archives</literal>. On peut empêcher la création des caches en positionnant "
+"<literal>pkgcache</literal> ou <literal>srcpkgcache</literal> à la valeur "
+"<literal>\"\"</literal>. Cela ralentit le démarrage mais économise de "
+"l'espace disque. Il vaut mieux se passer du cache <literal>pkgcache</"
+"literal> plutôt que se passer du cache <literal>srcpkgcache</literal>. Comme "
+"pour <literal>Dir::State</literal>, le répertoire par défaut est contenu "
+"dans <literal>Dir::Cache</literal>."
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: apt.conf.5.xml:611
 #: apt.conf.5.xml:611
@@ -4822,13 +4787,6 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:707
 #: apt.conf.5.xml:707
-#, fuzzy
-#| msgid ""
-#| "This is a list of shell commands to run before invoking &dpkg;. Like "
-#| "<literal>options</literal> this must be specified in list notation. The "
-#| "commands are invoked in order using <filename>/bin/sh</filename>; should "
-#| "any fail 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."
 msgid ""
 msgid ""
 "This is a list of shell commands to run before invoking &dpkg;. Like "
 "This is a list of shell commands to run before invoking &dpkg;. Like "
 "<literal>options</literal> this must be specified in list notation. The "
 "<literal>options</literal> this must be specified in list notation. The "
@@ -4839,20 +4797,14 @@ msgid ""
 msgstr ""
 msgstr ""
 "Il s'agit d'une liste de commandes shell à exécuter avant d'appeler &dpkg;.  "
 "Il s'agit d'une liste de commandes shell à exécuter avant d'appeler &dpkg;.  "
 "Tout comme pour <literal>Options</literal>, on doit utiliser la notation de "
 "Tout comme pour <literal>Options</literal>, on doit utiliser la notation de "
-"liste.  Les commandes sont appelées dans l'ordre, en utilisant <filename>/"
-"bin/sh</filename> : APT s'arrête dès que l'une d'elles échoue. Sur l'entrée "
-"standard, APT transmet aux commandes les noms de tous les fichiers .deb "
-"qu'il va installer, à raison d'un par ligne."
+"liste. Les commandes sont appelées dans l'ordre, en utilisant <filename>/bin/"
+"sh</filename> : APT s'arrête dès que l'une d'elles échoue. APT transmet aux "
+"commandes les noms de tous les fichiers .deb qu'il va installer, à raison "
+"d'un par ligne sur le descripteur de fichier demandé, par défaut sur "
+"l'entrée standard."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:714
 #: apt.conf.5.xml:714
-#, fuzzy
-#| msgid ""
-#| "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>."
 msgid ""
 msgid ""
 "Version 2 of this protocol dumps more information, including the protocol "
 "Version 2 of this protocol dumps more information, including the protocol "
 "version, the APT configuration space and the packages, files and versions "
 "version, the APT configuration space and the packages, files and versions "
@@ -4861,10 +4813,9 @@ msgid ""
 msgstr ""
 msgstr ""
 "La deuxième version de ce protocole donne plus de renseignements : on "
 "La deuxième version de ce protocole donne plus de renseignements : on "
 "obtient la version du protocole, la configuration de APT et les paquets, "
 "obtient la version du protocole, la configuration de APT et les paquets, "
-"fichiers ou versions qui ont changé. On autorise cette version en "
-"positionnant <literal>DPkg::Tools::Options::cmd::Version</literal> à 2. "
-"<literal>cmd</literal> est une commande passée à <literal>Pre-Install-Pkgs</"
-"literal>."
+"fichiers ou versions qui ont changé. La troisième version ajoute "
+"l'architecture et le marqueur <literal>MultiArch</literal> à chaque version "
+"déposée."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:719
 #: apt.conf.5.xml:719
@@ -4876,6 +4827,12 @@ msgid ""
 "the requested version it will send the information in the highest version it "
 "the requested version it will send the information in the highest version it "
 "has support for instead."
 "has support for instead."
 msgstr ""
 msgstr ""
+"La version du protocole qu'il faut utiliser pour la commande "
+"<literal><replaceable>cmd</replaceable></literal> peut être choisie en "
+"réglant <literal>DPkg::Tools::options::<replaceable>cmd</replaceable>::"
+"Version</literal> en conséquence, la version par défaut étant la première. "
+"Si APT ne gère pas la version demandée, il enverra les informations dans la "
+"version la plus haute qu'il gère."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:726
 #: apt.conf.5.xml:726
@@ -4887,6 +4844,13 @@ msgid ""
 "looking for the environment variable <envar>APT_HOOK_INFO_FD</envar> which "
 "looking for the environment variable <envar>APT_HOOK_INFO_FD</envar> which "
 "contains the number of the used file descriptor as a confirmation."
 "contains the number of the used file descriptor as a confirmation."
 msgstr ""
 msgstr ""
+"Le descripteur de fichier à utiliser pour l'envoi des informations peut être "
+"demandé avec l'option <literal>DPkg::Tools::options::<replaceable>cmd</"
+"replaceable>::InfoFD</literal> qui est par défaut <literal>0</literal> comme "
+"entrée standard ; l'option est disponible depuis la version 0.9.11. La prise "
+"en charge de l'option peut être détectée en regardant la variable "
+"d'environnement <envar>APT_HOOK_INFO_FD</envar> qui contient comme "
+"confirmation le numéro du descripteur de fichier utilisé."
 
 
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #. type: Content of: <refentry><refsect1><variablelist><varlistentry><listitem><para>
 #: apt.conf.5.xml:736
 #: apt.conf.5.xml:736
@@ -5462,6 +5426,9 @@ msgid ""
 "g. the config options <literal>DPkg::{Pre,Post}-Invoke</literal> or "
 "g. the config options <literal>DPkg::{Pre,Post}-Invoke</literal> or "
 "<literal>APT::Update::{Pre,Post}-Invoke</literal>."
 "<literal>APT::Update::{Pre,Post}-Invoke</literal>."
 msgstr ""
 msgstr ""
+"Affiche les commandes externes qui sont appelés par le point d'entrée apt. "
+"Cela inclut par exemple les options de configuration <literal>DPkg::{Pre,"
+"Post}-Invoke</literal> ou <literal>APT::Update::{Pre,Post}-Invoke</literal>."
 
 
 #. type: Content of: <refentry><refsect1><title>
 #. type: Content of: <refentry><refsect1><title>
 #: apt.conf.5.xml:1210 apt_preferences.5.xml:541 sources.list.5.xml:233
 #: apt.conf.5.xml:1210 apt_preferences.5.xml:541 sources.list.5.xml:233
@@ -5649,7 +5616,7 @@ msgid ""
 msgstr ""
 msgstr ""
 "pour les versions issues d'archives dont le fichier <filename>Release</"
 "pour les versions issues d'archives dont le fichier <filename>Release</"
 "filename> comporte la mention « NotAutomatic: yes » mais <emphasis>pas</"
 "filename> comporte la mention « NotAutomatic: yes » mais <emphasis>pas</"
-"emphasis> « ButAutomaticUpgrades: yes » commel'archive "
+"emphasis> « ButAutomaticUpgrades: yes » comme l'archive "
 "<literal>experimental</literal> de Debian."
 "<literal>experimental</literal> de Debian."
 
 
 #. type: Content of: <refentry><refsect1><refsect2><para><variablelist><varlistentry><term>
 #. type: Content of: <refentry><refsect1><refsect2><para><variablelist><varlistentry><term>
@@ -5908,7 +5875,7 @@ msgstr ""
 "Il est important de noter que le mot-clé utilisé ici est « <literal>origin</"
 "Il est important de noter que le mot-clé utilisé ici est « <literal>origin</"
 "literal> » qui peut servir à indiquer un nom d'hôte. Dans l'exemple qui "
 "literal> » qui peut servir à indiquer un nom d'hôte. Dans l'exemple qui "
 "suit, une haute priorité est donnée à toutes les versions disponibles sur le "
 "suit, une haute priorité est donnée à toutes les versions disponibles sur le "
-"serveur identifié par l' nom d'hôte « ftp.de.debian.org »."
+"serveur identifié par le nom d'hôte « ftp.de.debian.org »."
 
 
 #. type: Content of: <refentry><refsect1><refsect2><para><itemizedlist><listitem><programlisting>
 #. type: Content of: <refentry><refsect1><refsect2><para><itemizedlist><listitem><programlisting>
 #: apt_preferences.5.xml:216
 #: apt_preferences.5.xml:216
@@ -6944,10 +6911,9 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><literallayout>
 #. type: Content of: <refentry><refsect1><literallayout>
 #: sources.list.5.xml:76
 #: sources.list.5.xml:76
-#, fuzzy, no-wrap
-#| msgid "deb [ options ] uri distribution [component1] [component2] [...]"
+#, no-wrap
 msgid "deb [ options ] uri suite [component1] [component2] [...]"
 msgid "deb [ options ] uri suite [component1] [component2] [...]"
-msgstr "deb [ options ] uri distribution [composant1] [composant2] [...]"
+msgstr "deb [ options ] uri suite [composant1] [composant2] [...]"
 
 
 #. type: Content of: <refentry><refsect1><para><literallayout>
 #. type: Content of: <refentry><refsect1><para><literallayout>
 #: sources.list.5.xml:80
 #: sources.list.5.xml:80
@@ -6971,6 +6937,23 @@ msgid ""
 "     [option1]: [option1-value]\n"
 "     [option1]: [option1-value]\n"
 "   "
 "   "
 msgstr ""
 msgstr ""
+"     Types: deb deb-src\n"
+"     URIs: http://example.com\n"
+"     Suites: stable testing\n"
+"     Sections: component1 component2\n"
+"     Description: short\n"
+"      long long long\n"
+"     [option1]: [option1-value]\n"
+"\n"
+"     Types: deb\n"
+"     URIs: http://another.example.com\n"
+"     Suites: experimental\n"
+"     Sections: composant1 composant2\n"
+"     Enabled: no\n"
+"     Description: short\n"
+"      long long long\n"
+"     [option1]: [option1-value]\n"
+"   "
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: sources.list.5.xml:78
 #: sources.list.5.xml:78
@@ -6978,19 +6961,11 @@ msgid ""
 "Alternatively a rfc822 style format is also supported: <placeholder type="
 "Alternatively a rfc822 style format is also supported: <placeholder type="
 "\"literallayout\" id=\"0\"/>"
 "\"literallayout\" id=\"0\"/>"
 msgstr ""
 msgstr ""
+"Autrement, un autre format de style rfc822 est aussi géré : <placeholder "
+"type=\"literallayout\" id=\"0\"/>"
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: sources.list.5.xml:99
 #: sources.list.5.xml:99
-#, fuzzy
-#| msgid ""
-#| "The URI for the <literal>deb</literal> type must specify the base of the "
-#| "Debian distribution, from which APT will find the information it needs.  "
-#| "<literal>distribution</literal> can specify an exact path, in which case "
-#| "the components must be omitted and <literal>distribution</literal> must "
-#| "end with a slash (<literal>/</literal>). This is useful for the case when "
-#| "only a particular sub-section of the archive denoted by the URI is of "
-#| "interest.  If <literal>distribution</literal> does not specify an exact "
-#| "path, at least one <literal>component</literal> must be present."
 msgid ""
 msgid ""
 "The URI for the <literal>deb</literal> type must specify the base of the "
 "The URI for the <literal>deb</literal> type must specify the base of the "
 "Debian distribution, from which APT will find the information it needs.  "
 "Debian distribution, from which APT will find the information it needs.  "
@@ -7003,25 +6978,15 @@ msgid ""
 msgstr ""
 msgstr ""
 "L'URI de type <literal>deb</literal> doit indiquer la base de la "
 "L'URI de type <literal>deb</literal> doit indiquer la base de la "
 "distribution Debian dans laquelle APT trouvera les informations dont il a "
 "distribution Debian dans laquelle APT trouvera les informations dont il a "
-"besoin.  <literal>distribution</literal> peut spécifier le chemin exact : "
-"dans ce cas, on doit omettre les composants et <literal>distribution</"
-"literal> doit se terminer par une barre oblique (<literal>/</literal>). "
-"C'est utile quand seule une sous-section particulière de l'archive décrite "
-"par cet URI est intéressante. Quand <literal>distribution</literal> "
-"n'indique pas un chemin exact, un <literal>composant</literal> au moins doit "
-"être présent."
+"besoin.  <literal>suite</literal> peut spécifier le chemin exact : dans ce "
+"cas, on doit omettre les composants et <literal>suite</literal> doit se "
+"terminer par une barre oblique (<literal>/</literal>). C'est utile quand "
+"seule une sous-section particulière de l'archive décrite par cet URI est "
+"intéressante. Quand <literal>suite</literal> n'indique pas un chemin exact, "
+"un <literal>composant</literal> au moins doit être présent."
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: sources.list.5.xml:108
 #: sources.list.5.xml:108
-#, fuzzy
-#| msgid ""
-#| "<literal>distribution</literal> may also contain a variable, <literal>"
-#| "$(ARCH)</literal> which expands to the Debian architecture (such as "
-#| "<literal>amd64</literal> or <literal>armel</literal>) used on the system. "
-#| "This permits architecture-independent <filename>sources.list</filename> "
-#| "files to be used. In general this is only of interest when specifying an "
-#| "exact path, <literal>APT</literal> will automatically generate a URI with "
-#| "the current architecture otherwise."
 msgid ""
 msgid ""
 "<literal>suite</literal> may also contain a variable, <literal>$(ARCH)</"
 "<literal>suite</literal> may also contain a variable, <literal>$(ARCH)</"
 "literal> which expands to the Debian architecture (such as <literal>amd64</"
 "literal> which expands to the Debian architecture (such as <literal>amd64</"
@@ -7031,29 +6996,16 @@ msgid ""
 "<literal>APT</literal> will automatically generate a URI with the current "
 "<literal>APT</literal> will automatically generate a URI with the current "
 "architecture otherwise."
 "architecture otherwise."
 msgstr ""
 msgstr ""
-"<literal>distribution</literal> peut aussi contenir une variable <literal>"
-"$(ARCH)</literal>, qui sera remplacée par l'architecture Debian (comme "
-"<literal>amd64</literal> ou <literal>armel</literal>)  sur laquelle "
-"s'exécute le système. On peut ainsi utiliser un fichier <filename>sources."
-"list</filename> qui ne dépend pas d'une architecture. En général, ce n'est "
+"<literal>suite</literal> peut aussi contenir une variable <literal>$(ARCH)</"
+"literal>, qui sera remplacée par l'architecture Debian (comme "
+"<literal>amd64</literal> ou <literal>armel</literal>) sur laquelle s'exécute "
+"le système. On peut ainsi utiliser un fichier <filename>sources.list</"
+"filename> qui ne dépend pas d'une architecture. En général, ce n'est "
 "intéressant que si l'on indique un chemin exact ; sinon <literal>APT</"
 "intéressant que si l'on indique un chemin exact ; sinon <literal>APT</"
 "literal> crée automatiquement un URI en fonction de l'architecture effective."
 "literal> crée automatiquement un URI en fonction de l'architecture effective."
 
 
 #. type: Content of: <refentry><refsect1><para>
 #. type: Content of: <refentry><refsect1><para>
 #: sources.list.5.xml:116
 #: sources.list.5.xml:116
-#, fuzzy
-#| msgid ""
-#| "Since only one distribution can be specified per line it may be necessary "
-#| "to have multiple lines for the same URI, if a subset of all available "
-#| "distributions or components at that location is desired.  APT will sort "
-#| "the URI list after it has generated a complete set internally, and will "
-#| "collapse multiple references to the same Internet host, for instance, "
-#| "into a single connection, so that it does not inefficiently establish an "
-#| "FTP connection, close it, do something else, and then re-establish a "
-#| "connection to that same host. This feature is useful for accessing busy "
-#| "FTP sites with limits on the number of simultaneous anonymous users. APT "
-#| "also parallelizes connections to different hosts to more effectively deal "
-#| "with sites with low bandwidth."
 msgid ""
 msgid ""
 "In the traditional style sources.list format since only one distribution can "
 "In the traditional style sources.list format since only one distribution can "
 "be specified per line it may be necessary to have multiple lines for the "
 "be specified per line it may be necessary to have multiple lines for the "
@@ -7067,7 +7019,8 @@ msgid ""
 "users. APT also parallelizes connections to different hosts to more "
 "users. APT also parallelizes connections to different hosts to more "
 "effectively deal with sites with low bandwidth."
 "effectively deal with sites with low bandwidth."
 msgstr ""
 msgstr ""
-"Puisqu'on ne peut indiquer qu'une seule distribution par ligne, il peut être "
+"Lorsqu'on utilise le type de style de sources.list traditionnel, puisqu'on "
+"ne peut indiquer qu'une seule distribution par ligne, il peut être "
 "nécessaire de disposer le même URI sur plusieurs lignes quand on veut "
 "nécessaire de disposer le même URI sur plusieurs lignes quand on veut "
 "accéder à un sous-ensemble des distributions ou composants disponibles à "
 "accéder à un sous-ensemble des distributions ou composants disponibles à "
 "cette adresse. APT trie les URI après avoir crée pour lui-même la liste "
 "cette adresse. APT trie les URI après avoir crée pour lui-même la liste "
@@ -7113,24 +7066,16 @@ msgstr ""
 
 
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #: sources.list.5.xml:140
 #: sources.list.5.xml:140
-#, fuzzy
-#| msgid ""
-#| "<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."
 msgid ""
 msgid ""
 "<literal>arch+=<replaceable>arch1</replaceable>,<replaceable>arch2</"
 "<literal>arch+=<replaceable>arch1</replaceable>,<replaceable>arch2</"
 "replaceable>,…</literal> and <literal>arch-=<replaceable>arch1</replaceable>,"
 "replaceable>,…</literal> and <literal>arch-=<replaceable>arch1</replaceable>,"
 "<replaceable>arch2</replaceable>,…</literal> which can be used to add/remove "
 "<replaceable>arch2</replaceable>,…</literal> which can be used to add/remove "
 "architectures from the set which will be downloaded."
 "architectures from the set which will be downloaded."
 msgstr ""
 msgstr ""
-"<literal>arch=<replaceable>arch1</replaceable>,<replaceable>arch2</"
-"replaceable>,…</literal> peut être utilisé pour indiquer les architectures "
-"pour lesquelles l'information doit être téléchargée. Si cette option n'est "
-"pas utilisée, toutes les architectures définies par l'option <literal>APT::"
-"Architectures</literal> sera téléchargée."
+"<literal>arch+=<replaceable>arch1</replaceable>,<replaceable>arch2</"
+"replaceable>,…</literal> et <literal>arch-=<replaceable>arch1</replaceable>,"
+"<replaceable>arch2</replaceable>,…</literal> qui peuvent être utilisés pour "
+"ajouter ou supprimer des architectures dans l'ensemble qui sera téléchargée."
 
 
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #. type: Content of: <refentry><refsect1><para><itemizedlist><listitem><para>
 #: sources.list.5.xml:143
 #: sources.list.5.xml:143
@@ -8541,7 +8486,7 @@ msgstr "jgg@debian.org"
 #. type: Content of: <book><bookinfo><releaseinfo>
 #. type: Content of: <book><bookinfo><releaseinfo>
 #: guide.dbk:21 offline.dbk:21
 #: guide.dbk:21 offline.dbk:21
 msgid "Version &apt-product-version;"
 msgid "Version &apt-product-version;"
-msgstr ""
+msgstr "Version &apt-product-version;"
 
 
 #. type: Content of: <book><bookinfo><abstract><para>
 #. type: Content of: <book><bookinfo><abstract><para>
 #: guide.dbk:25
 #: guide.dbk:25
@@ -8561,7 +8506,7 @@ msgstr ""
 #. type: Content of: <book><bookinfo><legalnotice><title>
 #. type: Content of: <book><bookinfo><legalnotice><title>
 #: guide.dbk:32 offline.dbk:33
 #: guide.dbk:32 offline.dbk:33
 msgid "License Notice"
 msgid "License Notice"
-msgstr ""
+msgstr "Mention de licence "
 
 
 #. type: Content of: <book><bookinfo><legalnotice><para>
 #. type: Content of: <book><bookinfo><legalnotice><para>
 #: guide.dbk:34 offline.dbk:35
 #: guide.dbk:34 offline.dbk:35
@@ -8884,16 +8829,6 @@ msgstr ""
 
 
 #. type: Content of: <book><chapter><para>
 #. type: Content of: <book><chapter><para>
 #: guide.dbk:188
 #: guide.dbk:188
-#, fuzzy
-#| msgid ""
-#| "<command>apt-get</command> has several command line options that are "
-#| "detailed in its man page, <manref section=\"8\" name=\"apt-get\">. The "
-#| "most useful option is <literal>-d</literal> which does not install the "
-#| "fetched files. If the system has to download a large number of package it "
-#| "would be undesired to start installing them in case something goes wrong. "
-#| "When <literal>-d</literal> is used the downloaded archives can be "
-#| "installed by simply running the command that caused them to be downloaded "
-#| "again without <literal>-d</literal>."
 msgid ""
 msgid ""
 "<command>apt-get</command> has several command line options that are "
 "<command>apt-get</command> has several command line options that are "
 "detailed in its man page, <citerefentry><refentrytitle>apt-get</"
 "detailed in its man page, <citerefentry><refentrytitle>apt-get</"
@@ -8906,9 +8841,10 @@ msgid ""
 "literal>."
 "literal>."
 msgstr ""
 msgstr ""
 "<command>apt-get</command> fournit de nombreuses options de ligne de "
 "<command>apt-get</command> fournit de nombreuses options de ligne de "
-"commande qui sont expliquées en détail dans sa page de manuel, <manref "
-"section=\"8\" name=\"apt-get\">. Une des plus utiles est l'option <literal>-"
-"d</literal> qui récupère sans les installer les fichiers nécessaires. Si le "
+"commande qui sont expliquées en détail dans sa page de manuel, "
+"<citerefentry><refentrytitle>apt-get</refentrytitle><manvolnum>8</"
+"manvolnum></citerefentry>. Une des plus utiles est l'option <literal>-d</"
+"literal> qui récupère sans les installer les fichiers nécessaires. Si le "
 "système a besoin de télécharger un grand nombre de paquets, il est par "
 "système a besoin de télécharger un grand nombre de paquets, il est par "
 "exemple souhaitable de pouvoir simplement les récupérer sans les installer "
 "exemple souhaitable de pouvoir simplement les récupérer sans les installer "
 "immédiatement, au cas où quelque chose se passe mal. Une fois que <literal>-"
 "immédiatement, au cas où quelque chose se passe mal. Une fois que <literal>-"
@@ -9998,7 +9934,7 @@ msgid ""
 "the target machine. Take the disc back and run:"
 "the target machine. Take the disc back and run:"
 msgstr ""
 msgstr ""
 "Après cette opération, le disque contiendra tous les fichiers d'index et les "
 "Après cette opération, le disque contiendra tous les fichiers d'index et les "
-"archives nécessaires pour mettr eà jour la machine cible. Il est alors "
+"archives nécessaires pour mettre à jour la machine cible. Il est alors "
 "possible d'y ramener le disque et exécuter :"
 "possible d'y ramener le disque et exécuter :"
 
 
 #. type: Content of: <book><chapter><section><screen>
 #. type: Content of: <book><chapter><section><screen>

+ 3 - 3
ftparchive/cachedb.cc

@@ -328,12 +328,12 @@ bool CacheDB::LoadSource()
    if (Dsc.Read(FileName) == false)
    if (Dsc.Read(FileName) == false)
       return false;
       return false;
 
 
-   if (Dsc.Data == 0)
+   if (Dsc.Length == 0)
       return _error->Error(_("Failed to read .dsc"));
       return _error->Error(_("Failed to read .dsc"));
-   
+
    // Write back the control information
    // Write back the control information
    InitQuerySource();
    InitQuerySource();
-   if (Put(Dsc.Data, Dsc.Length) == true)
+   if (Put(Dsc.Data.c_str(), Dsc.Length) == true)
       CurStat.Flags |= FlSource;
       CurStat.Flags |= FlSource;
 
 
    return true;
    return true;

+ 27 - 14
ftparchive/sources.cc

@@ -1,5 +1,5 @@
 #include <string>
 #include <string>
-#include <iostream>
+#include <sstream>
 
 
 // for memcpy
 // for memcpy
 #include <cstring>
 #include <cstring>
@@ -9,17 +9,19 @@
 
 
 #include "sources.h"
 #include "sources.h"
 
 
-bool DscExtract::TakeDsc(const void *newData, unsigned long newSize)
+bool DscExtract::TakeDsc(const void *newData, unsigned long long newSize)
 {
 {
-   if(newSize > maxSize)
-     return _error->Error("DSC data is too large %lu!", newSize);
-
    if (newSize == 0)
    if (newSize == 0)
    {
    {
+      // adding two newlines 'off record' for pkgTagSection.Scan() calls
+      Data = "\n\n";
       Length = 0;
       Length = 0;
       return true;
       return true;
    }
    }
-   memcpy(Data, newData, newSize);
+
+   Data = std::string((const char*)newData, newSize);
+   // adding two newlines 'off record' for pkgTagSection.Scan() calls
+   Data.append("\n\n");
    Length = newSize;
    Length = newSize;
 
 
    return true;
    return true;
@@ -27,20 +29,31 @@ bool DscExtract::TakeDsc(const void *newData, unsigned long newSize)
 
 
 bool DscExtract::Read(std::string FileName)
 bool DscExtract::Read(std::string FileName)
 {
 {
+   Data.clear();
+   Length = 0;
+
    FileFd F;
    FileFd F;
    if (OpenMaybeClearSignedFile(FileName, F) == false)
    if (OpenMaybeClearSignedFile(FileName, F) == false)
       return false;
       return false;
-   
-   unsigned long long const FSize = F.FileSize();
-   if(FSize > maxSize)
-     return _error->Error("DSC file '%s' is too large!",FileName.c_str());
-
-   if (F.Read(Data, FSize) == false)
-      return false;
-   Length = FSize;
 
 
    IsClearSigned = (FileName != F.Name());
    IsClearSigned = (FileName != F.Name());
 
 
+   std::ostringstream data;
+   char buffer[1024];
+   do {
+      unsigned long long actual = 0;
+      if (F.Read(buffer, sizeof(buffer)-1, &actual) == false)
+	 return _error->Errno("read", "Failed to read dsc file %s", FileName.c_str());
+      if (actual == 0)
+	 break;
+      Length += actual;
+      buffer[actual] = '\0';
+      data << buffer;
+   } while(true);
+
+   // adding two newlines 'off record' for pkgTagSection.Scan() calls
+   data << "\n\n";
+   Data = data.str();
    return true;
    return true;
 }
 }
 
 

+ 9 - 17
ftparchive/sources.h

@@ -3,29 +3,21 @@
 
 
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/tagfile.h>
 
 
-class DscExtract 
+#include <string>
+
+class DscExtract
 {
 {
  public:
  public:
-   //FIXME: do we really need to enforce a maximum size of the dsc file?
-   static const int maxSize = 128*1024;
-
-   char *Data;
+   std::string Data;
    pkgTagSection Section;
    pkgTagSection Section;
-   unsigned long Length;
+   unsigned long long Length;
    bool IsClearSigned;
    bool IsClearSigned;
 
 
-   bool TakeDsc(const void *Data, unsigned long Size);
+   bool TakeDsc(const void *Data, unsigned long long Size);
    bool Read(std::string FileName);
    bool Read(std::string FileName);
-   
-   DscExtract() : Data(0), Length(0) {
-     Data = new char[maxSize];
-   };
-   ~DscExtract() { 
-      if(Data != NULL) {
-         delete [] Data;
-         Data = NULL;
-      } 
-   };
+
+   DscExtract() : Length(0), IsClearSigned(false) {};
+   ~DscExtract() {};
 };
 };
 
 
 
 

+ 2 - 10
ftparchive/writer.cc

@@ -634,18 +634,10 @@ bool SourcesWriter::DoPackage(string FileName)
    // the "db cursor"
    // the "db cursor"
    Db.Finish();
    Db.Finish();
 
 
-   // read stuff
-   char *Start = Db.Dsc.Data;
-   char *BlkEnd = Db.Dsc.Data + Db.Dsc.Length;
-
-   // Add extra \n to the end, just in case (as in clearsigned they are missing)
-   *BlkEnd++ = '\n';
-   *BlkEnd++ = '\n';
-
    pkgTagSection Tags;
    pkgTagSection Tags;
-   if (Tags.Scan(Start,BlkEnd - Start) == false)
+   if (Tags.Scan(Db.Dsc.Data.c_str(), Db.Dsc.Data.length()) == false)
       return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
       return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
-   
+
    if (Tags.Exists("Source") == false)
    if (Tags.Exists("Source") == false)
       return _error->Error("Could not find a Source entry in the DSC '%s'",FileName.c_str());
       return _error->Error("Could not find a Source entry in the DSC '%s'",FileName.c_str());
    Tags.Trim();
    Tags.Trim();

+ 2 - 0
methods/http.cc

@@ -440,6 +440,8 @@ bool HttpServerState::RunData(FileFd * const File)
          loss of the connection means we are done */
          loss of the connection means we are done */
       if (Encoding == Closes)
       if (Encoding == Closes)
 	 In.Limit(-1);
 	 In.Limit(-1);
+      else if (JunkSize != 0)
+	 In.Limit(JunkSize);
       else
       else
 	 In.Limit(Size - StartPos);
 	 In.Limit(Size - StartPos);
       
       

+ 17 - 4
methods/https.cc

@@ -59,6 +59,9 @@ HttpsMethod::parse_header(void *buffer, size_t size, size_t nmemb, void *userp)
       {
       {
          me->Server->Result = 200;
          me->Server->Result = 200;
 	 me->Server->StartPos = me->Server->Size;
 	 me->Server->StartPos = me->Server->Size;
+	 // the actual size is not important for https as curl will deal with it
+	 // by itself and e.g. doesn't bother us with transport-encoding…
+	 me->Server->JunkSize = std::numeric_limits<unsigned long long>::max();
       }
       }
       else
       else
 	 me->Server->StartPos = 0;
 	 me->Server->StartPos = 0;
@@ -76,18 +79,27 @@ size_t
 HttpsMethod::write_data(void *buffer, size_t size, size_t nmemb, void *userp)
 HttpsMethod::write_data(void *buffer, size_t size, size_t nmemb, void *userp)
 {
 {
    HttpsMethod *me = (HttpsMethod *)userp;
    HttpsMethod *me = (HttpsMethod *)userp;
+   size_t buffer_size = size * nmemb;
+   // we don't need to count the junk here, just drop anything we get as
+   // we don't always know how long it would be, e.g. in chunked encoding.
+   if (me->Server->JunkSize != 0)
+      return buffer_size;
 
 
-   if (me->Res.Size == 0)
+   if (me->ReceivedData == false)
+   {
       me->URIStart(me->Res);
       me->URIStart(me->Res);
-   if(me->File->Write(buffer, size*nmemb) != true)
+      me->ReceivedData = true;
+   }
+
+   if(me->File->Write(buffer, buffer_size) != true)
       return false;
       return false;
 
 
-   return size*nmemb;
+   return buffer_size;
 }
 }
 
 
 int
 int
 HttpsMethod::progress_callback(void *clientp, double dltotal, double /*dlnow*/,
 HttpsMethod::progress_callback(void *clientp, double dltotal, double /*dlnow*/,
-			      double /*ultotal*/, double /*ulnow*/)
+                             double /*ultotal*/, double /*ulnow*/)
 {
 {
    HttpsMethod *me = (HttpsMethod *)clientp;
    HttpsMethod *me = (HttpsMethod *)clientp;
    if(dltotal > 0 && me->Res.Size == 0) {
    if(dltotal > 0 && me->Res.Size == 0) {
@@ -171,6 +183,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    char curl_errorstr[CURL_ERROR_SIZE];
    char curl_errorstr[CURL_ERROR_SIZE];
    URI Uri = Itm->Uri;
    URI Uri = Itm->Uri;
    string remotehost = Uri.Host;
    string remotehost = Uri.Host;
+   ReceivedData = false;
 
 
    // TODO:
    // TODO:
    //       - http::Pipeline-Depth
    //       - http::Pipeline-Depth

+ 1 - 0
methods/https.h

@@ -66,6 +66,7 @@ class HttpsMethod : public pkgAcqMethod
    CURL *curl;
    CURL *curl;
    FetchResult Res;
    FetchResult Res;
    HttpsServerState *Server;
    HttpsServerState *Server;
+   bool ReceivedData;
 
 
    public:
    public:
    FileFd *File;
    FileFd *File;

+ 16 - 12
methods/server.cc

@@ -55,6 +55,7 @@ ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File,
    Minor = 0; 
    Minor = 0; 
    Result = 0; 
    Result = 0; 
    Size = 0; 
    Size = 0; 
+   JunkSize = 0;
    StartPos = 0;
    StartPos = 0;
    Encoding = Closes;
    Encoding = Closes;
    HaveContent = false;
    HaveContent = false;
@@ -128,7 +129,7 @@ bool ServerState::HeaderLine(string Line)
 	 if (elements == 3)
 	 if (elements == 3)
 	 {
 	 {
 	    Code[0] = '\0';
 	    Code[0] = '\0';
-	    if (Owner->Debug == true)
+	    if (Owner != NULL && Owner->Debug == true)
 	       clog << "HTTP server doesn't give Reason-Phrase for " << Result << std::endl;
 	       clog << "HTTP server doesn't give Reason-Phrase for " << Result << std::endl;
 	 }
 	 }
 	 else if (elements != 4)
 	 else if (elements != 4)
@@ -163,14 +164,14 @@ bool ServerState::HeaderLine(string Line)
 	 Encoding = Stream;
 	 Encoding = Stream;
       HaveContent = true;
       HaveContent = true;
 
 
-      // The length is already set from the Content-Range header
-      if (StartPos != 0)
-	 return true;
+      unsigned long long * SizePtr = &Size;
+      if (Result == 416)
+	 SizePtr = &JunkSize;
 
 
-      Size = strtoull(Val.c_str(), NULL, 10);
-      if (Size >= std::numeric_limits<unsigned long long>::max())
+      *SizePtr = strtoull(Val.c_str(), NULL, 10);
+      if (*SizePtr >= std::numeric_limits<unsigned long long>::max())
 	 return _error->Errno("HeaderLine", _("The HTTP server sent an invalid Content-Length header"));
 	 return _error->Errno("HeaderLine", _("The HTTP server sent an invalid Content-Length header"));
-      else if (Size == 0)
+      else if (*SizePtr == 0)
 	 HaveContent = false;
 	 HaveContent = false;
       return true;
       return true;
    }
    }
@@ -187,10 +188,7 @@ bool ServerState::HeaderLine(string Line)
 
 
       // §14.16 says 'byte-range-resp-spec' should be a '*' in case of 416
       // §14.16 says 'byte-range-resp-spec' should be a '*' in case of 416
       if (Result == 416 && sscanf(Val.c_str(), "bytes */%llu",&Size) == 1)
       if (Result == 416 && sscanf(Val.c_str(), "bytes */%llu",&Size) == 1)
-      {
-	 StartPos = 1; // ignore Content-Length, it would override Size
-	 HaveContent = false;
-      }
+	 ; // we got the expected filesize which is all we wanted
       else if (sscanf(Val.c_str(),"bytes %llu-%*u/%llu",&StartPos,&Size) != 2)
       else if (sscanf(Val.c_str(),"bytes %llu-%*u/%llu",&StartPos,&Size) != 2)
 	 return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
 	 return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
       if ((unsigned long long)StartPos > Size)
       if ((unsigned long long)StartPos > Size)
@@ -308,9 +306,15 @@ ServerMethod::DealWithHeaders(FetchResult &Res)
 	 if ((unsigned long long)SBuf.st_size == Server->Size)
 	 if ((unsigned long long)SBuf.st_size == Server->Size)
 	 {
 	 {
 	    // the file is completely downloaded, but was not moved
 	    // the file is completely downloaded, but was not moved
+	    if (Server->HaveContent == true)
+	    {
+	       // Send to error page to dev/null
+	       FileFd DevNull("/dev/null",FileFd::WriteExists);
+	       Server->RunData(&DevNull);
+	    }
+	    Server->HaveContent = false;
 	    Server->StartPos = Server->Size;
 	    Server->StartPos = Server->Size;
 	    Server->Result = 200;
 	    Server->Result = 200;
-	    Server->HaveContent = false;
 	 }
 	 }
 	 else if (unlink(Queue->DestFile.c_str()) == 0)
 	 else if (unlink(Queue->DestFile.c_str()) == 0)
 	 {
 	 {

+ 3 - 2
methods/server.h

@@ -34,7 +34,8 @@ struct ServerState
    char Code[360];
    char Code[360];
 
 
    // These are some statistics from the last parsed header lines
    // These are some statistics from the last parsed header lines
-   unsigned long long Size;
+   unsigned long long Size; // size of the usable content (aka: the file)
+   unsigned long long JunkSize; // size of junk content (aka: server error pages)
    unsigned long long StartPos;
    unsigned long long StartPos;
    time_t Date;
    time_t Date;
    bool HaveContent;
    bool HaveContent;
@@ -71,7 +72,7 @@ struct ServerState
    RunHeadersResult RunHeaders(FileFd * const File, const std::string &Uri);
    RunHeadersResult RunHeaders(FileFd * const File, const std::string &Uri);
 
 
    bool Comp(URI Other) const {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;};
    bool Comp(URI Other) const {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;};
-   virtual void Reset() {Major = 0; Minor = 0; Result = 0; Code[0] = '\0'; Size = 0;
+   virtual void Reset() {Major = 0; Minor = 0; Result = 0; Code[0] = '\0'; Size = 0; JunkSize = 0;
 		 StartPos = 0; Encoding = Closes; time(&Date); HaveContent = false;
 		 StartPos = 0; Encoding = Closes; time(&Date); HaveContent = false;
 		 State = Header; Persistent = false; Pipeline = true;};
 		 State = Header; Persistent = false; Pipeline = true;};
    virtual bool WriteResponse(std::string const &Data) = 0;
    virtual bool WriteResponse(std::string const &Data) = 0;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1008 - 1013
po/apt-all.pot


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1212 - 1217
po/ar.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1310 - 1315
po/ast.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1311 - 1316
po/bg.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1111 - 1116
po/bs.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1318 - 1323
po/ca.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1309 - 1311
po/cs.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1309 - 1314
po/cy.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1296 - 1298
po/da.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1328 - 1330
po/de.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1303 - 1308
po/dz.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1296 - 1301
po/el.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1624 - 1559
po/es.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1295 - 1300
po/eu.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1296 - 1301
po/fi.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1520 - 1509
po/fr.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1311 - 1316
po/gl.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1306 - 1311
po/hu.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1326 - 1328
po/it.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1330 - 1325
po/ja.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1299 - 1304
po/km.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1305 - 1310
po/ko.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1136 - 1141
po/ku.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1250 - 1255
po/lt.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1301 - 1306
po/mr.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1310 - 1315
po/nb.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1304 - 1309
po/ne.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1700 - 1622
po/nl.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1299 - 1304
po/nn.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1311 - 1316
po/pl.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1316 - 1321
po/pt.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1302 - 1307
po/pt_BR.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1298 - 1303
po/ro.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1316 - 1321
po/ru.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1301 - 1306
po/sk.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1299 - 1304
po/sl.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1314 - 1319
po/sv.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1292 - 1294
po/th.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1302 - 1307
po/tl.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1369 - 1374
po/tr.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1326 - 1331
po/uk.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1326 - 1328
po/vi.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1545 - 1504
po/zh_CN.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1285 - 1290
po/zh_TW.po


+ 81 - 32
test/integration/framework

@@ -102,7 +102,7 @@ runapt() {
 	local CMD="$1"
 	local CMD="$1"
 	shift
 	shift
 	case $CMD in
 	case $CMD in
-	sh|aptitude|*/*) ;;
+	sh|aptitude|*/*|command) ;;
 	*) CMD="${BUILDDIRECTORY}/$CMD";;
 	*) CMD="${BUILDDIRECTORY}/$CMD";;
 	esac
 	esac
 	MALLOC_PERTURB_=21 MALLOC_CHECK_=2 APT_CONFIG="$(getaptconfig)" LD_LIBRARY_PATH=${BUILDDIRECTORY} $CMD "$@"
 	MALLOC_PERTURB_=21 MALLOC_CHECK_=2 APT_CONFIG="$(getaptconfig)" LD_LIBRARY_PATH=${BUILDDIRECTORY} $CMD "$@"
@@ -325,6 +325,59 @@ configdpkg() {
 	fi
 	fi
 }
 }
 
 
+configdpkgnoopchroot() {
+	# create a library to noop chroot() and rewrite maintainer script executions
+	# via execvp() as used by dpkg as we don't want our rootdir to be a fullblown
+	# chroot directory dpkg could chroot into to execute the maintainer scripts
+	msgtest 'Building library to preload to make maintainerscript work in' 'dpkg'
+	cat << EOF > noopchroot.c
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+static char * chrootdir = NULL;
+
+int chroot(const char *path) {
+	printf("WARNING: CHROOTing to %s was ignored!\n", path);
+	free(chrootdir);
+	chrootdir = strdup(path);
+	return 0;
+}
+int execvp(const char *file, char *const argv[]) {
+	static int (*func_execvp) (const char *, char * const []) = NULL;
+	if (func_execvp == NULL)
+		func_execvp = (int (*) (const char *, char * const [])) dlsym(RTLD_NEXT, "execvp");
+	if (chrootdir == NULL || strncmp(file, "/var/lib/dpkg/", strlen("/var/lib/dpkg/")) != 0)
+		return func_execvp(file, argv);
+	printf("REWRITE execvp call %s into %s\n", file, chrootdir);
+	char newfile[strlen(chrootdir) + strlen(file)];
+	strcpy(newfile, chrootdir);
+	strcat(newfile, file);
+	return func_execvp(newfile, argv);
+}
+EOF
+	testsuccess --nomsg gcc -fPIC -shared -o noopchroot.so noopchroot.c -ldl
+
+	mkdir -p "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/"
+	DPKG="${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg"
+	echo "#!/bin/sh
+if [ -n \"\$LD_PRELOAD\" ]; then
+	export LD_PRELOAD=\"${TMPWORKINGDIRECTORY}/noopchroot.so \${LD_PRELOAD}\"
+else
+	export LD_PRELOAD=\"${TMPWORKINGDIRECTORY}/noopchroot.so\"
+fi
+dpkg \"\$@\"" > $DPKG
+	chmod +x $DPKG
+	sed -ie "s|^DPKG::options:: \"dpkg\";\$|DPKG::options:: \"$DPKG\";|" aptconfig.conf
+}
+
+configallowinsecurerepositories() {
+    echo "Acquire::AllowInsecureRepositories \"$1\";" >  rootdir/etc/apt/apt.conf.d/allow-insecure-repositories.conf
+
+}
+
 configcompression() {
 configcompression() {
 	while [ -n "$1" ]; do
 	while [ -n "$1" ]; do
 		case "$1" in
 		case "$1" in
@@ -442,7 +495,7 @@ buildsimplenativepackage() {
 	fi
 	fi
 	local BUILDDIR=${TMPWORKINGDIRECTORY}/incoming/${NAME}-${VERSION}
 	local BUILDDIR=${TMPWORKINGDIRECTORY}/incoming/${NAME}-${VERSION}
 
 
-	msgninfo "Build package ${NAME} in ${VERSION} for ${RELEASE} in ${DISTSECTION}… "
+	msgtest "Build source package in version ${VERSION} for ${RELEASE} in ${DISTSECTION}" "$NAME"
 	mkdir -p $BUILDDIR/debian/source
 	mkdir -p $BUILDDIR/debian/source
 	echo "* most suckless software product ever" > ${BUILDDIR}/FEATURES
 	echo "* most suckless software product ever" > ${BUILDDIR}/FEATURES
 	echo "#!/bin/sh
 	echo "#!/bin/sh
@@ -474,7 +527,10 @@ Package: $NAME" >> ${BUILDDIR}/debian/control
 	echo "Description: $DESCRIPTION" >> ${BUILDDIR}/debian/control
 	echo "Description: $DESCRIPTION" >> ${BUILDDIR}/debian/control
 
 
 	echo '3.0 (native)' > ${BUILDDIR}/debian/source/format
 	echo '3.0 (native)' > ${BUILDDIR}/debian/source/format
-	(cd ${BUILDDIR}/..; dpkg-source -b ${NAME}-${VERSION} 2>&1) | sed -n 's#^dpkg-source: info: building [^ ]\+ in ##p' \
+	cd ${BUILDDIR}/..
+	testsuccess --nomsg dpkg-source -b ${NAME}-${VERSION}
+	cd - >/dev/null
+	sed -n 's#^dpkg-source: info: building [^ ]\+ in ##p' ${TMPWORKINGDIRECTORY}/rootdir/tmp/testsuccess.output \
 		| while read SRC; do
 		| while read SRC; do
 		echo "pool/${SRC}" >> ${BUILDDIR}/../${RELEASE}.${DISTSECTION}.srclist
 		echo "pool/${SRC}" >> ${BUILDDIR}/../${RELEASE}.${DISTSECTION}.srclist
 #		if expr match "${SRC}" '.*\.dsc' >/dev/null 2>&1; then
 #		if expr match "${SRC}" '.*\.dsc' >/dev/null 2>&1; then
@@ -486,6 +542,7 @@ Package: $NAME" >> ${BUILDDIR}/debian/control
 	done
 	done
 
 
 	for arch in $(getarchitecturesfromcommalist "$ARCH"); do
 	for arch in $(getarchitecturesfromcommalist "$ARCH"); do
+		msgtest "Build binary package for ${RELEASE} in ${SECTION}" "$NAME"
 		rm -rf ${BUILDDIR}/debian/tmp
 		rm -rf ${BUILDDIR}/debian/tmp
 		mkdir -p ${BUILDDIR}/debian/tmp/DEBIAN ${BUILDDIR}/debian/tmp/usr/share/doc/${NAME} ${BUILDDIR}/debian/tmp/usr/bin
 		mkdir -p ${BUILDDIR}/debian/tmp/DEBIAN ${BUILDDIR}/debian/tmp/usr/share/doc/${NAME} ${BUILDDIR}/debian/tmp/usr/bin
 		cp ${BUILDDIR}/debian/copyright ${BUILDDIR}/debian/changelog ${BUILDDIR}/FEATURES ${BUILDDIR}/debian/tmp/usr/share/doc/${NAME}
 		cp ${BUILDDIR}/debian/copyright ${BUILDDIR}/debian/changelog ${BUILDDIR}/FEATURES ${BUILDDIR}/debian/tmp/usr/share/doc/${NAME}
@@ -499,11 +556,7 @@ Package: $NAME" >> ${BUILDDIR}/debian/control
 		local LOG="${BUILDDIR}/../${NAME}_${VERSION}_${arch}.dpkg-deb.log"
 		local LOG="${BUILDDIR}/../${NAME}_${VERSION}_${arch}.dpkg-deb.log"
 		# ensure the right permissions as dpkg-deb ensists
 		# ensure the right permissions as dpkg-deb ensists
 		chmod 755 ${BUILDDIR}/debian/tmp/DEBIAN
 		chmod 755 ${BUILDDIR}/debian/tmp/DEBIAN
-		if ! dpkg-deb -Z${COMPRESS_TYPE} --build ${BUILDDIR}/debian/tmp ${BUILDDIR}/.. >$LOG 2>&1; then
-			cat $LOG
-			false
-		fi
-		rm $LOG
+		testsuccess --nomsg dpkg-deb -Z${COMPRESS_TYPE} --build ${BUILDDIR}/debian/tmp ${BUILDDIR}/..
 		echo "pool/${NAME}_${VERSION}_${arch}.deb" >> ${BUILDDIR}/../${RELEASE}.${DISTSECTION}.pkglist
 		echo "pool/${NAME}_${VERSION}_${arch}.deb" >> ${BUILDDIR}/../${RELEASE}.${DISTSECTION}.pkglist
 	done
 	done
 
 
@@ -521,15 +574,13 @@ buildpackage() {
 	local ARCH=$(getarchitecture $4)
 	local ARCH=$(getarchitecture $4)
 	local PKGNAME="$(echo "$BUILDDIR" | grep -o '[^/]*$')"
 	local PKGNAME="$(echo "$BUILDDIR" | grep -o '[^/]*$')"
 	local BUILDLOG="$(readlink -f "${BUILDDIR}/../${PKGNAME}_${RELEASE}_${SECTION}.dpkg-bp.log")"
 	local BUILDLOG="$(readlink -f "${BUILDDIR}/../${PKGNAME}_${RELEASE}_${SECTION}.dpkg-bp.log")"
-	msgninfo "Build package ${PKGNAME} for ${RELEASE} in ${SECTION}… "
+	msgtest "Build package for ${RELEASE} in ${SECTION}" "$PKGNAME"
 	cd $BUILDDIR
 	cd $BUILDDIR
 	if [ "$ARCH" = "all" ]; then
 	if [ "$ARCH" = "all" ]; then
 		ARCH="$(dpkg-architecture -qDEB_HOST_ARCH 2> /dev/null)"
 		ARCH="$(dpkg-architecture -qDEB_HOST_ARCH 2> /dev/null)"
 	fi
 	fi
-	if ! dpkg-buildpackage -uc -us -a$ARCH >$BUILDLOG 2>&1 ; then
-		cat $BUILDLOG
-		false
-	fi
+	testsuccess --nomsg dpkg-buildpackage -uc -us -a$ARCH
+	cp ${TMPWORKINGDIRECTORY}/rootdir/tmp/testsuccess.output $BUILDLOG
 	local PKGS="$(grep '^dpkg-deb: building package' $BUILDLOG | cut -d'/' -f 2 | sed -e "s#'\.##")"
 	local PKGS="$(grep '^dpkg-deb: building package' $BUILDLOG | cut -d'/' -f 2 | sed -e "s#'\.##")"
 	local SRCS="$(grep '^dpkg-source: info: building' $BUILDLOG | grep -o '[a-z0-9._+~-]*$')"
 	local SRCS="$(grep '^dpkg-source: info: building' $BUILDLOG | grep -o '[a-z0-9._+~-]*$')"
 	cd - > /dev/null
 	cd - > /dev/null
@@ -539,7 +590,6 @@ buildpackage() {
 	for SRC in $SRCS; do
 	for SRC in $SRCS; do
 		echo "pool/${SRC}" >> ${TMPWORKINGDIRECTORY}/incoming/${RELEASE}.${SECTION}.srclist
 		echo "pool/${SRC}" >> ${TMPWORKINGDIRECTORY}/incoming/${RELEASE}.${SECTION}.srclist
 	done
 	done
-	msgdone "info"
 }
 }
 
 
 buildaptarchive() {
 buildaptarchive() {
@@ -730,7 +780,7 @@ buildaptarchivefromincoming() {
 	[ -e ftparchive.conf ] || createaptftparchiveconfig
 	[ -e ftparchive.conf ] || createaptftparchiveconfig
 	[ -e dists ] || buildaptftparchivedirectorystructure
 	[ -e dists ] || buildaptftparchivedirectorystructure
 	msgninfo "\tGenerate Packages, Sources and Contents files… "
 	msgninfo "\tGenerate Packages, Sources and Contents files… "
-	aptftparchive -qq generate ftparchive.conf
+	testsuccess aptftparchive generate ftparchive.conf
 	cd - > /dev/null
 	cd - > /dev/null
 	msgdone "info"
 	msgdone "info"
 	generatereleasefiles
 	generatereleasefiles
@@ -1014,8 +1064,8 @@ acquire::cdrom::autodetect 0;" > rootdir/etc/apt/apt.conf.d/00cdrom
 }
 }
 
 
 downloadfile() {
 downloadfile() {
-	local PROTO="$(echo "$1" | cut -d':' -f 1 )"
-	apthelper -o Debug::Acquire::${PROTO}=1 \
+	local PROTO="${1%%:*}"
+	apthelper -o Debug::Acquire::${PROTO}=1 -o Debug::pkgAcquire::Worker=1 \
 		download-file "$1" "$2" 2>&1 || true
 		download-file "$1" "$2" 2>&1 || true
 	# only if the file exists the download was successful
 	# only if the file exists the download was successful
 	if [ -e "$2" ]; then
 	if [ -e "$2" ]; then
@@ -1072,7 +1122,7 @@ testequal() {
 	if [ -n "$MSG" ]; then
 	if [ -n "$MSG" ]; then
 		msgtest "$MSG" "$*"
 		msgtest "$MSG" "$*"
 	fi
 	fi
-	$* 2>&1 | checkdiff $COMPAREFILE - && msgpass || msgfail
+	"$@" 2>&1 | checkdiff $COMPAREFILE - && msgpass || msgfail
 }
 }
 
 
 testequalor2() {
 testequalor2() {
@@ -1128,10 +1178,13 @@ testnopackage() {
 	fi
 	fi
 }
 }
 
 
-testdpkginstalled() {
-	msgtest "Test for correctly installed package(s) with" "dpkg -l $*"
-	local PKGS="$(dpkg -l "$@" 2>/dev/null | grep '^i' | wc -l)"
-	if [ "$PKGS" != $# ]; then
+testdpkgstatus() {
+	local STATE="$1"
+	local NR="$2"
+	shift 2
+	msgtest "Test that $NR package(s) are in state $STATE with" "dpkg -l $*"
+	local PKGS="$(dpkg -l "$@" 2>/dev/null | grep "^${STATE}" | wc -l)"
+	if [ "$PKGS" != $NR ]; then
 		echo >&2 $PKGS
 		echo >&2 $PKGS
 		dpkg -l "$@" | grep '^[a-z]' >&2
 		dpkg -l "$@" | grep '^[a-z]' >&2
 		msgfail
 		msgfail
@@ -1140,16 +1193,12 @@ testdpkginstalled() {
 	fi
 	fi
 }
 }
 
 
+testdpkginstalled() {
+	testdpkgstatus 'ii' "$#" "$@"
+}
+
 testdpkgnotinstalled() {
 testdpkgnotinstalled() {
-	msgtest "Test for correctly not-installed package(s) with" "dpkg -l $*"
-	local PKGS="$(dpkg -l "$@" 2> /dev/null | grep '^i' | wc -l)"
-	if [ "$PKGS" != 0 ]; then
-		echo
-		dpkg -l "$@" | grep '^[a-z]' >&2
-		msgfail
-	else
-		msgpass
-	fi
+	testdpkgstatus 'ii' '0' "$@"
 }
 }
 
 
 testmarkedauto() {
 testmarkedauto() {
@@ -1171,7 +1220,7 @@ testsuccess() {
 		msgtest 'Test for successful execution of' "$*"
 		msgtest 'Test for successful execution of' "$*"
 	fi
 	fi
 	local OUTPUT="${TMPWORKINGDIRECTORY}/rootdir/tmp/testsuccess.output"
 	local OUTPUT="${TMPWORKINGDIRECTORY}/rootdir/tmp/testsuccess.output"
-	if $@ >${OUTPUT} 2>&1; then
+	if "$@" >${OUTPUT} 2>&1; then
 		msgpass
 		msgpass
 	else
 	else
 		echo >&2
 		echo >&2

+ 28 - 0
test/integration/test-allow-scores-for-all-dependency-types

@@ -32,6 +32,11 @@ insertpackage 'multipleyes' 'foo' 'amd64' '2.2' 'Conflicts: bar (<= 3)'
 # having foo multiple times as conflict is a non-advisable hack in general
 # having foo multiple times as conflict is a non-advisable hack in general
 insertpackage 'multipleyes' 'bar' 'amd64' '2.2' 'Conflicts: foo (<= 3), foo (<= 3)'
 insertpackage 'multipleyes' 'bar' 'amd64' '2.2' 'Conflicts: foo (<= 3), foo (<= 3)'
 
 
+#774924 - slightly simplified
+insertpackage 'jessie' 'login' 'amd64' '2' 'Pre-Depends: libaudit1 (>= 0)'
+insertpackage 'jessie' 'libaudit1' 'amd64' '2' 'Depends: libaudit-common (>= 0)'
+insertpackage 'jessie' 'libaudit-common' 'amd64' '2' 'Breaks: libaudit0, libaudit1 (<< 2)'
+
 cp rootdir/var/lib/dpkg/status rootdir/var/lib/dpkg/status-backup
 cp rootdir/var/lib/dpkg/status rootdir/var/lib/dpkg/status-backup
 setupaptarchive
 setupaptarchive
 
 
@@ -142,3 +147,26 @@ Inst foo [1] (2 versioned [amd64])
 Inst baz (2 versioned [amd64])
 Inst baz (2 versioned [amd64])
 Conf foo (2 versioned [amd64])
 Conf foo (2 versioned [amd64])
 Conf baz (2 versioned [amd64])' aptget install baz -st versioned
 Conf baz (2 versioned [amd64])' aptget install baz -st versioned
+
+# recreating the exact situation is hard, so we pull tricks to get the score
+cp -f rootdir/var/lib/dpkg/status-backup rootdir/var/lib/dpkg/status
+insertinstalledpackage 'gdm3' 'amd64' '1' 'Depends: libaudit0, libaudit0'
+insertinstalledpackage 'login' 'amd64' '1' 'Essential: yes'
+insertinstalledpackage 'libaudit0' 'amd64' '1'
+testequal 'Reading package lists...
+Building dependency tree...
+The following packages will be REMOVED:
+  gdm3 libaudit0
+The following NEW packages will be installed:
+  libaudit-common libaudit1
+The following packages will be upgraded:
+  login
+1 upgraded, 2 newly installed, 2 to remove and 0 not upgraded.
+Remv gdm3 [1]
+Remv libaudit0 [1]
+Inst libaudit-common (2 jessie [amd64])
+Conf libaudit-common (2 jessie [amd64])
+Inst libaudit1 (2 jessie [amd64])
+Conf libaudit1 (2 jessie [amd64])
+Inst login [1] (2 jessie [amd64])
+Conf login (2 jessie [amd64])' aptget dist-upgrade -st jessie

+ 43 - 0
test/integration/test-apt-download-progress

@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# ensure downloading sends progress as a regression test for commit 9127d7ae
+#
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+changetohttpswebserver
+
+assertprogress() {
+    T="$1"
+    testsuccess grep "dlstatus:1:0:Retrieving file 1 of 1" "$T"
+    if ! egrep -q "dlstatus:1:[0-9]{1,2}\.(.*):Retrieving file 1 of 1" "$T"; then
+        cat "$T"
+        msgfail "Failed to detect download progress"
+    fi
+    testsuccess grep "dlstatus:1:100:Retrieving file 1 of 1" "$T"
+    #cat $T
+}
+
+# we need to ensure the file is reasonable big so that apt has a chance to
+# actually report progress - but not too big to ensure its not delaying the
+# test too much
+TESTFILE=testfile.big
+testsuccess dd if=/dev/zero of=./aptarchive/$TESTFILE bs=800k count=1 
+
+msgtest 'download progress works via' 'http'
+printf '\n'
+exec 3> apt-progress.log
+testsuccess apthelper download-file "http://localhost:8080/$TESTFILE" http-$TESTFILE -o APT::Status-Fd=3 -o Acquire::http::Dl-Limit=600
+assertprogress apt-progress.log
+
+msgtest 'download progress works via' 'https'
+printf '\n'
+exec 3> apt-progress.log
+testsuccess apthelper download-file "https://localhost:4433/$TESTFILE" https-$TESTFILE -o APT::Status-Fd=3 -o Acquire::https::Dl-Limit=600
+assertprogress apt-progress.log
+
+# cleanup
+rm -f apt-progress*.log

+ 0 - 4
test/integration/test-apt-ftparchive-src-cachedb

@@ -180,10 +180,6 @@ testequal "
 E: Could not find a Source entry in the DSC 'aptarchive/pool/invalid/invalid_1.0.dsc'" aptftparchive sources aptarchive/pool/invalid
 E: Could not find a Source entry in the DSC 'aptarchive/pool/invalid/invalid_1.0.dsc'" aptftparchive sources aptarchive/pool/invalid
 rm -f aptarchive/pool/invalid/invalid_1.0.dsc
 rm -f aptarchive/pool/invalid/invalid_1.0.dsc
 
 
-dd if=/dev/zero of="aptarchive/pool/invalid/toobig_1.0.dsc" bs=1k count=129 2>/dev/null
-testequal "
-E: DSC file 'aptarchive/pool/invalid/toobig_1.0.dsc' is too large!" aptftparchive sources aptarchive/pool/invalid
-
 # ensure clean works
 # ensure clean works
 rm -f aptarchive/pool/main/*
 rm -f aptarchive/pool/main/*
 aptftparchive clean apt-ftparchive.conf -o Debug::APT::FTPArchive::Clean=1 > clean-out.txt 2>&1 
 aptftparchive clean apt-ftparchive.conf -o Debug::APT::FTPArchive::Clean=1 > clean-out.txt 2>&1 

+ 4 - 0
test/integration/test-apt-get-source

@@ -82,3 +82,7 @@ testequal "$HEADER
 Need to get 0 B of source archives.
 Need to get 0 B of source archives.
 'file://${APTARCHIVE}/foo_0.0.1.dsc' foo_0.0.1.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
 'file://${APTARCHIVE}/foo_0.0.1.dsc' foo_0.0.1.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
 'file://${APTARCHIVE}/foo_0.0.1.tar.gz' foo_0.0.1.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source -q --print-uris -t unstable foo=0.0.1
 'file://${APTARCHIVE}/foo_0.0.1.tar.gz' foo_0.0.1.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source -q --print-uris -t unstable foo=0.0.1
+
+testequal "$HEADER
+Need to get 0 B of source archives.
+Fetch source foo" aptget source -q -s foo

+ 13 - 11
test/integration/test-apt-helper

@@ -10,34 +10,36 @@ configarchitecture "i386"
 changetohttpswebserver
 changetohttpswebserver
 
 
 test_apt_helper_download() {
 test_apt_helper_download() {
-    echo "foo" > aptarchive/foo
+    echo 'foo' > aptarchive/foo
+    echo 'bar' > aptarchive/foo2
 
 
     msgtest 'apt-file download-file md5sum'
     msgtest 'apt-file download-file md5sum'
-    apthelper -qq download-file http://localhost:8080/foo foo2 MD5Sum:d3b07384d113edec49eaa6238ad5ff00 && msgpass || msgfail
+    testsuccess --nomsg apthelper download-file http://localhost:8080/foo foo2 MD5Sum:d3b07384d113edec49eaa6238ad5ff00
     testfileequal foo2 'foo'
     testfileequal foo2 'foo'
 
 
     msgtest 'apt-file download-file sha1'
     msgtest 'apt-file download-file sha1'
-    apthelper -qq download-file http://localhost:8080/foo foo1 SHA1:f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 && msgpass || msgfail
+    testsuccess --nomsg apthelper download-file http://localhost:8080/foo foo1 SHA1:f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
     testfileequal foo1 'foo'
     testfileequal foo1 'foo'
 
 
     msgtest 'apt-file download-file sha256'
     msgtest 'apt-file download-file sha256'
-    apthelper -qq download-file http://localhost:8080/foo foo3 SHA256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c && msgpass || msgfail
+    testsuccess --nomsg apthelper download-file http://localhost:8080/foo foo3 SHA256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
     testfileequal foo3 'foo'
     testfileequal foo3 'foo'
 
 
     msgtest 'apt-file download-file no-hash'
     msgtest 'apt-file download-file no-hash'
-    apthelper -qq download-file http://localhost:8080/foo foo4 && msgpass || msgfail
+    testsuccess --nomsg apthelper download-file http://localhost:8080/foo foo4
     testfileequal foo4 'foo'
     testfileequal foo4 'foo'
     
     
     msgtest 'apt-file download-file wrong hash'
     msgtest 'apt-file download-file wrong hash'
-    if ! apthelper -qq download-file http://localhost:8080/foo foo5 MD5Sum:aabbcc 2>&1 2> download.stderr; then
-        msgpass
-    else
-        msgfail
-    fi
-    testfileequal download.stderr 'E: Failed to fetch http://localhost:8080/foo  Hash Sum mismatch
+    testfailure --nomsg apthelper -qq download-file http://localhost:8080/foo foo5 MD5Sum:aabbcc
+    testfileequal rootdir/tmp/testfailure.output 'E: Failed to fetch http://localhost:8080/foo  Hash Sum mismatch
 
 
 E: Download Failed'
 E: Download Failed'
     testfileequal foo5.FAILED 'foo'
     testfileequal foo5.FAILED 'foo'
+
+    msgtest 'apt-file download-file md5sum sha1'
+    testsuccess --nomsg apthelper download-file http://localhost:8080/foo foo6 MD5Sum:d3b07384d113edec49eaa6238ad5ff00 http://localhost:8080/foo2 foo7 SHA1:e242ed3bffccdf271b7fbaf34ed72d089537b42f
+    testfileequal foo6 'foo'
+    testfileequal foo7 'bar'
 }
 }
 
 
 test_apt_helper_detect_proxy() {
 test_apt_helper_detect_proxy() {

+ 6 - 0
test/integration/test-apt-key

@@ -105,3 +105,9 @@ testfileequal ./aptkey.list 'pub   2048R/528144E2 2011-01-16'
 testsuccess test ! -e rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
 testsuccess test ! -e rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
 testsuccess cmp keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg~
 testsuccess cmp keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg~
 testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
 testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
+
+msgtest 'Test key removal with' '8 byte key ID'
+cleanplate
+cp -a keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
+testsuccess --nomsg aptkey --fakeroot del 5A90D141DBAC8DAE
+testempty aptkey list

+ 36 - 31
test/integration/test-apt-progress-fd

@@ -19,13 +19,14 @@ testequal "dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:testing:0:Installing testing (amd64)
 pmstatus:testing:0:Installing testing (amd64)
-pmstatus:testing:20:Preparing testing (amd64)
-pmstatus:testing:40:Unpacking testing (amd64)
-pmstatus:testing:60:Preparing to configure testing (amd64)
-pmstatus:dpkg-exec:60:Running dpkg
-pmstatus:testing:60:Configuring testing (amd64)
-pmstatus:testing:80:Configuring testing (amd64)
-pmstatus:testing:100:Installed testing (amd64)" cat apt-progress.log
+pmstatus:testing:16.6667:Preparing testing (amd64)
+pmstatus:testing:33.3333:Unpacking testing (amd64)
+pmstatus:testing:50:Preparing to configure testing (amd64)
+pmstatus:dpkg-exec:50:Running dpkg
+pmstatus:testing:50:Configuring testing (amd64)
+pmstatus:testing:66.6667:Configuring testing (amd64)
+pmstatus:testing:83.3333:Installed testing (amd64)
+pmstatus:dpkg-exec:83.3333:Running dpkg" cat apt-progress.log
 
 
 # upgrade
 # upgrade
 exec 3> apt-progress.log
 exec 3> apt-progress.log
@@ -34,13 +35,14 @@ testequal "dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:testing:0:Installing testing (amd64)
 pmstatus:testing:0:Installing testing (amd64)
-pmstatus:testing:20:Preparing testing (amd64)
-pmstatus:testing:40:Unpacking testing (amd64)
-pmstatus:testing:60:Preparing to configure testing (amd64)
-pmstatus:dpkg-exec:60:Running dpkg
-pmstatus:testing:60:Configuring testing (amd64)
-pmstatus:testing:80:Configuring testing (amd64)
-pmstatus:testing:100:Installed testing (amd64)" cat apt-progress.log
+pmstatus:testing:16.6667:Preparing testing (amd64)
+pmstatus:testing:33.3333:Unpacking testing (amd64)
+pmstatus:testing:50:Preparing to configure testing (amd64)
+pmstatus:dpkg-exec:50:Running dpkg
+pmstatus:testing:50:Configuring testing (amd64)
+pmstatus:testing:66.6667:Configuring testing (amd64)
+pmstatus:testing:83.3333:Installed testing (amd64)
+pmstatus:dpkg-exec:83.3333:Running dpkg" cat apt-progress.log
 
 
 # reinstall
 # reinstall
 exec 3> apt-progress.log
 exec 3> apt-progress.log
@@ -49,22 +51,24 @@ testequal "dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:testing:0:Installing testing (amd64)
 pmstatus:testing:0:Installing testing (amd64)
-pmstatus:testing:20:Preparing testing (amd64)
-pmstatus:testing:40:Unpacking testing (amd64)
-pmstatus:testing:60:Preparing to configure testing (amd64)
-pmstatus:dpkg-exec:60:Running dpkg
-pmstatus:testing:60:Configuring testing (amd64)
-pmstatus:testing:80:Configuring testing (amd64)
-pmstatus:testing:100:Installed testing (amd64)" cat apt-progress.log
+pmstatus:testing:16.6667:Preparing testing (amd64)
+pmstatus:testing:33.3333:Unpacking testing (amd64)
+pmstatus:testing:50:Preparing to configure testing (amd64)
+pmstatus:dpkg-exec:50:Running dpkg
+pmstatus:testing:50:Configuring testing (amd64)
+pmstatus:testing:66.6667:Configuring testing (amd64)
+pmstatus:testing:83.3333:Installed testing (amd64)
+pmstatus:dpkg-exec:83.3333:Running dpkg" cat apt-progress.log
 
 
 # and remove
 # and remove
 exec 3> apt-progress.log
 exec 3> apt-progress.log
 testsuccess aptget remove testing -y -o APT::Status-Fd=3
 testsuccess aptget remove testing -y -o APT::Status-Fd=3
 testequal "pmstatus:dpkg-exec:0:Running dpkg
 testequal "pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:testing:0:Removing testing (amd64)
 pmstatus:testing:0:Removing testing (amd64)
-pmstatus:testing:33.3333:Preparing for removal of testing (amd64)
-pmstatus:testing:66.6667:Removing testing (amd64)
-pmstatus:testing:100:Removed testing (amd64)" cat apt-progress.log
+pmstatus:testing:25:Preparing for removal of testing (amd64)
+pmstatus:testing:50:Removing testing (amd64)
+pmstatus:testing:75:Removed testing (amd64)
+pmstatus:dpkg-exec:75:Running dpkg" cat apt-progress.log
 
 
 # install non-native and ensure we get proper progress info
 # install non-native and ensure we get proper progress info
 exec 3> apt-progress.log
 exec 3> apt-progress.log
@@ -75,12 +79,13 @@ testequal "dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 dlstatus:1:0:Retrieving file 1 of 1
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:dpkg-exec:0:Running dpkg
 pmstatus:testing2:0:Installing testing2 (i386)
 pmstatus:testing2:0:Installing testing2 (i386)
-pmstatus:testing2:20:Preparing testing2 (i386)
-pmstatus:testing2:40:Unpacking testing2 (i386)
-pmstatus:testing2:60:Preparing to configure testing2 (i386)
-pmstatus:dpkg-exec:60:Running dpkg
-pmstatus:testing2:60:Configuring testing2 (i386)
-pmstatus:testing2:80:Configuring testing2 (i386)
-pmstatus:testing2:100:Installed testing2 (i386)" cat apt-progress.log
+pmstatus:testing2:16.6667:Preparing testing2 (i386)
+pmstatus:testing2:33.3333:Unpacking testing2 (i386)
+pmstatus:testing2:50:Preparing to configure testing2 (i386)
+pmstatus:dpkg-exec:50:Running dpkg
+pmstatus:testing2:50:Configuring testing2 (i386)
+pmstatus:testing2:66.6667:Configuring testing2 (i386)
+pmstatus:testing2:83.3333:Installed testing2 (i386)
+pmstatus:dpkg-exec:83.3333:Running dpkg" cat apt-progress.log
 
 
 rm -f apt-progress*.log
 rm -f apt-progress*.log

+ 11 - 7
test/integration/test-apt-progress-fd-deb822

@@ -27,37 +27,41 @@ Message: Installing testing (amd64)
 
 
 Status: progress
 Status: progress
 Package: testing:amd64
 Package: testing:amd64
-Percent: 20
+Percent: 16.6667
 Message: Preparing testing (amd64)
 Message: Preparing testing (amd64)
 
 
 Status: progress
 Status: progress
 Package: testing:amd64
 Package: testing:amd64
-Percent: 40
+Percent: 33.3333
 Message: Unpacking testing (amd64)
 Message: Unpacking testing (amd64)
 
 
 Status: progress
 Status: progress
 Package: testing:amd64
 Package: testing:amd64
-Percent: 60
+Percent: 50
 Message: Preparing to configure testing (amd64)
 Message: Preparing to configure testing (amd64)
 
 
 Status: progress
 Status: progress
-Percent: 60
+Percent: 50
 Message: Running dpkg
 Message: Running dpkg
 
 
 Status: progress
 Status: progress
 Package: testing:amd64
 Package: testing:amd64
-Percent: 60
+Percent: 50
 Message: Configuring testing (amd64)
 Message: Configuring testing (amd64)
 
 
 Status: progress
 Status: progress
 Package: testing:amd64
 Package: testing:amd64
-Percent: 80
+Percent: 66.6667
 Message: Configuring testing (amd64)
 Message: Configuring testing (amd64)
 
 
 Status: progress
 Status: progress
 Package: testing:amd64
 Package: testing:amd64
-Percent: 100
+Percent: 83.3333
 Message: Installed testing (amd64)
 Message: Installed testing (amd64)
+
+Status: progress
+Percent: 83.3333
+Message: Running dpkg
 " cat apt-progress.log
 " cat apt-progress.log
 
 
 
 

+ 1 - 1
test/integration/test-apt-progress-fd-error

@@ -18,7 +18,7 @@ setupaptarchive
 exec 3> apt-progress.log
 exec 3> apt-progress.log
 testfailure aptget install foo1 foo2 -y -o APT::Status-Fd=3
 testfailure aptget install foo1 foo2 -y -o APT::Status-Fd=3
 msgtest "Ensure correct error message"
 msgtest "Ensure correct error message"
-if grep -q "aptarchive/pool/foo2_0.8.15_amd64.deb:40:trying to overwrite '/usr/bin/file-conflict', which is also in package foo1 0.8.15" apt-progress.log; then
+if grep -q "aptarchive/pool/foo2_0.8.15_amd64.deb:36.3636:trying to overwrite '/usr/bin/file-conflict', which is also in package foo1 0.8.15" apt-progress.log; then
 	msgpass
 	msgpass
 else
 else
 	cat apt-progress.log
 	cat apt-progress.log

+ 75 - 0
test/integration/test-bug-769609-triggers-still-pending-after-run

@@ -0,0 +1,75 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture 'amd64'
+
+msgtest 'Check if installed dpkg supports' 'noawait trigger'
+if dpkg-checkbuilddeps -d 'dpkg (>= 1.16.1)' /dev/null; then
+	msgpass
+else
+	msgskip 'dpkg version too old'
+	exit 0
+fi
+configdpkgnoopchroot
+
+buildtriggerpackages() {
+	local TYPE="$1"
+	setupsimplenativepackage "triggerable-$TYPE" 'all' '1.0' 'unstable' "Depends: trigdepends-$TYPE"
+	BUILDDIR="incoming/triggerable-${TYPE}-1.0"
+	cat >${BUILDDIR}/debian/postinst <<EOF
+#!/bin/sh
+if [ "\$1" = 'triggered' ]; then
+	ls -l /proc/self/fd/
+fi
+EOF
+	echo "$TYPE /usr/share/doc" > ${BUILDDIR}/debian/triggers
+	buildpackage "$BUILDDIR" 'unstable' 'main' 'native'
+	rm -rf "$BUILDDIR"
+	buildsimplenativepackage "trigdepends-$TYPE" 'all' '1.0' 'unstable'
+}
+
+#buildtriggerpackages 'interest'
+buildtriggerpackages 'interest-noawait'
+buildsimplenativepackage "trigstuff" 'all' '1.0' 'unstable'
+
+setupaptarchive
+
+runtests() {
+	local TYPE="$1"
+	msgmsg 'Working with trigger type' "$TYPE"
+	testsuccess aptget install triggerable-$TYPE -y
+	cp rootdir/tmp/testsuccess.output terminal.output
+	testsuccess grep '^REWRITE ' terminal.output
+	testdpkginstalled triggerable-$TYPE trigdepends-$TYPE
+
+	testsuccess aptget install trigdepends-$TYPE -y --reinstall
+	cp rootdir/tmp/testsuccess.output terminal.output
+	testsuccess grep '^REWRITE ' terminal.output
+	testsuccess grep ' root root ' terminal.output
+	testdpkginstalled triggerable-$TYPE trigdepends-$TYPE
+
+	testsuccess aptget install trigstuff -y
+	cp rootdir/tmp/testsuccess.output terminal.output
+	testsuccess grep '^REWRITE ' terminal.output
+	testsuccess grep ' root root ' terminal.output
+	testdpkginstalled triggerable-$TYPE trigdepends-$TYPE trigstuff
+
+	testsuccess aptget purge trigstuff -y
+	cp rootdir/tmp/testsuccess.output terminal.output
+	testsuccess grep '^REWRITE ' terminal.output
+	testsuccess grep ' root root ' terminal.output
+	testdpkginstalled triggerable-$TYPE trigdepends-$TYPE
+	testdpkgnotinstalled trigstuff
+
+	testsuccess aptget purge trigdepends-$TYPE -y
+	cp rootdir/tmp/testsuccess.output terminal.output
+	testfailure grep '^REWRITE ' terminal.output
+	testfailure grep ' root root ' terminal.output
+	testdpkgnotinstalled triggerable-$TYPE trigdepends-$TYPE
+}
+#runtests 'interest'
+runtests 'interest-noawait'

+ 1 - 45
test/integration/test-failing-maintainer-scripts

@@ -6,6 +6,7 @@ TESTDIR=$(readlink -f $(dirname $0))
 
 
 setupenvironment
 setupenvironment
 configarchitecture 'native'
 configarchitecture 'native'
+configdpkgnoopchroot
 
 
 # create a bunch of failures
 # create a bunch of failures
 createfailure() {
 createfailure() {
@@ -25,51 +26,6 @@ createfailure 'postrm'
 
 
 setupaptarchive
 setupaptarchive
 
 
-# create a library to noop chroot() and rewrite maintainer script executions
-# via execvp() as used by dpkg as we don't want our rootdir to be a fullblown
-# chroot directory dpkg could chroot into to execute the maintainer scripts
-cat << EOF > noopchroot.c
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dlfcn.h>
-
-static char * chrootdir = NULL;
-
-int chroot(const char *path) {
-	printf("WARNING: CHROOTing to %s was ignored!\n", path);
-	free(chrootdir);
-	chrootdir = strdup(path);
-	return 0;
-}
-int execvp(const char *file, char *const argv[]) {
-	static int (*func_execvp) (const char *, char * const []) = NULL;
-	if (func_execvp == NULL)
-		func_execvp = (int (*) (const char *, char * const [])) dlsym(RTLD_NEXT, "execvp");
-	if (chrootdir == NULL || strncmp(file, "/var/lib/dpkg/", strlen("/var/lib/dpkg/")) != 0)
-		return func_execvp(file, argv);
-	printf("REWRITE execvp call %s into %s\n", file, chrootdir);
-	char newfile[strlen(chrootdir) + strlen(file)];
-	strcpy(newfile, chrootdir);
-	strcat(newfile, file);
-	return func_execvp(newfile, argv);
-}
-EOF
-testsuccess gcc -fPIC -shared -o noopchroot.so noopchroot.c -ldl
-
-mkdir -p "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/"
-DPKG="${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg"
-echo "#!/bin/sh
-if [ -n \"\$LD_PRELOAD\" ]; then
-	export LD_PRELOAD=\"${TMPWORKINGDIRECTORY}/noopchroot.so \${LD_PRELOAD}\"
-else
-	export LD_PRELOAD=\"${TMPWORKINGDIRECTORY}/noopchroot.so\"
-fi
-dpkg \"\$@\"" > $DPKG
-chmod +x $DPKG
-sed -ie "s|^DPKG::options:: \"dpkg\";\$|DPKG::options:: \"$DPKG\";|" aptconfig.conf
-
 # setup some pre- and post- invokes to check the output isn't garbled later
 # setup some pre- and post- invokes to check the output isn't garbled later
 APTHOOK="${TMPWORKINGDIRECTORY}/rootdir/usr/bin/apthook"
 APTHOOK="${TMPWORKINGDIRECTORY}/rootdir/usr/bin/apthook"
 echo '#!/bin/sh
 echo '#!/bin/sh

+ 119 - 0
test/integration/test-no-fds-leaked-to-maintainer-scripts

@@ -0,0 +1,119 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture 'amd64' 'i386'
+configdpkgnoopchroot
+
+setupsimplenativepackage "fdleaks" 'all' '1.0' 'unstable'
+BUILDDIR="incoming/fdleaks-1.0"
+for script in 'preinst' 'postinst' 'prerm' 'postrm'; do
+	cat > ${BUILDDIR}/debian/$script << EOF
+#!/bin/sh
+if [ -e "$(pwd)/rootdir/tmp/read_stdin" ]; then
+	read line;
+	echo "STDIN: -\$line-"
+fi
+ls -l /proc/self/fd/
+EOF
+done
+buildpackage "$BUILDDIR" 'unstable' 'main' 'native'
+rm -rf "$BUILDDIR"
+
+PKGNAME='fdleaks:all'
+if ! dpkg-checkbuilddeps -d 'dpkg (>= 1.16.2)' /dev/null >/dev/null 2>&1; then
+	PKGNAME='fdleaks'
+fi
+
+setupaptarchive
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+testsuccess aptget install -y fdleaks -qq < /dev/null
+
+checkfdleak() {
+	msgtest 'Check if fds were not' 'leaked'
+	if [ "$(grep 'root root' rootdir/tmp/testsuccess.output | wc -l)" = "$1" ]; then
+		msgpass
+	else
+		echo
+		cat rootdir/tmp/testsuccess.output
+		msgfail
+	fi
+}
+checkinstall() {
+	checkfdleak 8
+
+	cp rootdir/tmp/testsuccess.output terminal.output
+	tail -n +3 rootdir/var/log/apt/term.log | head -n -1 > terminal.log
+	testfileequal 'terminal.log' "$(cat terminal.output)"
+
+	testequal "startup archives unpack
+install $PKGNAME <none> 1.0
+status half-installed $PKGNAME 1.0
+status unpacked $PKGNAME 1.0
+status unpacked $PKGNAME 1.0
+startup packages configure
+configure $PKGNAME 1.0 <none>
+status unpacked $PKGNAME 1.0
+status half-configured $PKGNAME 1.0
+status installed $PKGNAME 1.0
+startup packages configure" cut -f 3- -d' ' rootdir/var/log/dpkg.log
+}
+checkinstall
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+testsuccess aptget purge -y fdleaks -qq
+checkpurge() {
+	checkfdleak 12
+
+	cp rootdir/tmp/testsuccess.output terminal.output
+	tail -n +3 rootdir/var/log/apt/term.log | head -n -1 > terminal.log
+	testfileequal 'terminal.log' "$(cat terminal.output)"
+
+	testequal "startup packages purge
+status installed $PKGNAME 1.0
+remove $PKGNAME 1.0 <none>
+status half-configured $PKGNAME 1.0
+status half-installed $PKGNAME 1.0
+status config-files $PKGNAME 1.0
+purge $PKGNAME 1.0 <none>
+status config-files $PKGNAME 1.0
+status config-files $PKGNAME 1.0
+status config-files $PKGNAME 1.0
+status config-files $PKGNAME 1.0
+status config-files $PKGNAME 1.0
+status not-installed $PKGNAME <none>
+startup packages configure" cut -f 3- -d' ' rootdir/var/log/dpkg.log
+}
+checkpurge
+
+msgtest 'setsid provided is new enough to support' '-w'
+if dpkg-checkbuilddeps -d 'util-linux (>= 2.24.2-1)' /dev/null >/dev/null 2>&1; then
+	msgpass
+else
+	msgskip "$(command dpkg -l util-linux)"
+	exit
+fi
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+testsuccess runapt command setsid -w "${BUILDDIRECTORY}/apt-get" install -y fdleaks -qq < /dev/null
+checkinstall
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+testsuccess runapt command setsid -w "${BUILDDIRECTORY}/apt-get" purge -y fdleaks -qq
+checkpurge
+
+touch rootdir/tmp/read_stdin
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+for i in $(seq 1 10); do echo "$i"; done | testsuccess aptget install -y fdleaks -qq
+checkinstall
+testequal '2' grep -c '^STDIN: ' rootdir/var/log/apt/term.log
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+yes '' | testsuccess runapt command setsid -w "${BUILDDIRECTORY}/apt-get" purge -y fdleaks -qq
+checkpurge
+testequal '3' grep -c '^STDIN: ' rootdir/var/log/apt/term.log

+ 56 - 6
test/integration/test-partial-file-support

@@ -24,13 +24,25 @@ testdownloadfile() {
 	else
 	else
 		msgpass
 		msgpass
 	fi
 	fi
-	cat "$DOWNLOADLOG" | while read field hash; do
+	sed -e '/^ <- / s#%20# #g' -e '/^ <- / s#%0a#\n#g' "$DOWNLOADLOG" | grep '^.*-Hash: ' > receivedhashes.log
+	testsuccess test -s receivedhashes.log
+	local HASHES_OK=0
+	local HASHES_BAD=0
+	while read field hash; do
 		local EXPECTED
 		local EXPECTED
 		case "$field" in
 		case "$field" in
 		'MD5Sum-Hash:') EXPECTED="$(md5sum "$TESTFILE" | cut -d' ' -f 1)";;
 		'MD5Sum-Hash:') EXPECTED="$(md5sum "$TESTFILE" | cut -d' ' -f 1)";;
 		'SHA1-Hash:') EXPECTED="$(sha1sum "$TESTFILE" | cut -d' ' -f 1)";;
 		'SHA1-Hash:') EXPECTED="$(sha1sum "$TESTFILE" | cut -d' ' -f 1)";;
 		'SHA256-Hash:') EXPECTED="$(sha256sum "$TESTFILE" | cut -d' ' -f 1)";;
 		'SHA256-Hash:') EXPECTED="$(sha256sum "$TESTFILE" | cut -d' ' -f 1)";;
 		'SHA512-Hash:') EXPECTED="$(sha512sum "$TESTFILE" | cut -d' ' -f 1)";;
 		'SHA512-Hash:') EXPECTED="$(sha512sum "$TESTFILE" | cut -d' ' -f 1)";;
+		'Checksum-FileSize-Hash:')
+			#filesize is too weak to check for !=
+			if [ "$4" = '=' ]; then
+				EXPECTED="$(stat -c '%s' "$TESTFILE")"
+			else
+				continue
+			fi
+			;;
 		*) continue;;
 		*) continue;;
 		esac
 		esac
 		if [ "$4" = '=' ]; then
 		if [ "$4" = '=' ]; then
@@ -40,15 +52,41 @@ testdownloadfile() {
 		fi
 		fi
 		if [ "$EXPECTED" "$4" "$hash" ]; then
 		if [ "$EXPECTED" "$4" "$hash" ]; then
 			msgpass
 			msgpass
+			HASHES_OK=$((HASHES_OK+1));
 		else
 		else
-			cat >&2 "$DOWNLOADLOG"
 			msgfail "expected: $EXPECTED ; got: $hash"
 			msgfail "expected: $EXPECTED ; got: $hash"
+			HASHES_BAD=$((HASHES_BAD+1));
 		fi
 		fi
-	done
+	done < receivedhashes.log
+	msgtest 'At least one good hash and no bad ones'
+	if [ $HASHES_OK -eq 0 ] || [ $HASHES_BAD -ne 0 ]; then
+		cat >&2 "$DOWNLOADLOG"
+		msgfail
+	else
+		msgpass
+	fi
 }
 }
 
 
 TESTFILE='aptarchive/testfile'
 TESTFILE='aptarchive/testfile'
 cp -a ${TESTDIR}/framework $TESTFILE
 cp -a ${TESTDIR}/framework $TESTFILE
+cp -a ${TESTDIR}/framework "${TESTFILE}2"
+
+followuprequest() {
+	local DOWN='./testfile'
+
+	copysource $TESTFILE 1M $DOWN
+	testdownloadfile 'completely downloaded file' "${1}/testfile" "$DOWN" '='
+	testwebserverlaststatuscode '416' "$DOWNLOADLOG"
+
+	copysource $TESTFILE 1M $DOWN
+	copysource "${TESTFILE}2" 20 "${DOWN}2"
+	msgtest 'Testing download of files with' 'completely downloaded file + partial file'
+	testsuccess --nomsg apthelper -o Debug::Acquire::${1%%:*}=1 -o Debug::pkgAcquire::Worker=1 \
+		download-file "$1/testfile" "$DOWN" '' "$1/testfile2" "${DOWN}2"
+	testwebserverlaststatuscode '206' 'rootdir/tmp/testsuccess.output'
+	testsuccess diff -u "$TESTFILE" "${DOWN}"
+	testsuccess diff -u "${DOWN}" "${DOWN}2"
+}
 
 
 testrun() {
 testrun() {
 	webserverconfig 'aptwebserver::support::range' 'true'
 	webserverconfig 'aptwebserver::support::range' 'true'
@@ -65,9 +103,11 @@ testrun() {
 	testdownloadfile 'invalid partial data' "${1}/testfile" './testfile' '!='
 	testdownloadfile 'invalid partial data' "${1}/testfile" './testfile' '!='
 	testwebserverlaststatuscode '206' "$DOWNLOADLOG"
 	testwebserverlaststatuscode '206' "$DOWNLOADLOG"
 
 
-	copysource $TESTFILE 1M ./testfile
-	testdownloadfile 'completely downloaded file' "${1}/testfile" './testfile' '='
-	testwebserverlaststatuscode '416' "$DOWNLOADLOG"
+	webserverconfig 'aptwebserver::closeOnError' 'false'
+	followuprequest "$1"
+	webserverconfig 'aptwebserver::closeOnError' 'true'
+	followuprequest "$1"
+	webserverconfig 'aptwebserver::closeOnError' 'false'
 
 
 	copysource /dev/zero 1M ./testfile
 	copysource /dev/zero 1M ./testfile
 	testdownloadfile 'too-big partial file' "${1}/testfile" './testfile' '='
 	testdownloadfile 'too-big partial file' "${1}/testfile" './testfile' '='
@@ -85,8 +125,18 @@ testrun() {
 	testwebserverlaststatuscode '200' "$DOWNLOADLOG"
 	testwebserverlaststatuscode '200' "$DOWNLOADLOG"
 }
 }
 
 
+msgmsg 'http: Test with Content-Length'
+webserverconfig 'aptwebserver::chunked-transfer-encoding' 'false'
+testrun 'http://localhost:8080'
+msgmsg 'http: Test with Transfer-Encoding: chunked'
+webserverconfig 'aptwebserver::chunked-transfer-encoding' 'true'
 testrun 'http://localhost:8080'
 testrun 'http://localhost:8080'
 
 
 changetohttpswebserver
 changetohttpswebserver
 
 
+msgmsg 'https: Test with Content-Length'
+webserverconfig 'aptwebserver::chunked-transfer-encoding' 'false'
+testrun 'https://localhost:4433'
+msgmsg 'https: Test with Transfer-Encoding: chunked'
+webserverconfig 'aptwebserver::chunked-transfer-encoding' 'true'
 testrun 'https://localhost:4433'
 testrun 'https://localhost:4433'

+ 260 - 0
test/integration/test-ubuntu-bug-1098738-apt-get-source-md5sum

@@ -0,0 +1,260 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture 'native'
+
+cat > aptarchive/Sources <<EOF
+Package: pkg-md5-ok
+Binary: pkg-md5-ok
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Files:
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-ok_1.0.dsc
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-ok_1.0.tar.gz
+
+Package: pkg-sha256-ok
+Binary: pkg-sha256-ok
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Files:
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-ok_1.0.dsc
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-ok_1.0.tar.gz
+Checksums-Sha1:
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-ok_1.0.dsc
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-ok_1.0.tar.gz
+Checksums-Sha256:
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-sha256-ok_1.0.dsc
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-sha256-ok_1.0.tar.gz
+
+Package: pkg-sha256-bad
+Binary: pkg-sha256-bad
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Files:
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-bad_1.0.dsc
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-bad_1.0.tar.gz
+Checksums-Sha1:
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-bad_1.0.dsc
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-bad_1.0.tar.gz
+Checksums-Sha256:
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 pkg-sha256-bad_1.0.dsc
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 pkg-sha256-bad_1.0.tar.gz
+
+Package: pkg-no-md5
+Binary: pkg-no-md5
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Checksums-Sha1:
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-no-md5_1.0.dsc
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-no-md5_1.0.tar.gz
+Checksums-Sha256:
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-no-md5_1.0.dsc
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-no-md5_1.0.tar.gz
+
+Package: pkg-mixed-ok
+Binary: pkg-mixed-ok
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Checksums-Sha1:
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-mixed-ok_1.0.tar.gz
+Checksums-Sha256:
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-mixed-ok_1.0.dsc
+
+Package: pkg-mixed-sha1-bad
+Binary: pkg-mixed-sha1-bad
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Checksums-Sha1:
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 pkg-mixed-sha1-bad_1.0.dsc
+Checksums-Sha256:
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-mixed-sha1-bad_1.0.tar.gz
+
+Package: pkg-mixed-sha2-bad
+Binary: pkg-mixed-sha2-bad
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Checksums-Sha1:
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-mixed-sha2-bad_1.0.dsc
+Checksums-Sha256:
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 pkg-mixed-sha2-bad_1.0.tar.gz
+
+Package: pkg-md5-disagree
+Binary: pkg-md5-disagree
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Files:
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-disagree_1.0.dsc
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-disagree_1.0.tar.gz
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 pkg-md5-disagree_1.0.dsc
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 pkg-md5-disagree_1.0.tar.gz
+
+Package: pkg-md5-agree
+Binary: pkg-md5-agree
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Files:
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-agree_1.0.dsc
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-agree_1.0.tar.gz
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-agree_1.0.tar.gz
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-agree_1.0.dsc
+
+Package: pkg-sha256-disagree
+Binary: pkg-sha256-disagree
+Version: 1.0
+Maintainer: Joe Sixpack <joe@example.org>
+Architecture: all
+Files:
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-disagree_1.0.dsc
+ d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-disagree_1.0.tar.gz
+Checksums-Sha1:
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-disagree_1.0.dsc
+ da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-disagree_1.0.tar.gz
+Checksums-Sha256:
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-sha256-disagree_1.0.dsc
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-sha256-disagree_1.0.tar.gz
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 pkg-sha256-disagree_1.0.dsc
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 pkg-sha256-disagree_1.0.tar.gz
+EOF
+
+# create fetchable files
+for x in 'pkg-md5-ok' 'pkg-sha256-ok' 'pkg-sha256-bad' 'pkg-no-md5' \
+	 'pkg-mixed-ok' 'pkg-mixed-sha1-bad' 'pkg-mixed-sha2-bad' \
+	 'pkg-md5-agree' 'pkg-md5-disagree' 'pkg-sha256-disagree'; do
+	touch aptarchive/${x}_1.0.dsc aptarchive/${x}_1.0.tar.gz
+done
+
+setupaptarchive
+changetowebserver
+testsuccess aptget update
+
+testok() {
+	rm -f ${1}_1.0.dsc ${1}_1.0.tar.gz
+	testequal "Reading package lists...
+Building dependency tree...
+Need to get 0 B of source archives.
+Get:1 http://localhost:8080/  $1 1.0 (dsc)
+Get:2 http://localhost:8080/  $1 1.0 (tar)
+Download complete and in download only mode" aptget source -d "$@"
+	msgtest 'Files were successfully downloaded for' "$1"
+	testsuccess --nomsg test -e ${1}_1.0.dsc -a -e ${1}_1.0.tar.gz
+	rm -f ${1}_1.0.dsc ${1}_1.0.tar.gz
+}
+
+testkeep() {
+	touch ${1}_1.0.dsc ${1}_1.0.tar.gz
+	testequal "Reading package lists...
+Building dependency tree...
+Skipping already downloaded file '${1}_1.0.dsc'
+Skipping already downloaded file '${1}_1.0.tar.gz'
+Need to get 0 B of source archives.
+Download complete and in download only mode" aptget source -d "$@"
+	msgtest 'Files already downloaded are kept for' "$1"
+	testsuccess --nomsg test -e ${1}_1.0.dsc -a -e ${1}_1.0.tar.gz
+	rm -f ${1}_1.0.dsc ${1}_1.0.tar.gz
+}
+
+testmismatch() {
+	rm -f ${1}_1.0.dsc ${1}_1.0.tar.gz
+	testequal "Reading package lists...
+Building dependency tree...
+Need to get 0 B of source archives.
+Get:1 http://localhost:8080/  $1 1.0 (dsc)
+Get:2 http://localhost:8080/  $1 1.0 (tar)
+E: Failed to fetch http://localhost:8080/${1}_1.0.dsc  Hash Sum mismatch
+
+E: Failed to fetch http://localhost:8080/${1}_1.0.tar.gz  Hash Sum mismatch
+
+E: Failed to fetch some archives." aptget source -d "$@"
+	msgtest 'Files were not download as they have hashsum mismatches for' "$1"
+	testfailure --nomsg test -e ${1}_1.0.dsc -a -e ${1}_1.0.tar.gz
+
+	rm -f ${1}_1.0.dsc ${1}_1.0.tar.gz
+	testequal "Reading package lists...
+Building dependency tree...
+Skipping download of file 'pkg-sha256-bad_1.0.dsc' as requested hashsum is not available for authentication
+Skipping download of file 'pkg-sha256-bad_1.0.tar.gz' as requested hashsum is not available for authentication
+Need to get 0 B of source archives.
+Download complete and in download only mode" aptget source -d "$@" -o Acquire::ForceHash=ROT26
+	msgtest 'Files were not download as hash is unavailable for' "$1"
+	testfailure --nomsg test -e ${1}_1.0.dsc -a -e ${1}_1.0.tar.gz
+
+	rm -f ${1}_1.0.dsc ${1}_1.0.tar.gz
+	testequal "Reading package lists...
+Building dependency tree...
+Need to get 0 B of source archives.
+Get:1 http://localhost:8080/  $1 1.0 (dsc)
+Get:2 http://localhost:8080/  $1 1.0 (tar)
+Download complete and in download only mode" aptget source --allow-unauthenticated -d "$@" -o Acquire::ForceHash=ROT26
+	msgtest 'Files were downloaded unauthenticated as user allowed it' "$1"
+	testsuccess --nomsg test -e ${1}_1.0.dsc -a -e ${1}_1.0.tar.gz
+}
+
+testok pkg-md5-ok
+testkeep pkg-md5-ok
+testok pkg-sha256-ok
+testkeep pkg-sha256-ok
+
+# pkg-sha256-bad has a bad SHA sum, but good MD5 sum.  If apt is
+# checking the best available hash (as it should), this will trigger
+# a hash mismatch.
+testmismatch pkg-sha256-bad
+testmismatch pkg-sha256-bad
+testok pkg-sha256-bad -o Acquire::ForceHash=MD5Sum
+
+# not having MD5 sum doesn't mean the file doesn't exist at all …
+testok pkg-no-md5
+testok pkg-no-md5 -o Acquire::ForceHash=SHA256
+testequal "Reading package lists...
+Building dependency tree...
+Skipping download of file 'pkg-no-md5_1.0.dsc' as requested hashsum is not available for authentication
+Skipping download of file 'pkg-no-md5_1.0.tar.gz' as requested hashsum is not available for authentication
+Need to get 0 B of source archives.
+Download complete and in download only mode" aptget source -d pkg-no-md5 -o Acquire::ForceHash=MD5Sum
+msgtest 'Files were not download as MD5 is not available for this package' 'pkg-no-md5'
+testfailure --nomsg test -e pkg-no-md5_1.0.dsc -a -e pkg-no-md5_1.0.tar.gz
+
+# deal with cases in which we haven't for all files the same checksum type
+# mostly pathologic as this shouldn't happen, but just to be sure
+testok pkg-mixed-ok
+testequal 'Reading package lists...
+Building dependency tree...
+Need to get 0 B of source archives.
+Get:1 http://localhost:8080/  pkg-mixed-sha1-bad 1.0 (tar)
+Get:2 http://localhost:8080/  pkg-mixed-sha1-bad 1.0 (dsc)
+E: Failed to fetch http://localhost:8080/pkg-mixed-sha1-bad_1.0.dsc  Hash Sum mismatch
+
+E: Failed to fetch some archives.' aptget source -d pkg-mixed-sha1-bad
+msgtest 'Only tar file is downloaded as the dsc has hashsum mismatch' 'pkg-mixed-sha1-bad'
+testsuccess --nomsg test ! -e pkg-mixed-sha1-bad_1.0.dsc -a -e pkg-mixed-sha1-bad_1.0.tar.gz
+testequal 'Reading package lists...
+Building dependency tree...
+Need to get 0 B of source archives.
+Get:1 http://localhost:8080/  pkg-mixed-sha2-bad 1.0 (tar)
+Get:2 http://localhost:8080/  pkg-mixed-sha2-bad 1.0 (dsc)
+E: Failed to fetch http://localhost:8080/pkg-mixed-sha2-bad_1.0.tar.gz  Hash Sum mismatch
+
+E: Failed to fetch some archives.' aptget source -d pkg-mixed-sha2-bad
+msgtest 'Only dsc file is downloaded as the tar has hashsum mismatch' 'pkg-mixed-sha2-bad'
+testsuccess --nomsg test -e pkg-mixed-sha2-bad_1.0.dsc -a ! -e pkg-mixed-sha2-bad_1.0.tar.gz
+
+# it gets even more pathologic: multiple entries for one file, some even disagreeing!
+testok pkg-md5-agree
+testequal 'Reading package lists...
+Building dependency tree...
+E: Error parsing checksum in Files of source package pkg-md5-disagree' aptget source -d pkg-md5-disagree
+testequal 'Reading package lists...
+Building dependency tree...
+E: Error parsing checksum in Checksums-SHA256 of source package pkg-sha256-disagree' aptget source -d pkg-sha256-disagree

+ 116 - 65
test/interactive-helper/aptwebserver.cc

@@ -19,6 +19,8 @@
 #include <sys/stat.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <time.h>
 #include <unistd.h>
 #include <unistd.h>
+
+#include <algorithm>
 #include <iostream>
 #include <iostream>
 #include <sstream>
 #include <sstream>
 #include <list>
 #include <list>
@@ -79,12 +81,21 @@ static char const * httpcodeToStr(int const httpcode)		/*{{{*/
    return NULL;
    return NULL;
 }
 }
 									/*}}}*/
 									/*}}}*/
+static bool chunkedTransferEncoding(std::list<std::string> const &headers) {
+   if (std::find(headers.begin(), headers.end(), "Transfer-Encoding: chunked") != headers.end())
+      return true;
+   if (_config->FindB("aptwebserver::chunked-transfer-encoding", false) == true)
+      return true;
+   return false;
+}
 static void addFileHeaders(std::list<std::string> &headers, FileFd &data)/*{{{*/
 static void addFileHeaders(std::list<std::string> &headers, FileFd &data)/*{{{*/
 {
 {
-   std::ostringstream contentlength;
-   contentlength << "Content-Length: " << data.FileSize();
-   headers.push_back(contentlength.str());
-
+   if (chunkedTransferEncoding(headers) == false)
+   {
+      std::ostringstream contentlength;
+      contentlength << "Content-Length: " << data.FileSize();
+      headers.push_back(contentlength.str());
+   }
    std::string lastmodified("Last-Modified: ");
    std::string lastmodified("Last-Modified: ");
    lastmodified.append(TimeRFC1123(data.ModificationTime()));
    lastmodified.append(TimeRFC1123(data.ModificationTime()));
    headers.push_back(lastmodified);
    headers.push_back(lastmodified);
@@ -92,9 +103,12 @@ static void addFileHeaders(std::list<std::string> &headers, FileFd &data)/*{{{*/
 									/*}}}*/
 									/*}}}*/
 static void addDataHeaders(std::list<std::string> &headers, std::string &data)/*{{{*/
 static void addDataHeaders(std::list<std::string> &headers, std::string &data)/*{{{*/
 {
 {
-   std::ostringstream contentlength;
-   contentlength << "Content-Length: " << data.size();
-   headers.push_back(contentlength.str());
+   if (chunkedTransferEncoding(headers) == false)
+   {
+      std::ostringstream contentlength;
+      contentlength << "Content-Length: " << data.size();
+      headers.push_back(contentlength.str());
+   }
 }
 }
 									/*}}}*/
 									/*}}}*/
 static bool sendHead(int const client, int const httpcode, std::list<std::string> &headers)/*{{{*/
 static bool sendHead(int const client, int const httpcode, std::list<std::string> &headers)/*{{{*/
@@ -114,6 +128,9 @@ static bool sendHead(int const client, int const httpcode, std::list<std::string
    date.append(TimeRFC1123(time(NULL)));
    date.append(TimeRFC1123(time(NULL)));
    headers.push_back(date);
    headers.push_back(date);
 
 
+   if (chunkedTransferEncoding(headers) == true)
+      headers.push_back("Transfer-Encoding: chunked");
+
    std::clog << ">>> RESPONSE to " << client << " >>>" << std::endl;
    std::clog << ">>> RESPONSE to " << client << " >>>" << std::endl;
    bool Success = true;
    bool Success = true;
    for (std::list<std::string>::const_iterator h = headers.begin();
    for (std::list<std::string>::const_iterator h = headers.begin();
@@ -130,25 +147,55 @@ static bool sendHead(int const client, int const httpcode, std::list<std::string
    return Success;
    return Success;
 }
 }
 									/*}}}*/
 									/*}}}*/
-static bool sendFile(int const client, FileFd &data)			/*{{{*/
+static bool sendFile(int const client, std::list<std::string> const &headers, FileFd &data)/*{{{*/
 {
 {
    bool Success = true;
    bool Success = true;
+   bool const chunked = chunkedTransferEncoding(headers);
    char buffer[500];
    char buffer[500];
    unsigned long long actual = 0;
    unsigned long long actual = 0;
    while ((Success &= data.Read(buffer, sizeof(buffer), &actual)) == true)
    while ((Success &= data.Read(buffer, sizeof(buffer), &actual)) == true)
    {
    {
       if (actual == 0)
       if (actual == 0)
 	 break;
 	 break;
-      Success &= FileFd::Write(client, buffer, actual);
+
+      if (chunked == true)
+      {
+	 std::string size;
+	 strprintf(size, "%llX\r\n", actual);
+	 Success &= FileFd::Write(client, size.c_str(), size.size());
+	 Success &= FileFd::Write(client, buffer, actual);
+	 Success &= FileFd::Write(client, "\r\n", strlen("\r\n"));
+      }
+      else
+	 Success &= FileFd::Write(client, buffer, actual);
+   }
+   if (chunked == true)
+   {
+      char const * const finish = "0\r\n\r\n";
+      Success &= FileFd::Write(client, finish, strlen(finish));
    }
    }
    if (Success == false)
    if (Success == false)
-      std::cerr << "SENDFILE: READ/WRITE ERROR to " << client << std::endl;
+      std::cerr << "SENDFILE:" << (chunked ? " CHUNKED" : "") << " READ/WRITE ERROR to " << client << std::endl;
    return Success;
    return Success;
 }
 }
 									/*}}}*/
 									/*}}}*/
-static bool sendData(int const client, std::string const &data)		/*{{{*/
+static bool sendData(int const client, std::list<std::string> const &headers, std::string const &data)/*{{{*/
 {
 {
-   if (FileFd::Write(client, data.c_str(), data.size()) == false)
+   if (chunkedTransferEncoding(headers) == true)
+   {
+      unsigned long long const ullsize = data.length();
+      std::string size;
+      strprintf(size, "%llX\r\n", ullsize);
+      char const * const finish = "\r\n0\r\n\r\n";
+      if (FileFd::Write(client, size.c_str(), size.length()) == false ||
+	    FileFd::Write(client, data.c_str(), ullsize) == false ||
+	    FileFd::Write(client, finish, strlen(finish)) == false)
+      {
+	 std::cerr << "SENDDATA: CHUNK WRITE ERROR to " << client << std::endl;
+	 return false;
+      }
+   }
+   else if (FileFd::Write(client, data.c_str(), data.size()) == false)
    {
    {
       std::cerr << "SENDDATA: WRITE ERROR to " << client << std::endl;
       std::cerr << "SENDDATA: WRITE ERROR to " << client << std::endl;
       return false;
       return false;
@@ -157,34 +204,38 @@ static bool sendData(int const client, std::string const &data)		/*{{{*/
 }
 }
 									/*}}}*/
 									/*}}}*/
 static void sendError(int const client, int const httpcode, std::string const &request,/*{{{*/
 static void sendError(int const client, int const httpcode, std::string const &request,/*{{{*/
-	       bool content, std::string const &error = "")
+	       bool const content, std::string const &error, std::list<std::string> &headers)
 {
 {
-   std::list<std::string> headers;
    std::string response("<html><head><title>");
    std::string response("<html><head><title>");
    response.append(httpcodeToStr(httpcode)).append("</title></head>");
    response.append(httpcodeToStr(httpcode)).append("</title></head>");
    response.append("<body><h1>").append(httpcodeToStr(httpcode)).append("</h1>");
    response.append("<body><h1>").append(httpcodeToStr(httpcode)).append("</h1>");
    if (httpcode != 200)
    if (httpcode != 200)
-   {
-      if (error.empty() == false)
-	 response.append("<p><em>Error</em>: ").append(error).append("</p>");
-      response.append("This error is a result of the request: <pre>");
-   }
+      response.append("<p><em>Error</em>: ");
+   else
+      response.append("<p><em>Success</em>: ");
+   if (error.empty() == false)
+      response.append(error);
+   else
+      response.append(httpcodeToStr(httpcode));
+   if (httpcode != 200)
+      response.append("</p>This error is a result of the request: <pre>");
    else
    else
-   {
-      if (error.empty() == false)
-	 response.append("<p><em>Success</em>: ").append(error).append("</p>");
       response.append("The successfully executed operation was requested by: <pre>");
       response.append("The successfully executed operation was requested by: <pre>");
-   }
    response.append(request).append("</pre></body></html>");
    response.append(request).append("</pre></body></html>");
+   if (httpcode != 200)
+   {
+      if (_config->FindB("aptwebserver::closeOnError", false) == true)
+	 headers.push_back("Connection: close");
+   }
    addDataHeaders(headers, response);
    addDataHeaders(headers, response);
    sendHead(client, httpcode, headers);
    sendHead(client, httpcode, headers);
    if (content == true)
    if (content == true)
-      sendData(client, response);
+      sendData(client, headers, response);
 }
 }
 static void sendSuccess(int const client, std::string const &request,
 static void sendSuccess(int const client, std::string const &request,
-	       bool content, std::string const &error = "")
+	       bool const content, std::string const &error, std::list<std::string> &headers)
 {
 {
-   sendError(client, 200, request, content, error);
+   sendError(client, 200, request, content, error, headers);
 }
 }
 									/*}}}*/
 									/*}}}*/
 static void sendRedirect(int const client, int const httpcode, std::string const &uri,/*{{{*/
 static void sendRedirect(int const client, int const httpcode, std::string const &uri,/*{{{*/
@@ -221,7 +272,7 @@ static void sendRedirect(int const client, int const httpcode, std::string const
    headers.push_back(location);
    headers.push_back(location);
    sendHead(client, httpcode, headers);
    sendHead(client, httpcode, headers);
    if (content == true)
    if (content == true)
-      sendData(client, response);
+      sendData(client, headers, response);
 }
 }
 									/*}}}*/
 									/*}}}*/
 static int filter_hidden_files(const struct dirent *a)			/*{{{*/
 static int filter_hidden_files(const struct dirent *a)			/*{{{*/
@@ -263,16 +314,15 @@ static int grouped_alpha_case_sort(const struct dirent **a, const struct dirent
 }
 }
 									/*}}}*/
 									/*}}}*/
 static void sendDirectoryListing(int const client, std::string const &dir,/*{{{*/
 static void sendDirectoryListing(int const client, std::string const &dir,/*{{{*/
-			  std::string const &request, bool content)
+			  std::string const &request, bool content, std::list<std::string> &headers)
 {
 {
-   std::list<std::string> headers;
    std::ostringstream listing;
    std::ostringstream listing;
 
 
    struct dirent **namelist;
    struct dirent **namelist;
    int const counter = scandir(dir.c_str(), &namelist, filter_hidden_files, grouped_alpha_case_sort);
    int const counter = scandir(dir.c_str(), &namelist, filter_hidden_files, grouped_alpha_case_sort);
    if (counter == -1)
    if (counter == -1)
    {
    {
-      sendError(client, 500, request, content);
+      sendError(client, 500, request, content, "scandir failed", headers);
       return;
       return;
    }
    }
 
 
@@ -311,18 +361,18 @@ static void sendDirectoryListing(int const client, std::string const &dir,/*{{{*
    addDataHeaders(headers, response);
    addDataHeaders(headers, response);
    sendHead(client, 200, headers);
    sendHead(client, 200, headers);
    if (content == true)
    if (content == true)
-      sendData(client, response);
+      sendData(client, headers, response);
 }
 }
 									/*}}}*/
 									/*}}}*/
 static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
 static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
 		    std::string &filename, std::string &params, bool &sendContent,
 		    std::string &filename, std::string &params, bool &sendContent,
-		    bool &closeConnection)
+		    bool &closeConnection, std::list<std::string> &headers)
 {
 {
    if (strncmp(request.c_str(), "HEAD ", 5) == 0)
    if (strncmp(request.c_str(), "HEAD ", 5) == 0)
       sendContent = false;
       sendContent = false;
    if (strncmp(request.c_str(), "GET ", 4) != 0)
    if (strncmp(request.c_str(), "GET ", 4) != 0)
    {
    {
-      sendError(client, 501, request, true);
+      sendError(client, 501, request, true, "", headers);
       return false;
       return false;
    }
    }
 
 
@@ -333,7 +383,7 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
    if (lineend == std::string::npos || filestart == std::string::npos ||
    if (lineend == std::string::npos || filestart == std::string::npos ||
 	 fileend == std::string::npos || filestart == fileend)
 	 fileend == std::string::npos || filestart == fileend)
    {
    {
-      sendError(client, 500, request, sendContent, "Filename can't be extracted");
+      sendError(client, 500, request, sendContent, "Filename can't be extracted", headers);
       return false;
       return false;
    }
    }
 
 
@@ -345,14 +395,14 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
       closeConnection = strcasecmp(LookupTag(request, "Connection", "Keep-Alive").c_str(), "close") == 0;
       closeConnection = strcasecmp(LookupTag(request, "Connection", "Keep-Alive").c_str(), "close") == 0;
    else
    else
    {
    {
-      sendError(client, 500, request, sendContent, "Not a HTTP/1.{0,1} request");
+      sendError(client, 500, request, sendContent, "Not a HTTP/1.{0,1} request", headers);
       return false;
       return false;
    }
    }
 
 
    filename = request.substr(filestart, fileend - filestart);
    filename = request.substr(filestart, fileend - filestart);
    if (filename.find(' ') != std::string::npos)
    if (filename.find(' ') != std::string::npos)
    {
    {
-      sendError(client, 500, request, sendContent, "Filename contains an unencoded space");
+      sendError(client, 500, request, sendContent, "Filename contains an unencoded space", headers);
       return false;
       return false;
    }
    }
 
 
@@ -360,7 +410,7 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
    if (host.empty() == true)
    if (host.empty() == true)
    {
    {
       // RFC 2616 §14.23 requires Host
       // RFC 2616 §14.23 requires Host
-      sendError(client, 400, request, sendContent, "Host header is required");
+      sendError(client, 400, request, sendContent, "Host header is required", headers);
       return false;
       return false;
    }
    }
    host = "http://" + host;
    host = "http://" + host;
@@ -371,7 +421,7 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
    {
    {
       if (absolute.find("uri") == std::string::npos)
       if (absolute.find("uri") == std::string::npos)
       {
       {
-	 sendError(client, 400, request, sendContent, "Request is absoluteURI, but configured to not accept that");
+	 sendError(client, 400, request, sendContent, "Request is absoluteURI, but configured to not accept that", headers);
 	 return false;
 	 return false;
       }
       }
       // strip the host from the request to make it an absolute path
       // strip the host from the request to make it an absolute path
@@ -379,7 +429,7 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
    }
    }
    else if (absolute.find("path") == std::string::npos)
    else if (absolute.find("path") == std::string::npos)
    {
    {
-      sendError(client, 400, request, sendContent, "Request is absolutePath, but configured to not accept that");
+      sendError(client, 400, request, sendContent, "Request is absolutePath, but configured to not accept that", headers);
       return false;
       return false;
    }
    }
 
 
@@ -398,7 +448,8 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
        filename.find_first_of("\r\n\t\f\v") != std::string::npos ||
        filename.find_first_of("\r\n\t\f\v") != std::string::npos ||
        filename.find("/../") != std::string::npos)
        filename.find("/../") != std::string::npos)
    {
    {
-      sendError(client, 400, request, sendContent, "Filename contains illegal character (sequence)");
+      std::list<std::string> headers;
+      sendError(client, 400, request, sendContent, "Filename contains illegal character (sequence)", headers);
       return false;
       return false;
    }
    }
 
 
@@ -434,46 +485,45 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
-static bool handleOnTheFlyReconfiguration(int const client, std::string const &request, std::vector<std::string> const &parts)/*{{{*/
+static bool handleOnTheFlyReconfiguration(int const client, std::string const &request,/*{{{*/
+      std::vector<std::string> parts, std::list<std::string> &headers)
 {
 {
    size_t const pcount = parts.size();
    size_t const pcount = parts.size();
    if (pcount == 4 && parts[1] == "set")
    if (pcount == 4 && parts[1] == "set")
    {
    {
       _config->Set(parts[2], parts[3]);
       _config->Set(parts[2], parts[3]);
-      sendSuccess(client, request, true, "Option '" + parts[2] + "' was set to '" + parts[3] + "'!");
+      sendSuccess(client, request, true, "Option '" + parts[2] + "' was set to '" + parts[3] + "'!", headers);
       return true;
       return true;
    }
    }
    else if (pcount == 4 && parts[1] == "find")
    else if (pcount == 4 && parts[1] == "find")
    {
    {
-      std::list<std::string> headers;
       std::string response = _config->Find(parts[2], parts[3]);
       std::string response = _config->Find(parts[2], parts[3]);
       addDataHeaders(headers, response);
       addDataHeaders(headers, response);
       sendHead(client, 200, headers);
       sendHead(client, 200, headers);
-      sendData(client, response);
+      sendData(client, headers, response);
       return true;
       return true;
    }
    }
    else if (pcount == 3 && parts[1] == "find")
    else if (pcount == 3 && parts[1] == "find")
    {
    {
-      std::list<std::string> headers;
       if (_config->Exists(parts[2]) == true)
       if (_config->Exists(parts[2]) == true)
       {
       {
 	 std::string response = _config->Find(parts[2]);
 	 std::string response = _config->Find(parts[2]);
 	 addDataHeaders(headers, response);
 	 addDataHeaders(headers, response);
 	 sendHead(client, 200, headers);
 	 sendHead(client, 200, headers);
-	 sendData(client, response);
+	 sendData(client, headers, response);
 	 return true;
 	 return true;
       }
       }
-      sendError(client, 404, request, "Requested Configuration option doesn't exist.");
+      sendError(client, 404, request, true, "Requested Configuration option doesn't exist", headers);
       return false;
       return false;
    }
    }
    else if (pcount == 3 && parts[1] == "clear")
    else if (pcount == 3 && parts[1] == "clear")
    {
    {
       _config->Clear(parts[2]);
       _config->Clear(parts[2]);
-      sendSuccess(client, request, true, "Option '" + parts[2] + "' was cleared.");
+      sendSuccess(client, request, true, "Option '" + parts[2] + "' was cleared.", headers);
       return true;
       return true;
    }
    }
 
 
-   sendError(client, 400, request, true, "Unknown on-the-fly configuration request");
+   sendError(client, 400, request, true, "Unknown on-the-fly configuration request", headers);
    return false;
    return false;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -482,18 +532,22 @@ static void * handleClient(void * voidclient)				/*{{{*/
    int client = *((int*)(voidclient));
    int client = *((int*)(voidclient));
    std::clog << "ACCEPT client " << client << std::endl;
    std::clog << "ACCEPT client " << client << std::endl;
    std::vector<std::string> messages;
    std::vector<std::string> messages;
-   while (ReadMessages(client, messages))
+   bool closeConnection = false;
+   std::list<std::string> headers;
+   while (closeConnection == false && ReadMessages(client, messages))
    {
    {
-      bool closeConnection = false;
+      // if we announced a closing, do the close
+      if (std::find(headers.begin(), headers.end(), std::string("Connection: close")) != headers.end())
+	 break;
+      headers.clear();
       for (std::vector<std::string>::const_iterator m = messages.begin();
       for (std::vector<std::string>::const_iterator m = messages.begin();
 	    m != messages.end() && closeConnection == false; ++m) {
 	    m != messages.end() && closeConnection == false; ++m) {
 	 std::clog << ">>> REQUEST from " << client << " >>>" << std::endl << *m
 	 std::clog << ">>> REQUEST from " << client << " >>>" << std::endl << *m
 	    << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
 	    << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
-	 std::list<std::string> headers;
 	 std::string filename;
 	 std::string filename;
 	 std::string params;
 	 std::string params;
 	 bool sendContent = true;
 	 bool sendContent = true;
-	 if (parseFirstLine(client, *m, filename, params, sendContent, closeConnection) == false)
+	 if (parseFirstLine(client, *m, filename, params, sendContent, closeConnection, headers) == false)
 	    continue;
 	    continue;
 
 
 	 // special webserver command request
 	 // special webserver command request
@@ -502,7 +556,7 @@ static void * handleClient(void * voidclient)				/*{{{*/
 	    std::vector<std::string> parts = VectorizeString(filename, '/');
 	    std::vector<std::string> parts = VectorizeString(filename, '/');
 	    if (parts[0] == "_config")
 	    if (parts[0] == "_config")
 	    {
 	    {
-	       handleOnTheFlyReconfiguration(client, *m, parts);
+	       handleOnTheFlyReconfiguration(client, *m, parts, headers);
 	       continue;
 	       continue;
 	    }
 	    }
 	 }
 	 }
@@ -534,7 +588,7 @@ static void * handleClient(void * voidclient)				/*{{{*/
 	       {
 	       {
 		  char error[300];
 		  char error[300];
 		  regerror(res, pattern, error, sizeof(error));
 		  regerror(res, pattern, error, sizeof(error));
-		  sendError(client, 500, *m, sendContent, error);
+		  sendError(client, 500, *m, sendContent, error, headers);
 		  continue;
 		  continue;
 	       }
 	       }
 	       if (regexec(pattern, filename.c_str(), 0, 0, 0) == 0)
 	       if (regexec(pattern, filename.c_str(), 0, 0, 0) == 0)
@@ -553,7 +607,7 @@ static void * handleClient(void * voidclient)				/*{{{*/
 	 if (_config->FindB("aptwebserver::support::http", true) == false &&
 	 if (_config->FindB("aptwebserver::support::http", true) == false &&
 	       LookupTag(*m, "Host").find(":4433") == std::string::npos)
 	       LookupTag(*m, "Host").find(":4433") == std::string::npos)
 	 {
 	 {
-	    sendError(client, 400, *m, sendContent, "HTTP disabled, all requests must be HTTPS");
+	    sendError(client, 400, *m, sendContent, "HTTP disabled, all requests must be HTTPS", headers);
 	    continue;
 	    continue;
 	 }
 	 }
 	 else if (RealFileExists(filename) == true)
 	 else if (RealFileExists(filename) == true)
@@ -609,17 +663,16 @@ static void * handleClient(void * voidclient)				/*{{{*/
 			headers.push_back(contentrange.str());
 			headers.push_back(contentrange.str());
 			sendHead(client, 206, headers);
 			sendHead(client, 206, headers);
 			if (sendContent == true)
 			if (sendContent == true)
-			   sendFile(client, data);
+			   sendFile(client, headers, data);
 			continue;
 			continue;
 		     }
 		     }
 		     else
 		     else
 		     {
 		     {
-			headers.push_back("Content-Length: 0");
 			std::ostringstream contentrange;
 			std::ostringstream contentrange;
 			contentrange << "Content-Range: bytes */" << filesize;
 			contentrange << "Content-Range: bytes */" << filesize;
 			headers.push_back(contentrange.str());
 			headers.push_back(contentrange.str());
-			sendHead(client, 416, headers);
-			continue;
+			sendError(client, 416, *m, sendContent, "", headers);
+			break;
 		     }
 		     }
 		  }
 		  }
 	       }
 	       }
@@ -628,22 +681,20 @@ static void * handleClient(void * voidclient)				/*{{{*/
 	    addFileHeaders(headers, data);
 	    addFileHeaders(headers, data);
 	    sendHead(client, 200, headers);
 	    sendHead(client, 200, headers);
 	    if (sendContent == true)
 	    if (sendContent == true)
-	       sendFile(client, data);
+	       sendFile(client, headers, data);
 	 }
 	 }
 	 else if (DirectoryExists(filename) == true)
 	 else if (DirectoryExists(filename) == true)
 	 {
 	 {
 	    if (filename[filename.length()-1] == '/')
 	    if (filename[filename.length()-1] == '/')
-	       sendDirectoryListing(client, filename, *m, sendContent);
+	       sendDirectoryListing(client, filename, *m, sendContent, headers);
 	    else
 	    else
 	       sendRedirect(client, 301, filename.append("/"), *m, sendContent);
 	       sendRedirect(client, 301, filename.append("/"), *m, sendContent);
 	 }
 	 }
 	 else
 	 else
-	    sendError(client, 404, *m, sendContent);
+	    sendError(client, 404, *m, sendContent, "", headers);
       }
       }
       _error->DumpErrors(std::cerr);
       _error->DumpErrors(std::cerr);
       messages.clear();
       messages.clear();
-      if (closeConnection == true)
-	 break;
    }
    }
    close(client);
    close(client);
    std::clog << "CLOSE client " << client << std::endl;
    std::clog << "CLOSE client " << client << std::endl;

+ 68 - 0
test/libapt/commandline_test.cc

@@ -2,6 +2,7 @@
 
 
 #include <apt-pkg/cmndline.h>
 #include <apt-pkg/cmndline.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
+#include <apt-private/private-cmndline.h>
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
@@ -85,3 +86,70 @@ TEST(CommandLineTest, BoolParsing)
    }
    }
 
 
 }
 }
+
+bool DoVoid(CommandLine &) { return false; }
+
+TEST(CommandLineTest,GetCommand)
+{
+   CommandLine::Dispatch Cmds[] = { {"install",&DoVoid}, {"remove", &DoVoid}, {0,0} };
+   {
+   char const * argv[] = { "apt-get", "-t", "unstable", "remove", "-d", "foo" };
+   char const * com = CommandLine::GetCommand(Cmds, sizeof(argv)/sizeof(argv[0]), argv);
+   EXPECT_STREQ("remove", com);
+   std::vector<CommandLine::Args> Args = getCommandArgs("apt-get", com);
+   ::Configuration c;
+   CommandLine CmdL(Args.data(), &c);
+   ASSERT_TRUE(CmdL.Parse(sizeof(argv)/sizeof(argv[0]), argv));
+   EXPECT_EQ(c.Find("APT::Default-Release"), "unstable");
+   EXPECT_TRUE(c.FindB("APT::Get::Download-Only"));
+   ASSERT_EQ(2, CmdL.FileSize());
+   EXPECT_EQ(std::string(CmdL.FileList[0]), "remove");
+   EXPECT_EQ(std::string(CmdL.FileList[1]), "foo");
+   }
+   {
+   char const * argv[] = {"apt-get", "-t", "unstable", "remove", "--", "-d", "foo" };
+   char const * com = CommandLine::GetCommand(Cmds, sizeof(argv)/sizeof(argv[0]), argv);
+   EXPECT_STREQ("remove", com);
+   std::vector<CommandLine::Args> Args = getCommandArgs("apt-get", com);
+   ::Configuration c;
+   CommandLine CmdL(Args.data(), &c);
+   ASSERT_TRUE(CmdL.Parse(sizeof(argv)/sizeof(argv[0]), argv));
+   EXPECT_EQ(c.Find("APT::Default-Release"), "unstable");
+   EXPECT_FALSE(c.FindB("APT::Get::Download-Only"));
+   ASSERT_EQ(3, CmdL.FileSize());
+   EXPECT_EQ(std::string(CmdL.FileList[0]), "remove");
+   EXPECT_EQ(std::string(CmdL.FileList[1]), "-d");
+   EXPECT_EQ(std::string(CmdL.FileList[2]), "foo");
+   }
+   {
+   char const * argv[] = {"apt-get", "-t", "unstable", "--", "remove", "-d", "foo" };
+   char const * com = CommandLine::GetCommand(Cmds, sizeof(argv)/sizeof(argv[0]), argv);
+   EXPECT_STREQ("remove", com);
+   std::vector<CommandLine::Args> Args = getCommandArgs("apt-get", com);
+   ::Configuration c;
+   CommandLine CmdL(Args.data(), &c);
+   ASSERT_TRUE(CmdL.Parse(sizeof(argv)/sizeof(argv[0]), argv));
+   EXPECT_EQ(c.Find("APT::Default-Release"), "unstable");
+   EXPECT_FALSE(c.FindB("APT::Get::Download-Only"));
+   ASSERT_EQ(CmdL.FileSize(), 3);
+   EXPECT_EQ(std::string(CmdL.FileList[0]), "remove");
+   EXPECT_EQ(std::string(CmdL.FileList[1]), "-d");
+   EXPECT_EQ(std::string(CmdL.FileList[2]), "foo");
+   }
+   {
+   char const * argv[] = {"apt-get", "install", "-t", "unstable", "--", "remove", "-d", "foo" };
+   char const * com = CommandLine::GetCommand(Cmds, sizeof(argv)/sizeof(argv[0]), argv);
+   EXPECT_STREQ("install", com);
+   std::vector<CommandLine::Args> Args = getCommandArgs("apt-get", com);
+   ::Configuration c;
+   CommandLine CmdL(Args.data(), &c);
+   ASSERT_TRUE(CmdL.Parse(sizeof(argv)/sizeof(argv[0]), argv));
+   EXPECT_EQ(c.Find("APT::Default-Release"), "unstable");
+   EXPECT_FALSE(c.FindB("APT::Get::Download-Only"));
+   ASSERT_EQ(CmdL.FileSize(), 4);
+   EXPECT_EQ(std::string(CmdL.FileList[0]), "install");
+   EXPECT_EQ(std::string(CmdL.FileList[1]), "remove");
+   EXPECT_EQ(std::string(CmdL.FileList[2]), "-d");
+   EXPECT_EQ(std::string(CmdL.FileList[3]), "foo");
+   }
+}

+ 52 - 12
test/libapt/hashsums_test.cc

@@ -207,16 +207,56 @@ TEST(HashSumsTest, FileBased)
    }
    }
    fd.Close();
    fd.Close();
 
 
-   {
-      HashString sha2("SHA256", sha256.Value());
-      EXPECT_TRUE(sha2.VerifyFile(__FILE__));
-   }
-   {
-      HashString sha2("SHA512", sha512.Value());
-      EXPECT_TRUE(sha2.VerifyFile(__FILE__));
-   }
-   {
-      HashString sha2("SHA256:" + sha256.Value());
-      EXPECT_TRUE(sha2.VerifyFile(__FILE__));
-   }
+   HashString sha2file("SHA512", sha512.Value());
+   EXPECT_TRUE(sha2file.VerifyFile(__FILE__));
+   HashString sha2wrong("SHA512", "00000000000");
+   EXPECT_FALSE(sha2wrong.VerifyFile(__FILE__));
+   EXPECT_EQ(sha2file, sha2file);
+   EXPECT_TRUE(sha2file == sha2file);
+   EXPECT_NE(sha2file, sha2wrong);
+   EXPECT_TRUE(sha2file != sha2wrong);
+
+   HashString sha2big("SHA256", sha256.Value());
+   EXPECT_TRUE(sha2big.VerifyFile(__FILE__));
+   HashString sha2small("sha256:" + sha256.Value());
+   EXPECT_TRUE(sha2small.VerifyFile(__FILE__));
+   EXPECT_EQ(sha2big, sha2small);
+   EXPECT_TRUE(sha2big == sha2small);
+   EXPECT_FALSE(sha2big != sha2small);
+
+   HashStringList hashes;
+   EXPECT_TRUE(hashes.empty());
+   EXPECT_TRUE(hashes.push_back(sha2file));
+   EXPECT_FALSE(hashes.empty());
+   EXPECT_EQ(1, hashes.size());
+
+   HashStringList wrong;
+   EXPECT_TRUE(wrong.push_back(sha2wrong));
+   EXPECT_NE(wrong, hashes);
+   EXPECT_FALSE(wrong == hashes);
+   EXPECT_TRUE(wrong != hashes);
+
+   HashStringList similar;
+   EXPECT_TRUE(similar.push_back(sha2big));
+   EXPECT_NE(similar, hashes);
+   EXPECT_FALSE(similar == hashes);
+   EXPECT_TRUE(similar != hashes);
+
+   EXPECT_TRUE(hashes.push_back(sha2big));
+   EXPECT_EQ(2, hashes.size());
+   EXPECT_TRUE(hashes.push_back(sha2small));
+   EXPECT_EQ(2, hashes.size());
+   EXPECT_FALSE(hashes.push_back(sha2wrong));
+   EXPECT_EQ(2, hashes.size());
+   EXPECT_TRUE(hashes.VerifyFile(__FILE__));
+
+   EXPECT_EQ(similar, hashes);
+   EXPECT_TRUE(similar == hashes);
+   EXPECT_FALSE(similar != hashes);
+   similar.clear();
+   EXPECT_TRUE(similar.empty());
+   EXPECT_EQ(0, similar.size());
+   EXPECT_NE(similar, hashes);
+   EXPECT_FALSE(similar == hashes);
+   EXPECT_TRUE(similar != hashes);
 }
 }

+ 2 - 2
test/libapt/makefile

@@ -14,8 +14,8 @@ test: $(BIN)/gtest$(BASENAME)
 $(BIN)/gtest$(BASENAME): $(LIB)/gtest.a
 $(BIN)/gtest$(BASENAME): $(LIB)/gtest.a
 
 
 PROGRAM = gtest${BASENAME}
 PROGRAM = gtest${BASENAME}
-SLIBS = -lapt-pkg -pthread $(LIB)/gtest.a
-LIB_MAKES = apt-pkg/makefile
+SLIBS = -lapt-pkg -lapt-private -pthread $(LIB)/gtest.a
+LIB_MAKES = apt-pkg/makefile apt-private/makefile
 SOURCE = gtest_runner.cc $(wildcard *-helpers.cc *_test.cc)
 SOURCE = gtest_runner.cc $(wildcard *-helpers.cc *_test.cc)
 include $(PROGRAM_H)
 include $(PROGRAM_H)