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, 0};
405 
406  snprintf(command, sizeof(command), "RETR %s\r\n", s->path);
407  if (ftp_send_command(s, command, retr_codes, NULL) != 150)
408  return AVERROR(EIO);
409 
410  s->state = DOWNLOADING;
411 
412  return 0;
413 }
414 
415 static int ftp_store(FTPContext *s)
416 {
418  static const int stor_codes[] = {150, 0};
419 
420  snprintf(command, sizeof(command), "STOR %s\r\n", s->path);
421  if (ftp_send_command(s, command, stor_codes, NULL) != 150)
422  return AVERROR(EIO);
423 
424  s->state = UPLOADING;
425 
426  return 0;
427 }
428 
429 static int ftp_type(FTPContext *s)
430 {
431  static const char *command = "TYPE I\r\n";
432  static const int type_codes[] = {200, 0};
433 
434  if (ftp_send_command(s, command, type_codes, NULL) != 200)
435  return AVERROR(EIO);
436 
437  return 0;
438 }
439 
440 static int ftp_restart(FTPContext *s, int64_t pos)
441 {
443  static const int rest_codes[] = {350, 0};
444 
445  snprintf(command, sizeof(command), "REST %"PRId64"\r\n", pos);
446  if (ftp_send_command(s, command, rest_codes, NULL) != 350)
447  return AVERROR(EIO);
448 
449  return 0;
450 }
451 
453 {
454  static const int cwd_codes[] = {250, 550, 0}; /* 550 is incorrect code */
455  char command[MAX_URL_SIZE];
456 
457  snprintf(command, sizeof(command), "CWD %s\r\n", s->path);
458  if (ftp_send_command(s, command, cwd_codes, NULL) != 250)
459  return AVERROR(EIO);
460  return 0;
461 }
462 
464 {
465  static const char *command = "MLSD\r\n";
466  static const int mlsd_codes[] = {150, 500, 0}; /* 500 is incorrect code */
467 
468  if (ftp_send_command(s, command, mlsd_codes, NULL) != 150)
469  return AVERROR(ENOSYS);
470  s->listing_method = MLSD;
471  return 0;
472 }
473 
475 {
476  static const char *command = "NLST\r\n";
477  static const int nlst_codes[] = {226, 425, 426, 451, 450, 550, 0};
478 
479  if (ftp_send_command(s, command, nlst_codes, NULL) != 226)
480  return AVERROR(ENOSYS);
481  s->listing_method = NLST;
482  return 0;
483 }
484 
485 static int ftp_has_feature(FTPContext *s, const char *feature_name);
486 
487 static int ftp_list(FTPContext *s)
488 {
489  int ret;
490  s->state = LISTING_DIR;
491 
492  if ((ret = ftp_list_mlsd(s)) < 0)
493  ret = ftp_list_nlst(s);
494 
495  return ret;
496 }
497 
498 static int ftp_has_feature(FTPContext *s, const char *feature_name)
499 {
500  if (!s->features)
501  return 0;
502 
503  return av_stristr(s->features, feature_name) != NULL;
504 }
505 
507 {
508  static const char *feat_command = "FEAT\r\n";
509  static const char *enable_utf8_command = "OPTS UTF8 ON\r\n";
510  static const int feat_codes[] = {211, 0};
511  static const int opts_codes[] = {200, 451, 0};
512 
513  av_freep(&s->features);
514  if (ftp_send_command(s, feat_command, feat_codes, &s->features) != 211) {
515  av_freep(&s->features);
516  }
517 
518  if (ftp_has_feature(s, "UTF8")) {
519  if (ftp_send_command(s, enable_utf8_command, opts_codes, NULL) == 200)
520  s->utf8 = 1;
521  }
522 
523  return 0;
524 }
525 
527 {
528  char buf[CONTROL_BUFFER_SIZE], *response = NULL;
529  int err;
531  FTPContext *s = h->priv_data;
532  static const int connect_codes[] = {220, 0};
533 
534  if (!s->conn_control) {
535  ff_url_join(buf, sizeof(buf), "tcp", NULL,
537  if (s->rw_timeout != -1) {
538  av_dict_set_int(&opts, "timeout", s->rw_timeout, 0);
539  } /* if option is not given, don't pass it and let tcp use its own default */
541  &h->interrupt_callback, &opts,
542  h->protocol_whitelist);
543  av_dict_free(&opts);
544  if (err < 0) {
545  av_log(h, AV_LOG_ERROR, "Cannot open control connection\n");
546  return err;
547  }
548 
549  /* check if server is ready */
550  if (ftp_status(s, ((h->flags & AVIO_FLAG_WRITE) ? &response : NULL), connect_codes) != 220) {
551  av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n");
552  return AVERROR(EACCES);
553  }
554 
555  if ((h->flags & AVIO_FLAG_WRITE) && av_stristr(response, "pure-ftpd")) {
556  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.");
557  }
558  av_free(response);
559 
560  if ((err = ftp_auth(s)) < 0) {
561  av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
562  return err;
563  }
564 
565  if ((err = ftp_type(s)) < 0) {
566  av_log(h, AV_LOG_ERROR, "Set content type failed\n");
567  return err;
568  }
569 
570  ftp_features(s);
571  }
572  return 0;
573 }
574 
576 {
577  int err;
578  char buf[CONTROL_BUFFER_SIZE];
580  FTPContext *s = h->priv_data;
581 
582  if (!s->conn_data) {
583  /* Enter passive mode */
584  if (ftp_passive_mode_epsv(s) < 0) {
585  /* Use PASV as fallback */
586  if ((err = ftp_passive_mode(s)) < 0)
587  return err;
588  }
589  /* Open data connection */
590  ff_url_join(buf, sizeof(buf), "tcp", NULL, s->hostname, s->server_data_port, NULL);
591  if (s->rw_timeout != -1) {
592  av_dict_set_int(&opts, "timeout", s->rw_timeout, 0);
593  } /* if option is not given, don't pass it and let tcp use its own default */
594  err = ffurl_open_whitelist(&s->conn_data, buf, h->flags,
595  &h->interrupt_callback, &opts,
596  h->protocol_whitelist);
597  av_dict_free(&opts);
598  if (err < 0)
599  return err;
600 
601  if (s->position)
602  if ((err = ftp_restart(s, s->position)) < 0)
603  return err;
604  }
605  s->state = READY;
606  return 0;
607 }
608 
609 static int ftp_abort(URLContext *h)
610 {
611  static const char *command = "ABOR\r\n";
612  int err;
613  static const int abor_codes[] = {225, 226, 0};
614  FTPContext *s = h->priv_data;
615 
616  /* According to RCF 959:
617  "ABOR command tells the server to abort the previous FTP
618  service command and any associated transfer of data."
619 
620  There are FTP server implementations that don't response
621  to any commands during data transfer in passive mode (including ABOR).
622 
623  This implementation closes data connection by force.
624  */
625 
626  if (ftp_send_command(s, command, NULL, NULL) < 0) {
628  if ((err = ftp_connect_control_connection(h)) < 0) {
629  av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
630  return err;
631  }
632  } else {
634  if (ftp_status(s, NULL, abor_codes) < 225) {
635  /* wu-ftpd also closes control connection after data connection closing */
637  if ((err = ftp_connect_control_connection(h)) < 0) {
638  av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
639  return err;
640  }
641  }
642  }
643 
644  return 0;
645 }
646 
647 static int ftp_connect(URLContext *h, const char *url)
648 {
649  char proto[10], path[MAX_URL_SIZE], credencials[MAX_URL_SIZE], hostname[MAX_URL_SIZE];
650  const char *tok_user = NULL, *tok_pass = NULL;
651  char *end = NULL, *newpath = NULL;
652  int err;
653  FTPContext *s = h->priv_data;
654 
655  s->state = DISCONNECTED;
657  s->filesize = -1;
658  s->position = 0;
659  s->features = NULL;
660 
661  av_url_split(proto, sizeof(proto),
662  credencials, sizeof(credencials),
663  hostname, sizeof(hostname),
665  path, sizeof(path),
666  url);
667 
668  tok_user = av_strtok(credencials, ":", &end);
669  tok_pass = av_strtok(end, ":", &end);
670  if (!tok_user) {
671  tok_user = "anonymous";
672  tok_pass = av_x_if_null(s->anonymous_password, "nopassword");
673  }
674  s->user = av_strdup(tok_user);
675  s->password = av_strdup(tok_pass);
676  s->hostname = av_strdup(hostname);
677  if (!s->hostname || !s->user || (tok_pass && !s->password)) {
678  return AVERROR(ENOMEM);
679  }
680 
681  if (s->server_control_port < 0 || s->server_control_port > 65535)
682  s->server_control_port = 21;
683 
684  if ((err = ftp_connect_control_connection(h)) < 0)
685  return err;
686 
687  if ((err = ftp_current_dir(s)) < 0)
688  return err;
689 
690  newpath = av_append_path_component(s->path, path);
691  if (!newpath)
692  return AVERROR(ENOMEM);
693  av_free(s->path);
694  s->path = newpath;
695 
696  return 0;
697 }
698 
699 static int ftp_open(URLContext *h, const char *url, int flags)
700 {
701  FTPContext *s = h->priv_data;
702  int err;
703 
704  ff_dlog(h, "ftp protocol open\n");
705 
706  if ((err = ftp_connect(h, url)) < 0)
707  goto fail;
708 
709  if (ftp_restart(s, 0) < 0) {
710  h->is_streamed = 1;
711  } else {
712  if (ftp_file_size(s) < 0 && flags & AVIO_FLAG_READ)
713  h->is_streamed = 1;
714  if (s->write_seekable != 1 && flags & AVIO_FLAG_WRITE)
715  h->is_streamed = 1;
716  }
717 
718  return 0;
719 
720  fail:
721  av_log(h, AV_LOG_ERROR, "FTP open failed\n");
722  ftp_close(h);
723  return err;
724 }
725 
726 static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
727 {
728  FTPContext *s = h->priv_data;
729  int err;
730  int64_t new_pos, fake_pos;
731 
732  ff_dlog(h, "ftp protocol seek %"PRId64" %d\n", pos, whence);
733 
734  switch(whence) {
735  case AVSEEK_SIZE:
736  return s->filesize;
737  case SEEK_SET:
738  new_pos = pos;
739  break;
740  case SEEK_CUR:
741  new_pos = s->position + pos;
742  break;
743  case SEEK_END:
744  if (s->filesize < 0)
745  return AVERROR(EIO);
746  new_pos = s->filesize + pos;
747  break;
748  default:
749  return AVERROR(EINVAL);
750  }
751 
752  if (h->is_streamed)
753  return AVERROR(EIO);
754 
755  if (new_pos < 0) {
756  av_log(h, AV_LOG_ERROR, "Seeking to nagative position.\n");
757  return AVERROR(EINVAL);
758  }
759 
760  fake_pos = s->filesize != -1 ? FFMIN(new_pos, s->filesize) : new_pos;
761  if (fake_pos != s->position) {
762  if ((err = ftp_abort(h)) < 0)
763  return err;
764  s->position = fake_pos;
765  }
766  return new_pos;
767 }
768 
769 static int ftp_read(URLContext *h, unsigned char *buf, int size)
770 {
771  FTPContext *s = h->priv_data;
772  int read, err, retry_done = 0;
773 
774  ff_dlog(h, "ftp protocol read %d bytes\n", size);
775  retry:
776  if (s->state == DISCONNECTED) {
777  /* optimization */
778  if (s->position >= s->filesize)
779  return 0;
780  if ((err = ftp_connect_data_connection(h)) < 0)
781  return err;
782  }
783  if (s->state == READY) {
784  if (s->position >= s->filesize)
785  return 0;
786  if ((err = ftp_retrieve(s)) < 0)
787  return err;
788  }
789  if (s->conn_data && s->state == DOWNLOADING) {
790  read = ffurl_read(s->conn_data, buf, size);
791  if (read >= 0) {
792  s->position += read;
793  if (s->position >= s->filesize) {
794  /* server will terminate, but keep current position to avoid madness */
795  /* save position to restart from it */
796  int64_t pos = s->position;
797  if (ftp_abort(h) < 0) {
798  s->position = pos;
799  return AVERROR(EIO);
800  }
801  s->position = pos;
802  }
803  }
804  if (read <= 0 && s->position < s->filesize && !h->is_streamed) {
805  /* Server closed connection. Probably due to inactivity */
806  int64_t pos = s->position;
807  av_log(h, AV_LOG_INFO, "Reconnect to FTP server.\n");
808  if ((err = ftp_abort(h)) < 0)
809  return err;
810  if ((err = ftp_seek(h, pos, SEEK_SET)) < 0) {
811  av_log(h, AV_LOG_ERROR, "Position cannot be restored.\n");
812  return err;
813  }
814  if (!retry_done) {
815  retry_done = 1;
816  goto retry;
817  }
818  }
819  return read;
820  }
821 
822  av_log(h, AV_LOG_DEBUG, "FTP read failed\n");
823  return AVERROR(EIO);
824 }
825 
826 static int ftp_write(URLContext *h, const unsigned char *buf, int size)
827 {
828  int err;
829  FTPContext *s = h->priv_data;
830  int written;
831 
832  ff_dlog(h, "ftp protocol write %d bytes\n", size);
833 
834  if (s->state == DISCONNECTED) {
835  if ((err = ftp_connect_data_connection(h)) < 0)
836  return err;
837  }
838  if (s->state == READY) {
839  if ((err = ftp_store(s)) < 0)
840  return err;
841  }
842  if (s->conn_data && s->state == UPLOADING) {
843  written = ffurl_write(s->conn_data, buf, size);
844  if (written > 0) {
845  s->position += written;
846  s->filesize = FFMAX(s->filesize, s->position);
847  }
848  return written;
849  }
850 
851  av_log(h, AV_LOG_ERROR, "FTP write failed\n");
852  return AVERROR(EIO);
853 }
854 
855 static int ftp_close(URLContext *h)
856 {
857  FTPContext *s = h->priv_data;
858 
859  ff_dlog(h, "ftp protocol close\n");
860 
862  av_freep(&s->user);
863  av_freep(&s->password);
864  av_freep(&s->hostname);
865  av_freep(&s->path);
866  av_freep(&s->features);
867 
868  return 0;
869 }
870 
872 {
873  FTPContext *s = h->priv_data;
874 
875  ff_dlog(h, "ftp protocol get_file_handle\n");
876 
877  if (s->conn_data)
878  return ffurl_get_file_handle(s->conn_data);
879 
880  return AVERROR(EIO);
881 }
882 
883 static int ftp_shutdown(URLContext *h, int flags)
884 {
885  FTPContext *s = h->priv_data;
886 
887  ff_dlog(h, "ftp protocol shutdown\n");
888 
889  if (s->conn_data)
890  return ffurl_shutdown(s->conn_data, flags);
891 
892  return AVERROR(EIO);
893 }
894 
896 {
897  FTPContext *s = h->priv_data;
898  int ret;
899 
900  if ((ret = ftp_connect(h, h->filename)) < 0)
901  goto fail;
902  if ((ret = ftp_set_dir(s)) < 0)
903  goto fail;
904  if ((ret = ftp_connect_data_connection(h)) < 0)
905  goto fail;
906  if ((ret = ftp_list(s)) < 0)
907  goto fail;
909  if (!s->dir_buffer) {
910  ret = AVERROR(ENOMEM);
911  goto fail;
912  }
913  s->dir_buffer[0] = 0;
914  if (s->conn_data && s->state == LISTING_DIR)
915  return 0;
916  fail:
918  ffurl_closep(&s->conn_data);
919  return ret;
920 }
921 
922 static int64_t ftp_parse_date(const char *date)
923 {
924  struct tm tv;
925  memset(&tv, 0, sizeof(struct tm));
926  av_small_strptime(date, "%Y%m%d%H%M%S", &tv);
927  return INT64_C(1000000) * av_timegm(&tv);
928 }
929 
930 static int ftp_parse_entry_nlst(char *line, AVIODirEntry *next)
931 {
932  next->name = av_strdup(line);
933  return 0;
934 }
935 
936 static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next)
937 {
938  char *fact, *value;
939  ff_dlog(NULL, "%s\n", mlsd);
940  while(fact = av_strtok(mlsd, ";", &mlsd)) {
941  if (fact[0] == ' ') {
942  next->name = av_strdup(&fact[1]);
943  continue;
944  }
945  fact = av_strtok(fact, "=", &value);
946  if (!av_strcasecmp(fact, "type")) {
947  if (!av_strcasecmp(value, "cdir") || !av_strcasecmp(value, "pdir"))
948  return 1;
949  if (!av_strcasecmp(value, "dir"))
950  next->type = AVIO_ENTRY_DIRECTORY;
951  else if (!av_strcasecmp(value, "file"))
952  next->type = AVIO_ENTRY_FILE;
953  else if (!av_strcasecmp(value, "OS.unix=slink:"))
955  } else if (!av_strcasecmp(fact, "modify")) {
956  next->modification_timestamp = ftp_parse_date(value);
957  } else if (!av_strcasecmp(fact, "UNIX.mode")) {
958  next->filemode = strtoumax(value, NULL, 8);
959  } else if (!av_strcasecmp(fact, "UNIX.uid") || !av_strcasecmp(fact, "UNIX.owner"))
960  next->user_id = strtoumax(value, NULL, 10);
961  else if (!av_strcasecmp(fact, "UNIX.gid") || !av_strcasecmp(fact, "UNIX.group"))
962  next->group_id = strtoumax(value, NULL, 10);
963  else if (!av_strcasecmp(fact, "size") || !av_strcasecmp(fact, "sizd"))
964  next->size = strtoll(value, NULL, 10);
965  }
966  return 0;
967 }
968 
969 /**
970  * @return 0 on success, negative on error, positive on entry to discard.
971  */
972 static int ftp_parse_entry(URLContext *h, char *line, AVIODirEntry *next)
973 {
974  FTPContext *s = h->priv_data;
975 
976  switch (s->listing_method) {
977  case MLSD:
978  return ftp_parse_entry_mlsd(line, next);
979  case NLST:
980  return ftp_parse_entry_nlst(line, next);
981  case UNKNOWN_METHOD:
982  default:
983  return -1;
984  }
985 }
986 
987 static int ftp_read_dir(URLContext *h, AVIODirEntry **next)
988 {
989  FTPContext *s = h->priv_data;
990  char *start, *found;
991  int ret, retried;
992 
993  do {
994  retried = 0;
995  start = s->dir_buffer + s->dir_buffer_offset;
996  while (!(found = strstr(start, "\n"))) {
997  if (retried)
998  return AVERROR(EIO);
1000  s->dir_buffer_offset = 0;
1001  if (s->dir_buffer_size)
1002  memmove(s->dir_buffer, start, s->dir_buffer_size);
1004  if (ret < 0)
1005  return ret;
1006  if (!ret) {
1007  *next = NULL;
1008  return 0;
1009  }
1010  s->dir_buffer_size += ret;
1011  s->dir_buffer[s->dir_buffer_size] = 0;
1012  start = s->dir_buffer;
1013  retried = 1;
1014  }
1015  s->dir_buffer_offset += (found + 1 - start);
1016  found[0] = 0;
1017  if (found > start && found[-1] == '\r')
1018  found[-1] = 0;
1019 
1020  *next = ff_alloc_dir_entry();
1021  if (!*next)
1022  return AVERROR(ENOMEM);
1023  (*next)->utf8 = s->utf8;
1024  ret = ftp_parse_entry(h, start, *next);
1025  if (ret) {
1027  if (ret < 0)
1028  return ret;
1029  }
1030  } while (ret > 0);
1031  return 0;
1032 }
1033 
1035 {
1036  FTPContext *s = h->priv_data;
1037  av_freep(&s->dir_buffer);
1039  ffurl_closep(&s->conn_data);
1040  return 0;
1041 }
1042 
1044 {
1045  FTPContext *s = h->priv_data;
1046  char command[MAX_URL_SIZE];
1047  static const int del_codes[] = {250, 421, 450, 500, 501, 502, 530, 550, 0};
1048  static const int rmd_codes[] = {250, 421, 500, 501, 502, 530, 550, 0};
1049  int ret;
1050 
1051  if ((ret = ftp_connect(h, h->filename)) < 0)
1052  goto cleanup;
1053 
1054  snprintf(command, sizeof(command), "DELE %s\r\n", s->path);
1055  if (ftp_send_command(s, command, del_codes, NULL) == 250) {
1056  ret = 0;
1057  goto cleanup;
1058  }
1059 
1060  snprintf(command, sizeof(command), "RMD %s\r\n", s->path);
1061  if (ftp_send_command(s, command, rmd_codes, NULL) == 250)
1062  ret = 0;
1063  else
1064  ret = AVERROR(EIO);
1065 
1066 cleanup:
1067  ftp_close(h);
1068  return ret;
1069 }
1070 
1071 static int ftp_move(URLContext *h_src, URLContext *h_dst)
1072 {
1073  FTPContext *s = h_src->priv_data;
1074  char command[MAX_URL_SIZE], path[MAX_URL_SIZE];
1075  static const int rnfr_codes[] = {350, 421, 450, 500, 501, 502, 503, 530, 0};
1076  static const int rnto_codes[] = {250, 421, 500, 501, 502, 503, 530, 532, 553, 0};
1077  int ret;
1078 
1079  if ((ret = ftp_connect(h_src, h_src->filename)) < 0)
1080  goto cleanup;
1081 
1082  snprintf(command, sizeof(command), "RNFR %s\r\n", s->path);
1083  if (ftp_send_command(s, command, rnfr_codes, NULL) != 350) {
1084  ret = AVERROR(EIO);
1085  goto cleanup;
1086  }
1087 
1088  av_url_split(0, 0, 0, 0, 0, 0, 0,
1089  path, sizeof(path),
1090  h_dst->filename);
1091  snprintf(command, sizeof(command), "RNTO %s\r\n", path);
1092  if (ftp_send_command(s, command, rnto_codes, NULL) == 250)
1093  ret = 0;
1094  else
1095  ret = AVERROR(EIO);
1096 
1097 cleanup:
1098  ftp_close(h_src);
1099  return ret;
1100 }
1101 
1103  .name = "ftp",
1104  .url_open = ftp_open,
1105  .url_read = ftp_read,
1106  .url_write = ftp_write,
1107  .url_seek = ftp_seek,
1108  .url_close = ftp_close,
1109  .url_get_file_handle = ftp_get_file_handle,
1110  .url_shutdown = ftp_shutdown,
1111  .priv_data_size = sizeof(FTPContext),
1112  .priv_data_class = &ftp_context_class,
1113  .url_open_dir = ftp_open_dir,
1114  .url_read_dir = ftp_read_dir,
1115  .url_close_dir = ftp_close_dir,
1116  .url_delete = ftp_delete,
1117  .url_move = ftp_move,
1119  .default_whitelist = "tcp",
1120 };
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition: parseutils.c:540
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:4029
#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
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:35
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:487
static int ftp_move(URLContext *h_src, URLContext *h_dst)
Definition: ftp.c:1071
#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:433
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:46
AVIOInterruptCB interrupt_callback
Definition: url.h:48
Describes single entry of the directory.
Definition: avio.h:78
#define AVIO_FLAG_READ
read-only
Definition: avio.h:537
static int ftp_connect(URLContext *h, const char *url)
Definition: ftp.c:647
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:538
static int ftp_open(URLContext *h, const char *url, int flags)
Definition: ftp.c:699
uint8_t * control_buf_end
Definition: ftp.c:53
size_t dir_buffer_size
Definition: ftp.c:69
int flags
Definition: url.h:44
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:660
Definition: ftp.c:34
Definition: ftp.c:37
#define MAX_URL_SIZE
Definition: internal.h:28
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:987
static int ftp_connect_data_connection(URLContext *h)
Definition: ftp.c:575
uint8_t
#define av_malloc(s)
static int ftp_set_dir(FTPContext *s)
Definition: ftp.c:452
static int ftp_shutdown(URLContext *h, int flags)
Definition: ftp.c:883
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:1043
static int ftp_connect_control_connection(URLContext *h)
Definition: ftp.c:526
#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:50
av_default_item_name
#define AVERROR(e)
Definition: error.h:43
static int ftp_abort(URLContext *h)
Definition: ftp.c:609
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:199
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:80
void avio_free_directory_entry(AVIODirEntry **entry)
Free entry allocated by avio_read_dir().
Definition: avio.c:615
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:930
static int ftp_read(URLContext *h, unsigned char *buf, int size)
Definition: ftp.c:769
static int ftp_close(URLContext *h)
Definition: ftp.c:855
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:440
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:498
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:638
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:456
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:726
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:336
#define AV_BPRINT_SIZE_AUTOMATIC
static int ftp_close_dir(URLContext *h)
Definition: ftp.c:1034
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:871
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:39
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition: avio.h:539
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:506
void * priv_data
Definition: url.h:42
static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next)
Definition: ftp.c:936
#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:826
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
URLProtocol ff_ftp_protocol
Definition: ftp.c:1102
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:143
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:43
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition: avio.h:416
char * hostname
Server address.
Definition: ftp.c:56
static int ftp_store(FTPContext *s)
Definition: ftp.c:415
static int ftp_type(FTPContext *s)
Definition: ftp.c:429
#define D
Definition: ftp.c:75
#define av_free(p)
static int ftp_open_dir(URLContext *h)
Definition: ftp.c:895
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
AVDictionary * opts
Definition: movenc-test.c:50
static int ftp_list_mlsd(FTPContext *s)
Definition: ftp.c:463
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:922
Definition: ftp.c:48
static int ftp_parse_entry(URLContext *h, char *line, AVIODirEntry *next)
Definition: ftp.c:972
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:419
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:127
static int ftp_list_nlst(FTPContext *s)
Definition: ftp.c:474