]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/acquire-item.cc
* merge patch that enforces stricter https server certificate
[apt.git] / apt-pkg / acquire-item.cc
index f3784a58bc9d2e9dce1963b8d360fd3ed360378a..aee1872273dafb472449ad821f52aa281d9cf817 100644 (file)
@@ -63,6 +63,7 @@ void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 {
    Status = StatIdle;
    ErrorText = LookupTag(Message,"Message");
+   UsedMirror =  LookupTag(Message,"UsedMirror");
    if (QueueCounter <= 1)
    {
       /* This indicates that the file is not available right now but might
@@ -75,10 +76,17 @@ void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
         Dequeue();
         return;
       }
-      
+
       Status = StatError;
       Dequeue();
    }   
+   
+   // report mirror failure back to LP if we actually use a mirror
+   string FailReason = LookupTag(Message, "FailReason");
+   if(FailReason.size() != 0)
+      ReportMirrorFailure(FailReason);
+   else
+      ReportMirrorFailure(ErrorText);
 }
                                                                        /*}}}*/
 // Acquire::Item::Start - Item has begun to download                   /*{{{*/
@@ -100,7 +108,7 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash,
 {
    // We just downloaded something..
    string FileName = LookupTag(Message,"Filename");
-   // we only inform the Log class if it was actually not a local thing
+   UsedMirror =  LookupTag(Message,"UsedMirror");
    if (Complete == false && !Local && FileName == DestFile)
    {
       if (Owner->Log != 0)
@@ -109,7 +117,6 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash,
 
    if (FileSize == 0)
       FileSize= Size;
-   
    Status = StatDone;
    ErrorText = string();
    Owner->Dequeue(this);
@@ -132,6 +139,49 @@ void pkgAcquire::Item::Rename(string From,string To)
 }
                                                                        /*}}}*/
 
+void pkgAcquire::Item::ReportMirrorFailure(string FailCode)
+{
+   // we only act if a mirror was used at all
+   if(UsedMirror.empty())
+      return;
+#if 0
+   std::cerr << "\nReportMirrorFailure: " 
+            << UsedMirror
+            << " Uri: " << DescURI()
+            << " FailCode: " 
+            << FailCode << std::endl;
+#endif
+   const char *Args[40];
+   unsigned int i = 0;
+   string report = _config->Find("Methods::Mirror::ProblemReporting", 
+                                "/usr/lib/apt/apt-report-mirror-failure");
+   if(!FileExists(report))
+      return;
+   Args[i++] = report.c_str();
+   Args[i++] = UsedMirror.c_str();
+   Args[i++] = DescURI().c_str();
+   Args[i++] = FailCode.c_str();
+   Args[i++] = NULL;
+   pid_t pid = ExecFork();
+   if(pid < 0) 
+   {
+      _error->Error("ReportMirrorFailure Fork failed");
+      return;
+   }
+   else if(pid == 0) 
+   {
+      execvp(Args[0], (char**)Args);
+      std::cerr << "Could not exec " << Args[0] << std::endl;
+      _exit(100);
+   }
+   if(!ExecWait(pid, "report-mirror-failure")) 
+   {
+      _error->Warning("Couldn't report problem to '%s'",
+                     _config->Find("Methods::Mirror::ProblemReporting").c_str());
+   }
+}
+
+
 
 // AcqDiffIndex::AcqDiffIndex - Constructor                    
 // ---------------------------------------------------------------------
@@ -345,7 +395,7 @@ void pkgAcqDiffIndex::Done(string Message,unsigned long Size,string Md5Hash,
  */
 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
                                   string URI,string URIDesc,string ShortDesc,
-                                  HashString ExpectedMD5
+                                  HashString ExpectedHash
                                   vector<DiffInfo> diffs)
    : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), 
      available_patches(diffs)
@@ -590,7 +640,6 @@ string pkgAcqIndex::Custom600Headers()
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) != 0)
       return "\nIndex-File: true";
-   
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }
                                                                        /*}}}*/
@@ -646,6 +695,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash,
          Status = StatAuthError;
          ErrorText = _("Hash Sum mismatch");
          Rename(DestFile,DestFile + ".FAILED");
+        ReportMirrorFailure("HashChecksumFailure");
          return;
       }
       // Done, move it into position
@@ -674,10 +724,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash,
    {
       // The files timestamp matches
       if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
-      {
-        unlink(FileName.c_str());
         return;
-      }
       Decompression = true;
       Local = true;
       DestFile += ".decomp";
@@ -696,10 +743,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash,
    
    // The files timestamp matches
    if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
-   {
-      unlink(FileName.c_str());
       return;
-   }
 
    if (FileName == DestFile)
       Erase = true;
@@ -707,7 +751,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash,
       Local = true;
    
    string compExt = Desc.URI.substr(Desc.URI.size()-3);
-   char *decompProg;
+   const char *decompProg;
    if(compExt == "bz2") 
       decompProg = "bzip2";
    else if(compExt == ".gz") 
@@ -776,16 +820,19 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
    Desc.Owner = this;
    Desc.ShortDesc = ShortDesc;
    Desc.URI = URI;
-   
       
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) == 0)
    {
-      // File was already in place.  It needs to be re-verified
-      // because Release might have changed, so Move it into partial
-      Rename(Final,DestFile);
+      // File was already in place.  It needs to be re-downloaded/verified
+      // because Release might have changed, we do give it a differnt
+      // name than DestFile because otherwise the http method will
+      // send If-Range requests and there are too many broken servers
+      // out there that do not understand them
+      LastGoodSig = DestFile+".reverify";
+      Rename(Final,LastGoodSig);
    }
 
    QueueURI(Desc);
