aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Mike Kelly <pioto@pioto.org> 2007-08-08 17:30:05 +0000
committerAvatar Mike Kelly <pioto@pioto.org> 2007-08-08 17:30:05 +0000
commit28b5f288d4a7cef0f0022789d4a9141997474807 (patch)
treef268c5fabc500f775552fb679c13f22529a329e3
parent0eb34d3a8c272ed1c750b8c1a741d441ec5437cd (diff)
downloadpaludis-28b5f288d4a7cef0f0022789d4a9141997474807.tar.gz
paludis-28b5f288d4a7cef0f0022789d4a9141997474807.tar.xz
Make CheckFetchedFilesVisitor verify that fetched files match their Manifest2 checksums and size. Also, add Manifest2Reader, which iterates over a list of Manifest2Entrys.
-rw-r--r--paludis/repositories/e/Makefile.am19
-rw-r--r--paludis/repositories/e/check_fetched_files_visitor.cc107
-rw-r--r--paludis/repositories/e/check_fetched_files_visitor.hh2
-rw-r--r--paludis/repositories/e/e_repository_TEST.cc29
-rw-r--r--paludis/repositories/e/manifest2_entry.sr18
-rw-r--r--paludis/repositories/e/manifest2_reader.cc147
-rw-r--r--paludis/repositories/e/manifest2_reader.hh84
7 files changed, 403 insertions, 3 deletions
diff --git a/paludis/repositories/e/Makefile.am b/paludis/repositories/e/Makefile.am
index 3b354fb..69e9704 100644
--- a/paludis/repositories/e/Makefile.am
+++ b/paludis/repositories/e/Makefile.am
@@ -9,7 +9,8 @@ DISTCLEANFILES = \
vdb_merger-sr.hh vdb_merger-sr.cc \
vdb_unmerger-sr.hh vdb_unmerger-sr.cc \
eapi-sr.hh eapi-sr.cc \
- dep_parser-se.hh dep_parser-se.cc
+ dep_parser-se.hh dep_parser-se.cc \
+ manifest2_entry-sr.hh manifest2_entry-sr.cc
MAINTAINERCLEANFILES = Makefile.in
@@ -74,6 +75,8 @@ paludis_repositories_e_include_HEADERS = \
layout.hh \
make_ebin_repository.hh \
make_ebuild_repository.hh \
+ manifest2_entry-sr.hh \
+ manifest2_reader.hh \
source_uri_finder.hh \
traditional_layout.hh \
use_desc.hh \
@@ -118,6 +121,7 @@ libpaludiserepository_la_SOURCES = \
layout.cc \
make_ebin_repository.cc \
make_ebuild_repository.cc \
+ manifest2_reader.cc \
registration.cc \
source_uri_finder.cc \
traditional_layout.cc \
@@ -287,6 +291,9 @@ EXTRA_DIST = \
fetch_visitor_TEST.cc \
fetch_visitor_TEST_setup.sh \
fetch_visitor_TEST_cleanup.sh \
+ manifest2_entry.sr \
+ manifest2_entry-sr.hh \
+ manifest2_entry-sr.cc \
source_uri_finder_TEST.cc \
xml_things_TEST.cc \
xml_things_TEST_setup.sh \
@@ -327,7 +334,9 @@ BUILT_SOURCES = \
vdb_unmerger-sr.hh \
vdb_unmerger-sr.cc \
eapi-sr.hh \
- eapi-sr.cc
+ eapi-sr.cc \
+ manifest2_entry-sr.hh \
+ manifest2_entry-sr.cc
check_SCRIPTS = \
e_repository_TEST_setup.sh e_repository_TEST_cleanup.sh \
@@ -358,6 +367,12 @@ e_repository_params-sr.hh : e_repository_params.sr $(top_srcdir)/misc/make_sr.ba
e_repository_params-sr.cc : e_repository_params.sr $(top_srcdir)/misc/make_sr.bash
$(top_srcdir)/misc/make_sr.bash --source $(srcdir)/e_repository_params.sr > $@
+manifest2_entry-sr.hh : manifest2_entry.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/manifest2_entry.sr > $@
+
+manifest2_entry-sr.cc : manifest2_entry.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/manifest2_entry.sr > $@
+
vdb_merger-sr.hh : vdb_merger.sr $(top_srcdir)/misc/make_sr.bash
$(top_srcdir)/misc/make_sr.bash --header $(srcdir)/vdb_merger.sr > $@
diff --git a/paludis/repositories/e/check_fetched_files_visitor.cc b/paludis/repositories/e/check_fetched_files_visitor.cc
index 76a58a5..055cfa4 100644
--- a/paludis/repositories/e/check_fetched_files_visitor.cc
+++ b/paludis/repositories/e/check_fetched_files_visitor.cc
@@ -34,7 +34,15 @@
#include <paludis/util/join.hh>
#include <paludis/util/save.hh>
#include <paludis/util/stringify.hh>
+
+#include <paludis/digests/rmd160.hh>
+#include <paludis/digests/sha256.hh>
+#include <paludis/digests/md5.hh>
+
+#include <paludis/repositories/e/manifest2_reader.hh>
+
#include <iostream>
+#include <fstream>
#include <list>
#include <set>
@@ -56,6 +64,8 @@ namespace paludis
bool need_nofetch;
bool in_nofetch;
+ const tr1::shared_ptr<Manifest2Reader> m2r;
+
Implementation(
const Environment * const e,
const tr1::shared_ptr<const PackageID> & i,
@@ -68,7 +78,8 @@ namespace paludis
check_unneeded(c),
failures(new Sequence<FetchActionFailure>),
need_nofetch(false),
- in_nofetch(n)
+ in_nofetch(n),
+ m2r(new Manifest2Reader(d / "Manifest"))
{
}
};
@@ -155,6 +166,95 @@ CheckFetchedFilesVisitor::visit_leaf(const LabelsDepSpec<URILabelVisitorTypes> &
_imp->in_nofetch = v.result;
}
+bool
+CheckFetchedFilesVisitor::check_distfile_manifest(const FSEntry & distfile)
+{
+ for (Manifest2Reader::Iterator m(_imp->m2r->begin()), m_end(_imp->m2r->end()) ;
+ m != m_end ; ++m)
+ {
+ if (distfile.basename() != m->name)
+ continue;
+
+ if (distfile.file_size() != m->size)
+ {
+ Log::get_instance()->message(ll_debug, lc_context)
+ << "Malformed Manifest: no file size found";
+ std::cout << "incorrect size";
+ _imp->failures->push_back(FetchActionFailure::create()
+ .target_file(stringify(distfile.basename()))
+ .requires_manual_fetching(false)
+ .failed_integrity_checks("Incorrect file size")
+ .failed_automatic_fetching(false)
+ );
+ return false;
+ }
+
+ std::ifstream file_stream(stringify(distfile).c_str());
+ if (! file_stream)
+ throw InternalError("Couldn't read distfile: '"+stringify(distfile)
+ +"'");
+
+ if (! m->rmd160.empty())
+ {
+ RMD160 rmd160sum(file_stream);
+ if (rmd160sum.hexsum() != m->rmd160)
+ {
+ Log::get_instance()->message(ll_debug, lc_context)
+ << "Malformed Manifest: failed RMD160 checksum";
+ std::cout << "failed RMD160";
+ _imp->failures->push_back(FetchActionFailure::create()
+ .target_file(stringify(distfile.basename()))
+ .requires_manual_fetching(false)
+ .failed_integrity_checks("Failed RMD160 checksum")
+ .failed_automatic_fetching(false)
+ );
+ return false;
+ }
+ file_stream.clear();
+ file_stream.seekg(0, std::ios::beg);
+ }
+
+ if (! m->sha256.empty())
+ {
+ SHA256 sha256sum(file_stream);
+ if (sha256sum.hexsum() != m->sha256)
+ {
+ Log::get_instance()->message(ll_debug, lc_context)
+ << "Malformed Manifest: failed SHA256 checksum";
+ std::cout << "failed SHA256";
+ _imp->failures->push_back(FetchActionFailure::create()
+ .target_file(stringify(distfile.basename()))
+ .requires_manual_fetching(false)
+ .failed_integrity_checks("Failed SHA256 checksum")
+ .failed_automatic_fetching(false)
+ );
+ return false;
+ }
+ file_stream.clear();
+ file_stream.seekg(0, std::ios::beg);
+ }
+
+ if (! m->md5.empty())
+ {
+ MD5 md5sum(file_stream);
+ if (md5sum.hexsum() != m->md5)
+ {
+ Log::get_instance()->message(ll_debug, lc_context)
+ << "Malformed Manifest: failed MD5 checksum";
+ std::cout << "failed MD5";
+ _imp->failures->push_back(FetchActionFailure::create()
+ .target_file(stringify(distfile.basename()))
+ .requires_manual_fetching(false)
+ .failed_integrity_checks("Failed MD5 checksum")
+ .failed_automatic_fetching(false)
+ );
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
void
CheckFetchedFilesVisitor::visit_leaf(const URIDepSpec & u)
{
@@ -206,6 +306,11 @@ CheckFetchedFilesVisitor::visit_leaf(const URIDepSpec & u)
.failed_automatic_fetching(false)
);
}
+ else if (! check_distfile_manifest(_imp->distdir / u.filename()))
+ {
+ Log::get_instance()->message(ll_debug, lc_context)
+ << "Manifest check failed for '" << u.filename() << "'";
+ }
else
{
Log::get_instance()->message(ll_debug, lc_context) << "Success for '" << u.filename() << "'";
diff --git a/paludis/repositories/e/check_fetched_files_visitor.hh b/paludis/repositories/e/check_fetched_files_visitor.hh
index 1503eb1..2d8ecea 100644
--- a/paludis/repositories/e/check_fetched_files_visitor.hh
+++ b/paludis/repositories/e/check_fetched_files_visitor.hh
@@ -38,6 +38,8 @@ namespace paludis
private PrivateImplementationPattern<CheckFetchedFilesVisitor>,
public ConstVisitor<URISpecTree>
{
+ private:
+ bool check_distfile_manifest(const FSEntry & distfile);
public:
CheckFetchedFilesVisitor(
const Environment * const,
diff --git a/paludis/repositories/e/e_repository_TEST.cc b/paludis/repositories/e/e_repository_TEST.cc
index 0b6464d..f24b05c 100644
--- a/paludis/repositories/e/e_repository_TEST.cc
+++ b/paludis/repositories/e/e_repository_TEST.cc
@@ -972,6 +972,35 @@ namespace test_cases
}
} test_e_repository_fetch;
+ struct ERepositoryManifestCheckTest : TestCase
+ {
+ ERepositoryManifestCheckTest() : TestCase("manifest_check") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ tr1::shared_ptr<Map<std::string, std::string> > keys(
+ new Map<std::string, std::string>);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "e_repository_TEST_dir/repo11");
+ keys->insert("profiles", "e_repository_TEST_dir/repo11/profiles/profile");
+ tr1::shared_ptr<ERepository> repo(make_ebuild_repository(
+ &env, keys));
+ env.package_database()->add_repository(1, repo);
+
+ FetchAction action(FetchActionOptions::create()
+ .fetch_unneeded(false)
+ .safe_resume(true)
+ );
+
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec("category/package", pds_pm_unspecific)), qo_order_by_version)->last());
+ TEST_CHECK(id);
+ id->perform_action(action);
+ }
+ } test_e_repository_manifest_check;
+
struct ERepositoryInstallEAPI0Test : TestCase
{
ERepositoryInstallEAPI0Test() : TestCase("install_eapi_0") { }
diff --git a/paludis/repositories/e/manifest2_entry.sr b/paludis/repositories/e/manifest2_entry.sr
new file mode 100644
index 0000000..3d591fa
--- /dev/null
+++ b/paludis/repositories/e/manifest2_entry.sr
@@ -0,0 +1,18 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_Manifest2Entry()
+{
+ visible
+
+ key type "std::string"
+ key name "std::string"
+ key size "off_t"
+
+ key sha1 "std::string"
+ key sha256 "std::string"
+ key rmd160 "std::string"
+ key md5 "std::string"
+
+ allow_named_args
+}
diff --git a/paludis/repositories/e/manifest2_reader.cc b/paludis/repositories/e/manifest2_reader.cc
new file mode 100644
index 0000000..cab2c21
--- /dev/null
+++ b/paludis/repositories/e/manifest2_reader.cc
@@ -0,0 +1,147 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Mike Kelly <pioto@pioto.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/e/manifest2_reader.hh>
+
+#include <paludis/config_file.hh>
+#include <paludis/util/destringify.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/options.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <libwrapiter/libwrapiter_forward_iterator.hh>
+
+#include <list>
+
+#include <paludis/repositories/e/manifest2_entry-sr.cc>
+
+
+/** \file
+ * Implementation of manifest2_reader.hh
+ *
+ * \ingroup grpmanifest2reader
+ */
+
+using namespace paludis;
+using namespace paludis::erepository;
+
+namespace paludis
+{
+ template<>
+ struct Implementation<Manifest2Reader>
+ {
+ FSEntry manifest;
+ std::list<Manifest2Entry> entries;
+
+ Implementation(const FSEntry & f) :
+ manifest(f)
+ {
+ }
+ };
+}
+
+Manifest2Error::Manifest2Error(const std::string & msg) throw () :
+ ActionError("Manifest2 Error: " + msg)
+{
+}
+
+Manifest2Reader::Manifest2Reader(const FSEntry & f) :
+ PrivateImplementationPattern<Manifest2Reader>(new Implementation<Manifest2Reader>(f))
+{
+ if (! f.exists())
+ return;
+
+ LineConfigFile lines(_imp->manifest, LineConfigFileOptions());
+
+ for (LineConfigFile::Iterator l(lines.begin()), l_end(lines.end()) ;
+ l != l_end ; ++l)
+ {
+ std::list<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise((*l),
+ create_inserter<std::string>(std::back_inserter(tokens)));
+ std::list<std::string>::const_iterator t(tokens.begin()), t_end(tokens.end());
+
+ std::string type, name, sha1, sha256, rmd160, md5;
+ off_t size;
+
+ if (t_end == t)
+ continue;
+ type = (*t);
+
+ ++t;
+ if (t_end == t)
+ throw Manifest2Error("no file name found");
+ name = (*t);
+
+ ++t;
+ if (t_end == t)
+ throw Manifest2Error("no file size found");
+ size = destringify<off_t>(*t);
+
+ ++t;
+ for ( ; t!= t_end ; ++t)
+ {
+ std::string checksum_type(*t);
+ ++t;
+
+ if (t_end == t)
+ throw Manifest2Error("no checksum for: " + checksum_type);
+
+ if ("SHA1" == checksum_type)
+ sha1 = (*t);
+ else if ("SHA256" == checksum_type)
+ sha256 = (*t);
+ else if ("RMD160" == checksum_type)
+ rmd160 = (*t);
+ else if ("MD5" == checksum_type)
+ md5 = (*t);
+ else
+ Log::get_instance()->message(ll_debug, lc_no_context)
+ << "Skipping unknown checksum type " << checksum_type;
+ }
+
+ _imp->entries.push_back(Manifest2Entry::create()
+ .type(type)
+ .size(size)
+ .name(name)
+ .sha1(sha1)
+ .sha256(sha256)
+ .rmd160(rmd160)
+ .md5(md5)
+ );
+ }
+}
+
+Manifest2Reader::~Manifest2Reader()
+{
+}
+
+Manifest2Reader::Iterator
+Manifest2Reader::begin() const
+{
+ return Iterator(_imp->entries.begin());
+}
+
+Manifest2Reader::Iterator
+Manifest2Reader::end() const
+{
+ return Iterator(_imp->entries.end());
+}
diff --git a/paludis/repositories/e/manifest2_reader.hh b/paludis/repositories/e/manifest2_reader.hh
new file mode 100644
index 0000000..978ba83
--- /dev/null
+++ b/paludis/repositories/e/manifest2_reader.hh
@@ -0,0 +1,84 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Mike Kelly <pioto@pioto.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_MANIFEST2_READER_HH
+#define PALUDIS_GUARD_PALUDIS_MANIFEST2_READER_HH 1
+
+#include <paludis/action.hh>
+#include <paludis/util/fs_entry-fwd.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/sr.hh>
+
+#include <paludis/repositories/e/manifest2_entry-sr.hh>
+
+#include <string>
+
+/** \file
+ * Declarations for the Manifest2Reader class
+ *
+ * \ingroup grpmanifest2reader
+ */
+
+namespace paludis
+{
+
+ namespace erepository
+ {
+ /**
+ * Thrown if a Manifest2 file cannot be read properly.
+ *
+ * \ingroup grpexceptions
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE Manifest2Error :
+ public ActionError
+ {
+ public:
+ Manifest2Error(const std::string & msg) throw ();
+ };
+
+ /**
+ * Gives an Iterator of Manifest2Entrys from a given Manifest 2 style
+ * file.
+ *
+ * \ingroup grpmanifest2reader
+ */
+ class PALUDIS_VISIBLE Manifest2Reader :
+ private PrivateImplementationPattern<Manifest2Reader>
+ {
+ public:
+ ///\name Basic operations
+
+ Manifest2Reader(const FSEntry & f);
+ ~Manifest2Reader();
+
+ ///}
+
+ /// \name Iterator functions
+
+ typedef libwrapiter::ForwardIterator<Manifest2Reader, const Manifest2Entry> Iterator;
+ Iterator begin() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ Iterator end() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ ///}
+ };
+ }
+}
+
+#endif