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

use HashStringList in the acquire system

It is not very extensible to have the supported Hashes hardcoded
everywhere and especially if it is part of virtual method names.
It is also possible that a method does not support the 'best' hash
(yet), so we might end up not being able to verify a file even though we
have a common subset of supported hashes. And those are just two of the
cases in which it is handy to have a more dynamic selection.

The downside is that this is a MAJOR API break, but the HashStringList
has a string constructor for compatibility, so with a bit of luck the
few frontends playing with the acquire system directly are okay.
David Kalnischkies лет назад: 13
Родитель
Сommit
b3501edb70

+ 95 - 107
apt-pkg/acquire-item.cc

@@ -50,6 +50,19 @@
 
 
 using namespace std;
 using namespace std;
 
 
+static void printHashSumComparision(std::string const &URI, HashStringList const &Expected, HashStringList const &Actual) /*{{{*/
+{
+   if (_config->FindB("Debug::Acquire::HashSumMismatch", false) == false)
+      return;
+   std::cerr << std::endl << URI << ":" << std::endl << " Expected Hash: " << std::endl;
+   for (HashStringList::const_iterator hs = Expected.begin(); hs != Expected.end(); ++hs)
+      std::cerr <<  "\t- " << hs->toStr() << std::endl;
+   std::cerr << " Actual Hash: " << std::endl;
+   for (HashStringList::const_iterator hs = Actual.begin(); hs != Actual.end(); ++hs)
+      std::cerr <<  "\t- " << hs->toStr() << std::endl;
+}
+									/*}}}*/
+
 // Acquire::Item::Item - Constructor					/*{{{*/
 // Acquire::Item::Item - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
@@ -118,7 +131,7 @@ void pkgAcquire::Item::Start(string /*Message*/,unsigned long long Size)
 // Acquire::Item::Done - Item downloaded OK				/*{{{*/
 // Acquire::Item::Done - Item downloaded OK				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-void pkgAcquire::Item::Done(string Message,unsigned long long Size,string /*Hash*/,
+void pkgAcquire::Item::Done(string Message,unsigned long long Size,HashStringList const &/*Hash*/,
 			    pkgAcquire::MethodConfig * /*Cnf*/)
 			    pkgAcquire::MethodConfig * /*Cnf*/)
 {
 {
    // We just downloaded something..
    // We just downloaded something..
@@ -229,8 +242,8 @@ void pkgAcquire::Item::ReportMirrorFailure(string FailCode)
    possibly query additional files */
    possibly query additional files */
 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner, string const &URI,
 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner, string const &URI,
 				 string const &URIDesc, string const &ShortDesc,
 				 string const &URIDesc, string const &ShortDesc,
-				 HashString const &ExpectedHash)
-   : Item(Owner), ExpectedHash(ExpectedHash)
+				 HashStringList const &ExpectedHashes)
+   : Item(Owner), ExpectedHashes(ExpectedHashes)
 {
 {
    /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
    /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
    Debug = _config->FindB("Debug::pkgAcquire::SubIndex",false);
    Debug = _config->FindB("Debug::pkgAcquire::SubIndex",false);
@@ -252,7 +265,7 @@ pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner, string const &URI,
 // AcqSubIndex::Custom600Headers - Insert custom request headers	/*{{{*/
 // AcqSubIndex::Custom600Headers - Insert custom request headers	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The only header we use is the last-modified header. */
 /* The only header we use is the last-modified header. */
-string pkgAcqSubIndex::Custom600Headers()
+string pkgAcqSubIndex::Custom600Headers() const
 {
 {
    string Final = _config->FindDir("Dir::State::lists");
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(Desc.URI);
    Final += URItoFileName(Desc.URI);
@@ -275,7 +288,7 @@ void pkgAcqSubIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/*
    // No good Index is provided
    // No good Index is provided
 }
 }
 									/*}}}*/
 									/*}}}*/
-void pkgAcqSubIndex::Done(string Message,unsigned long long Size,string Md5Hash,	/*{{{*/
+void pkgAcqSubIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,	/*{{{*/
 			   pkgAcquire::MethodConfig *Cnf)
 			   pkgAcquire::MethodConfig *Cnf)
 {
 {
    if(Debug)
    if(Debug)
@@ -297,7 +310,7 @@ void pkgAcqSubIndex::Done(string Message,unsigned long long Size,string Md5Hash,
       return;
       return;
    }
    }
 
 
-   Item::Done(Message,Size,Md5Hash,Cnf);
+   Item::Done(Message, Size, Hashes, Cnf);
 
 
    string FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(Desc.URI);
    string FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(Desc.URI);
 
 
@@ -343,12 +356,11 @@ bool pkgAcqSubIndex::ParseIndex(string const &IndexFile)		/*{{{*/
  * the original packages file
  * the original packages file
  */
  */
 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
-                                 IndexTarget const *Target,
-				 HashString ExpectedHash,
-                                 indexRecords *MetaIndexParser)
-   : Item(Owner), ExpectedHash(ExpectedHash), Target(Target),
+      struct IndexTarget const * const Target,
+      HashStringList const &ExpectedHashes,
+      indexRecords *MetaIndexParser)
+   : Item(Owner), ExpectedHashes(ExpectedHashes), Target(Target),
      MetaIndexParser(MetaIndexParser)
      MetaIndexParser(MetaIndexParser)
-     
 {
 {
    
    
    Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
    Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
@@ -393,7 +405,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The only header we use is the last-modified header. */
 /* The only header we use is the last-modified header. */
-string pkgAcqDiffIndex::Custom600Headers()
+string pkgAcqDiffIndex::Custom600Headers() const
 {
 {
    string Final = _config->FindDir("Dir::State::lists");
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI) + string(".IndexDiff");
    Final += URItoFileName(RealURI) + string(".IndexDiff");
@@ -447,7 +459,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile)		/*{{{*/
 	 // list cleanup needs to know that this file as well as the already
 	 // list cleanup needs to know that this file as well as the already
 	 // present index is ours, so we create an empty diff to save it for us
 	 // present index is ours, so we create an empty diff to save it for us
 	 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
 	 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
-	       ExpectedHash, ServerSha1, available_patches);
+	       ExpectedHashes, ServerSha1, available_patches);
 	 return true;
 	 return true;
       }
       }
       else
       else
@@ -533,12 +545,12 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile)		/*{{{*/
 
 
 	 if (pdiff_merge == false)
 	 if (pdiff_merge == false)
 	    new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
 	    new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
-		  ExpectedHash, ServerSha1, available_patches);
+		  ExpectedHashes, ServerSha1, available_patches);
 	 else
 	 else
 	 {
 	 {
 	    std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
 	    std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
 	    for(size_t i = 0; i < available_patches.size(); ++i)
 	    for(size_t i = 0; i < available_patches.size(); ++i)
-	       (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, RealURI, Description, Desc.ShortDesc, ExpectedHash,
+	       (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, RealURI, Description, Desc.ShortDesc, ExpectedHashes,
 		     available_patches[i], diffs);
 		     available_patches[i], diffs);
 	 }
 	 }
 
 
@@ -563,20 +575,20 @@ void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/
       std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
       std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
 		<< "Falling back to normal index file acquire" << std::endl;
 		<< "Falling back to normal index file acquire" << std::endl;
 
 
-   new pkgAcqIndex(Owner, Target, ExpectedHash, MetaIndexParser);
+   new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser);
 
 
    Complete = false;
    Complete = false;
    Status = StatDone;
    Status = StatDone;
    Dequeue();
    Dequeue();
 }
 }
 									/*}}}*/
 									/*}}}*/
-void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,string Md5Hash,	/*{{{*/
+void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,	/*{{{*/
 			   pkgAcquire::MethodConfig *Cnf)
 			   pkgAcquire::MethodConfig *Cnf)
 {
 {
    if(Debug)
    if(Debug)
       std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
       std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
 
 
-   Item::Done(Message,Size,Md5Hash,Cnf);
+   Item::Done(Message, Size, Hashes, Cnf);
 
 
    string FinalFile;
    string FinalFile;
    FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
    FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
@@ -607,10 +619,10 @@ void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,string Md5Hash
  */
  */
 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
 				   string URI,string URIDesc,string ShortDesc,
 				   string URI,string URIDesc,string ShortDesc,
-				   HashString ExpectedHash, 
+				   HashStringList const &ExpectedHashes,
 				   string ServerSha1,
 				   string ServerSha1,
 				   vector<DiffInfo> diffs)
 				   vector<DiffInfo> diffs)
-   : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), 
+   : Item(Owner), RealURI(URI), ExpectedHashes(ExpectedHashes),
      available_patches(diffs), ServerSha1(ServerSha1)
      available_patches(diffs), ServerSha1(ServerSha1)
 {
 {
    
    
@@ -642,7 +654,7 @@ void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)
       std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
       std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
 		<< "Falling back to normal index file acquire" << std::endl;
 		<< "Falling back to normal index file acquire" << std::endl;
    new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc, 
    new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc, 
-		   ExpectedHash);
+		   ExpectedHashes);
    Finish();
    Finish();
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -656,7 +668,7 @@ void pkgAcqIndexDiffs::Finish(bool allDone)
       DestFile = _config->FindDir("Dir::State::lists");
       DestFile = _config->FindDir("Dir::State::lists");
       DestFile += URItoFileName(RealURI);
       DestFile += URItoFileName(RealURI);
 
 
-      if(!ExpectedHash.empty() && !ExpectedHash.VerifyFile(DestFile))
+      if(ExpectedHashes.usable() && !ExpectedHashes.VerifyFile(DestFile))
       {
       {
 	 RenameOnError(HashSumMismatch);
 	 RenameOnError(HashSumMismatch);
 	 Dequeue();
 	 Dequeue();
@@ -734,13 +746,13 @@ bool pkgAcqIndexDiffs::QueueNextDiff()					/*{{{*/
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
-void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size,string Md5Hash,	/*{{{*/
+void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringList const &Hashes,	/*{{{*/
 			    pkgAcquire::MethodConfig *Cnf)
 			    pkgAcquire::MethodConfig *Cnf)
 {
 {
    if(Debug)
    if(Debug)
       std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
       std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
 
 
-   Item::Done(Message,Size,Md5Hash,Cnf);
+   Item::Done(Message, Size, Hashes, Cnf);
 
 
    string FinalFile;
    string FinalFile;
    FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
    FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
@@ -783,7 +795,7 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size,string Md5Has
       // see if there is more to download
       // see if there is more to download
       if(available_patches.empty() == false) {
       if(available_patches.empty() == false) {
 	 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
 	 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
-			      ExpectedHash, ServerSha1, available_patches);
+			      ExpectedHashes, ServerSha1, available_patches);
 	 return Finish();
 	 return Finish();
       } else 
       } else 
 	 return Finish(true);
 	 return Finish(true);
@@ -793,10 +805,10 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size,string Md5Has
 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor			/*{{{*/
 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor			/*{{{*/
 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire *Owner,
 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire *Owner,
 				   string const &URI, string const &URIDesc,
 				   string const &URI, string const &URIDesc,
-				   string const &ShortDesc, HashString const &ExpectedHash,
+				   string const &ShortDesc, HashStringList const &ExpectedHashes,
 				   DiffInfo const &patch,
 				   DiffInfo const &patch,
 				   std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
 				   std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
