]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/acquire-item.cc
Merge remote-tracking branch 'upstream/debian/experimental' into feature/acq-trans
[apt.git] / apt-pkg / acquire-item.cc
index 43c09e7b58f47da2740e671432f6535b560ef7c4..eee1097e918125a1a3e15e3e9c60b9fa25f58ca2 100644 (file)
@@ -376,7 +376,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
    Desc.URI = Target->URI + ".diff/Index";
 
    DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-   DestFile += URItoFileName(Target->URI) + string(".DiffIndex");
+   DestFile += URItoFileName(Desc.URI);
 
    if(Debug)
       std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
@@ -412,7 +412,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
 string pkgAcqDiffIndex::Custom600Headers() const
 {
    string Final = _config->FindDir("Dir::State::lists");
-   Final += URItoFileName(RealURI) + string(".IndexDiff");
+   Final += URItoFileName(Desc.URI);
    
    if(Debug)
       std::clog << "Custom600Header-IMS: " << Final << std::endl;
@@ -676,12 +676,21 @@ void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)
 // Finish - helper that cleans the item out of the fetcher queue       /*{{{*/
 void pkgAcqIndexDiffs::Finish(bool allDone)
 {
+   if(Debug)
+      std::clog << "pkgAcqIndexDiffs::Finish(): " 
+                << allDone << " "
+                << Desc.URI << std::endl;
+
    // we restore the original name, this is required, otherwise
    // the file will be cleaned
    if(allDone) 
    {
       DestFile = _config->FindDir("Dir::State::lists");
       DestFile += URItoFileName(RealURI);
+      
+      // FIXME: we want the rred stuff to use the real transactional update
+      //        this is just a workaround
+      PartialFile = DestFile;
 
       if(HashSums().usable() && !HashSums().VerifyFile(DestFile))
       {
@@ -929,6 +938,8 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri
 
       // otherwise lists cleanup will eat the file
       DestFile = FinalFile;
+      // FIXME: make the merged rred code really transactional
+      PartialFile = FinalFile;
 
       // ensure the ed's are gone regardless of list-cleanup
       for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
@@ -1094,6 +1105,9 @@ string pkgAcqIndex::Custom600Headers() const
    return msg;
 }
                                                                        /*}}}*/
+// pkgAcqIndex::Failed - getting the indexfile failed                  /*{{{*/
+// ---------------------------------------------------------------------
+/* */
 void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
 {
    size_t const nextExt = CompressionExtension.find(' ');
@@ -1117,17 +1131,47 @@ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)  /*{{{*/
    Owner->AbortTransaction(TransactionID);
 }
                                                                        /*}}}*/
+// pkgAcqIndex::GetFinalFilename - Return the full final file path      /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+std::string pkgAcqIndex::GetFinalFilename(std::string const &URI,
+                                          std::string const &compExt)
+{
+   std::string FinalFile = _config->FindDir("Dir::State::lists");
+   FinalFile += URItoFileName(URI);
+   if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
+      FinalFile += ".gz";
+   return FinalFile;
+}
+                                                                       /*}}}*/
+// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit        /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqIndex::ReverifyAfterIMS(std::string const &FileName)
+{
+   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
+   if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
+      DestFile += ".gz";
+
+   // copy FinalFile into partial/ so that we check the hash again
+   string FinalFile = GetFinalFilename(RealURI, compExt);
+   Decompression = true;
+   Desc.URI = "copy:" + FinalFile;
+   QueueURI(Desc);
+}
+                                                                       /*}}}*/
 // AcqIndex::Done - Finished a fetch                                   /*{{{*/
 // ---------------------------------------------------------------------
 /* This goes through a number of states.. On the initial fetch the
    method could possibly return an alternate filename which points
    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 decompressed with a gzip uri. */
+   is decompressed with a compressed uri. */
 void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,
                       pkgAcquire::MethodConfig *Cfg)
 {
    Item::Done(Message,Size,Hashes,Cfg);
+   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
 
    if (Decompression == true)
    {
@@ -1145,9 +1189,10 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
       /* Always verify the index file for correctness (all indexes must
        * have a Package field) (LP: #346386) (Closes: #627642) 
        */
-      FileFd fd(DestFile, FileFd::ReadOnly);
-      // Only test for correctness if the file is not empty (empty is ok)
-      if (fd.FileSize() > 0)
+      FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Extension);
+      // Only test for correctness if the content of the file is not empty
+      // (empty is ok)
+      if (fd.Size() > 0)
       {
          pkgTagSection sec;
          pkgTagFile tag(&fd);
@@ -1161,24 +1206,33 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
          }
       }
        
