[vlc-devel] [PATCH] smb: implement readdir using libsmbclient
Thomas Guillem
thomas at gllm.fr
Mon May 4 17:46:13 CEST 2015
On Mon, May 4, 2015, at 14:51, Thomas Guillem wrote:
> vlc smb:// to browse domains
> vlc smb://domain to browse servers
> vlc smb://server to browse shares
> vlc smb://server/share* to browse files
> ---
> TODO: Implement it on windows.
> We need to way to identify smb type via readdir (SERVER, WORKGROUP,
> FILE_SHARE,
> DIR, ...)
>
> modules/access/smb.c | 192
> ++++++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 145 insertions(+), 47 deletions(-)
>
> diff --git a/modules/access/smb.c b/modules/access/smb.c
> index f738f20..48b4679 100644
> --- a/modules/access/smb.c
> +++ b/modules/access/smb.c
> @@ -1,7 +1,7 @@
> /*****************************************************************************
> * smb.c: SMB input module
> *****************************************************************************
> - * Copyright (C) 2001-2009 VLC authors and VideoLAN
> + * Copyright (C) 2001-2015 VLC authors and VideoLAN
> * $Id$
> *
> * Authors: Gildas Bazin <gbazin at videolan.org>
> @@ -34,7 +34,7 @@
> # include <sys/stat.h>
> # include <io.h>
> # define smbc_open(a,b,c) vlc_open(a,b,c)
> -# define smbc_fstat(a,b) _fstati64(a,b)
> +# define smbc_stat(a,b) _stati64(a,b)
> # define smbc_read read
> # define smbc_lseek _lseeki64
> # define smbc_close close
> @@ -46,6 +46,7 @@
> #include <vlc_fs.h>
> #include <vlc_plugin.h>
> #include <vlc_access.h>
> +#include <vlc_input_item.h>
>
> /*****************************************************************************
> * Module descriptor
> @@ -87,6 +88,9 @@ vlc_module_end ()
> static ssize_t Read( access_t *, uint8_t *, size_t );
> static int Seek( access_t *, uint64_t );
> static int Control( access_t *, int, va_list );
> +#ifndef _WIN32
> +static int DirRead( access_t *, input_item_node_t * );
> +#endif
>
> struct access_sys_t
> {
> @@ -112,6 +116,32 @@ static void smb_auth( const char *srv, const char
> *shr, char *wg, int wglen,
> }
> #endif
>
> +/* Build an SMB URI
> + * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] */
> +static int smb_get_uri( access_t *p_access, char **ppsz_uri,
> + const char *psz_domain,
> + const char *psz_user, const char *psz_pwd,
> + const char *psz_location, const char *psz_name )
> +{
> +#define PSZ_NAME_OR_NULL psz_name ? "/" : "", psz_name ? psz_name : ""
> +#ifdef _WIN32
> + if( psz_user )
> + Win32AddConnection( p_access, psz_location, psz_user, psz_pwd,
> psz_domain);
> + return asprintf( ppsz_uri, "//%s%s%s", psz_location,
> PSZ_NAME_OR_NULL );
> +#else
> + (void) p_access;
> + if( psz_user )
> + return asprintf( ppsz_uri, "smb://%s%s%s%s%s@%s%s%s",
> + psz_domain ? psz_domain : "", psz_domain ? ";"
> : "",
> + psz_user, psz_pwd ? ":" : "",
> + psz_pwd ? psz_pwd : "", psz_location,
> + PSZ_NAME_OR_NULL );
> + else
> + return asprintf( ppsz_uri, "smb://%s%s%s", psz_location,
> + PSZ_NAME_OR_NULL );
> +#endif
> +}
> +
> /****************************************************************************
> * Open: connect to smb server and ask for file
> ****************************************************************************/
> @@ -120,20 +150,19 @@ static int Open( vlc_object_t *p_this )
> access_t *p_access = (access_t*)p_this;
> access_sys_t *p_sys;
> struct stat filestat;
> - char *psz_location, *psz_uri;
> + char *psz_location, *psz_uri = NULL;
> char *psz_user = NULL, *psz_pwd = NULL, *psz_domain = NULL;
> int i_ret;
> int i_smb;
> + uint64_t i_size;
>
> /* Parse input URI
> - * [[[domain;]user[:password@]]server[/share[/path[/file]]]] */
> + * [[[domain;]user[:password@]]server[/share[/path[/file]]]]
> + * No need to search a user/pwd if there is no '/', indeed, user/pwd
> are
> + * set for a FILE_SHARE. */
> +
> psz_location = strchr( p_access->psz_location, '/' );
> - if( !psz_location )
> - {
> - msg_Err( p_access, "invalid SMB URI: smb://%s", psz_location );
> - return VLC_EGENERIC;
> - }
> - else
> + if( psz_location )
> {
> char *psz_tmp = strdup( p_access->psz_location );
> char *psz_parser;
> @@ -168,31 +197,18 @@ static int Open( vlc_object_t *p_this )
> }
>
> free( psz_tmp );
> - }
>
> - /* Build an SMB URI
> - * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
> */
> + if( !psz_user ) psz_user = var_InheritString( p_access,
> "smb-user" );
> + if( psz_user && !*psz_user ) { free( psz_user ); psz_user =
> NULL; }
> + if( !psz_pwd ) psz_pwd = var_InheritString( p_access, "smb-pwd"
> );
> + if( psz_pwd && !*psz_pwd ) { free( psz_pwd ); psz_pwd = NULL; }
> + if( !psz_domain ) psz_domain = var_InheritString( p_access,
> "smb-domain" );
> + if( psz_domain && !*psz_domain ) { free( psz_domain );
> psz_domain = NULL; }
> + } else
> + psz_location = p_access->psz_location;
>
> - if( !psz_user ) psz_user = var_InheritString( p_access, "smb-user"
> );
> - if( psz_user && !*psz_user ) { free( psz_user ); psz_user = NULL; }
> - if( !psz_pwd ) psz_pwd = var_InheritString( p_access, "smb-pwd" );
> - if( psz_pwd && !*psz_pwd ) { free( psz_pwd ); psz_pwd = NULL; }
> - if( !psz_domain ) psz_domain = var_InheritString( p_access,
> "smb-domain" );
> - if( psz_domain && !*psz_domain ) { free( psz_domain ); psz_domain =
> NULL; }
> -
> -#ifdef _WIN32
> - if( psz_user )
> - Win32AddConnection( p_access, psz_location, psz_user, psz_pwd,
> psz_domain);
> - i_ret = asprintf( &psz_uri, "//%s", psz_location );
> -#else
> - if( psz_user )
> - i_ret = asprintf( &psz_uri, "smb://%s%s%s%s%s@%s",
> - psz_domain ? psz_domain : "", psz_domain ? ";"
> : "",
> - psz_user, psz_pwd ? ":" : "",
> - psz_pwd ? psz_pwd : "", psz_location );
> - else
> - i_ret = asprintf( &psz_uri, "smb://%s", psz_location );
> -#endif
> + i_ret = smb_get_uri( p_access, &psz_uri, psz_domain, psz_user,
> psz_pwd,
> + psz_location, NULL );
>
> free( psz_user );
> free( psz_pwd );
> @@ -217,28 +233,47 @@ static int Open( vlc_object_t *p_this )
> #if defined(smbc_open) && defined(open)
> # undef open
> #endif
> - if( (i_smb = smbc_open( psz_uri, O_RDONLY, 0 )) < 0 )
> +
> + /* Init p_access */
> + access_InitFields( p_access );
> + p_sys =
> + p_access->p_sys = (access_sys_t*)calloc( 1, sizeof( access_sys_t )
> );
> + if( !p_sys )
> {
> - msg_Err( p_access, "open failed for '%s' (%s)",
> - p_access->psz_location, vlc_strerror_c(errno) );
> free( psz_uri );
> - return VLC_EGENERIC;
> + return VLC_ENOMEM;
> }
>
> - /* Init p_access */
> - STANDARD_READ_ACCESS_INIT;
> + i_ret = smbc_stat( psz_uri, &filestat );
>
> - i_ret = smbc_fstat( i_smb, &filestat );
> - if( i_ret )
> + /* smbc_stat fails with servers or shares. Assume they are directory
> */
> + if( i_ret || S_ISDIR( filestat.st_mode ) )
> {
> - errno = i_ret;
> - msg_Err( p_access, "stat failed (%s)", vlc_strerror_c(errno) );
> +#ifdef _WIN32
> + return VLC_EGENERIC;
> +#else
> + p_access->pf_readdir = DirRead;
> + i_smb = smbc_opendir( psz_uri );
> + i_size = 0;
> +#endif
> }
> else
> - p_sys->size = filestat.st_size;
> -
> + {
> + ACCESS_SET_CALLBACKS( Read, NULL, Control, Seek );
> + i_smb = smbc_open( psz_uri, O_RDONLY, 0 );
> + i_size = filestat.st_size;
> + }
> free( psz_uri );
>
> + if( i_smb < 0 )
> + {
> + msg_Err( p_access, "open failed for '%s' (%s)",
> + p_access->psz_location, vlc_strerror_c(errno) );
> + free( p_sys );
> + return VLC_EGENERIC;
> + }
> +
> + p_sys->size = i_size;
> p_sys->i_smb = i_smb;
>
> return VLC_SUCCESS;
> @@ -252,8 +287,12 @@ static void Close( vlc_object_t *p_this )
> access_t *p_access = (access_t*)p_this;
> access_sys_t *p_sys = p_access->p_sys;
>
> - smbc_close( p_sys->i_smb );
> - free( p_sys );
> +#ifndef _WIN32
> + if( p_access->pf_readdir )
> + smbc_closedir( p_sys->i_smb );
> + else
> +#endif
> + smbc_close( p_sys->i_smb );
> }
>
> /*****************************************************************************
> @@ -305,6 +344,65 @@ static ssize_t Read( access_t *p_access, uint8_t
> *p_buffer, size_t i_len )
> return i_read;
> }
>
> +#ifndef _WIN32
> +/*****************************************************************************
> + * DirRead:
> +
> *****************************************************************************/
> +static int DirRead (access_t *p_access, input_item_node_t
> *p_current_node)
> +{
> + access_sys_t *p_sys = p_access->p_sys;
> + struct smbc_dirent *p_entry;
> +
> + while( ( p_entry = smbc_readdir( p_sys->i_smb ) ) )
> + {
> + char *psz_uri;
> + const char *psz_location = p_access->psz_location;
> + const char *psz_name = p_entry->name;
> + int i_type;
> +
> + /* skip "." and ".." */
> + if( ( p_entry->namelen == 1 && p_entry->name[0] == '.' ) ||
> + ( p_entry->namelen == 2 && p_entry->name[0] == '.'
> + && p_entry->name[1] == '.' ) )
> + continue;
> +
> + switch( p_entry->smbc_type )
> + {
> + case SMBC_SERVER:
> + case SMBC_WORKGROUP:
> + psz_location = p_entry->name;
> + psz_name = NULL;
> + case SMBC_FILE_SHARE:
> + case SMBC_DIR:
> + i_type = ITEM_TYPE_DIRECTORY;
> + break;
> + case SMBC_FILE:
> + i_type = ITEM_TYPE_FILE;
> + break;
> + default:
> + case SMBC_PRINTER_SHARE:
> + case SMBC_COMMS_SHARE:
> + case SMBC_IPC_SHARE:
> + case SMBC_LINK:
> + continue;
> + }
> +
> + if( smb_get_uri( p_access, &psz_uri, NULL, NULL, NULL,
> + psz_location, psz_name ) != -1 )
> + {
> + input_item_t *p_item;
> +
> + p_item = input_item_NewWithTypeExt( psz_uri, p_entry->name,
> 0, NULL,
> + 0, -1, i_type, 1 );
> + input_item_CopyOptions( p_current_node->p_item, p_item );
> + input_item_node_AppendItem( p_current_node, p_item );
> + free( psz_uri );
item leak here, will be fixed in next patch.
> + }
> + }
> + return VLC_SUCCESS;
> +}
> +#endif
> +
> /*****************************************************************************
> * Control:
> *****************************************************************************/
> --
> 2.1.4
>
More information about the vlc-devel
mailing list