From 4f51fd8636592a96aecf17c8bf4cfdb3ea2207cc Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 8 Jun 2015 00:06:41 +0200 Subject: support hashes for compressed pdiff files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment we only have hashes for the uncompressed pdiff files, but via the new '$HASH-Download' field in the .diff/Index hashes can be provided for the .gz compressed pdiff file, which apt will pick up now and use to verify the download. Now, we "just" need a buy in from the creators of repositories… --- apt-pkg/acquire-item.cc | 72 +++++++++++++++++++++++++++++++++++++++-------- apt-pkg/acquire-item.h | 11 +++----- apt-pkg/contrib/hashes.cc | 11 ++++++-- apt-pkg/contrib/hashes.h | 7 +++++ apt-pkg/indexrecords.cc | 4 +-- 5 files changed, 80 insertions(+), 25 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 7b69ee993..a3f47242f 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -152,14 +152,18 @@ HashStringList pkgAcqMetaBase::GetExpectedHashes() const APT_CONST bool pkgAcqIndexDiffs::HashesRequired() const { - /* FIXME: We have only hashes for uncompressed pdiffs. - rred uncompresses them on the fly while parsing. - In StateFetchDiff state we also uncompress on the fly for hash check. - Hashes are checked while searching for (next) patch to apply. */ + /* 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. */ + if (State == StateFetchDiff) + return available_patches[0].download_hashes.empty() == false; return false; } HashStringList pkgAcqIndexDiffs::GetExpectedHashes() const { + if (State == StateFetchDiff) + return available_patches[0].download_hashes; return HashStringList(); } @@ -168,11 +172,15 @@ APT_CONST bool pkgAcqIndexMergeDiffs::HashesRequired() const /* @see #pkgAcqIndexDiffs::HashesRequired, with the difference that 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 State == StateApplyDiff; } HashStringList pkgAcqIndexMergeDiffs::GetExpectedHashes() const { - if (State == StateApplyDiff) + if (State == StateFetchDiff) + return patch.download_hashes; + else if (State == StateApplyDiff) return GetExpectedHashesFor(Target->MetaKey); return HashStringList(); } @@ -1618,7 +1626,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/ std::vector::iterator cur = available_patches.begin(); for (; cur != available_patches.end(); ++cur) { - if (cur->file != filename || unlikely(cur->result_size != size)) + if (cur->file != filename) continue; cur->result_hashes.push_back(HashString(*type, hash)); break; @@ -1630,8 +1638,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/ DiffInfo next; next.file = filename; next.result_hashes.push_back(HashString(*type, hash)); - next.result_size = size; - next.patch_size = 0; + next.result_hashes.FileSize(size); available_patches.push_back(next); } else @@ -1679,10 +1686,9 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/ { if (cur->file != filename) continue; - if (unlikely(cur->patch_size != 0 && cur->patch_size != size)) - continue; + if (cur->patch_hashes.empty()) + cur->patch_hashes.FileSize(size); cur->patch_hashes.push_back(HashString(*type, hash)); - cur->patch_size = size; break; } if (cur != available_patches.end()) @@ -1694,6 +1700,48 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/ } } + for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type) + { + std::string tagname = *type; + tagname.append("-Download"); + std::string const tmp = Tags.FindS(tagname.c_str()); + if (tmp.empty() == true) + continue; + + string hash, filename; + unsigned long long size; + std::stringstream ss(tmp); + + // FIXME: all of pdiff supports only .gz compressed patches + while (ss >> hash >> size >> filename) + { + if (unlikely(hash.empty() == true || filename.empty() == true)) + continue; + if (unlikely(APT::String::Endswith(filename, ".gz") == false)) + continue; + filename.erase(filename.length() - 3); + + // see if we have a record for this file already + std::vector::iterator cur = available_patches.begin(); + for (; cur != available_patches.end(); ++cur) + { + if (cur->file != filename) + continue; + if (cur->download_hashes.empty()) + cur->download_hashes.FileSize(size); + cur->download_hashes.push_back(HashString(*type, hash)); + break; + } + if (cur != available_patches.end()) + continue; + if (Debug == true) + std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename + << " wasn't in the list for the first parsed hash! (download)" << std::endl; + break; + } + } + + bool foundStart = false; for (std::vector::iterator cur = available_patches.begin(); cur != available_patches.end(); ++cur) @@ -1729,7 +1777,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string const &IndexDiffFile) /*{{{*/ unsigned long long patchesSize = 0; for (std::vector::const_iterator cur = available_patches.begin(); cur != available_patches.end(); ++cur) - patchesSize += cur->patch_size; + patchesSize += cur->patch_hashes.FileSize(); unsigned long long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100); if (sizeLimit > 0 && (sizeLimit/100) < patchesSize) { diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index f24af1aec..910e4131b 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -705,17 +705,14 @@ struct APT_HIDDEN DiffInfo { /*{{{*/ /** The filename of the diff. */ std::string file; - /** The hashes of the diff */ + /** The hashes of the file after the diff is applied */ HashStringList result_hashes; - /** The hashes of the file after the diff is applied */ + /** The hashes of the diff */ HashStringList patch_hashes; - /** The size of the file after the diff is applied */ - unsigned long long result_size; - - /** The size of the diff itself */ - unsigned long long patch_size; + /** The hashes of the compressed diff */ + HashStringList download_hashes; }; /*}}}*/ /** \brief An item that is responsible for fetching client-merge patches {{{ diff --git a/apt-pkg/contrib/hashes.cc b/apt-pkg/contrib/hashes.cc index 11a7e479b..46cf0ba08 100644 --- a/apt-pkg/contrib/hashes.cc +++ b/apt-pkg/contrib/hashes.cc @@ -188,6 +188,13 @@ unsigned long long HashStringList::FileSize() const /*{{{*/ return strtoull(hv.c_str(), NULL, 10); } /*}}}*/ +bool HashStringList::FileSize(unsigned long long const Size) /*{{{*/ +{ + std::string size; + strprintf(size, "%llu", Size); + return push_back(HashString("Checksum-FileSize", size)); +} + /*}}}*/ bool HashStringList::supported(char const * const type) /*{{{*/ { for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t) @@ -361,9 +368,7 @@ APT_IGNORE_DEPRECATED_PUSH if ((d->CalcHashes & SHA512SUM) == SHA512SUM) hashes.push_back(HashString("SHA512", SHA512.Result().Value())); APT_IGNORE_DEPRECATED_POP - std::string SizeStr; - strprintf(SizeStr, "%llu", d->FileSize); - hashes.push_back(HashString("Checksum-FileSize", SizeStr)); + hashes.FileSize(d->FileSize); return hashes; } APT_IGNORE_DEPRECATED_PUSH diff --git a/apt-pkg/contrib/hashes.h b/apt-pkg/contrib/hashes.h index 176ce4faa..e8d84da9e 100644 --- a/apt-pkg/contrib/hashes.h +++ b/apt-pkg/contrib/hashes.h @@ -96,6 +96,13 @@ class HashStringList */ unsigned long long FileSize() const; + /** sets the filesize hash + * + * @param Size of the file + * @return @see #push_back + */ + bool FileSize(unsigned long long const Size); + /** check if the given hash type is supported * * @param type to check diff --git a/apt-pkg/indexrecords.cc b/apt-pkg/indexrecords.cc index c26868cac..7e6da9558 100644 --- a/apt-pkg/indexrecords.cc +++ b/apt-pkg/indexrecords.cc @@ -121,9 +121,7 @@ bool indexRecords::Load(const string Filename) /*{{{*/ indexRecords::checkSum *Sum = new indexRecords::checkSum; Sum->MetaKeyFilename = Name; Sum->Size = Size; - std::string SizeStr; - strprintf(SizeStr, "%llu", Size); - Sum->Hashes.push_back(HashString("Checksum-FileSize", SizeStr)); + Sum->Hashes.FileSize(Size); APT_IGNORE_DEPRECATED(Sum->Hash = HashString(HashString::SupportedHashes()[i],Hash);) Entries[Name] = Sum; } -- cgit v1.2.3