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

rework hashsum verification in the acquire system

Having every item having its own code to verify the file(s) it handles
is an errorprune process and easy to break, especially if items move
through various stages (download, uncompress, patching, …). With a giant
rework we centralize (most of) the verification to have a better
enforcement rate and (hopefully) less chance for bugs, but it breaks the
ABI bigtime in exchange – and as we break it anyway, it is broken even
harder.

It shouldn't effect most frontends as they don't deal with the acquire
system at all or implement their own items, but some do and will need to
be patched (might be an opportunity to use apt on-board material).

The theory is simple: Items implement methods to decide if hashes need to
be checked (in this stage) and to return the expected hashes for this
item (in this stage). The verification itself is done in worker message
passing which has the benefit that a hashsum error is now a proper error
for the acquire system rather than a Done() which is later revised to a
Failed().
David Kalnischkies лет назад: 11
Родитель
Сommit
448c38bdcd

Разница между файлами не показана из-за своего большого размера
+ 1859 - 1891
apt-pkg/acquire-item.cc


Разница между файлами не показана из-за своего большого размера
+ 286 - 391
apt-pkg/acquire-item.h


+ 4 - 1
apt-pkg/acquire-method.cc

@@ -376,7 +376,10 @@ int pkgAcqMethod::Run(bool Single)
 		  Tmp->ExpectedHashes.push_back(HashString(*t, hash));
 	    }
             char *End;
-            Tmp->MaximumSize = strtoll(LookupTag(Message, "Maximum-Size", "0").c_str(), &End, 10);
+	    if (Tmp->ExpectedHashes.FileSize() > 0)
+	       Tmp->MaximumSize = Tmp->ExpectedHashes.FileSize();
+	    else
+	       Tmp->MaximumSize = strtoll(LookupTag(Message, "Maximum-Size", "0").c_str(), &End, 10);
 	    Tmp->Next = 0;
 	    
 	    // Append it to the list

+ 111 - 78
apt-pkg/acquire-worker.cc

@@ -55,8 +55,8 @@ pkgAcquire::Worker::Worker(Queue *Q,MethodConfig *Cnf,
    CurrentItem = 0;
    TotalSize = 0;
    CurrentSize = 0;
-   
-   Construct();   
+
+   Construct();
 }
 									/*}}}*/
 // Worker::Worker - Constructor for method config startup		/*{{{*/
@@ -70,8 +70,8 @@ pkgAcquire::Worker::Worker(MethodConfig *Cnf)
    CurrentItem = 0;
    TotalSize = 0;
    CurrentSize = 0;
-   
-   Construct();   
+
+   Construct();
 }
 									/*}}}*/
 // Worker::Construct - Constructor helper				/*{{{*/
@@ -136,7 +136,7 @@ bool pkgAcquire::Worker::Start()
    }
    for (int I = 0; I != 4; I++)
       SetCloseExec(Pipes[I],true);
-   
+
    // Fork off the process
    Process = ExecFork();
    if (Process == 0)
@@ -145,9 +145,9 @@ bool pkgAcquire::Worker::Start()
       dup2(Pipes[1],STDOUT_FILENO);
       dup2(Pipes[2],STDIN_FILENO);
       SetCloseExec(STDOUT_FILENO,false);
-      SetCloseExec(STDIN_FILENO,false);      
+      SetCloseExec(STDIN_FILENO,false);
       SetCloseExec(STDERR_FILENO,false);
-      
+
       const char *Args[2];
       Args[0] = Method.c_str();
       Args[1] = 0;
@@ -165,7 +165,7 @@ bool pkgAcquire::Worker::Start()
    close(Pipes[2]);
    OutReady = false;
    InReady = true;
-   
+
    // Read the configuration data
    if (WaitFd(InFd) == false ||
        ReadMessages() == false)
@@ -174,7 +174,7 @@ bool pkgAcquire::Worker::Start()
    RunMessages();
    if (OwnerQ != 0)
       SendConfiguration();
-   
+
    return true;
 }
 									/*}}}*/
@@ -201,7 +201,7 @@ bool pkgAcquire::Worker::RunMessages()
 
       if (Debug == true)
 	 clog << " <- " << Access << ':' << QuoteString(Message,"\n") << endl;
-      
+
       // Fetch the message number
       char *End;
       int Number = strtol(Message.c_str(),&End,10);
@@ -215,15 +215,15 @@ bool pkgAcquire::Worker::RunMessages()
 
       // update used mirror
       string UsedMirror = LookupTag(Message,"UsedMirror", "");
-      if (!UsedMirror.empty() && 
+      if (!UsedMirror.empty() &&
           Itm && 
-          Itm->Description.find(" ") != string::npos) 
+          Itm->Description.find(" ") != string::npos)
       {
          Itm->Description.replace(0, Itm->Description.find(" "), UsedMirror);
          // FIXME: will we need this as well?
          //Itm->ShortDesc = UsedMirror;
       }
