static vlc_keystore_entry * find_closest_path(vlc_keystore_entry *p_entries, unsigned i_count, const char *psz_path) { vlc_keystore_entry *p_match_entry = NULL; size_t i_last_pathlen = 0; char *psz_decoded_path = vlc_uri_decode_duplicate(psz_path); if (psz_decoded_path == NULL) return NULL; /* Try to find the entry that has the closest path to psz_url */ for (unsigned int i = 0; i < i_count; ++i) { vlc_keystore_entry *p_entry = &p_entries[i]; const char *psz_entry_path = p_entry->ppsz_values[KEY_PATH]; if (psz_entry_path == NULL) { if (p_match_entry == NULL) p_match_entry = p_entry; continue; } size_t i_entry_pathlen = strlen(psz_entry_path); if (strncasecmp(psz_decoded_path, psz_entry_path, i_entry_pathlen) == 0 && i_entry_pathlen > i_last_pathlen) { i_last_pathlen = i_entry_pathlen; p_match_entry = p_entry; } } free(psz_decoded_path); return p_match_entry; }
/* Get the share and filepath from uri (also replace all / by \ in url.psz_path) */ static bool get_path( stream_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; char *iter; if( p_sys->url.psz_path == NULL ) return false; p_sys->psz_fullpath = vlc_uri_decode_duplicate( p_sys->url.psz_path ); if( p_sys->psz_fullpath == NULL ) return false; backslash_path( p_sys->psz_fullpath ); /* Is path longer than just "/" ? */ if( strlen( p_sys->psz_fullpath ) > 1 ) { iter = p_sys->psz_fullpath; while( *iter == '\\' ) iter++; /* Handle smb://Host/////Share/ */ p_sys->psz_share = iter; } else { msg_Dbg( p_access, "no share, nor file path provided, will switch to browser"); return false; } iter = strchr( p_sys->psz_share, '\\' ); if( iter == NULL || strlen(iter + 1) == 0 ) { if( iter != NULL ) /* Remove the trailing \ */ *iter = '\0'; p_sys->psz_path = ""; msg_Dbg( p_access, "no file path provided, will switch to browser "); return true; } p_sys->psz_path = iter + 1; /* Skip the first \ */ *iter = '\0'; return true; }
static int Open(vlc_object_t *p_obj) { access_t *p_access = (access_t *)p_obj; access_sys_t *p_sys = calloc(1, sizeof (*p_sys)); if (unlikely(p_sys == NULL)) goto error; p_access->p_sys = p_sys; p_sys->b_auto_guid = var_InheritBool(p_obj, "nfs-auto-guid"); /* nfs_* functions need a decoded url */ p_sys->psz_url_decoded = vlc_uri_decode_duplicate(p_access->psz_url); if (p_sys->psz_url_decoded == NULL) goto error; /* Parse the encoded URL */ vlc_UrlParse(&p_sys->encoded_url, p_access->psz_url); if (p_sys->encoded_url.psz_option) { if (strstr(p_sys->encoded_url.psz_option, "uid") || strstr(p_sys->encoded_url.psz_option, "gid")) p_sys->b_auto_guid = false; } if (NfsInit(p_access, p_sys->psz_url_decoded) == -1) goto error; if (p_sys->p_nfs_url->path != NULL && p_sys->p_nfs_url->file != NULL) { /* The url has a valid path and file, mount the path and open/opendir * the file */ msg_Dbg(p_access, "nfs_mount: server: '%s', path: '%s'", p_sys->p_nfs_url->server, p_sys->p_nfs_url->path); if (nfs_mount_async(p_sys->p_nfs, p_sys->p_nfs_url->server, p_sys->p_nfs_url->path, nfs_mount_cb, p_access) < 0) { msg_Err(p_access, "nfs_mount_async failed"); goto error; } if (vlc_nfs_mainloop(p_access, nfs_mount_open_finished_cb) < 0) goto error; if (p_sys->psz_url_decoded_slash != NULL) { /* Retry to mount by adding a '/' to the path, see comment in * nfs_mount_cb */ nfs_destroy_url(p_sys->p_nfs_url); nfs_destroy_context(p_sys->p_nfs); p_sys->p_nfs_url = NULL; p_sys->p_nfs = NULL; if (NfsInit(p_access, p_sys->psz_url_decoded_slash) == -1 || p_sys->p_nfs_url->path == NULL || p_sys->p_nfs_url->file == NULL) goto error; if (nfs_mount_async(p_sys->p_nfs, p_sys->p_nfs_url->server, p_sys->p_nfs_url->path, nfs_mount_cb, p_access) < 0) { msg_Err(p_access, "nfs_mount_async failed"); goto error; } if (vlc_nfs_mainloop(p_access, nfs_mount_open_slash_finished_cb) < 0) goto error; } if (p_sys->p_nfsfh != NULL) { p_access->pf_read = FileRead; p_access->pf_seek = FileSeek; p_access->pf_control = FileControl; } else if (p_sys->p_nfsdir != NULL) { p_access->pf_readdir = DirRead; p_access->pf_seek = NULL; p_access->pf_control = DirControl; } else vlc_assert_unreachable(); } else { /* url is just a server: fetch exports point */ nfs_destroy_context(p_sys->p_nfs); p_sys->p_nfs = NULL; p_sys->p_mount = rpc_init_context(); if (p_sys->p_mount == NULL) { msg_Err(p_access, "rpc_init_context failed"); goto error; } p_sys->res.exports.ppsz_names = NULL; p_sys->res.exports.i_count = -1; if (mount_getexports_async(p_sys->p_mount, p_sys->p_nfs_url->server, mount_export_cb, p_access) < 0) { msg_Err(p_access, "mount_getexports_async failed"); goto error; } if (vlc_mount_mainloop(p_access, mount_getexports_finished_cb) < 0) goto error; p_access->pf_readdir = MountRead; p_access->pf_seek = NULL; p_access->pf_control = DirControl; } return VLC_SUCCESS; error: Close(p_obj); return VLC_EGENERIC; }
/** * Parses clipinfo parameter * @param psz_clipinfo: string containing the clipinfo parameter along with quotes * @param ppsz_artist: Buffer to store artist name * @param ppsz_title: Buffer to store title * @param ppsz_album: Buffer to store album * @param ppsz_genre: Buffer to store genre * @param ppsz_year: Buffer to store year * @param ppsz_cdnum: Buffer to store cdnum * @param ppsz_comments: Buffer to store comments */ static void ParseClipInfo( const char *psz_clipinfo, char **ppsz_artist, char **ppsz_title, char **ppsz_album, char **ppsz_genre, char **ppsz_year, char **ppsz_cdnum, char **ppsz_comments ) { char *psz_option_next, *psz_option_start, *psz_param, *psz_value, *psz_suboption; char *psz_temp_clipinfo = strdup( psz_clipinfo ); psz_option_start = strchr( psz_temp_clipinfo, '"' ); if( !psz_option_start ) { free( psz_temp_clipinfo ); return; } psz_option_start++; psz_option_next = psz_option_start; while( 1 ) /* Process each sub option */ { /* Get the sub option */ psz_option_start = psz_option_next; psz_option_next = strchr( psz_option_start, '|' ); if( psz_option_next ) *psz_option_next = '\0'; else psz_option_next = strchr( psz_option_start, '"' ); if( psz_option_next ) *psz_option_next = '\0'; else psz_option_next = strchr( psz_option_start, '\0' ); if( psz_option_next == psz_option_start ) break; psz_suboption = strdup( psz_option_start ); if( !psz_suboption ) break; /* Parse out param and value */ psz_param = psz_suboption; if( strchr( psz_suboption, '=' ) ) { psz_value = strchr( psz_suboption, '=' ) + 1; *( strchr( psz_suboption, '=' ) ) = '\0'; } else { free( psz_suboption ); break; } /* Put into args */ if( !strcmp( psz_param, "artist name" ) ) *ppsz_artist = vlc_uri_decode_duplicate( psz_value ); else if( !strcmp( psz_param, "title" ) ) *ppsz_title = vlc_uri_decode_duplicate( psz_value ); else if( !strcmp( psz_param, "album name" ) ) *ppsz_album = vlc_uri_decode_duplicate( psz_value ); else if( !strcmp( psz_param, "genre" ) ) *ppsz_genre = vlc_uri_decode_duplicate( psz_value ); else if( !strcmp( psz_param, "year" ) ) *ppsz_year = vlc_uri_decode_duplicate( psz_value ); else if( !strcmp( psz_param, "cdnum" ) ) *ppsz_cdnum = vlc_uri_decode_duplicate( psz_value ); else if( !strcmp( psz_param, "comments" ) ) *ppsz_comments = vlc_uri_decode_duplicate( psz_value ); free( psz_suboption ); psz_option_next++; } free( psz_temp_clipinfo ); }
/** * Main demux callback function * @param p_demux: this demux object */ static int Demux( demux_t *p_demux ) { char *psz_line; char *psz_artist = NULL, *psz_album = NULL, *psz_genre = NULL, *psz_year = NULL; char *psz_author = NULL, *psz_title = NULL, *psz_copyright = NULL, *psz_cdnum = NULL, *psz_comments = NULL; mtime_t i_duration = -1; const char **ppsz_options = NULL; int i_options = 0, i_start = 0, i_stop = 0; bool b_cleanup = false; input_item_t *p_input; input_item_t *p_current_input = GetCurrentItem(p_demux); input_item_node_t *p_subitems = input_item_node_Create( p_current_input ); psz_line = vlc_stream_ReadLine( p_demux->s ); while( psz_line ) { char *psz_parse = psz_line; /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++; if( *psz_parse == '#' ) { /* Ignore comments */ } else if( *psz_parse ) { char *psz_mrl, *psz_option_next, *psz_option; char *psz_param, *psz_value; /* Get the MRL from the file. Note that this might contain parameters of form ?param1=value1¶m2=value2 in a RAM file */ psz_mrl = ProcessMRL( psz_parse, p_demux->p_sys->psz_prefix ); b_cleanup = true; if ( !psz_mrl ) goto error; /* We have the MRL, now we have to check for options and parse them from MRL */ psz_option = strchr( psz_mrl, '?' ); /* Look for start of options */ if( psz_option ) { /* Remove options from MRL because VLC can't get the file otherwise */ *psz_option = '\0'; psz_option++; psz_option_next = psz_option; while( 1 ) /* Process each option */ { /* Look for end of first option which maybe a & or \0 */ psz_option = psz_option_next; psz_option_next = strchr( psz_option, '&' ); if( psz_option_next ) { *psz_option_next = '\0'; psz_option_next++; } else psz_option_next = strchr( psz_option, '\0' ); /* Quit if options are over */ if( psz_option_next == psz_option ) break; /* Parse out param and value */ psz_param = psz_option; psz_value = strchr( psz_option, '=' ); if( psz_value == NULL ) break; *psz_value = '\0'; psz_value++; /* Take action based on parameter value in the below if else structure */ /* TODO: Remove any quotes surrounding values if required */ if( !strcmp( psz_param, "clipinfo" ) ) { ParseClipInfo( psz_value, &psz_artist, &psz_title, &psz_album, &psz_genre, &psz_year, &psz_cdnum, &psz_comments ); /* clipinfo has various sub parameters, which is parsed by this function */ } else if( !strcmp( psz_param, "author" ) ) { psz_author = vlc_uri_decode_duplicate(psz_value); EnsureUTF8( psz_author ); } else if( !strcmp( psz_param, "start" ) && strncmp( psz_mrl, "rtsp", 4 ) /* Our rtsp-real or our real demuxer is wrong */ ) { i_start = ParseTime( psz_value, strlen( psz_value ) ); char *temp; if( i_start ) { if( asprintf( &temp, ":start-time=%d", i_start ) != -1 ) INSERT_ELEM( ppsz_options, i_options, i_options, temp ); } } else if( !strcmp( psz_param, "end" ) ) { i_stop = ParseTime( psz_value, strlen( psz_value ) ); char *temp; if( i_stop ) { if( asprintf( &temp, ":stop-time=%d", i_stop ) != -1 ) INSERT_ELEM( ppsz_options, i_options, i_options, temp ); } } else if( !strcmp( psz_param, "title" ) ) { free( psz_title ); psz_title = vlc_uri_decode_duplicate(psz_value); EnsureUTF8( psz_title ); } else if( !strcmp( psz_param, "copyright" ) ) { psz_copyright = vlc_uri_decode_duplicate(psz_value); EnsureUTF8( psz_copyright ); } else { /* TODO: insert option anyway? Currently ignores*/ /* INSERT_ELEM( ppsz_options, i_options, i_options, psz_option ); */ } } } /* Create the input item and pump in all the options into playlist item */ p_input = input_item_NewExt( psz_mrl, psz_title, i_duration, ITEM_TYPE_UNKNOWN, ITEM_NET_UNKNOWN ); if( !p_input ) { free( psz_mrl ); goto error; } input_item_AddOptions( p_input, i_options, ppsz_options, 0 ); if( !EMPTY_STR( psz_artist ) ) input_item_SetArtist( p_input, psz_artist ); if( !EMPTY_STR( psz_author ) ) input_item_SetPublisher( p_input, psz_author ); if( !EMPTY_STR( psz_title ) ) input_item_SetTitle( p_input, psz_title ); if( !EMPTY_STR( psz_copyright ) ) input_item_SetCopyright( p_input, psz_copyright ); if( !EMPTY_STR( psz_album ) ) input_item_SetAlbum( p_input, psz_album ); if( !EMPTY_STR( psz_genre ) ) input_item_SetGenre( p_input, psz_genre ); if( !EMPTY_STR( psz_year ) ) input_item_SetDate( p_input, psz_year ); if( !EMPTY_STR( psz_cdnum ) ) input_item_SetTrackNum( p_input, psz_cdnum ); if( !EMPTY_STR( psz_comments ) ) input_item_SetDescription( p_input, psz_comments ); input_item_node_AppendItem( p_subitems, p_input ); vlc_gc_decref( p_input ); free( psz_mrl ); } error: /* Fetch another line */ free( psz_line ); psz_line = vlc_stream_ReadLine( p_demux->s ); if( !psz_line ) b_cleanup = true; if( b_cleanup ) { /* Cleanup state */ while( i_options-- ) free( (char*)ppsz_options[i_options] ); FREENULL( ppsz_options ); FREENULL( psz_artist ); FREENULL( psz_title ); FREENULL( psz_author ); FREENULL( psz_copyright ); FREENULL( psz_album ); FREENULL( psz_genre ); FREENULL( psz_year ); FREENULL( psz_cdnum ); FREENULL( psz_comments ); i_options = 0; i_duration = -1; i_start = 0; i_stop = 0; b_cleanup = false; } } input_item_node_PostAndDelete( p_subitems ); vlc_gc_decref(p_current_input); var_Destroy( p_demux, "m3u-extvlcopt" ); return 0; /* Needed for correct operation of go back */ }
bool vlc_credential_store(vlc_credential *p_credential, vlc_object_t *p_parent) { if (!is_credential_valid(p_credential)) return false; /* Don't need to store again */ if (p_credential->b_from_keystore) return p_credential->b_from_keystore; vlc_keystore *p_keystore; if (p_credential->b_store) { /* Store in permanent keystore */ assert(p_credential->p_keystore != NULL); p_keystore = p_credential->p_keystore; } else { /* Store in memory keystore */ p_keystore = get_memory_keystore(p_parent); } if (p_keystore == NULL) return false; const vlc_url_t *p_url = p_credential->p_url; char *psz_path = NULL; if (protocol_store_path(p_url) && (psz_path = vlc_uri_decode_duplicate(p_url->psz_path)) != NULL) { char *p_slash; if (protocol_is_smb(p_url)) { /* Remove all characters after the first slash (store the share but * not the path) */ p_slash = strchr(psz_path + 1, '/'); } else { /* Remove all characters after the last slash (store the path * without the filename) */ p_slash = strrchr(psz_path + 1, '/'); } if (p_slash && psz_path != p_slash) *p_slash = '\0'; } const char *ppsz_values[KEY_MAX] = { 0 }; ppsz_values[KEY_PROTOCOL] = p_url->psz_protocol; ppsz_values[KEY_USER] = p_credential->psz_username; ppsz_values[KEY_SERVER] = p_url->psz_host; ppsz_values[KEY_PATH] = psz_path; ppsz_values[KEY_REALM] = p_credential->psz_realm; ppsz_values[KEY_AUTHTYPE] = p_credential->psz_authtype; char psz_port[21]; if (protocol_set_port(p_url, psz_port)) ppsz_values[KEY_PORT] = psz_port; char *psz_label; if (asprintf(&psz_label, "LibVLC password for %s://%s%s", p_url->psz_protocol, p_url->psz_host, psz_path ? psz_path : "") == -1) { free(psz_path); return false; } const uint8_t *p_password = (const uint8_t *) (p_credential->psz_password != NULL ? p_credential->psz_password : ""); bool b_ret = vlc_keystore_store(p_keystore, ppsz_values, p_password, -1, psz_label) == VLC_SUCCESS; free(psz_label); free(psz_path); return b_ret; }
/***************************************************************************** * Open: Initialize module's data structures and libdsm *****************************************************************************/ static int Open( vlc_object_t *p_this ) { access_t *p_access = (access_t*)p_this; access_sys_t *p_sys; smb_stat st; /* Init p_access */ access_InitFields( p_access ); p_sys = p_access->p_sys = (access_sys_t*)calloc( 1, sizeof( access_sys_t ) ); if( p_access->p_sys == NULL ) return VLC_ENOMEM; p_sys->p_ns = netbios_ns_new(); if( p_sys->p_ns == NULL ) goto error; p_sys->p_session = smb_session_new(); if( p_sys->p_session == NULL ) goto error; char *psz_decoded_location = vlc_uri_decode_duplicate( p_access->psz_location ); if( psz_decoded_location == NULL ) goto error; vlc_UrlParse( &p_sys->url, psz_decoded_location ); free( psz_decoded_location ); if( get_address( p_access ) != VLC_SUCCESS ) goto error; msg_Dbg( p_access, "Session: Host name = %s, ip = %s", p_sys->netbios_name, inet_ntoa( p_sys->addr ) ); /* Now that we have the required data, let's establish a session */ if( !smb_session_connect( p_sys->p_session, p_sys->netbios_name, p_sys->addr.s_addr, SMB_TRANSPORT_TCP ) ) { msg_Err( p_access, "Unable to connect/negotiate SMB session"); goto error; } get_path( p_access ); if( login( p_access ) != VLC_SUCCESS ) { msg_Err( p_access, "Unable to open file with path %s (in share %s)", p_sys->psz_path, p_sys->psz_share ); goto error; } /* If there is no shares, browse them */ if( !p_sys->psz_share ) return BrowserInit( p_access ); assert(p_sys->i_fd > 0); msg_Dbg( p_access, "Path: Share name = %s, path = %s", p_sys->psz_share, p_sys->psz_path ); st = smb_stat_fd( p_sys->p_session, p_sys->i_fd ); if( smb_stat_get( st, SMB_STAT_ISDIR ) ) { smb_fclose( p_sys->p_session, p_sys->i_fd ); return BrowserInit( p_access ); } msg_Dbg( p_access, "Successfully opened smb://%s", p_access->psz_location ); ACCESS_SET_CALLBACKS( Read, NULL, Control, Seek ); return VLC_SUCCESS; error: Close( p_this ); return VLC_EGENERIC; }
/**************************************************************************** * Open: connect to smb server and ask for file ****************************************************************************/ static int Open( vlc_object_t *p_this ) { stream_t *p_access = (stream_t*)p_this; access_sys_t *p_sys; struct stat filestat; vlc_url_t url; vlc_credential credential; char *psz_decoded_path = NULL, *psz_uri = NULL, *psz_var_domain = NULL; int i_ret; int i_smb; uint64_t i_size; bool b_is_dir = false; #ifndef _WIN32 if( smbc_init( smb_auth, 0 ) ) return VLC_EGENERIC; #endif /* ** some version of glibc defines open as a macro, causing havoc ** with other macros using 'open' under the hood, such as the ** following one: */ #if defined(smbc_open) && defined(open) # undef open #endif vlc_UrlParse( &url, p_access->psz_url ); if( url.psz_path ) { psz_decoded_path = vlc_uri_decode_duplicate( url.psz_path ); if( !psz_decoded_path ) { vlc_UrlClean( &url ); return VLC_EGENERIC; } } vlc_credential_init( &credential, &url ); psz_var_domain = var_InheritString( p_access, "smb-domain" ); credential.psz_realm = psz_var_domain; vlc_credential_get( &credential, p_access, "smb-user", "smb-pwd", NULL, NULL ); for (;;) { if( smb_get_uri( p_access, &psz_uri, credential.psz_realm, credential.psz_username, credential.psz_password, url.psz_host, psz_decoded_path, NULL ) == -1 ) { vlc_credential_clean( &credential ); free(psz_var_domain); free( psz_decoded_path ); vlc_UrlClean( &url ); return VLC_ENOMEM; } if( ( i_ret = smbc_stat( psz_uri, &filestat ) ) && errno == EACCES ) { errno = 0; if( vlc_credential_get( &credential, p_access, "smb-user", "smb-pwd", SMB_LOGIN_DIALOG_TITLE, SMB_LOGIN_DIALOG_TEXT, url.psz_host) ) continue; } /* smbc_stat fails with servers or shares. Assume they are directory */ if( i_ret || S_ISDIR( filestat.st_mode ) ) b_is_dir = true; break; } vlc_credential_store( &credential, p_access ); vlc_credential_clean( &credential ); free(psz_var_domain); free( psz_decoded_path ); /* Init p_access */ p_sys = p_access->p_sys = vlc_calloc( p_this, 1, sizeof( access_sys_t ) ); if( !p_sys ) { free( psz_uri ); vlc_UrlClean( &url ); return VLC_ENOMEM; } if( b_is_dir ) { p_sys->url = url; p_access->pf_readdir = DirRead; p_access->pf_control = access_vaDirectoryControlHelper; i_size = 0; #ifndef _WIN32 i_smb = smbc_opendir( psz_uri ); if( i_smb < 0 ) vlc_UrlClean( &p_sys->url ); #endif } else { ACCESS_SET_CALLBACKS( Read, NULL, Control, Seek ); i_smb = smbc_open( psz_uri, O_RDONLY, 0 ); i_size = filestat.st_size; vlc_UrlClean( &url ); } free( psz_uri ); #ifndef _WIN32 if( i_smb < 0 ) { msg_Err( p_access, "open failed for '%s' (%s)", p_access->psz_location, vlc_strerror_c(errno) ); return VLC_EGENERIC; } #endif p_sys->size = i_size; p_sys->i_smb = i_smb; return VLC_SUCCESS; }
static int Open(vlc_object_t *obj) { stream_t *access = (stream_t *)obj; vlc_url_t url; vlc_credential credential; char *psz_decoded_path = NULL, *psz_uri = NULL, *psz_var_domain = NULL; int fd; uint64_t size; bool is_dir; if (vlc_UrlParseFixup(&url, access->psz_url) != 0) { vlc_UrlClean(&url); return VLC_EGENERIC; } if (url.psz_path != NULL) { psz_decoded_path = vlc_uri_decode_duplicate(url.psz_path); if (psz_decoded_path == NULL) { vlc_UrlClean(&url); return VLC_EGENERIC; } } vlc_credential_init(&credential, &url); psz_var_domain = var_InheritString(access, "smb-domain"); credential.psz_realm = psz_var_domain; vlc_credential_get(&credential, access, "smb-user", "smb-pwd", NULL, NULL); for (;;) { struct stat st; if (smb_get_uri(access, &psz_uri, credential.psz_realm, credential.psz_username, credential.psz_password, url.psz_host, psz_decoded_path, NULL ) == -1 ) { vlc_credential_clean(&credential); free(psz_var_domain); free(psz_decoded_path); vlc_UrlClean(&url); return VLC_ENOMEM; } if (stat(psz_uri, &st) == 0) { is_dir = S_ISDIR(st.st_mode) != 0; size = st.st_size; break; } /* stat() fails with servers or shares. Assume directory. */ is_dir = true; size = 0; if (errno != EACCES) break; errno = 0; if (!vlc_credential_get(&credential, access, "smb-user", "smb-pwd", SMB_LOGIN_DIALOG_TITLE, SMB_LOGIN_DIALOG_TEXT, url.psz_host)) break; } vlc_credential_store(&credential, access); vlc_credential_clean(&credential); free(psz_var_domain); free(psz_decoded_path); /* Init access */ access_sys_t *sys = vlc_obj_calloc(obj, 1, sizeof (*sys)); if (unlikely(sys == NULL)) { free(psz_uri); vlc_UrlClean(&url); return VLC_ENOMEM; } access->p_sys = sys; if (is_dir) { sys->url = url; access->pf_readdir = DirRead; access->pf_control = access_vaDirectoryControlHelper; } else { access->pf_read = Read; access->pf_control = Control; access->pf_seek = Seek; fd = open(psz_uri, O_RDONLY, 0); vlc_UrlClean(&url); } free(psz_uri); sys->size = size; sys->i_smb = fd; return VLC_SUCCESS; }