libzypp  15.24.2
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 
137  virtual ManagedFile doProvidePackage() const = 0;
138 
139  protected:
141  Report & report() const
142  { return *_report; }
143 
145  bool progressPackageDownload( int value ) const
146  { return report()->progress( value, _package ); }
147 
149 
150  RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, UserData & userData ) const
151  {
152  if ( !_target )
153  _target = getZYpp()->getTarget();
154 
157  if ( _target )
158  ret = _target->rpmDb().checkPackage( path_r, detail );
159  else
160  detail.push_back( RpmDb::CheckPackageDetail::value_type( ret, "OOps. Target is not initialized!" ) );
161 
162  userData.set( "CheckPackageResult", ret );
163  userData.set( "CheckPackageDetail", std::move(detail) );
164  return ret;
165  }
166 
171  {
172  switch ( action_r )
173  {
175  _retry = true;
176  break;
178  WAR << _package->asUserString() << ": " << "User requested to accept insecure file" << endl;
179  break;
180  default:
182  ZYPP_THROW(AbortRequestException("User requested to abort"));
183  break;
184  }
185  }
186 
188  void defaultReportSignatureError( RpmDb::CheckPackageResult ret, const std::string & detail_r = std::string() ) const
189  {
190  str::Str msg;
191  msg << _package->asUserString() << ": " << _("Signature verification failed") << " " << ret;
192  if ( ! detail_r.empty() )
193  msg << "\n" << detail_r;
195  }
196 
197  protected:
202 
203  private:
204  typedef shared_ptr<void> ScopedGuard;
205 
207  {
208  _report.reset( new Report );
209  // Use a custom deleter calling _report.reset() when guard goes out of
210  // scope (cast required as reset is overloaded). We want report to end
211  // when leaving providePackage and not wait for *this going out of scope.
212  return shared_ptr<void>( static_cast<void*>(0),
213  bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
214  ref(_report) ) );
215  }
216 
217  mutable bool _retry;
218  mutable shared_ptr<Report> _report;
219  mutable Target_Ptr _target;
220  };
222 
225  { return ManagedFile(); }
226 
229  {
230  ManagedFile ret;
231  OnMediaLocation loc = _package->location();
232 
233  ProvideFilePolicy policy;
234  policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
235  return _access.provideFile( _package->repoInfo(), loc, policy );
236  }
237 
239 
241  {
242  ScopedGuard guardReport( newReport() );
243 
244  // check for cache hit:
246  if ( ! ret->empty() )
247  {
248  MIL << "provided Package from cache " << _package << " at " << ret << endl;
249  report()->infoInCache( _package, ret );
250  return ret; // <-- cache hit
251  }
252 
253  // HERE: cache misss, check toplevel cache or do download:
254  RepoInfo info = _package->repoInfo();
255 
256  // Check toplevel cache
257  {
258  RepoManagerOptions topCache;
259  if ( info.packagesPath().dirname() != topCache.repoPackagesCachePath ) // not using toplevel cache
260  {
261  const OnMediaLocation & loc( _package->location() );
262  if ( ! loc.checksum().empty() ) // no cache hit without checksum
263  {
264  PathInfo pi( topCache.repoPackagesCachePath / info.packagesPath().basename() / loc.filename() );
265  if ( pi.isExist() && loc.checksum() == CheckSum( loc.checksum().type(), std::ifstream( pi.c_str() ) ) )
266  {
267  report()->start( _package, pi.path().asFileUrl() );
268  const Pathname & dest( info.packagesPath() / loc.filename() );
269  if ( filesystem::assert_dir( dest.dirname() ) == 0 && filesystem::hardlinkCopy( pi.path(), dest ) == 0 )
270  {
271  ret = ManagedFile( dest );
272  if ( ! info.keepPackages() )
274 
275  MIL << "provided Package from toplevel cache " << _package << " at " << ret << endl;
276  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
277  return ret; // <-- toplevel cache hit
278  }
279  }
280  }
281  }
282  }
283 
284  // FIXME we only support the first url for now.
285  if ( info.baseUrlsEmpty() )
286  ZYPP_THROW(Exception("No url in repository."));
287 
288  MIL << "provide Package " << _package << endl;
289  Url url = * info.baseUrlsBegin();
290  do {
291  _retry = false;
292  if ( ! ret->empty() )
293  {
295  ret.reset();
296  }
297  report()->start( _package, url );
298  try
299  {
300  ret = doProvidePackage();
301 
302  if ( info.pkgGpgCheck() )
303  {
304  UserData userData( "pkgGpgCheck" );
305  userData.set( "Package", _package );
306  userData.set( "Localpath", ret.value() );
307  RpmDb::CheckPackageResult res = packageSigCheck( ret, userData );
308  // publish the checkresult, even if it is OK. Apps may want to report something...
309  report()->pkgGpgCheck( userData );
310 USR << "CHK: " << res << endl;
311  if ( res != RpmDb::CHK_OK )
312  {
313  if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action
314  {
315  resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
316  }
317  else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details)
318  {
319  defaultReportSignatureError( res );
320  }
321  else // no advice from user => usedefaults
322  {
323  switch ( res )
324  {
325  case RpmDb::CHK_OK: // Signature is OK
326  break;
327 
328  case RpmDb::CHK_NOKEY: // Public key is unavailable
329  case RpmDb::CHK_NOTFOUND: // Signature is unknown type
330  case RpmDb::CHK_FAIL: // Signature does not verify
331  case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted
332  case RpmDb::CHK_ERROR: // File does not exist or can't be opened
333  default:
334  // report problem (w. details), throw if to abort, else retry/ignore
335  defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
336  break;
337  }
338  }
339  }
340  }
341  }
342  catch ( const UserRequestException & excpt )
343  {
344  ERR << "Failed to provide Package " << _package << endl;
345  if ( ! _retry )
346  ZYPP_RETHROW( excpt );
347  }
348  catch ( const FileCheckException & excpt )
349  {
350  ERR << "Failed to provide Package " << _package << endl;
351  if ( ! _retry )
352  {
353  const std::string & package_str = _package->asUserString();
354  // TranslatorExplanation %s = package being checked for integrity
355  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() ) ) )
356  {
358  _retry = true;
359  break;
361  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
362  break;
364  ZYPP_THROW(AbortRequestException("User requested to abort"));
365  break;
366  default:
367  break;
368  }
369  }
370  }
371  catch ( const Exception & excpt )
372  {
373  ERR << "Failed to provide Package " << _package << endl;
374  if ( ! _retry )
375  {
376  // Aything else gets reported
377  const std::string & package_str = _package->asUserString();
378 
379  // TranslatorExplanation %s = name of the package being processed.
380  std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
381  detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
382 
383  switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
384  {
386  _retry = true;
387  break;
389  ZYPP_THROW(SkipRequestException("User requested skip of file", excpt));
390  break;
392  ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
393  break;
394  default:
395  ZYPP_RETHROW( excpt );
396  break;
397  }
398  }
399  }
400  } while ( _retry );
401 
402  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
403  MIL << "provided Package " << _package << " at " << ret << endl;
404  return ret;
405  }
406 
407 
413  {
414  public:
416  const Package::constPtr & package_r,
417  const DeltaCandidates & deltas_r,
418  const PackageProviderPolicy & policy_r )
419  : PackageProvider::Impl( access_r, package_r, deltas_r, policy_r )
420  {}
421 
422  protected:
423  virtual ManagedFile doProvidePackageFromCache() const;
424 
425  virtual ManagedFile doProvidePackage() const;
426 
427  private:
429 
430  ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
431 
432  bool progressDeltaDownload( int value ) const
433  { return report()->progressDeltaDownload( value ); }
434 
435  void progressDeltaApply( int value ) const
436  { return report()->progressDeltaApply( value ); }
437 
438  bool queryInstalled( const Edition & ed_r = Edition() ) const
439  { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
440  };
442 
444  {
445  return ManagedFile( _package->cachedLocation() );
446  }
447 
449  {
450  Url url;
451  RepoInfo info = _package->repoInfo();
452  // FIXME we only support the first url for now.
453  if ( info.baseUrlsEmpty() )
454  ZYPP_THROW(Exception("No url in repository."));
455  else
456  url = * info.baseUrlsBegin();
457 
458  // check whether to process patch/delta rpms
459  if ( ZConfig::instance().download_use_deltarpm()
461  {
462  std::list<DeltaRpm> deltaRpms;
463  _deltas.deltaRpms( _package ).swap( deltaRpms );
464 
465  if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() )
466  {
467  for_( it, deltaRpms.begin(), deltaRpms.end())
468  {
469  DBG << "tryDelta " << *it << endl;
470  ManagedFile ret( tryDelta( *it ) );
471  if ( ! ret->empty() )
472  return ret;
473  }
474  }
475  }
476 
477  // no patch/delta -> provide full package
478  return Base::doProvidePackage();
479  }
480 
482  {
483  if ( delta_r.baseversion().edition() != Edition::noedition
484  && ! queryInstalled( delta_r.baseversion().edition() ) )
485  return ManagedFile();
486 
487  if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
488  return ManagedFile();
489 
490  report()->startDeltaDownload( delta_r.location().filename(),
491  delta_r.location().downloadSize() );
492  ManagedFile delta;
493  try
494  {
495  ProvideFilePolicy policy;
496  policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) );
497  delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
498  }
499  catch ( const Exception & excpt )
500  {
501  report()->problemDeltaDownload( excpt.asUserHistory() );
502  return ManagedFile();
503  }
504  report()->finishDeltaDownload();
505 
506  report()->startDeltaApply( delta );
507  if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
508  {
509  report()->problemDeltaApply( _("applydeltarpm check failed.") );
510  return ManagedFile();
511  }
512 
513  // build the package and put it into the cache
514  Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
515 
516  if ( ! applydeltarpm::provide( delta, destination,
517  bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
518  {
519  report()->problemDeltaApply( _("applydeltarpm failed.") );
520  return ManagedFile();
521  }
522  report()->finishDeltaApply();
523 
524  return ManagedFile( destination, filesystem::unlink );
525  }
526 
527 #if 0
528  class PluginPackageProvider : public PackageProvider::Impl
536  {
537  public:
538  PluginPackageProvider( const std::string & stem_r,
539  RepoMediaAccess & access_r,
540  const Package::constPtr & package_r,
541  const DeltaCandidates & deltas_r,
542  const PackageProviderPolicy & policy_r )
543  : Base( access_r, package_r, deltas_r, policy_r )
544  {}
545 
546  protected:
547  virtual ManagedFile doProvidePackageFromCache() const
548  {
549  return Base::doProvidePackageFromCache();
550  }
551 
552  virtual ManagedFile doProvidePackage() const
553  {
554  return Base::doProvidePackage();
555  }
556  };
558 #endif
559 
561  // class PackageProvider
563 
565  const Package::constPtr & package_r,
566  const DeltaCandidates & deltas_r,
567  const PackageProviderPolicy & policy_r )
568  {
569  return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r );
570  }
571 
573  const Package::constPtr & package_r,
574  const DeltaCandidates & deltas_r,
575  const PackageProviderPolicy & policy_r )
576  : _pimpl( Impl::factoryMake( access_r, package_r, deltas_r, policy_r ) )
577  {}
578 
580  {}
581 
583  { return _pimpl->providePackage(); }
584 
586  { return _pimpl->providePackageFromCache(); }
587 
589  { return _pimpl->isCached(); }
590 
591  } // namespace repo
593 } // 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
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
Helper filtering the files offered by a RepomdFileReader.
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:446
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:304
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:398
#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:392
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 USR
Definition: Logger.h:69
#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:455
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 verification 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 verification 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.