-      
+
       // Determine the message number and dispatch
       switch (Number)
       {
@@ -232,18 +232,18 @@ bool pkgAcquire::Worker::RunMessages()
 	 if (Capabilities(Message) == false)
 	    return _error->Error("Unable to process Capabilities message from %s",Access.c_str());
 	 break;
-	 
+
 	 // 101 Log
 	 case 101:
 	 if (Debug == true)
 	    clog << " <- (log) " << LookupTag(Message,"Message") << endl;
 	 break;
-	 
+
 	 // 102 Status
 	 case 102:
 	 Status = LookupTag(Message,"Message");
 	 break;
-	    
+
          // 103 Redirect
          case 103:
          {
@@ -252,7 +252,7 @@ bool pkgAcquire::Worker::RunMessages()
                _error->Error("Method gave invalid 103 Redirect message");
                break;
             }
- 
+
             string NewURI = LookupTag(Message,"New-URI",URI.c_str());
             Itm->URI = NewURI;
 
@@ -272,7 +272,7 @@ bool pkgAcquire::Worker::RunMessages()
 	       Log->Done(Desc);
             break;
          }
-   
+
 	 // 200 URI Start
 	 case 200:
 	 {
@@ -281,23 +281,23 @@ bool pkgAcquire::Worker::RunMessages()
 	       _error->Error("Method gave invalid 200 URI Start message");
 	       break;
 	    }
-	    
+
 	    CurrentItem = Itm;
 	    CurrentSize = 0;
 	    TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
 	    ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
-	    Itm->Owner->Start(Message,strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10));
+	    Itm->Owner->Start(Message, TotalSize);
 
 	    // Display update before completion
 	    if (Log != 0 && Log->MorePulses == true)
 	       Log->Pulse(Itm->Owner->GetOwner());
-	    
+
 	    if (Log != 0)
 	       Log->Fetch(*Itm);
 
 	    break;
 	 }
-	 
+
 	 // 201 URI Done
 	 case 201:
 	 {
@@ -306,7 +306,7 @@ bool pkgAcquire::Worker::RunMessages()
 	       _error->Error("Method gave invalid 201 URI Done message");
 	       break;
 	    }
-	    
+
 	    pkgAcquire::Item *Owner = Itm->Owner;
 	    pkgAcquire::ItemDesc Desc = *Itm;
 
@@ -316,22 +316,11 @@ bool pkgAcquire::Worker::RunMessages()
 	    // Display update before completion
 	    if (Log != 0 && Log->MorePulses == true)
 	       Log->Pulse(Owner->GetOwner());
-	    
+
 	    OwnerQ->ItemDone(Itm);
-	    unsigned long long const ServerSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
-            bool isHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
-                         StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
-            // Using the https method the server might return 200, but the
-            // If-Modified-Since condition is not satsified, libcurl will
-            // discard the download. In this case, however, TotalSize will be
-            // set to the actual size of the file, while ServerSize will be set
-            // to 0. Therefore, if the item is marked as a hit and the
-            // downloaded size (ServerSize) is 0, we ignore TotalSize.
-	    if (TotalSize != 0 && (!isHit || ServerSize != 0) && ServerSize != TotalSize)
-	       _error->Warning("Size of file %s is not what the server reported %s %llu",
-			       Owner->DestFile.c_str(), LookupTag(Message,"Size","0").c_str(),TotalSize);
-
-	    // see if there is a hash to verify
+
+	    HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
+	    // see if we got hashes to verify
 	    HashStringList ReceivedHashes;
 	    for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
 	    {
@@ -340,6 +329,18 @@ bool pkgAcquire::Worker::RunMessages()
 	       if (hashsum.empty() == false)
 		  ReceivedHashes.push_back(HashString(*type, hashsum));
 	    }
+	    // not all methods always sent Hashes our way
+	    if (ExpectedHashes.usable() == true && ReceivedHashes.usable() == false)
+	    {
+	       std::string const filename = LookupTag(Message, "Filename", Owner->DestFile.c_str());
+	       if (filename.empty() == false && RealFileExists(filename))
+	       {
+		  Hashes calc(ExpectedHashes);
+		  FileFd file(filename, FileFd::ReadOnly, FileFd::None);
+		  calc.AddFD(file);
+		  ReceivedHashes = calc.GetHashStringList();
+	       }
+	    }
 
 	    if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
 	    {
@@ -348,30 +349,66 @@ bool pkgAcquire::Worker::RunMessages()
 	       for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
 		  std::clog <<  "\t- " << hs->toStr() << std::endl;
 	       std::clog << "ExpectedHash:" << endl;
-	       HashStringList expectedHashes = Owner->HashSums();
-	       for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
+	       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, ReceivedHashes, Config);
-	    ItemDone();
 
