Fix Werrors with GCC-14.1.0
[platform/upstream/libzypp.git] / zypp / repo / PackageProvider.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/repo/PackageProvider.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <zypp/repo/PackageDelta.h>
16 #include <zypp/base/Logger.h>
17 #include <zypp/base/Gettext.h>
18 #include <zypp/base/UserRequestException.h>
19 #include <zypp/base/NonCopyable.h>
20 #include <zypp/repo/PackageProvider.h>
21 #include <zypp/repo/Applydeltarpm.h>
22 #include <zypp/repo/PackageDelta.h>
23
24 #include <zypp/TmpPath.h>
25 #include <zypp/ZConfig.h>
26 #include <zypp/RepoInfo.h>
27 #include <zypp/RepoManager.h>
28 #include <zypp/SrcPackage.h>
29
30 #include <zypp/ZYppFactory.h>
31 #include <zypp/Target.h>
32 #include <zypp/target/rpm/RpmDb.h>
33 #include <zypp/FileChecker.h>
34 #include <zypp/target/rpm/RpmHeader.h>
35
36 using std::endl;
37
38 ///////////////////////////////////////////////////////////////////
39 namespace zypp
40 {
41   ///////////////////////////////////////////////////////////////////
42   namespace repo
43   {
44     ///////////////////////////////////////////////////////////////////
45     /// \class RpmSigCheckException
46     /// \brief Exception thrown by \ref PackageProviderImpl::rpmSigFileChecker
47     ///////////////////////////////////////////////////////////////////
48     class RpmSigCheckException : public FileCheckException
49     {
50     public:
51       RpmSigCheckException( repo::DownloadResolvableReport::Action action_r, std::string msg_r = "RpmSigCheckException" )
52       : FileCheckException( std::move(msg_r) )
53       , _action( std::move(action_r) )
54       {}
55
56       /** Users final decision how to proceed */
57       const repo::DownloadResolvableReport::Action & action() const
58       { return _action; }
59
60     private:
61       repo::DownloadResolvableReport::Action _action;
62     };
63
64
65     ///////////////////////////////////////////////////////////////////
66     //  class PackageProviderPolicy
67     ///////////////////////////////////////////////////////////////////
68
69     bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
70                                                 const Edition &     ed_r,
71                                                 const Arch &        arch_r ) const
72     {
73       if ( _queryInstalledCB )
74         return _queryInstalledCB( name_r, ed_r, arch_r );
75       return false;
76     }
77
78     ///////////////////////////////////////////////////////////////////
79     /// \class PackageProvider::Impl
80     /// \brief PackageProvider implementation interface.
81     ///////////////////////////////////////////////////////////////////
82     struct PackageProvider::Impl : private base::NonCopyable
83     {
84       Impl() {}
85       virtual ~Impl() {}
86
87       /** Provide the package.
88        * The basic workflow.
89        * \throws Exception.
90        */
91       virtual ManagedFile providePackage() const = 0;
92
93       /** Provide the package if it is cached. */
94       virtual ManagedFile providePackageFromCache() const = 0;
95
96       /** Whether the package is cached. */
97       virtual bool isCached() const = 0;
98     };
99
100     ///////////////////////////////////////////////////////////////////
101     /// \class PackageProviderImpl<TPackage>
102     /// \brief PackageProvider implementation for \c Package and \c SrcPackage
103     ///////////////////////////////////////////////////////////////////
104     template <class TPackage>
105     class PackageProviderImpl : public PackageProvider::Impl
106     {
107       typedef typename TPackage::constPtr TPackagePtr;  // Package or SrcPackage
108       typedef callback::UserData UserData;
109     public:
110       /** Ctor taking the Package to provide. */
111       PackageProviderImpl( RepoMediaAccess & access_r, const TPackagePtr & package_r,
112                            const PackageProviderPolicy & policy_r )
113       : _policy( policy_r )
114       , _package( package_r )
115       , _access( access_r )
116       , _retry(false)
117       {}
118
119       virtual ~PackageProviderImpl() {}
120
121     public:
122       /** Provide the package.
123        * The basic workflow.
124        * \throws Exception.
125        */
126       virtual ManagedFile providePackage() const;
127
128       /** Provide the package if it is cached. */
129       virtual ManagedFile providePackageFromCache() const
130       {
131         ManagedFile ret( doProvidePackageFromCache() );
132         if ( ! ( ret->empty() ||  _package->repoInfo().keepPackages() ) )
133           ret.setDispose( filesystem::unlink );
134         return ret;
135       }
136
137       /** Whether the package is cached. */
138       virtual bool isCached() const
139       { return ! doProvidePackageFromCache()->empty(); }
140
141     protected:
142       typedef PackageProviderImpl<TPackage>     Base;
143       typedef callback::SendReport<repo::DownloadResolvableReport>      Report;
144
145       /** Lookup the final rpm in cache.
146        *
147        * A cache hit will return a non empty ManagedFile and an empty one on cache miss.
148        *
149        * \note File disposal depending on the repos keepPackages setting
150        * are not set here, but in \ref providePackage or \ref providePackageFromCache.
151        */
152       ManagedFile doProvidePackageFromCache() const
153       { return ManagedFile( _package->cachedLocation() ); }
154
155       /** Actually provide the final rpm.
156        * Report start/problem/finish and retry loop are hadled by \ref providePackage.
157        * Here you trigger just progress and delta/plugin callbacks as needed.
158        *
159        * Proxy method for progressPackageDownload is provided here.
160        * \code
161        * ProvideFilePolicy policy;
162        * policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
163        * return _access.provideFile( _package->repoInfo(), loc, policy );
164        * \endcode
165        *
166        * \note The provided default implementation retrieves the packages default
167        * location.
168        */
169       virtual ManagedFile doProvidePackage() const
170       {
171         ManagedFile ret;
172         OnMediaLocation loc = _package->location();
173
174         ProvideFilePolicy policy;
175         policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
176         policy.fileChecker( bind( &Base::rpmSigFileChecker, this, _1 ) );
177         return _access.provideFile( _package->repoInfo(), loc, policy );
178       }
179
180     protected:
181       /** Access to the DownloadResolvableReport */
182       Report & report() const
183       { return *_report; }
184
185       /** Redirect ProvideFilePolicy package download progress to this. */
186       bool progressPackageDownload( int value ) const
187       { return report()->progress( value, _package ); }
188
189
190       /** \name Validate a rpm packages signature.
191        *
192        * This is the \ref FileChecker passed down to the \ref Fetcher to validate
193        * a provided rpm package. This builtin checker includes the workflow
194        * communicating with the user in case of a problem with the package
195        * signature.
196        *
197        * \throws RpmSigCheckException if the package is not accepted, propagating
198        * the users decision how to proceed (\ref DownloadResolvableReport::Action).
199        *
200        * \note This check is also needed, if the the rpm is built locally by using
201        * delta rpms! \ref \see RpmPackageProvider
202        */
203       //@{
204       void rpmSigFileChecker( const Pathname & file_r ) const
205       {
206         RepoInfo info = _package->repoInfo();
207         if ( info.pkgGpgCheck() )
208         {
209           UserData userData( "pkgGpgCheck" );
210           ResObject::constPtr roptr( _package );        // gcc6 needs it more explcit. Has problem deducing
211           userData.set( "ResObject", roptr );           // a type for '_package->asKind<ResObject>()'...
212           /*legacy:*/userData.set( "Package", roptr->asKind<Package>() );
213           userData.set( "Localpath", file_r );
214
215           RpmDb::CheckPackageResult res = RpmDb::CHK_NOKEY;
216           while ( res == RpmDb::CHK_NOKEY ) {
217             res = packageSigCheck( file_r, info.pkgGpgCheckIsMandatory(), userData );
218
219             // publish the checkresult, even if it is OK. Apps may want to report something...
220             report()->pkgGpgCheck( userData );
221
222             if ( res == RpmDb::CHK_NOKEY ) {
223               // if the check fails because we don't know the key
224               // we try to resolv it with gpgkey urls from the
225               // repository, if available
226
227               target::rpm::RpmHeader::constPtr hr = target::rpm::RpmHeader::readPackage( file_r );
228               if ( !hr ) {
229                 // we did not find any information about the key in the header
230                 // this should never happen
231                 WAR << "Unable to read package header from " << hr << endl;
232                 break;
233               }
234
235               std::string keyID = hr->signatureKeyID();
236               if ( keyID.length() > 0 ) {
237                 if ( ! getZYpp()->keyRing()->provideAndImportKeyFromRepositoryWorkflow( keyID, info ) )
238                   break;
239
240               } else {
241                 // we did not find any information about the key in the header
242                 // this should never happen
243                 WAR << "packageSigCheck returned without setting providing missing key information" << endl;
244                 break;
245               }
246             }
247           }
248
249           if ( res != RpmDb::CHK_OK )
250           {
251             if ( userData.hasvalue( "Action" ) )        // pkgGpgCheck report provided an user error action
252             {
253               resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
254             }
255             else if ( userData.haskey( "Action" ) )     // pkgGpgCheck requests the default problem report (wo. details)
256             {
257               defaultReportSignatureError( res );
258             }
259             else                                        // no advice from user => usedefaults
260             {
261               switch ( res )
262               {
263                 case RpmDb::CHK_OK:             // Signature is OK
264                   break;
265
266                 case RpmDb::CHK_NOKEY:          // Public key is unavailable
267                 case RpmDb::CHK_NOTFOUND:       // Signature is unknown type
268                 case RpmDb::CHK_FAIL:           // Signature does not verify
269                 case RpmDb::CHK_NOTTRUSTED:     // Signature is OK, but key is not trusted
270                 case RpmDb::CHK_ERROR:          // File does not exist or can't be opened
271                 case RpmDb::CHK_NOSIG:          // File is unsigned
272                 default:
273                   // report problem (w. details), throw if to abort, else retry/ignore
274                   defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
275                   break;
276               }
277             }
278           }
279         }
280       }
281
282       typedef target::rpm::RpmDb RpmDb;
283
284       /** Actual rpm package signature check. */
285       RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, bool isMandatory_r, UserData & userData ) const
286       {
287         if ( !_target )
288           _target = getZYpp()->getTarget();
289
290         RpmDb::CheckPackageResult ret = RpmDb::CHK_ERROR;
291         RpmDb::CheckPackageDetail detail;
292         if ( _target )
293         {
294           ret = _target->rpmDb().checkPackageSignature( path_r, detail );
295           if ( ret == RpmDb::CHK_NOSIG && !isMandatory_r )
296           {
297             WAR << "Relax CHK_NOSIG: Config says unsigned packages are OK" << endl;
298             ret = RpmDb::CHK_OK;
299           }
300         }
301         else
302           detail.push_back( RpmDb::CheckPackageDetail::value_type( ret, "OOps. Target is not initialized!" ) );
303
304         userData.set( "CheckPackageResult", ret );
305         userData.set( "CheckPackageDetail", std::move(detail) );
306         return ret;
307       }
308
309       /** React on signature verification error user action.
310        * \note: IGNORE == accept insecure file (no SkipRequestException!)
311        */
312       void resolveSignatureErrorAction( repo::DownloadResolvableReport::Action action_r ) const
313       {
314         switch ( action_r )
315         {
316           case repo::DownloadResolvableReport::IGNORE:
317             WAR << _package->asUserString() << ": " << "User requested to accept insecure file" << endl;
318             break;
319           default:
320           case repo::DownloadResolvableReport::RETRY:
321           case repo::DownloadResolvableReport::ABORT:
322             ZYPP_THROW(RpmSigCheckException(action_r,"Signature verification failed"));
323             break;
324         }
325       }
326
327       /** Default signature verification error handling. */
328       void defaultReportSignatureError( RpmDb::CheckPackageResult ret, const std::string & detail_r = std::string() ) const
329       {
330         str::Str msg;
331         msg << _package->asUserString() << ": " << _("Signature verification failed") << " " << ret;
332         if ( ! detail_r.empty() )
333           msg << "\n" << detail_r;
334         resolveSignatureErrorAction( report()->problem( _package, repo::DownloadResolvableReport::INVALID, msg.str() ) );
335       }
336       //@}
337
338     protected:
339       PackageProviderPolicy     _policy;
340       TPackagePtr               _package;
341       RepoMediaAccess &         _access;
342
343     private:
344       typedef shared_ptr<void>  ScopedGuard;
345
346       ScopedGuard newReport() const
347       {
348         _report.reset( new Report );
349         // Use a custom deleter calling _report.reset() when guard goes out of
350         // scope (cast required as reset is overloaded). We want report to end
351         // when leaving providePackage and not wait for *this going out of scope.
352         return shared_ptr<void>( static_cast<void*>(0),
353                                  bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
354                                        ref(_report) ) );
355       }
356
357       mutable bool               _retry;
358       mutable shared_ptr<Report> _report;
359       mutable Target_Ptr         _target;
360     };
361     ///////////////////////////////////////////////////////////////////
362
363     template <class TPackage>
364     ManagedFile PackageProviderImpl<TPackage>::providePackage() const
365     {
366       ScopedGuard guardReport( newReport() );
367
368       // check for cache hit:
369       ManagedFile ret( providePackageFromCache() );
370       if ( ! ret->empty() )
371       {
372         MIL << "provided Package from cache " << _package << " at " << ret << endl;
373         report()->infoInCache( _package, ret );
374         return ret; // <-- cache hit
375       }
376
377       // HERE: cache misss, check toplevel cache or do download:
378       RepoInfo info = _package->repoInfo();
379
380       // Check toplevel cache
381       {
382         RepoManagerOptions topCache;
383         if ( info.packagesPath().dirname() != topCache.repoPackagesCachePath )  // not using toplevel cache
384         {
385           const OnMediaLocation & loc( _package->location() );
386           if ( ! loc.checksum().empty() )       // no cache hit without checksum
387           {
388             PathInfo pi( topCache.repoPackagesCachePath / info.packagesPath().basename() / info.path() / loc.filename() );
389             if ( pi.isExist() && loc.checksum() == CheckSum( loc.checksum().type(), std::ifstream( pi.c_str() ) ) )
390             {
391               report()->start( _package, pi.path().asFileUrl() );
392               const Pathname & dest( info.packagesPath() / info.path() / loc.filename() );
393               if ( filesystem::assert_dir( dest.dirname() ) == 0 && filesystem::hardlinkCopy( pi.path(), dest ) == 0 )
394               {
395                 ret = ManagedFile( dest );
396                 if ( ! info.keepPackages() )
397                   ret.setDispose( filesystem::unlink );
398
399                 MIL << "provided Package from toplevel cache " << _package << " at " << ret << endl;
400                 report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
401                 return ret; // <-- toplevel cache hit
402               }
403             }
404           }
405         }
406       }
407
408       // FIXME we only support the first url for now.
409       if ( info.baseUrlsEmpty() )
410         ZYPP_THROW(Exception("No url in repository."));
411
412       MIL << "provide Package " << _package << endl;
413       Url url = * info.baseUrlsBegin();
414       try {
415       do {
416         _retry = false;
417         if ( ! ret->empty() )
418         {
419           ret.setDispose( filesystem::unlink );
420           ret.reset();
421         }
422         report()->start( _package, url );
423         try
424           {
425             ret = doProvidePackage();
426           }
427         catch ( const UserRequestException & excpt )
428           {
429             ERR << "Failed to provide Package " << _package << endl;
430             if ( ! _retry )
431               ZYPP_RETHROW( excpt );
432           }
433         catch ( const RpmSigCheckException & excpt )
434           {
435             ERR << "Failed to provide Package " << _package << endl;
436             if ( ! _retry )
437             {
438               // Signature verification error was already reported by the
439               // rpmSigFileChecker. Just handle the users action decision:
440               switch ( excpt.action() )
441               {
442                 case repo::DownloadResolvableReport::RETRY:
443                   _retry = true;
444                   break;
445                 case repo::DownloadResolvableReport::IGNORE:
446                   ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
447                   break;
448                 default:
449                 case repo::DownloadResolvableReport::ABORT:
450                   ZYPP_THROW(AbortRequestException("User requested to abort"));
451                   break;
452               }
453             }
454           }
455         catch ( const FileCheckException & excpt )
456           {
457             ERR << "Failed to provide Package " << _package << endl;
458             if ( ! _retry )
459             {
460               const std::string & package_str = _package->asUserString();
461               // TranslatorExplanation %s = package being checked for integrity
462               switch ( report()->problem( _package, repo::DownloadResolvableReport::INVALID, str::form(_("Package %s seems to be corrupted during transfer. Do you want to retry retrieval?"), package_str.c_str() ) ) )
463               {
464                 case repo::DownloadResolvableReport::RETRY:
465                   _retry = true;
466                   break;
467                 case repo::DownloadResolvableReport::IGNORE:
468                   ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
469                   break;
470                 default:
471                 case repo::DownloadResolvableReport::ABORT:
472                   ZYPP_THROW(AbortRequestException("User requested to abort"));
473                   break;
474               }
475             }
476           }
477         catch ( const Exception & excpt )
478           {
479             ERR << "Failed to provide Package " << _package << endl;
480             if ( ! _retry )
481             {
482                 // Aything else gets reported
483                 const std::string & package_str = _package->asUserString();
484
485                 // TranslatorExplanation %s = name of the package being processed.
486                 std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
487                 detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
488
489                 switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
490                 {
491                       case repo::DownloadResolvableReport::RETRY:
492                         _retry = true;
493                         break;
494                       case repo::DownloadResolvableReport::IGNORE:
495                         ZYPP_THROW(SkipRequestException("User requested skip of file", excpt));
496                         break;
497                       default:
498                       case repo::DownloadResolvableReport::ABORT:
499                         ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
500                         break;
501                 }
502               }
503           }
504       } while ( _retry );
505       } catch(...){
506         // bsc#1045735: Be sure no invalid files stay in the cache!
507         if ( ! ret->empty() )
508           ret.setDispose( filesystem::unlink );
509         throw;
510       }
511
512       report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
513       MIL << "provided Package " << _package << " at " << ret << endl;
514       return ret;
515     }
516
517
518     ///////////////////////////////////////////////////////////////////
519     /// \class RpmPackageProvider
520     /// \brief RPM PackageProvider implementation (with deltarpm processing).
521     ///////////////////////////////////////////////////////////////////
522     class RpmPackageProvider : public PackageProviderImpl<Package>
523     {
524     public:
525       RpmPackageProvider( RepoMediaAccess & access_r,
526                           const Package::constPtr & package_r,
527                           const DeltaCandidates & deltas_r,
528                           const PackageProviderPolicy & policy_r )
529       : PackageProviderImpl<Package>( access_r, package_r, policy_r )
530       , _deltas( deltas_r )
531       {}
532
533     protected:
534       virtual ManagedFile doProvidePackage() const;
535
536     private:
537       typedef packagedelta::DeltaRpm    DeltaRpm;
538
539       ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
540
541       bool progressDeltaDownload( int value ) const
542       { return report()->progressDeltaDownload( value ); }
543
544       void progressDeltaApply( int value ) const
545       { return report()->progressDeltaApply( value ); }
546
547       bool queryInstalled( const Edition & ed_r = Edition() ) const
548       { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
549
550     private:
551       DeltaCandidates           _deltas;
552     };
553     ///////////////////////////////////////////////////////////////////
554
555     ManagedFile RpmPackageProvider::doProvidePackage() const
556     {
557       // check whether to process patch/delta rpms
558       // FIXME we only check the first url for now.
559       if ( ZConfig::instance().download_use_deltarpm()
560         && ( _package->repoInfo().url().schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) )
561       {
562         std::list<DeltaRpm> deltaRpms;
563         _deltas.deltaRpms( _package ).swap( deltaRpms );
564
565         if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() )
566         {
567           for_( it, deltaRpms.begin(), deltaRpms.end())
568           {
569             DBG << "tryDelta " << *it << endl;
570             ManagedFile ret( tryDelta( *it ) );
571             if ( ! ret->empty() )
572               return ret;
573           }
574         }
575       }
576
577       // no patch/delta -> provide full package
578       return Base::doProvidePackage();
579     }
580
581     ManagedFile RpmPackageProvider::tryDelta( const DeltaRpm & delta_r ) const
582     {
583       if ( delta_r.baseversion().edition() != Edition::noedition
584            && ! queryInstalled( delta_r.baseversion().edition() ) )
585         return ManagedFile();
586
587       if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
588         return ManagedFile();
589
590       report()->startDeltaDownload( delta_r.location().filename(),
591                                     delta_r.location().downloadSize() );
592       ManagedFile delta;
593       try
594         {
595           ProvideFilePolicy policy;
596           policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) );
597           delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
598         }
599       catch ( const Exception & excpt )
600         {
601           report()->problemDeltaDownload( excpt.asUserHistory() );
602           return ManagedFile();
603         }
604       report()->finishDeltaDownload();
605
606       report()->startDeltaApply( delta );
607       if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
608         {
609           report()->problemDeltaApply( _("applydeltarpm check failed.") );
610           return ManagedFile();
611         }
612
613       // Build the package
614       Pathname cachedest( _package->repoInfo().packagesPath() / _package->repoInfo().path() / _package->location().filename() );
615       Pathname builddest( cachedest.extend( ".drpm" ) );
616
617       if ( ! applydeltarpm::provide( delta, builddest,
618                                      bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
619         {
620           report()->problemDeltaApply( _("applydeltarpm failed.") );
621           return ManagedFile();
622         }
623       ManagedFile builddestCleanup( builddest, filesystem::unlink );
624       report()->finishDeltaApply();
625
626       // Check and move it into the cache
627       // Here the rpm itself is ready. If the packages sigcheck fails, it
628       // makes no sense to return a ManagedFile() and fallback to download the
629       // full rpm. It won't be different. So let the exceptions escape...
630       rpmSigFileChecker( builddest );
631       if ( filesystem::hardlinkCopy( builddest, cachedest ) != 0 )
632         ZYPP_THROW( Exception( str::Str() << "Can't hardlink/copy " << builddest << " to " << cachedest ) );
633
634       return ManagedFile( cachedest, filesystem::unlink );
635     }
636
637     ///////////////////////////////////////////////////////////////////
638     //  class PackageProvider
639     ///////////////////////////////////////////////////////////////////
640     namespace factory
641     {
642       inline PackageProvider::Impl * make( RepoMediaAccess & access_r, const PoolItem & pi_r,
643                                            const DeltaCandidates & deltas_r,
644                                            const PackageProviderPolicy & policy_r )
645       {
646         if ( pi_r.isKind<Package>() )
647           return new RpmPackageProvider( access_r, pi_r->asKind<Package>(), deltas_r, policy_r );
648         else if ( pi_r.isKind<SrcPackage>() )
649           return new PackageProviderImpl<SrcPackage>( access_r, pi_r->asKind<SrcPackage>(), policy_r );
650         else
651           ZYPP_THROW( Exception( str::Str() << "Don't know how to cache non-package " << pi_r.asUserString() ) );
652       }
653
654       inline PackageProvider::Impl * make( RepoMediaAccess & access_r, const PoolItem & pi_r,
655                                                   const PackageProviderPolicy & policy_r )
656       {
657         if ( pi_r.isKind<Package>() )
658           return new PackageProviderImpl<Package>( access_r, pi_r->asKind<Package>(), policy_r );
659         else if ( pi_r.isKind<SrcPackage>() )
660           return new PackageProviderImpl<SrcPackage>( access_r, pi_r->asKind<SrcPackage>(), policy_r );
661         else
662           ZYPP_THROW( Exception( str::Str() << "Don't know how to cache non-package " << pi_r.asUserString() ) );
663       }
664
665       inline PackageProvider::Impl * make( RepoMediaAccess & access_r, const Package::constPtr & package_r,
666                                            const DeltaCandidates & deltas_r,
667                                            const PackageProviderPolicy & policy_r )
668       { return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r ); }
669
670     } // namespace factory
671     ///////////////////////////////////////////////////////////////////
672
673     PackageProvider::PackageProvider( RepoMediaAccess & access_r, const PoolItem & pi_r,
674                                       const DeltaCandidates & deltas_r, const PackageProviderPolicy & policy_r )
675
676     : _pimpl( factory::make( access_r, pi_r, deltas_r, policy_r ) )
677     {}
678
679     PackageProvider::PackageProvider( RepoMediaAccess & access_r, const PoolItem & pi_r,
680                                       const PackageProviderPolicy & policy_r )
681     : _pimpl( factory::make( access_r, pi_r, policy_r ) )
682     {}
683
684     /* legacy */
685     PackageProvider::PackageProvider( RepoMediaAccess & access_r,
686                                       const Package::constPtr & package_r,
687                                       const DeltaCandidates & deltas_r,
688                                       const PackageProviderPolicy & policy_r )
689     : _pimpl( factory::make( access_r, package_r, deltas_r, policy_r ) )
690     {}
691
692     PackageProvider::~PackageProvider()
693     {}
694
695     ManagedFile PackageProvider::providePackage() const
696     { return _pimpl->providePackage(); }
697
698     ManagedFile PackageProvider::providePackageFromCache() const
699     { return _pimpl->providePackageFromCache(); }
700
701     bool PackageProvider::isCached() const
702     { return _pimpl->isCached(); }
703
704   } // namespace repo
705   ///////////////////////////////////////////////////////////////////
706 } // namespace zypp
707 ///////////////////////////////////////////////////////////////////