Signed-off-by: Lukasz Marek <lukasz.m.luki2 at gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
... | ... |
@@ -24,6 +24,7 @@ |
24 | 24 |
#include "libavutil/avstring.h" |
25 | 25 |
#include "libavutil/opt.h" |
26 | 26 |
#include "libavutil/attributes.h" |
27 |
+#include "libavformat/avio.h" |
|
27 | 28 |
#include "avformat.h" |
28 | 29 |
#include "internal.h" |
29 | 30 |
#include "url.h" |
... | ... |
@@ -33,6 +34,7 @@ typedef struct { |
33 | 33 |
ssh_session session; |
34 | 34 |
sftp_session sftp; |
35 | 35 |
sftp_file file; |
36 |
+ sftp_dir dir; |
|
36 | 37 |
int64_t filesize; |
37 | 38 |
int rw_timeout; |
38 | 39 |
int trunc; |
... | ... |
@@ -187,11 +189,11 @@ static av_cold int libssh_close(URLContext *h) |
187 | 187 |
return 0; |
188 | 188 |
} |
189 | 189 |
|
190 |
-static av_cold int libssh_open(URLContext *h, const char *url, int flags) |
|
190 |
+static av_cold int libssh_connect(URLContext *h, const char *url, char *path, size_t path_size) |
|
191 | 191 |
{ |
192 | 192 |
LIBSSHContext *libssh = h->priv_data; |
193 |
- char proto[10], path[MAX_URL_SIZE], hostname[1024], credencials[1024]; |
|
194 |
- int port, ret; |
|
193 |
+ char proto[10], hostname[1024], credencials[1024]; |
|
194 |
+ int port = 22, ret; |
|
195 | 195 |
const char *user = NULL, *pass = NULL; |
196 | 196 |
char *end = NULL; |
197 | 197 |
|
... | ... |
@@ -199,7 +201,7 @@ static av_cold int libssh_open(URLContext *h, const char *url, int flags) |
199 | 199 |
credencials, sizeof(credencials), |
200 | 200 |
hostname, sizeof(hostname), |
201 | 201 |
&port, |
202 |
- path, sizeof(path), |
|
202 |
+ path, path_size, |
|
203 | 203 |
url); |
204 | 204 |
|
205 | 205 |
// a port of 0 will use a port from ~/.ssh/config or the default value 22 |
... | ... |
@@ -207,15 +209,27 @@ static av_cold int libssh_open(URLContext *h, const char *url, int flags) |
207 | 207 |
port = 0; |
208 | 208 |
|
209 | 209 |
if ((ret = libssh_create_ssh_session(libssh, hostname, port)) < 0) |
210 |
- goto fail; |
|
210 |
+ return ret; |
|
211 | 211 |
|
212 | 212 |
user = av_strtok(credencials, ":", &end); |
213 | 213 |
pass = av_strtok(end, ":", &end); |
214 | 214 |
|
215 | 215 |
if ((ret = libssh_authentication(libssh, user, pass)) < 0) |
216 |
- goto fail; |
|
216 |
+ return ret; |
|
217 | 217 |
|
218 | 218 |
if ((ret = libssh_create_sftp_session(libssh)) < 0) |
219 |
+ return ret; |
|
220 |
+ |
|
221 |
+ return 0; |
|
222 |
+} |
|
223 |
+ |
|
224 |
+static av_cold int libssh_open(URLContext *h, const char *url, int flags) |
|
225 |
+{ |
|
226 |
+ int ret; |
|
227 |
+ LIBSSHContext *libssh = h->priv_data; |
|
228 |
+ char path[MAX_URL_SIZE]; |
|
229 |
+ |
|
230 |
+ if ((ret = libssh_connect(h, url, path, sizeof(path))) < 0) |
|
219 | 231 |
goto fail; |
220 | 232 |
|
221 | 233 |
if ((ret = libssh_open_file(libssh, flags, path)) < 0) |
... | ... |
@@ -293,6 +307,88 @@ static int libssh_write(URLContext *h, const unsigned char *buf, int size) |
293 | 293 |
return bytes_written; |
294 | 294 |
} |
295 | 295 |
|
296 |
+static int libssh_open_dir(URLContext *h) |
|
297 |
+{ |
|
298 |
+ LIBSSHContext *libssh = h->priv_data; |
|
299 |
+ int ret; |
|
300 |
+ char path[MAX_URL_SIZE]; |
|
301 |
+ |
|
302 |
+ if ((ret = libssh_connect(h, h->filename, path, sizeof(path))) < 0) |
|
303 |
+ goto fail; |
|
304 |
+ |
|
305 |
+ if (!(libssh->dir = sftp_opendir(libssh->sftp, path))) { |
|
306 |
+ av_log(libssh, AV_LOG_ERROR, "Error opening sftp dir: %s\n", ssh_get_error(libssh->session)); |
|
307 |
+ ret = AVERROR(EIO); |
|
308 |
+ goto fail; |
|
309 |
+ } |
|
310 |
+ |
|
311 |
+ return 0; |
|
312 |
+ |
|
313 |
+ fail: |
|
314 |
+ libssh_close(h); |
|
315 |
+ return ret; |
|
316 |
+} |
|
317 |
+ |
|
318 |
+static int libssh_read_dir(URLContext *h, AVIODirEntry **next) |
|
319 |
+{ |
|
320 |
+ LIBSSHContext *libssh = h->priv_data; |
|
321 |
+ sftp_attributes attr = NULL; |
|
322 |
+ AVIODirEntry *entry; |
|
323 |
+ |
|
324 |
+ *next = entry = ff_alloc_dir_entry(); |
|
325 |
+ if (!entry) |
|
326 |
+ return AVERROR(ENOMEM); |
|
327 |
+ |
|
328 |
+ do { |
|
329 |
+ if (attr) |
|
330 |
+ sftp_attributes_free(attr); |
|
331 |
+ attr = sftp_readdir(libssh->sftp, libssh->dir); |
|
332 |
+ if (!attr) { |
|
333 |
+ av_freep(next); |
|
334 |
+ if (sftp_dir_eof(libssh->dir)) |
|
335 |
+ return 0; |
|
336 |
+ return AVERROR(EIO); |
|
337 |
+ } |
|
338 |
+ } while (!strcmp(attr->name, ".") || !strcmp(attr->name, "..")); |
|
339 |
+ |
|
340 |
+ entry->name = av_strdup(attr->name); |
|
341 |
+ entry->group_id = attr->gid; |
|
342 |
+ entry->user_id = attr->uid; |
|
343 |
+ entry->size = attr->size; |
|
344 |
+ entry->access_timestamp = INT64_C(1000000) * attr->atime; |
|
345 |
+ entry->modification_timestamp = INT64_C(1000000) * attr->mtime; |
|
346 |
+ entry->filemode = attr->permissions & 0777; |
|
347 |
+ switch(attr->type) { |
|
348 |
+ case SSH_FILEXFER_TYPE_REGULAR: |
|
349 |
+ entry->type = AVIO_ENTRY_FILE; |
|
350 |
+ break; |
|
351 |
+ case SSH_FILEXFER_TYPE_DIRECTORY: |
|
352 |
+ entry->type = AVIO_ENTRY_DIRECTORY; |
|
353 |
+ break; |
|
354 |
+ case SSH_FILEXFER_TYPE_SYMLINK: |
|
355 |
+ entry->type = AVIO_ENTRY_SYMBOLIC_LINK; |
|
356 |
+ break; |
|
357 |
+ case SSH_FILEXFER_TYPE_SPECIAL: |
|
358 |
+ /* Special type includes: sockets, char devices, block devices and pipes. |
|
359 |
+ It is probably better to return unknown type, to not confuse anybody. */ |
|
360 |
+ case SSH_FILEXFER_TYPE_UNKNOWN: |
|
361 |
+ default: |
|
362 |
+ entry->type = AVIO_ENTRY_UNKNOWN; |
|
363 |
+ } |
|
364 |
+ sftp_attributes_free(attr); |
|
365 |
+ return 0; |
|
366 |
+} |
|
367 |
+ |
|
368 |
+static int libssh_close_dir(URLContext *h) |
|
369 |
+{ |
|
370 |
+ LIBSSHContext *libssh = h->priv_data; |
|
371 |
+ if (libssh->dir) |
|
372 |
+ sftp_closedir(libssh->dir); |
|
373 |
+ libssh->dir = NULL; |
|
374 |
+ libssh_close(h); |
|
375 |
+ return 0; |
|
376 |
+} |
|
377 |
+ |
|
296 | 378 |
#define OFFSET(x) offsetof(LIBSSHContext, x) |
297 | 379 |
#define D AV_OPT_FLAG_DECODING_PARAM |
298 | 380 |
#define E AV_OPT_FLAG_ENCODING_PARAM |
... | ... |
@@ -317,6 +413,9 @@ URLProtocol ff_libssh_protocol = { |
317 | 317 |
.url_write = libssh_write, |
318 | 318 |
.url_seek = libssh_seek, |
319 | 319 |
.url_close = libssh_close, |
320 |
+ .url_open_dir = libssh_open_dir, |
|
321 |
+ .url_read_dir = libssh_read_dir, |
|
322 |
+ .url_close_dir = libssh_close_dir, |
|
320 | 323 |
.priv_data_size = sizeof(LIBSSHContext), |
321 | 324 |
.priv_data_class = &libssh_context_class, |
322 | 325 |
.flags = URL_PROTOCOL_FLAG_NETWORK, |