-	    // Log that we are done
-	    if (Log != 0)
+	    // decide if what we got is what we expected
+	    bool consideredOkay = false;
+	    bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
+	       StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
+	    if (ExpectedHashes.usable())
 	    {
-	       if (isHit)
+	       if (ReceivedHashes.usable() == false)
 	       {
-		  /* Hide 'hits' for local only sources - we also manage to
-		     hide gets */
-		  if (Config->LocalOnly == false)
-		     Log->IMSHit(Desc);
-	       }	       
+		  /* IMS-Hits can't be checked here as we will have uncompressed file,
+		     but the hashes for the compressed file. What we have was good through
+		     so all we have to ensure later is that we are not stalled. */
+		  consideredOkay = isIMSHit;
+	       }
+	       else if (ReceivedHashes == ExpectedHashes)
+		  consideredOkay = true;
 	       else
-		  Log->Done(Desc);
+		  consideredOkay = false;
+
+	    }
+	    else if (Owner->HashesRequired() == true)
+	       consideredOkay = false;
+	    else
+	       consideredOkay = true;
+
+	    if (consideredOkay == true)
+	    {
+	       Owner->Done(Message, ReceivedHashes, Config);
+	       ItemDone();
+
+	       // Log that we are done
+	       if (Log != 0)
+	       {
+		  if (isIMSHit)
+		  {
+		     /* Hide 'hits' for local only sources - we also manage to
+			hide gets */
+		     if (Config->LocalOnly == false)
+			Log->IMSHit(Desc);
+		  }
+		  else
+		     Log->Done(Desc);
+	       }
+	    }
+	    else
+	    {
+	       Owner->Status = pkgAcquire::Item::StatAuthError;
+	       Owner->Failed(Message,Config);
+	       ItemDone();
+
+	       if (Log != 0)
+		  Log->Fail(Desc);
 	    }
 	    break;
-	 }	 
-	 
+	 }
+
 	 // 400 URI Failure
 	 case 400:
 	 {
@@ -408,18 +445,18 @@ bool pkgAcquire::Worker::RunMessages()
 	       Log->Fail(Desc);
 
 	    break;
-	 }	 
-	 
+	 }
+
 	 // 401 General Failure
 	 case 401:
 	 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
 	 break;
-	 
+
 	 // 403 Media Change
 	 case 403:
-	 MediaChange(Message); 
+	 MediaChange(Message);
 	 break;
-      }      
+      }
    }
    return true;
 }
@@ -432,7 +469,7 @@ bool pkgAcquire::Worker::Capabilities(string Message)
 {
    if (Config == 0)
       return true;
-   
+
    Config->Version = LookupTag(Message,"Version");
    Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
    Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
@@ -447,13 +484,13 @@ bool pkgAcquire::Worker::Capabilities(string Message)
       clog << "Configured access method " << Config->Access << endl;
       clog << "Version:" << Config->Version <<
 	      " SingleInstance:" << Config->SingleInstance <<
-	      " Pipeline:" << Config->Pipeline << 
-	      " SendConfig:" << Config->SendConfig << 
-	      " LocalOnly: " << Config->LocalOnly << 
-	      " NeedsCleanup: " << Config->NeedsCleanup << 
+	      " Pipeline:" << Config->Pipeline <<
+	      " SendConfig:" << Config->SendConfig <<
+	      " LocalOnly: " << Config->LocalOnly <<
+	      " NeedsCleanup: " << Config->NeedsCleanup <<
 	      " Removable: " << Config->Removable << endl;
    }
-   
+
    return true;
 }
 									/*}}}*/
