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       options["guest"]; // prevent smbmount from asking for password
00163     
00164       if ( ! options.has( "rw" ) ) {
00165         options["ro"];
00166       }
00167     
00168       Mount::Options::iterator toEnv;
00169     
00170       // extract 'username', do not overwrite any _url.username
00171       toEnv = options.find("username");
00172       if ( toEnv != options.end() ) {
00173         if ( username.empty() )
00174         username = toEnv->second;
00175         options.erase( toEnv );
00176       }
00177       toEnv = options.find("user"); // actually cifs specific
00178       if ( toEnv != options.end() ) {
00179         if ( username.empty() )
00180         username = toEnv->second;
00181         options.erase( toEnv );
00182       }
00183     
00184       // extract 'password', do not overwrite any _url.password
00185       toEnv = options.find("password");
00186       if ( toEnv != options.end() ) {
00187         if ( password.empty() )
00188         password = toEnv->second;
00189         options.erase( toEnv );
00190       }
00191       toEnv = options.find("pass"); // actually cifs specific
00192       if ( toEnv != options.end() ) {
00193         if ( password.empty() )
00194         password = toEnv->second;
00195         options.erase( toEnv );
00196       }
00197     
00198       // look for a workgroup
00199       string workgroup = _url.getQueryParam("workgroup");
00200       if ( workgroup.size() ) {
00201         options["workgroup"] = workgroup;
00202       }
00203     
00204       // pass 'username' and 'password' via environment
00205       Mount::Environment environment;
00206       if ( username.size() )
00207         environment["USER"] = username;
00208       if ( password.size() )
00209         environment["PASSWD"] = password;
00210     
00212       // In case we need a tmpfile, credentials will remove
00213       // it in it's destructor after the mout call below.
00214       filesystem::TmpPath credentials;
00215       if ( username.size() || password.size() )
00216         {
00217           filesystem::TmpFile tmp;
00218           ofstream outs( tmp.path().asString().c_str() );
00219           outs << "username=" <<  username << endl;
00220           outs << "password=" <<  password << endl;
00221           outs.close();
00222     
00223           credentials = tmp;
00224           options["credentials"] = credentials.path().asString();
00225         }
00226       //
00228     
00229       mount.mount( path, mountpoint, _vfstype,
00230                    options.asString(), environment );
00231 
00232       setMediaSource(media);
00233 
00234       // wait for /etc/mtab update ...
00235       // (shouldn't be needed)
00236       int limit = 3;
00237       bool mountsucceeded;
00238       while( !(mountsucceeded=isAttached()) && --limit)
00239       {
00240         sleep(1);
00241       }
00242 
00243       if( !mountsucceeded)
00244       {
00245         setMediaSource(MediaSourceRef());
00246         try
00247         {
00248           mount.umount(attachPoint().asString());
00249         }
00250         catch (const MediaException & excpt_r)
00251         {
00252           ZYPP_CAUGHT(excpt_r);
00253         }
00254         ZYPP_THROW(MediaMountException(
00255           "Unable to verify that the media was mounted",
00256           path, mountpoint
00257         ));
00258       }
00259     }
00260 
00262     //
00263     //  METHOD NAME : MediaSMB::isAttached
00264     //  METHOD TYPE : bool
00265     //
00266     //  DESCRIPTION : Override check if media is attached.
00267     //
00268     bool
00269     MediaSMB::isAttached() const
00270     {
00271       return checkAttached(true);
00272     }
00273 
00275     //
00276     //
00277     //  METHOD NAME : MediaSMB::releaseFrom
00278     //  METHOD TYPE : PMError
00279     //
00280     //  DESCRIPTION : Asserted that media is attached.
00281     //
00282     void MediaSMB::releaseFrom( bool eject )
00283     {
00284       Mount mount;
00285       mount.umount(attachPoint().asString());
00286     }
00287 
00288 
00290     //
00291     //  METHOD NAME : MediaSMB::getFile
00292     //  METHOD TYPE : PMError
00293     //
00294     //  DESCRIPTION : Asserted that media is attached.
00295     //
00296     void MediaSMB::getFile (const Pathname & filename) const
00297     {
00298       MediaHandler::getFile( filename );
00299     }
00300 
00302     //
00303     //  METHOD NAME : MediaSMB::getDir
00304     //  METHOD TYPE : PMError
00305     //
00306     //  DESCRIPTION : Asserted that media is attached.
00307     //
00308     void MediaSMB::getDir( const Pathname & dirname, bool recurse_r ) const
00309     {
00310       MediaHandler::getDir( dirname, recurse_r );
00311     }
00312 
00314     //
00315     //
00316     //  METHOD NAME : MediaSMB::getDirInfo
00317     //  METHOD TYPE : PMError
00318     //
00319     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00320     //
00321     void MediaSMB::getDirInfo( std::list<std::string> & retlist,
00322                                const Pathname & dirname, bool dots ) const
00323     {
00324       MediaHandler::getDirInfo( retlist, dirname, dots );
00325     }
00326 
00328     //
00329     //
00330     //  METHOD NAME : MediaSMB::getDirInfo
00331     //  METHOD TYPE : PMError
00332     //
00333     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00334     //
00335     void MediaSMB::getDirInfo( filesystem::DirContent & retlist,
00336                                const Pathname & dirname, bool dots ) const
00337     {
00338       MediaHandler::getDirInfo( retlist, dirname, dots );
00339     }
00340 
00341   } // namespace media
00342 } // namespace zypp

Generated on Thu Jul 6 00:07:21 2006 for zypp by  doxygen 1.4.6