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 )
00158   {
00159     ProvideFileOperation op;
00160     provide( boost::ref(op), resource, options );
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 );
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);
00179     return op.result;
00180   }
00181 
00182   void MediaSetAccess::provide( ProvideOperation op,
00183                                 const OnMediaLocation &resource,
00184                                 ProvideFileOptions options )
00185   {
00186     Pathname file(resource.filename());
00187     unsigned media_nr(resource.medianr());
00188 
00189     callback::SendReport<media::MediaChangeReport> report;
00190     media::MediaManager media_mgr;
00191 
00192     media::MediaAccessId media;
00193 
00194     do
00195     {
00196       // get the mediaId, but don't try to attach it here
00197       media = getMediaAccessId( media_nr);
00198 
00199       try
00200       {
00201         DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
00202             << " from media number " << media_nr << endl;
00203         // try to attach the media
00204         if ( ! media_mgr.isAttached(media) )
00205           media_mgr.attach(media);
00206         op(media, file);
00207         break;
00208       }
00209       catch ( media::MediaException & excp )
00210       {
00211         ZYPP_CAUGHT(excp);
00212         media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
00213         unsigned int devindex = 0;
00214         vector<string> devices;
00215         media_mgr.getDetectedDevices(media, devices, devindex);
00216 
00217         do
00218         {
00219           if (user != media::MediaChangeReport::EJECT) // no use in calling this again
00220           {
00221             DBG << "Media couldn't provide file " << file << " , releasing." << endl;
00222             try
00223             {
00224               media_mgr.release(media);
00225             }
00226             catch (const Exception & excpt_r)
00227             {
00228                 ZYPP_CAUGHT(excpt_r);
00229                 MIL << "Failed to release media " << media << endl;
00230             }
00231           }
00232 
00233           // set up the reason
00234           media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
00235 
00236           if( typeid(excp) == typeid( media::MediaFileNotFoundException )  ||
00237               typeid(excp) == typeid( media::MediaNotAFileException ) )
00238           {
00239             reason = media::MediaChangeReport::NOT_FOUND;
00240           }
00241           else if( typeid(excp) == typeid( media::MediaNotDesiredException)  ||
00242               typeid(excp) == typeid( media::MediaNotAttachedException) )
00243           {
00244             reason = media::MediaChangeReport::WRONG;
00245           }
00246           else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
00247                    typeid(excp) == typeid( media::MediaTemporaryProblemException))
00248           {
00249             reason = media::MediaChangeReport::IO_SOFT;
00250           }
00251 
00252           // non interactive only bother the user if wrong medium is in the drive
00253           // otherwise propagate the error
00254           if ( ( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG)
00255           {
00256               MIL << "Can't provide file. Non-Interactive mode." << endl;
00257               ZYPP_RETHROW(excp);
00258           }
00259           else
00260           {
00261             // release all media before requesting another (#336881)
00262             media_mgr.releaseAll();
00263 
00264             user = report->requestMedia (
00265               _url,
00266               media_nr,
00267               _label,
00268               reason,
00269               excp.asUserString(),
00270               devices,
00271               devindex
00272             );
00273           }
00274 
00275           MIL << "ProvideFile exception caught, callback answer: " << user << endl;
00276 
00277           if( user == media::MediaChangeReport::ABORT )
00278           {
00279             DBG << "Aborting" << endl;
00280             ZYPP_RETHROW ( excp );
00281           }
00282           else if ( user == media::MediaChangeReport::IGNORE )
00283           {
00284             DBG << "Skipping" << endl;
00285             SkipRequestException nexcp("User-requested skipping of a file");
00286             nexcp.remember(excp);
00287             ZYPP_THROW(nexcp);
00288           }
00289           else if ( user == media::MediaChangeReport::EJECT )
00290           {
00291             DBG << "Eject: try to release" << endl;
00292             media_mgr.releaseAll();
00293             // eject
00294             media_mgr.release (media,
00295               devindex < devices.size() ? devices[devindex] : "");
00296           }
00297           else if ( user == media::MediaChangeReport::RETRY  ||
00298             user == media::MediaChangeReport::CHANGE_URL )
00299           {
00300             // retry
00301             DBG << "Going to try again" << endl;
00302             // invalidate current media access id
00303             media_mgr.close(media);
00304             _medias.erase(media_nr);
00305 
00306             // not attaching, media set will do that for us
00307             // this could generate uncaught exception (#158620)
00308             break;
00309           }
00310           else
00311           {
00312             DBG << "Don't know, let's ABORT" << endl;
00313             ZYPP_RETHROW ( excp );
00314           }
00315         } while( user == media::MediaChangeReport::EJECT );
00316       }
00317 
00318       // retry or change URL
00319     } while( true );
00320   }
00321 
00322   Pathname MediaSetAccess::provideDir(const Pathname & dir,
00323                                       bool recursive,
00324                                       unsigned media_nr,
00325                                       ProvideFileOptions options )
00326   {
00327     OnMediaLocation resource;
00328     resource.setLocation(dir, media_nr);
00329     if ( recursive )
00330     {
00331         ProvideDirTreeOperation op;
00332         provide( boost::ref(op), resource, options);
00333         return op.result;
00334     }
00335     ProvideDirOperation op;
00336     provide( boost::ref(op), resource, options);
00337     return op.result;
00338   }
00339 
00340   media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
00341   {
00342     media::MediaManager media_mgr;
00343 
00344     if (_medias.find(medianr) != _medias.end())
00345     {
00346       media::MediaAccessId id = _medias[medianr];
00347       return id;
00348     }
00349     Url url;
00350     url = rewriteUrl (_url, medianr);
00351     media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
00352     _medias[medianr] = id;
00353 
00354     try
00355     {
00356       if (_verifiers.find(medianr) != _verifiers.end())
00357       {
00358         // a verifier is set for this media
00359         // FIXME check the case where the verifier exists
00360         // but we have no access id for the media
00361         media::MediaAccessId id = _medias[medianr];
00362         media::MediaManager media_mgr;
00363         media_mgr.delVerifier(id);
00364         media_mgr.addVerifier( id, _verifiers[medianr] );
00365         // remove any saved verifier for this media
00366         _verifiers.erase(medianr);
00367       }
00368     }
00369     catch ( const Exception &e )
00370     {
00371       ZYPP_CAUGHT(e);
00372       WAR << "Verifier not found" << endl;
00373     }
00374 
00375     return id;
00376   }
00377 
00378 
00379   Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
00380   {
00381     std::string scheme = url_r.getScheme();
00382     if (scheme == "cd" || scheme == "dvd")
00383       return url_r;
00384 
00385     DBG << "Rewriting url " << url_r << endl;
00386 
00387     if( scheme == "iso")
00388     {
00389       // TODO the iso parameter will not be required in the future, this
00390       // code has to be adapted together with the MediaISO change.
00391       // maybe some MediaISOURL interface should be used.
00392       std::string isofile = url_r.getQueryParam("iso");
00393       str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
00394 
00395       str::smatch what;
00396       if(str::regex_match(isofile, what, e))
00397       {
00398         Url url( url_r);
00399         isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
00400         url.setQueryParam("iso", isofile);
00401         DBG << "Url rewrite result: " << url << endl;
00402         return url;
00403       }
00404     }
00405     else
00406     {
00407       std::string pathname = url_r.getPathName();
00408       str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
00409       str::smatch what;
00410       if(str::regex_match(pathname, what, e))
00411       {
00412         Url url( url_r);
00413         pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
00414         url.setPathName(pathname);
00415         DBG << "Url rewrite result: " << url << endl;
00416         return url;
00417       }
00418     }
00419     return url_r;
00420   }
00421 
00422   void MediaSetAccess::release()
00423   {
00424     DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
00425     media::MediaManager manager;
00426     for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
00427       manager.release(m->second, "");
00428   }
00429 
00430   std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
00431   {
00432     str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
00433     return str;
00434   }
00435 
00437 } // namespace zypp

doxygen