@@ -797,7 +844,7 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
 string pkgAcqMetaSig::Custom600Headers()
 {
    struct stat Buf;
-   if (stat(DestFile.c_str(),&Buf) != 0)
+   if (stat(LastGoodSig.c_str(),&Buf) != 0)
       return "\nIndex-File: true";
 
    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
@@ -827,9 +874,16 @@ void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5,
 
    Complete = true;
 
+   // put the last known good file back on i-m-s hit (it will
+   // be re-verified again)
+   // Else do nothing, we have the new file in DestFile then
+   if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+      Rename(LastGoodSig, DestFile);
+
    // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
-   new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
-                      DestFile, IndexTargets, MetaIndexParser);
+   new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, 
+                      MetaIndexShortDesc,  DestFile, IndexTargets, 
+                      MetaIndexParser);
 
 }
                                                                        /*}}}*/
@@ -842,8 +896,8 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
    {
       Item::Failed(Message,Cnf);
       // move the sigfile back on transient network failures 
-      if(FileExists(DestFile))
-        Rename(DestFile,Final);
+      if(FileExists(LastGoodSig))
+        Rename(LastGoodSig,Final);
 
       // set the status back to , Item::Failed likes to reset it
       Status = pkgAcquire::Item::StatTransientNetworkError;
@@ -918,6 +972,15 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string Hash,
    if (AuthPass == true)
    {
       AuthDone(Message);
+
+      // all cool, move Release file into place
+      Complete = true;
+
+      string FinalFile = _config->FindDir("Dir::State::lists");
+      FinalFile += URItoFileName(RealURI);
+      Rename(DestFile,FinalFile);
+      chmod(FinalFile.c_str(),0644);
+      DestFile = FinalFile;
    }
    else
    {
@@ -969,22 +1032,15 @@ void pkgAcqMetaIndex::RetrievalDone(string Message)
       return;
    }
 
-   // see if the download was a IMSHit
+   // make sure to verify against the right file on I-M-S hit
    IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
+   if(IMSHit)
+   {
+      string FinalFile = _config->FindDir("Dir::State::lists");
+      FinalFile += URItoFileName(RealURI);
+      DestFile = FinalFile;
+   }
    Complete = true;
-
-   string FinalFile = _config->FindDir("Dir::State::lists");
-   FinalFile += URItoFileName(RealURI);
-
-   // If we get a IMS hit we can remove the empty file in partial
-   // othersie we move the file in place
-   if (IMSHit)
-      unlink(DestFile.c_str());
-   else
-      Rename(DestFile,FinalFile);
-
-   chmod(FinalFile.c_str(),0644);
-   DestFile = FinalFile;
 }
 
 void pkgAcqMetaIndex::AuthDone(string Message)
@@ -1014,7 +1070,6 @@ void pkgAcqMetaIndex::AuthDone(string Message)
    QueueIndexes(true);
 
    // Done, move signature file into position
-
    string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
       URItoFileName(RealURI) + ".gpg";
    Rename(SigFile,VerifiedSigFile);
@@ -1055,7 +1110,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)
       
       // Queue Packages file (either diff or full packages files, depending
       // on the users option)
-      if(_config->FindB("Acquire::PDiffs",true) == true) 
+      if(_config->FindB("Acquire::PDiffs",false) == true) 
         new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
                             (*Target)->ShortDesc, ExpectedIndexHash);
       else 
@@ -1159,30 +1214,30 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 {
    if (AuthPass == true)
    {
-      // if we fail the authentication but got the file via a IMS-Hit 
-      // this means that the file wasn't downloaded and that it might be
-      // just stale (server problem, proxy etc). we delete what we have
-      // queue it again without i-m-s 
-      // alternatively we could just unlink the file and let the user try again
-      if (IMSHit)
+      // gpgv method failed, if we have a good signature 
+      string LastGoodSigFile = _config->FindDir("Dir::State::lists") +
+        "partial/" + URItoFileName(RealURI) + ".gpg.reverify";
+      if(FileExists(LastGoodSigFile))
       {
-        Complete = false;
-        Local = false;
-        AuthPass = false;
-        unlink(DestFile.c_str());
-
-        DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-        DestFile += URItoFileName(RealURI);
-        Desc.URI = RealURI;
-        QueueURI(Desc);
+        string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
+           URItoFileName(RealURI) + ".gpg";
+        Rename(LastGoodSigFile,VerifiedSigFile);
+        Status = StatTransientNetworkError;
+        _error->Warning(_("A error occurred during the signature "
+                          "verification. The repository is not updated "
+                          "and the previous index files will be used."
+                          "GPG error: %s: %s\n"),
+                        Desc.Description.c_str(),
+                        LookupTag(Message,"Message").c_str());
+        RunScripts("APT::Update::Auth-Failure");
         return;
+      } else {
+        _error->Warning(_("GPG error: %s: %s"),
+                        Desc.Description.c_str(),
+                        LookupTag(Message,"Message").c_str());
       }
-
       // gpgv method failed 
-      _error->Warning("GPG error: %s: %s",
-                      Desc.Description.c_str(),
-                      LookupTag(Message,"Message").c_str());
-
+      ReportMirrorFailure("GPGFailure");
    }
 
    // No Release file was present, or verification failed, so fall