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 
00057       struct DownloadFileReportHack : public callback::ReceiveReport<repo::RepoReport>
00058       {
00059         virtual bool progress( const ProgressData &progress )
00060         {
00061           if ( _redirect )
00062             return _redirect( progress.val() );
00063           return true;
00064         }
00065         function<bool ( int )> _redirect;
00066       };
00067 
00069     } // namespace
00071 
00072     ManagedFile provideFile( RepoInfo repo_r,
00073                              const OnMediaLocation & loc_r,
00074                              const ProvideFilePolicy & policy_r )
00075     {
00076       RepoMediaAccess access;
00077       return access.provideFile(repo_r, loc_r, policy_r );
00078     }
00079 
00081     class RepoMediaAccess::Impl
00082     {
00083     public:
00084       Impl( const ProvideFilePolicy & defaultPolicy_r )
00085         : _defaultPolicy( defaultPolicy_r )
00086       {}
00087 
00088       ~Impl()
00089       {
00090         std::map<Url, shared_ptr<MediaSetAccess> >::iterator it;
00091         for ( it = _medias.begin();
00092               it != _medias.end();
00093               ++it )
00094         {
00095           it->second->release();
00096         }
00097       }
00098 
00106       shared_ptr<MediaSetAccess> mediaAccessForUrl( const Url &url, RepoInfo repo )
00107       {
00108         std::map<Url, shared_ptr<MediaSetAccess> >::const_iterator it;
00109         it = _medias.find(url);
00110         shared_ptr<MediaSetAccess> media;
00111         if ( it != _medias.end() )
00112         {
00113           media = it->second;
00114         }
00115         else
00116         {
00117           media.reset( new MediaSetAccess(url) );
00118           _medias[url] = media;
00119         }
00120         setVerifierForRepo( repo, media );
00121         return media;
00122       }
00123 
00124       private:
00125         void setVerifierForRepo( RepoInfo repo, shared_ptr<MediaSetAccess> media )
00126         {
00127           // Always set the MediaSetAccess label.
00128           media->setLabel( repo.name() );
00129 
00130           // set a verifier if the repository has it
00131 
00132           Pathname mediafile = repo.metadataPath() + "/media.1/media";
00133           if ( ! repo.metadataPath().empty() )
00134           {
00135             if ( PathInfo(mediafile).isExist() )
00136             {
00137               std::map<shared_ptr<MediaSetAccess>, RepoInfo>::const_iterator it;
00138               it = _verifier.find(media);
00139               if ( it != _verifier.end() )
00140               {
00141                 if ( it->second.alias() == repo.alias() )
00142                 {
00143                   // this media is already using this repo verifier
00144                   return;
00145                 }
00146               }
00147 
00148               std::ifstream str(mediafile.asString().c_str());
00149               std::string vendor;
00150               std::string mediaid;
00151               std::string buffer;
00152               if ( str )
00153               {
00154                 getline(str, vendor);
00155                 getline(str, mediaid);
00156                 getline(str, buffer);
00157 
00158                 unsigned media_nr = str::strtonum<unsigned>(buffer);
00159                 MIL << "Repository '" << repo.alias() << "' has " << media_nr << " medias"<< endl;
00160 
00161                 for ( unsigned i=1; i <= media_nr; ++i )
00162                 {
00163                   media::MediaVerifierRef verifier( new repo::SUSEMediaVerifier( vendor, mediaid, i ) );
00164 
00165                   media->setVerifier( i, verifier);
00166                 }
00167                 _verifier[media] = repo;
00168               }
00169               else
00170               {
00171                 ZYPP_THROW(RepoMetadataException(repo));
00172               }
00173             }
00174             else
00175             {
00176               WAR << "No media verifier for repo '" << repo.alias() << "' media/media.1 does not exist in '" << repo.metadataPath() << "'" << endl;
00177             }
00178           }
00179           else
00180           {
00181             WAR << "'" << repo.alias() << "' metadata path is empty. Can't set verifier. Probably this repository does not come from RepoManager." << endl;
00182           }
00183         }
00184 
00185       private:
00186         std::map<shared_ptr<MediaSetAccess>, RepoInfo> _verifier;
00187         std::map<Url, shared_ptr<MediaSetAccess> > _medias;
00188 
00189       public:
00190         ProvideFilePolicy _defaultPolicy;
00191     };
00193 
00194 
00195     RepoMediaAccess::RepoMediaAccess( const ProvideFilePolicy & defaultPolicy_r )
00196       : _impl( new Impl( defaultPolicy_r ) )
00197     {}
00198 
00199     RepoMediaAccess::~RepoMediaAccess()
00200     {}
00201 
00202     void RepoMediaAccess::setDefaultPolicy( const ProvideFilePolicy & policy_r )
00203     { _impl->_defaultPolicy = policy_r; }
00204 
00205     const ProvideFilePolicy & RepoMediaAccess::defaultPolicy() const
00206     { return _impl->_defaultPolicy; }
00207 
00208     ManagedFile RepoMediaAccess::provideFile( RepoInfo repo_r,
00209                                               const OnMediaLocation & loc_r,
00210                                               const ProvideFilePolicy & policy_r )
00211     {
00212       MIL << loc_r << endl;
00213       // Arrange DownloadFileReportHack to recieve the source::DownloadFileReport
00214       // and redirect download progress triggers to call the ProvideFilePolicy
00215       // callback.
00216       DownloadFileReportHack dumb;
00217       dumb._redirect = bind( mem_fun_ref( &ProvideFilePolicy::progress ),
00218                              ref( policy_r ), _1 );
00219       callback::TempConnect<repo::RepoReport> temp( dumb );
00220 
00221       RepoException repo_excpt(repo_r,
00222                             str::form(_("Can't provide file '%s' from repository '%s'"),
00223                                loc_r.filename().c_str(),
00224                                repo_r.alias().c_str() ) );
00225 
00226       if ( repo_r.baseUrlsEmpty() )
00227       {
00228         repo_excpt.remember(RepoException(_("No url in repository.")));
00229         ZYPP_THROW(repo_excpt);
00230       }
00231 
00232       Fetcher fetcher;
00233       fetcher.addCachePath( repo_r.packagesPath() );
00234 
00235       MIL << "Added cache path " << repo_r.packagesPath() << endl;
00236 
00237       for ( RepoInfo::urls_const_iterator it = repo_r.baseUrlsBegin();
00238             it != repo_r.baseUrlsEnd();
00239             /* incremented in the loop */ )
00240       {
00241         Url url( *it );
00242         ++it;
00243         try
00244         {
00245           MIL << "Providing file of repo '" << repo_r.alias()
00246               << "' from " << url << endl;
00247           shared_ptr<MediaSetAccess> access = _impl->mediaAccessForUrl( url, repo_r );
00248 
00249           fetcher.enqueue( loc_r );
00250 
00251           // FIXME: works for packages only
00252           fetcher.start( repo_r.packagesPath(), *access );
00253 
00254           // reached if no exception has been thrown, so this is the correct file
00255           ManagedFile ret( repo_r.packagesPath() + loc_r.filename() );
00256 
00257           std::string scheme( url.getScheme() );
00258           if ( !repo_r.keepPackages() )
00259           {
00260             ret.setDispose( filesystem::unlink );
00261           }
00262 
00263           if ( loc_r.checksum().empty() )
00264           {
00265             // no checksum in metadata
00266             WAR << "No checksum in metadata " << loc_r << endl;
00267           }
00268           else
00269           {
00270             std::ifstream input( ret->asString().c_str() );
00271             CheckSum retChecksum( loc_r.checksum().type(), input );
00272             input.close();
00273 
00274             if ( loc_r.checksum() != retChecksum )
00275             {
00276               // failed integity check
00277               std::ostringstream err;
00278               err << "File " << ret << " fails integrity check. Expected: [" << loc_r.checksum() << "] Got: [";
00279               if ( retChecksum.empty() )
00280                 err << "Failed to compute checksum";
00281               else
00282                 err << retChecksum;
00283               err << "]";
00284 
00285               WAR << err.str() << endl;
00286 
00287               if ( policy_r.failOnChecksumError() )
00288                 ZYPP_THROW( FileCheckException( err.str() ) );
00289               else
00290                 WAR << "NO failOnChecksumError: " << err.str() << endl;
00291             }
00292           }
00293 
00294           MIL << "provideFile at " << ret << endl;
00295           return ret;
00296         }
00297         catch ( const SkipRequestException &e )
00298         {
00299           ZYPP_CAUGHT( e );
00300           ZYPP_RETHROW(e);
00301         }
00302         catch ( const AbortRequestException &e )
00303         {
00304           ZYPP_CAUGHT( e );
00305           ZYPP_RETHROW(e);
00306         }
00307         catch ( const Exception &e )
00308         {
00309           ZYPP_CAUGHT( e );
00310 
00311           repo_excpt.remember(e);
00312 
00313           WAR << "Trying next url" << endl;
00314           continue;
00315         }
00316       } // iteration over urls
00317 
00318       ZYPP_THROW(repo_excpt);
00319       return ManagedFile(); // not reached
00320     }
00321 
00323   } // namespace repo
00326 } // namespace zypp

doxygen