MediaSMB.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <iostream>
00014 #include <fstream>
00015 
00016 #include "zypp/base/Logger.h"
00017 #include "zypp/TmpPath.h"
00018 #include "zypp/KVMap.h"
00019 #include "zypp/media/Mount.h"
00020 #include "zypp/media/MediaSMB.h"
00021 
00022 #include <sys/types.h>
00023 #include <sys/mount.h>
00024 #include <errno.h>
00025 #include <dirent.h>
00026 
00027 using namespace std;
00028 
00029 namespace zypp {
00030   namespace media {
00031 
00032     /******************************************************************
00033     **
00034     **
00035     **  FUNCTION NAME : getShare
00036     **  FUNCTION TYPE : inline Pathname
00037     **
00038     ** Get the 1st path component (CIFS share name).
00039     */
00040     inline string getShare( Pathname spath_r )
00041     {
00042       if ( spath_r.empty() )
00043         return string();
00044     
00045       string share( spath_r.absolutename().asString() );
00046       string::size_type sep = share.find( "/", 1 );
00047       if ( sep == string::npos )
00048         share = share.erase( 0, 1 ); // nothing but the share name in spath_r
00049       else
00050         share = share.substr( 1, sep-1 );
00051     
00052       // deescape %2f in sharename
00053       while ( (sep = share.find( "%2f" )) != string::npos ) {
00054         share.replace( sep, 3, "/" );
00055       }
00056     
00057       return share;
00058     }
00059 
00060     /******************************************************************
00061     **
00062     **
00063     **  FUNCTION NAME : stripShare
00064     **  FUNCTION TYPE : inline Pathname
00065     **
00066     ** Strip off the 1st path component (CIFS share name).
00067     */
00068     inline Pathname stripShare( Pathname spath_r )
00069     {
00070       if ( spath_r.empty() )
00071         return Pathname();
00072     
00073       string striped( spath_r.absolutename().asString() );
00074       string::size_type sep = striped.find( "/", 1 );
00075       if ( sep == string::npos )
00076         return "/"; // nothing but the share name in spath_r
00077     
00078       return striped.substr( sep );
00079     }
00080 
00082     //
00083     //  CLASS NAME : MediaSMB
00084     //
00086 
00088     //
00089     //
00090     //  METHOD NAME : MediaSMB::MediaSMB
00091     //  METHOD TYPE : Constructor
00092     //
00093     //  DESCRIPTION :
00094     //
00095     MediaSMB::MediaSMB( const Url &      url_r,
00096                         const Pathname & attach_point_hint_r )
00097         : MediaHandler( url_r, attach_point_hint_r,
00098                     stripShare( url_r.getPathName() ), // urlpath WITHOUT share name at attachpoint
00099                     false )       // does_download
00100         , _vfstype( "cifs" )
00101     {
00102         MIL << "MediaSMB::MediaSMB(" << url_r << ", " << attach_point_hint_r << ")" << endl;
00103     }
00104 
00106     //
00107     //
00108     //  METHOD NAME : MediaSMB::attachTo
00109     //  METHOD TYPE : PMError
00110     //
00111     //  DESCRIPTION : Asserted that not already attached, and attachPoint
00112     //      is a directory.
00113     //
00114     //      NOTE: The implementation currently serves both, "smb" and
00115     //      and "cifs" URL's, but passes "cifs" to the mount command
00116     //      in any case.
00117     //
00118     void MediaSMB::attachTo(bool next)
00119     {
00120       if(_url.getHost().empty())
00121         ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
00122       if(next)
00123         ZYPP_THROW(MediaNotSupportedException(_url));
00124     
00125       string path = "//";
00126       path += _url.getHost() + "/" + getShare( _url.getPathName() );
00127    
00128       MediaSourceRef media( new MediaSource( _vfstype, path));
00129       AttachedMedia  ret( findAttachedMedia( media));
00130 
00131       if( ret.mediaSource &&
00132           ret.attachPoint &&
00133           !ret.attachPoint->empty())
00134       {
00135         DBG << "Using a shared media "
00136             << ret.mediaSource->name
00137             << " attached on "
00138             << ret.attachPoint->path
00139             << endl;
00140 
00141         removeAttachPoint();
00142         setAttachPoint(ret.attachPoint);
00143         setMediaSource(ret.mediaSource);
00144         return;
00145       }
00146 
00147       std::string mountpoint = attachPoint().asString();
00148       if( !isUseableAttachPoint(attachPoint()))
00149       {
00150         mountpoint = createAttachPoint().asString();
00151         if( mountpoint.empty())
00152           ZYPP_THROW( MediaBadAttachPointException(url()));
00153         setAttachPoint( mountpoint, true);
00154       }
00155 
00156       Mount mount;
00157  
00158       Mount::Options options( _url.getQueryParam("mountoptions") );
00159       string username = _url.getUsername();
00160       string password = _url.getPassword();
00161     
00162       if ( ! options.has( "rw" ) ) {
00163         options["ro"];
00164       }
00165     
00166       Mount::Options::iterator toEnv;
00167     
00168       // extract 'username', do not overwrite any _url.username
00169       toEnv = options.find("username");
00170       if ( toEnv != options.end() ) {
00171         if ( username.empty() )
00172         username = toEnv->second;
00173         options.erase( toEnv );
00174       }
00175       toEnv = options.find("user"); // actually cifs specific
00176       if ( toEnv != options.end() ) {
00177         if ( username.empty() )
00178         username = toEnv->second;
00179         options.erase( toEnv );
00180       }
00181     
00182       // extract 'password', do not overwrite any _url.password
00183       toEnv = options.find("password");
00184       if ( toEnv != options.end() ) {
00185         if ( password.empty() )
00186         password = toEnv->second;
00187         options.erase( toEnv );
00188       }
00189       toEnv = options.find("pass"); // actually cifs specific
00190       if ( toEnv != options.end() ) {
00191         if ( password.empty() )
00192         password = toEnv->second;
00193         options.erase( toEnv );
00194       }
00195     
00196       // look for a workgroup
00197       string workgroup = _url.getQueryParam("workgroup");
00198       if ( workgroup.size() ) {
00199         options["workgroup"] = workgroup;
00200       }
00201     
00202       // pass 'username' and 'password' via environment
00203       Mount::Environment environment;
00204       if ( username.size() )
00205         environment["USER"] = username;
00206       if ( password.size() )
00207         environment["PASSWD"] = password;
00208     
00210       // In case we need a tmpfile, credentials will remove
00211       // it in it's destructor after the mout call below.
00212       filesystem::TmpPath credentials;
00213       if ( username.size() || password.size() )
00214         {
00215           filesystem::TmpFile tmp;
00216           ofstream outs( tmp.path().asString().c_str() );
00217           outs << "username=" <<  username << endl;
00218           outs << "password=" <<  password << endl;
00219           outs.close();
00220     
00221           credentials = tmp;
00222           options["credentials"] = credentials.path().asString();
00223         }
00224       else
00225         // prevent smbmount from asking for password
00226         // only add this option if 'credentials' is not used (bnc #560496)
00227         options["guest"]; // prevent smbmount from asking for password
00228 
00229       //
00231     
00232       mount.mount( path, mountpoint, _vfstype,
00233                    options.asString(), environment );
00234 
00235       setMediaSource(media);
00236 
00237       // wait for /etc/mtab update ...
00238       // (shouldn't be needed)
00239       int limit = 3;
00240       bool mountsucceeded;
00241       while( !(mountsucceeded=isAttached()) && --limit)
00242       {
00243         sleep(1);
00244       }
00245 
00246       if( !mountsucceeded)
00247       {
00248         setMediaSource(MediaSourceRef());
00249         try
00250         {
00251           mount.umount(attachPoint().asString());
00252         }
00253         catch (const MediaException & excpt_r)
00254         {
00255           ZYPP_CAUGHT(excpt_r);
00256         }
00257         ZYPP_THROW(MediaMountException(
00258           "Unable to verify that the media was mounted",
00259           path, mountpoint
00260         ));
00261       }
00262     }
00263 
00265     //
00266     //  METHOD NAME : MediaSMB::isAttached
00267     //  METHOD TYPE : bool
00268     //
00269     //  DESCRIPTION : Override check if media is attached.
00270     //
00271     bool
00272     MediaSMB::isAttached() const
00273     {
00274       return checkAttached(true);
00275     }
00276 
00278     //
00279     //
00280     //  METHOD NAME : MediaSMB::releaseFrom
00281     //  METHOD TYPE : PMError
00282     //
00283     //  DESCRIPTION : Asserted that media is attached.
00284     //
00285     void MediaSMB::releaseFrom( bool eject )
00286     {
00287       Mount mount;
00288       mount.umount(attachPoint().asString());
00289     }
00290 
00291 
00293     //
00294     //  METHOD NAME : MediaSMB::getFile
00295     //  METHOD TYPE : PMError
00296     //
00297     //  DESCRIPTION : Asserted that media is attached.
00298     //
00299     void MediaSMB::getFile (const Pathname & filename) const
00300     {
00301       MediaHandler::getFile( filename );
00302     }
00303 
00305     //
00306     //  METHOD NAME : MediaSMB::getDir
00307     //  METHOD TYPE : PMError
00308     //
00309     //  DESCRIPTION : Asserted that media is attached.
00310     //
00311     void MediaSMB::getDir( const Pathname & dirname, bool recurse_r ) const
00312     {
00313       MediaHandler::getDir( dirname, recurse_r );
00314     }
00315 
00317     //
00318     //
00319     //  METHOD NAME : MediaSMB::getDirInfo
00320     //  METHOD TYPE : PMError
00321     //
00322     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00323     //
00324     void MediaSMB::getDirInfo( std::list<std::string> & retlist,
00325                                const Pathname & dirname, bool dots ) const
00326     {
00327       MediaHandler::getDirInfo( retlist, dirname, dots );
00328     }
00329 
00331     //
00332     //
00333     //  METHOD NAME : MediaSMB::getDirInfo
00334     //  METHOD TYPE : PMError
00335     //
00336     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00337     //
00338     void MediaSMB::getDirInfo( filesystem::DirContent & retlist,
00339                                const Pathname & dirname, bool dots ) const
00340     {
00341       MediaHandler::getDirInfo( retlist, dirname, dots );
00342     }
00343 
00344     bool MediaSMB::getDoesFileExist( const Pathname & filename ) const
00345     {
00346       return MediaHandler::getDoesFileExist( filename );
00347     }    
00348     
00349   } // namespace media
00350 } // namespace zypp

Generated on Wed Feb 16 18:51:44 2011 for zypp by  doxygen 1.4.6