+      // FIXME: can we void the "Erase" bool here as its very non-local?
+      std::string CompressedFile = _config->FindDir("Dir::State::lists") + "partial/";
+      CompressedFile += URItoFileName(RealURI);
+      // Remove the compressed version.
+      if (Erase == true)
+        unlink(CompressedFile.c_str());
+
       // Done, queue for rename on transaction finished
       PartialFile = DestFile;
+      DestFile = GetFinalFilename(RealURI, compExt);
 
-      string FinalFile = _config->FindDir("Dir::State::lists");
-      FinalFile += URItoFileName(RealURI);
-      DestFile = FinalFile;
-#if 0
-      /* We restore the original name to DestFile so that the clean operation
-         will work OK */
-      DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-      DestFile += URItoFileName(RealURI);
-      
-      // Remove the compressed version.
-      if (Erase == true)
-        unlink(DestFile.c_str());
-#endif
       return;
    }
+   
+   // FIXME: use the same method to find 
+   // check the compressed hash too
+   if(MetaKey != "" && Hashes.size() > 0)
+   {
+      indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
+      if(Record && Record->Hashes.usable() && Hashes != Record->Hashes)
+      {
+         RenameOnError(HashSumMismatch);
+         printHashSumComparision(RealURI, Record->Hashes, Hashes);
+         Failed(Message, Cfg);
+         return;
+      }
+   }
 
    Erase = false;
    Complete = true;
@@ -1189,7 +1243,10 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
    {
       // The files timestamp matches
       if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
+      {
+         ReverifyAfterIMS(FileName);
         return;
+      }
       Decompression = true;
       Local = true;
       DestFile += ".decomp";
@@ -1206,13 +1263,10 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
       ErrorText = "Method gave a blank filename";
    }
 
-   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
-
    // The files timestamp matches
-   if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) {
-       if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
-         // Update DestFile for .gz suffix so that the clean operation keeps it
-         DestFile += ".gz";
+   if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+   {
+      ReverifyAfterIMS(FileName);
       return;
     }
 
@@ -1225,14 +1279,9 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
 
    // If we enable compressed indexes and already have gzip, keep it
    if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) {
-      string FinalFile = _config->FindDir("Dir::State::lists");
-      FinalFile += URItoFileName(RealURI) + ".gz";
-      Rename(DestFile,FinalFile);
-      chmod(FinalFile.c_str(),0644);
-      
-      // Update DestFile for .gz suffix so that the clean operation keeps it
-      DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-      DestFile += URItoFileName(RealURI) + ".gz";
+      // Done, queue for rename on transaction finished
+      PartialFile = DestFile;
+      DestFile = GetFinalFilename(RealURI, compExt);
       return;
     }
 
@@ -1318,13 +1367,56 @@ void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
    Item::Failed(Message,Cnf);
 }
                                                                        /*}}}*/
+
+pkgAcqMetaSigBase::pkgAcqMetaSigBase(pkgAcquire *Owner,
+                                     HashStringList const &ExpectedHashes,
+                                     unsigned long TransactionID)
+   : Item(Owner, ExpectedHashes, TransactionID)
+{
+}
+                                                                       /*{{{*/
+bool pkgAcqMetaSigBase::GenerateAuthWarning(const std::string &RealURI,
+                                            const std::string &Message)
+{
+   string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
+   
+   if(FileExists(Final))
+   {
+      Status = StatTransientNetworkError;
+      _error->Warning(_("An error occurred during the signature "
+                        "verification. The repository is not updated "
+                        "and the previous index files will be used. "
+                        "GPG error: %s: %s\n"),
+                      Desc.Description.c_str(),
+                      LookupTag(Message,"Message").c_str());
+      RunScripts("APT::Update::Auth-Failure");
+      return true;
+   } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
+      /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
+      _error->Error(_("GPG error: %s: %s"),
+                    Desc.Description.c_str(),
+                    LookupTag(Message,"Message").c_str());
+      Status = StatError;
+      return true;
+   } else {
+      _error->Warning(_("GPG error: %s: %s"),
+                      Desc.Description.c_str(),
+                      LookupTag(Message,"Message").c_str());
+   }
+   // gpgv method failed 
+   ReportMirrorFailure("GPGFailure");
+   return false;
+}
+                                                                       /*}}}*/
+
+
 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,                        /*{{{*/
                              unsigned long TransactionID,
                             string URI,string URIDesc,string ShortDesc,
                              string MetaIndexFile,
                             const vector<IndexTarget*>* IndexTargets,
                             indexRecords* MetaIndexParser) :
