00001
00002
00003
00004
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
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 }
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
00167 media->setLabel( repo.name() );
00168
00169
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
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
00253
00254
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 )
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
00288 fetcher.start( repo_r.packagesPath(), *access );
00289
00290
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
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
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 }
00353
00354 ZYPP_THROW(repo_excpt);
00355 return ManagedFile();
00356 }
00357
00359 }
00362 }