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