contrib: cargo: use the 0.6.13 cargo-c version
[vlc.git] / modules / access / samba.c
blob9f397c44b7d77a5fd9af335a6285821f12b8f8ca
1 /*****************************************************************************
2 * samba.c: Samba / libsmbclient input module
3 *****************************************************************************
4 * Copyright (C) 2001-2015 VLC authors and VideoLAN
6 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <assert.h>
28 #include <errno.h>
29 #include <libsmbclient.h>
31 #include <vlc_common.h>
32 #include <vlc_fs.h>
33 #include <vlc_plugin.h>
34 #include <vlc_access.h>
35 #include <vlc_input_item.h>
36 #include <vlc_url.h>
37 #include <vlc_keystore.h>
39 #include "smb_common.h"
41 typedef struct
43 int i_smb;
44 uint64_t size;
45 vlc_url_t url;
46 } access_sys_t;
48 /* Build an SMB URI
49 * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] */
50 static char *smb_get_uri(
51 const char *psz_domain,
52 const char *psz_user, const char *psz_pwd,
53 const char *psz_server, const char *psz_share_path,
54 const char *psz_name)
56 char *uri;
58 assert(psz_server);
59 #define PSZ_SHARE_PATH_OR_NULL psz_share_path ? psz_share_path : ""
60 #define PSZ_NAME_OR_NULL psz_name ? "/" : "", psz_name ? psz_name : ""
61 if( (psz_user
62 ? asprintf( &uri, "smb://%s%s%s%s%s@%s%s%s%s",
63 psz_domain ? psz_domain : "", psz_domain ? ";" : "",
64 psz_user, psz_pwd ? ":" : "",
65 psz_pwd ? psz_pwd : "", psz_server,
66 PSZ_SHARE_PATH_OR_NULL, PSZ_NAME_OR_NULL )
67 : asprintf( &uri, "smb://%s%s%s%s", psz_server,
68 PSZ_SHARE_PATH_OR_NULL, PSZ_NAME_OR_NULL )) == -1 )
69 uri = NULL;
70 return uri;
73 /*****************************************************************************
74 * Seek: try to go at the right place
75 *****************************************************************************/
76 static int Seek( stream_t *p_access, uint64_t i_pos )
78 access_sys_t *p_sys = p_access->p_sys;
79 int64_t i_ret;
81 if( i_pos >= INT64_MAX )
82 return VLC_EGENERIC;
84 msg_Dbg( p_access, "seeking to %"PRId64, i_pos );
86 i_ret = smbc_lseek( p_sys->i_smb, i_pos, SEEK_SET );
87 if( i_ret == -1 )
89 msg_Err( p_access, "seek failed (%s)", vlc_strerror_c(errno) );
90 return VLC_EGENERIC;
93 return VLC_SUCCESS;
96 /*****************************************************************************
97 * Read:
98 *****************************************************************************/
99 static ssize_t Read( stream_t *p_access, void *p_buffer, size_t i_len )
101 access_sys_t *p_sys = p_access->p_sys;
102 int i_read;
104 i_read = smbc_read( p_sys->i_smb, p_buffer, i_len );
105 if( i_read < 0 )
107 msg_Err( p_access, "read failed (%s)", vlc_strerror_c(errno) );
108 i_read = 0;
111 return i_read;
114 /*****************************************************************************
115 * DirRead:
116 *****************************************************************************/
117 static int DirRead (stream_t *p_access, input_item_node_t *p_node )
119 access_sys_t *p_sys = p_access->p_sys;
120 int i_ret = VLC_SUCCESS;
122 struct vlc_readdir_helper rdh;
123 vlc_readdir_helper_init( &rdh, p_access, p_node );
125 struct smbc_dirent *p_entry;
127 while( i_ret == VLC_SUCCESS && ( p_entry = smbc_readdir( p_sys->i_smb ) ) )
129 const char *psz_server = p_sys->url.psz_host;
130 const char *psz_path = p_sys->url.psz_path;
131 const char *psz_name = p_entry->name;
132 int i_type;
134 switch( p_entry->smbc_type )
136 case SMBC_SERVER:
137 case SMBC_WORKGROUP:
138 psz_server = p_sys->url.psz_host;
139 psz_path = NULL;
140 psz_name = NULL;
141 /* fall through */
142 case SMBC_FILE_SHARE:
143 case SMBC_DIR:
144 i_type = ITEM_TYPE_DIRECTORY;
145 break;
146 case SMBC_FILE:
147 i_type = ITEM_TYPE_FILE;
148 break;
149 default:
150 case SMBC_PRINTER_SHARE:
151 case SMBC_COMMS_SHARE:
152 case SMBC_IPC_SHARE:
153 case SMBC_LINK:
154 continue;
157 char *psz_encoded_name = NULL;
158 if( psz_name != NULL
159 && ( psz_encoded_name = vlc_uri_encode( psz_name ) ) == NULL )
161 i_ret = VLC_ENOMEM;
162 break;
165 char *uri = smb_get_uri(NULL, NULL, NULL,
166 psz_server, psz_path, psz_encoded_name);
167 if (uri == NULL) {
168 free(psz_encoded_name);
169 i_ret = VLC_ENOMEM;
170 break;
172 free(psz_encoded_name);
173 i_ret = vlc_readdir_helper_additem(&rdh, uri, NULL, p_entry->name,
174 i_type, ITEM_NET);
175 free(uri);
178 vlc_readdir_helper_finish( &rdh, i_ret == VLC_SUCCESS );
180 return i_ret;
183 /*****************************************************************************
184 * Control:
185 *****************************************************************************/
186 static int Control( stream_t *p_access, int i_query, va_list args )
188 access_sys_t *sys = p_access->p_sys;
190 switch( i_query )
192 case STREAM_CAN_SEEK:
193 case STREAM_CAN_PAUSE:
194 case STREAM_CAN_CONTROL_PACE:
195 *va_arg( args, bool* ) = true;
196 break;
198 case STREAM_CAN_FASTSEEK:
199 *va_arg( args, bool* ) = false;
200 break;
202 case STREAM_GET_SIZE:
203 if( p_access->pf_readdir != NULL )
204 return VLC_EGENERIC;
205 *va_arg( args, uint64_t * ) = sys->size;
206 break;
208 case STREAM_GET_PTS_DELAY:
209 *va_arg( args, vlc_tick_t * ) = VLC_TICK_FROM_MS(
210 var_InheritInteger( p_access, "network-caching" ) );
211 break;
213 case STREAM_SET_PAUSE_STATE:
214 /* Nothing to do */
215 break;
217 default:
218 return VLC_EGENERIC;
221 return VLC_SUCCESS;
224 static void smb_auth(const char *srv, const char *shr, char *wg, int wglen,
225 char *un, int unlen, char *pw, int pwlen)
227 VLC_UNUSED(srv);
228 VLC_UNUSED(shr);
229 VLC_UNUSED(wg);
230 VLC_UNUSED(wglen);
231 VLC_UNUSED(un);
232 VLC_UNUSED(unlen);
233 VLC_UNUSED(pw);
234 VLC_UNUSED(pwlen);
235 //wglen = unlen = pwlen = 0;
238 static int Open(vlc_object_t *obj)
240 stream_t *access = (stream_t *)obj;
241 vlc_url_t url;
242 vlc_credential credential;
243 char *psz_decoded_path = NULL, *uri, *psz_var_domain = NULL;
244 int fd;
245 uint64_t size;
246 bool is_dir;
248 if (smbc_init(smb_auth, 0))
249 return VLC_EGENERIC;
251 if (vlc_UrlParseFixup(&url, access->psz_url) != 0)
253 vlc_UrlClean(&url);
254 return VLC_EGENERIC;
257 if (url.psz_path != NULL)
259 psz_decoded_path = vlc_uri_decode_duplicate(url.psz_path);
260 if (psz_decoded_path == NULL)
262 vlc_UrlClean(&url);
263 return VLC_EGENERIC;
267 vlc_credential_init(&credential, &url);
268 psz_var_domain = var_InheritString(access, "smb-domain");
269 credential.psz_realm = psz_var_domain;
270 vlc_credential_get(&credential, access, "smb-user", "smb-pwd", NULL, NULL);
272 for (;;)
274 struct stat st;
276 uri = smb_get_uri(credential.psz_realm, credential.psz_username,
277 credential.psz_password, url.psz_host,
278 psz_decoded_path, NULL);
279 if (uri == NULL)
281 vlc_credential_clean(&credential);
282 free(psz_var_domain);
283 free(psz_decoded_path);
284 vlc_UrlClean(&url);
285 return VLC_ENOMEM;
288 if (smbc_stat(uri, &st) == 0)
290 is_dir = S_ISDIR(st.st_mode) != 0;
291 size = st.st_size;
292 break;
295 /* smbc_stat() fails with servers or shares. Assume directory. */
296 is_dir = true;
297 size = 0;
299 if (errno != EACCES)
300 break;
302 errno = 0;
303 if (!vlc_credential_get(&credential, access, "smb-user",
304 "smb-pwd", SMB_LOGIN_DIALOG_TITLE,
305 SMB_LOGIN_DIALOG_TEXT, url.psz_host))
306 break;
309 vlc_credential_store(&credential, access);
310 vlc_credential_clean(&credential);
311 free(psz_var_domain);
312 free(psz_decoded_path);
314 /* Init access */
315 access_sys_t *sys = vlc_obj_calloc(obj, 1, sizeof (*sys));
316 if (unlikely(sys == NULL))
318 free(uri);
319 vlc_UrlClean(&url);
320 return VLC_ENOMEM;
323 access->p_sys = sys;
325 if (is_dir)
327 sys->url = url;
328 access->pf_readdir = DirRead;
329 access->pf_control = access_vaDirectoryControlHelper;
330 fd = smbc_opendir(uri);
331 if (fd < 0)
332 vlc_UrlClean(&sys->url);
334 else
336 access->pf_read = Read;
337 access->pf_control = Control;
338 access->pf_seek = Seek;
339 fd = smbc_open(uri, O_RDONLY, 0);
340 vlc_UrlClean(&url);
342 free(uri);
344 if (fd < 0)
346 msg_Err(obj, "cannot open %s: %s",
347 access->psz_location, vlc_strerror_c(errno));
348 return VLC_EGENERIC;
351 sys->size = size;
352 sys->i_smb = fd;
354 return VLC_SUCCESS;
357 static void Close(vlc_object_t *obj)
359 stream_t *access = (stream_t *)obj;
360 access_sys_t *sys = access->p_sys;
362 vlc_UrlClean(&sys->url);
364 if (access->pf_readdir != NULL)
365 smbc_closedir(sys->i_smb);
366 else
367 smbc_close(sys->i_smb);
370 vlc_module_begin()
371 set_shortname("SMB")
372 set_description(N_("SMB input"))
373 set_help(N_("Samba (Windows network shares) input"))
374 set_capability("access", 0)
375 set_category(CAT_INPUT)
376 set_subcategory(SUBCAT_INPUT_ACCESS)
377 add_string("smb-user", NULL, SMB_USER_TEXT, SMB_USER_LONGTEXT, false)
378 add_password("smb-pwd", NULL, SMB_PASS_TEXT, SMB_PASS_LONGTEXT)
379 add_string("smb-domain", NULL, SMB_DOMAIN_TEXT, SMB_DOMAIN_LONGTEXT, false)
380 add_shortcut("smb")
381 set_callbacks(Open, Close)
382 vlc_module_end()