libzypp  15.21.1
PackageProvider.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
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"
19 #include "zypp/base/NonCopyable.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 
29 #include "zypp/ZYppFactory.h"
30 #include "zypp/Target.h"
31 #include "zypp/target/rpm/RpmDb.h"
32 #include "zypp/FileChecker.h"
33 
34 using std::endl;
35 
37 namespace zypp
38 {
40  namespace repo
41  {
43  // class PackageProviderPolicy
45 
46  bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
47  const Edition & ed_r,
48  const Arch & arch_r ) const
49  {
50  if ( _queryInstalledCB )
51  return _queryInstalledCB( name_r, ed_r, arch_r );
52  return false;
53  }
54 
55 
61  {
63  public:
65  Impl( RepoMediaAccess & access_r,
66  const Package::constPtr & package_r,
67  const DeltaCandidates & deltas_r,
68  const PackageProviderPolicy & policy_r )
69  : _policy( policy_r )
70  , _package( package_r )
71  , _deltas( deltas_r )
72  , _access( access_r )
73  , _retry(false)
74  {}
75 
76  virtual ~Impl() {}
77 
82  static Impl * factoryMake( RepoMediaAccess & access_r,
83  const Package::constPtr & package_r,
84  const DeltaCandidates & deltas_r,
85  const PackageProviderPolicy & policy_r );
86 
87  public:
93 
96  {
98  if ( ! ( ret->empty() || _package->repoInfo().keepPackages() ) )
100  return ret;
101  }
102 
104  bool isCached() const
105  { return ! doProvidePackageFromCache()->empty(); }
106 
107  protected:
110 
121  virtual ManagedFile doProvidePackageFromCache() const = 0;
122 
140  virtual ManagedFile doProvidePackage() const = 0;
141 
142  protected:
144  Report & report() const
145  { return *_report; }
146 
148  bool progressPackageDownload( int value ) const
149  { return report()->progress( value, _package ); }
150 
152  bool failOnChecksumError() const
153  {
154  std::string package_str = _package->name() + "-" + _package->edition().asString();
155 
156  // TranslatorExplanation %s = package being checked for integrity
157  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() ) ) )
158  {
160  _retry = true;
161  break;
163  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
164  break;
166  ZYPP_THROW(AbortRequestException("User requested to abort"));
167  break;
168  default:
169  break;
170  }
171  return true; // anyway a failure
172  }
173 
175 
176  RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, UserData & userData ) const
177  {
178  if ( !_target )
179  _target = getZYpp()->getTarget();
180 
183  if ( _target )
184  ret = _target->rpmDb().checkPackage( path_r, detail );
185  else
186  detail.push_back( RpmDb::CheckPackageDetail::value_type( ret, "OOps. Target is not initialized!" ) );
187 
188  userData.set( "CheckPackageResult", ret );
189  userData.set( "CheckPackageDetail", std::move(detail) );
190  return ret;
191  }
192 
195  {
196  // TranslatorExplanation %s = package being checked for integrity
197  switch ( action_r )
198  {
200  _retry = true;
201  break;
203  WAR << _package->asUserString() << ": " << "User requested skip of insecure file" << endl;
204  break;
205  default:
207  ZYPP_THROW(AbortRequestException("User requested to abort"));
208  break;
209  }
210  }
211 
213  void defaultReportSignatureError( RpmDb::CheckPackageResult ret, const std::string & detail_r = std::string() ) const
214  {
215  str::Str msg;
216  msg << _package->asUserString() << ": " << _("Signature verification failed") << " " << ret;
217  if ( ! detail_r.empty() )
218  msg << "\n" << detail_r;
220  }
221 
222  protected:
227 
228  private:
229  typedef shared_ptr<void> ScopedGuard;
230 
232  {
233  _report.reset( new Report );
234  // Use a custom deleter calling _report.reset() when guard goes out of
235  // scope (cast required as reset is overloaded). We want report to end
236  // when leaving providePackage and not wait for *this going out of scope.
237  return shared_ptr<void>( static_cast<void*>(0),
238  bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
239  ref(_report) ) );
240  }
241 
242  mutable bool _retry;
243  mutable shared_ptr<Report> _report;
244  mutable Target_Ptr _target;
245  };
247 
250  { return ManagedFile(); }
251 
254  {
255  ManagedFile ret;
256  OnMediaLocation loc = _package->location();
257 
258  ProvideFilePolicy policy;
259  policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
260  policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
261  return _access.provideFile( _package->repoInfo(), loc, policy );
262  }
263 
265 
267  {
268  ScopedGuard guardReport( newReport() );
269 
270  // check for cache hit:
272  if ( ! ret->empty() )
273  {
274  MIL << "provided Package from cache " << _package << " at " << ret << endl;
275  report()->infoInCache( _package, ret );
276  return ret; // <-- cache hit
277  }
278 
279  // HERE: cache misss, check toplevel cache or do download:
280  RepoInfo info = _package->repoInfo();
281 
282  // Check toplevel cache
283  {
284  RepoManagerOptions topCache;
285  if ( info.packagesPath().dirname() != topCache.repoPackagesCachePath ) // not using toplevel cache
286  {
287  const OnMediaLocation & loc( _package->location() );
288  if ( ! loc.checksum().empty() ) // no cache hit without checksum
289  {
290  PathInfo pi( topCache.repoPackagesCachePath / info.packagesPath().basename() / loc.filename() );
291  if ( pi.isExist() && loc.checksum() == CheckSum( loc.checksum().type(), std::ifstream( pi.c_str() ) ) )
292  {
293  report()->start( _package, pi.path().asFileUrl() );
294  const Pathname & dest( info.packagesPath() / loc.filename() );
295  if ( filesystem::assert_dir( dest.dirname() ) == 0 && filesystem::hardlinkCopy( pi.path(), dest ) == 0 )
296  {
297  ret = ManagedFile( dest );
298  if ( ! info.keepPackages() )
300 
301  MIL << "provided Package from toplevel cache " << _package << " at " << ret << endl;
302  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
303  return ret; // <-- toplevel cache hit
304  }
305  }
306  }
307  }
308  }
309 
310  // FIXME we only support the first url for now.
311  if ( info.baseUrlsEmpty() )
312  ZYPP_THROW(Exception("No url in repository."));
313 
314  MIL << "provide Package " << _package << endl;
315  Url url = * info.baseUrlsBegin();
316  do {
317  _retry = false;
318  if ( ! ret->empty() )
319  {
321  ret.reset();
322  }
323  report()->start( _package, url );
324  try
325  {
326  ret = doProvidePackage();
327 
328  if ( info.pkgGpgCheck() )
329  {
330  UserData userData( "pkgGpgCheck" );
331  userData.set( "Package", _package );
332  userData.set( "Localpath", ret.value() );
333  RpmDb::CheckPackageResult res = packageSigCheck( ret, userData );
334  // publish the checkresult, even if it is OK. Apps may want to report something...
335  report()->pkgGpgCheck( userData );
336 
337  if ( res != RpmDb::CHK_OK )
338  {
339  if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action
340  {
341  resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
342  }
343  else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details)
344  {
345  defaultReportSignatureError( res );
346  }
347  else // no advice from user => usedefaults
348  {
349  switch ( res )
350  {
351  case RpmDb::CHK_OK: // Signature is OK
352  break;
353 
354  case RpmDb::CHK_NOKEY: // Public key is unavailable
355  case RpmDb::CHK_NOTFOUND: // Signature is unknown type
356  case RpmDb::CHK_FAIL: // Signature does not verify
357  case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted
358  case RpmDb::CHK_ERROR: // File does not exist or can't be opened
359  default:
360  // report problem (w. details), throw if to abort, else retry/ignore
361  defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
362  break;
363  }
364  }
365  }
366  }
367  }
368  catch ( const UserRequestException & excpt )
369  {
370  // UserRequestException e.g. from failOnChecksumError was already reported.
371  ERR << "Failed to provide Package " << _package << endl;
372  if ( ! _retry )
373  {
374  ZYPP_RETHROW( excpt );
375  }
376  }
377  catch ( const Exception & excpt )
378  {
379  ERR << "Failed to provide Package " << _package << endl;
380  if ( ! _retry )
381  {
382  // Aything else gets reported
383  std::string package_str = _package->name() + "-" + _package->edition().asString();
384 
385  // TranslatorExplanation %s = name of the package being processed.
386  std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
387  detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
388 
389  switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
390  {
392  _retry = true;
393  break;
395  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
396  break;
398  ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
399  break;
400  default:
401  ZYPP_RETHROW( excpt );
402  break;
403  }
404  }
405  }
406  } while ( _retry );
407 
408  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
409  MIL << "provided Package " << _package << " at " << ret << endl;
410  return ret;
411  }
412 
413 
419  {
420  public:
422  const Package::constPtr & package_r,
423  const DeltaCandidates & deltas_r,
424  const PackageProviderPolicy & policy_r )
425  : PackageProvider::Impl( access_r, package_r, deltas_r, policy_r )
426  {}
427 
428  protected:
429  virtual ManagedFile doProvidePackageFromCache() const;
430 
431  virtual ManagedFile doProvidePackage() const;
432 
433  private:
435 
436  ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
437 
438  bool progressDeltaDownload( int value ) const
439  { return report()->progressDeltaDownload( value ); }
440 
441  void progressDeltaApply( int value ) const
442  { return report()->progressDeltaApply( value ); }
443 
444  bool queryInstalled( const Edition & ed_r = Edition() ) const
445  { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
446  };
448 
450  {
451  return ManagedFile( _package->cachedLocation() );
452  }
453 
455  {
456  Url url;
457  RepoInfo info = _package->repoInfo();
458  // FIXME we only support the first url for now.
459  if ( info.baseUrlsEmpty() )
460  ZYPP_THROW(Exception("No url in repository."));
461  else
462  url = * info.baseUrlsBegin();
463 
464  // check whether to process patch/delta rpms
465  if ( ZConfig::instance().download_use_deltarpm()
467  {
468  std::list<DeltaRpm> deltaRpms;
469  _deltas.deltaRpms( _package ).swap( deltaRpms );
470 
471  if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() )
472  {
473  for_( it, deltaRpms.begin(), deltaRpms.end())
474  {
475  DBG << "tryDelta " << *it << endl;
476  ManagedFile ret( tryDelta( *it ) );
477  if ( ! ret->empty() )
478  return ret;
479  }
480  }
481  }
482 
483  // no patch/delta -> provide full package
484  return Base::doProvidePackage();
485  }
486 
488  {
489  if ( delta_r.baseversion().edition() != Edition::noedition
490  && ! queryInstalled( delta_r.baseversion().edition() ) )
491  return ManagedFile();
492 
493  if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
494  return ManagedFile();
495 
496  report()->startDeltaDownload( delta_r.location().filename(),
497  delta_r.location().downloadSize() );
498  ManagedFile delta;
499  try
500  {
501  ProvideFilePolicy policy;
502  policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) );
503  delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
504  }
505  catch ( const Exception & excpt )
506  {
507  report()->problemDeltaDownload( excpt.asUserHistory() );
508  return ManagedFile();
509  }
510  report()->finishDeltaDownload();
511 
512  report()->startDeltaApply( delta );
513  if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
514  {
515  report()->problemDeltaApply( _("applydeltarpm check failed.") );
516  return ManagedFile();
517  }
518 
519  // build the package and put it into the cache
520  Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
521 
522  if ( ! applydeltarpm::provide( delta, destination,
523  bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
524  {
525  report()->problemDeltaApply( _("applydeltarpm failed.") );
526  return ManagedFile();
527  }
528  report()->finishDeltaApply();
529 
530  return ManagedFile( destination, filesystem::unlink );
531  }
532 
533 #if 0
534  class PluginPackageProvider : public PackageProvider::Impl
542  {
543  public:
544  PluginPackageProvider( const std::string & stem_r,
545  RepoMediaAccess & access_r,
546  const Package::constPtr & package_r,
547  const DeltaCandidates & deltas_r,
548  const PackageProviderPolicy & policy_r )
549  : Base( access_r, package_r, deltas_r, policy_r )
550  {}
551 
552  protected:
553  virtual ManagedFile doProvidePackageFromCache() const
554  {
555  return Base::doProvidePackageFromCache();
556  }
557 
558  virtual ManagedFile doProvidePackage() const
559  {
560  return Base::doProvidePackage();
561  }
562  };
564 #endif
565 
567  // class PackageProvider
569 
571  const Package::constPtr & package_r,
572  const DeltaCandidates & deltas_r,
573  const PackageProviderPolicy & policy_r )
574  {
575  return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r );
576  }
577 
579  const Package::constPtr & package_r,
580  const DeltaCandidates & deltas_r,
581  const PackageProviderPolicy & policy_r )
582  : _pimpl( Impl::factoryMake( access_r, package_r, deltas_r, policy_r ) )
583  {}
584 
586  {}
587 
589  { return _pimpl->providePackage(); }
590 
592  { return _pimpl->providePackageFromCache(); }
593 
595  { return _pimpl->isCached(); }
596 
597  } // namespace repo
599 } // namespace zypp
Candidate delta and patches for a package.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:320
RepoInfo info() const
Return any associated RepoInfo.
Definition: Repository.cc:273
Interface to gettext.
Interface to the rpm program.
Definition: RpmDb.h:47
#define MIL
Definition: Logger.h:64
bool failOnChecksumError() const
Redirect ProvideFilePolicy failOnChecksumError to this if needed.
virtual ManagedFile doProvidePackageFromCache() const
Lookup the final rpm in cache.
RpmDb::CheckPackageResult packageSigCheck(const Pathname &path_r, UserData &userData) const
const Repository & repository() const
Definition: PackageDelta.h:70
PackageProvider implementation.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:321
Describes a path on a certain media amongs as the information required to download it...
bool hasvalue(const std::string &key_r) const
Whether key_r is in data and value is not empty.
Definition: UserData.h:101
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:121
const BaseVersion & baseversion() const
Definition: PackageDelta.h:69
ManagedFile providePackage() const
Provide the package.
bool isCached() const
Whether the package is cached.
Architecture.
Definition: Arch.h:36
ManagedFile tryDelta(const DeltaRpm &delta_r) const
void reset()
Reset to default Ctor values.
Definition: AutoDispose.h:145
urls_const_iterator baseUrlsBegin() const
iterator that points at begin of repository urls
Definition: RepoInfo.cc:417
callback::SendReport< repo::DownloadResolvableReport > Report
bool isCached() const
Whether the package is cached.
Policies and options for PackageProvider.
bool haveApplydeltarpm()
Test whether an execuatble applydeltarpm program is available.
bool pkgGpgCheck() const
Whether the signature of rpm packages should be checked for this repo.
Definition: RepoInfo.cc:296
What is known about a repository.
Definition: RepoInfo.h:71
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
Edition represents [epoch:]version[-release]
Definition: Edition.h:60
void progressDeltaApply(int value) const
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
Report & report() const
Access to the DownloadResolvableReport.
Pathname packagesPath() const
Path where this repo packages are cached.
Definition: RepoInfo.cc:381
#define ERR
Definition: Logger.h:66
bool queryInstalled(const Edition &ed_r=Edition()) const
ManagedFile providePackageFromCache() const
Provide the package if it is cached.
Repo manager settings.
Definition: RepoManager.h:53
Policy for provideFile.
std::string str() const
Definition: String.h:220
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:329
RW_pointer< Impl > _pimpl
Implementation class.
PackageProvider(RepoMediaAccess &access, const Package::constPtr &package, const DeltaCandidates &deltas, const PackageProviderPolicy &policy_r=PackageProviderPolicy())
Ctor taking the Package to provide.
const Tp & get(const std::string &key_r) const
Pass back a const Tp & reference to key_r value.
Definition: UserData.h:175
packagedelta::DeltaRpm DeltaRpm
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
bool keepPackages() const
Whether packages downloaded from this repository will be kept in local cache.
Definition: RepoInfo.cc:375
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:210
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:653
ManagedFile providePackageFromCache() const
Provide the package if it is cached.
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition: UserData.h:118
#define WAR
Definition: Logger.h:65
Detailed rpm signature check log messages A single multiline message if CHK_OK.
Definition: RpmDb.h:443
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:808
zypp::Url url
Definition: MediaCurl.cc:192
bool progressPackageDownload(int value) const
Redirect ProvideFilePolicy package download progress to this.
RpmPackageProvider(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
#define _(MSG)
Definition: Gettext.h:29
reference value() const
Reference to the Tp object.
Definition: AutoDispose.h:133
const OnMediaLocation & location() const
Definition: PackageDelta.h:68
virtual ManagedFile doProvidePackage() const
Actually provide the final rpm.
Provides files from different repos.
bool baseUrlsEmpty() const
whether repository urls are available
Definition: RepoInfo.cc:426
ProvideFilePolicy & failOnChecksumErrorCB(FailOnChecksumErrorCB failOnChecksumErrorCB_r)
Set callback.
void setDispose(const Dispose &dispose_r)
Set a new dispose function.
Definition: AutoDispose.h:158
const std::string & sequenceinfo() const
Definition: PackageDelta.h:46
virtual ManagedFile doProvidePackageFromCache() const =0
Lookup the final rpm in cache.
Base class for Exception.
Definition: Exception.h:143
ProvideFilePolicy & progressCB(ProgressCB progressCB_r)
Set callback.
Provide a package from a Repo.
Impl(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
Ctor taking the Package to provide.
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:177
const Pathname & filename() const
The path to the resource relatve to the url and path.
ManagedFile providePackage() const
Provide the package.
void defaultReportSignatureError(RpmDb::CheckPackageResult ret, const std::string &detail_r=std::string()) const
Default signature verrification error handling.
Typesafe passing of user data via callbacks.
Definition: UserData.h:38
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:92
shared_ptr< MediaSetAccess > _access
RPM PackageProvider implementation.
Pathname repoPackagesCachePath
Definition: RepoManager.h:82
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:75
CheckPackageResult
checkPackage result
Definition: RpmDb.h:429
bool quickcheck(const std::string &sequenceinfo_r)
Quick via check sequence info.
Definition: Applydeltarpm.h:48
bool check(const std::string &sequenceinfo_r, bool quick_r)
Check via sequence info.
virtual ManagedFile doProvidePackage() const =0
Actually provide the final rpm.
bool queryInstalled(const std::string &name_r, const Edition &ed_r, const Arch &arch_r) const
Evaluate callback.
bool haskey(const std::string &key_r) const
Whether key_r is in data.
Definition: UserData.h:97
bool progressDeltaDownload(int value) const
Base for exceptions caused by explicit user request.
static bool schemeIsDownloading(const std::string &scheme_r)
http https ftp sftp tftp
Definition: Url.cc:474
void resolveSignatureErrorAction(repo::DownloadResolvableReport::Action action_r) const
React on signature verrification error user action.
const ByteCount & downloadSize() const
The size of the resource on the server.
bool provide(const Pathname &delta_r, const Pathname &new_r, const Progress &report_r)
Apply a binary delta to on-disk data to re-create a new rpm.
Url manipulation class.
Definition: Url.h:87
TraitsType::constPtrType constPtr
Definition: Package.h:38
bool download_use_deltarpm_always() const
Whether to consider using a deltarpm even when rpm is local.
Definition: ZConfig.cc:961
#define DBG
Definition: Logger.h:63
static const Edition noedition
Value representing noedition ("") This is in fact a valid Edition.
Definition: Edition.h:73
static Impl * factoryMake(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
Factory method providing the appropriate implementation.