@@ -463,10 +500,10 @@ bool pkgAcquire::Worker::Capabilities(string Message)
 bool pkgAcquire::Worker::MediaChange(string Message)
 {
    int status_fd = _config->FindI("APT::Status-Fd",-1);
-   if(status_fd > 0) 
+   if(status_fd > 0)
    {
       string Media = LookupTag(Message,"Media");
-      string Drive = LookupTag(Message,"Drive"); 
+      string Drive = LookupTag(Message,"Drive");
       ostringstream msg,status;
       ioprintf(msg,_("Please insert the disc labeled: "
 		     "'%s' "
@@ -536,12 +573,12 @@ bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
 {
    if (OutFd == -1)
       return false;
-   
+
    string Message = "600 URI Acquire\n";
    Message.reserve(300);
    Message += "URI: " + Item->URI;
    Message += "\nFilename: " + Item->Owner->DestFile;
-   HashStringList const hsl = Item->Owner->HashSums();
+   HashStringList const hsl = Item->Owner->GetExpectedHashes();
    for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
       Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
    if(Item->Owner->FileSize > 0)
@@ -564,7 +601,7 @@ bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
       clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
    OutQueue += Message;
    OutReady = true;
-   
+
    return true;
 }
 									/*}}}*/
@@ -586,7 +623,7 @@ bool pkgAcquire::Worker::OutFdReady()
    OutQueue.erase(0,Res);
    if (OutQueue.empty() == true)
       OutReady = false;
-   
+
    return true;
 }
 									/*}}}*/
@@ -608,7 +645,7 @@ bool pkgAcquire::Worker::InFdReady()
 bool pkgAcquire::Worker::MethodFailure()
 {
    _error->Error("Method %s has died unexpectedly!",Access.c_str());
-   
+
    // do not reap the child here to show meaningfull error to the user
    ExecWait(Process,Access.c_str(),false);
    Process = -1;
@@ -620,26 +657,22 @@ bool pkgAcquire::Worker::MethodFailure()
    InReady = false;
    OutQueue = string();
    MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
-   
+
    return false;
 }
 									/*}}}*/
-// Worker::Pulse - Called periodically 					/*{{{*/
+// Worker::Pulse - Called periodically					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 void pkgAcquire::Worker::Pulse()
 {
    if (CurrentItem == 0)
       return;
- 
+
    struct stat Buf;
    if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
       return;
    CurrentSize = Buf.st_size;
-   
-   // Hmm? Should not happen...
-   if (CurrentSize > TotalSize && TotalSize != 0)
-      TotalSize = CurrentSize;
 }
 									/*}}}*/
 // Worker::ItemDone - Called when the current item is finished		/*{{{*/

+ 10 - 0
apt-pkg/contrib/hashes.cc

@@ -23,6 +23,7 @@
 #include <stddef.h>
 #include <algorithm>
 #include <unistd.h>
+#include <stdlib.h>
 #include <string>
 #include <iostream>
 									/*}}}*/
@@ -178,6 +179,15 @@ HashString const * HashStringList::find(char const * const type) const /*{{{*/
    return NULL;
 }
 									/*}}}*/
+unsigned long long HashStringList::FileSize() const			/*{{{*/
+{
+   HashString const * const hsf = find("Checksum-FileSize");
+   if (hsf == NULL)
+      return 0;
+   std::string const hv = hsf->HashValue();
+   return strtoull(hv.c_str(), NULL, 10);
+}
+									/*}}}*/
 bool HashStringList::supported(char const * const type)			/*{{{*/
 {
    for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t)

+ 9 - 0
apt-pkg/contrib/hashes.h

@@ -87,6 +87,15 @@ class HashStringList
     */
    HashString const * find(char const * const type) const;
    HashString const * find(std::string const &type) const { return find(type.c_str()); }
+
+   /** finds the filesize hash and returns it as number
+    *
+    * @return beware: if the size isn't known we return \b 0 here,
+    * just like we would do for an empty file. If that is a problem
+    * for you have to get the size manually out of the list.
+    */
+   unsigned long long FileSize() const;
+
    /** check if the given hash type is supported
     *
     * @param type to check

+ 2 - 2
apt-pkg/deb/debindexfile.cc

@@ -742,13 +742,13 @@ bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const
 
    // and give it to the list parser
    debDebFileParser Parser(DebControl, DebFile);
-   if(Gen.SelectFile(DebFile, "local", *this) == false)
+   if(Gen.SelectFile(DebFile, "local", *this, pkgCache::Flag::LocalSource) == false)
       return _error->Error("Problem with SelectFile %s", DebFile.c_str());
 
    pkgCache::PkgFileIterator File = Gen.GetCurFile();
    File->Size = DebControl->Size();
    File->mtime = DebControl->ModificationTime();
-   
+
    if (Gen.MergeList(Parser) == false)
       return _error->Error("Problem with MergeLister for %s", DebFile.c_str());
 

+ 31 - 47
apt-pkg/deb/debmetaindex.cc

@@ -192,11 +192,13 @@ vector <IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
 		vector<debSectionEntry const*> const SectionEntries = src->second;
 		for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
 		     I != SectionEntries.end(); ++I) {
-			IndexTarget * Target = new IndexTarget();
-			Target->ShortDesc = "Sources";
-			Target->MetaKey = SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
-			Target->URI = SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section);
-			Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
+			char const * const ShortDesc = "Sources";
+			IndexTarget * const Target = new IndexTarget(
+			      SourceIndexURISuffix(ShortDesc, (*I)->Section),
+			      ShortDesc,
+			      Info(ShortDesc, (*I)->Section),
+			      SourceIndexURI(ShortDesc, (*I)->Section)
+			      );
 			IndexTargets->push_back (Target);
 		}
 	}
@@ -212,11 +214,13 @@ vector <IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
 			continue;
 		for (vector <const debSectionEntry *>::const_iterator I = a->second.begin();
 		     I != a->second.end(); ++I) {
-			IndexTarget * Target = new IndexTarget();
-			Target->ShortDesc = "Packages";
-			Target->MetaKey = IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section, a->first);
-			Target->URI = IndexURI(Target->ShortDesc.c_str(), (*I)->Section, a->first);
-			Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section, a->first);
+			char const * const ShortDesc = "Packages";
+			IndexTarget * const Target = new IndexTarget(
+			      IndexURISuffix(ShortDesc, (*I)->Section, a->first),
+			      ShortDesc,
+			      Info (ShortDesc, (*I)->Section, a->first),
+			      IndexURI(ShortDesc, (*I)->Section, a->first)
+			      );
 			IndexTargets->push_back (Target);
 			sections.insert((*I)->Section);
 		}
@@ -235,11 +239,13 @@ vector <IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
 	     s != sections.end(); ++s) {
 		for (std::vector<std::string>::const_iterator l = lang.begin();
 		     l != lang.end(); ++l) {
-			IndexTarget * Target = new OptionalIndexTarget();
-			Target->ShortDesc = "Translation-" + *l;
-			Target->MetaKey = TranslationIndexURISuffix(l->c_str(), *s);
-			Target->URI = TranslationIndexURI(l->c_str(), *s);
-			Target->Description = Info (Target->ShortDesc.c_str(), *s);
+			std::string const ShortDesc = "Translation-" + *l;
+			IndexTarget * const Target = new OptionalIndexTarget(
+			      TranslationIndexURISuffix(l->c_str(), *s),
+			      ShortDesc,
+			      Info (ShortDesc.c_str(), *s),
+			      TranslationIndexURI(l->c_str(), *s)
+			      );
 			IndexTargets->push_back(Target);
 		}
 	}
@@ -249,8 +255,6 @@ vector <IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
 									/*}}}*/
 bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 {
-   bool const tryInRelease = _config->FindB("Acquire::TryInRelease", true);
-
    indexRecords * const iR = new indexRecords(Dist);
    if (Trusted == ALWAYS_TRUSTED)
       iR->SetTrusted(true);
@@ -258,37 +262,17 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
       iR->SetTrusted(false);
 
    // special case for --print-uris
-   if (GetAll) {
-      vector <IndexTarget *> *targets = ComputeIndexTargets();
-      for (vector <IndexTarget*>::const_iterator Target = targets->begin(); Target != targets->end(); ++Target) {
-	 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
-			 (*Target)->ShortDesc, HashStringList());
-      }
-      delete targets;
-
-      // this is normally created in pkgAcqMetaSig, but if we run
-      // in --print-uris mode, we add it here
-      if (tryInRelease == false)
-	 new pkgAcqMetaIndex(Owner, NULL,
-                             MetaIndexURI("Release"),
-                             MetaIndexInfo("Release"), "Release",
-                             MetaIndexURI("Release.gpg"), MetaIndexInfo("Release.gpg"), "Release.gpg",
-                             ComputeIndexTargets(),
-                             iR);
+   vector <IndexTarget *> const * const targets = ComputeIndexTargets();
+#define APT_TARGET(X) IndexTarget("", X, MetaIndexInfo(X), MetaIndexURI(X))
+   pkgAcqMetaBase * const TransactionManager = new pkgAcqMetaClearSig(Owner,
+	 APT_TARGET("InRelease"), APT_TARGET("Release"), APT_TARGET("Release.gpg"),
+	 targets, iR);
+#undef APT_TARGET
+   if (GetAll)
+   {
+      for (vector <IndexTarget*>::const_iterator Target = targets->begin(); Target != targets->end(); ++Target)
+	 new pkgAcqIndex(Owner, TransactionManager, *Target);
    }
-   if (tryInRelease == true)
-      new pkgAcqMetaClearSig(Owner, 
-            MetaIndexURI("InRelease"), MetaIndexInfo("InRelease"), "InRelease",
-	    MetaIndexURI("Release"), MetaIndexInfo("Release"), "Release",
-	    MetaIndexURI("Release.gpg"), MetaIndexInfo("Release.gpg"), "Release.gpg",
-	    ComputeIndexTargets(),
-	    iR);
-   else
-      new pkgAcqMetaIndex(Owner, NULL,
-          MetaIndexURI("Release"), MetaIndexInfo("Release"), "Release",
-          MetaIndexURI("Release.gpg"), MetaIndexInfo("Release.gpg"), "Release.gpg",
-          ComputeIndexTargets(),
-          iR);
 
    return true;
 }

+ 1 - 1
apt-pkg/indexrecords.cc

@@ -73,7 +73,7 @@ APT_PURE indexRecords::checkSum *indexRecords::Lookup(const string MetaKey)
 
 APT_PURE bool indexRecords::Exists(string const &MetaKey) const
 {
-   return Entries.count(MetaKey) == 1;
+   return Entries.find(MetaKey) != Entries.end();
 }
 
 bool indexRecords::Load(const string Filename)				/*{{{*/

+ 6 - 1
apt-pkg/pkgcache.h

@@ -190,7 +190,12 @@ class pkgCache								/*{{{*/
    struct Flag
    {
       enum PkgFlags {Auto=(1<<0),Essential=(1<<3),Important=(1<<4)};
-      enum PkgFFlags {NotSource=(1<<0),NotAutomatic=(1<<1),ButAutomaticUpgrades=(1<<2)};
+      enum PkgFFlags {
+	 NotSource=(1<<0), /*!< packages can't be fetched from here, e.g. dpkg/status file */
+	 NotAutomatic=(1<<1), /*!< archive has a default pin of 1 */
+	 ButAutomaticUpgrades=(1<<2), /*!< (together with the previous) archive has a default pin of 100 */
+	 LocalSource=(1<<3), /*!< local sources can't and will not be verified by hashes */
+      };
    };
    
    protected:

+ 5 - 1
methods/file.cc

@@ -57,7 +57,11 @@ bool FileMethod::Fetch(FetchItem *Itm)
       Res.LastModified = Buf.st_mtime;
       Res.IMSHit = false;
       if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0)
-	 Res.IMSHit = true;
+      {
+	 unsigned long long const filesize = Itm->ExpectedHashes.FileSize();
+	 if (filesize != 0 && filesize == Res.Size)
+	    Res.IMSHit = true;
+      }
    }
 
    // See if the uncompressed file exists and reuse it