-   Item(Owner, HashStringList(), TransactionID), RealURI(URI), 
+   pkgAcqMetaSigBase(Owner, HashStringList(), TransactionID), RealURI(URI), 
    MetaIndexParser(MetaIndexParser), MetaIndexFile(MetaIndexFile),
    IndexTargets(IndexTargets), AuthPass(false), IMSHit(false)
 {
@@ -1438,6 +1530,14 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
    DestFile += URItoFileName(RealURI);
    PartialFile = "";
 
+   // FIXME: duplicated code from pkgAcqMetaIndex
+   if (AuthPass == true)
+   {
+      bool Stop = GenerateAuthWarning(RealURI, Message);
+      if(Stop)
+         return;
+   }
+
    // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
    if (Cnf->LocalOnly == true || 
        StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
@@ -1457,7 +1557,7 @@ pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner,                       /*{{{*/
                                  string MetaIndexSigURI,string MetaIndexSigURIDesc, string MetaIndexSigShortDesc,
                                 const vector<IndexTarget*>* IndexTargets,
                                 indexRecords* MetaIndexParser) :
-   Item(Owner, HashStringList(), TransactionID), RealURI(URI), IndexTargets(IndexTargets),
+   pkgAcqMetaSigBase(Owner, HashStringList(), TransactionID), RealURI(URI), IndexTargets(IndexTargets),
    MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false),
    MetaIndexSigURI(MetaIndexSigURI), MetaIndexSigURIDesc(MetaIndexSigURIDesc),
    MetaIndexSigShortDesc(MetaIndexSigShortDesc)
@@ -1534,18 +1634,6 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList
       }
       else
       {
-         // FIXME: move this into pkgAcqMetaClearSig::Done on the next
-         //        ABI break
-
-         // if we expect a ClearTextSignature (InRelase), ensure that
-         // this is what we get and if not fail to queue a 
-         // Release/Release.gpg, see #346386
-         if (SigFile == DestFile && !StartsWithGPGClearTextSignature(DestFile))
-         {
-            Failed(Message, Cfg);
-            return;
-         }
-
          // There was a signature file, so pass it to gpgv for
          // verification
          if (_config->FindB("Debug::pkgAcquire::Auth", false))
@@ -1834,39 +1922,13 @@ bool pkgAcqMetaIndex::VerifyVendor(string Message)                      /*{{{*/
 void pkgAcqMetaIndex::Failed(string Message,
                              pkgAcquire::MethodConfig * /*Cnf*/)
 {
+   string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
+
    if (AuthPass == true)
    {
-      // gpgv method failed, if we have a good signature 
-      string LastGoodSigFile = _config->FindDir("Dir::State::lists");
-      LastGoodSigFile += URItoFileName(RealURI);
-      if (DestFile != SigFile)
-        LastGoodSigFile.append(".gpg");
-
-      if(FileExists(LastGoodSigFile))
-      {
-        Status = StatTransientNetworkError;
-        _error->Warning(_("An error occurred during the signature "
-                          "verification. The repository is not updated "
-                          "and the previous index files will be used. "
-                          "GPG error: %s: %s\n"),
-                        Desc.Description.c_str(),
-                        LookupTag(Message,"Message").c_str());
-        RunScripts("APT::Update::Auth-Failure");
-        return;
-      } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
-        /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
-        _error->Error(_("GPG error: %s: %s"),
-                        Desc.Description.c_str(),
-                        LookupTag(Message,"Message").c_str());
-         Status = StatError;
-        return;
-      } else {
-        _error->Warning(_("GPG error: %s: %s"),
-                        Desc.Description.c_str(),
-                        LookupTag(Message,"Message").c_str());
-      }
-      // gpgv method failed 
-      ReportMirrorFailure("GPGFailure");
+      bool Stop = GenerateAuthWarning(RealURI, Message);
+      if(Stop)
+         return;
    }
 
    /* Always move the meta index, even if gpgv failed. This ensures
@@ -1963,6 +2025,24 @@ string pkgAcqMetaClearSig::Custom600Headers() const
    return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }
                                                                        /*}}}*/
+// pkgAcqMetaClearSig::Done - We got a file                            /*{{{*/
+// ---------------------------------------------------------------------
+void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size, 
+                              HashStringList const &Hashes,
+                              pkgAcquire::MethodConfig *Cnf)
+{
+   // if we expect a ClearTextSignature (InRelase), ensure that
+   // this is what we get and if not fail to queue a 
+   // Release/Release.gpg, see #346386
+   if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
+   {
+      pkgAcquire::Item::Failed(Message, Cnf);
+      ErrorText = _("Does not start with a cleartext signature");
+      return;
+   }
+   pkgAcqMetaIndex::Done(Message, Size, Hashes, Cnf);
+}
+                                                                       /*}}}*/
 void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
 {
    // we failed, we will not get additional items from this method