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