]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/acquire-item.cc
require $(HASH)-Download field in .diff/Index files
[apt.git] / apt-pkg / acquire-item.cc
index 2057b728781213b2e66c227a0694d3e7312d9a4e..45f8cb76cfb6e13d7acfe0601720d0dc2cc24a1e 100644 (file)
 #include <stdio.h>
 #include <ctime>
 #include <sstream>
+#include <numeric>
 
 #include <apti18n.h>
                                                                        /*}}}*/
 
 using namespace std;
 
-static void printHashSumComparision(std::string const &URI, HashStringList const &Expected, HashStringList const &Actual) /*{{{*/
+static void printHashSumComparison(std::string const &URI, HashStringList const &Expected, HashStringList const &Actual) /*{{{*/
 {
    if (_config->FindB("Debug::Acquire::HashSumMismatch", false) == false)
       return;
@@ -205,12 +206,12 @@ HashStringList pkgAcqMetaBase::GetExpectedHashes() const
 
 APT_CONST bool pkgAcqIndexDiffs::HashesRequired() const
 {
-   /* We don't always have the diff of the downloaded pdiff file.
-      What we have for sure is hashes for the uncompressed file,
-      but rred uncompresses them on the fly while parsing, so not handled here.
-      Hashes are (also) checked while searching for (next) patch to apply. */
+   /* We can't check hashes of rred result as we don't know what the
+      hash of the file will be. We just know the hash of the patch(es),
+      the hash of the file they will apply on and the hash of the resulting
+      file. */
    if (State == StateFetchDiff)
-      return available_patches[0].download_hashes.empty() == false;
+      return true;
    return false;
 }
 HashStringList pkgAcqIndexDiffs::GetExpectedHashes() const
@@ -226,7 +227,7 @@ APT_CONST bool pkgAcqIndexMergeDiffs::HashesRequired() const
       we can check the rred result after all patches are applied as
       we know the expected result rather than potentially apply more patches */
    if (State == StateFetchDiff)
-      return patch.download_hashes.empty() == false;
+      return true;
    return State == StateApplyDiff;
 }
 HashStringList pkgAcqIndexMergeDiffs::GetExpectedHashes() const
@@ -1820,7 +1821,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/
       if (Debug == true)
       {
         std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl;
-         printHashSumComparision(CurrentPackagesFile, ServerHashes, TargetFileHashes);
+         printHashSumComparison(CurrentPackagesFile, ServerHashes, TargetFileHashes);
       }
       return false;
    }
@@ -2021,6 +2022,17 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile)        /*{{{*/
       return false;
    }
 
+   for (auto const &patch: available_patches)
+      if (patch.result_hashes.usable() == false ||
+           patch.patch_hashes.usable() == false ||
+           patch.download_hashes.usable() == false)
+      {
+        if (Debug)
+           std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": provides no usable hashes for " << patch.file
+              << " so fallback to complete download" << std::endl;
+        return false;
+      }
+
    // patching with too many files is rather slow compared to a fast download
    unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
    if (fileLimit != 0 && fileLimit < available_patches.size())
@@ -2035,7 +2047,6 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/
    unsigned short const sizeLimitPercent = _config->FindI("Acquire::PDiffs::SizeLimit", 100);
    if (sizeLimitPercent > 0 && TransactionManager->MetaIndexParser != nullptr)
    {
-      // compressed case
       unsigned long long downloadSize = std::accumulate(available_patches.begin(),
            available_patches.end(), 0llu, [](unsigned long long const T, DiffInfo const &I) {
            return T + I.download_hashes.FileSize();
@@ -2064,23 +2075,6 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile)        /*{{{*/
            return false;
         }
       }
-      // uncompressed case
-      downloadSize = std::accumulate(available_patches.begin(),
-           available_patches.end(), 0llu, [](unsigned long long const T, DiffInfo const &I) {
-           return T + I.patch_hashes.FileSize();
-           });
-      if (downloadSize != 0)
-      {
-        unsigned long long const downloadSizeIdx = ServerSize;
-        unsigned long long const sizeLimit = downloadSizeIdx * sizeLimitPercent;
-        if ((sizeLimit/100) < downloadSize)
-        {
-           if (Debug)
-              std::clog << "Need " << downloadSize << " uncompressed bytes (Limit is " << (sizeLimit/100) << ", "
-                 << "original is " << downloadSizeIdx << ") so fallback to complete download" << std::endl;
-           return false;
-        }
-      }
    }
 
    // we have something, queue the diffs
@@ -2475,8 +2469,21 @@ void pkgAcqIndexMergeDiffs::Done(string const &Message, HashStringList const &Ha
 
    Item::Done(Message, Hashes, Cnf);
 
+   if (std::any_of(allPatches->begin(), allPatches->end(),
+           [](pkgAcqIndexMergeDiffs const * const P) { return P->State == StateErrorDiff; }))
+   {
+      if(Debug)
+        std::clog << "Another patch failed already, no point in processing this one." << std::endl;
+      return;
+   }
+
    std::string const UncompressedUnpatchedFile = GetPartialFileNameFromURI(Target.URI);
    std::string const UnpatchedFile = GetExistingFilename(UncompressedUnpatchedFile);
+   if (UnpatchedFile.empty())
+   {
+      _error->Fatal("Unpatched file %s doesn't exist (anymore)!", UnpatchedFile.c_str());
+      return;
+   }
    std::string const PatchFile = GetMergeDiffsPatchFileName(UnpatchedFile, patch.file);
    std::string const PatchedFile = GetKeepCompressedFileName(UncompressedUnpatchedFile, Target);
 
@@ -3076,9 +3083,14 @@ std::string pkgAcqArchive::ShortDesc() const                             /*{{{*/
 pkgAcqArchive::~pkgAcqArchive() {}
 
 // AcqChangelog::pkgAcqChangelog - Constructors                                /*{{{*/
+class pkgAcqChangelog::Private
+{
+   public:
+   std::string FinalFile;
+};
 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::VerIterator const &Ver,
       std::string const &DestDir, std::string const &DestFilename) :
