libzypp  10.5.0
MediaAccess.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <ctype.h>
00014 
00015 #include <iostream>
00016 #include <map>
00017 
00018 #include "zypp/base/Logger.h"
00019 #include "zypp/ZConfig.h"
00020 #include "zypp/PluginScript.h"
00021 #include "zypp/ExternalProgram.h"
00022 
00023 #include "zypp/media/MediaException.h"
00024 #include "zypp/media/MediaAccess.h"
00025 #include "zypp/media/MediaHandler.h"
00026 
00027 #include "zypp/media/MediaNFS.h"
00028 #include "zypp/media/MediaCD.h"
00029 #include "zypp/media/MediaDIR.h"
00030 #include "zypp/media/MediaDISK.h"
00031 #include "zypp/media/MediaCIFS.h"
00032 #include "zypp/media/MediaCurl.h"
00033 #include "zypp/media/MediaAria2c.h"
00034 #include "zypp/media/MediaMultiCurl.h"
00035 #include "zypp/media/MediaISO.h"
00036 #include "zypp/media/MediaPlugin.h"
00037 #include "zypp/media/UrlResolverPlugin.h"
00038 
00039 using namespace std;
00040 
00041 namespace zypp {
00042   namespace media {
00043 
00045 //
00046 //      CLASS NAME : MediaAccess
00047 //
00049 
00050 const Pathname MediaAccess::_noPath; // empty path
00051 
00053 // constructor
00054 MediaAccess::MediaAccess ()
00055     : _handler (0)
00056 {
00057 }
00058 
00059 // destructor
00060 MediaAccess::~MediaAccess()
00061 {
00062   try
00063     {
00064       close(); // !!! make sure handler gets properly deleted.
00065     }
00066   catch(...) {}
00067 }
00068 
00069 AttachedMedia
00070 MediaAccess::attachedMedia() const
00071 {
00072         return _handler ? _handler->attachedMedia()
00073                         : AttachedMedia();
00074 }
00075 
00076 bool
00077 MediaAccess::isSharedMedia() const
00078 {
00079         return _handler ? _handler->isSharedMedia()
00080                         : false;
00081 }
00082 
00083 void
00084 MediaAccess::resetParentId()
00085 {
00086         if( _handler) _handler->resetParentId();
00087 }
00088 
00089 bool
00090 MediaAccess::dependsOnParent() const
00091 {
00092         return _handler ? _handler->dependsOnParent() : false;
00093 }
00094 
00095 bool
00096 MediaAccess::dependsOnParent(MediaAccessId parentId,
00097                              bool exactIdMatch) const
00098 {
00099         return _handler ? _handler->dependsOnParent(parentId, exactIdMatch)
00100                         : false;
00101 }
00102 
00103 // open URL
00104 void
00105 MediaAccess::open (const Url& o_url, const Pathname & preferred_attach_point)
00106 {
00107     if(!o_url.isValid()) {
00108         MIL << "Url is not valid" << endl;
00109         ZYPP_THROW(MediaBadUrlException(o_url));
00110     }
00111 
00112     close();
00113 
00114     UrlResolverPlugin::HeaderList custom_headers;
00115     Url url = UrlResolverPlugin::resolveUrl(o_url, custom_headers);
00116 
00117     std::string scheme = url.getScheme();
00118     MIL << "Trying scheme '" << scheme << "'" << endl;
00119 
00120     /*
00121     ** WARNING: Don't forget to update MediaAccess::downloads(url)
00122     **          if you are adding a new url scheme / handler!
00123     */
00124     if (scheme == "cd" || scheme == "dvd")
00125         _handler = new MediaCD (url,preferred_attach_point);
00126     else if (scheme == "nfs" || scheme == "nfs4")
00127         _handler = new MediaNFS (url,preferred_attach_point);
00128     else if (scheme == "iso")
00129         _handler = new MediaISO (url,preferred_attach_point);
00130     else if (scheme == "file" || scheme == "dir")
00131         _handler = new MediaDIR (url,preferred_attach_point);
00132     else if (scheme == "hd")
00133         _handler = new MediaDISK (url,preferred_attach_point);
00134     else if (scheme == "cifs" || scheme == "smb")
00135         _handler = new MediaCIFS (url,preferred_attach_point);
00136     else if (scheme == "ftp" || scheme == "http" || scheme == "https")
00137     {
00138         // Another good idea would be activate MediaAria2c handler via external var
00139         bool use_aria = false;
00140         bool use_multicurl = true;
00141         string urlmediahandler ( url.getQueryParam("mediahandler") );
00142         if ( urlmediahandler == "multicurl" )
00143         {
00144           use_aria = false;
00145           use_multicurl = true;
00146         }
00147         else if ( urlmediahandler == "aria2c" )
00148         {
00149           use_aria = true;
00150           use_multicurl = false;
00151         }
00152         else if ( urlmediahandler == "curl" )
00153         {
00154           use_aria = false;
00155           use_multicurl = false;
00156         }
00157         else
00158         {
00159           if ( ! urlmediahandler.empty() )
00160           {
00161             WAR << "unknown mediahandler set: " << urlmediahandler << endl;
00162           }
00163           const char *ariaenv = getenv( "ZYPP_ARIA2C" );
00164           const char *multicurlenv = getenv( "ZYPP_MULTICURL" );
00165           // if user disabled it manually
00166           if ( use_multicurl && multicurlenv && ( strcmp(multicurlenv, "0" ) == 0 ) )
00167           {
00168               WAR << "multicurl manually disabled." << endl;
00169               use_multicurl = false;
00170           }
00171           else if ( !use_multicurl && multicurlenv && ( strcmp(multicurlenv, "1" ) == 0 ) )
00172           {
00173               WAR << "multicurl manually enabled." << endl;
00174               use_multicurl = true;
00175           }
00176           // if user disabled it manually
00177           if ( use_aria && ariaenv && ( strcmp(ariaenv, "0" ) == 0 ) )
00178           {
00179               WAR << "aria2c manually disabled. Falling back to curl" << endl;
00180               use_aria = false;
00181           }
00182           else if ( !use_aria && ariaenv && ( strcmp(ariaenv, "1" ) == 0 ) )
00183           {
00184               // no aria for ftp - no advantage in that over curl
00185               if ( url.getScheme() == "ftp" )
00186                   WAR << "no aria2c for FTP, despite ZYPP_ARIA2C=1" << endl;
00187               else
00188               {
00189                   WAR << "aria2c manually enabled." << endl;
00190                   use_aria = true;
00191               }
00192           }
00193         }
00194 
00195         // disable if it does not exist
00196         if ( use_aria && ! MediaAria2c::existsAria2cmd() )
00197         {
00198             WAR << "aria2c not found. Falling back to curl" << endl;
00199             use_aria = false;
00200         }
00201 
00202         MediaCurl *curl;
00203 
00204         if ( use_aria )
00205             curl = new MediaAria2c (url,preferred_attach_point);
00206         else if ( use_multicurl )
00207             curl = new MediaMultiCurl (url,preferred_attach_point);
00208         else
00209             curl = new MediaCurl (url,preferred_attach_point);
00210 
00211         UrlResolverPlugin::HeaderList::const_iterator it;
00212         for (it = custom_headers.begin();
00213              it != custom_headers.end();
00214              ++it) {
00215             std::string header = it->first + ": " + it->second;
00216             MIL << "Added custom header -> " << header << endl;
00217             curl->settings().addHeader(header);
00218         }
00219         _handler = curl;
00220     }
00221     else if (scheme == "plugin" )
00222         _handler = new MediaPlugin (url,preferred_attach_point);
00223     else
00224     {
00225         ZYPP_THROW(MediaUnsupportedUrlSchemeException(url));
00226     }
00227 
00228     // check created handler
00229     if ( !_handler ){
00230       ERR << "Failed to create media handler" << endl;
00231       ZYPP_THROW(MediaSystemException(url, "Failed to create media handler"));
00232     }
00233 
00234     MIL << "Opened: " << *this << endl;
00235 }
00236 
00237 // Type of media if open, otherwise NONE.
00238 std::string
00239 MediaAccess::protocol() const
00240 {
00241   if ( !_handler )
00242     return "unknown";
00243 
00244   return _handler->protocol();
00245 }
00246 
00247 bool
00248 MediaAccess::downloads() const
00249 {
00250         return _handler ? _handler->downloads() : false;
00251 }
00252 
00254 //
00255 //
00256 //      METHOD NAME : MediaAccess::url
00257 //      METHOD TYPE : Url
00258 //
00259 Url MediaAccess::url() const
00260 {
00261   if ( !_handler )
00262     return Url();
00263 
00264   return _handler->url();
00265 }
00266 
00267 // close handler
00268 void
00269 MediaAccess::close ()
00270 {
00272   // !!! make shure handler gets properly deleted.
00273   // I.e. release attached media before deleting the handler.
00275   if ( _handler ) {
00276     try {
00277       _handler->release();
00278     }
00279     catch (const MediaException & excpt_r)
00280     {
00281       ZYPP_CAUGHT(excpt_r);
00282       WAR << "Close: " << *this << " (" << excpt_r << ")" << endl;
00283       ZYPP_RETHROW(excpt_r);
00284     }
00285     MIL << "Close: " << *this << " (OK)" << endl;
00286     delete _handler;
00287     _handler = 0;
00288   }
00289 }
00290 
00291 
00292 // attach media
00293 void MediaAccess::attach (bool next)
00294 {
00295   if ( !_handler ) {
00296     ZYPP_THROW(MediaNotOpenException("attach"));
00297   }
00298   _handler->attach(next);
00299 }
00300 
00301 // True if media is open and attached.
00302 bool
00303 MediaAccess::isAttached() const
00304 {
00305   return( _handler && _handler->isAttached() );
00306 }
00307 
00308 
00309 bool MediaAccess::hasMoreDevices() const
00310 {
00311   return _handler && _handler->hasMoreDevices();
00312 }
00313 
00314 
00315 void
00316 MediaAccess::getDetectedDevices(std::vector<std::string> & devices,
00317                                 unsigned int & index) const
00318 {
00319   if (_handler)
00320   {
00321     _handler->getDetectedDevices(devices, index);
00322     return;
00323   }
00324 
00325   if (!devices.empty())
00326     devices.clear();
00327   index = 0;
00328 }
00329 
00330 
00331 // local directory that corresponds to medias url
00332 // If media is not open an empty pathname.
00333 Pathname
00334 MediaAccess::localRoot() const
00335 {
00336   if ( !_handler )
00337     return _noPath;
00338 
00339   return _handler->localRoot();
00340 }
00341 
00342 // Short for 'localRoot() + pathname', but returns an empty
00343 // * pathname if media is not open.
00344 Pathname
00345 MediaAccess::localPath( const Pathname & pathname ) const
00346 {
00347   if ( !_handler )
00348     return _noPath;
00349 
00350   return _handler->localPath( pathname );
00351 }
00352 
00353 void
00354 MediaAccess::disconnect()
00355 {
00356   if ( !_handler )
00357     ZYPP_THROW(MediaNotOpenException("disconnect"));
00358 
00359   _handler->disconnect();
00360 }
00361 
00362 
00363 void
00364 MediaAccess::release( const std::string & ejectDev )
00365 {
00366   if ( !_handler )
00367     return;
00368 
00369   _handler->release( ejectDev );
00370 }
00371 
00372 // provide file denoted by path to attach dir
00373 //
00374 // filename is interpreted relative to the attached url
00375 // and a path prefix is preserved to destination
00376 void
00377 MediaAccess::provideFile( const Pathname & filename ) const
00378 {
00379   if ( !_handler ) {
00380     ZYPP_THROW(MediaNotOpenException("provideFile(" + filename.asString() + ")"));
00381   }
00382 
00383   _handler->provideFile( filename );
00384 }
00385 
00386 void
00387 MediaAccess::setDeltafile( const Pathname & filename ) const
00388 {
00389   if ( !_handler ) {
00390     ZYPP_THROW(MediaNotOpenException("setDeltafile(" + filename.asString() + ")"));
00391   }
00392 
00393   _handler->setDeltafile( filename );
00394 }
00395 
00396 void
00397 MediaAccess::releaseFile( const Pathname & filename ) const
00398 {
00399   if ( !_handler )
00400     return;
00401 
00402   _handler->releaseFile( filename );
00403 }
00404 
00405 // provide directory tree denoted by path to attach dir
00406 //
00407 // dirname is interpreted relative to the attached url
00408 // and a path prefix is preserved to destination
00409 void
00410 MediaAccess::provideDir( const Pathname & dirname ) const
00411 {
00412   if ( !_handler ) {
00413     ZYPP_THROW(MediaNotOpenException("provideDir(" + dirname.asString() + ")"));
00414   }
00415 
00416   _handler->provideDir( dirname );
00417 }
00418 
00419 void
00420 MediaAccess::provideDirTree( const Pathname & dirname ) const
00421 {
00422   if ( !_handler ) {
00423     ZYPP_THROW(MediaNotOpenException("provideDirTree(" + dirname.asString() + ")"));
00424   }
00425 
00426   _handler->provideDirTree( dirname );
00427 }
00428 
00429 void
00430 MediaAccess::releaseDir( const Pathname & dirname ) const
00431 {
00432   if ( !_handler )
00433     return;
00434 
00435   _handler->releaseDir( dirname );
00436 }
00437 
00438 void
00439 MediaAccess::releasePath( const Pathname & pathname ) const
00440 {
00441   if ( !_handler )
00442     return;
00443 
00444   _handler->releasePath( pathname );
00445 }
00446 
00447 // Return content of directory on media
00448 void
00449 MediaAccess::dirInfo( std::list<std::string> & retlist, const Pathname & dirname, bool dots ) const
00450 {
00451   retlist.clear();
00452 
00453   if ( !_handler ) {
00454     ZYPP_THROW(MediaNotOpenException("dirInfo(" + dirname.asString() + ")"));
00455   }
00456 
00457   _handler->dirInfo( retlist, dirname, dots );
00458 }
00459 
00460 // Return content of directory on media
00461 void
00462 MediaAccess::dirInfo( filesystem::DirContent & retlist, const Pathname & dirname, bool dots ) const
00463 {
00464   retlist.clear();
00465 
00466   if ( !_handler ) {
00467     ZYPP_THROW(MediaNotOpenException("dirInfo(" + dirname.asString() + ")"));
00468   }
00469 
00470   _handler->dirInfo( retlist, dirname, dots );
00471 }
00472 
00473 // return if a file exists
00474 bool
00475 MediaAccess::doesFileExist( const Pathname & filename ) const
00476 {
00477   if ( !_handler ) {
00478     ZYPP_THROW(MediaNotOpenException("doesFileExist(" + filename.asString() + ")"));
00479   }
00480 
00481   return _handler->doesFileExist( filename );
00482 }
00483 
00484 std::ostream &
00485 MediaAccess::dumpOn( std::ostream & str ) const
00486 {
00487   if ( !_handler )
00488     return str << "MediaAccess( closed )";
00489 
00490   str << _handler->protocol() << "(" << *_handler << ")";
00491   return str;
00492 }
00493 
00494 void MediaAccess::getFile( const Url &from, const Pathname &to )
00495 {
00496   DBG << "From: " << from << endl << "To: " << to << endl;
00497 
00498   Pathname path = from.getPathData();
00499   Pathname dir = path.dirname();
00500   string base = path.basename();
00501 
00502   Url u = from;
00503   u.setPathData( dir.asString() );
00504 
00505   MediaAccess media;
00506 
00507   try {
00508     media.open( u );
00509     media.attach();
00510     media._handler->provideFileCopy( base, to );
00511     media.release();
00512   }
00513   catch (const MediaException & excpt_r)
00514   {
00515     ZYPP_RETHROW(excpt_r);
00516   }
00517 }
00518 
00519     std::ostream & operator<<( std::ostream & str, const MediaAccess & obj )
00520     { return obj.dumpOn( str ); }
00521 
00523   } // namespace media
00524 } // namespace zypp