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 #include "zypp/ZYppFactory.h"
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
00100 SourceImpl::SourceImpl( const null & )
00101 : base::ProvideNumericId<SourceImpl,Source_Ref::NumericId>( NULL )
00102 , _res_store_initialized(true)
00103 {}
00104
00106
00107
00108
00109
00110 SourceImpl::SourceImpl()
00111 : _enabled(true)
00112 , _autorefresh(true)
00113 , _priority (0)
00114 , _priority_unsubscribed (0)
00115 , _subscribed(false)
00116 , _base_source(false)
00117 , _res_store_initialized(false)
00118 {
00119 }
00120
00122
00123
00124
00125
00126 void SourceImpl::factoryCtor( const media::MediaId & media_r,
00127 const Pathname & path_r,
00128 const std::string & alias_r,
00129 const Pathname cache_dir_r,
00130 bool base_source,
00131 bool auto_refresh )
00132 {
00133 _autorefresh = auto_refresh;
00134 _media_set = new MediaSet( selfSourceRef() );
00135 _url = media_mgr.url( media_r );
00136 _media_set->redirect( 1, media_r );
00137 _path = path_r;
00138 _alias = alias_r;
00139 _cache_dir = cache_dir_r;
00140 _subscribed = true;
00141 _base_source = base_source;
00142
00143 try
00144 {
00145 factoryInit();
00146 }
00147 catch ( Exception & excpt )
00148 {
00149 _store.clear();
00150 ZYPP_RETHROW( excpt );
00151 }
00152 }
00153
00155
00156
00157
00158
00159 void SourceImpl::factoryInit()
00160 {
00161 ZYPP_THROW( Exception( "FactoryInit not implemented!" ) );
00162 }
00163
00165
00166
00167
00168
00169 SourceImpl::~SourceImpl()
00170 {
00171 if (_media_set) {
00172 media::MediaAccessId _media = _media_set->getMediaAccessId( 1 );
00173 media_mgr.release (_media, false);
00174 }
00175 }
00176
00177 const ResStore & SourceImpl::resolvables() const
00178 {
00179 if ( !_res_store_initialized )
00180 {
00181
00182 Source_Ref self( const_cast<SourceImpl*>(this)->selfSourceRef() );
00183 const_cast<SourceImpl*>(this)->createResolvables(self);
00184 const_cast<SourceImpl*>(this)->_res_store_initialized = true;
00185 }
00186 return _store;
00187 }
00188
00189 const ResStore SourceImpl::resolvables(zypp::Resolvable::Kind kind) const
00190 {
00191 Source_Ref self( const_cast<SourceImpl*>(this)->selfSourceRef() );
00192 return const_cast<SourceImpl*>(this)->provideResolvables(self, kind);
00193 }
00194
00195 Pathname SourceImpl::tmpMetadataDir() const
00196 {
00197 if ( !_tmp_metadata_dir_ptr )
00198 _tmp_metadata_dir_ptr.reset(new filesystem::TmpDir(getZYpp()->tmpPath()));
00199 return _tmp_metadata_dir_ptr->path();
00200 }
00201
00202 Date SourceImpl::timestamp() const
00203 {
00204 return Date::now();
00205 }
00206
00207 void SourceImpl::dirInfo(const unsigned media_nr,
00208 std::list<std::string> &retlist,
00209 const Pathname &path_r,
00210 bool dots ) const
00211 {
00212 DBG << "reading " << path_r << " file list" << endl;
00213 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr );
00214 media_mgr.dirInfo( _media, retlist, path_r, dots );
00215 }
00216
00217 const Pathname SourceImpl::providePackage( Package::constPtr package )
00218 {
00219 bool retry = true;
00220 bool digest_ok = false;
00221 Pathname file;
00222 callback::SendReport<source::DownloadResolvableReport> report;
00223 DownloadProgressPackageReceiver download_report( report, package );
00224
00225 while (retry)
00226 {
00227 report->start( package, package->source().url() );
00228
00229 callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
00230
00231 try
00232 {
00233 file = provideJustFile( package->location(), package->sourceMediaNr());
00234 }
00235 catch (const Exception &e)
00236 {
00237 ERR << "Failed to provide " << package << " from " << url() << " in source " << alias() << std::endl;
00238 ZYPP_RETHROW (e);
00239 }
00240
00241 report->finish( package, source::DownloadResolvableReport::NO_ERROR, "" );
00242
00243 CheckSum checksum = package->checksum();
00244 std::string calculated_digest;
00245
00246
00247 try
00248 {
00249 std::ifstream is(file.asString().c_str(), std::ifstream::binary);
00250 calculated_digest = Digest::digest(checksum.type(), is);
00251 is.close();
00252 }
00253 catch (std::exception &e)
00254 {
00255 ERR << "Can't open " << file << " for integrity check." << std::endl;
00256 }
00257
00258 if ( checksum.checksum() == calculated_digest )
00259 {
00260 MIL << package->location() << " ok. [" << calculated_digest << "]" << std::endl;
00261 digest_ok = true;
00262 retry = false;
00263 }
00264
00265 if (!digest_ok)
00266 {
00267 std::string package_str = package->name() + "-" + package->edition().asString();
00268 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?");
00269
00270 if( useraction == source::DownloadResolvableReport::ABORT )
00271 {
00272 ZYPP_THROW(Exception("Package " + package->location().asString() + " fails integrity check. Expected: [" + checksum.checksum() + "] Read: [" + calculated_digest + "] (" + checksum.type() + ")"));
00273 }
00274 else if ( useraction == source::DownloadResolvableReport::RETRY )
00275 {
00276 retry = true;
00277 }
00278 }
00279 }
00280 return file;
00281 }
00282
00283 void SourceImpl::resetMediaVerifier()
00284 {
00285 try
00286 {
00287 media::MediaManager media_mgr;
00288 MIL << "Reseting media verifier" << std::endl;
00289
00290
00291 media::MediaAccessId _media = _media_set->getMediaAccessId(1, true);
00292 media_mgr.delVerifier(_media);
00293 media_mgr.addVerifier(_media, media::MediaVerifierRef(new media::NoVerifier()));
00294 }
00295 catch (const Exception & excpt_r)
00296 {
00297 ZYPP_CAUGHT(excpt_r);
00298 WAR << "Media Verifier not found." << endl;
00299 }
00300 }
00301
00302 const Pathname SourceImpl::provideFile(const Pathname & file_r,
00303 const unsigned media_nr,
00304 bool cached,
00305 bool checkonly )
00306 {
00307 callback::SendReport<source::DownloadFileReport> report;
00308 DownloadProgressFileReceiver download_report( report );
00309
00310 SourceFactory source_factory;
00311
00312 Url file_url( url().asString() + file_r.asString() );
00313
00314 report->start( source_factory.createFrom(this), file_url );
00315
00316 callback::TempConnect<media::DownloadProgressReport> tmp_download( download_report );
00317
00318 Pathname file = provideJustFile( file_r, media_nr, cached, checkonly );
00319
00320 report->finish( file_url, source::DownloadFileReport::NO_ERROR, "" );
00321
00322 return file;
00323 }
00324
00325 const Pathname SourceImpl::tryToProvideFile( const Pathname & file, const unsigned media_nr )
00326 {
00327 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr);
00328 media_mgr.provideFile (_media, file, false, false);
00329 return media_mgr.localPath( _media, file );
00330 }
00331
00332 void SourceImpl::copyLocalMetadata(const Pathname &src, const Pathname &dst) const
00333 {
00334
00335 if (dst == Pathname("/") )
00336 ZYPP_THROW(Exception("I refuse to use / as local dir"));
00337
00338 if (0 != assert_dir(dst, 0755))
00339 ZYPP_THROW(Exception("Cannot create local directory" + dst.asString()));
00340
00341 MIL << "Cleaning up local dir" << std::endl;
00342 filesystem::clean_dir(dst);
00343 MIL << "Copying " << src << " content to local : " << dst << std::endl;
00344
00345 if ( copy_dir_content( src, dst) != 0)
00346 {
00347 filesystem::clean_dir(dst);
00348 ZYPP_THROW(Exception( "Can't copy downloaded data to local dir. local dir cleaned."));
00349 }
00350 }
00351
00352 const Pathname SourceImpl::provideJustFile(const Pathname & file_r,
00353 const unsigned media_nr,
00354 bool cached,
00355 bool checkonly )
00356 {
00357 callback::SendReport<media::MediaChangeReport> report;
00358
00359 SourceFactory source_factory;
00360
00361
00362 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr, true );
00363 do {
00364 try {
00365 DBG << "Going to try provide file " << file_r << " from " << media_nr << endl;
00366
00367
00368 _media = _media_set->getMediaAccessId( media_nr );
00369 media_mgr.provideFile (_media, file_r, cached, checkonly);
00370 break;
00371 }
00372 catch ( Exception & excp )
00373 {
00374 ZYPP_CAUGHT(excp);
00375 media::MediaChangeReport::Action user;
00376
00377 do {
00378
00379 DBG << "Media couldn't provide file " << file_r << " , releasing." << endl;
00380 try {
00381 media_mgr.release (_media, false);
00382 }
00383 catch (const Exception & excpt_r)
00384 {
00385 ZYPP_CAUGHT(excpt_r);
00386 MIL << "Failed to release media " << _media << endl;
00387 }
00388 MIL << "Releasing all medias of all sources" << endl;
00389 try {
00390 zypp::SourceManager::sourceManager()->releaseAllSources();
00391 }
00392 catch (const zypp::Exception& excpt_r)
00393 {
00394 ZYPP_CAUGHT(excpt_r);
00395 ERR << "Failed to release all sources" << endl;
00396 }
00397
00398
00399 media::MediaChangeReport::Error reason
00400 = media::MediaChangeReport::INVALID;
00401
00402 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
00403 typeid(excp) == typeid( media::MediaNotAFileException ) )
00404 {
00405 reason = media::MediaChangeReport::NOT_FOUND;
00406 } else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
00407 typeid(excp) == typeid( media::MediaNotAttachedException) )
00408 {
00409 reason = media::MediaChangeReport::WRONG;
00410 }
00411
00412 user = checkonly ? media::MediaChangeReport::ABORT :
00413 report->requestMedia (
00414 source_factory.createFrom( this ),
00415 media_nr,
00416 reason,
00417 excp.asUserString()
00418 );
00419
00420 DBG << "ProvideFile exception caught, callback answer: " << user << endl;
00421
00422 if( user == media::MediaChangeReport::ABORT )
00423 {
00424 DBG << "Aborting" << endl;
00425 ZYPP_RETHROW ( excp );
00426 }
00427 else if ( user == media::MediaChangeReport::IGNORE )
00428 {
00429 DBG << "Skipping" << endl;
00430 ZYPP_THROW ( SkipRequestedException("User-requested skipping of a file") );
00431 }
00432 else if ( user == media::MediaChangeReport::EJECT )
00433 {
00434 DBG << "Eject: try to release" << endl;
00435 try {
00436 zypp::SourceManager::sourceManager()->releaseAllSources();
00437 }
00438 catch (const zypp::Exception& excpt_r)
00439 {
00440 ZYPP_CAUGHT(excpt_r);
00441 ERR << "Failed to release all sources" << endl;
00442 }
00443 media_mgr.release (_media, true);
00444
00445 }
00446 else if ( user == media::MediaChangeReport::RETRY ||
00447 user == media::MediaChangeReport::CHANGE_URL )
00448 {
00449
00450 DBG << "Going to try again" << endl;
00451
00452
00453
00454
00455 break;
00456 }
00457 else {
00458 DBG << "Don't know, let's ABORT" << endl;
00459
00460 ZYPP_RETHROW ( excp );
00461 }
00462 } while( user == media::MediaChangeReport::EJECT );
00463 }
00464
00465
00466 } while( true );
00467
00468 return media_mgr.localPath( _media, file_r );
00469 }
00470
00471 const Pathname SourceImpl::provideDirTree(const Pathname & path_r, const unsigned media_nr)
00472 {
00473 callback::SendReport<media::MediaChangeReport> report;
00474 SourceFactory source_factory;
00475
00476 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr, true );
00477 do
00478 {
00479 try
00480 {
00481 DBG << "Going to try provide tree " << path_r << " from " << media_nr << endl;
00482
00483 _media = _media_set->getMediaAccessId( media_nr );
00484 media_mgr.provideDirTree (_media, path_r);
00485 break;
00486 }
00487 catch ( Exception & excp )
00488 {
00489 ZYPP_CAUGHT(excp);
00490 media::MediaChangeReport::Action user;
00491
00492 do
00493 {
00494 DBG << "Media couldn't provide tree " << path_r << " , releasing." << endl;
00495 try
00496 {
00497 media_mgr.release (_media, false);
00498 }
00499 catch (const Exception & excpt_r)
00500 {
00501 ZYPP_CAUGHT(excpt_r);
00502 MIL << "Failed to release media " << _media << endl;
00503 }
00504 MIL << "Releasing all medias of all sources" << endl;
00505 try
00506 {
00507 zypp::SourceManager::sourceManager()->releaseAllSources();
00508 }
00509 catch (const zypp::Exception& excpt_r)
00510 {
00511 ZYPP_CAUGHT(excpt_r);
00512 ERR << "Failed to release all sources" << endl;
00513 }
00514
00515 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
00516
00517 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) || typeid(excp) == typeid( media::MediaNotAFileException ) )
00518 {
00519 reason = media::MediaChangeReport::NOT_FOUND;
00520 }
00521 else if( typeid(excp) == typeid( media::MediaNotDesiredException) || typeid(excp) == typeid( media::MediaNotAttachedException) )
00522 {
00523 reason = media::MediaChangeReport::WRONG;
00524 }
00525 user = report->requestMedia ( source_factory.createFrom( this ), media_nr, reason, excp.asUserString() );
00526
00527 DBG << "ProvideFile exception caught, callback answer: " << user << endl;
00528
00529 if( user == media::MediaChangeReport::ABORT )
00530 {
00531 DBG << "Aborting" << endl;
00532 ZYPP_RETHROW ( excp );
00533 }
00534 else if ( user == media::MediaChangeReport::EJECT )
00535 {
00536 DBG << "Eject: try to release" << endl;
00537 try {
00538 zypp::SourceManager::sourceManager()->releaseAllSources();
00539 }
00540 catch (const zypp::Exception& excpt_r)
00541 {
00542 ZYPP_CAUGHT(excpt_r);
00543 ERR << "Failed to release all sources" << endl;
00544 }
00545 media_mgr.release (_media, true);
00546
00547 }
00548 else if ( user == media::MediaChangeReport::RETRY ||
00549 user == media::MediaChangeReport::CHANGE_URL )
00550 {
00551
00552 DBG << "Going to try again" << endl;
00553
00554
00555
00556
00557 break;
00558 }
00559 else
00560 {
00561 DBG << "Don't know, let's ABORT" << endl;
00562
00563 ZYPP_RETHROW ( excp );
00564 }
00565 } while( user == media::MediaChangeReport::EJECT );
00566 }
00567
00568 } while( true );
00569 return media_mgr.localPath( _media, path_r );
00570 }
00571
00572 const void SourceImpl::releaseFile(const Pathname & file_r,
00573 const unsigned media_nr)
00574 {
00575 DBG << "releaseFile(" << file_r << ", " << media_nr << ")" << endl;
00576 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr );
00577 media_mgr.releaseFile(_media, file_r);
00578 }
00579
00580 const void SourceImpl::releaseDir(const Pathname & path_r,
00581 const unsigned media_nr,
00582 const bool recursive)
00583 {
00584 DBG << "releaseDir(" << path_r << ", " << media_nr << (recursive?", recursive":"") << ")" << endl;
00585 media::MediaAccessId _media = _media_set->getMediaAccessId( media_nr );
00586 if (recursive)
00587 media_mgr.releasePath(_media, path_r);
00588 else
00589 media_mgr.releaseDir(_media, path_r);
00590 }
00591
00592 void SourceImpl::changeMedia( const media::MediaId & media_r, const Pathname & path_r )
00593 {
00594 DBG << "changeMedia(" << path_r << ")" << endl;
00595 _url = media_mgr.url( media_r );
00596 _media_set->reset();
00597 _media_set->redirect( 1, media_r );
00598 _path = path_r;
00599 }
00600
00601 void SourceImpl::enable()
00602 {
00603
00604
00605 _enabled = true;
00606 }
00607
00608 void SourceImpl::createResolvables(Source_Ref source_r)
00609 {}
00610
00611 ResStore SourceImpl::provideResolvables(Source_Ref source_r, zypp::Resolvable::Kind kind)
00612 {
00613 WAR << "provideResolvables not implemented by the source" << endl;
00614 return ResStore();
00615 }
00616
00617 void SourceImpl::storeMetadata(const Pathname & cache_dir_r)
00618 {}
00619
00620 void SourceImpl::refresh()
00621 {
00622 MIL << "Refreshing" << endl;
00623
00624
00625 try{
00626 storeMetadata( _cache_dir );
00627 }
00628 catch( const zypp::Exception & excpt )
00629 {
00630 ERR << "Unable to refresh the source cache" << endl;
00631 if( ! _cache_dir.empty() && _cache_dir != "/" )
00632 filesystem::clean_dir( _cache_dir );
00633
00634 ZYPP_RETHROW( excpt );
00635 }
00636 }
00637
00638 void SourceImpl::redirect(unsigned media_nr, const Url & new_url)
00639 {
00640 DBG << "redirect(" << new_url << ")" << endl;
00641 media::MediaAccessId id = media_mgr.open( new_url );
00642 _media_set->redirect( media_nr, id );
00643 }
00644 void SourceImpl::reattach(const Pathname &attach_point)
00645 {
00646 DBG << "reattach(" << attach_point << ")" << endl;
00647 _media_set->reattach( attach_point );
00648 }
00649
00650 void SourceImpl::release()
00651 {
00652 if (_media_set)
00653 _media_set->release();
00654 }
00655
00656 media::MediaVerifierRef SourceImpl::verifier(unsigned media_nr)
00657 { return media::MediaVerifierRef(new media::NoVerifier()); }
00658
00660
00661
00662 std::string SourceImpl::type (void) const
00663 { return "undefined"; }
00664
00665 std::string SourceImpl::id (void) const
00666 { return _id; }
00667
00668 void SourceImpl::setId (const std::string id_r)
00669 { _id = id_r; }
00670
00671 unsigned SourceImpl::priority (void) const
00672 { return _priority; }
00673
00674 void SourceImpl::setPriority (unsigned p)
00675 { _priority = p; }
00676
00677 unsigned SourceImpl::priorityUnsubscribed (void) const
00678 { return _priority_unsubscribed; }
00679
00680 void SourceImpl::setPriorityUnsubscribed (unsigned p)
00681 { _priority_unsubscribed = p; }
00682
00683 bool SourceImpl::subscribed (void) const
00684 { return _subscribed; }
00685
00686 void SourceImpl::setSubscribed (bool s)
00687 { _subscribed = s; }
00688
00689 const Pathname & SourceImpl::cacheDir (void)
00690 { return _cache_dir; }
00691
00692 Url SourceImpl::url (void) const
00693 { return _url; }
00694
00695 void SourceImpl::setUrl( const Url & url )
00696 { _url = url; }
00697
00698 bool SourceImpl::remote() const
00699 {
00700 bool downloads = false;
00701 try {
00702 downloads = media::MediaManager::downloads(_url);
00703 }
00704 catch(const zypp::Exception &e)
00705 {
00706
00707 ZYPP_CAUGHT(e);
00708 }
00709 return downloads;
00710 }
00711
00712 const Pathname & SourceImpl::path (void) const
00713 { return _path; }
00714
00715 unsigned SourceImpl::numberOfMedia(void) const
00716 { return 1; }
00717
00718 std::string SourceImpl::vendor (void) const
00719 { return ""; }
00720
00721 const std::list<Pathname> SourceImpl::publicKeys()
00722 { return std::list<Pathname>(); }
00723
00724 std::string SourceImpl::unique_id (void) const
00725 { return ""; }
00726
00728
00732 std::string SourceImpl::zmdName (void) const
00733 { return "zmdname"; }
00734
00735 void SourceImpl::setZmdName (const std::string name_r)
00736 { return; }
00737
00738 std::string SourceImpl::zmdDescription (void) const
00739 { return "zmddescription"; }
00740
00741 void SourceImpl::setZmdDescription (const std::string desc_r)
00742 { return; }
00743
00745
00746 std::ostream & SourceImpl::dumpOn( std::ostream & str ) const
00747 {
00748 str << "Source[" << numericId() << "|" << type();
00749 if ( !_alias.empty() )
00750 str << "|" << _alias;
00751 str << "]";
00752
00753 str << "{"
00754 << _url << "(" << _path << ")";
00755 if ( ! _cache_dir.empty() )
00756 str << "; cache " << _cache_dir;
00757 str << "}";
00758
00759 return str;
00760 }
00761
00762 SourceImpl::Verifier::Verifier(const std::string & vendor_r, const std::string & id_r, const media::MediaNr media_nr)
00763 : _media_vendor(vendor_r)
00764 , _media_id(id_r)
00765 , _media_nr(media_nr)
00766 {}
00767
00768 bool SourceImpl::Verifier::isDesiredMedia(const media::MediaAccessRef &ref)
00769 {
00770 if (_media_vendor.empty() || _media_id.empty())
00771 return true;
00772 #warning TODO define what does missing media_id/media_vendor mean
00773
00774 Pathname media_file = "/media." + str::numstring(_media_nr) + "/media";
00775 ref->provideFile (media_file);
00776 media_file = ref->localPath(media_file);
00777 std::ifstream str(media_file.asString().c_str());
00778 std::string vendor;
00779 std::string id;
00780
00781 #warning check the stream status
00782 getline(str, vendor);
00783 getline(str, id);
00784
00785 return (vendor == _media_vendor && id == _media_id );
00786 }
00787
00789 }
00792 }