SourceImpl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
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     //  METHOD NAME : SourceImpl::SourceImpl
00100     //  METHOD TYPE : Ctor
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     //  METHOD NAME : SourceImpl::factoryCtor
00116     //  METHOD TYPE : void
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       // for sources which are neither CD nor DVD we enable autorefresh by default
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     //  METHOD NAME : SourceImpl::factoryInit
00150     //  METHOD TYPE : void
00151     //
00152     void SourceImpl::factoryInit()
00153     {}
00154 
00156     //
00157     //  METHOD NAME : SourceImpl::~SourceImpl
00158     //  METHOD TYPE : Dtor
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         // cast away const to allow late init
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         // check digest  
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       // get the mediaId, but don't try to attach it here
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           // try to attach the media
00301           _media = _media_set->getMediaAccessId( media_nr ); // in case of redirect
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             // set up the reason
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); // one more release needed for eject
00377               // FIXME: this will not work, probably
00378             }
00379             else if ( user == media::MediaChangeReport::RETRY  ||
00380             user == media::MediaChangeReport::CHANGE_URL )
00381             {
00382               // retry
00383               DBG << "Going to try again" << endl;
00384 
00385               // not attaching, media set will do that for us
00386               // this could generate uncaught exception (#158620)
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         // retry or change URL
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       // get the mediaId, but don't try to attach it here
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           // try to attach the media
00416           _media = _media_set->getMediaAccessId( media_nr ); // in case of redirect
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             // set up the reason
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); // one more release needed for eject
00479               // FIXME: this will not work, probably
00480             }
00481             else if ( user == media::MediaChangeReport::RETRY  ||
00482                       user == media::MediaChangeReport::CHANGE_URL )
00483             {
00484               // retry
00485               DBG << "Going to try again" << endl;
00486   
00487               // not attaching, media set will do that for us
00488               // this could generate uncaught exception (#158620)
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       // retry or change URL
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 //      if (autorefresh())
00537 //      refresh();
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         // TODO: will this work in chroot?
00556         // TODO: better download somewhere else and then copy over
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     // attribute accessors
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         // should not happen, but ...
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   } // namespace source
00724 } // namespace zypp

Generated on Thu May 4 16:03:26 2006 for zypp by  doxygen 1.4.6