smb.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:14k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * smb.c: SMB input module
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 the VideoLAN team
  5.  * $Id: fcfa9fe0760580c3c72e9e4fe9504325e38864b6 $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_charset.h>
  31. #include <vlc_plugin.h>
  32. #include <vlc_access.h>
  33. #ifdef WIN32
  34. #ifdef HAVE_FCNTL_H
  35. #   include <fcntl.h>
  36. #endif
  37. #   ifdef HAVE_SYS_STAT_H
  38. #       include <sys/stat.h>
  39. #   endif
  40. #   include <io.h>
  41. #   define smbc_open(a,b,c) utf8_open(a,b,c)
  42. #   define stat _stati64
  43. #   define smbc_fstat(a,b) _fstati64(a,b)
  44. #   define smbc_read read
  45. #   define smbc_lseek _lseeki64
  46. #   define smbc_close close
  47. #else
  48. #   include <libsmbclient.h>
  49. #   define USE_CTX 1
  50. #endif
  51. #include <errno.h>
  52. /*****************************************************************************
  53.  * Module descriptor
  54.  *****************************************************************************/
  55. static int  Open ( vlc_object_t * );
  56. static void Close( vlc_object_t * );
  57. #define CACHING_TEXT N_("Caching value in ms")
  58. #define CACHING_LONGTEXT N_( 
  59.     "Caching value for SMB streams. This " 
  60.     "value should be set in milliseconds." )
  61. #define USER_TEXT N_("SMB user name")
  62. #define USER_LONGTEXT N_("User name that will " 
  63.     "be used for the connection.")
  64. #define PASS_TEXT N_("SMB password")
  65. #define PASS_LONGTEXT N_("Password that will be " 
  66.     "used for the connection.")
  67. #define DOMAIN_TEXT N_("SMB domain")
  68. #define DOMAIN_LONGTEXT N_("Domain/Workgroup that " 
  69.     "will be used for the connection.")
  70. vlc_module_begin ()
  71.     set_shortname( "SMB" )
  72.     set_description( N_("SMB input") )
  73.     set_capability( "access", 0 )
  74.     set_category( CAT_INPUT )
  75.     set_subcategory( SUBCAT_INPUT_ACCESS )
  76.     add_integer( "smb-caching", 2 * DEFAULT_PTS_DELAY / 1000, NULL,
  77.                  CACHING_TEXT, CACHING_LONGTEXT, true )
  78.         change_safe()
  79.     add_string( "smb-user", NULL, NULL, USER_TEXT, USER_LONGTEXT,
  80.                 false )
  81.     add_string( "smb-pwd", NULL, NULL, PASS_TEXT,
  82.                 PASS_LONGTEXT, false )
  83.     add_string( "smb-domain", NULL, NULL, DOMAIN_TEXT,
  84.                 DOMAIN_LONGTEXT, false )
  85.     add_shortcut( "smb" )
  86.     set_callbacks( Open, Close )
  87. vlc_module_end ()
  88. /*****************************************************************************
  89.  * Local prototypes
  90.  *****************************************************************************/
  91. static ssize_t Read( access_t *, uint8_t *, size_t );
  92. static int Seek( access_t *, int64_t );
  93. static int Control( access_t *, int, va_list );
  94. struct access_sys_t
  95. {
  96. #ifdef USE_CTX
  97.     SMBCCTX *p_smb;
  98.     SMBCFILE *p_file;
  99. #else
  100.     int i_smb;
  101. #endif
  102. };
  103. #ifdef WIN32
  104. static void Win32AddConnection( access_t *, char *, char *, char *, char * );
  105. #else
  106. static void smb_auth( const char *srv, const char *shr, char *wg, int wglen,
  107.                       char *un, int unlen, char *pw, int pwlen )
  108. {
  109.     //wglen = unlen = pwlen = 0;
  110. }
  111. #endif
  112. /****************************************************************************
  113.  * Open: connect to smb server and ask for file
  114.  ****************************************************************************/
  115. static int Open( vlc_object_t *p_this )
  116. {
  117.     access_t     *p_access = (access_t*)p_this;
  118.     access_sys_t *p_sys;
  119.     struct stat  filestat;
  120.     char         *psz_path, *psz_uri;
  121.     char         *psz_user = NULL, *psz_pwd = NULL, *psz_domain = NULL;
  122.     int          i_ret;
  123. #ifdef USE_CTX
  124.     SMBCCTX      *p_smb;
  125.     SMBCFILE     *p_file;
  126. #else
  127.     int          i_smb;
  128. #endif
  129.     /* Parse input URI
  130.      * [[[domain;]user[:password@]]server[/share[/path[/file]]]] */
  131.     psz_path = strchr( p_access->psz_path, '/' );
  132.     if( !psz_path )
  133.     {
  134.         msg_Err( p_access, "invalid SMB URI: smb://%s", psz_path );
  135.         return VLC_EGENERIC;
  136.     }
  137.     else
  138.     {
  139.         char *psz_tmp = strdup( p_access->psz_path );
  140.         char *psz_parser;
  141.         psz_tmp[ psz_path - p_access->psz_path ] = 0;
  142.         psz_path = p_access->psz_path;
  143.         psz_parser = strchr( psz_tmp, '@' );
  144.         if( psz_parser )
  145.         {
  146.             /* User info is there */
  147.             *psz_parser = 0;
  148.             psz_path = p_access->psz_path + (psz_parser - psz_tmp) + 1;
  149.             psz_parser = strchr( psz_tmp, ':' );
  150.             if( psz_parser )
  151.             {
  152.                 /* Password found */
  153.                 psz_pwd = strdup( psz_parser+1 );
  154.                 *psz_parser = 0;
  155.             }
  156.             psz_parser = strchr( psz_tmp, ';' );
  157.             if( psz_parser )
  158.             {
  159.                 /* Domain found */
  160.                 *psz_parser = 0; psz_parser++;
  161.                 psz_domain = strdup( psz_tmp );
  162.             }
  163.             else psz_parser = psz_tmp;
  164.             psz_user = strdup( psz_parser );
  165.         }
  166.         free( psz_tmp );
  167.     }
  168.     /* Build an SMB URI
  169.      * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] */
  170.     if( !psz_user ) psz_user = var_CreateGetString( p_access, "smb-user" );
  171.     if( psz_user && !*psz_user ) { free( psz_user ); psz_user = NULL; }
  172.     if( !psz_pwd ) psz_pwd = var_CreateGetString( p_access, "smb-pwd" );
  173.     if( psz_pwd && !*psz_pwd ) { free( psz_pwd ); psz_pwd = NULL; }
  174.     if( !psz_domain ) psz_domain = var_CreateGetString( p_access, "smb-domain" );
  175.     if( psz_domain && !*psz_domain ) { free( psz_domain ); psz_domain = NULL; }
  176. #ifdef WIN32
  177.     if( psz_user )
  178.         Win32AddConnection( p_access, psz_path, psz_user, psz_pwd, psz_domain);
  179.     i_ret = asprintf( &psz_uri, "//%s", psz_path );
  180. #else
  181.     if( psz_user )
  182.         i_ret = asprintf( &psz_uri, "smb://%s%s%s%s%s@%s",
  183.                           psz_domain ? psz_domain : "", psz_domain ? ";" : "",
  184.                           psz_user, psz_pwd ? ":" : "",
  185.                           psz_pwd ? psz_pwd : "", psz_path );
  186.     else
  187.         i_ret = asprintf( &psz_uri, "smb://%s", psz_path );
  188. #endif
  189.     free( psz_user );
  190.     free( psz_pwd );
  191.     free( psz_domain );
  192.     if( i_ret == -1 )
  193.         return VLC_ENOMEM;
  194. #ifdef USE_CTX
  195.     if( !(p_smb = smbc_new_context()) )
  196.     {
  197.         free( psz_uri );
  198.         return VLC_ENOMEM;
  199.     }
  200.     p_smb->debug = 1;
  201.     p_smb->callbacks.auth_fn = smb_auth;
  202.     if( !smbc_init_context( p_smb ) )
  203.     {
  204.         msg_Err( p_access, "cannot initialize context (%m)" );
  205.         smbc_free_context( p_smb, 1 );
  206.         free( psz_uri );
  207.         return VLC_EGENERIC;
  208.     }
  209.     if( !(p_file = (p_smb->open)( p_smb, psz_uri, O_RDONLY, 0 )) )
  210.     {
  211.         msg_Err( p_access, "open failed for '%s' (%m)",
  212.                  p_access->psz_path );
  213.         smbc_free_context( p_smb, 1 );
  214.         free( psz_uri );
  215.         return VLC_EGENERIC;
  216.     }
  217.     /* Init p_access */
  218.     STANDARD_READ_ACCESS_INIT;
  219.     i_ret = p_smb->fstat( p_smb, p_file, &filestat );
  220.     if( i_ret ) msg_Err( p_access, "stat failed (%m)" );
  221.     else p_access->info.i_size = filestat.st_size;
  222. #else
  223. #ifndef WIN32
  224.     if( smbc_init( smb_auth, 1 ) )
  225.     {
  226.         free( psz_uri );
  227.         return VLC_EGENERIC;
  228.     }
  229. #endif
  230. /*
  231. ** some version of glibc defines open as a macro, causing havoc
  232. ** with other macros using 'open' under the hood, such as the
  233. ** following one:
  234. */
  235. #if defined(smbc_open) && defined(open)
  236. # undef open
  237. #endif
  238.     if( (i_smb = smbc_open( psz_uri, O_RDONLY, 0 )) < 0 )
  239.     {
  240.         msg_Err( p_access, "open failed for '%s' (%m)",
  241.                  p_access->psz_path );
  242.         free( psz_uri );
  243.         return VLC_EGENERIC;
  244.     }
  245.     /* Init p_access */
  246.     STANDARD_READ_ACCESS_INIT;
  247.     i_ret = smbc_fstat( i_smb, &filestat );
  248.     if( i_ret )
  249.     {
  250.         errno = i_ret;
  251.         msg_Err( p_access, "stat failed (%m)" );
  252.     }
  253.     else p_access->info.i_size = filestat.st_size;
  254. #endif
  255.     free( psz_uri );
  256. #ifdef USE_CTX
  257.     p_sys->p_smb = p_smb;
  258.     p_sys->p_file = p_file;
  259. #else
  260.     p_sys->i_smb = i_smb;
  261. #endif
  262.     /* Update default_pts to a suitable value for smb access */
  263.     var_Create( p_access, "smb-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  264.     return VLC_SUCCESS;
  265. }
  266. /*****************************************************************************
  267.  * Close: free unused data structures
  268.  *****************************************************************************/
  269. static void Close( vlc_object_t *p_this )
  270. {
  271.     access_t     *p_access = (access_t*)p_this;
  272.     access_sys_t *p_sys = p_access->p_sys;
  273. #ifdef USE_CTX
  274. #  ifndef HAVE__SMBCCTX_CLOSE_FN
  275.     p_sys->p_smb->close( p_sys->p_smb, p_sys->p_file );
  276. #  else
  277.     p_sys->p_smb->close_fn( p_sys->p_smb, p_sys->p_file );
  278. #  endif
  279.     smbc_free_context( p_sys->p_smb, 1 );
  280. #else
  281.     smbc_close( p_sys->i_smb );
  282. #endif
  283.     free( p_sys );
  284. }
  285. /*****************************************************************************
  286.  * Seek: try to go at the right place
  287.  *****************************************************************************/
  288. static int Seek( access_t *p_access, int64_t i_pos )
  289. {
  290.     access_sys_t *p_sys = p_access->p_sys;
  291.     int64_t      i_ret;
  292.     if( i_pos < 0 ) return VLC_EGENERIC;
  293.     msg_Dbg( p_access, "seeking to %"PRId64, i_pos );
  294. #ifdef USE_CTX
  295.     i_ret = p_sys->p_smb->lseek(p_sys->p_smb, p_sys->p_file, i_pos, SEEK_SET);
  296. #else
  297.     i_ret = smbc_lseek( p_sys->i_smb, i_pos, SEEK_SET );
  298. #endif
  299.     if( i_ret == -1 )
  300.     {
  301.         msg_Err( p_access, "seek failed (%m)" );
  302.         return VLC_EGENERIC;
  303.     }
  304.     p_access->info.b_eof = false;
  305.     p_access->info.i_pos = i_ret;
  306.     return VLC_SUCCESS;
  307. }
  308. /*****************************************************************************
  309.  * Read:
  310.  *****************************************************************************/
  311. static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
  312. {
  313.     access_sys_t *p_sys = p_access->p_sys;
  314.     int i_read;
  315.     if( p_access->info.b_eof ) return 0;
  316. #ifdef USE_CTX
  317.     i_read = p_sys->p_smb->read(p_sys->p_smb, p_sys->p_file, p_buffer, i_len);
  318. #else
  319.     i_read = smbc_read( p_sys->i_smb, p_buffer, i_len );
  320. #endif
  321.     if( i_read < 0 )
  322.     {
  323.         msg_Err( p_access, "read failed (%m)" );
  324.         return -1;
  325.     }
  326.     if( i_read == 0 ) p_access->info.b_eof = true;
  327.     else if( i_read > 0 ) p_access->info.i_pos += i_read;
  328.     return i_read;
  329. }
  330. /*****************************************************************************
  331.  * Control:
  332.  *****************************************************************************/
  333. static int Control( access_t *p_access, int i_query, va_list args )
  334. {
  335.     bool        *pb_bool;
  336.     int64_t     *pi_64;
  337.     switch( i_query )
  338.     {
  339.     case ACCESS_CAN_SEEK:
  340.         pb_bool = (bool*)va_arg( args, bool* );
  341.         *pb_bool = true;
  342.         break;
  343.     case ACCESS_CAN_FASTSEEK:
  344.         pb_bool = (bool*)va_arg( args, bool* );
  345.         *pb_bool = true;
  346.         break;
  347.     case ACCESS_CAN_PAUSE:
  348.         pb_bool = (bool*)va_arg( args, bool* );
  349.         *pb_bool = true;
  350.         break;
  351.     case ACCESS_CAN_CONTROL_PACE:
  352.         pb_bool = (bool*)va_arg( args, bool* );
  353.         *pb_bool = true;
  354.         break;
  355.     case ACCESS_GET_PTS_DELAY:
  356.         pi_64 = (int64_t*)va_arg( args, int64_t * );
  357.         *pi_64 = (int64_t)var_GetInteger( p_access, "smb-caching" ) * 1000;
  358.         break;
  359.     case ACCESS_SET_PAUSE_STATE:
  360.         /* Nothing to do */
  361.         break;
  362.     case ACCESS_GET_TITLE_INFO:
  363.     case ACCESS_SET_TITLE:
  364.     case ACCESS_SET_SEEKPOINT:
  365.     case ACCESS_SET_PRIVATE_ID_STATE:
  366.     case ACCESS_GET_CONTENT_TYPE:
  367.         return VLC_EGENERIC;
  368.     default:
  369.         msg_Warn( p_access, "unimplemented query in control" );
  370.         return VLC_EGENERIC;
  371.     }
  372.     return VLC_SUCCESS;
  373. }
  374. #ifdef WIN32
  375. static void Win32AddConnection( access_t *p_access, char *psz_path,
  376.                                 char *psz_user, char *psz_pwd,
  377.                                 char *psz_domain )
  378. {
  379.     DWORD (*OurWNetAddConnection2)( LPNETRESOURCE, LPCTSTR, LPCTSTR, DWORD );
  380.     char psz_remote[MAX_PATH], psz_server[MAX_PATH], psz_share[MAX_PATH];
  381.     NETRESOURCE net_resource;
  382.     DWORD i_result;
  383.     char *psz_parser;
  384.     VLC_UNUSED( psz_domain );
  385.     HINSTANCE hdll = LoadLibrary(_T("MPR.DLL"));
  386.     if( !hdll )
  387.     {
  388.         msg_Warn( p_access, "couldn't load mpr.dll" );
  389.         return;
  390.     }
  391.     OurWNetAddConnection2 =
  392.       (void *)GetProcAddress( hdll, _T("WNetAddConnection2A") );
  393.     if( !OurWNetAddConnection2 )
  394.     {
  395.         msg_Warn( p_access, "couldn't find WNetAddConnection2 in mpr.dll" );
  396.         return;
  397.     }
  398.     memset( &net_resource, 0, sizeof(net_resource) );
  399.     net_resource.dwType = RESOURCETYPE_DISK;
  400.     /* Find out server and share names */
  401.     strlcpy( psz_server, psz_path, sizeof( psz_server ) );
  402.     psz_share[0] = 0;
  403.     psz_parser = strchr( psz_path, '/' );
  404.     if( psz_parser )
  405.     {
  406.         char *psz_parser2 = strchr( ++psz_parser, '/' );
  407.         if( psz_parser2 )
  408.             strlcpy( psz_share, psz_parser, sizeof( psz_share ) );
  409.    }
  410.     snprintf( psz_remote, sizeof( psz_remote ), "\\%s\%s", psz_server, psz_share );
  411.     net_resource.lpRemoteName = psz_remote;
  412.     i_result = OurWNetAddConnection2( &net_resource, psz_pwd, psz_user, 0 );
  413.     if( i_result != NO_ERROR )
  414.     {
  415.         msg_Dbg( p_access, "connected to %s", psz_remote );
  416.     }
  417.     else if( i_result != ERROR_ALREADY_ASSIGNED &&
  418.              i_result != ERROR_DEVICE_ALREADY_REMEMBERED )
  419.     {
  420.         msg_Dbg( p_access, "already connected to %s", psz_remote );
  421.     }
  422.     else
  423.     {
  424.         msg_Dbg( p_access, "failed to connect to %s", psz_remote );
  425.     }
  426.     FreeLibrary( hdll );
  427. }
  428. #endif // WIN32