+ 1 - 1
test/integration/test-apt-get-source-authenticated

@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # Regression test for debian bug #749795. Ensure that we fail with
-# a error if apt-get source foo will download a source that comes
+# an error if apt-get source foo will download a source that comes
 # from a unauthenticated repository
 #
 set -e

+ 27 - 28
test/integration/test-apt-sources-deb822

@@ -23,46 +23,45 @@ Description: summay
 
 msgtest 'Test sources.list' 'old style'
 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 
-'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.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 " aptget update --print-uris
 
 msgtest 'Test sources.list' 'simple deb822'
 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 
-'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris
-
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.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 " aptget update --print-uris
 
 msgtest 'Test deb822 with' 'two entries'
 # Two entries
 echo "$BASE" > $SOURCES
 echo "" >> $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 
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.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/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
+'http://ftp.debian.org/debian/dists/unstable/InRelease' ftp.debian.org_debian_dists_unstable_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/InRelease' ftp.debian.org_debian_dists_unstable_InRelease 0 "  aptget update --print-uris
+'http://ftp.debian.org/debian/dists/unstable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_unstable_main_i18n_Translation-en 0 " aptget update --print-uris
 
 # two suite entries
 msgtest 'Test deb822 with' 'two Suite entries'
 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 
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.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/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
+'http://ftp.debian.org/debian/dists/unstable/InRelease' ftp.debian.org_debian_dists_unstable_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/InRelease' ftp.debian.org_debian_dists_unstable_InRelease 0 "  aptget update --print-uris 
+'http://ftp.debian.org/debian/dists/unstable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_unstable_main_i18n_Translation-en 0 " aptget update --print-uris
 
 msgtest 'Test deb822' 'architecture option'
 echo "$BASE" > $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 
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
+'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/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris
 
 
 msgtest 'Test old-style sources.list file which has' 'malformed dist'
