00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <iostream>
00011 #include <fstream>
00012
00013 #include "zypp/base/LogTools.h"
00014 #include "zypp/base/Regex.h"
00015 #include "zypp/base/UserRequestException.h"
00016 #include "zypp/ZYppCallbacks.h"
00017 #include "zypp/MediaSetAccess.h"
00018 #include "zypp/PathInfo.h"
00019
00020
00021 using namespace std;
00022
00024 namespace zypp
00025 {
00026
00027 IMPL_PTR_TYPE(MediaSetAccess);
00028
00030
00031 MediaSetAccess::MediaSetAccess(const Url &url,
00032 const Pathname & prefered_attach_point)
00033 : _url(url)
00034 , _prefAttachPoint(prefered_attach_point)
00035 {}
00036
00037 MediaSetAccess::MediaSetAccess(const std::string & label_r,
00038 const Url &url,
00039 const Pathname & prefered_attach_point)
00040 : _url(url)
00041 , _prefAttachPoint(prefered_attach_point)
00042 , _label( label_r )
00043 {}
00044
00045 MediaSetAccess::~MediaSetAccess()
00046 {
00047 try
00048 {
00049 release();
00050 }
00051 catch(...) {}
00052 }
00053
00054
00055 void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
00056 {
00057 if (_medias.find(media_nr) != _medias.end())
00058 {
00059
00060 media::MediaAccessId id = _medias[media_nr];
00061 media::MediaManager media_mgr;
00062 media_mgr.addVerifier( id, verifier );
00063
00064 _verifiers.erase(media_nr);
00065 }
00066 else
00067 {
00068
00069
00070 _verifiers[media_nr] = verifier;
00071 }
00072 }
00073
00074 void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
00075 {
00076 releaseFile( on_media_file.filename(), on_media_file.medianr() );
00077 }
00078
00079 void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
00080 {
00081 media::MediaManager media_mgr;
00082 media::MediaAccessId media;
00083
00084 media = getMediaAccessId( media_nr);
00085 DBG << "Going to release file " << file
00086 << " from media number " << media_nr << endl;
00087
00088 if ( ! media_mgr.isAttached(media) )
00089 return;
00090
00091 media_mgr.releaseFile (media, file);
00092 }
00093
00094 void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
00095 bool dots, unsigned media_nr )
00096 {
00097 media::MediaManager media_mgr;
00098 media::MediaAccessId media;
00099 media = getMediaAccessId(media_nr);
00100
00101
00102 if ( ! media_mgr.isAttached(media) )
00103 media_mgr.attach(media);
00104
00105 media_mgr.dirInfo(media, retlist, dirname, dots);
00106 }
00107
00108 struct ProvideFileOperation
00109 {
00110 Pathname result;
00111 void operator()( media::MediaAccessId media, const Pathname &file )
00112 {
00113 media::MediaManager media_mgr;
00114 media_mgr.provideFile(media, file);
00115 result = media_mgr.localPath(media, file);
00116 }
00117 };
00118
00119 struct ProvideDirTreeOperation
00120 {
00121 Pathname result;
00122 void operator()( media::MediaAccessId media, const Pathname &file )
00123 {
00124 media::MediaManager media_mgr;
00125 media_mgr.provideDirTree(media, file);
00126 result = media_mgr.localPath(media, file);
00127 }
00128 };
00129
00130 struct ProvideDirOperation
00131 {
00132 Pathname result;
00133 void operator()( media::MediaAccessId media, const Pathname &file )
00134 {
00135 media::MediaManager media_mgr;
00136 media_mgr.provideDir(media, file);
00137 result = media_mgr.localPath(media, file);
00138 }
00139 };
00140
00141 struct ProvideFileExistenceOperation
00142 {
00143 bool result;
00144 ProvideFileExistenceOperation()
00145 : result(false)
00146 {}
00147
00148 void operator()( media::MediaAccessId media, const Pathname &file )
00149 {
00150 media::MediaManager media_mgr;
00151 result = media_mgr.doesFileExist(media, file);
00152 }
00153 };
00154
00155
00156
00157 Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options, const Pathname &deltafile )
00158 {
00159 ProvideFileOperation op;
00160 provide( boost::ref(op), resource, options, deltafile );
00161 return op.result;
00162 }
00163
00164 Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
00165 {
00166 OnMediaLocation resource;
00167 ProvideFileOperation op;
00168 resource.setLocation(file, media_nr);
00169 provide( boost::ref(op), resource, options, Pathname() );
00170 return op.result;
00171 }
00172
00173 bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
00174 {
00175 ProvideFileExistenceOperation op;
00176 OnMediaLocation resource;
00177 resource.setLocation(file, media_nr);
00178 provide( boost::ref(op), resource, PROVIDE_DEFAULT, Pathname());
00179 return op.result;
00180 }
00181
00182 void MediaSetAccess::provide( ProvideOperation op,
00183 const OnMediaLocation &resource,
00184 ProvideFileOptions options,
00185 const Pathname &deltafile )
00186 {
00187 Pathname file(resource.filename());
00188 unsigned media_nr(resource.medianr());
00189
00190 callback::SendReport<media::MediaChangeReport> report;
00191 media::MediaManager media_mgr;
00192
00193 media::MediaAccessId media;
00194
00195 do
00196 {
00197
00198 media = getMediaAccessId( media_nr);
00199 bool deltafileset = false;
00200
00201 try
00202 {
00203 DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
00204 << " from media number " << media_nr << endl;
00205
00206 if ( ! media_mgr.isAttached(media) )
00207 media_mgr.attach(media);
00208 media_mgr.setDeltafile(media, deltafile);
00209 deltafileset = true;
00210 op(media, file);
00211 media_mgr.setDeltafile(media, Pathname());
00212 break;
00213 }
00214 catch ( media::MediaException & excp )
00215 {
00216 ZYPP_CAUGHT(excp);
00217 if (deltafileset)
00218 media_mgr.setDeltafile(media, Pathname());
00219 media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
00220 unsigned int devindex = 0;
00221 vector<string> devices;
00222 media_mgr.getDetectedDevices(media, devices, devindex);
00223
00224 do
00225 {
00226 if (user != media::MediaChangeReport::EJECT)
00227 {
00228 DBG << "Media couldn't provide file " << file << " , releasing." << endl;
00229 try
00230 {
00231 media_mgr.release(media);
00232 }
00233 catch (const Exception & excpt_r)
00234 {
00235 ZYPP_CAUGHT(excpt_r);
00236 MIL << "Failed to release media " << media << endl;
00237 }
00238 }
00239
00240
00241 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
00242
00243 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
00244 typeid(excp) == typeid( media::MediaNotAFileException ) )
00245 {
00246 reason = media::MediaChangeReport::NOT_FOUND;
00247 }
00248 else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
00249 typeid(excp) == typeid( media::MediaNotAttachedException) )
00250 {
00251 reason = media::MediaChangeReport::WRONG;
00252 }
00253 else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
00254 typeid(excp) == typeid( media::MediaTemporaryProblemException))
00255 {
00256 reason = media::MediaChangeReport::IO_SOFT;
00257 }
00258
00259
00260
00261 if ( ( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG)
00262 {
00263 MIL << "Can't provide file. Non-Interactive mode." << endl;
00264 ZYPP_RETHROW(excp);
00265 }
00266 else
00267 {
00268
00269 media_mgr.releaseAll();
00270
00271 user = report->requestMedia (
00272 _url,
00273 media_nr,
00274 _label,
00275 reason,
00276 excp.asUserString(),
00277 devices,
00278 devindex
00279 );
00280 }
00281
00282 MIL << "ProvideFile exception caught, callback answer: " << user << endl;
00283
00284 if( user == media::MediaChangeReport::ABORT )
00285 {
00286 DBG << "Aborting" << endl;
00287 ZYPP_RETHROW ( excp );
00288 }
00289 else if ( user == media::MediaChangeReport::IGNORE )
00290 {
00291 DBG << "Skipping" << endl;
00292 SkipRequestException nexcp("User-requested skipping of a file");
00293 nexcp.remember(excp);
00294 ZYPP_THROW(nexcp);
00295 }
00296 else if ( user == media::MediaChangeReport::EJECT )
00297 {
00298 DBG << "Eject: try to release" << endl;
00299 media_mgr.releaseAll();
00300
00301 media_mgr.release (media,
00302 devindex < devices.size() ? devices[devindex] : "");
00303 }
00304 else if ( user == media::MediaChangeReport::RETRY ||
00305 user == media::MediaChangeReport::CHANGE_URL )
00306 {
00307
00308 DBG << "Going to try again" << endl;
00309
00310 media_mgr.close(media);
00311 _medias.erase(media_nr);
00312
00313
00314
00315 break;
00316 }
00317 else
00318 {
00319 DBG << "Don't know, let's ABORT" << endl;
00320 ZYPP_RETHROW ( excp );
00321 }
00322 } while( user == media::MediaChangeReport::EJECT );
00323 }
00324
00325
00326 } while( true );
00327 }
00328
00329 Pathname MediaSetAccess::provideDir(const Pathname & dir,
00330 bool recursive,
00331 unsigned media_nr,
00332 ProvideFileOptions options )
00333 {
00334 OnMediaLocation resource;
00335 resource.setLocation(dir, media_nr);
00336 if ( recursive )
00337 {
00338 ProvideDirTreeOperation op;
00339 provide( boost::ref(op), resource, options, Pathname());
00340 return op.result;
00341 }
00342 ProvideDirOperation op;
00343 provide( boost::ref(op), resource, options, Pathname());
00344 return op.result;
00345 }
00346
00347 media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
00348 {
00349 media::MediaManager media_mgr;
00350
00351 if (_medias.find(medianr) != _medias.end())
00352 {
00353 media::MediaAccessId id = _medias[medianr];
00354 return id;
00355 }
00356 Url url;
00357 url = rewriteUrl (_url, medianr);
00358 media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
00359 _medias[medianr] = id;
00360
00361 try
00362 {
00363 if (_verifiers.find(medianr) != _verifiers.end())
00364 {
00365
00366
00367
00368 media::MediaAccessId id = _medias[medianr];
00369 media::MediaManager media_mgr;
00370 media_mgr.delVerifier(id);
00371 media_mgr.addVerifier( id, _verifiers[medianr] );
00372
00373 _verifiers.erase(medianr);
00374 }
00375 }
00376 catch ( const Exception &e )
00377 {
00378 ZYPP_CAUGHT(e);
00379 WAR << "Verifier not found" << endl;
00380 }
00381
00382 return id;
00383 }
00384
00385
00386 Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
00387 {
00388 std::string scheme = url_r.getScheme();
00389 if (scheme == "cd" || scheme == "dvd")
00390 return url_r;
00391
00392 DBG << "Rewriting url " << url_r << endl;
00393
00394 if( scheme == "iso")
00395 {
00396
00397
00398
00399 std::string isofile = url_r.getQueryParam("iso");
00400 str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
00401
00402 str::smatch what;
00403 if(str::regex_match(isofile, what, e))
00404 {
00405 Url url( url_r);
00406 isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
00407 url.setQueryParam("iso", isofile);
00408 DBG << "Url rewrite result: " << url << endl;
00409 return url;
00410 }
00411 }
00412 else
00413 {
00414 std::string pathname = url_r.getPathName();
00415 str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
00416 str::smatch what;
00417 if(str::regex_match(pathname, what, e))
00418 {
00419 Url url( url_r);
00420 pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
00421 url.setPathName(pathname);
00422 DBG << "Url rewrite result: " << url << endl;
00423 return url;
00424 }
00425 }
00426 return url_r;
00427 }
00428
00429 void MediaSetAccess::release()
00430 {
00431 DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
00432 media::MediaManager manager;
00433 for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
00434 manager.release(m->second, "");
00435 }
00436
00437 std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
00438 {
00439 str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
00440 return str;
00441 }
00442
00444 }