00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <fstream>
00014 #include "zypp/base/Logger.h"
00015 #include "zypp/Digest.h"
00016 #include "zypp/SourceFactory.h"
00017 #include "zypp/source/SourceImpl.h"
00018 #include "zypp/ZYppCallbacks.h"
00019 #include "zypp/SourceManager.h"
00020
00021 #include <fstream>
00022
00023 using std::endl;
00024
00026 namespace zypp
00027 {
00028
00029 namespace source
00030 {
00031
00032 IMPL_PTR_TYPE(SourceImpl);
00033
00034
00035 class DownloadProgressPackageReceiver
00036 : public callback::ReceiveReport<media::DownloadProgressReport>
00037 {
00038 callback::SendReport <DownloadResolvableReport> & _report;
00039 Resolvable::constPtr _resolvable;
00040
00041 public:
00042
00043 DownloadProgressPackageReceiver (
00044 callback::SendReport <DownloadResolvableReport> & report_r,
00045 Resolvable::constPtr resolvable_r
00046 )
00047 : _report (report_r)
00048 , _resolvable (resolvable_r)
00049 {}
00050
00051 virtual ~DownloadProgressPackageReceiver () {}
00052
00053 virtual void reportbegin() {}
00054
00055 virtual void reportend() {}
00056
00061 virtual bool progress( int percent, Url )
00062 {
00063 return _report->progress( percent, _resolvable );
00064 }
00065 };
00066
00067
00068 class DownloadProgressFileReceiver
00069 : public callback::ReceiveReport<media::DownloadProgressReport>
00070 {
00071 callback::SendReport <DownloadFileReport> & _report;
00072
00073 public:
00074
00075 DownloadProgressFileReceiver (
00076 callback::SendReport <DownloadFileReport> & report_r
00077 )
00078 : _report (report_r)
00079 {}
00080
00081 virtual ~DownloadProgressFileReceiver () {}
00082
00083 virtual void reportbegin() {}
00084
00085 virtual void reportend() {}
00086
00091 virtual bool progress( int percent, Url url )
00092 {
00093 return _report->progress( percent, url );
00094 }
00095 };
00096
00098
00099
00100
00101
00102 SourceImpl::SourceImpl()
00103 : _enabled(true)
00104 , _autorefresh(true)
00105 , _priority (0)
00106 , _priority_unsubscribed (0)
00107 , _subscribed(false)
00108 , _res_store_initialized(false)
00109 , _base_source(false)
00110 {
00111 }
00112
00114
00115
00116
00117
00118 void SourceImpl::factoryCtor( const media::MediaId & media_r,
00119 const Pathname & path_r,
00120 const std::string & alias_r,
00121 const Pathname cache_dir_r,
00122 const bool base_source)
00123 {
00124 _media_set = new MediaSet( selfSourceRef() );
00125 _url = media_mgr.url( media_r );
00126 _media_set->redirect( 1, media_r );
00127 _path = path_r;
00128 _alias = alias_r;
00129 _cache_dir = cache_dir_r;
00130 _subscribed = true;
00131 _base_source = base_source;
00132
00133
00134 _autorefresh = media::MediaAccess::canBeVolatile( _url );
00135
00136 try
00137 {
00138 factoryInit();
00139 }
00140 catch ( Exception & excpt )
00141 {
00142 _store.clear();
00143 ZYPP_RETHROW( excpt );
00144 }
00145 }
00146
00148
00149
00150
00151
00152 void SourceImpl::factoryInit()
00153 {}
00154
00156
00157
00158
00159
00160 SourceImpl::~SourceImpl()
00161 {
00162 if (_media_set) {
00163 media::MediaAccessId _media = _media_set->getMediaAccessId( 1 );
00164 media_mgr.release (_media, false);
00165 }
00166 }
00167
00168 const ResStore & SourceImpl::resolvables() const
00169 {
00170 if ( !_res_store_initialized )
00171 {
00172
00173 Source_Ref self( const_cast<SourceImpl*>(this)->selfSourceRef() );
00174 const_cast<SourceImpl*>(this)->createResolvables(self);
00175 const_cast<SourceImpl*>(this)->_res_store_initialized = true;
00176 }
00177 return _store;
00178 }
00179
00180 const ResStore SourceImpl::resolvables(zypp::Resolvable::Kind kind) const
00181 {
00182 Source_Ref self( const_cast<SourceImpl*>(this)->selfSourceRef() );
00183 return const_cast<SourceImpl*>(this)->provideResolvables(self, kind);
00184 }
00185
00186 void SourceImpl::dirInfo(const unsigned media_nr,
00187 std::list<std::string> &retlist,
00188 const Pathname &path_r,
00189 bool dots ) const
00190 {
00191 DBG << "reading " << path_r << " file list" << endl;
00192 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr );
00193 media_mgr.dirInfo( _media, retlist, path_r, dots );
00194 }
00195
00196 const Pathname SourceImpl::providePackage( Package::constPtr package )
00197 {
00198 bool retry = true;
00199 bool digest_ok = false;
00200 Pathname file;
00201 callback::SendReport<source::DownloadResolvableReport> report;
00202 DownloadProgressPackageReceiver download_report( report, package );
00203
00204 while (retry)
00205 {
00206 report->start( package, package->source().url() );
00207
00208 callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
00209
00210 file = provideJustFile( package->location(), package->mediaId());
00211
00212 report->finish( package, source::DownloadResolvableReport::NO_ERROR, "" );
00213
00214 CheckSum checksum = package->checksum();
00215 std::string calculated_digest;
00216
00217
00218 try
00219 {
00220 std::ifstream is(file.asString().c_str(), std::ifstream::binary);
00221 calculated_digest = Digest::digest(checksum.type(), is);
00222 is.close();
00223 }
00224 catch (std::exception &e)
00225 {
00226 ERR << "Can't open " << file << " for integrity check." << std::endl;
00227 }
00228
00229 if ( checksum.checksum() == calculated_digest )
00230 {
00231 MIL << package->location() << " ok. [" << calculated_digest << "]" << std::endl;
00232 digest_ok = true;
00233 retry = false;
00234 }
00235
00236 if (!digest_ok)
00237 {
00238 std::string package_str = package->name() + "-" + package->edition().asString();
00239 source::DownloadResolvableReport::Action useraction = report->problem(package, source::DownloadResolvableReport::INVALID, "Package " + package_str + " fails integrity check. Do you want to retry downloading it, or abort installation?");
00240
00241 if( useraction == source::DownloadResolvableReport::ABORT )
00242 {
00243 ZYPP_THROW(Exception("Package " + package->location().asString() + " fails integrity check. Expected: [" + checksum.checksum() + "] Read: [" + calculated_digest + "] (" + checksum.type() + ")"));
00244 }
00245 else if ( useraction == source::DownloadResolvableReport::RETRY )
00246 {
00247 retry = true;
00248 }
00249 }
00250 }
00251 return file;
00252 }
00253
00254 const Pathname SourceImpl::provideFile(const Pathname & file_r,
00255 const unsigned media_nr,
00256 bool cached,
00257 bool checkonly )
00258 {
00259 callback::SendReport<source::DownloadFileReport> report;
00260 DownloadProgressFileReceiver download_report( report );
00261
00262 SourceFactory source_factory;
00263
00264 Url file_url( url().asString() + file_r.asString() );
00265
00266 report->start( source_factory.createFrom(this), file_url );
00267
00268 callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
00269
00270 Pathname file = provideJustFile( file_r, media_nr, cached, checkonly );
00271
00272 report->finish( file_url, source::DownloadFileReport::NO_ERROR, "" );
00273
00274 return file;
00275 }
00276
00277 const Pathname SourceImpl::tryToProvideFile( const Pathname & file, const unsigned media_nr )
00278 {
00279 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr);
00280 media_mgr.provideFile (_media, file, false, false);
00281 return media_mgr.localPath( _media, file );
00282 }
00283
00284
00285 const Pathname SourceImpl::provideJustFile(const Pathname & file_r,
00286 const unsigned media_nr,
00287 bool cached,
00288 bool checkonly )
00289 {
00290 callback::SendReport<media::MediaChangeReport> report;
00291
00292 SourceFactory source_factory;
00293
00294
00295 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr, true );
00296 do {
00297 try {
00298 DBG << "Going to try provide file " << file_r << " from " << media_nr << endl;
00299
00300
00301 _media = _media_set->getMediaAccessId( media_nr );
00302 media_mgr.provideFile (_media, file_r, cached, checkonly);
00303 break;
00304 }
00305 catch ( Exception & excp )
00306 {
00307 ZYPP_CAUGHT(excp);
00308 media::MediaChangeReport::Action user;
00309
00310 do {
00311
00312 DBG << "Media couldn't provide file " << file_r << " , releasing." << endl;
00313 try {
00314 media_mgr.release (_media, false);
00315 }
00316 catch (const Exception & excpt_r)
00317 {
00318 ZYPP_CAUGHT(excpt_r);
00319 MIL << "Failed to release media " << _media << endl;
00320 }
00321 MIL << "Releasing all medias of all sources" << endl;
00322 try {
00323 zypp::SourceManager::sourceManager()->releaseAllSources();
00324 }
00325 catch (const zypp::Exception& excpt_r)
00326 {
00327 ZYPP_CAUGHT(excpt_r);
00328 ERR << "Failed to release all sources" << endl;
00329 }
00330
00331
00332 media::MediaChangeReport::Error reason
00333 = media::MediaChangeReport::INVALID;
00334
00335 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
00336 typeid(excp) == typeid( media::MediaNotAFileException ) )
00337 {
00338 reason = media::MediaChangeReport::NOT_FOUND;
00339 } else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
00340 typeid(excp) == typeid( media::MediaNotAttachedException) )
00341 {
00342 reason = media::MediaChangeReport::WRONG;
00343 }
00344
00345 user = checkonly ? media::MediaChangeReport::ABORT :
00346 report->requestMedia (
00347 source_factory.createFrom( this ),
00348 media_nr,
00349 reason,
00350 excp.asUserString()
00351 );
00352
00353 DBG << "ProvideFile exception caught, callback answer: " << user << endl;
00354
00355 if( user == media::MediaChangeReport::ABORT )
00356 {
00357 DBG << "Aborting" << endl;
00358 ZYPP_RETHROW ( excp );
00359 }
00360 else if ( user == media::MediaChangeReport::IGNORE )
00361 {
00362 DBG << "Skipping" << endl;
00363 ZYPP_THROW ( SkipRequestedException("User-requested skipping of a file") );
00364 }
00365 else if ( user == media::MediaChangeReport::EJECT )
00366 {
00367 DBG << "Eject: try to release" << endl;
00368 try {
00369 zypp::SourceManager::sourceManager()->releaseAllSources();
00370 }
00371 catch (const zypp::Exception& excpt_r)
00372 {
00373 ZYPP_CAUGHT(excpt_r);
00374 ERR << "Failed to release all sources" << endl;
00375 }
00376 media_mgr.release (_media, true);
00377
00378 }
00379 else if ( user == media::MediaChangeReport::RETRY ||
00380 user == media::MediaChangeReport::CHANGE_URL )
00381 {
00382
00383 DBG << "Going to try again" << endl;
00384
00385
00386
00387
00388 break;
00389 }
00390 else {
00391 DBG << "Don't know, let's ABORT" << endl;
00392
00393 ZYPP_RETHROW ( excp );
00394 }
00395 } while( user == media::MediaChangeReport::EJECT );
00396 }
00397
00398
00399 } while( true );
00400
00401 return media_mgr.localPath( _media, file_r );
00402 }
00403
00404 const Pathname SourceImpl::provideDirTree(const Pathname & path_r, const unsigned media_nr)
00405 {
00406 callback::SendReport<media::MediaChangeReport> report;
00407 SourceFactory source_factory;
00408
00409 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr, true );
00410 do
00411 {
00412 try
00413 {
00414 DBG << "Going to try provide tree " << path_r << " from " << media_nr << endl;
00415
00416 _media = _media_set->getMediaAccessId( media_nr );
00417 media_mgr.provideDirTree (_media, path_r);
00418 break;
00419 }
00420 catch ( Exception & excp )
00421 {
00422 ZYPP_CAUGHT(excp);
00423 media::MediaChangeReport::Action user;
00424
00425 do
00426 {
00427 DBG << "Media couldn't provide tree " << path_r << " , releasing." << endl;
00428 try
00429 {
00430 media_mgr.release (_media, false);
00431 }
00432 catch (const Exception & excpt_r)
00433 {
00434 ZYPP_CAUGHT(excpt_r);
00435 MIL << "Failed to release media " << _media << endl;
00436 }
00437 MIL << "Releasing all medias of all sources" << endl;
00438 try
00439 {
00440 zypp::SourceManager::sourceManager()->releaseAllSources();
00441 }
00442 catch (const zypp::Exception& excpt_r)
00443 {
00444 ZYPP_CAUGHT(excpt_r);
00445 ERR << "Failed to release all sources" << endl;
00446 }
00447
00448 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
00449
00450 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) || typeid(excp) == typeid( media::MediaNotAFileException ) )
00451 {
00452 reason = media::MediaChangeReport::NOT_FOUND;
00453 }
00454 else if( typeid(excp) == typeid( media::MediaNotDesiredException) || typeid(excp) == typeid( media::MediaNotAttachedException) )
00455 {
00456 reason = media::MediaChangeReport::WRONG;
00457 }
00458 user = report->requestMedia ( source_factory.createFrom( this ), media_nr, reason, excp.asUserString() );
00459
00460 DBG << "ProvideFile exception caught, callback answer: " << user << endl;
00461
00462 if( user == media::MediaChangeReport::ABORT )
00463 {
00464 DBG << "Aborting" << endl;
00465 ZYPP_RETHROW ( excp );
00466 }
00467 else if ( user == media::MediaChangeReport::EJECT )
00468 {
00469 DBG << "Eject: try to release" << endl;
00470 try {
00471 zypp::SourceManager::sourceManager()->releaseAllSources();
00472 }
00473 catch (const zypp::Exception& excpt_r)
00474 {
00475 ZYPP_CAUGHT(excpt_r);
00476 ERR << "Failed to release all sources" << endl;
00477 }
00478 media_mgr.release (_media, true);
00479
00480 }
00481 else if ( user == media::MediaChangeReport::RETRY ||
00482 user == media::MediaChangeReport::CHANGE_URL )
00483 {
00484
00485 DBG << "Going to try again" << endl;
00486
00487
00488
00489
00490 break;
00491 }
00492 else
00493 {
00494 DBG << "Don't know, let's ABORT" << endl;
00495
00496 ZYPP_RETHROW ( excp );
00497 }
00498 } while( user == media::MediaChangeReport::EJECT );
00499 }
00500
00501 } while( true );
00502 return media_mgr.localPath( _media, path_r );
00503 }
00504
00505 const void SourceImpl::releaseFile(const Pathname & file_r,
00506 const unsigned media_nr)
00507 {
00508 DBG << "releaseFile(" << file_r << ", " << media_nr << ")" << endl;
00509 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr );
00510 media_mgr.releaseFile(_media, file_r);
00511 }
00512
00513 const void SourceImpl::releaseDir(const Pathname & path_r,
00514 const unsigned media_nr,
00515 const bool recursive)
00516 {
00517 DBG << "releaseDir(" << path_r << ", " << media_nr << (recursive?", recursive":"") << ")" << endl;
00518 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr );
00519 if (recursive)
00520 media_mgr.releasePath(_media, path_r);
00521 else
00522 media_mgr.releaseDir(_media, path_r);
00523 }
00524
00525 void SourceImpl::changeMedia( const media::MediaId & media_r, const Pathname & path_r )
00526 {
00527 DBG << "changeMedia(" << path_r << ")" << endl;
00528 _url = media_mgr.url( media_r );
00529 _media_set->reset();
00530 _media_set->redirect( 1, media_r );
00531 _path = path_r;
00532 }
00533
00534 void SourceImpl::enable()
00535 {
00536
00537
00538 _enabled = true;
00539 }
00540
00541 void SourceImpl::createResolvables(Source_Ref source_r)
00542 {}
00543
00544 ResStore SourceImpl::provideResolvables(Source_Ref source_r, zypp::Resolvable::Kind kind)
00545 {
00546 WAR << "provideResolvables not implemented by the source" << endl;
00547 return ResStore();
00548 }
00549
00550 void SourceImpl::storeMetadata(const Pathname & cache_dir_r)
00551 {}
00552
00553 void SourceImpl::refresh()
00554 {
00555
00556
00557 try{
00558 storeMetadata( _cache_dir );
00559 }
00560 catch( const zypp::Exception & excpt )
00561 {
00562 ERR << "Unable to refresh the source cache" << endl;
00563 if( ! _cache_dir.empty() && _cache_dir != "/" )
00564 filesystem::clean_dir( _cache_dir );
00565
00566 ZYPP_RETHROW( excpt );
00567 }
00568 }
00569
00570 void SourceImpl::redirect(unsigned media_nr, const Url & new_url)
00571 {
00572 DBG << "redirect(" << new_url << ")" << endl;
00573 media::MediaAccessId id = media_mgr.open( new_url );
00574 _media_set->redirect( media_nr, id );
00575 }
00576 void SourceImpl::reattach(const Pathname &attach_point)
00577 {
00578 DBG << "reattach(" << attach_point << ")" << endl;
00579 _media_set->reattach( attach_point );
00580 }
00581
00582 void SourceImpl::release()
00583 {
00584 if (_media_set)
00585 _media_set->release();
00586 }
00587
00588 media::MediaVerifierRef SourceImpl::verifier(unsigned media_nr)
00589 { return media::MediaVerifierRef(new media::NoVerifier()); }
00590
00592
00593
00594 std::string SourceImpl::type (void) const
00595 { return "undefined"; }
00596
00597 std::string SourceImpl::id (void) const
00598 { return _id; }
00599
00600 void SourceImpl::setId (const std::string id_r)
00601 { _id = id_r; }
00602
00603 unsigned SourceImpl::priority (void) const
00604 { return _priority; }
00605
00606 void SourceImpl::setPriority (unsigned p)
00607 { _priority = p; }
00608
00609 unsigned SourceImpl::priorityUnsubscribed (void) const
00610 { return _priority_unsubscribed; }
00611
00612 void SourceImpl::setPriorityUnsubscribed (unsigned p)
00613 { _priority_unsubscribed = p; }
00614
00615 bool SourceImpl::subscribed (void) const
00616 { return _subscribed; }
00617
00618 void SourceImpl::setSubscribed (bool s)
00619 { _subscribed = s; }
00620
00621 const Pathname & SourceImpl::cacheDir (void)
00622 { return _cache_dir; }
00623
00624 Url SourceImpl::url (void) const
00625 { return _url; }
00626
00627 void SourceImpl::setUrl( const Url & url )
00628 { _url = url; }
00629
00630 bool SourceImpl::remote() const
00631 {
00632 bool downloads = false;
00633 try {
00634 downloads = media::MediaManager::downloads(_url);
00635 }
00636 catch(const zypp::Exception &e)
00637 {
00638
00639 ZYPP_CAUGHT(e);
00640 }
00641 return downloads;
00642 }
00643
00644 const Pathname & SourceImpl::path (void) const
00645 { return _path; }
00646
00647 unsigned SourceImpl::numberOfMedia(void) const
00648 { return 1; }
00649
00650 std::string SourceImpl::vendor (void) const
00651 { return ""; }
00652
00653 const std::list<Pathname> SourceImpl::publicKeys()
00654 { return std::list<Pathname>(); }
00655
00656 std::string SourceImpl::unique_id (void) const
00657 { return ""; }
00658
00660
00664 std::string SourceImpl::zmdName (void) const
00665 { return "zmdname"; }
00666
00667 void SourceImpl::setZmdName (const std::string name_r)
00668 { return; }
00669
00670 std::string SourceImpl::zmdDescription (void) const
00671 { return "zmddescription"; }
00672
00673 void SourceImpl::setZmdDescription (const std::string desc_r)
00674 { return; }
00675
00677
00678 std::ostream & SourceImpl::dumpOn( std::ostream & str ) const
00679 {
00680 str << "Source[" << numericId() << "|" << type();
00681 if ( !_alias.empty() )
00682 str << "|" << _alias;
00683 str << "]";
00684
00685 str << "{"
00686 << _url << "(" << _path << ")";
00687 if ( ! _cache_dir.empty() )
00688 str << "; cache " << _cache_dir;
00689 str << "}";
00690
00691 return str;
00692 }
00693
00694 SourceImpl::Verifier::Verifier(const std::string & vendor_r, const std::string & id_r, const media::MediaNr media_nr)
00695 : _media_vendor(vendor_r)
00696 , _media_id(id_r)
00697 , _media_nr(media_nr)
00698 {}
00699
00700 bool SourceImpl::Verifier::isDesiredMedia(const media::MediaAccessRef &ref)
00701 {
00702 if (_media_vendor.empty() || _media_id.empty())
00703 return true;
00704 #warning TODO define what does missing media_id/media_vendor mean
00705
00706 Pathname media_file = "/media." + str::numstring(_media_nr) + "/media";
00707 ref->provideFile (media_file);
00708 media_file = ref->localPath(media_file);
00709 std::ifstream str(media_file.asString().c_str());
00710 std::string vendor;
00711 std::string id;
00712
00713 #warning check the stream status
00714 getline(str, vendor);
00715 getline(str, id);
00716
00717 return (vendor == _media_vendor && id == _media_id );
00718 }
00719
00721 }
00724 }