@@ -85,20 +84,20 @@ testempty aptget update --print-uris
 # multiple URIs
 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
-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 
+testequal --nomsg  "'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/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.debian.org/debian/dists/stable/InRelease' ftp.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/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 "  aptget update --print-uris 
+'http://ftp.debian.org/debian/dists/stable/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris
 
 # multiple Type in one field
 msgtest 'Test deb822 sources.list file which has' 'Multiple Types work'
 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 
+testequal --nomsg "'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0 
+'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/main/i18n/Translation-en.bz2' ftp.debian.org_debian_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris
 
 # a Suite
 msgtest 'Test deb822 sources.list file which has' 'a exact path and no sections'
@@ -107,6 +106,6 @@ Types: deb
 URIs: http://emacs.naquadah.org
 Suites: stable/
 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 
-'http://emacs.naquadah.org/stable/InRelease' emacs.naquadah.org_stable_InRelease 0 "  aptget update --print-uris 
+testequal --nomsg "'http://emacs.naquadah.org/stable/InRelease' emacs.naquadah.org_stable_InRelease 0 
+'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 " aptget update --print-uris

+ 1 - 1
test/integration/test-apt-update-expected-size

@@ -35,7 +35,7 @@ test_packagestoobig() {
 	done
 	NEW_SIZE="$(stat --printf=%s aptarchive/dists/unstable/main/binary-i386/Packages)"
 	testfailuremsg "W: Failed to fetch ${1}/dists/unstable/main/binary-i386/Packages  Writing more data than expected ($NEW_SIZE > $SIZE)
-E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -o Debug::pkgAcquire::Worker=0 -o Debug::Acquire::Transaction=0
+E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::Transaction=0
 }
 
 methodtest() {

+ 4 - 0
test/integration/test-apt-update-file

@@ -22,6 +22,10 @@ addtrap 'prefix' 'chmod 750 aptarchive/dists/unstable/main/binary-amd64;'
 chmod 550 aptarchive/dists/unstable/main/binary-amd64
 
 testsuccess aptget update
+
+# the release files aren't an IMS-hit, but the indexes are
+redatereleasefiles '+1 hour'
+
 testsuccess aptget update -o Debug::pkgAcquire::Auth=1
 cp -a rootdir/tmp/testsuccess.output rootdir/tmp/update.output
 

+ 6 - 5
test/integration/test-apt-update-nofallback

@@ -28,6 +28,7 @@ Description: an autogenerated evil package
 EOF
     # avoid ims hit
     touch -d '+1hour' aptarchive/dists/unstable/main/binary-i386/Packages
+    compressfile aptarchive/dists/unstable/main/binary-i386/Packages
 }
 
 assert_update_is_refused_and_last_good_state_used()
