FFmpeg
Loading...
Searching...
No Matches
ftp.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013 Lukasz Marek <lukasz.m.luki@gmail.com>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <string.h>
22#include <time.h>
23
24#include "libavutil/avstring.h"
25#include "libavutil/internal.h"
26#include "libavutil/mem.h"
28#include "avformat.h"
29#include "internal.h"
30#include "url.h"
31#include "urldecode.h"
32#include "libavutil/opt.h"
33#include "libavutil/bprint.h"
34
35#define CONTROL_BUFFER_SIZE 1024
36#define DIR_BUFFER_SIZE 4096
37
47
53
54typedef struct {
55 const AVClass *class;
56 URLContext *conn_control; /**< Control connection */
57 URLContext *conn_data; /**< Data connection, NULL when not connected */
58 uint8_t control_buffer[CONTROL_BUFFER_SIZE]; /**< Control connection buffer */
60 int server_data_port; /**< Data connection port opened by server, -1 on error. */
61 int server_control_port; /**< Control connection port, default is 21 */
62 char *hostname; /**< Server address. */
63 char *user; /**< Server user */
64 char *password; /**< Server user's password */
65 char *path; /**< Path to resource on server. */
66 int64_t filesize; /**< Size of file on server, -1 on error. */
67 int64_t position; /**< Current position, calculated. */
68 int rw_timeout; /**< Network timeout. */
69 const char *anonymous_password; /**< Password to be used for anonymous user. An email should be used. */
70 int write_seekable; /**< Control seekability, 0 = disable, 1 = enable. */
71 FTPState state; /**< State of data connection */
72 FTPListingMethod listing_method; /**< Called listing method */
73 char *features; /**< List of server's features represented as raw response */
77 int utf8;
78 const char *option_user; /**< User to be used if none given in the URL */
79 const char *option_password; /**< Password to be used if none given in the URL */
81
82#define OFFSET(x) offsetof(FTPContext, x)
83#define D AV_OPT_FLAG_DECODING_PARAM
84#define E AV_OPT_FLAG_ENCODING_PARAM
85static const AVOption options[] = {
86 {"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
87 {"ftp-write-seekable", "control seekability of connection during encoding", OFFSET(write_seekable), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E },
88 {"ftp-anonymous-password", "password for anonymous login. E-mail address should be used.", OFFSET(anonymous_password), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
89 {"ftp-user", "user for FTP login. Overridden by whatever is in the URL.", OFFSET(option_user), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
90 {"ftp-password", "password for FTP login. Overridden by whatever is in the URL.", OFFSET(option_password), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
91 {NULL}
92};
93
94static const AVClass ftp_context_class = {
95 .class_name = "ftp",
96 .item_name = av_default_item_name,
97 .option = options,
98 .version = LIBAVUTIL_VERSION_INT,
99};
100
101static int ftp_close(URLContext *h);
102
103static int is_bad_string(const unsigned char *s)
104{
105 while(*s) {
106 if (*s < 0x20 || *s == 0x7F || *s == 0xFF)
107 return 1;
108 s++;
109 }
110 return 0;
111}
112
114{
115 int len;
116 if (s->control_buf_ptr >= s->control_buf_end) {
117 len = ffurl_read(s->conn_control, s->control_buffer, CONTROL_BUFFER_SIZE);
118 if (len < 0) {
119 return len;
120 } else if (!len) {
121 return -1;
122 } else {
123 s->control_buf_ptr = s->control_buffer;
124 s->control_buf_end = s->control_buffer + len;
125 }
126 }
127 return *s->control_buf_ptr++;
128}
129
130static int ftp_get_line(FTPContext *s, char *line, int line_size)
131{
132 int ch;
133 char *q = line;
134
135 for (;;) {
136 ch = ftp_getc(s);
137 if (ch < 0) {
138 return ch;
139 }
140 if (ch == '\n') {
141 /* process line */
142 if (q > line && q[-1] == '\r')
143 q--;
144 *q = '\0';
145 return 0;
146 } else {
147 if ((q - line) < line_size - 1)
148 *q++ = ch;
149 }
150 }
151}
152
153/*
154 * This routine returns ftp server response code.
155 * Server may send more than one response for a certain command.
156 * First expected code is returned.
157 */
158static int ftp_status(FTPContext *s, char **line, const int response_codes[])
159{
160 int err, i, dash = 0, result = 0, code_found = 0, linesize;
161 char buf[CONTROL_BUFFER_SIZE];
162 AVBPrint line_buffer;
163
164 if (line)
166
167 while (!code_found || dash) {
168 if ((err = ftp_get_line(s, buf, sizeof(buf))) < 0) {
169 if (line)
170 av_bprint_finalize(&line_buffer, NULL);
171 return err;
172 }
173
174 av_log(s, AV_LOG_DEBUG, "%s\n", buf);
175
176 linesize = strlen(buf);
177 err = 0;
178 if (linesize >= 3) {
179 for (i = 0; i < 3; ++i) {
180 if (buf[i] < '0' || buf[i] > '9') {
181 err = 0;
182 break;
183 }
184 err *= 10;
185 err += buf[i] - '0';
186 }
187 }
188
189 if (!code_found) {
190 if (err >= 500) {
191 code_found = 1;
192 result = err;
193 } else
194 for (i = 0; response_codes[i]; ++i) {
195 if (err == response_codes[i]) {
196 code_found = 1;
197 result = err;
198 break;
199 }
200 }
201 }
202 if (code_found) {
203 if (line)
204 av_bprintf(&line_buffer, "%s\r\n", buf);
205 if (linesize >= 4) {
206 if (!dash && buf[3] == '-')
207 dash = err;
208 else if (err == dash && buf[3] == ' ')
209 dash = 0;
210 }
211 }
212 }
213
214 if (line)
215 av_bprint_finalize(&line_buffer, line);
216 return result;
217}
218
219static int ftp_send_command(FTPContext *s, const char *command,
220 const int response_codes[], char **response)
221{
222 int err;
223
224 ff_dlog(s, "%s", command);
225
226 if (response)
227 *response = NULL;
228
229 if (!s->conn_control)
230 return AVERROR(EIO);
231
232 if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0)
233 return err;
234 if (!err)
235 return -1;
236
237 /* return status */
238 if (response_codes) {
239 return ftp_status(s, response, response_codes);
240 }
241 return 0;
242}
243
245{
246 ffurl_closep(&s->conn_data);
247 s->state = DISCONNECTED;
248}
249
251{
252 ffurl_closep(&s->conn_control);
254}
255
257{
258 char buf[CONTROL_BUFFER_SIZE];
259 int err;
260 static const int user_codes[] = {331, 230, 0};
261 static const int pass_codes[] = {230, 0};
262
263 if (is_bad_string(s->user))
264 return AVERROR(EINVAL);
265 err = snprintf(buf, sizeof(buf), "USER %s\r\n", s->user);
266 if (err >= sizeof(buf))
267 return AVERROR(ENOSYS);
268
269 err = ftp_send_command(s, buf, user_codes, NULL);
270 if (err == 331) {
271 if (s->password) {
272 if (is_bad_string(s->password))
273 return AVERROR(EINVAL);
274 err = snprintf(buf, sizeof(buf), "PASS %s\r\n", s->password);
275 if (err >= sizeof(buf))
276 return AVERROR(ENOSYS);
277
278 err = ftp_send_command(s, buf, pass_codes, NULL);
279 } else
280 return AVERROR(EACCES);
281 }
282 if (err != 230)
283 return AVERROR(EACCES);
284
285 return 0;
286}
287
289{
290 char *res = NULL, *start = NULL, *end = NULL;
291 int i;
292 static const char d = '|';
293 static const char *command = "EPSV\r\n";
294 static const int epsv_codes[] = {229, 0};
295
296 if (ftp_send_command(s, command, epsv_codes, &res) != 229 || !res)
297 goto fail;
298
299 for (i = 0; res[i]; ++i) {
300 if (res[i] == '(') {
301 start = res + i + 1;
302 } else if (res[i] == ')') {
303 end = res + i;
304 break;
305 }
306 }
307 if (!start || !end)
308 goto fail;
309
310 *end = '\0';
311 if (strlen(start) < 5)
312 goto fail;
313 if (start[0] != d || start[1] != d || start[2] != d || end[-1] != d)
314 goto fail;
315 start += 3;
316 end[-1] = '\0';
317
318 s->server_data_port = atoi(start);
319 ff_dlog(s, "Server data port: %d\n", s->server_data_port);
320
321 av_free(res);
322 return 0;
323
324 fail:
325 av_free(res);
326 s->server_data_port = -1;
327 return AVERROR(ENOSYS);
328}
329
331{
332 char *res = NULL, *start = NULL, *end = NULL;
333 int i;
334 static const char *command = "PASV\r\n";
335 static const int pasv_codes[] = {227, 0};
336
337 if (ftp_send_command(s, command, pasv_codes, &res) != 227 || !res)
338 goto fail;
339
340 for (i = 0; res[i]; ++i) {
341 if (res[i] == '(') {
342 start = res + i + 1;
343 } else if (res[i] == ')') {
344 end = res + i;
345 break;
346 }
347 }
348 if (!start || !end)
349 goto fail;
350
351 *end = '\0';
352 /* skip ip */
353 if (!av_strtok(start, ",", &end)) goto fail;
354 if (!av_strtok(NULL, ",", &end)) goto fail;
355 if (!av_strtok(NULL, ",", &end)) goto fail;
356 if (!av_strtok(NULL, ",", &end)) goto fail;
357
358 /* parse port number */
359 start = av_strtok(NULL, ",", &end);
360 if (!start) goto fail;
361 s->server_data_port = atoi(start) * 256;
362 start = av_strtok(NULL, ",", &end);
363 if (!start) goto fail;
364 s->server_data_port += atoi(start);
365 ff_dlog(s, "Server data port: %d\n", s->server_data_port);
366
367 av_free(res);
368 return 0;
369
370 fail:
371 av_free(res);
372 s->server_data_port = -1;
373 return AVERROR(EIO);
374}
375
377{
378 char *res = NULL, *start = NULL, *end = NULL;
379 int i;
380 static const char *command = "PWD\r\n";
381 static const int pwd_codes[] = {257, 0};
382
383 if (ftp_send_command(s, command, pwd_codes, &res) != 257 || !res)
384 goto fail;
385
386 for (i = 0; res[i]; ++i) {
387 if (res[i] == '"') {
388 if (!start) {
389 start = res + i + 1;
390 continue;
391 }
392 end = res + i;
393 break;
394 }
395 }
396
397 if (!end)
398 goto fail;
399
400 *end = '\0';
401 s->path = av_strdup(start);
402
403 av_free(res);
404
405 if (!s->path)
406 return AVERROR(ENOMEM);
407 return 0;
408
409 fail:
410 av_free(res);
411 return AVERROR(EIO);
412}
413
415{
417 char *res = NULL;
418 int ret;
419 static const int size_codes[] = {213, 0};
420
421 ret = snprintf(command, sizeof(command), "SIZE %s\r\n", s->path);
422 if (ret >= sizeof(command))
423 return AVERROR(ENOSYS);
424
425 if (ftp_send_command(s, command, size_codes, &res) == 213 && res && strlen(res) > 4) {
426 s->filesize = strtoll(&res[4], NULL, 10);
427 } else {
428 s->filesize = -1;
429 av_free(res);
430 return AVERROR(EIO);
431 }
432
433 av_free(res);
434 return 0;
435}
436
438{
440 static const int retr_codes[] = {150, 125, 0};
441 int resp_code, ret;
442
443 ret = snprintf(command, sizeof(command), "RETR %s\r\n", s->path);
444 if (ret >= sizeof(command))
445 return AVERROR(ENOSYS);
446
447 resp_code = ftp_send_command(s, command, retr_codes, NULL);
448 if (resp_code != 125 && resp_code != 150)
449 return AVERROR(EIO);
450
451 s->state = DOWNLOADING;
452
453 return 0;
454}
455
457{
459 static const int stor_codes[] = {150, 125, 0};
460 int resp_code, ret;
461
462 ret = snprintf(command, sizeof(command), "STOR %s\r\n", s->path);
463 if (ret >= sizeof(command))
464 return AVERROR(ENOSYS);
465
466 resp_code = ftp_send_command(s, command, stor_codes, NULL);
467 if (resp_code != 125 && resp_code != 150)
468 return AVERROR(EIO);
469
470 s->state = UPLOADING;
471
472 return 0;
473}
474
476{
477 static const char *command = "TYPE I\r\n";
478 static const int type_codes[] = {200, 0};
479
480 if (ftp_send_command(s, command, type_codes, NULL) != 200)
481 return AVERROR(EIO);
482
483 return 0;
484}
485
487{
489 static const int rest_codes[] = {350, 0};
490
491 snprintf(command, sizeof(command), "REST %"PRId64"\r\n", pos);
492 if (ftp_send_command(s, command, rest_codes, NULL) != 350)
493 return AVERROR(EIO);
494
495 return 0;
496}
497
499{
500 static const int cwd_codes[] = {250, 550, 0}; /* 550 is incorrect code */
501 char command[MAX_URL_SIZE];
502 int ret;
503
504 ret = snprintf(command, sizeof(command), "CWD %s\r\n", s->path);
505 if (ret >= sizeof(command))
506 return AVERROR(ENOSYS);
507
508 if (ftp_send_command(s, command, cwd_codes, NULL) != 250)
509 return AVERROR(EIO);
510 return 0;
511}
512
514{
515 static const char *command = "MLSD\r\n";
516 static const int mlsd_codes[] = {150, 500, 0}; /* 500 is incorrect code */
517
518 if (ftp_send_command(s, command, mlsd_codes, NULL) != 150)
519 return AVERROR(ENOSYS);
520 s->listing_method = MLSD;
521 return 0;
522}
523
525{
526 static const char *command = "NLST\r\n";
527 static const int nlst_codes[] = {226, 425, 426, 451, 450, 550, 0};
528
529 if (ftp_send_command(s, command, nlst_codes, NULL) != 226)
530 return AVERROR(ENOSYS);
531 s->listing_method = NLST;
532 return 0;
533}
534
536{
537 int ret;
538 s->state = LISTING_DIR;
539
540 if ((ret = ftp_list_mlsd(s)) < 0)
541 ret = ftp_list_nlst(s);
542
543 return ret;
544}
545
546static int ftp_has_feature(FTPContext *s, const char *feature_name)
547{
548 if (!s->features)
549 return 0;
550
551 return av_stristr(s->features, feature_name) != NULL;
552}
553
555{
556 static const char *feat_command = "FEAT\r\n";
557 static const char *enable_utf8_command = "OPTS UTF8 ON\r\n";
558 static const int feat_codes[] = {211, 0};
559 static const int opts_codes[] = {200, 202, 451, 0};
560
561 av_freep(&s->features);
562 if (ftp_send_command(s, feat_command, feat_codes, &s->features) != 211) {
563 av_freep(&s->features);
564 }
565
566 if (ftp_has_feature(s, "UTF8")) {
567 int ret = ftp_send_command(s, enable_utf8_command, opts_codes, NULL);
568 if (ret == 200 || ret == 202)
569 s->utf8 = 1;
570 }
571
572 return 0;
573}
574
576{
577 char buf[CONTROL_BUFFER_SIZE], *response = NULL;
578 int err;
580 FTPContext *s = h->priv_data;
581 static const int connect_codes[] = {220, 0};
582
583 if (!s->conn_control) {
584 ff_url_join(buf, sizeof(buf), "tcp", NULL,
585 s->hostname, s->server_control_port, NULL);
586 if (s->rw_timeout != -1) {
587 av_dict_set_int(&opts, "timeout", s->rw_timeout, 0);
588 } /* if option is not given, don't pass it and let tcp use its own default */
589 err = ffurl_open_whitelist(&s->conn_control, buf, AVIO_FLAG_READ_WRITE,
590 &h->interrupt_callback, &opts,
591 h->protocol_whitelist, h->protocol_blacklist, h);
593 if (err < 0) {
594 av_log(h, AV_LOG_ERROR, "Cannot open control connection\n");
595 return err;
596 }
597
598 /* check if server is ready */
599 if (ftp_status(s, ((h->flags & AVIO_FLAG_WRITE) ? &response : NULL), connect_codes) != 220) {
600 av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n");
601 return AVERROR(EACCES);
602 }
603
604 if ((h->flags & AVIO_FLAG_WRITE) && av_stristr(response, "pure-ftpd")) {
605 av_log(h, AV_LOG_WARNING, "Pure-FTPd server is used as an output protocol. It is known issue this implementation may produce incorrect content and it cannot be fixed at this moment.");
606 }
607 av_free(response);
608
609 if ((err = ftp_auth(s)) < 0) {
610 av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
611 return err;
612 }
613
614 if ((err = ftp_type(s)) < 0) {
615 av_log(h, AV_LOG_ERROR, "Set content type failed\n");
616 return err;
617 }
618
620 }
621 return 0;
622}
623
625{
626 int err;
627 char buf[CONTROL_BUFFER_SIZE];
629 FTPContext *s = h->priv_data;
630
631 if (!s->conn_data) {
632 /* Enter passive mode */
633 if (ftp_passive_mode_epsv(s) < 0) {
634 /* Use PASV as fallback */
635 if ((err = ftp_passive_mode(s)) < 0)
636 return err;
637 }
638 /* Open data connection */
639 ff_url_join(buf, sizeof(buf), "tcp", NULL, s->hostname, s->server_data_port, NULL);
640 if (s->rw_timeout != -1) {
641 av_dict_set_int(&opts, "timeout", s->rw_timeout, 0);
642 } /* if option is not given, don't pass it and let tcp use its own default */
643 err = ffurl_open_whitelist(&s->conn_data, buf, h->flags,
644 &h->interrupt_callback, &opts,
645 h->protocol_whitelist, h->protocol_blacklist, h);
647 if (err < 0)
648 return err;
649
650 if (s->position)
651 if ((err = ftp_restart(s, s->position)) < 0)
652 return err;
653 }
654 s->state = READY;
655 return 0;
656}
657
659{
660 static const char *command = "ABOR\r\n";
661 int err;
662 static const int abor_codes[] = {225, 226, 0};
663 FTPContext *s = h->priv_data;
664
665 /* According to RCF 959:
666 "ABOR command tells the server to abort the previous FTP
667 service command and any associated transfer of data."
668
669 There are FTP server implementations that don't response
670 to any commands during data transfer in passive mode (including ABOR).
671
672 This implementation closes data connection by force.
673 */
674
675 if (ftp_send_command(s, command, NULL, NULL) < 0) {
677 if ((err = ftp_connect_control_connection(h)) < 0) {
678 av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
679 return err;
680 }
681 } else {
683 if (ftp_status(s, NULL, abor_codes) < 225) {
684 /* wu-ftpd also closes control connection after data connection closing */
685 ffurl_closep(&s->conn_control);
686 if ((err = ftp_connect_control_connection(h)) < 0) {
687 av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
688 return err;
689 }
690 }
691 }
692
693 return 0;
694}
695
696static int ftp_connect(URLContext *h, const char *url)
697{
698 char proto[10], path[MAX_URL_SIZE], credentials[MAX_URL_SIZE], hostname[MAX_URL_SIZE];
699 const char *tok_user = NULL, *tok_pass = NULL;
700 char *newpath = NULL;
701 int err;
702 FTPContext *s = h->priv_data;
703
704 s->state = DISCONNECTED;
705 s->listing_method = UNKNOWN_METHOD;
706 s->filesize = -1;
707 s->position = 0;
708 s->features = NULL;
709
710 av_url_split(proto, sizeof(proto),
711 credentials, sizeof(credentials),
712 hostname, sizeof(hostname),
713 &s->server_control_port,
714 path, sizeof(path),
715 url);
716
717 if (!*credentials) {
718 if (!s->option_user) {
719 tok_user = "anonymous";
720 tok_pass = av_x_if_null(s->anonymous_password, "nopassword");
721 } else {
722 tok_user = s->option_user;
723 tok_pass = s->option_password;
724 }
725 s->user = av_strdup(tok_user);
726 s->password = av_strdup(tok_pass);
727 } else {
728 char *pass = strchr(credentials, ':');
729 if (pass) {
730 *pass++ = '\0';
731 tok_pass = pass;
732 s->password = ff_urldecode(pass, 0);
733 } else {
734 tok_pass = s->option_password;
735 s->password = av_strdup(tok_pass);
736 }
737 s->user = ff_urldecode(credentials, 0);
738 }
739 s->hostname = av_strdup(hostname);
740 if (!s->hostname || !s->user || (tok_pass && !s->password)) {
741 return AVERROR(ENOMEM);
742 }
743
744 if (s->server_control_port < 0 || s->server_control_port > 65535)
745 s->server_control_port = 21;
746
747 if ((err = ftp_connect_control_connection(h)) < 0)
748 return err;
749
750 if ((err = ftp_current_dir(s)) < 0)
751 return err;
752
753 newpath = av_append_path_component(s->path, path);
754 if (!newpath)
755 return AVERROR(ENOMEM);
756 av_free(s->path);
757 s->path = newpath;
758
759 if (is_bad_string(s->path)) {
760 av_log(h, AV_LOG_ERROR, "Path contains non-printable characters\n");
761 return AVERROR(EINVAL);
762 }
763
764 return 0;
765}
766
767static int ftp_open(URLContext *h, const char *url, int flags)
768{
769 FTPContext *s = h->priv_data;
770 int err;
771
772 ff_dlog(h, "ftp protocol open\n");
773
774 if ((err = ftp_connect(h, url)) < 0)
775 goto fail;
776
777 if (ftp_restart(s, 0) < 0) {
778 h->is_streamed = 1;
779 } else {
781 if (s->write_seekable != 1 && flags & AVIO_FLAG_WRITE)
782 h->is_streamed = 1;
783 }
784
785 return 0;
786
787 fail:
788 av_log(h, AV_LOG_ERROR, "FTP open failed\n");
789 ftp_close(h);
790 return err;
791}
792
793static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
794{
795 FTPContext *s = h->priv_data;
796 int err;
797 int64_t new_pos;
798
799 ff_dlog(h, "ftp protocol seek %"PRId64" %d\n", pos, whence);
800
801 switch(whence) {
802 case AVSEEK_SIZE:
803 return s->filesize;
804 case SEEK_SET:
805 new_pos = pos;
806 break;
807 case SEEK_CUR:
808 new_pos = s->position + pos;
809 break;
810 case SEEK_END:
811 if (s->filesize < 0)
812 return AVERROR(EIO);
813 new_pos = s->filesize + pos;
814 break;
815 default:
816 return AVERROR(EINVAL);
817 }
818
819 if (h->is_streamed)
820 return AVERROR(EIO);
821
822 if (new_pos < 0) {
823 av_log(h, AV_LOG_ERROR, "Seeking to negative position.\n");
824 return AVERROR(EINVAL);
825 }
826
827 if (new_pos != s->position) {
828 if ((err = ftp_abort(h)) < 0)
829 return err;
830 s->position = new_pos;
831 }
832 return new_pos;
833}
834
835static int ftp_read(URLContext *h, unsigned char *buf, int size)
836{
837 FTPContext *s = h->priv_data;
838 int read, err, retry_done = 0;
839
840 ff_dlog(h, "ftp protocol read %d bytes\n", size);
841 retry:
842 if (s->state == ENDOFFILE)
843 return AVERROR_EOF;
844 if (s->state == DISCONNECTED) {
845 if ((err = ftp_connect_data_connection(h)) < 0)
846 return err;
847 }
848 if (s->state == READY) {
849 if ((err = ftp_retrieve(s)) < 0)
850 return err;
851 }
852 if (s->conn_data && s->state == DOWNLOADING) {
853 read = ffurl_read(s->conn_data, buf, size);
854 if (read >= 0) {
855 s->position += read;
856 s->filesize = FFMAX(s->filesize, s->position);
857 }
858 if (read == AVERROR_EOF) {
859 static const int retr_codes[] = {226, 250, 425, 426, 451, 0};
860 char *response = NULL;
861 err = ftp_status(s, &response, retr_codes);
862 if (err == 226) {
864 av_freep(&response);
865 s->state = ENDOFFILE;
866 return AVERROR_EOF;
867 }
868 /* 250 is not allowed, any other status means some kind of error */
869 av_log(h, AV_LOG_ERROR, "FTP transfer failed: %s\n", response ? response : (err < 0 ? av_err2str(err) : "?"));
870 av_freep(&response);
871 read = AVERROR(EIO);
872 }
873 if (read <= 0 && !h->is_streamed) {
874 /* Server closed connection. Probably due to inactivity */
875 av_log(h, AV_LOG_INFO, "Reconnect to FTP server.\n");
876 if ((err = ftp_abort(h)) < 0)
877 return err;
878 if (!retry_done) {
879 retry_done = 1;
880 goto retry;
881 }
882 }
883 return read;
884 }
885
886 av_log(h, AV_LOG_DEBUG, "FTP read failed\n");
887 return AVERROR(EIO);
888}
889
890static int ftp_write(URLContext *h, const unsigned char *buf, int size)
891{
892 int err;
893 FTPContext *s = h->priv_data;
894 int written;
895
896 ff_dlog(h, "ftp protocol write %d bytes\n", size);
897
898 if (s->state == DISCONNECTED) {
899 if ((err = ftp_connect_data_connection(h)) < 0)
900 return err;
901 }
902 if (s->state == READY) {
903 if ((err = ftp_store(s)) < 0)
904 return err;
905 }
906 if (s->conn_data && s->state == UPLOADING) {
907 written = ffurl_write(s->conn_data, buf, size);
908 if (written > 0) {
909 s->position += written;
910 s->filesize = FFMAX(s->filesize, s->position);
911 }
912 return written;
913 }
914
915 av_log(h, AV_LOG_ERROR, "FTP write failed\n");
916 return AVERROR(EIO);
917}
918
920{
921 FTPContext *s = h->priv_data;
922
923 ff_dlog(h, "ftp protocol close\n");
924
926 av_freep(&s->user);
927 av_freep(&s->password);
928 av_freep(&s->hostname);
929 av_freep(&s->path);
930 av_freep(&s->features);
931
932 return 0;
933}
934
936{
937 FTPContext *s = h->priv_data;
938
939 ff_dlog(h, "ftp protocol get_file_handle\n");
940
941 if (s->conn_data)
942 return ffurl_get_file_handle(s->conn_data);
943
944 return AVERROR(EIO);
945}
946
948{
949 FTPContext *s = h->priv_data;
950
951 ff_dlog(h, "ftp protocol shutdown\n");
952
953 if (s->conn_data)
954 return ffurl_shutdown(s->conn_data, flags);
955
956 return AVERROR(EIO);
957}
958
960{
961 FTPContext *s = h->priv_data;
962 int ret;
963
964 if ((ret = ftp_connect(h, h->filename)) < 0)
965 goto fail;
966 if ((ret = ftp_set_dir(s)) < 0)
967 goto fail;
968 if ((ret = ftp_connect_data_connection(h)) < 0)
969 goto fail;
970 if ((ret = ftp_list(s)) < 0)
971 goto fail;
972 s->dir_buffer = av_malloc(DIR_BUFFER_SIZE);
973 if (!s->dir_buffer) {
974 ret = AVERROR(ENOMEM);
975 goto fail;
976 }
977 s->dir_buffer[0] = 0;
978 if (s->conn_data && s->state == LISTING_DIR)
979 return 0;
980 fail:
981 ffurl_closep(&s->conn_control);
982 ffurl_closep(&s->conn_data);
983 return ret;
984}
985
986static int64_t ftp_parse_date(const char *date)
987{
988 struct tm tv;
989 memset(&tv, 0, sizeof(struct tm));
990 av_small_strptime(date, "%Y%m%d%H%M%S", &tv);
991 return INT64_C(1000000) * av_timegm(&tv);
992}
993
994static int ftp_parse_entry_nlst(char *line, AVIODirEntry *next)
995{
996 next->name = av_strdup(line);
997 return 0;
998}
999
1000static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next)
1001{
1002 char *fact, *value;
1003 char *saveptr = NULL, *p = mlsd;
1004 ff_dlog(NULL, "%s\n", mlsd);
1005 while(fact = av_strtok(p, ";", &saveptr)) {
1006 p = NULL;
1007 if (fact[0] == ' ') {
1008 next->name = av_strdup(&fact[1]);
1009 continue;
1010 }
1011 fact = av_strtok(fact, "=", &value);
1012 if (!fact)
1013 continue;
1014 if (!av_strcasecmp(fact, "type")) {
1015 if (!av_strcasecmp(value, "cdir") || !av_strcasecmp(value, "pdir"))
1016 return 1;
1017 if (!av_strcasecmp(value, "dir"))
1018 next->type = AVIO_ENTRY_DIRECTORY;
1019 else if (!av_strcasecmp(value, "file"))
1020 next->type = AVIO_ENTRY_FILE;
1021 else if (!av_strcasecmp(value, "OS.unix=slink:"))
1023 } else if (!av_strcasecmp(fact, "modify")) {
1025 } else if (!av_strcasecmp(fact, "UNIX.mode")) {
1026 next->filemode = strtoumax(value, NULL, 8);
1027 } else if (!av_strcasecmp(fact, "UNIX.uid") || !av_strcasecmp(fact, "UNIX.owner"))
1028 next->user_id = strtoumax(value, NULL, 10);
1029 else if (!av_strcasecmp(fact, "UNIX.gid") || !av_strcasecmp(fact, "UNIX.group"))
1030 next->group_id = strtoumax(value, NULL, 10);
1031 else if (!av_strcasecmp(fact, "size") || !av_strcasecmp(fact, "sizd"))
1032 next->size = strtoll(value, NULL, 10);
1033 }
1034 return 0;
1035}
1036
1037/**
1038 * @return 0 on success, negative on error, positive on entry to discard.
1039 */
1041{
1042 FTPContext *s = h->priv_data;
1043
1044 switch (s->listing_method) {
1045 case MLSD:
1046 return ftp_parse_entry_mlsd(line, next);
1047 case NLST:
1048 return ftp_parse_entry_nlst(line, next);
1049 case UNKNOWN_METHOD:
1050 default:
1051 return -1;
1052 }
1053}
1054
1056{
1057 FTPContext *s = h->priv_data;
1058 char *start, *found;
1059 int ret, retried;
1060
1061 do {
1062 retried = 0;
1063 start = s->dir_buffer + s->dir_buffer_offset;
1064 while (!(found = strstr(start, "\n"))) {
1065 if (retried)
1066 return AVERROR(EIO);
1067 s->dir_buffer_size -= s->dir_buffer_offset;
1068 s->dir_buffer_offset = 0;
1069 if (s->dir_buffer_size)
1070 memmove(s->dir_buffer, start, s->dir_buffer_size);
1071 ret = ffurl_read(s->conn_data, s->dir_buffer + s->dir_buffer_size, DIR_BUFFER_SIZE - (s->dir_buffer_size + 1));
1072 if (ret < 0)
1073 return ret;
1074 if (!ret) {
1075 *next = NULL;
1076 return 0;
1077 }
1078 s->dir_buffer_size += ret;
1079 s->dir_buffer[s->dir_buffer_size] = 0;
1080 start = s->dir_buffer;
1081 retried = 1;
1082 }
1083 s->dir_buffer_offset += (found + 1 - start);
1084 found[0] = 0;
1085 if (found > start && found[-1] == '\r')
1086 found[-1] = 0;
1087
1088 *next = ff_alloc_dir_entry();
1089 if (!*next)
1090 return AVERROR(ENOMEM);
1091 (*next)->utf8 = s->utf8;
1092 ret = ftp_parse_entry(h, start, *next);
1093 if (ret) {
1095 if (ret < 0)
1096 return ret;
1097 }
1098 } while (ret > 0);
1099 return 0;
1100}
1101
1103{
1104 FTPContext *s = h->priv_data;
1105 av_freep(&s->dir_buffer);
1106 ffurl_closep(&s->conn_control);
1107 ffurl_closep(&s->conn_data);
1108 return 0;
1109}
1110
1112{
1113 FTPContext *s = h->priv_data;
1114 char command[MAX_URL_SIZE];
1115 static const int del_codes[] = {250, 421, 450, 500, 501, 502, 530, 550, 0};
1116 static const int rmd_codes[] = {250, 421, 500, 501, 502, 530, 550, 0};
1117 int ret;
1118
1119 if ((ret = ftp_connect(h, h->filename)) < 0)
1120 goto cleanup;
1121
1122 ret = snprintf(command, sizeof(command), "DELE %s\r\n", s->path);
1123 if (ret >= sizeof(command)) {
1124 ret = AVERROR(ENOSYS);
1125 goto cleanup;
1126 }
1127
1128 if (ftp_send_command(s, command, del_codes, NULL) == 250) {
1129 ret = 0;
1130 goto cleanup;
1131 }
1132
1133 ret = snprintf(command, sizeof(command), "RMD %s\r\n", s->path);
1134 if (ret >= sizeof(command)) {
1135 ret = AVERROR(ENOSYS);
1136 goto cleanup;
1137 }
1138
1139 if (ftp_send_command(s, command, rmd_codes, NULL) == 250)
1140 ret = 0;
1141 else
1142 ret = AVERROR(EIO);
1143
1144cleanup:
1145 ftp_close(h);
1146 return ret;
1147}
1148
1149static int ftp_move(URLContext *h_src, URLContext *h_dst)
1150{
1151 FTPContext *s = h_src->priv_data;
1152 char command[MAX_URL_SIZE], path[MAX_URL_SIZE];
1153 static const int rnfr_codes[] = {350, 421, 450, 500, 501, 502, 503, 530, 0};
1154 static const int rnto_codes[] = {250, 421, 500, 501, 502, 503, 530, 532, 553, 0};
1155 int ret;
1156
1157 if ((ret = ftp_connect(h_src, h_src->filename)) < 0)
1158 goto cleanup;
1159
1160 ret = snprintf(command, sizeof(command), "RNFR %s\r\n", s->path);
1161 if (ret >= sizeof(command)) {
1162 ret = AVERROR(ENOSYS);
1163 goto cleanup;
1164 }
1165
1166 if (ftp_send_command(s, command, rnfr_codes, NULL) != 350) {
1167 ret = AVERROR(EIO);
1168 goto cleanup;
1169 }
1170
1171 av_url_split(0, 0, 0, 0, 0, 0, 0,
1172 path, sizeof(path),
1173 h_dst->filename);
1174 if (is_bad_string(path)) {
1175 ret = AVERROR(EINVAL);
1176 goto cleanup;
1177 }
1178 ret = snprintf(command, sizeof(command), "RNTO %s\r\n", path);
1179 if (ret >= sizeof(command)) {
1180 ret = AVERROR(ENOSYS);
1181 goto cleanup;
1182 }
1183
1184 if (ftp_send_command(s, command, rnto_codes, NULL) == 250)
1185 ret = 0;
1186 else
1187 ret = AVERROR(EIO);
1188
1189cleanup:
1190 ftp_close(h_src);
1191 return ret;
1192}
1193
1195 .name = "ftp",
1196 .url_open = ftp_open,
1197 .url_read = ftp_read,
1198 .url_write = ftp_write,
1199 .url_seek = ftp_seek,
1200 .url_close = ftp_close,
1201 .url_get_file_handle = ftp_get_file_handle,
1202 .url_shutdown = ftp_shutdown,
1203 .priv_data_size = sizeof(FTPContext),
1204 .priv_data_class = &ftp_context_class,
1205 .url_open_dir = ftp_open_dir,
1206 .url_read_dir = ftp_read_dir,
1207 .url_close_dir = ftp_close_dir,
1208 .url_delete = ftp_delete,
1209 .url_move = ftp_move,
1211 .default_whitelist = "tcp",
1212};
static double fact(double i)
Definition af_aiir.c:935
static AVDictionary * opts
#define E
Definition avdct.c:34
#define D
Definition avdct.c:35
Main libavformat public API header.
int ffurl_shutdown(URLContext *h, int flags)
Signal the URLContext that we are done reading or writing the stream.
Definition avio.c:915
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it.
Definition avio.c:461
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:656
void avio_free_directory_entry(AVIODirEntry **entry)
Free entry allocated by avio_read_dir().
Definition avio.c:859
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition avio.c:882
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition avio.h:468
#define AVIO_FLAG_WRITE
write-only
Definition avio.h:618
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition avio.h:619
@ AVIO_ENTRY_SYMBOLIC_LINK
Definition avio.h:73
@ AVIO_ENTRY_DIRECTORY
Definition avio.h:71
@ AVIO_ENTRY_FILE
Definition avio.h:75
static uint32_t BS_FUNC read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
AVBPrint public header.
#define AV_BPRINT_SIZE_AUTOMATIC
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
double value
Definition eval.c:102
static av_cold void cleanup(FlashSV2Context *s)
static int ftp_connect(URLContext *h, const char *url)
Definition ftp.c:696
static const AVClass ftp_context_class
Definition ftp.c:94
static int ftp_shutdown(URLContext *h, int flags)
Definition ftp.c:947
static int ftp_read_dir(URLContext *h, AVIODirEntry **next)
Definition ftp.c:1055
static void ftp_close_data_connection(FTPContext *s)
Definition ftp.c:244
static int ftp_store(FTPContext *s)
Definition ftp.c:456
static int ftp_file_size(FTPContext *s)
Definition ftp.c:414
static int ftp_set_dir(FTPContext *s)
Definition ftp.c:498
static int ftp_close(URLContext *h)
Definition ftp.c:919
static int ftp_connect_data_connection(URLContext *h)
Definition ftp.c:624
static int ftp_getc(FTPContext *s)
Definition ftp.c:113
static int ftp_get_file_handle(URLContext *h)
Definition ftp.c:935
static int ftp_connect_control_connection(URLContext *h)
Definition ftp.c:575
static int ftp_passive_mode_epsv(FTPContext *s)
Definition ftp.c:288
static int ftp_passive_mode(FTPContext *s)
Definition ftp.c:330
static int ftp_auth(FTPContext *s)
Definition ftp.c:256
static int ftp_read(URLContext *h, unsigned char *buf, int size)
Definition ftp.c:835
static int ftp_current_dir(FTPContext *s)
Definition ftp.c:376
static int ftp_delete(URLContext *h)
Definition ftp.c:1111
static int ftp_status(FTPContext *s, char **line, const int response_codes[])
Definition ftp.c:158
static int ftp_list(FTPContext *s)
Definition ftp.c:535
FTPListingMethod
Definition ftp.c:48
@ NLST
Definition ftp.c:50
@ UNKNOWN_METHOD
Definition ftp.c:49
@ MLSD
Definition ftp.c:51
static int ftp_list_nlst(FTPContext *s)
Definition ftp.c:524
static int ftp_abort(URLContext *h)
Definition ftp.c:658
static int ftp_type(FTPContext *s)
Definition ftp.c:475
static int ftp_open(URLContext *h, const char *url, int flags)
Definition ftp.c:767
static int ftp_get_line(FTPContext *s, char *line, int line_size)
Definition ftp.c:130
static int ftp_write(URLContext *h, const unsigned char *buf, int size)
Definition ftp.c:890
static int is_bad_string(const unsigned char *s)
Definition ftp.c:103
static int ftp_parse_entry_nlst(char *line, AVIODirEntry *next)
Definition ftp.c:994
#define CONTROL_BUFFER_SIZE
Definition ftp.c:35
static int ftp_restart(FTPContext *s, int64_t pos)
Definition ftp.c:486
#define DIR_BUFFER_SIZE
Definition ftp.c:36
static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next)
Definition ftp.c:1000
static int ftp_list_mlsd(FTPContext *s)
Definition ftp.c:513
static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
Definition ftp.c:793
static int64_t ftp_parse_date(const char *date)
Definition ftp.c:986
static int ftp_close_dir(URLContext *h)
Definition ftp.c:1102
#define OFFSET(x)
Definition ftp.c:82
static int ftp_move(URLContext *h_src, URLContext *h_dst)
Definition ftp.c:1149
static int ftp_parse_entry(URLContext *h, char *line, AVIODirEntry *next)
Definition ftp.c:1040
static int ftp_features(FTPContext *s)
Definition ftp.c:554
static void ftp_close_both_connections(FTPContext *s)
Definition ftp.c:250
static int ftp_retrieve(FTPContext *s)
Definition ftp.c:437
FTPState
Definition ftp.c:38
@ UPLOADING
Definition ftp.c:42
@ READY
Definition ftp.c:40
@ UNKNOWN
Definition ftp.c:39
@ LISTING_DIR
Definition ftp.c:43
@ ENDOFFILE
Definition ftp.c:45
@ DISCONNECTED
Definition ftp.c:44
@ DOWNLOADING
Definition ftp.c:41
static int ftp_has_feature(FTPContext *s, const char *feature_name)
Definition ftp.c:546
static int ftp_open_dir(URLContext *h)
Definition ftp.c:959
const URLProtocol ff_ftp_protocol
Definition ftp.c:1194
static int ftp_send_command(FTPContext *s, const char *command, const int response_codes[], char **response)
Definition ftp.c:219
#define fail
Definition test.h:479
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
Definition utils.c:361
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:233
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set() that converts the value to a string and stores it.
Definition dict.c:177
#define AVERROR_EOF
End of file.
Definition error.h:57
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
static void * av_x_if_null(const void *p, const void *x)
Return x default pointer in case p is NULL.
Definition avutil.h:311
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle.
Definition avstring.c:58
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition avstring.c:179
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition avstring.c:208
char * av_append_path_component(const char *path, const char *component)
Append path component to the existing path.
Definition avstring.c:292
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define MAX_URL_SIZE
Definition internal.h:30
common internal API header
#define FFMAX(a, b)
Definition macros.h:47
Memory handling functions.
#define av_strdup(s)
Definition ops_static.c:55
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
char * av_small_strptime(const char *p, const char *fmt, struct tm *dt)
Simplified version of strptime.
Definition parseutils.c:494
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition parseutils.c:573
misc parsing utilities
#define snprintf
Definition snprintf.h:34
unsigned int pos
Definition spdifenc.c:431
Describe the class of an AVClass context structure.
Definition log.h:76
Describes single entry of the directory.
Definition avio.h:87
int64_t user_id
User ID of owner, -1 if unknown.
Definition avio.h:99
int type
Type of the entry.
Definition avio.h:89
int64_t size
File size in bytes, -1 if unknown.
Definition avio.h:92
int64_t group_id
Group ID of owner, -1 if unknown.
Definition avio.h:100
char * name
Filename.
Definition avio.h:88
int64_t modification_timestamp
Time of last modification in microseconds since unix epoch, -1 if unknown.
Definition avio.h:93
int64_t filemode
Unix file mode, -1 if unknown.
Definition avio.h:101
AVOption.
Definition opt.h:428
uint8_t control_buffer[CONTROL_BUFFER_SIZE]
Control connection buffer.
Definition ftp.c:58
uint8_t * control_buf_ptr
Definition ftp.c:59
int write_seekable
Control seekability, 0 = disable, 1 = enable.
Definition ftp.c:70
int utf8
Definition ftp.c:77
const char * option_password
Password to be used if none given in the URL.
Definition ftp.c:79
char * features
List of server's features represented as raw response.
Definition ftp.c:73
int64_t filesize
Size of file on server, -1 on error.
Definition ftp.c:66
FTPState state
State of data connection.
Definition ftp.c:71
uint8_t * control_buf_end
Definition ftp.c:59
size_t dir_buffer_size
Definition ftp.c:75
char * password
Server user's password.
Definition ftp.c:64
URLContext * conn_control
Control connection.
Definition ftp.c:56
size_t dir_buffer_offset
Definition ftp.c:76
char * user
Server user.
Definition ftp.c:63
int rw_timeout
Network timeout.
Definition ftp.c:68
char * dir_buffer
Definition ftp.c:74
int server_control_port
Control connection port, default is 21.
Definition ftp.c:61
FTPListingMethod listing_method
Called listing method.
Definition ftp.c:72
int64_t position
Current position, calculated.
Definition ftp.c:67
int server_data_port
Data connection port opened by server, -1 on error.
Definition ftp.c:60
const char * option_user
User to be used if none given in the URL.
Definition ftp.c:78
char * hostname
Server address.
Definition ftp.c:62
URLContext * conn_data
Data connection, NULL when not connected.
Definition ftp.c:57
char * path
Path to resource on server.
Definition ftp.c:65
const char * anonymous_password
Password to be used for anonymous user.
Definition ftp.c:69
void * priv_data
Definition url.h:38
char * filename
specified URL
Definition url.h:39
#define av_free(p)
#define ff_dlog(a,...)
#define av_freep(p)
#define av_log(a,...)
int size
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition url.c:40
AVIODirEntry * ff_alloc_dir_entry(void)
Allocate directory entry with default values.
Definition url.c:327
unbuffered private I/O API
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition url.h:204
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition url.h:183
#define URL_PROTOCOL_FLAG_NETWORK
Definition url.h:33
char * ff_urldecode(const char *url, int decode_plus_sign)
Decodes an URL from its percent-encoded form back into normal representation.
Definition urldecode.c:80
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
int len