libzypp 8.13.6
|
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