@@ -87,16 +88,16 @@ test_from_inrelease_to_unsigned_with_override()
 {
     # setup archive with InRelease file
     setupaptarchive_with_lists_clean
-    # FIXME: is not what the server reported 4104 4106
-    testsuccess aptget update #-o Debug::pkgAcquire::Worker=1
+    testsuccess aptget update
 
     # simulate moving to a unsigned but otherwise valid repo
     simulate_mitm_and_inject_evil_package
-    generatereleasefiles
+    generatereleasefiles '+2 hours'
+    find $APTARCHIVE -name '*Packages*' -exec touch -d '+2 hours' {} \;
 
     # and ensure we can update to it (with enough force) 
     testwarning aptget update --allow-insecure-repositories \
-        -o Acquire::AllowDowngradeToInsecureRepositories=1
+        -o Acquire::AllowDowngradeToInsecureRepositories=1 -o Debug::pkgAcquire::Worker=1 -o Debug::pkgAcquire::Auth=1
     # but that the individual packages are still considered untrusted
     testfailureequal "WARNING: The following packages cannot be authenticated!
   evil
@@ -167,7 +168,7 @@ test_inrelease_to_invalid_inrelease()
     listcurrentlistsdirectory > lists.before
 
     # now remove InRelease and subvert Release do no longer verify
-    sed -i 's/Codename.*/Codename: evil!'/ $APTARCHIVE/dists/unstable/InRelease
+    sed -i 's/^Codename:.*/Codename: evil!/' $APTARCHIVE/dists/unstable/InRelease
     inject_evil_package
 
     testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file: unstable InRelease: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>

+ 28 - 2
test/integration/test-apt-update-not-modified

@@ -43,7 +43,9 @@ Version: 1
 EOF
 	compressfile aptarchive/dists/unstable/main/binary-amd64/Packages
 	testfailureequal "Hit $1 unstable InRelease
-Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists.good/unstable/main/binary-amd64/Packages.gz') B]
+Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B]
+Err $1 unstable/main amd64 Packages
+  Hash Sum mismatch
 W: Failed to fetch $1/dists/unstable/main/binary-amd64/Packages.gz  Hash Sum mismatch
 
 E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update
@@ -87,8 +89,32 @@ Hit $1 unstable Release
 Reading package lists..." aptget update
 	testfileequal 'listsdir-without-amd64.lst' "$(listcurrentlistsdirectory)"
 
-	# readd arch so its downloaded again
+	# readd arch so its downloaded again
 	configarchitecture 'amd64' 'i386'
+	# … but oh noes, hashsum mismatch!
+	find aptarchive/dists/unstable/main/binary-amd64/ -type f -delete
+	cat >> aptarchive/dists/unstable/main/binary-amd64/Packages <<EOF
+
+Package: thisisbad
+Architecture: amd64
+Version: 1
+EOF
+	compressfile aptarchive/dists/unstable/main/binary-amd64/Packages
+	testfailureequal "Ign $1 unstable InRelease
+  404  Not Found
+Hit $1 unstable Release
+Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B]
+Err $1 unstable/main amd64 Packages
+  Hash Sum mismatch
+W: Failed to fetch $1/dists/unstable/main/binary-amd64/Packages.gz  Hash Sum mismatch
+
+E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update
+	testfileequal 'listsdir-without-amd64.lst' "$(listcurrentlistsdirectory)"
+	rm -rf aptarchive/dists
+	cp -a aptarchive/dists.good aptarchive/dists
+	find aptarchive/dists -name 'InRelease' -delete
+
+	# … now everything is fine again
 	testsuccessequal "Ign $1 unstable InRelease
   404  Not Found
 Hit $1 unstable Release

+ 4 - 5
test/integration/test-apt-update-stale

@@ -18,7 +18,7 @@ setupaptarchive --no-update
 changetowebserver
 
 echo "Acquire::Languages \"none\";" > rootdir/etc/apt/apt.conf.d/00nolanguages
-testsuccess aptget update
+testsuccess aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::http=1
 listcurrentlistsdirectory > lists.before
 
 # insert new version
@@ -26,7 +26,7 @@ mkdir aptarchive/dists/unstable/main/binary-i386/saved
 cp -p aptarchive/dists/unstable/main/binary-i386/Packages* \
      aptarchive/dists/unstable/main/binary-i386/saved
 insertpackage 'unstable' 'foo' 'all' '2.0'
-
+touch -d '+1 hour' aptarchive/dists/unstable/main/binary-i386/Packages
 compressfile aptarchive/dists/unstable/main/binary-i386/Packages
 # ensure that we do not get a I-M-S hit for the Release file
 
