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