libzypp  10.5.0
MediaSetAccess.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
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 //#include "zypp/source/MediaSetAccessReportReceivers.h"
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(...) {} // don't let exception escape a dtor.
00052   }
00053 
00054 
00055   void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
00056   {
00057     if (_medias.find(media_nr) != _medias.end())
00058     {
00059       // the media already exists, set theverifier
00060       media::MediaAccessId id = _medias[media_nr];
00061       media::MediaManager media_mgr;
00062       media_mgr.addVerifier( id, verifier );
00063       // remove any saved verifier for this media
00064       _verifiers.erase(media_nr);
00065     }
00066     else
00067     {
00068       // save the verifier in the map, and set it when
00069       // the media number is first attached
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; //disattached media is free
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     // try to attach the media
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       // get the mediaId, but don't try to attach it here
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         // try to attach the media
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) // no use in calling this again
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           // set up the reason
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           // non interactive only bother the user if wrong medium is in the drive
00260           // otherwise propagate the error
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             // release all media before requesting another (#336881)
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             // eject
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             // retry
00308             DBG << "Going to try again" << endl;
00309             // invalidate current media access id
00310             media_mgr.close(media);
00311             _medias.erase(media_nr);
00312 
00313             // not attaching, media set will do that for us
00314             // this could generate uncaught exception (#158620)
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       // retry or change URL
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         // a verifier is set for this media
00366         // FIXME check the case where the verifier exists
00367         // but we have no access id for the media
00368         media::MediaAccessId id = _medias[medianr];
00369         media::MediaManager media_mgr;
00370         media_mgr.delVerifier(id);
00371         media_mgr.addVerifier( id, _verifiers[medianr] );
00372         // remove any saved verifier for this media
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       // TODO the iso parameter will not be required in the future, this
00397       // code has to be adapted together with the MediaISO change.
00398       // maybe some MediaISOURL interface should be used.
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 } // namespace zypp