@@ -39,7 +39,6 @@ cp -p aptarchive/dists/unstable/main/binary-i386/saved/Packages* \
      aptarchive/dists/unstable/main/binary-i386/
 
 # ensure this raises an error
-testfailureequal "W: Failed to fetch http://localhost:8080/dists/unstable/main/binary-i386/Packages  Hash Sum mismatch
-
-E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq
+testfailuremsg "W: Failed to fetch copy:$(readlink -f ./rootdir)/var/lib/apt/lists/localhost:8080_dists_unstable_main_binary-i386_Packages  Hash Sum mismatch
+E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::http=1
 testfileequal lists.before "$(listcurrentlistsdirectory)"

+ 1 - 1
test/integration/test-bug-595691-empty-and-broken-archive-files

@@ -12,7 +12,7 @@ setupflataptarchive
 
 testaptgetupdate() {
 	rm -rf rootdir/var/lib/apt
-	aptget update 2>> testaptgetupdate.diff >> testaptgetupdate.diff || true
+	aptget update >testaptgetupdate.diff 2>&1 || true
 	sed -i -e '/Ign /,+1d' -e '/Release/ d' -e 's#Get:[0-9]\+ #Get: #' -e 's#\[[0-9]* [kMGTPY]*B\]#\[\]#' testaptgetupdate.diff
 	GIVEN="$1"
 	shift

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

@@ -176,7 +176,11 @@ testmismatch() {
 Building dependency tree...
 Need to get 6 B of source archives.
 Get:1 http://localhost:8080/  $1 1.0 (dsc) [3 B]
+Err http://localhost:8080/  $1 1.0 (dsc)
+  Hash Sum mismatch
 Get:2 http://localhost:8080/  $1 1.0 (tar) [3 B]
+Err http://localhost:8080/  $1 1.0 (tar)
+  Hash Sum mismatch
 E: Failed to fetch http://localhost:8080/${1}_1.0.dsc  Hash Sum mismatch
 
 E: Failed to fetch http://localhost:8080/${1}_1.0.tar.gz  Hash Sum mismatch
@@ -238,6 +242,8 @@ Building dependency tree...
 Need to get 6 B of source archives.
 Get:1 http://localhost:8080/  pkg-mixed-sha1-bad 1.0 (tar) [3 B]
 Get:2 http://localhost:8080/  pkg-mixed-sha1-bad 1.0 (dsc) [3 B]
+Err http://localhost:8080/  pkg-mixed-sha1-bad 1.0 (dsc)
+  Hash Sum mismatch
 E: Failed to fetch http://localhost:8080/pkg-mixed-sha1-bad_1.0.dsc  Hash Sum mismatch
 
 E: Failed to fetch some archives.' aptget source -d pkg-mixed-sha1-bad
@@ -247,6 +253,8 @@ testfailureequal 'Reading package lists...
 Building dependency tree...
 Need to get 6 B of source archives.
 Get:1 http://localhost:8080/  pkg-mixed-sha2-bad 1.0 (tar) [3 B]
+Err http://localhost:8080/  pkg-mixed-sha2-bad 1.0 (tar)
+  Hash Sum mismatch
 Get:2 http://localhost:8080/  pkg-mixed-sha2-bad 1.0 (dsc) [3 B]
 E: Failed to fetch http://localhost:8080/pkg-mixed-sha2-bad_1.0.tar.gz  Hash Sum mismatch
 

+ 4 - 2
test/libapt/acqprogress_test.cc

@@ -1,4 +1,5 @@
 #include <config.h>
+#include <apt-pkg/hashes.h>
 #include <apt-pkg/acquire.h>
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/configuration.h>
@@ -10,9 +11,10 @@
 class TestItem: public pkgAcquire::Item
 {
 public:
-   TestItem(pkgAcquire * const Acq) : pkgAcquire::Item(Acq, "", NULL) {}
+   TestItem(pkgAcquire * const Acq) : pkgAcquire::Item(Acq) {}
 
-   virtual std::string DescURI() { return ""; }
+   virtual std::string DescURI() const { return ""; }
+   virtual HashStringList GetExpectedHashes() const { return HashStringList(); }
 
 };
 

+ 3 - 0
test/libapt/hashsums_test.cc

@@ -306,6 +306,7 @@ TEST(HashSumsTest, HashStringList)
    EXPECT_EQ(NULL, list.find(NULL));
    EXPECT_EQ(NULL, list.find(""));
    EXPECT_EQ(NULL, list.find("MD5Sum"));
+   EXPECT_EQ(0, list.FileSize());
 
    // empty lists aren't equal
    HashStringList list2;
@@ -316,6 +317,8 @@ TEST(HashSumsTest, HashStringList)
    list.push_back(HashString("Checksum-FileSize", "29"));
    EXPECT_FALSE(list.empty());
    EXPECT_FALSE(list.usable());
+   EXPECT_EQ(1, list.size());
+   EXPECT_EQ(29, list.FileSize());
 
    Hashes hashes;
    hashes.Add("The quick brown fox jumps over the lazy dog");