libzypp 8.13.6

RepoProvideFile.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 <sstream>
00015 #include <set>
00016 
00017 #include "zypp/base/Gettext.h"
00018 #include "zypp/base/Logger.h"
00019 #include "zypp/base/String.h"
00020 #include "zypp/base/UserRequestException.h"
00021 #include "zypp/repo/RepoProvideFile.h"
00022 #include "zypp/ZYppCallbacks.h"
00023 #include "zypp/MediaSetAccess.h"
00024 #include "zypp/ZConfig.h"
00025 #include "zypp/repo/SUSEMediaVerifier.h"
00026 #include "zypp/repo/RepoException.h"
00027 
00028 #include "zypp/repo/SUSEMediaVerifier.h"
00029 #include "zypp/repo/RepoException.h"
00030 #include "zypp/FileChecker.h"
00031 #include "zypp/Fetcher.h"
00032 
00033 using std::endl;
00034 using std::set;
00035 
00037 namespace zypp
00038 { 
00039 
00040   namespace repo
00041   { 
00042 
00044     //
00045     //  provideFile
00046     //
00048 
00050     namespace
00051     { 
00052 
00058       struct DownloadFileReportHack : public callback::ReceiveReport<media::DownloadProgressReport>
00059       {
00060         typedef callback::ReceiveReport<ReportType> BaseType;
00061         typedef function<bool(int)>                 RedirectType;
00062 
00063         DownloadFileReportHack( RedirectType redirect_r )
00064         : _oldRec( Distributor::instance().getReceiver() )
00065         , _redirect( redirect_r )
00066         { connect(); }
00067         ~DownloadFileReportHack()
00068         { if ( _oldRec ) Distributor::instance().setReceiver( *_oldRec ); else Distributor::instance().noReceiver(); }
00069 
00070         virtual void start( const Url & file, Pathname localfile )
00071         {
00072           if ( _oldRec )
00073             _oldRec->start( file, localfile );
00074           else
00075             BaseType::start( file, localfile );
00076         }
00077 
00078         virtual bool progress( int value, const Url & file, double dbps_avg = -1, double dbps_current = -1 )
00079         {
00080           bool ret = true;
00081           if ( _oldRec )
00082             ret &= _oldRec->progress( value, file, dbps_avg, dbps_current );
00083           if ( _redirect )
00084             ret &= _redirect( value );
00085           return ret;
00086         }
00087 
00088         virtual Action problem( const Url & file, Error error, const std::string & description )
00089         {
00090           if ( _oldRec )
00091             return _oldRec->problem( file, error, description );
00092           return BaseType::problem( file, error, description );
00093         }
00094         virtual void finish( const Url & file, Error error, const std::string & reason )
00095         {
00096           if ( _oldRec )
00097             _oldRec->finish( file, error, reason );
00098           else
00099             BaseType::finish( file, error, reason );
00100         }
00101 
00102         private:
00103           Receiver * _oldRec;
00104           RedirectType _redirect;
00105       };
00106 
00108     } // namespace
00110 
00111     ManagedFile provideFile( RepoInfo repo_r,
00112                              const OnMediaLocation & loc_r,
00113                              const ProvideFilePolicy & policy_r )
00114     {
00115       RepoMediaAccess access;
00116       return access.provideFile(repo_r, loc_r, policy_r );
00117     }
00118 
00120     class RepoMediaAccess::Impl
00121     {
00122     public:
00123       Impl( const ProvideFilePolicy & defaultPolicy_r )
00124         : _defaultPolicy( defaultPolicy_r )
00125       {}
00126 
00127       ~Impl()
00128       {
00129         std::map<Url, shared_ptr<MediaSetAccess> >::iterator it;
00130         for ( it = _medias.begin();
00131               it != _medias.end();
00132               ++it )
00133         {
00134           it->second->release();
00135         }
00136       }
00137 
00145       shared_ptr<MediaSetAccess> mediaAccessForUrl( const Url &url, RepoInfo repo )
00146       {
00147         std::map<Url, shared_ptr<MediaSetAccess> >::const_iterator it;
00148         it = _medias.find(url);
00149         shared_ptr<MediaSetAccess> media;
00150         if ( it != _medias.end() )
00151         {
00152           media = it->second;
00153         }
00154         else
00155         {
00156           media.reset( new MediaSetAccess(url) );
00157           _medias[url] = media;
00158         }
00159         setVerifierForRepo( repo, media );
00160         return media;
00161       }
00162 
00163       private:
00164         void setVerifierForRepo( RepoInfo repo, shared_ptr<MediaSetAccess> media )
00165         {
00166           // Always set the MediaSetAccess label.
00167           media->setLabel( repo.name() );
00168 
00169           // set a verifier if the repository has it
00170 
00171           Pathname mediafile = repo.metadataPath() + "/media.1/media";
00172           if ( ! repo.metadataPath().empty() )
00173           {
00174             if ( PathInfo(mediafile).isExist() )
00175             {
00176               std::map<shared_ptr<MediaSetAccess>, RepoInfo>::const_iterator it;
00177               it = _verifier.find(media);
00178               if ( it != _verifier.end() )
00179               {
00180                 if ( it->second.alias() == repo.alias() )
00181                 {
00182                   // this media is already using this repo verifier
00183                   return;
00184                 }
00185               }
00186 
00187               std::ifstream str(mediafile.asString().c_str());
00188               std::string vendor;
00189               std::string mediaid;
00190               std::string buffer;
00191               if ( str )
00192               {
00193                 getline(str, vendor);
00194                 getline(str, mediaid);
00195                 getline(str, buffer);
00196 
00197                 unsigned media_nr = str::strtonum<unsigned>(buffer);
00198                 MIL << "Repository '" << repo.alias() << "' has " << media_nr << " medias"<< endl;
00199 
00200                 for ( unsigned i=1; i <= media_nr; ++i )
00201                 {
00202                   media::MediaVerifierRef verifier( new repo::SUSEMediaVerifier( vendor, mediaid, i ) );
00203 
00204                   media->setVerifier( i, verifier);
00205                 }
00206                 _verifier[media] = repo;
00207               }
00208               else
00209               {
00210                 ZYPP_THROW(RepoMetadataException(repo));
00211               }
00212             }
00213             else
00214             {
00215               WAR << "No media verifier for repo '" << repo.alias() << "' media/media.1 does not exist in '" << repo.metadataPath() << "'" << endl;
00216             }
00217           }
00218           else
00219           {
00220             WAR << "'" << repo.alias() << "' metadata path is empty. Can't set verifier. Probably this repository does not come from RepoManager." << endl;
00221           }
00222         }
00223 
00224       private:
00225         std::map<shared_ptr<MediaSetAccess>, RepoInfo> _verifier;
00226         std::map<Url, shared_ptr<MediaSetAccess> > _medias;
00227 
00228       public:
00229         ProvideFilePolicy _defaultPolicy;
00230     };
00232 
00233 
00234     RepoMediaAccess::RepoMediaAccess( const ProvideFilePolicy & defaultPolicy_r )
00235       : _impl( new Impl( defaultPolicy_r ) )
00236     {}
00237 
00238     RepoMediaAccess::~RepoMediaAccess()
00239     {}
00240 
00241     void RepoMediaAccess::setDefaultPolicy( const ProvideFilePolicy & policy_r )
00242     { _impl->_defaultPolicy = policy_r; }
00243 
00244     const ProvideFilePolicy & RepoMediaAccess::defaultPolicy() const
00245     { return _impl->_defaultPolicy; }
00246 
00247     ManagedFile RepoMediaAccess::provideFile( RepoInfo repo_r,
00248                                               const OnMediaLocation & loc_r,
00249                                               const ProvideFilePolicy & policy_r )
00250     {
00251       MIL << loc_r << endl;
00252       // Arrange DownloadFileReportHack to recieve the source::DownloadFileReport
00253       // and redirect download progress triggers to call the ProvideFilePolicy
00254       // callback.
00255       DownloadFileReportHack dumb( bind( mem_fun_ref( &ProvideFilePolicy::progress ), ref( policy_r ), _1 ) );
00256 
00257       RepoException repo_excpt(repo_r,
00258                                str::form(_("Can't provide file '%s' from repository '%s'"),
00259                                loc_r.filename().c_str(),
00260                                repo_r.alias().c_str() ) );
00261 
00262       if ( repo_r.baseUrlsEmpty() )
00263       {
00264         repo_excpt.remember(RepoException(_("No url in repository.")));
00265         ZYPP_THROW(repo_excpt);
00266       }
00267 
00268       Fetcher fetcher;
00269       fetcher.addCachePath( repo_r.packagesPath() );
00270 
00271       MIL << "Added cache path " << repo_r.packagesPath() << endl;
00272 
00273       for ( RepoInfo::urls_const_iterator it = repo_r.baseUrlsBegin();
00274             it != repo_r.baseUrlsEnd();
00275             /* incremented in the loop */ )
00276       {
00277         Url url( *it );
00278         ++it;
00279         try
00280         {
00281           MIL << "Providing file of repo '" << repo_r.alias()
00282               << "' from " << url << endl;
00283           shared_ptr<MediaSetAccess> access = _impl->mediaAccessForUrl( url, repo_r );
00284 
00285           fetcher.enqueue( loc_r );
00286 
00287           // FIXME: works for packages only
00288           fetcher.start( repo_r.packagesPath(), *access );
00289 
00290           // reached if no exception has been thrown, so this is the correct file
00291           ManagedFile ret( repo_r.packagesPath() + loc_r.filename() );
00292 
00293           std::string scheme( url.getScheme() );
00294           if ( !repo_r.keepPackages() )
00295           {
00296             ret.setDispose( filesystem::unlink );
00297           }
00298 
00299           if ( loc_r.checksum().empty() )
00300           {
00301             // no checksum in metadata
00302             WAR << "No checksum in metadata " << loc_r << endl;
00303           }
00304           else
00305           {
00306             std::ifstream input( ret->asString().c_str() );
00307             CheckSum retChecksum( loc_r.checksum().type(), input );
00308             input.close();
00309 
00310             if ( loc_r.checksum() != retChecksum )
00311             {
00312               // failed integity check
00313               std::ostringstream err;
00314               err << "File " << ret << " fails integrity check. Expected: [" << loc_r.checksum() << "] Got: [";
00315               if ( retChecksum.empty() )
00316                 err << "Failed to compute checksum";
00317               else
00318                 err << retChecksum;
00319               err << "]";
00320 
00321               WAR << err.str() << endl;
00322 
00323               if ( policy_r.failOnChecksumError() )
00324                 ZYPP_THROW( FileCheckException( err.str() ) );
00325               else
00326                 WAR << "NO failOnChecksumError: " << err.str() << endl;
00327             }
00328           }
00329 
00330           MIL << "provideFile at " << ret << endl;
00331           return ret;
00332         }
00333         catch ( const SkipRequestException &e )
00334         {
00335           ZYPP_CAUGHT( e );
00336           ZYPP_RETHROW(e);
00337         }
00338         catch ( const AbortRequestException &e )
00339         {
00340           ZYPP_CAUGHT( e );
00341           ZYPP_RETHROW(e);
00342         }
00343         catch ( const Exception &e )
00344         {
00345           ZYPP_CAUGHT( e );
00346 
00347           repo_excpt.remember(e);
00348 
00349           WAR << "Trying next url" << endl;
00350           continue;
00351         }
00352       } // iteration over urls
00353 
00354       ZYPP_THROW(repo_excpt);
00355       return ManagedFile(); // not reached
00356     }
00357 
00359   } // namespace repo
00362 } // namespace zypp