Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

smb.c

00001 /*****************************************************************************
00002  * smb.c: SMB input module
00003  *****************************************************************************
00004  * Copyright (C) 2001-2004 the VideoLAN team
00005  * $Id: smb.c 12451 2005-09-02 18:18:03Z gbazin $
00006  *
00007  * Authors: Gildas Bazin <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>
00028 
00029 #include <vlc/vlc.h>
00030 #include <vlc/input.h>
00031 
00032 #ifdef WIN32
00033 #ifdef HAVE_FCNTL_H
00034 #   include <fcntl.h>
00035 #endif
00036 #   ifdef HAVE_SYS_STAT_H
00037 #       include <sys/stat.h>
00038 #   endif
00039 #   include <io.h>
00040 #   define smbc_open(a,b,c) open(a,b,c)
00041 #   define stat _stati64
00042 #   define smbc_fstat(a,b) _fstati64(a,b)
00043 #   define smbc_read read
00044 #   define smbc_lseek _lseeki64
00045 #   define smbc_close close
00046 #else
00047 #   include <libsmbclient.h>
00048 #   define USE_CTX 1
00049 #endif
00050 
00051 #include <errno.h>
00052 
00053 /*****************************************************************************
00054  * Module descriptor
00055  *****************************************************************************/
00056 static int  Open ( vlc_object_t * );
00057 static void Close( vlc_object_t * );
00058 
00059 #define CACHING_TEXT N_("Caching value in ms")
00060 #define CACHING_LONGTEXT N_( \
00061     "Allows you to modify the default caching value for SMB streams. This " \
00062     "value should be set in millisecond units." )
00063 #define USER_TEXT N_("SMB user name")
00064 #define USER_LONGTEXT N_("Allows you to modify the user name that will " \
00065     "be used for the connection.")
00066 #define PASS_TEXT N_("SMB password")
00067 #define PASS_LONGTEXT N_("Allows you to modify the password that will be " \
00068     "used for the connection.")
00069 #define DOMAIN_TEXT N_("SMB domain")
00070 #define DOMAIN_LONGTEXT N_("Allows you to modify the domain/workgroup that " \
00071     "will be used for the connection.")
00072 
00073 vlc_module_begin();
00074     set_shortname( "SMB" );
00075     set_description( _("SMB input") );
00076     set_capability( "access2", 0 );
00077     set_category( CAT_INPUT );
00078     set_subcategory( SUBCAT_INPUT_ACCESS );
00079     add_integer( "smb-caching", 2 * DEFAULT_PTS_DELAY / 1000, NULL,
00080                  CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
00081     add_string( "smb-user", NULL, NULL, USER_TEXT, USER_LONGTEXT,
00082                 VLC_FALSE );
00083     add_string( "smb-pwd", NULL, NULL, PASS_TEXT,
00084                 PASS_LONGTEXT, VLC_FALSE );
00085     add_string( "smb-domain", NULL, NULL, DOMAIN_TEXT,
00086                 DOMAIN_LONGTEXT, VLC_FALSE );
00087     add_shortcut( "smb" );
00088     set_callbacks( Open, Close );
00089 vlc_module_end();
00090 
00091 /*****************************************************************************
00092  * Local prototypes
00093  *****************************************************************************/
00094 static int Read( access_t *, uint8_t *, int );
00095 static int Seek( access_t *, int64_t );
00096 static int Control( access_t *, int, va_list );
00097 
00098 struct access_sys_t
00099 {
00100 #ifdef USE_CTX
00101     SMBCCTX *p_smb;
00102     SMBCFILE *p_file;
00103 #else
00104     int i_smb;
00105 #endif
00106 };
00107 
00108 #ifdef WIN32
00109 static void Win32AddConnection( access_t *, char *, char *, char *, char * );
00110 #endif
00111 
00112 void smb_auth( const char *srv, const char *shr, char *wg, int wglen,
00113                char *un, int unlen, char *pw, int pwlen )
00114 {
00115     //wglen = unlen = pwlen = 0;
00116 }
00117 
00118 /****************************************************************************
00119  * Open: connect to smb server and ask for file
00120  ****************************************************************************/
00121 static int Open( vlc_object_t *p_this )
00122 {
00123     access_t     *p_access = (access_t*)p_this;
00124     access_sys_t *p_sys;
00125     struct stat  filestat;
00126     char         *psz_path, *psz_uri;
00127     char         *psz_user = 0, *psz_pwd = 0, *psz_domain = 0;
00128     int          i_ret;
00129 
00130 #ifdef USE_CTX
00131     SMBCCTX      *p_smb;
00132     SMBCFILE     *p_file;
00133 #else
00134     int          i_smb;
00135 #endif
00136 
00137     /* Parse input URI
00138      * [[[domain;]user[:password@]]server[/share[/path[/file]]]] */
00139 
00140     psz_path = strchr( p_access->psz_path, '/' );
00141     if( !psz_path )
00142     {
00143         msg_Err( p_access, "invalid SMB URI: smb://%s", psz_path );
00144         return VLC_EGENERIC;
00145     }
00146     else
00147     {
00148         char *psz_tmp = strdup( p_access->psz_path );
00149         char *psz_parser;
00150 
00151         psz_tmp[ psz_path - p_access->psz_path ] = 0;
00152         psz_path = p_access->psz_path;
00153         psz_parser = strchr( psz_tmp, '@' );
00154         if( psz_parser )
00155         {
00156             /* User info is there */
00157             *psz_parser = 0;
00158             psz_path = p_access->psz_path + (psz_parser - psz_tmp) + 1;
00159 
00160             psz_parser = strchr( psz_tmp, ':' );
00161             if( psz_parser )
00162             {
00163                 /* Password found */
00164                 psz_pwd = strdup( psz_parser+1 );
00165                 *psz_parser = 0;
00166             }
00167 
00168             psz_parser = strchr( psz_tmp, ';' );
00169             if( psz_parser )
00170             {
00171                 /* Domain found */
00172                 *psz_parser = 0; psz_parser++;
00173                 psz_domain = strdup( psz_tmp );
00174             }
00175             else psz_parser = psz_tmp;
00176 
00177             psz_user = strdup( psz_parser );
00178         }
00179 
00180         free( psz_tmp );
00181     }
00182 
00183     /* Build an SMB URI
00184      * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] */
00185 
00186     if( !psz_user ) psz_user = var_CreateGetString( p_access, "smb-user" );
00187     if( psz_user && !*psz_user ) { free( psz_user ); psz_user = 0; }
00188     if( !psz_pwd ) psz_pwd = var_CreateGetString( p_access, "smb-pwd" );
00189     if( psz_pwd && !*psz_pwd ) { free( psz_pwd ); psz_pwd = 0; }
00190     if(!psz_domain) psz_domain = var_CreateGetString( p_access, "smb-domain" );
00191     if( psz_domain && !*psz_domain ) { free( psz_domain ); psz_domain = 0; }
00192 
00193 #ifdef WIN32
00194     if( psz_user )
00195         Win32AddConnection( p_access, psz_path, psz_user, psz_pwd, psz_domain);
00196     asprintf( &psz_uri, "//%s", psz_path );
00197 #else
00198     if( psz_user )
00199         asprintf( &psz_uri, "smb://%s%s%s%s%s@%s",
00200                   psz_domain ? psz_domain : "", psz_domain ? ";" : "",
00201                   psz_user, psz_pwd ? ":" : "",
00202                   psz_pwd ? psz_pwd : "", psz_path );
00203     else
00204         asprintf( &psz_uri, "smb://%s", psz_path );
00205 #endif
00206 
00207     if( psz_user ) free( psz_user );
00208     if( psz_pwd ) free( psz_pwd );
00209     if( psz_domain ) free( psz_domain );
00210 
00211 #ifdef USE_CTX
00212     if( !(p_smb = smbc_new_context()) )
00213     {
00214         msg_Err( p_access, "out of memory" );
00215         free( psz_uri );
00216         return VLC_ENOMEM;
00217     }
00218     p_smb->debug = 1;
00219     p_smb->callbacks.auth_fn = smb_auth;
00220 
00221     if( !smbc_init_context( p_smb ) )
00222     {
00223         msg_Err( p_access, "cannot initialize context (%s)", strerror(errno) );
00224         smbc_free_context( p_smb, 1 );
00225         free( psz_uri );
00226         return VLC_EGENERIC;
00227     }
00228 
00229     if( !(p_file = p_smb->open( p_smb, psz_uri, O_RDONLY, 0 )) )
00230     {
00231         msg_Err( p_access, "open failed for '%s' (%s)",
00232                  p_access->psz_path, strerror(errno) );
00233         smbc_free_context( p_smb, 1 );
00234         free( psz_uri );
00235         return VLC_EGENERIC;
00236     }
00237 
00238     p_access->info.i_size = 0;
00239     i_ret = p_smb->fstat( p_smb, p_file, &filestat );
00240     if( i_ret ) msg_Err( p_access, "stat failed (%s)", strerror(errno) );
00241     else p_access->info.i_size = filestat.st_size;
00242 
00243 #else
00244 
00245 #ifndef WIN32
00246     if( smbc_init( smb_auth, 1 ) )
00247     {
00248         free( psz_uri );
00249         return VLC_EGENERIC;
00250     }
00251 #endif
00252 
00253     if( (i_smb = smbc_open( psz_uri, O_RDONLY, 0 )) < 0 )
00254     {
00255         msg_Err( p_access, "open failed for '%s' (%s)",
00256                  p_access->psz_path, strerror(errno) );
00257         free( psz_uri );
00258         return VLC_EGENERIC;
00259     }
00260 
00261     p_access->info.i_size = 0;
00262     i_ret = smbc_fstat( i_smb, &filestat );
00263     if( i_ret ) msg_Err( p_access, "stat failed (%s)", strerror(i_ret) );
00264     else p_access->info.i_size = filestat.st_size;
00265 #endif
00266 
00267     free( psz_uri );
00268 
00269     /* Init p_access */
00270     p_access->pf_read = Read;
00271     p_access->pf_block = NULL;
00272     p_access->pf_seek = Seek;
00273     p_access->pf_control = Control;
00274     p_access->info.i_update = 0;
00275     p_access->info.i_pos = 0;
00276     p_access->info.b_eof = VLC_FALSE;
00277     p_access->info.i_title = 0;
00278     p_access->info.i_seekpoint = 0;
00279     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
00280     memset( p_sys, 0, sizeof( access_sys_t ) );
00281 
00282 #ifdef USE_CTX
00283     p_sys->p_smb = p_smb;
00284     p_sys->p_file = p_file;
00285 #else
00286     p_sys->i_smb = i_smb;
00287 #endif
00288 
00289     /* Update default_pts to a suitable value for smb access */
00290     var_Create( p_access, "smb-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00291 
00292     return VLC_SUCCESS;
00293 }
00294 
00295 /*****************************************************************************
00296  * Close: free unused data structures
00297  *****************************************************************************/
00298 static void Close( vlc_object_t *p_this )
00299 {
00300     access_t     *p_access = (access_t*)p_this;
00301     access_sys_t *p_sys = p_access->p_sys;
00302 
00303 #ifdef USE_CTX
00304 #  ifndef HAVE__SMBCCTX_CLOSE_FN
00305     p_sys->p_smb->close( p_sys->p_smb, p_sys->p_file );
00306 #  else
00307     p_sys->p_smb->close_fn( p_sys->p_smb, p_sys->p_file );
00308 #  endif
00309     smbc_free_context( p_sys->p_smb, 1 );
00310 #else
00311     smbc_close( p_sys->i_smb );
00312 #endif
00313 
00314     free( p_sys );
00315 }
00316 
00317 /*****************************************************************************
00318  * Seek: try to go at the right place
00319  *****************************************************************************/
00320 static int Seek( access_t *p_access, int64_t i_pos )
00321 {
00322     access_sys_t *p_sys = p_access->p_sys;
00323     int64_t      i_ret;
00324 
00325     if( i_pos < 0 ) return VLC_EGENERIC;
00326 
00327     msg_Dbg( p_access, "seeking to "I64Fd, i_pos );
00328 
00329 #ifdef USE_CTX
00330     i_ret = p_sys->p_smb->lseek(p_sys->p_smb, p_sys->p_file, i_pos, SEEK_SET);
00331 #else
00332     i_ret = smbc_lseek( p_sys->i_smb, i_pos, SEEK_SET );
00333 #endif
00334     if( i_ret == -1 )
00335     {
00336         msg_Err( p_access, "seek failed (%s)", strerror(errno) );
00337         return VLC_EGENERIC;
00338     }
00339 
00340     p_access->info.b_eof = VLC_FALSE;
00341     p_access->info.i_pos = i_ret;
00342 
00343     return VLC_SUCCESS;
00344 }
00345 
00346 /*****************************************************************************
00347  * Read:
00348  *****************************************************************************/
00349 static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
00350 {
00351     access_sys_t *p_sys = p_access->p_sys;
00352     int i_read;
00353 
00354     if( p_access->info.b_eof ) return 0;
00355 
00356 #ifdef USE_CTX
00357     i_read = p_sys->p_smb->read(p_sys->p_smb, p_sys->p_file, p_buffer, i_len);
00358 #else
00359     i_read = smbc_read( p_sys->i_smb, p_buffer, i_len );
00360 #endif
00361     if( i_read < 0 )
00362     {
00363         msg_Err( p_access, "read failed (%s)", strerror(errno) );
00364         return -1;
00365     }
00366 
00367     if( i_read == 0 ) p_access->info.b_eof = VLC_TRUE;
00368     else if( i_read > 0 ) p_access->info.i_pos += i_read;
00369 
00370     return i_read;
00371 }
00372 
00373 /*****************************************************************************
00374  * Control:
00375  *****************************************************************************/
00376 static int Control( access_t *p_access, int i_query, va_list args )
00377 {
00378     vlc_bool_t   *pb_bool;
00379     int          *pi_int;
00380     int64_t      *pi_64;
00381 
00382     switch( i_query )
00383     {
00384     case ACCESS_CAN_SEEK:
00385         pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00386         *pb_bool = VLC_TRUE;
00387         break;
00388     case ACCESS_CAN_FASTSEEK:
00389         pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00390         *pb_bool = VLC_TRUE;
00391         break;
00392     case ACCESS_CAN_PAUSE:
00393         pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00394         *pb_bool = VLC_TRUE;
00395         break;
00396     case ACCESS_CAN_CONTROL_PACE:
00397         pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00398         *pb_bool = VLC_TRUE;
00399         break;
00400 
00401     case ACCESS_GET_MTU:
00402         pi_int = (int*)va_arg( args, int * );
00403         *pi_int = 0;
00404         break;
00405 
00406     case ACCESS_GET_PTS_DELAY:
00407         pi_64 = (int64_t*)va_arg( args, int64_t * );
00408         *pi_64 = (int64_t)var_GetInteger( p_access, "smb-caching" ) * 1000;
00409         break;
00410 
00411     case ACCESS_SET_PAUSE_STATE:
00412         /* Nothing to do */
00413         break;
00414 
00415     case ACCESS_GET_TITLE_INFO:
00416     case ACCESS_SET_TITLE:
00417     case ACCESS_SET_SEEKPOINT:
00418     case ACCESS_SET_PRIVATE_ID_STATE:
00419         return VLC_EGENERIC;
00420 
00421     default:
00422         msg_Warn( p_access, "unimplemented query in control" );
00423         return VLC_EGENERIC;
00424 
00425     }
00426 
00427     return VLC_SUCCESS;
00428 }
00429 
00430 #ifdef WIN32
00431 static void Win32AddConnection( access_t *p_access, char *psz_path,
00432                                 char *psz_user, char *psz_pwd,
00433                                 char *psz_domain )
00434 {
00435     DWORD (*OurWNetAddConnection2)( LPNETRESOURCE, LPCTSTR, LPCTSTR, DWORD );
00436     char psz_remote[MAX_PATH], psz_server[MAX_PATH], psz_share[MAX_PATH];
00437     NETRESOURCE net_resource;
00438     DWORD i_result;
00439     char *psz_parser;
00440 
00441     HINSTANCE hdll = LoadLibrary(_T("MPR.DLL"));
00442     if( !hdll )
00443     {
00444         msg_Warn( p_access, "couldn't load mpr.dll" );
00445         return;
00446     }
00447 
00448     OurWNetAddConnection2 =
00449       (void *)GetProcAddress( hdll, _T("WNetAddConnection2A") );
00450     if( !OurWNetAddConnection2 )
00451     {
00452         msg_Warn( p_access, "couldn't find WNetAddConnection2 in mpr.dll" );
00453         return;
00454     }
00455 
00456     memset( &net_resource, 0, sizeof(net_resource) );
00457     net_resource.dwType = RESOURCETYPE_DISK;
00458 
00459     /* Find out server and share names */
00460     psz_server[0] = psz_share[0] = 0;
00461     psz_parser = strchr( psz_path, '/' );
00462     if( psz_parser )
00463     {
00464         char *psz_parser2;
00465         strncat( psz_server, psz_path, psz_parser - psz_path );
00466         psz_parser2 = strchr( psz_parser+1, '/' );
00467         if( psz_parser2 )
00468             strncat( psz_share, psz_parser+1, psz_parser2 - psz_parser -1 );
00469     }
00470     else strncat( psz_server, psz_path, MAX_PATH );
00471 
00472     sprintf( psz_remote, "\\\\%s\\%s", psz_server, psz_share );
00473     net_resource.lpRemoteName = psz_remote;
00474 
00475     i_result = OurWNetAddConnection2( &net_resource, psz_pwd, psz_user, 0 );
00476 
00477     if( i_result != NO_ERROR )
00478     {
00479         msg_Dbg( p_access, "connected to %s", psz_remote );
00480     }
00481     else if( i_result != ERROR_ALREADY_ASSIGNED && 
00482              i_result != ERROR_DEVICE_ALREADY_REMEMBERED )
00483     {
00484         msg_Dbg( p_access, "already connected to %s", psz_remote );
00485     }
00486     else
00487     {
00488         msg_Dbg( p_access, "failed to connect to %s", psz_remote );
00489     }
00490 
00491     FreeLibrary( hdll );
00492 }
00493 #endif // WIN32

Generated on Tue Dec 20 10:14:26 2005 for vlc-0.8.4a by  doxygen 1.4.2