[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