-   pkgAcquire::Item(Owner), d(NULL), SrcName(Ver.SourcePkgName()), SrcVersion(Ver.SourceVerStr())
+   pkgAcquire::Item(Owner), d(new pkgAcqChangelog::Private()), SrcName(Ver.SourcePkgName()), SrcVersion(Ver.SourceVerStr())
 {
    Desc.URI = URI(Ver);
    Init(DestDir, DestFilename);
@@ -3087,7 +3099,7 @@ pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::VerIterator
 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::RlsFileIterator const &RlsFile,
       char const * const Component, char const * const SrcName, char const * const SrcVersion,
       const string &DestDir, const string &DestFilename) :
-   pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
+   pkgAcquire::Item(Owner), d(new pkgAcqChangelog::Private()), SrcName(SrcName), SrcVersion(SrcVersion)
 {
    Desc.URI = URI(RlsFile, Component, SrcName, SrcVersion);
    Init(DestDir, DestFilename);
@@ -3095,7 +3107,7 @@ pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::RlsFileIter
 pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner,
       std::string const &URI, char const * const SrcName, char const * const SrcVersion,
       const string &DestDir, const string &DestFilename) :
-   pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
+   pkgAcquire::Item(Owner), d(new pkgAcqChangelog::Private()), SrcName(SrcName), SrcVersion(SrcVersion)
 {
    Desc.URI = URI;
    Init(DestDir, DestFilename);
@@ -3116,30 +3128,44 @@ void pkgAcqChangelog::Init(std::string const &DestDir, std::string const &DestFi
       return;
    }
 
-   if (DestDir.empty())
+   std::string DestFileName;
+   if (DestFilename.empty())
+      DestFileName = flCombine(DestFile, SrcName + ".changelog");
+   else
+      DestFileName = flCombine(DestFile, DestFilename);
+
+   std::string const SandboxUser = _config->Find("APT::Sandbox::User");
+   std::string const systemTemp = GetTempDir(SandboxUser);
+   char tmpname[1000];
+   snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", systemTemp.c_str());
+   if (NULL == mkdtemp(tmpname))
+   {
+      _error->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName.c_str(), SrcVersion.c_str());
+      Status = StatError;
+      return;
+   }
+   TemporaryDirectory = tmpname;
+
+   ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory.c_str(),
+        SandboxUser.c_str(), "root", 0700);
+
+   DestFile = flCombine(TemporaryDirectory, DestFileName);
+   if (DestDir.empty() == false)
    {
-      std::string const SandboxUser = _config->Find("APT::Sandbox::User");
-      std::string const systemTemp = GetTempDir(SandboxUser);
-      char tmpname[100];
-      snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", systemTemp.c_str());
-      if (NULL == mkdtemp(tmpname))
+      d->FinalFile = flCombine(DestDir, DestFileName);
+      if (RealFileExists(d->FinalFile))
       {
-        _error->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName.c_str(), SrcVersion.c_str());
-        Status = StatError;
-        return;
+        FileFd file1, file2;
+        if (file1.Open(DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Exclusive) &&
+              file2.Open(d->FinalFile, FileFd::ReadOnly) && CopyFile(file2, file1))
+        {
+           struct timeval times[2];
+           times[0].tv_sec = times[1].tv_sec = file2.ModificationTime();
+           times[0].tv_usec = times[1].tv_usec = 0;
+           utimes(DestFile.c_str(), times);
+        }
       }
-      DestFile = TemporaryDirectory = tmpname;
-
-      ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile.c_str(),
-                                     SandboxUser.c_str(), "root", 0700);
    }
-   else
-      DestFile = DestDir;
-
-   if (DestFilename.empty())
-      DestFile = flCombine(DestFile, SrcName + ".changelog");
-   else
-      DestFile = flCombine(DestFile, DestFilename);
 
    Desc.ShortDesc = "Changelog";
    strprintf(Desc.Description, "%s %s %s Changelog", URI::SiteOnly(Desc.URI).c_str(), SrcName.c_str(), SrcVersion.c_str());
@@ -3286,7 +3312,6 @@ void pkgAcqChangelog::Failed(string const &Message, pkgAcquire::MethodConfig con
       ErrorText = errText;
    else
       ErrorText = errText + " (" + ErrorText + ")";
-   return;
 }
                                                                        /*}}}*/
 // AcqChangelog::Done - Item downloaded OK                             /*{{{*/
@@ -3294,6 +3319,12 @@ void pkgAcqChangelog::Done(string const &Message,HashStringList const &CalcHashe
                      pkgAcquire::MethodConfig const * const Cnf)
 {
    Item::Done(Message,CalcHashes,Cnf);
+   if (d->FinalFile.empty() == false)
+   {
+      if (RemoveFile("pkgAcqChangelog::Done", d->FinalFile) == false ||
+           Rename(DestFile, d->FinalFile) == false)
+        Status = StatError;
+   }
 
    Complete = true;
 }
@@ -3305,6 +3336,7 @@ pkgAcqChangelog::~pkgAcqChangelog()                                       /*{{{*/
       RemoveFile("~pkgAcqChangelog", DestFile);
       rmdir(TemporaryDirectory.c_str());
    }
+   delete d;
 }
                                                                        /*}}}*/