-   : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash),
+   : Item(Owner), RealURI(URI), ExpectedHashes(ExpectedHashes),
      patch(patch),allPatches(allPatches), State(StateFetchDiff)
      patch(patch),allPatches(allPatches), State(StateFetchDiff)
 {
 {
 
 
@@ -839,16 +851,16 @@ void pkgAcqIndexMergeDiffs::Failed(string Message,pkgAcquire::MethodConfig * /*C
    State = StateErrorDiff;
    State = StateErrorDiff;
    std::clog << "Falling back to normal index file acquire" << std::endl;
    std::clog << "Falling back to normal index file acquire" << std::endl;
    new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc,
    new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc,
-		   ExpectedHash);
+		   ExpectedHashes);
 }
 }
 									/*}}}*/
 									/*}}}*/
-void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,string Md5Hash,	/*{{{*/
+void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStringList const &Hashes,	/*{{{*/
 			    pkgAcquire::MethodConfig *Cnf)
 			    pkgAcquire::MethodConfig *Cnf)
 {
 {
    if(Debug)
    if(Debug)
       std::clog << "pkgAcqIndexMergeDiffs::Done(): " << Desc.URI << std::endl;
       std::clog << "pkgAcqIndexMergeDiffs::Done(): " << Desc.URI << std::endl;
 
 
-   Item::Done(Message,Size,Md5Hash,Cnf);
+   Item::Done(Message,Size,Hashes,Cnf);
 
 
    string const FinalFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
    string const FinalFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
 
 
@@ -884,7 +896,7 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,string M
    else if (State == StateApplyDiff)
    else if (State == StateApplyDiff)
    {
    {
       // see if we really got the expected file
       // see if we really got the expected file
-      if(!ExpectedHash.empty() && !ExpectedHash.VerifyFile(DestFile))
+      if(ExpectedHashes.usable() && !ExpectedHashes.VerifyFile(DestFile))
       {
       {
 	 RenameOnError(HashSumMismatch);
 	 RenameOnError(HashSumMismatch);
 	 return;
 	 return;
@@ -921,8 +933,8 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,string M
    instantiated to fetch the revision file */   
    instantiated to fetch the revision file */   
 pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
 pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
 			 string URI,string URIDesc,string ShortDesc,
 			 string URI,string URIDesc,string ShortDesc,
-			 HashString ExpectedHash, string comprExt)
-   : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), Target(0),
+			 HashStringList const &ExpectedHashes, string comprExt)
+   : Item(Owner), RealURI(URI), ExpectedHashes(ExpectedHashes), Target(0),
      MetaIndexParser(0)
      MetaIndexParser(0)
 {
 {
    if(comprExt.empty() == true)
    if(comprExt.empty() == true)
@@ -940,14 +952,14 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
 
 
    Init(URI, URIDesc, ShortDesc);
    Init(URI, URIDesc, ShortDesc);
 }
 }
-pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target,
-			 HashString const &ExpectedHash, indexRecords *MetaIndexParser)
-   : Item(Owner), RealURI(Target->URI), ExpectedHash(ExpectedHash)
+pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, struct IndexTarget const * const Target,
+			 HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser)
+   : Item(Owner), RealURI(Target->URI), ExpectedHashes(ExpectedHashes)
 {
 {
    // autoselect the compression method
    // autoselect the compression method
    std::vector<std::string> types = APT::Configuration::getCompressionTypes();
    std::vector<std::string> types = APT::Configuration::getCompressionTypes();
    CompressionExtension = "";
    CompressionExtension = "";
-   if (ExpectedHash.empty() == false)
+   if (ExpectedHashes.usable())
    {
    {
       for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
       for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
 	 if (*t == "uncompressed" || MetaIndexParser->Exists(string(Target->MetaKey).append(".").append(*t)) == true)
 	 if (*t == "uncompressed" || MetaIndexParser->Exists(string(Target->MetaKey).append(".").append(*t)) == true)
@@ -1016,7 +1028,7 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &S
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The only header we use is the last-modified header. */
 /* The only header we use is the last-modified header. */
-string pkgAcqIndex::Custom600Headers()
+string pkgAcqIndex::Custom600Headers() const
 {
 {
    string Final = _config->FindDir("Dir::State::lists");
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
    Final += URItoFileName(RealURI);
@@ -1062,22 +1074,17 @@ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)	/*{{{*/
    to the uncompressed version of the file. If this is so the file
    to the uncompressed version of the file. If this is so the file
    is copied into the partial directory. In all other cases the file
    is copied into the partial directory. In all other cases the file
    is decompressed with a gzip uri. */
    is decompressed with a gzip uri. */
-void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash,
+void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,
 		       pkgAcquire::MethodConfig *Cfg)
 		       pkgAcquire::MethodConfig *Cfg)
 {
 {
-   Item::Done(Message,Size,Hash,Cfg);
+   Item::Done(Message,Size,Hashes,Cfg);
 
 
    if (Decompression == true)
    if (Decompression == true)
    {
    {
-      if (_config->FindB("Debug::pkgAcquire::Auth", false))
-      {
-         std::cerr << std::endl << RealURI << ": Computed Hash: " << Hash;
-         std::cerr << "  Expected Hash: " << ExpectedHash.toStr() << std::endl;
-      }
-
-      if (!ExpectedHash.empty() && ExpectedHash.toStr() != Hash)
+      if (ExpectedHashes.usable() && ExpectedHashes != Hashes)
       {
       {
 	 RenameOnError(HashSumMismatch);
 	 RenameOnError(HashSumMismatch);
+	 printHashSumComparision(RealURI, ExpectedHashes, Hashes);
          return;
          return;
       }
       }
 
 
@@ -1199,12 +1206,12 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash,
 /* The Translation file is added to the queue */
 /* The Translation file is added to the queue */
 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
 			    string URI,string URIDesc,string ShortDesc) 
 			    string URI,string URIDesc,string ShortDesc) 
-  : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashString(), "")
+  : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashStringList(), "")
 {
 {
 }
 }
-pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const *Target,
-			 HashString const &ExpectedHash, indexRecords *MetaIndexParser)
-  : pkgAcqIndex(Owner, Target, ExpectedHash, MetaIndexParser)
+pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, struct IndexTarget const * const Target,
+			 HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser)
+  : pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser)
 {
 {
    // load the filesize
    // load the filesize
    indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
    indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
@@ -1214,7 +1221,7 @@ pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const *Target,
 									/*}}}*/
 									/*}}}*/
 // AcqIndexTrans::Custom600Headers - Insert custom request headers	/*{{{*/
 // AcqIndexTrans::Custom600Headers - Insert custom request headers	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
-string pkgAcqIndexTrans::Custom600Headers()
+string pkgAcqIndexTrans::Custom600Headers() const
 {
 {
    string Final = _config->FindDir("Dir::State::lists");
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
    Final += URItoFileName(RealURI);
@@ -1311,7 +1318,7 @@ pkgAcqMetaSig::~pkgAcqMetaSig()						/*{{{*/
 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers	/*{{{*/
 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The only header we use is the last-modified header. */
 /* The only header we use is the last-modified header. */
-string pkgAcqMetaSig::Custom600Headers()
+string pkgAcqMetaSig::Custom600Headers() const
 {
 {
    struct stat Buf;
    struct stat Buf;
    if (stat(LastGoodSig.c_str(),&Buf) != 0)
    if (stat(LastGoodSig.c_str(),&Buf) != 0)
@@ -1320,10 +1327,10 @@ string pkgAcqMetaSig::Custom600Headers()
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }
 }
 
 
-void pkgAcqMetaSig::Done(string Message,unsigned long long Size,string MD5,
+void pkgAcqMetaSig::Done(string Message,unsigned long long Size, HashStringList const &Hashes,
 			 pkgAcquire::MethodConfig *Cfg)
 			 pkgAcquire::MethodConfig *Cfg)
 {
 {
-   Item::Done(Message,Size,MD5,Cfg);
+   Item::Done(Message, Size, Hashes, Cfg);
 
 
    string FileName = LookupTag(Message,"Filename");
    string FileName = LookupTag(Message,"Filename");
    if (FileName.empty() == true)
    if (FileName.empty() == true)
@@ -1426,7 +1433,7 @@ pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner,			/*{{{*/
 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers	/*{{{*/
 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The only header we use is the last-modified header. */
 /* The only header we use is the last-modified header. */
-string pkgAcqMetaIndex::Custom600Headers()
+string pkgAcqMetaIndex::Custom600Headers() const
 {
 {
    string Final = _config->FindDir("Dir::State::lists");
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
    Final += URItoFileName(RealURI);
@@ -1438,10 +1445,10 @@ string pkgAcqMetaIndex::Custom600Headers()
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }
 }
 									/*}}}*/
 									/*}}}*/
-void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,string Hash,	/*{{{*/
+void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,	/*{{{*/
 			   pkgAcquire::MethodConfig *Cfg)
 			   pkgAcquire::MethodConfig *Cfg)
 {
 {
-   Item::Done(Message,Size,Hash,Cfg);
+   Item::Done(Message,Size,Hashes,Cfg);
 
 
    // MetaIndexes are done in two passes: one to download the
    // MetaIndexes are done in two passes: one to download the
    // metaindex with an appropriate method, and a second to verify it
    // metaindex with an appropriate method, and a second to verify it
@@ -1616,8 +1623,8 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
         Target != IndexTargets->end();
         Target != IndexTargets->end();
         ++Target)
         ++Target)
    {
    {
-      HashString ExpectedIndexHash;
-      indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
+      HashStringList ExpectedIndexHashes;
+      const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
       bool compressedAvailable = false;
       bool compressedAvailable = false;
       if (Record == NULL)
       if (Record == NULL)
       {
       {
@@ -1640,14 +1647,16 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
       }
       }
       else
       else
       {
       {
-	 ExpectedIndexHash = Record->Hash;
+	 ExpectedIndexHashes = Record->Hashes;
 	 if (_config->FindB("Debug::pkgAcquire::Auth", false))
 	 if (_config->FindB("Debug::pkgAcquire::Auth", false))
 	 {
 	 {
-	    std::cerr << "Queueing: " << (*Target)->URI << std::endl;
-	    std::cerr << "Expected Hash: " << ExpectedIndexHash.toStr() << std::endl;
+	    std::cerr << "Queueing: " << (*Target)->URI << std::endl
+	       << "Expected Hash:" << std::endl;
+	    for (HashStringList::const_iterator hs = ExpectedIndexHashes.begin(); hs != ExpectedIndexHashes.end(); ++hs)
+	       std::cerr <<  "\t- " << hs->toStr() << std::endl;
 	    std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
 	    std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
 	 }
 	 }
-	 if (verify == true && ExpectedIndexHash.empty() == true && (*Target)->IsOptional() == false)
+	 if (verify == true && ExpectedIndexHashes.empty() == true && (*Target)->IsOptional() == false)
 	 {
 	 {
 	    Status = StatAuthError;
 	    Status = StatAuthError;
 	    strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
 	    strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
@@ -1659,14 +1668,14 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
       {
       {
 	 if ((*Target)->IsSubIndex() == true)
 	 if ((*Target)->IsSubIndex() == true)
 	    new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
 	    new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
-				(*Target)->ShortDesc, ExpectedIndexHash);
+				(*Target)->ShortDesc, ExpectedIndexHashes);
 	 else if (transInRelease == false || Record != NULL || compressedAvailable == true)
 	 else if (transInRelease == false || Record != NULL || compressedAvailable == true)
 	 {
 	 {
 	    if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
 	    if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
 		MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)
 		MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)
-	       new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
+	       new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
 	    else
 	    else
-	       new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
+	       new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
 	 }
 	 }
 	 continue;
 	 continue;
       }
       }
@@ -1677,9 +1686,9 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)				/*{{{*/
          instead, but passing the required info to it is to much hassle */
          instead, but passing the required info to it is to much hassle */
       if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
       if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
 	  MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
 	  MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
-	 new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
+	 new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
       else
       else
-	 new pkgAcqIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser);
+	 new pkgAcqIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
    }
    }
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -1868,7 +1877,7 @@ pkgAcqMetaClearSig::~pkgAcqMetaClearSig()				/*{{{*/
 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers	/*{{{*/
 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 // FIXME: this can go away once the InRelease file is used widely
 // FIXME: this can go away once the InRelease file is used widely
-string pkgAcqMetaClearSig::Custom600Headers()
+string pkgAcqMetaClearSig::Custom600Headers() const
 {
 {
    string Final = _config->FindDir("Dir::State::lists");
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
    Final += URItoFileName(RealURI);
@@ -2002,7 +2011,6 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
    checking later. */
    checking later. */
 bool pkgAcqArchive::QueueNext()
 bool pkgAcqArchive::QueueNext()
 {
 {
-   string const ForceHash = _config->Find("Acquire::ForceHash");
    for (; Vf.end() == false; ++Vf)
    for (; Vf.end() == false; ++Vf)
    {
    {
       // Ignore not source sources
       // Ignore not source sources
@@ -2023,31 +2031,10 @@ bool pkgAcqArchive::QueueNext()
       pkgRecords::Parser &Parse = Recs->Lookup(Vf);
       pkgRecords::Parser &Parse = Recs->Lookup(Vf);
       if (_error->PendingError() == true)
       if (_error->PendingError() == true)
 	 return false;
 	 return false;
-      
+
       string PkgFile = Parse.FileName();
       string PkgFile = Parse.FileName();
-      if (ForceHash.empty() == false)
-      {
-	 if(stringcasecmp(ForceHash, "sha512") == 0)
-	    ExpectedHash = HashString("SHA512", Parse.SHA512Hash());
-	 else if(stringcasecmp(ForceHash, "sha256") == 0)
-	    ExpectedHash = HashString("SHA256", Parse.SHA256Hash());
-	 else if (stringcasecmp(ForceHash, "sha1") == 0)
-	    ExpectedHash = HashString("SHA1", Parse.SHA1Hash());
-	 else
-	    ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
-      }
-      else
-      {
-	 string Hash;
-	 if ((Hash = Parse.SHA512Hash()).empty() == false)
-	    ExpectedHash = HashString("SHA512", Hash);
-	 else if ((Hash = Parse.SHA256Hash()).empty() == false)
-	    ExpectedHash = HashString("SHA256", Hash);
-	 else if ((Hash = Parse.SHA1Hash()).empty() == false)
-	    ExpectedHash = HashString("SHA1", Hash);
-	 else
-	    ExpectedHash = HashString("MD5Sum", Parse.MD5Hash());
-      }
+      ExpectedHashes = Parse.Hashes();
+
       if (PkgFile.empty() == true)
       if (PkgFile.empty() == true)
 	 return _error->Error(_("The package index files are corrupted. No Filename: "
 	 return _error->Error(_("The package index files are corrupted. No Filename: "
 			      "field for package %s."),
 			      "field for package %s."),
@@ -2134,10 +2121,10 @@ bool pkgAcqArchive::QueueNext()
 // AcqArchive::Done - Finished fetching					/*{{{*/
 // AcqArchive::Done - Finished fetching					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash,
+void pkgAcqArchive::Done(string Message,unsigned long long Size, HashStringList const &CalcHashes,
 			 pkgAcquire::MethodConfig *Cfg)
 			 pkgAcquire::MethodConfig *Cfg)
 {
 {
-   Item::Done(Message,Size,CalcHash,Cfg);
+   Item::Done(Message, Size, CalcHashes, Cfg);
    
    
    // Check the size
    // Check the size
    if (Size != Version->Size)
    if (Size != Version->Size)
@@ -2145,12 +2132,12 @@ void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash,
       RenameOnError(SizeMismatch);
       RenameOnError(SizeMismatch);
       return;
       return;
    }
    }
-   
-   // Check the hash
+
    // FIXME: could this empty() check impose *any* sort of security issue?
    // FIXME: could this empty() check impose *any* sort of security issue?
-   if(ExpectedHash.empty() == false && ExpectedHash.toStr() != CalcHash)
+   if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
    {
    {
       RenameOnError(HashSumMismatch);
       RenameOnError(HashSumMismatch);
+      printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
       return;
       return;
    }
    }
 
 
@@ -2222,7 +2209,7 @@ void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 									/*}}}*/
 									/*}}}*/
 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
-APT_PURE bool pkgAcqArchive::IsTrusted()
+APT_PURE bool pkgAcqArchive::IsTrusted() const
 {
 {
    return Trusted;
    return Trusted;
 }
 }
@@ -2241,11 +2228,11 @@ void pkgAcqArchive::Finished()
 // AcqFile::pkgAcqFile - Constructor					/*{{{*/
 // AcqFile::pkgAcqFile - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The file is added to the queue */
 /* The file is added to the queue */
-pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string Hash,
+pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI, HashStringList const &Hashes,
 		       unsigned long long Size,string Dsc,string ShortDesc,
 		       unsigned long long Size,string Dsc,string ShortDesc,
 		       const string &DestDir, const string &DestFilename,
 		       const string &DestDir, const string &DestFilename,
                        bool IsIndexFile) :
                        bool IsIndexFile) :
-                       Item(Owner), ExpectedHash(Hash), IsIndexFile(IsIndexFile)
+                       Item(Owner), ExpectedHashes(Hashes), IsIndexFile(IsIndexFile)
 {
 {
    Retries = _config->FindI("Acquire::Retries",0);
    Retries = _config->FindI("Acquire::Retries",0);
    
    
@@ -2282,15 +2269,16 @@ pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string Hash,
 // AcqFile::Done - Item downloaded OK					/*{{{*/
 // AcqFile::Done - Item downloaded OK					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-void pkgAcqFile::Done(string Message,unsigned long long Size,string CalcHash,
+void pkgAcqFile::Done(string Message,unsigned long long Size,HashStringList const &CalcHashes,
 		      pkgAcquire::MethodConfig *Cnf)
 		      pkgAcquire::MethodConfig *Cnf)
 {
 {
-   Item::Done(Message,Size,CalcHash,Cnf);
+   Item::Done(Message,Size,CalcHashes,Cnf);
 
 
    // Check the hash
    // Check the hash
-   if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash)
+   if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
    {
    {
       RenameOnError(HashSumMismatch);
       RenameOnError(HashSumMismatch);
+      printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
       return;
       return;
    }
    }
    
    
@@ -2361,7 +2349,7 @@ void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* The only header we use is the last-modified header. */
 /* The only header we use is the last-modified header. */
-string pkgAcqFile::Custom600Headers()
+string pkgAcqFile::Custom600Headers() const
 {
 {
    if (IsIndexFile)
    if (IsIndexFile)
       return "\nIndex-File: true";
       return "\nIndex-File: true";

+ 73 - 73
apt-pkg/acquire-item.h

@@ -211,12 +211,12 @@ class pkgAcquire::Item : public WeakPointable
     *  \param Message Data from the acquire method.  Use LookupTag()
     *  \param Message Data from the acquire method.  Use LookupTag()
     *  to parse it.
     *  to parse it.
     *  \param Size The size of the object that was fetched.
     *  \param Size The size of the object that was fetched.
-    *  \param Hash The HashSum of the object that was fetched.
+    *  \param Hashes The HashSums of the object that was fetched.
     *  \param Cnf The method via which the object was fetched.
     *  \param Cnf The method via which the object was fetched.
     *
     *
     *  \sa pkgAcqMethod
     *  \sa pkgAcqMethod
     */
     */
-   virtual void Done(std::string Message,unsigned long long Size,std::string Hash,
+   virtual void Done(std::string Message, unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
 
 
    /** \brief Invoked when the worker starts to fetch this object.
    /** \brief Invoked when the worker starts to fetch this object.
@@ -238,34 +238,35 @@ class pkgAcquire::Item : public WeakPointable
     *  line, so they should (if nonempty) have a leading newline and
     *  line, so they should (if nonempty) have a leading newline and
     *  no trailing newline.
     *  no trailing newline.
     */
     */
-   virtual std::string Custom600Headers() {return std::string();};
+   virtual std::string Custom600Headers() const {return std::string();};
 
 
    /** \brief A "descriptive" URI-like string.
    /** \brief A "descriptive" URI-like string.
     *
     *
     *  \return a URI that should be used to describe what is being fetched.
     *  \return a URI that should be used to describe what is being fetched.
     */
     */
-   virtual std::string DescURI() = 0;
+   virtual std::string DescURI() const = 0;
    /** \brief Short item description.
    /** \brief Short item description.
     *
     *
     *  \return a brief description of the object being fetched.
     *  \return a brief description of the object being fetched.
     */
     */
-   virtual std::string ShortDesc() {return DescURI();}
+   virtual std::string ShortDesc() const {return DescURI();}
 
 
    /** \brief Invoked by the worker when the download is completely done. */
    /** \brief Invoked by the worker when the download is completely done. */
    virtual void Finished() {};
    virtual void Finished() {};
    
    
-   /** \brief HashSum 
+   /** \brief HashSums
     *
     *
-    *  \return the HashSum of this object, if applicable; otherwise, an
-    *  empty string.
+    *  \return the HashSums of this object, if applicable; otherwise, an
+    *  empty list.
     */
     */
-   virtual std::string HashSum() {return std::string();};
+   virtual HashStringList HashSums() const {return HashStringList();};
+   std::string HashSum() const {HashStringList const hashes = HashSums(); HashString const * const hs = hashes.find(NULL); return hs != NULL ? hs->toStr() : ""; };
 
 
    /** \return the acquire process with which this item is associated. */
    /** \return the acquire process with which this item is associated. */
-   pkgAcquire *GetOwner() {return Owner;};
+   pkgAcquire *GetOwner() const {return Owner;};
 
 
    /** \return \b true if this object is being fetched from a trusted source. */
    /** \return \b true if this object is being fetched from a trusted source. */
-   virtual bool IsTrusted() {return false;};
+   virtual bool IsTrusted() const {return false;};
    
    
    // report mirror problems
    // report mirror problems
    /** \brief Report mirror problem
    /** \brief Report mirror problem
@@ -338,17 +339,17 @@ class pkgAcqSubIndex : public pkgAcquire::Item
    /** \brief The item that is currently being downloaded. */
    /** \brief The item that is currently being downloaded. */
    pkgAcquire::ItemDesc Desc;
    pkgAcquire::ItemDesc Desc;
 
 
-   /** \brief The Hash that this file should have after download
+   /** \brief The Hashes that this file should have after download
     */
     */
-   HashString ExpectedHash;
+   HashStringList ExpectedHashes;
 
 
  public:
  public:
    // Specialized action members
    // Specialized action members
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual void Done(std::string Message,unsigned long long Size,std::string Md5Hash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() {return Desc.URI;};
-   virtual std::string Custom600Headers();
+   virtual std::string DescURI() const {return Desc.URI;};
+   virtual std::string Custom600Headers() const;
    virtual bool ParseIndex(std::string const &IndexFile);
    virtual bool ParseIndex(std::string const &IndexFile);
 
 
    /** \brief Create a new pkgAcqSubIndex.
    /** \brief Create a new pkgAcqSubIndex.
@@ -361,10 +362,10 @@ class pkgAcqSubIndex : public pkgAcquire::Item
     *
     *
     *  \param ShortDesc A short description of the list file to download.
     *  \param ShortDesc A short description of the list file to download.
     *
     *
-    *  \param ExpectedHash The list file's MD5 signature.
+    *  \param ExpectedHashes The list file's hashsums which are expected.
     */
     */
    pkgAcqSubIndex(pkgAcquire *Owner, std::string const &URI,std::string const &URIDesc,
    pkgAcqSubIndex(pkgAcquire *Owner, std::string const &URI,std::string const &URIDesc,
-		   std::string const &ShortDesc, HashString const &ExpectedHash);
+		   std::string const &ShortDesc, HashStringList const &ExpectedHashes);
 };
 };
 									/*}}}*/
 									/*}}}*/
 /** \brief An item that is responsible for fetching an index file of	{{{
 /** \brief An item that is responsible for fetching an index file of	{{{
@@ -390,10 +391,10 @@ class pkgAcqDiffIndex : public pkgAcquire::Item
     */
     */
    std::string RealURI;
    std::string RealURI;
 
 
-   /** \brief The Hash that the real index file should have after
+   /** \brief The Hashes that the real index file should have after
     *  all patches have been applied.
     *  all patches have been applied.
     */
     */
-   HashString ExpectedHash;
+   HashStringList ExpectedHashes;
 
 
    /** \brief The index file which will be patched to generate the new
    /** \brief The index file which will be patched to generate the new
     *  file.
     *  file.
@@ -413,10 +414,10 @@ class pkgAcqDiffIndex : public pkgAcquire::Item
  public:
  public:
    // Specialized action members
    // Specialized action members
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual void Done(std::string Message,unsigned long long Size,std::string Md5Hash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() {return RealURI + "Index";};
-   virtual std::string Custom600Headers();
+   virtual std::string DescURI() const {return RealURI + "Index";};
+   virtual std::string Custom600Headers() const;
 
 
    /** \brief Parse the Index file for a set of Packages diffs.
    /** \brief Parse the Index file for a set of Packages diffs.
     *
     *
@@ -441,11 +442,11 @@ class pkgAcqDiffIndex : public pkgAcquire::Item
     *
     *
     *  \param ShortDesc A short description of the list file to download.
     *  \param ShortDesc A short description of the list file to download.
     *
     *
-    *  \param ExpectedHash The list file's MD5 signature.
+    *  \param ExpectedHashes The list file's hashsums which are expected.
     */
     */
    pkgAcqDiffIndex(pkgAcquire *Owner,
    pkgAcqDiffIndex(pkgAcquire *Owner,
                    struct IndexTarget const * const Target,
                    struct IndexTarget const * const Target,
-                   HashString ExpectedHash,
+                   HashStringList const &ExpectedHashes,
                    indexRecords *MetaIndexParser);
                    indexRecords *MetaIndexParser);
 };
 };
 									/*}}}*/
 									/*}}}*/
@@ -479,10 +480,10 @@ class pkgAcqIndexMergeDiffs : public pkgAcquire::Item
     */
     */
    std::string RealURI;
    std::string RealURI;
 
 
-   /** \brief HashSum of the package index file that is being
-    *  reconstructed.
+   /** \brief The Hashes that the real index file should have after
+    *  all patches have been applied.
     */
     */
-   HashString ExpectedHash;
+   HashStringList ExpectedHashes;
 
 
    /** \brief description of the file being downloaded. */
    /** \brief description of the file being downloaded. */
    std::string Description;
    std::string Description;
@@ -516,10 +517,9 @@ class pkgAcqIndexMergeDiffs : public pkgAcquire::Item
     *  outright; its arguments are ignored.
     *  outright; its arguments are ignored.
     */
     */
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-
-   virtual void Done(std::string Message,unsigned long long Size,std::string Md5Hash,
-		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() {return RealURI + "Index";};
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
+	 pkgAcquire::MethodConfig *Cnf);
+   virtual std::string DescURI() const {return RealURI + "Index";};
 
 
    /** \brief Create an index merge-diff item.
    /** \brief Create an index merge-diff item.
     *
     *
@@ -532,7 +532,7 @@ class pkgAcqIndexMergeDiffs : public pkgAcquire::Item
     *
     *
     *  \param ShortDesc A brief description of this item.
     *  \param ShortDesc A brief description of this item.
     *
     *
-    *  \param ExpectedHash The expected md5sum of the completely
+    *  \param ExpectedHashes The expected md5sum of the completely
     *  reconstructed package index file; the index file will be tested
     *  reconstructed package index file; the index file will be tested
     *  against this value when it is entirely reconstructed.
     *  against this value when it is entirely reconstructed.
     *
     *
@@ -543,7 +543,7 @@ class pkgAcqIndexMergeDiffs : public pkgAcquire::Item
     *  check if it was the last one to complete the download step
     *  check if it was the last one to complete the download step
     */
     */
    pkgAcqIndexMergeDiffs(pkgAcquire *Owner,std::string const &URI,std::string const &URIDesc,
    pkgAcqIndexMergeDiffs(pkgAcquire *Owner,std::string const &URI,std::string const &URIDesc,
-		    std::string const &ShortDesc, HashString const &ExpectedHash,
+		    std::string const &ShortDesc, HashStringList const &ExpectedHashes,
 		    DiffInfo const &patch, std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches);
 		    DiffInfo const &patch, std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches);
 };
 };
 									/*}}}*/
 									/*}}}*/
@@ -576,8 +576,8 @@ class pkgAcqIndexDiffs : public pkgAcquire::Item
    /** \brief Handle tasks that must be performed after the item
    /** \brief Handle tasks that must be performed after the item
     *  finishes downloading.
     *  finishes downloading.
     *
     *
-    *  Dequeues the item and checks the resulting file's md5sum
-    *  against ExpectedHash after the last patch was applied.
+    *  Dequeues the item and checks the resulting file's hashsums
+    *  against ExpectedHashes after the last patch was applied.
     *  There is no need to check the md5/sha1 after a "normal" 
     *  There is no need to check the md5/sha1 after a "normal" 
     *  patch because QueueNextDiff() will check the sha1 later.
     *  patch because QueueNextDiff() will check the sha1 later.
     *
     *
@@ -603,10 +603,10 @@ class pkgAcqIndexDiffs : public pkgAcquire::Item
     */
     */
    std::string RealURI;
    std::string RealURI;
 
 
-   /** \brief The HashSum of the package index file that is being
+   /** \brief The HashSums of the package index file that is being
     *  reconstructed.
     *  reconstructed.
     */
     */
-   HashString ExpectedHash;
+   HashStringList ExpectedHashes;
 
 
    /** A description of the file being downloaded. */
    /** A description of the file being downloaded. */
    std::string Description;
    std::string Description;
@@ -649,9 +649,9 @@ class pkgAcqIndexDiffs : public pkgAcquire::Item
     */
     */
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
 
 
-   virtual void Done(std::string Message,unsigned long long Size,std::string Md5Hash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() {return RealURI + "Index";};
+   virtual std::string DescURI() const {return RealURI + "Index";};
 
 
    /** \brief Create an index diff item.
    /** \brief Create an index diff item.
     *
     *
@@ -667,7 +667,7 @@ class pkgAcqIndexDiffs : public pkgAcquire::Item
     *
     *
     *  \param ShortDesc A brief description of this item.
     *  \param ShortDesc A brief description of this item.
     *
     *
-    *  \param ExpectedHash The expected md5sum of the completely
+    *  \param ExpectedHashes The expected md5sum of the completely
     *  reconstructed package index file; the index file will be tested
     *  reconstructed package index file; the index file will be tested
     *  against this value when it is entirely reconstructed.
     *  against this value when it is entirely reconstructed.
     *
     *
@@ -678,7 +678,7 @@ class pkgAcqIndexDiffs : public pkgAcquire::Item
     *  that depends on it.
     *  that depends on it.
     */
     */
    pkgAcqIndexDiffs(pkgAcquire *Owner,std::string URI,std::string URIDesc,
    pkgAcqIndexDiffs(pkgAcquire *Owner,std::string URI,std::string URIDesc,
-		    std::string ShortDesc, HashString ExpectedHash,
+		    std::string ShortDesc, HashStringList const &ExpectedHashes,
 		    std::string ServerSha1,
 		    std::string ServerSha1,
 		    std::vector<DiffInfo> diffs=std::vector<DiffInfo>());
 		    std::vector<DiffInfo> diffs=std::vector<DiffInfo>());
 };
 };
@@ -723,7 +723,7 @@ class pkgAcqIndex : public pkgAcquire::Item
    std::string RealURI;
    std::string RealURI;
 
 
    /** \brief The expected hashsum of the decompressed index file. */
    /** \brief The expected hashsum of the decompressed index file. */
-   HashString ExpectedHash;
+   HashStringList ExpectedHashes;
 
 
    /** \brief The compression-related file extensions that are being
    /** \brief The compression-related file extensions that are being
     *  added to the downloaded file one by one if first fails (e.g., "gz bz2").
     *  added to the downloaded file one by one if first fails (e.g., "gz bz2").
@@ -739,11 +739,11 @@ class pkgAcqIndex : public pkgAcquire::Item
    
    
    // Specialized action members
    // Specialized action members
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual void Done(std::string Message,unsigned long long Size,std::string Md5Hash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string Custom600Headers();
-   virtual std::string DescURI() {return Desc.URI;};
-   virtual std::string HashSum() {return ExpectedHash.toStr(); };
+   virtual std::string Custom600Headers() const;
+   virtual std::string DescURI() const {return Desc.URI;};
+   virtual HashStringList HashSums() const {return ExpectedHashes; };
 
 
    /** \brief Create a pkgAcqIndex.
    /** \brief Create a pkgAcqIndex.
     *
     *
@@ -756,7 +756,7 @@ class pkgAcqIndex : public pkgAcquire::Item
     *
     *
     *  \param ShortDesc A brief description of this index file.
     *  \param ShortDesc A brief description of this index file.
     *
     *
-    *  \param ExpectedHash The expected hashsum of this index file.
+    *  \param ExpectedHashes The expected hashsum of this index file.
     *
     *
     *  \param compressExt The compression-related extension with which
     *  \param compressExt The compression-related extension with which
     *  this index file should be downloaded, or "" to autodetect
     *  this index file should be downloaded, or "" to autodetect
@@ -765,10 +765,10 @@ class pkgAcqIndex : public pkgAcquire::Item
     *  fallback is ".gz" or none.
     *  fallback is ".gz" or none.
     */
     */
    pkgAcqIndex(pkgAcquire *Owner,std::string URI,std::string URIDesc,
    pkgAcqIndex(pkgAcquire *Owner,std::string URI,std::string URIDesc,
-	       std::string ShortDesc, HashString ExpectedHash, 
+	       std::string ShortDesc, HashStringList const &ExpectedHashes,
 	       std::string compressExt="");
 	       std::string compressExt="");
    pkgAcqIndex(pkgAcquire *Owner, struct IndexTarget const * const Target,
    pkgAcqIndex(pkgAcquire *Owner, struct IndexTarget const * const Target,
-			 HashString const &ExpectedHash, indexRecords *MetaIndexParser);
+			 HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser);
    void Init(std::string const &URI, std::string const &URIDesc, std::string const &ShortDesc);
    void Init(std::string const &URI, std::string const &URIDesc, std::string const &ShortDesc);
 };
 };
 									/*}}}*/
 									/*}}}*/
@@ -784,7 +784,7 @@ class pkgAcqIndexTrans : public pkgAcqIndex
    public:
    public:
   
   
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual std::string Custom600Headers();
+   virtual std::string Custom600Headers() const;
 
 
    /** \brief Create a pkgAcqIndexTrans.
    /** \brief Create a pkgAcqIndexTrans.
     *
     *
@@ -800,7 +800,7 @@ class pkgAcqIndexTrans : public pkgAcqIndex
    pkgAcqIndexTrans(pkgAcquire *Owner,std::string URI,std::string URIDesc,
    pkgAcqIndexTrans(pkgAcquire *Owner,std::string URI,std::string URIDesc,
 		    std::string ShortDesc);
 		    std::string ShortDesc);
    pkgAcqIndexTrans(pkgAcquire *Owner, struct IndexTarget const * const Target,
    pkgAcqIndexTrans(pkgAcquire *Owner, struct IndexTarget const * const Target,
-		    HashString const &ExpectedHash, indexRecords *MetaIndexParser);
+		    HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser);
 };
 };
 									/*}}}*/
 									/*}}}*/
 /** \brief Information about an index file. */				/*{{{*/
 /** \brief Information about an index file. */				/*{{{*/
@@ -904,10 +904,10 @@ class pkgAcqMetaSig : public pkgAcquire::Item
    
    
    // Specialized action members
    // Specialized action members
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual void Done(std::string Message,unsigned long long Size,std::string Md5Hash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string Custom600Headers();
-   virtual std::string DescURI() {return RealURI; };
+   virtual std::string Custom600Headers() const;
+   virtual std::string DescURI() const {return RealURI; };
 
 
    /** \brief Create a new pkgAcqMetaSig. */
    /** \brief Create a new pkgAcqMetaSig. */
    pkgAcqMetaSig(pkgAcquire *Owner,std::string URI,std::string URIDesc, std::string ShortDesc,
    pkgAcqMetaSig(pkgAcquire *Owner,std::string URI,std::string URIDesc, std::string ShortDesc,
@@ -1000,10 +1000,10 @@ class pkgAcqMetaIndex : public pkgAcquire::Item
    
    
    // Specialized action members
    // Specialized action members
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual void Done(std::string Message,unsigned long long Size, std::string Hash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string Custom600Headers();
-   virtual std::string DescURI() {return RealURI; };
+   virtual std::string Custom600Headers() const;
+   virtual std::string DescURI() const {return RealURI; };
 
 
    /** \brief Create a new pkgAcqMetaIndex. */
    /** \brief Create a new pkgAcqMetaIndex. */
    pkgAcqMetaIndex(pkgAcquire *Owner,
    pkgAcqMetaIndex(pkgAcquire *Owner,
@@ -1036,7 +1036,7 @@ class pkgAcqMetaClearSig : public pkgAcqMetaIndex
 
 
 public:
 public:
    void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual std::string Custom600Headers();
+   virtual std::string Custom600Headers() const;
 
 
    /** \brief Create a new pkgAcqMetaClearSig. */
    /** \brief Create a new pkgAcqMetaClearSig. */
    pkgAcqMetaClearSig(pkgAcquire *Owner,
    pkgAcqMetaClearSig(pkgAcquire *Owner,
@@ -1073,7 +1073,7 @@ class pkgAcqArchive : public pkgAcquire::Item
    pkgRecords *Recs;
    pkgRecords *Recs;
 
 
    /** \brief The hashsum of this package. */
    /** \brief The hashsum of this package. */
-   HashString ExpectedHash;
+   HashStringList ExpectedHashes;
 
 
    /** \brief A location in which the actual filename of the package
    /** \brief A location in which the actual filename of the package
     *  should be stored.
     *  should be stored.
@@ -1101,13 +1101,13 @@ class pkgAcqArchive : public pkgAcquire::Item
    public:
    public:
    
    
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual void Done(std::string Message,unsigned long long Size,std::string Hash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() {return Desc.URI;};
-   virtual std::string ShortDesc() {return Desc.ShortDesc;};
+   virtual std::string DescURI() const {return Desc.URI;};
+   virtual std::string ShortDesc() const {return Desc.ShortDesc;};
    virtual void Finished();
    virtual void Finished();
-   virtual std::string HashSum() {return ExpectedHash.toStr(); };
-   virtual bool IsTrusted();
+   virtual HashStringList HashSums() const {return ExpectedHashes; };
+   virtual bool IsTrusted() const;
    
    
    /** \brief Create a new pkgAcqArchive.
    /** \brief Create a new pkgAcqArchive.
     *
     *
@@ -1144,7 +1144,7 @@ class pkgAcqFile : public pkgAcquire::Item
    pkgAcquire::ItemDesc Desc;
    pkgAcquire::ItemDesc Desc;
 
 
    /** \brief The hashsum of the file to download, if it is known. */
    /** \brief The hashsum of the file to download, if it is known. */
-   HashString ExpectedHash;
+   HashStringList ExpectedHashes;
 
 
    /** \brief How many times to retry the download, set from
    /** \brief How many times to retry the download, set from
     *  Acquire::Retries.
     *  Acquire::Retries.
@@ -1158,11 +1158,11 @@ class pkgAcqFile : public pkgAcquire::Item
    
    
    // Specialized action members
    // Specialized action members
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
-   virtual void Done(std::string Message,unsigned long long Size,std::string CalcHash,
+   virtual void Done(std::string Message,unsigned long long Size, HashStringList const &CalcHashes,
 		     pkgAcquire::MethodConfig *Cnf);
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() {return Desc.URI;};
-   virtual std::string HashSum() {return ExpectedHash.toStr(); };
-   virtual std::string Custom600Headers();
+   virtual std::string DescURI() const {return Desc.URI;};
+   virtual HashStringList HashSums() const { return ExpectedHashes; };
+   virtual std::string Custom600Headers() const;
 
 
    /** \brief Create a new pkgAcqFile object.
    /** \brief Create a new pkgAcqFile object.
     *
     *
@@ -1171,8 +1171,8 @@ class pkgAcqFile : public pkgAcquire::Item
     *
     *
     *  \param URI The URI to download.
     *  \param URI The URI to download.
     *
     *
-    *  \param Hash The hashsum of the file to download, if it is known;
-    *  otherwise "".
+    *  \param Hashes The hashsums of the file to download, if they are known;
+    *  otherwise empty list.
     *
     *
     *  \param Size The size of the file to download, if it is known;
     *  \param Size The size of the file to download, if it is known;
     *  otherwise 0.
     *  otherwise 0.
@@ -1195,7 +1195,7 @@ class pkgAcqFile : public pkgAcquire::Item
     * is the absolute name to which the file should be downloaded.
     * is the absolute name to which the file should be downloaded.
     */
     */
 
 
-   pkgAcqFile(pkgAcquire *Owner, std::string URI, std::string Hash, unsigned long long Size,
+   pkgAcqFile(pkgAcquire *Owner, std::string URI, HashStringList const &Hashes, unsigned long long Size,
 	      std::string Desc, std::string ShortDesc,
 	      std::string Desc, std::string ShortDesc,
 	      const std::string &DestDir="", const std::string &DestFilename="",
 	      const std::string &DestDir="", const std::string &DestFilename="",
 	      bool IsIndexFile=false);
 	      bool IsIndexFile=false);

+ 16 - 23
apt-pkg/acquire-method.cc

@@ -147,6 +147,16 @@ void pkgAcqMethod::URIStart(FetchResult &Res)
 // AcqMethod::URIDone - A URI is finished				/*{{{*/
 // AcqMethod::URIDone - A URI is finished				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
+static void printHashStringList(HashStringList const * const list)
+{
+      for (HashStringList::const_iterator hash = list->begin(); hash != list->end(); ++hash)
+      {
+	 // very old compatibility name for MD5Sum
+	 if (hash->HashType() == "MD5Sum")
+	    std::cout << "MD5-Hash: " << hash->HashValue() << "\n";
+	 std::cout << hash->HashType() << "-Hash: " << hash->HashValue() << "\n";
+      }
+}
 void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
 void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
 {
 {
    if (Queue == 0)
    if (Queue == 0)
@@ -164,15 +174,8 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
    if (Res.LastModified != 0)
    if (Res.LastModified != 0)
       std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
       std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
 
 
-   if (Res.MD5Sum.empty() == false)
-      std::cout << "MD5-Hash: " << Res.MD5Sum << "\n"
-		<< "MD5Sum-Hash: " << Res.MD5Sum << "\n";
-   if (Res.SHA1Sum.empty() == false)
-      std::cout << "SHA1-Hash: " << Res.SHA1Sum << "\n";
-   if (Res.SHA256Sum.empty() == false)
-      std::cout << "SHA256-Hash: " << Res.SHA256Sum << "\n";
-   if (Res.SHA512Sum.empty() == false)
-      std::cout << "SHA512-Hash: " << Res.SHA512Sum << "\n";
+   printHashStringList(&Res.Hashes);
+
    if (UsedMirror.empty() == false)
    if (UsedMirror.empty() == false)
       std::cout << "UsedMirror: " << UsedMirror << "\n";
       std::cout << "UsedMirror: " << UsedMirror << "\n";
    if (Res.GPGVOutput.empty() == false)
    if (Res.GPGVOutput.empty() == false)
@@ -200,15 +203,8 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
       if (Alt->LastModified != 0)
       if (Alt->LastModified != 0)
 	 std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
 	 std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
 
 
-      if (Alt->MD5Sum.empty() == false)
-	 std::cout << "Alt-MD5-Hash: " << Alt->MD5Sum << "\n";
-      if (Alt->SHA1Sum.empty() == false)
-	 std::cout << "Alt-SHA1-Hash: " << Alt->SHA1Sum << "\n";
-      if (Alt->SHA256Sum.empty() == false)
-	 std::cout << "Alt-SHA256-Hash: " << Alt->SHA256Sum << "\n";
-      if (Alt->SHA512Sum.empty() == false)
-         std::cout << "Alt-SHA512-Hash: " << Alt->SHA512Sum << "\n";
-     
+      printHashStringList(&Alt->Hashes);
+
       if (Alt->IMSHit == true)
       if (Alt->IMSHit == true)
 	 std::cout << "Alt-IMS-Hit: true\n";
 	 std::cout << "Alt-IMS-Hit: true\n";
    }
    }
@@ -442,12 +438,9 @@ pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This hides the number of hashes we are supporting from the caller. 
 /* This hides the number of hashes we are supporting from the caller. 
    It just deals with the hash class. */
    It just deals with the hash class. */
-void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
+void pkgAcqMethod::FetchResult::TakeHashes(class Hashes &Hash)
 {
 {
-   MD5Sum = Hash.MD5.Result();
-   SHA1Sum = Hash.SHA1.Result();
-   SHA256Sum = Hash.SHA256.Result();
-   SHA512Sum = Hash.SHA512.Result();
+   Hashes = Hash.GetHashStringList();
 }
 }
 									/*}}}*/
 									/*}}}*/
 void pkgAcqMethod::Dequeue() {						/*{{{*/
 void pkgAcqMethod::Dequeue() {						/*{{{*/

+ 3 - 6
apt-pkg/acquire-method.h

@@ -20,6 +20,7 @@
 #ifndef PKGLIB_ACQUIRE_METHOD_H
 #ifndef PKGLIB_ACQUIRE_METHOD_H
 #define PKGLIB_ACQUIRE_METHOD_H
 #define PKGLIB_ACQUIRE_METHOD_H
 
 
+#include <apt-pkg/hashes.h>
 #include <apt-pkg/macros.h>
 #include <apt-pkg/macros.h>
 
 
 #include <stdarg.h>
 #include <stdarg.h>
@@ -33,7 +34,6 @@
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #endif
 #endif
 
 
-class Hashes;
 class pkgAcqMethod
 class pkgAcqMethod
 {
 {
    protected:
    protected:
@@ -51,10 +51,7 @@ class pkgAcqMethod
    
    
    struct FetchResult
    struct FetchResult
    {
    {
-      std::string MD5Sum;
-      std::string SHA1Sum;
-      std::string SHA256Sum;
-      std::string SHA512Sum;
+      HashStringList Hashes;
       std::vector<std::string> GPGVOutput;
       std::vector<std::string> GPGVOutput;
       time_t LastModified;
       time_t LastModified;
       bool IMSHit;
       bool IMSHit;
@@ -62,7 +59,7 @@ class pkgAcqMethod
       unsigned long long Size;
       unsigned long long Size;
       unsigned long long ResumePoint;
       unsigned long long ResumePoint;
       
       
-      void TakeHashes(Hashes &Hash);
+      void TakeHashes(class Hashes &Hash);
       FetchResult();
       FetchResult();
    };
    };
 
 

+ 21 - 16
apt-pkg/acquire-worker.cc

@@ -326,25 +326,30 @@ bool pkgAcquire::Worker::RunMessages()
 			       Owner->DestFile.c_str(), LookupTag(Message,"Size","0").c_str(),TotalSize);
 			       Owner->DestFile.c_str(), LookupTag(Message,"Size","0").c_str(),TotalSize);
 
 
 	    // see if there is a hash to verify
 	    // see if there is a hash to verify
-	    string RecivedHash;
-	    HashString expectedHash(Owner->HashSum());
-	    if(!expectedHash.empty()) 
+	    HashStringList RecivedHashes;
+	    HashStringList expectedHashes = Owner->HashSums();
+	    for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
 	    {
 	    {
-	       string hashTag = expectedHash.HashType()+"-Hash";
-	       string hashSum = LookupTag(Message, hashTag.c_str());
-	       if(!hashSum.empty())
-		  RecivedHash = expectedHash.HashType() + ":" + hashSum;
-	       if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
-	       {
-		  clog << "201 URI Done: " << Owner->DescURI() << endl
-		       << "RecivedHash: " << RecivedHash << endl
-		       << "ExpectedHash: " << expectedHash.toStr() 
-		       << endl << endl;
-	       }
+	       std::string const tagname = hs->HashType() + "-Hash";
+	       std::string const hashsum = LookupTag(Message, tagname.c_str());
+	       if (hashsum.empty() == false)
+		  RecivedHashes.push_back(HashString(hs->HashType(), hashsum));
+	    }
+
+	    if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
+	    {
+	       std::clog << "201 URI Done: " << Owner->DescURI() << endl
+		  << "RecivedHash:" << endl;
+	       for (HashStringList::const_iterator hs = RecivedHashes.begin(); hs != RecivedHashes.end(); ++hs)
+		  std::clog <<  "\t- " << hs->toStr() << std::endl;
+	       std::clog << "ExpectedHash:" << endl;
+	       for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
+		  std::clog <<  "\t- " << hs->toStr() << std::endl;
+	       std::clog << endl;
 	    }
 	    }
-	    Owner->Done(Message, ServerSize, RecivedHash.c_str(), Config);
+	    Owner->Done(Message, ServerSize, RecivedHashes, Config);
 	    ItemDone();
 	    ItemDone();
-	    
+
 	    // Log that we are done
 	    // Log that we are done
 	    if (Log != 0)
 	    if (Log != 0)
 	    {
 	    {

+ 73 - 24
apt-pkg/contrib/hashes.cc

@@ -141,11 +141,21 @@ APT_PURE bool HashString::operator!=(HashString const &other) const
 }
 }
 									/*}}}*/
 									/*}}}*/
 
 
+bool HashStringList::usable() const					/*{{{*/
+{
+   if (empty() == true)
+      return false;
+   std::string const forcedType = _config->Find("Acquire::ForceHash", "");
+   if (forcedType.empty() == true)
+      return true;
+   return find(forcedType) != NULL;
+}
+									/*}}}*/
 HashString const * HashStringList::find(char const * const type) const /*{{{*/
 HashString const * HashStringList::find(char const * const type) const /*{{{*/
 {
 {
    if (type == NULL || type[0] == '\0')
    if (type == NULL || type[0] == '\0')
    {
    {
-      std::string forcedType = _config->Find("Acquire::ForceHash", "");
+      std::string const forcedType = _config->Find("Acquire::ForceHash", "");
       if (forcedType.empty() == false)
       if (forcedType.empty() == false)
 	 return find(forcedType.c_str());
 	 return find(forcedType.c_str());
       for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t)
       for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t)
@@ -196,6 +206,15 @@ bool HashStringList::VerifyFile(std::string filename) const		/*{{{*/
 									/*}}}*/
 									/*}}}*/
 bool HashStringList::operator==(HashStringList const &other) const	/*{{{*/
 bool HashStringList::operator==(HashStringList const &other) const	/*{{{*/
 {
 {
+   std::string const forcedType = _config->Find("Acquire::ForceHash", "");
+   if (forcedType.empty() == false)
+   {
+      HashString const * const hs = other.find(forcedType);
+      HashString const * const ohs = other.find(forcedType);
+      if (hs == NULL || ohs == NULL)
+	 return false;
+      return hs == ohs;
+   }
    short matches = 0;
    short matches = 0;
    for (const_iterator hs = begin(); hs != end(); ++hs)
    for (const_iterator hs = begin(); hs != end(); ++hs)
    {
    {
@@ -216,11 +235,28 @@ bool HashStringList::operator!=(HashStringList const &other) const
 }
 }
 									/*}}}*/
 									/*}}}*/
 
 
-// Hashes::AddFD - Add the contents of the FD				/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool Hashes::AddFD(int const Fd,unsigned long long Size, bool const addMD5,
-		   bool const addSHA1, bool const addSHA256, bool const addSHA512)
+// Hashes::Add* - Add the contents of data or FD			/*{{{*/
+bool Hashes::Add(const unsigned char * const Data,unsigned long long const Size, unsigned int const Hashes)
+{
+   bool Res = true;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+   if ((Hashes & MD5SUM) == MD5SUM)
+      Res &= MD5.Add(Data, Size);
+   if ((Hashes & SHA1SUM) == SHA1SUM)
+      Res &= SHA1.Add(Data, Size);
+   if ((Hashes & SHA256SUM) == SHA256SUM)
+      Res &= SHA256.Add(Data, Size);
+   if ((Hashes & SHA512SUM) == SHA512SUM)
+      Res &= SHA512.Add(Data, Size);
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+   return Res;
+}
+bool Hashes::AddFD(int const Fd,unsigned long long Size, unsigned int const Hashes)
 {
 {
    unsigned char Buf[64*64];
    unsigned char Buf[64*64];
    bool const ToEOF = (Size == UntilEOF);
    bool const ToEOF = (Size == UntilEOF);
@@ -234,19 +270,12 @@ bool Hashes::AddFD(int const Fd,unsigned long long Size, bool const addMD5,
       if (ToEOF && Res == 0) // EOF
       if (ToEOF && Res == 0) // EOF
 	 break;
 	 break;
       Size -= Res;
       Size -= Res;
-      if (addMD5 == true)
-	 MD5.Add(Buf,Res);
-      if (addSHA1 == true)
-	 SHA1.Add(Buf,Res);
-      if (addSHA256 == true)
-	 SHA256.Add(Buf,Res);
-      if (addSHA512 == true)
-	 SHA512.Add(Buf,Res);
+      if (Add(Buf, Res, Hashes) == false)
+	 return false;
    }
    }
    return true;
    return true;
 }
 }
-bool Hashes::AddFD(FileFd &Fd,unsigned long long Size, bool const addMD5,
-		   bool const addSHA1, bool const addSHA256, bool const addSHA512)
+bool Hashes::AddFD(FileFd &Fd,unsigned long long Size, unsigned int const Hashes)
 {
 {
    unsigned char Buf[64*64];
    unsigned char Buf[64*64];
    bool const ToEOF = (Size == 0);
    bool const ToEOF = (Size == 0);
@@ -265,15 +294,35 @@ bool Hashes::AddFD(FileFd &Fd,unsigned long long Size, bool const addMD5,
       else if (a == 0) // EOF
       else if (a == 0) // EOF
 	 break;
 	 break;
       Size -= a;
       Size -= a;
-      if (addMD5 == true)
-	 MD5.Add(Buf, a);
-      if (addSHA1 == true)
-	 SHA1.Add(Buf, a);
-      if (addSHA256 == true)
-	 SHA256.Add(Buf, a);
-      if (addSHA512 == true)
-	 SHA512.Add(Buf, a);
+      if (Add(Buf, a, Hashes) == false)
+	 return false;
    }
    }
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
+HashStringList Hashes::GetHashStringList()
+{
+   HashStringList hashes;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+   hashes.push_back(HashString("MD5Sum", MD5.Result().Value()));
+   hashes.push_back(HashString("SHA1", SHA1.Result().Value()));
+   hashes.push_back(HashString("SHA256", SHA256.Result().Value()));
+   hashes.push_back(HashString("SHA512", SHA512.Result().Value()));
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+   return hashes;
+}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+	#pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
+#endif
+Hashes::Hashes() {}
+Hashes::~Hashes() {}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif

+ 64 - 20
apt-pkg/contrib/hashes.h

@@ -114,6 +114,15 @@ class HashStringList
     */
     */
    bool empty() const { return list.empty(); }
    bool empty() const { return list.empty(); }
 
 
+   /** has the list at least one good entry
+    *
+    * similar to #empty, but handles forced hashes.
+    *
+    * @return if no hash is forced, same result as #empty,
+    * if one is forced \b true if this has is available, \b false otherwise
+    */
+   bool usable() const;
+
    typedef std::vector<HashString>::const_iterator const_iterator;
    typedef std::vector<HashString>::const_iterator const_iterator;
 
 
    /** iterator to the first element */
    /** iterator to the first element */
@@ -128,8 +137,10 @@ class HashStringList
    /** compare two HashStringList for similarity.
    /** compare two HashStringList for similarity.
     *
     *
     * Two lists are similar if at least one hashtype is in both lists
     * 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.
+    * and the hashsum matches. All hashes are checked by default,
+    * if one doesn't match false is returned regardless of how many
+    * matched before. If a hash is forced, only this hash is compared,
+    * all others are ignored.
     */
     */
    bool operator==(HashStringList const &other) const;
    bool operator==(HashStringList const &other) const;
    bool operator!=(HashStringList const &other) const;
    bool operator!=(HashStringList const &other) const;
@@ -152,30 +163,63 @@ class HashStringList
 
 
 class Hashes
 class Hashes
 {
 {
+   /** \brief dpointer placeholder */
+   void *d;
+
    public:
    public:
+   /* those will disappear in the future as it is hard to add new ones this way.
+    * Use Add* to build the results and get them via GetHashStringList() instead */
+   APT_DEPRECATED MD5Summation MD5;
+   APT_DEPRECATED SHA1Summation SHA1;
+   APT_DEPRECATED SHA256Summation SHA256;
+   APT_DEPRECATED SHA512Summation SHA512;
 
 
-   MD5Summation MD5;
-   SHA1Summation SHA1;
-   SHA256Summation SHA256;
-   SHA512Summation SHA512;
-   
    static const int UntilEOF = 0;
    static const int UntilEOF = 0;
 
 
-   inline bool Add(const unsigned char *Data,unsigned long long Size)
+   bool Add(const unsigned char * const Data, unsigned long long const Size, unsigned int const Hashes = ~0);
+   inline bool Add(const char * const Data)
+   {return Add((unsigned char const * const)Data,strlen(Data));};
+   inline bool Add(const unsigned char * const Beg,const unsigned char * const End)
+   {return Add(Beg,End-Beg);};
+
+   enum SupportedHashes { MD5SUM = (1 << 0), SHA1SUM = (1 << 1), SHA256SUM = (1 << 2),
+      SHA512SUM = (1 << 3) };
+   bool AddFD(int const Fd,unsigned long long Size = 0, unsigned int const Hashes = ~0);
+   bool AddFD(FileFd &Fd,unsigned long long Size = 0, unsigned int const Hashes = ~0);
+
+   HashStringList GetHashStringList();
+
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+   Hashes();
+   virtual ~Hashes();
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+
+   private:
+   APT_HIDDEN APT_CONST inline unsigned int boolsToFlag(bool const addMD5, bool const addSHA1, bool const addSHA256, bool const addSHA512)
    {
    {
-      return MD5.Add(Data,Size) && SHA1.Add(Data,Size) && SHA256.Add(Data,Size) && SHA512.Add(Data,Size);
+      unsigned int Hashes = ~0;
+      if (addMD5 == false) Hashes &= ~MD5SUM;
+      if (addSHA1 == false) Hashes &= ~SHA1SUM;
+      if (addSHA256 == false) Hashes &= ~SHA256SUM;
+      if (addSHA512 == false) Hashes &= ~SHA512SUM;
+      return Hashes;
+   }
+
+   public:
+   APT_DEPRECATED bool AddFD(int const Fd, unsigned long long Size, bool const addMD5,
+	 bool const addSHA1, bool const addSHA256, bool const addSHA512) {
+      return AddFD(Fd, Size, boolsToFlag(addMD5, addSHA1, addSHA256, addSHA512));
+   };
+
+   APT_DEPRECATED bool AddFD(FileFd &Fd, unsigned long long Size, bool const addMD5,
+	 bool const addSHA1, bool const addSHA256, bool const addSHA512) {
+      return AddFD(Fd, Size, boolsToFlag(addMD5, addSHA1, addSHA256, addSHA512));
    };
    };
-   inline bool Add(const char *Data) {return Add((unsigned char const *)Data,strlen(Data));};
-   inline bool AddFD(int const Fd,unsigned long long Size = 0)
-   { return AddFD(Fd, Size, true, true, true, true); };
-   bool AddFD(int const Fd, unsigned long long Size, bool const addMD5,
-	      bool const addSHA1, bool const addSHA256, bool const addSHA512);
-   inline bool AddFD(FileFd &Fd,unsigned long long Size = 0)
-   { return AddFD(Fd, Size, true, true, true, true); };
-   bool AddFD(FileFd &Fd, unsigned long long Size, bool const addMD5,
-	      bool const addSHA1, bool const addSHA256, bool const addSHA512);
-   inline bool Add(const unsigned char *Beg,const unsigned char *End) 
-                  {return Add(Beg,End-Beg);};
 };
 };
 
 
 #endif
 #endif

+ 1 - 1
apt-pkg/deb/debmetaindex.cc

@@ -258,7 +258,7 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
       vector <struct IndexTarget *> *targets = ComputeIndexTargets();
       vector <struct IndexTarget *> *targets = ComputeIndexTargets();
       for (vector <struct IndexTarget*>::const_iterator Target = targets->begin(); Target != targets->end(); ++Target) {
       for (vector <struct IndexTarget*>::const_iterator Target = targets->begin(); Target != targets->end(); ++Target) {
 	 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
 	 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
-			 (*Target)->ShortDesc, HashString());
+			 (*Target)->ShortDesc, HashStringList());
       }
       }
       delete targets;
       delete targets;
 
 

+ 11 - 30
apt-pkg/deb/debrecords.cc

@@ -73,36 +73,17 @@ string debRecordParser::Homepage()
    return Section.FindS("Homepage");
    return Section.FindS("Homepage");
 }
 }
 									/*}}}*/
 									/*}}}*/
-// RecordParser::MD5Hash - Return the archive hash			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string debRecordParser::MD5Hash()
-{
-   return Section.FindS("MD5Sum");
-}
-									/*}}}*/
-// RecordParser::SHA1Hash - Return the archive hash			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string debRecordParser::SHA1Hash()
-{
-   return Section.FindS("SHA1");
-}
-									/*}}}*/
-// RecordParser::SHA256Hash - Return the archive hash			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string debRecordParser::SHA256Hash()
-{
-   return Section.FindS("SHA256");
-}
-									/*}}}*/
-// RecordParser::SHA512Hash - Return the archive hash			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string debRecordParser::SHA512Hash()
-{
-   return Section.FindS("SHA512");
+// RecordParser::Hashes - return the available archive hashes		/*{{{*/
+HashStringList debRecordParser::Hashes() const
+{
+   HashStringList hashes;
+   for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+   {
+      std::string const hash = Section.FindS(*type);
+      if (hash.empty() == false)
+	 hashes.push_back(HashString(*type, hash));
+   }
+   return hashes;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // RecordParser::Maintainer - Return the maintainer email		/*{{{*/
 // RecordParser::Maintainer - Return the maintainer email		/*{{{*/

+ 3 - 5
apt-pkg/deb/debrecords.h

@@ -42,13 +42,11 @@ class debRecordParser : public pkgRecords::Parser
 
 
    // These refer to the archive file for the Version
    // These refer to the archive file for the Version
    virtual std::string FileName();
    virtual std::string FileName();
-   virtual std::string MD5Hash();
-   virtual std::string SHA1Hash();
-   virtual std::string SHA256Hash();
-   virtual std::string SHA512Hash();
    virtual std::string SourcePkg();
    virtual std::string SourcePkg();
    virtual std::string SourceVer();
    virtual std::string SourceVer();
-   
+
+   virtual HashStringList Hashes() const;
+
    // These are some general stats about the package
    // These are some general stats about the package
    virtual std::string Maintainer();
    virtual std::string Maintainer();
    virtual std::string ShortDesc();
    virtual std::string ShortDesc();

+ 5 - 3
apt-pkg/indexcopy.cc

@@ -516,7 +516,7 @@ bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
       return false;
       return false;
    }
    }
 
 
-   if (!Record->Hash.VerifyFile(prefix+file))
+   if (!Record->Hashes.VerifyFile(prefix+file))
    {
    {
       _error->Warning(_("Hash mismatch for: %s"),file.c_str());
       _error->Warning(_("Hash mismatch for: %s"),file.c_str());
       return false;
       return false;
@@ -524,8 +524,10 @@ bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
 
 
    if(Debug == true)
    if(Debug == true)
    {
    {
-      cout << "File: " << prefix+file << endl;
-      cout << "Expected Hash " << Record->Hash.toStr() << endl;
+      cout << "File: " << prefix+file << endl
+	 << "Expected Hash " << endl;
+      for (HashStringList::const_iterator hs = Record->Hashes.begin(); hs != Record->Hashes.end(); ++hs)
+	 std::cout <<  "\t- " << hs->toStr() << std::endl;
    }
    }
 
 
    return true;
    return true;

+ 1 - 1
apt-pkg/indexrecords.cc

@@ -105,7 +105,7 @@ bool indexRecords::Load(const string Filename)				/*{{{*/
 	    return false;
 	    return false;
 	 indexRecords::checkSum *Sum = new indexRecords::checkSum;
 	 indexRecords::checkSum *Sum = new indexRecords::checkSum;
 	 Sum->MetaKeyFilename = Name;
 	 Sum->MetaKeyFilename = Name;
-	 Sum->Hash = HashString(HashString::SupportedHashes()[i],Hash);
+	 Sum->Hashes.push_back(HashString(HashString::SupportedHashes()[i],Hash));
 	 Sum->Size = Size;
 	 Sum->Size = Size;
 	 Entries[Name] = Sum;
 	 Entries[Name] = Sum;
       }
       }

+ 11 - 1
apt-pkg/indexrecords.h

@@ -55,11 +55,21 @@ class indexRecords
    virtual ~indexRecords(){};
    virtual ~indexRecords(){};
 };
 };
 
 
+#if __GNUC__ >= 4
+	// ensure that con- & de-structor don't trigger this warning
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
 struct indexRecords::checkSum
 struct indexRecords::checkSum
 {
 {
    std::string MetaKeyFilename;
    std::string MetaKeyFilename;
-   HashString Hash;
+   HashStringList Hashes;
    unsigned long long Size;
    unsigned long long Size;
+
+   APT_DEPRECATED HashString Hash;
 };
 };
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
 
 #endif
 #endif

+ 22 - 4
apt-pkg/pkgrecords.h

@@ -18,6 +18,8 @@
 #define PKGLIB_PKGRECORDS_H
 #define PKGLIB_PKGRECORDS_H
 
 
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/pkgcache.h>
+#include <apt-pkg/hashes.h>
+#include <apt-pkg/macros.h>
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
@@ -56,13 +58,21 @@ class pkgRecords::Parser						/*{{{*/
    
    
    // These refer to the archive file for the Version
    // These refer to the archive file for the Version
    virtual std::string FileName() {return std::string();};
    virtual std::string FileName() {return std::string();};
-   virtual std::string MD5Hash() {return std::string();};
-   virtual std::string SHA1Hash() {return std::string();};
-   virtual std::string SHA256Hash() {return std::string();};
-   virtual std::string SHA512Hash() {return std::string();};
    virtual std::string SourcePkg() {return std::string();};
    virtual std::string SourcePkg() {return std::string();};
    virtual std::string SourceVer() {return std::string();};
    virtual std::string SourceVer() {return std::string();};
 
 
+   /** return all known hashes in this record.
+    *
+    * For authentication proposes packages come with hashsums which
+    * this method is supposed to parse and return so that clients can
+    * choose the hash to be used.
+    */
+   virtual HashStringList Hashes() const { return HashStringList(); };
+   APT_DEPRECATED std::string MD5Hash() const { return GetHashFromHashes("MD5Sum"); };
+   APT_DEPRECATED std::string SHA1Hash() const { return GetHashFromHashes("SHA1"); };
+   APT_DEPRECATED std::string SHA256Hash() const { return GetHashFromHashes("SHA256"); };
+   APT_DEPRECATED std::string SHA512Hash() const { return GetHashFromHashes("SHA512"); };
+
    // These are some general stats about the package
    // These are some general stats about the package
    virtual std::string Maintainer() {return std::string();};
    virtual std::string Maintainer() {return std::string();};
    virtual std::string ShortDesc() {return std::string();};
    virtual std::string ShortDesc() {return std::string();};
@@ -77,6 +87,14 @@ class pkgRecords::Parser						/*{{{*/
    virtual void GetRec(const char *&Start,const char *&Stop) {Start = Stop = 0;};
    virtual void GetRec(const char *&Start,const char *&Stop) {Start = Stop = 0;};
    
    
    virtual ~Parser() {};
    virtual ~Parser() {};
+
+   private:
+   APT_HIDDEN std::string GetHashFromHashes(char const * const type) const
+   {
+      HashStringList const hashes = Hashes();
+      HashString const * const hs = hashes.find(type);
+      return hs != NULL ? hs->HashValue() : "";
+   };
 };
 };
 									/*}}}*/
 									/*}}}*/
 #endif
 #endif

+ 2 - 4
cmdline/apt-get.cc

@@ -838,8 +838,7 @@ static bool DoSource(CommandLine &CmdL)
 	    }
 	    }
 
 
 	 // see if we have a hash (Acquire::ForceHash is the only way to have none)
 	 // 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)
+	 if (I->Hashes.usable() == false && _config->FindB("APT::Get::AllowUnauthenticated",false) == false)
 	 {
 	 {
 	    ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n",
 	    ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n",
 		     localFile.c_str());
 		     localFile.c_str());
@@ -847,8 +846,7 @@ static bool DoSource(CommandLine &CmdL)
 	 }
 	 }
 
 
 	 new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
 	 new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
-			hs != NULL ? hs->toStr() : "", I->Size,
-			Last->Index().SourceInfo(*Last,*I),Src);
+			I->Hashes, I->Size, Last->Index().SourceInfo(*Last,*I), Src);
       }
       }
    }
    }
    
    

+ 24 - 24
test/integration/test-apt-sources-deb822

@@ -23,14 +23,14 @@ Description: summay
 
 
 msgtest 'Test sources.list' 'old style'
 msgtest 'Test sources.list' 'old style'
 echo "deb http://ftp.debian.org/debian stable main" > $SOURCES
 echo "deb http://ftp.debian.org/debian stable main" > $SOURCES
-testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
 
 
 msgtest 'Test sources.list' 'simple deb822'
 msgtest 'Test sources.list' 'simple deb822'
 echo "$BASE"  > $SOURCES
 echo "$BASE"  > $SOURCES
-testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
 
 
 
 
@@ -39,29 +39,29 @@ msgtest 'Test deb822 with' 'two entries'
 echo "$BASE" > $SOURCES
 echo "$BASE" > $SOURCES
 echo "" >> $SOURCES
 echo "" >> $SOURCES
 echo "$BASE" | sed  s/stable/unstable/  >> $SOURCES
 echo "$BASE" | sed  s/stable/unstable/  >> $SOURCES
-testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
-'http://ftp.debian.org/debian/dists/unstable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_unstable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/unstable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_unstable_main_i18n_Translation-en 0 :
+'http://ftp.debian.org/debian/dists/unstable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_unstable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/unstable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_unstable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/unstable/InRelease' ftp.debian.org_debian_dists_unstable_InRelease 0 "  aptget update --print-uris
 'http://ftp.debian.org/debian/dists/unstable/InRelease' ftp.debian.org_debian_dists_unstable_InRelease 0 "  aptget update --print-uris
 
 
 # two suite entries
 # two suite entries
 msgtest 'Test deb822 with' 'two Suite entries'
 msgtest 'Test deb822 with' 'two Suite entries'
 echo "$BASE"  | sed -e "s/stable/stable unstable/" > $SOURCES
 echo "$BASE"  | sed -e "s/stable/stable unstable/" > $SOURCES
-testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
-'http://ftp.debian.org/debian/dists/unstable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_unstable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/unstable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_unstable_main_i18n_Translation-en 0 :
+'http://ftp.debian.org/debian/dists/unstable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_unstable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/unstable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_unstable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/unstable/InRelease' ftp.debian.org_debian_dists_unstable_InRelease 0 "  aptget update --print-uris 
 'http://ftp.debian.org/debian/dists/unstable/InRelease' ftp.debian.org_debian_dists_unstable_InRelease 0 "  aptget update --print-uris 
 
 
 msgtest 'Test deb822' 'architecture option'
 msgtest 'Test deb822' 'architecture option'
 echo "$BASE" > $SOURCES
 echo "$BASE" > $SOURCES
 echo "Architectures: amd64 armel" >> $SOURCES
 echo "Architectures: amd64 armel" >> $SOURCES
-testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-amd64/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-amd64_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/binary-armel/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-armel_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/binary-amd64/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-amd64_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/binary-armel/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-armel_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
 
 
 
 
@@ -85,19 +85,19 @@ testempty aptget update --print-uris
 # multiple URIs
 # multiple URIs
 msgtest 'Test deb822 sources.list file which has' 'Multiple URIs work'
 msgtest 'Test deb822 sources.list file which has' 'Multiple URIs work'
 echo "$BASE"  | sed -e 's#http://ftp.debian.org/debian#http://ftp.debian.org/debian http://ftp.de.debian.org/debian#' > $SOURCES
 echo "$BASE"  | sed -e 's#http://ftp.debian.org/debian#http://ftp.debian.org/debian http://ftp.de.debian.org/debian#' > $SOURCES
-testequal --nomsg  "'http://ftp.de.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.de.debian.org_debian_dists_stable_main_binary-i386_Packages 0 :
-'http://ftp.de.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.de.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+testequal --nomsg  "'http://ftp.de.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.de.debian.org_debian_dists_stable_main_binary-i386_Packages 0 
+'http://ftp.de.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.de.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.de.debian.org/debian/dists/stable/InRelease' ftp.de.debian.org_debian_dists_stable_InRelease 0 
 'http://ftp.de.debian.org/debian/dists/stable/InRelease' ftp.de.debian.org_debian_dists_stable_InRelease 0 
-'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris 
 
 
 # multiple Type in one field
 # multiple Type in one field
 msgtest 'Test deb822 sources.list file which has' 'Multiple Types work'
 msgtest 'Test deb822 sources.list file which has' 'Multiple Types work'
 echo "$BASE"  | sed -e 's#Types: deb#Types: deb deb-src#' > $SOURCES
 echo "$BASE"  | sed -e 's#Types: deb#Types: deb deb-src#' > $SOURCES
-testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/source/Sources.bz2' ftp.debian.org_debian_dists_stable_main_source_Sources 0 :
-'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 :
-'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 :
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/main/source/Sources.bz2' ftp.debian.org_debian_dists_stable_main_source_Sources 0 
+'http://ftp.debian.org/debian/dists/stable/main/binary-i386/Packages.bz2' ftp.debian.org_debian_dists_stable_main_binary-i386_Packages 0 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris 
 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris 
 
 
 # a Suite
 # a Suite
@@ -107,6 +107,6 @@ Types: deb
 URIs: http://emacs.naquadah.org
 URIs: http://emacs.naquadah.org
 Suites: stable/
 Suites: stable/
 EOF
 EOF
-testequal --nomsg "'http://emacs.naquadah.org/stable/Packages.bz2' emacs.naquadah.org_stable_Packages 0 :
-'http://emacs.naquadah.org/stable/en.bz2' emacs.naquadah.org_stable_en 0 :
+testequal --nomsg "'http://emacs.naquadah.org/stable/Packages.bz2' emacs.naquadah.org_stable_Packages 0 
+'http://emacs.naquadah.org/stable/en.bz2' emacs.naquadah.org_stable_en 0 
 'http://emacs.naquadah.org/stable/InRelease' emacs.naquadah.org_stable_InRelease 0 "  aptget update --print-uris 
 'http://emacs.naquadah.org/stable/InRelease' emacs.naquadah.org_stable_InRelease 0 "  aptget update --print-uris 

+ 4 - 4
test/integration/test-bug-722207-print-uris-even-if-very-quiet

@@ -16,10 +16,10 @@ setupaptarchive
 
 
 APTARCHIVE=$(readlink -f ./aptarchive)
 APTARCHIVE=$(readlink -f ./aptarchive)
 
 
-testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 MD5Sum:" aptget upgrade -qq --print-uris
-testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 MD5Sum:" aptget dist-upgrade -qq --print-uris
-testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 MD5Sum:" aptget install apt -qq --print-uris
-testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 MD5Sum:" aptget download apt -qq --print-uris
+testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 " aptget upgrade -qq --print-uris
+testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 " aptget dist-upgrade -qq --print-uris
+testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 " aptget install apt -qq --print-uris
+testequal "'file://${APTARCHIVE}/pool/main/apt/apt_2_all.deb' apt_2_all.deb 0 " aptget download apt -qq --print-uris
 testequal "'file://${APTARCHIVE}/apt_2.dsc' apt_2.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
 testequal "'file://${APTARCHIVE}/apt_2.dsc' apt_2.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
 'file://${APTARCHIVE}/apt_2.tar.gz' apt_2.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source apt -qq --print-uris
 'file://${APTARCHIVE}/apt_2.tar.gz' apt_2.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source apt -qq --print-uris
 testequal "'http://packages.debian.org/changelogs/pool/main/apt/apt_2/changelog'" aptget changelog apt -qq --print-uris
 testequal "'http://packages.debian.org/changelogs/pool/main/apt/apt_2/changelog'" aptget changelog apt -qq --print-uris

+ 0 - 6
test/integration/test-pdiff-usage

@@ -13,12 +13,6 @@ changetowebserver
 
 
 PKGFILE="${TESTDIR}/$(echo "$(basename $0)" | sed 's#^test-#Packages-#')"
 PKGFILE="${TESTDIR}/$(echo "$(basename $0)" | sed 's#^test-#Packages-#')"
 
 
-echo '#!/bin/sh
-touch merge-was-used
-/usr/bin/diffindex-rred "$@"' > extrred
-chmod +x extrred
-echo 'Dir::Bin::rred "./extrred";' > rootdir/etc/apt/apt.conf.d/99rred
-
 wasmergeused() {
 wasmergeused() {
 	msgtest 'Test for successful execution of' "$*"
 	msgtest 'Test for successful execution of' "$*"
 	local OUTPUT=$(mktemp)
 	local OUTPUT=$(mktemp)

+ 1 - 1
test/integration/test-ubuntu-bug-346386-apt-get-update-paywall

@@ -22,7 +22,7 @@ Config-Item: Acquire::http::DependOnSTDIN=0
 600 Acquire URI
 600 Acquire URI
 URI: http://localhost:8080/holygrail
 URI: http://localhost:8080/holygrail
 Filename: knights-talking
 Filename: knights-talking
-' | LD_LIBRARY_PATH=${BUILDDIRECTORY} ${METHODSDIR}/http >/dev/null 2>&1 && msgpass || msgfail
+' | runapt ${METHODSDIR}/http >/dev/null 2>&1 && msgpass || msgfail
 testfileequal knights-talking 'ni ni ni'
 testfileequal knights-talking 'ni ni ni'
 
 
 ensure_n_canary_strings_in_dir() {
 ensure_n_canary_strings_in_dir() {

+ 77 - 8
test/libapt/hashsums_test.cc

@@ -1,5 +1,6 @@
 #include <config.h>
 #include <config.h>
 
 
+#include <apt-pkg/configuration.h>
 #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>
@@ -166,20 +167,26 @@ TEST(HashSumsTest, FileBased)
    {
    {
       Hashes hashes;
       Hashes hashes;
       hashes.AddFD(fd.Fd());
       hashes.AddFD(fd.Fd());
-      EXPECT_EQ(md5.Value(), hashes.MD5.Result().Value());
-      EXPECT_EQ(sha1.Value(), hashes.SHA1.Result().Value());
-      EXPECT_EQ(sha256.Value(), hashes.SHA256.Result().Value());
-      EXPECT_EQ(sha512.Value(), hashes.SHA512.Result().Value());
+      HashStringList list = hashes.GetHashStringList();
+      EXPECT_FALSE(list.empty());
+      EXPECT_EQ(4, list.size());
+      EXPECT_EQ(md5.Value(), list.find("MD5Sum")->HashValue());
+      EXPECT_EQ(sha1.Value(), list.find("SHA1")->HashValue());
+      EXPECT_EQ(sha256.Value(), list.find("SHA256")->HashValue());
+      EXPECT_EQ(sha512.Value(), list.find("SHA512")->HashValue());
    }
    }
    unsigned long sz = fd.FileSize();
    unsigned long sz = fd.FileSize();
    fd.Seek(0);
    fd.Seek(0);
    {
    {
       Hashes hashes;
       Hashes hashes;
       hashes.AddFD(fd.Fd(), sz);
       hashes.AddFD(fd.Fd(), sz);
-      EXPECT_EQ(md5.Value(), hashes.MD5.Result().Value());
-      EXPECT_EQ(sha1.Value(), hashes.SHA1.Result().Value());
-      EXPECT_EQ(sha256.Value(), hashes.SHA256.Result().Value());
-      EXPECT_EQ(sha512.Value(), hashes.SHA512.Result().Value());
+      HashStringList list = hashes.GetHashStringList();
+      EXPECT_FALSE(list.empty());
+      EXPECT_EQ(4, list.size());
+      EXPECT_EQ(md5.Value(), list.find("MD5Sum")->HashValue());
+      EXPECT_EQ(sha1.Value(), list.find("SHA1")->HashValue());
+      EXPECT_EQ(sha256.Value(), list.find("SHA256")->HashValue());
+      EXPECT_EQ(sha512.Value(), list.find("SHA512")->HashValue());
    }
    }
    fd.Seek(0);
    fd.Seek(0);
    {
    {
@@ -260,3 +267,65 @@ TEST(HashSumsTest, FileBased)
    EXPECT_FALSE(similar == hashes);
    EXPECT_FALSE(similar == hashes);
    EXPECT_TRUE(similar != hashes);
    EXPECT_TRUE(similar != hashes);
 }
 }
+TEST(HashSumsTest, HashStringList)
+{
+   _config->Clear("Acquire::ForceHash");
+
+   HashStringList list;
+   EXPECT_TRUE(list.empty());
+   EXPECT_FALSE(list.usable());
+   EXPECT_EQ(0, list.size());
+   EXPECT_EQ(NULL, list.find(NULL));
+   EXPECT_EQ(NULL, list.find(""));
+   EXPECT_EQ(NULL, list.find("MD5Sum"));
+
+   HashStringList list2;
+   EXPECT_FALSE(list == list2);
+   EXPECT_TRUE(list != list2);
+
+   Hashes hashes;
+   hashes.Add("The quick brown fox jumps over the lazy dog");
+   list = hashes.GetHashStringList();
+   EXPECT_FALSE(list.empty());
+   EXPECT_TRUE(list.usable());
+   EXPECT_EQ(4, list.size());
+   EXPECT_TRUE(NULL != list.find(NULL));
+   EXPECT_TRUE(NULL != list.find(""));
+   EXPECT_TRUE(NULL != list.find("MD5Sum"));
+   EXPECT_TRUE(NULL == list.find("ROT26"));
+
+   _config->Set("Acquire::ForceHash", "MD5Sum");
+   EXPECT_FALSE(list.empty());
+   EXPECT_TRUE(list.usable());
+   EXPECT_EQ(4, list.size());
+   EXPECT_TRUE(NULL != list.find(NULL));
+   EXPECT_TRUE(NULL != list.find(""));
+   EXPECT_TRUE(NULL != list.find("MD5Sum"));
+   EXPECT_TRUE(NULL == list.find("ROT26"));
+
+   _config->Set("Acquire::ForceHash", "ROT26");
+   EXPECT_FALSE(list.empty());
+   EXPECT_FALSE(list.usable());
+   EXPECT_EQ(4, list.size());
+   EXPECT_TRUE(NULL == list.find(NULL));
+   EXPECT_TRUE(NULL == list.find(""));
+   EXPECT_TRUE(NULL != list.find("MD5Sum"));
+   EXPECT_TRUE(NULL == list.find("ROT26"));
+
+   _config->Clear("Acquire::ForceHash");
+
+   list2.push_back(*list.find("MD5Sum"));
+   EXPECT_TRUE(list == list2);
+   EXPECT_FALSE(list != list2);
+
+   // introduce a mismatch to the list
+   list2.push_back(HashString("SHA1", "cacecbd74968bc90ea3342767e6b94f46ddbcafc"));
+   EXPECT_FALSE(list == list2);
+   EXPECT_TRUE(list != list2);
+
+   _config->Set("Acquire::ForceHash", "MD5Sum");
+   EXPECT_TRUE(list == list2);
+   EXPECT_FALSE(list != list2);
+
+   _config->Clear("Acquire::ForceHash");
+}