#include "zypp/ZConfig.h"
#include "zypp/RepoInfo.h"
#include "zypp/RepoManager.h"
-#include "zypp/SrcPackage.h"
#include "zypp/ZYppFactory.h"
#include "zypp/Target.h"
namespace repo
{
///////////////////////////////////////////////////////////////////
- /// \class RpmSigCheckException
- /// \brief Exception thrown by \ref PackageProviderImpl::rpmSigFileChecker
- ///////////////////////////////////////////////////////////////////
- class RpmSigCheckException : public FileCheckException
- {
- public:
- RpmSigCheckException( repo::DownloadResolvableReport::Action action_r, std::string msg_r = "RpmSigCheckException" )
- : FileCheckException( std::move(msg_r) )
- , _action( std::move(action_r) )
- {}
-
- /** Users final decision how to proceed */
- const repo::DownloadResolvableReport::Action & action() const
- { return _action; }
-
- private:
- repo::DownloadResolvableReport::Action _action;
- };
-
-
- ///////////////////////////////////////////////////////////////////
// class PackageProviderPolicy
///////////////////////////////////////////////////////////////////
return false;
}
- ///////////////////////////////////////////////////////////////////
- /// \class PackageProvider::Impl
- /// \brief PackageProvider implementation interface.
- ///////////////////////////////////////////////////////////////////
- struct PackageProvider::Impl : private base::NonCopyable
- {
- Impl() {}
- virtual ~Impl() {}
-
- /** Provide the package.
- * The basic workflow.
- * \throws Exception.
- */
- virtual ManagedFile providePackage() const = 0;
-
- /** Provide the package if it is cached. */
- virtual ManagedFile providePackageFromCache() const = 0;
-
- /** Whether the package is cached. */
- virtual bool isCached() const = 0;
- };
///////////////////////////////////////////////////////////////////
- /// \class PackageProviderImpl<TPackage>
- /// \brief PackageProvider implementation for \c Package and \c SrcPackage
+ /// \class PackageProvider::Impl
+ /// \brief PackageProvider implementation.
///////////////////////////////////////////////////////////////////
- template <class TPackage>
- class PackageProviderImpl : public PackageProvider::Impl
+ class PackageProvider::Impl : private base::NonCopyable
{
- typedef typename TPackage::constPtr TPackagePtr; // Package or SrcPackage
typedef callback::UserData UserData;
public:
/** Ctor taking the Package to provide. */
- PackageProviderImpl( RepoMediaAccess & access_r, const TPackagePtr & package_r,
- const PackageProviderPolicy & policy_r )
+ Impl( RepoMediaAccess & access_r,
+ const Package::constPtr & package_r,
+ const DeltaCandidates & deltas_r,
+ const PackageProviderPolicy & policy_r )
: _policy( policy_r )
, _package( package_r )
+ , _deltas( deltas_r )
, _access( access_r )
, _retry(false)
{}
- virtual ~PackageProviderImpl() {}
+ virtual ~Impl() {}
+
+ /** Factory method providing the appropriate implementation.
+ * Called by PackageProvider ctor. Returned pointer should be
+ * immediately wrapped into a smartpointer.
+ */
+ static Impl * factoryMake( RepoMediaAccess & access_r,
+ const Package::constPtr & package_r,
+ const DeltaCandidates & deltas_r,
+ const PackageProviderPolicy & policy_r );
public:
/** Provide the package.
* The basic workflow.
* \throws Exception.
*/
- virtual ManagedFile providePackage() const;
+ ManagedFile providePackage() const;
/** Provide the package if it is cached. */
- virtual ManagedFile providePackageFromCache() const
+ ManagedFile providePackageFromCache() const
{
ManagedFile ret( doProvidePackageFromCache() );
if ( ! ( ret->empty() || _package->repoInfo().keepPackages() ) )
}
/** Whether the package is cached. */
- virtual bool isCached() const
+ bool isCached() const
{ return ! doProvidePackageFromCache()->empty(); }
protected:
- typedef PackageProviderImpl<TPackage> Base;
+ typedef PackageProvider::Impl Base;
typedef callback::SendReport<repo::DownloadResolvableReport> Report;
/** Lookup the final rpm in cache.
*
- * A cache hit will return a non empty ManagedFile and an empty one on cache miss.
+ * A non empty ManagedFile will be returned to the caller.
*
* \note File disposal depending on the repos keepPackages setting
* are not set here, but in \ref providePackage or \ref providePackageFromCache.
+ *
+ * \note The provoided default implementation returns an empty ManagedFile
+ * (cache miss).
*/
- ManagedFile doProvidePackageFromCache() const
- { return ManagedFile( _package->cachedLocation() ); }
+ virtual ManagedFile doProvidePackageFromCache() const = 0;
/** Actually provide the final rpm.
* Report start/problem/finish and retry loop are hadled by \ref providePackage.
* \note The provided default implementation retrieves the packages default
* location.
*/
- virtual ManagedFile doProvidePackage() const
- {
- ManagedFile ret;
- OnMediaLocation loc = _package->location();
-
- ProvideFilePolicy policy;
- policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
- policy.fileChecker( bind( &Base::rpmSigFileChecker, this, _1 ) );
- return _access.provideFile( _package->repoInfo(), loc, policy );
- }
+ virtual ManagedFile doProvidePackage() const = 0;
protected:
/** Access to the DownloadResolvableReport */
bool progressPackageDownload( int value ) const
{ return report()->progress( value, _package ); }
-
- /** \name Validate a rpm packages signature.
- *
- * This is the \ref FileChecker passed down to the \ref Fetcher to validate
- * a provided rpm package. This builtin checker includes the workflow
- * communicating with the user in case of a problem with the package
- * signature.
- *
- * \throws RpmSigCheckException if the package is not accepted, propagating
- * the users decision how to proceed (\ref DownloadResolvableReport::Action).
- *
- * \note This check is also needed, if the the rpm is built locally by using
- * delta rpms! \ref \see RpmPackageProvider
- */
- //@{
- void rpmSigFileChecker( const Pathname & file_r ) const
- {
- const RepoInfo & info = _package->repoInfo();
- if ( info.pkgGpgCheck() )
- {
- UserData userData( "pkgGpgCheck" );
- ResObject::constPtr roptr( _package ); // gcc6 needs it more explcit. Has problem deducing
- userData.set( "ResObject", roptr ); // a type for '_package->asKind<ResObject>()'...
- /*legacy:*/userData.set( "Package", roptr->asKind<Package>() );
- userData.set( "Localpath", file_r );
- RpmDb::CheckPackageResult res = packageSigCheck( file_r, info.pkgGpgCheckIsMandatory(), userData );
-
- // publish the checkresult, even if it is OK. Apps may want to report something...
- report()->pkgGpgCheck( userData );
-
- if ( res != RpmDb::CHK_OK )
- {
- if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action
- {
- resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
- }
- else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details)
- {
- defaultReportSignatureError( res );
- }
- else // no advice from user => usedefaults
- {
- switch ( res )
- {
- case RpmDb::CHK_OK: // Signature is OK
- break;
-
- case RpmDb::CHK_NOKEY: // Public key is unavailable
- case RpmDb::CHK_NOTFOUND: // Signature is unknown type
- case RpmDb::CHK_FAIL: // Signature does not verify
- case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted
- case RpmDb::CHK_ERROR: // File does not exist or can't be opened
- case RpmDb::CHK_NOSIG: // File is unsigned
- default:
- // report problem (w. details), throw if to abort, else retry/ignore
- defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
- break;
- }
- }
- }
- }
- }
-
typedef target::rpm::RpmDb RpmDb;
- /** Actual rpm package signature check. */
- RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, bool isMandatory_r, UserData & userData ) const
+ RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, UserData & userData ) const
{
if ( !_target )
_target = getZYpp()->getTarget();
RpmDb::CheckPackageResult ret = RpmDb::CHK_ERROR;
RpmDb::CheckPackageDetail detail;
if ( _target )
- {
- ret = _target->rpmDb().checkPackageSignature( path_r, detail );
- if ( ret == RpmDb::CHK_NOSIG && !isMandatory_r )
- {
- WAR << "Relax CHK_NOSIG: Config says unsigned packages are OK" << endl;
- ret = RpmDb::CHK_OK;
- }
- }
+ ret = _target->rpmDb().checkPackage( path_r, detail );
else
detail.push_back( RpmDb::CheckPackageDetail::value_type( ret, "OOps. Target is not initialized!" ) );
return ret;
}
- /** React on signature verification error user action.
+ /** React on signature verification error user action
* \note: IGNORE == accept insecure file (no SkipRequestException!)
*/
void resolveSignatureErrorAction( repo::DownloadResolvableReport::Action action_r ) const
{
switch ( action_r )
{
+ case repo::DownloadResolvableReport::RETRY:
+ _retry = true;
+ break;
case repo::DownloadResolvableReport::IGNORE:
WAR << _package->asUserString() << ": " << "User requested to accept insecure file" << endl;
break;
default:
- case repo::DownloadResolvableReport::RETRY:
case repo::DownloadResolvableReport::ABORT:
- ZYPP_THROW(RpmSigCheckException(action_r,"Signature verification failed"));
+ ZYPP_THROW(AbortRequestException("User requested to abort"));
break;
}
}
msg << "\n" << detail_r;
resolveSignatureErrorAction( report()->problem( _package, repo::DownloadResolvableReport::INVALID, msg.str() ) );
}
- //@}
protected:
PackageProviderPolicy _policy;
- TPackagePtr _package;
+ Package::constPtr _package;
+ DeltaCandidates _deltas;
RepoMediaAccess & _access;
private:
};
///////////////////////////////////////////////////////////////////
- template <class TPackage>
- ManagedFile PackageProviderImpl<TPackage>::providePackage() const
+ /** Default implementation (cache miss). */
+ ManagedFile PackageProvider::Impl::doProvidePackageFromCache() const
+ { return ManagedFile(); }
+
+ /** Default implementation (provide full package) */
+ ManagedFile PackageProvider::Impl::doProvidePackage() const
+ {
+ ManagedFile ret;
+ OnMediaLocation loc = _package->location();
+
+ ProvideFilePolicy policy;
+ policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
+ return _access.provideFile( _package->repoInfo(), loc, policy );
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ManagedFile PackageProvider::Impl::providePackage() const
{
ScopedGuard guardReport( newReport() );
MIL << "provide Package " << _package << endl;
Url url = * info.baseUrlsBegin();
- try {
do {
_retry = false;
if ( ! ret->empty() )
try
{
ret = doProvidePackage();
+
+ if ( info.pkgGpgCheck() )
+ {
+ UserData userData( "pkgGpgCheck" );
+ userData.set( "Package", _package );
+ userData.set( "Localpath", ret.value() );
+ RpmDb::CheckPackageResult res = packageSigCheck( ret, userData );
+ // publish the checkresult, even if it is OK. Apps may want to report something...
+ report()->pkgGpgCheck( userData );
+USR << "CHK: " << res << endl;
+ if ( res != RpmDb::CHK_OK )
+ {
+ if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action
+ {
+ resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
+ }
+ else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details)
+ {
+ defaultReportSignatureError( res );
+ }
+ else // no advice from user => usedefaults
+ {
+ switch ( res )
+ {
+ case RpmDb::CHK_OK: // Signature is OK
+ break;
+
+ case RpmDb::CHK_NOKEY: // Public key is unavailable
+ case RpmDb::CHK_NOTFOUND: // Signature is unknown type
+ case RpmDb::CHK_FAIL: // Signature does not verify
+ case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted
+ case RpmDb::CHK_ERROR: // File does not exist or can't be opened
+ default:
+ // report problem (w. details), throw if to abort, else retry/ignore
+ defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
+ break;
+ }
+ }
+ }
+ }
}
catch ( const UserRequestException & excpt )
{
if ( ! _retry )
ZYPP_RETHROW( excpt );
}
- catch ( const RpmSigCheckException & excpt )
- {
- ERR << "Failed to provide Package " << _package << endl;
- if ( ! _retry )
- {
- // Signature verification error was already reported by the
- // rpmSigFileChecker. Just handle the users action decision:
- switch ( excpt.action() )
- {
- case repo::DownloadResolvableReport::RETRY:
- _retry = true;
- break;
- case repo::DownloadResolvableReport::IGNORE:
- ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
- break;
- default:
- case repo::DownloadResolvableReport::ABORT:
- ZYPP_THROW(AbortRequestException("User requested to abort"));
- break;
- }
- }
- }
catch ( const FileCheckException & excpt )
{
ERR << "Failed to provide Package " << _package << endl;
case repo::DownloadResolvableReport::IGNORE:
ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
break;
- default:
case repo::DownloadResolvableReport::ABORT:
ZYPP_THROW(AbortRequestException("User requested to abort"));
break;
+ default:
+ break;
}
}
}
case repo::DownloadResolvableReport::IGNORE:
ZYPP_THROW(SkipRequestException("User requested skip of file", excpt));
break;
- default:
case repo::DownloadResolvableReport::ABORT:
ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
break;
+ default:
+ ZYPP_RETHROW( excpt );
+ break;
}
}
}
} while ( _retry );
- } catch(...){
- // bsc#1045735: Be sure no invalid files stay in the cache!
- if ( ! ret->empty() )
- ret.setDispose( filesystem::unlink );
- throw;
- }
report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
MIL << "provided Package " << _package << " at " << ret << endl;
///////////////////////////////////////////////////////////////////
/// \class RpmPackageProvider
- /// \brief RPM PackageProvider implementation (with deltarpm processing).
+ /// \brief RPM PackageProvider implementation.
///////////////////////////////////////////////////////////////////
- class RpmPackageProvider : public PackageProviderImpl<Package>
+ class RpmPackageProvider : public PackageProvider::Impl
{
public:
RpmPackageProvider( RepoMediaAccess & access_r,
const Package::constPtr & package_r,
const DeltaCandidates & deltas_r,
const PackageProviderPolicy & policy_r )
- : PackageProviderImpl<Package>( access_r, package_r, policy_r )
- , _deltas( deltas_r )
+ : PackageProvider::Impl( access_r, package_r, deltas_r, policy_r )
{}
protected:
+ virtual ManagedFile doProvidePackageFromCache() const;
+
virtual ManagedFile doProvidePackage() const;
private:
bool queryInstalled( const Edition & ed_r = Edition() ) const
{ return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
-
- private:
- DeltaCandidates _deltas;
};
///////////////////////////////////////////////////////////////////
+ ManagedFile RpmPackageProvider::doProvidePackageFromCache() const
+ {
+ return ManagedFile( _package->cachedLocation() );
+ }
+
ManagedFile RpmPackageProvider::doProvidePackage() const
{
+ Url url;
+ RepoInfo info = _package->repoInfo();
+ // FIXME we only support the first url for now.
+ if ( info.baseUrlsEmpty() )
+ ZYPP_THROW(Exception("No url in repository."));
+ else
+ url = * info.baseUrlsBegin();
+
// check whether to process patch/delta rpms
- // FIXME we only check the first url for now.
if ( ZConfig::instance().download_use_deltarpm()
- && ( _package->repoInfo().url().schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) )
+ && ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) )
{
std::list<DeltaRpm> deltaRpms;
_deltas.deltaRpms( _package ).swap( deltaRpms );
return ManagedFile();
}
- // Build the package
- Pathname cachedest( _package->repoInfo().packagesPath() / _package->location().filename() );
- Pathname builddest( cachedest.extend( ".drpm" ) );
+ // build the package and put it into the cache
+ Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
- if ( ! applydeltarpm::provide( delta, builddest,
+ if ( ! applydeltarpm::provide( delta, destination,
bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
{
report()->problemDeltaApply( _("applydeltarpm failed.") );
return ManagedFile();
}
- ManagedFile builddestCleanup( builddest, filesystem::unlink );
report()->finishDeltaApply();
- // Check and move it into the cache
- // Here the rpm itself is ready. If the packages sigcheck fails, it
- // makes no sense to return a ManagedFile() and fallback to download the
- // full rpm. It won't be different. So let the exceptions escape...
- rpmSigFileChecker( builddest );
- if ( filesystem::hardlinkCopy( builddest, cachedest ) != 0 )
- ZYPP_THROW( Exception( str::Str() << "Can't hardlink/copy " << builddest << " to " << cachedest ) );
-
- return ManagedFile( cachedest, filesystem::unlink );
+ return ManagedFile( destination, filesystem::unlink );
}
+#if 0
///////////////////////////////////////////////////////////////////
- // class PackageProvider
+ /// \class PluginPackageProvider
+ /// \brief Plugin PackageProvider implementation.
+ ///
+ /// Basically downloads the default package and calls a
+ /// 'stem'2rpm plugin to cteate the final .rpm package.
///////////////////////////////////////////////////////////////////
- namespace factory
+ class PluginPackageProvider : public PackageProvider::Impl
{
- inline PackageProvider::Impl * make( RepoMediaAccess & access_r, const PoolItem & pi_r,
- const DeltaCandidates & deltas_r,
- const PackageProviderPolicy & policy_r )
+ public:
+ PluginPackageProvider( const std::string & stem_r,
+ RepoMediaAccess & access_r,
+ const Package::constPtr & package_r,
+ const DeltaCandidates & deltas_r,
+ const PackageProviderPolicy & policy_r )
+ : Base( access_r, package_r, deltas_r, policy_r )
+ {}
+
+ protected:
+ virtual ManagedFile doProvidePackageFromCache() const
{
- if ( pi_r.satSolvable().isKind<Package>() )
- return new RpmPackageProvider( access_r, pi_r->asKind<Package>(), deltas_r, policy_r );
- else if ( pi_r.satSolvable().isKind<SrcPackage>() )
- return new PackageProviderImpl<SrcPackage>( access_r, pi_r->asKind<SrcPackage>(), policy_r );
- else
- ZYPP_THROW( Exception( str::Str() << "Don't know how to cache non-package " << pi_r.satSolvable().asUserString() ) );
+ return Base::doProvidePackageFromCache();
}
- inline PackageProvider::Impl * make( RepoMediaAccess & access_r, const PoolItem & pi_r,
- const PackageProviderPolicy & policy_r )
+ virtual ManagedFile doProvidePackage() const
{
- if ( pi_r.satSolvable().isKind<Package>() )
- return new PackageProviderImpl<Package>( access_r, pi_r->asKind<Package>(), policy_r );
- else if ( pi_r.satSolvable().isKind<SrcPackage>() )
- return new PackageProviderImpl<SrcPackage>( access_r, pi_r->asKind<SrcPackage>(), policy_r );
- else
- ZYPP_THROW( Exception( str::Str() << "Don't know how to cache non-package " << pi_r.satSolvable().asUserString() ) );
+ return Base::doProvidePackage();
}
-
- inline PackageProvider::Impl * make( RepoMediaAccess & access_r, const Package::constPtr & package_r,
- const DeltaCandidates & deltas_r,
- const PackageProviderPolicy & policy_r )
- { return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r ); }
-
- } // namespace factory
+ };
///////////////////////////////////////////////////////////////////
+#endif
- PackageProvider::PackageProvider( RepoMediaAccess & access_r, const PoolItem & pi_r,
- const DeltaCandidates & deltas_r, const PackageProviderPolicy & policy_r )
-
- : _pimpl( factory::make( access_r, pi_r, deltas_r, policy_r ) )
- {}
+ ///////////////////////////////////////////////////////////////////
+ // class PackageProvider
+ ///////////////////////////////////////////////////////////////////
- PackageProvider::PackageProvider( RepoMediaAccess & access_r, const PoolItem & pi_r,
- const PackageProviderPolicy & policy_r )
- : _pimpl( factory::make( access_r, pi_r, policy_r ) )
- {}
+ PackageProvider::Impl * PackageProvider::Impl::factoryMake( RepoMediaAccess & access_r,
+ const Package::constPtr & package_r,
+ const DeltaCandidates & deltas_r,
+ const PackageProviderPolicy & policy_r )
+ {
+ return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r );
+ }
- /* legacy */
PackageProvider::PackageProvider( RepoMediaAccess & access_r,
const Package::constPtr & package_r,
const DeltaCandidates & deltas_r,
const PackageProviderPolicy & policy_r )
- : _pimpl( factory::make( access_r, package_r, deltas_r, policy_r ) )
+ : _pimpl( Impl::factoryMake( access_r, package_r, deltas_r, policy_r ) )
{}
PackageProvider::~PackageProvider()