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