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_INT, {.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;
530  AVDictionary *opts = NULL;
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  av_dict_free(&opts);
543  if (err < 0) {
544  av_log(h, AV_LOG_ERROR, "Cannot open control connection\n");
545  return err;
546  }
547 
548  /* check if server is ready */
549  if (ftp_status(s, ((h->flags & AVIO_FLAG_WRITE) ? &response : NULL), connect_codes) != 220) {
550  av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n");
551  return AVERROR(EACCES);
552  }
553 
554  if ((h->flags & AVIO_FLAG_WRITE) && av_stristr(response, "pure-ftpd")) {
555  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.");
556  }
557  av_free(response);
558 
559  if ((err = ftp_auth(s)) < 0) {
560  av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
561  return err;
562  }
563 
564  if ((err = ftp_type(s)) < 0) {
565  av_log(h, AV_LOG_ERROR, "Set content type failed\n");
566  return err;
567  }
568 
569  ftp_features(s);
570  }
571  return 0;
572 }
573 
575 {
576  int err;
577  char buf[CONTROL_BUFFER_SIZE];
578  AVDictionary *opts = NULL;
579  FTPContext *s = h->priv_data;
580 
581  if (!s->conn_data) {
582  /* Enter passive mode */
583  if (ftp_passive_mode_epsv(s) < 0) {
584  /* Use PASV as fallback */
585  if ((err = ftp_passive_mode(s)) < 0)
586  return err;
587  }
588  /* Open data connection */
589  ff_url_join(buf, sizeof(buf), "tcp", NULL, s->hostname, s->server_data_port, NULL);
590  if (s->rw_timeout != -1) {
591  av_dict_set_int(&opts, "timeout", s->rw_timeout, 0);
592  } /* if option is not given, don't pass it and let tcp use its own default */
593  err = ffurl_open(&s->conn_data, buf, h->flags,
594  &h->interrupt_callback, &opts);
595  av_dict_free(&opts);
596  if (err < 0)
597  return err;
598 
599  if (s->position)
600  if ((err = ftp_restart(s, s->position)) < 0)
601  return err;
602  }
603  s->state = READY;
604  return 0;
605 }
606 
607 static int ftp_abort(URLContext *h)
608 {
609  static const char *command = "ABOR\r\n";
610  int err;
611  static const int abor_codes[] = {225, 226, 0};
612  FTPContext *s = h->priv_data;
613 
614  /* According to RCF 959:
615  "ABOR command tells the server to abort the previous FTP
616  service command and any associated transfer of data."
617 
618  There are FTP server implementations that don't response
619  to any commands during data transfer in passive mode (including ABOR).
620 
621  This implementation closes data connection by force.
622  */
623 
624  if (ftp_send_command(s, command, NULL, NULL) < 0) {
626  if ((err = ftp_connect_control_connection(h)) < 0) {
627  av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
628  return err;
629  }
630  } else {
632  if (ftp_status(s, NULL, abor_codes) < 225) {
633  /* wu-ftpd also closes control connection after data connection closing */
635  if ((err = ftp_connect_control_connection(h)) < 0) {
636  av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
637  return err;
638  }
639  }
640  }
641 
642  return 0;
643 }
644 
645 static int ftp_connect(URLContext *h, const char *url)
646 {
647  char proto[10], path[MAX_URL_SIZE], credencials[MAX_URL_SIZE], hostname[MAX_URL_SIZE];
648  const char *tok_user = NULL, *tok_pass = NULL;
649  char *end = NULL, *newpath = NULL;
650  int err;
651  FTPContext *s = h->priv_data;
652 
653  s->state = DISCONNECTED;
655  s->filesize = -1;
656  s->position = 0;
657  s->features = NULL;
658 
659  av_url_split(proto, sizeof(proto),
660  credencials, sizeof(credencials),
661  hostname, sizeof(hostname),
663  path, sizeof(path),
664  url);
665 
666  tok_user = av_strtok(credencials, ":", &end);
667  tok_pass = av_strtok(end, ":", &end);
668  if (!tok_user) {
669  tok_user = "anonymous";
670  tok_pass = av_x_if_null(s->anonymous_password, "nopassword");
671  }
672  s->user = av_strdup(tok_user);
673  s->password = av_strdup(tok_pass);
674  s->hostname = av_strdup(hostname);
675  if (!s->hostname || !s->user || (tok_pass && !s->password)) {
676  return AVERROR(ENOMEM);
677  }
678 
679  if (s->server_control_port < 0 || s->server_control_port > 65535)
680  s->server_control_port = 21;
681 
682  if ((err = ftp_connect_control_connection(h)) < 0)
683  return err;
684 
685  if ((err = ftp_current_dir(s)) < 0)
686  return err;
687 
688  newpath = av_append_path_component(s->path, path);
689  if (!newpath)
690  return AVERROR(ENOMEM);
691  av_free(s->path);
692  s->path = newpath;
693 
694  return 0;
695 }
696 
697 static int ftp_open(URLContext *h, const char *url, int flags)
698 {
699  FTPContext *s = h->priv_data;
700  int err;
701 
702  ff_dlog(h, "ftp protocol open\n");
703 
704  if ((err = ftp_connect(h, url)) < 0)
705  goto fail;
706 
707  if (ftp_restart(s, 0) < 0) {
708  h->is_streamed = 1;
709  } else {
710  if (ftp_file_size(s) < 0 && flags & AVIO_FLAG_READ)
711  h->is_streamed = 1;
712  if (s->write_seekable != 1 && flags & AVIO_FLAG_WRITE)
713  h->is_streamed = 1;
714  }
715 
716  return 0;
717 
718  fail:
719  av_log(h, AV_LOG_ERROR, "FTP open failed\n");
720  ftp_close(h);
721  return err;
722 }
723 
724 static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
725 {
726  FTPContext *s = h->priv_data;
727  int err;
728  int64_t new_pos, fake_pos;
729 
730  ff_dlog(h, "ftp protocol seek %"PRId64" %d\n", pos, whence);
731 
732  switch(whence) {
733  case AVSEEK_SIZE:
734  return s->filesize;
735  case SEEK_SET:
736  new_pos = pos;
737  break;
738  case SEEK_CUR:
739  new_pos = s->position + pos;
740  break;
741  case SEEK_END:
742  if (s->filesize < 0)
743  return AVERROR(EIO);
744  new_pos = s->filesize + pos;
745  break;
746  default:
747  return AVERROR(EINVAL);
748  }
749 
750  if (h->is_streamed)
751  return AVERROR(EIO);
752 
753  if (new_pos < 0) {
754  av_log(h, AV_LOG_ERROR, "Seeking to nagative position.\n");
755  return AVERROR(EINVAL);
756  }
757 
758  fake_pos = s->filesize != -1 ? FFMIN(new_pos, s->filesize) : new_pos;
759  if (fake_pos != s->position) {
760  if ((err = ftp_abort(h)) < 0)
761  return err;
762  s->position = fake_pos;
763  }
764  return new_pos;
765 }
766 
767 static int ftp_read(URLContext *h, unsigned char *buf, int size)
768 {
769  FTPContext *s = h->priv_data;
770  int read, err, retry_done = 0;
771 
772  ff_dlog(h, "ftp protocol read %d bytes\n", size);
773  retry:
774  if (s->state == DISCONNECTED) {
775  /* optimization */
776  if (s->position >= s->filesize)
777  return 0;
778  if ((err = ftp_connect_data_connection(h)) < 0)
779  return err;
780  }
781  if (s->state == READY) {
782  if (s->position >= s->filesize)
783  return 0;
784  if ((err = ftp_retrieve(s)) < 0)
785  return err;
786  }
787  if (s->conn_data && s->state == DOWNLOADING) {
788  read = ffurl_read(s->conn_data, buf, size);
789  if (read >= 0) {
790  s->position += read;
791  if (s->position >= s->filesize) {
792  /* server will terminate, but keep current position to avoid madness */
793  /* save position to restart from it */
794  int64_t pos = s->position;
795  if (ftp_abort(h) < 0) {
796  s->position = pos;
797  return AVERROR(EIO);
798  }
799  s->position = pos;
800  }
801  }
802  if (read <= 0 && s->position < s->filesize && !h->is_streamed) {
803  /* Server closed connection. Probably due to inactivity */
804  int64_t pos = s->position;
805  av_log(h, AV_LOG_INFO, "Reconnect to FTP server.\n");
806  if ((err = ftp_abort(h)) < 0)
807  return err;
808  if ((err = ftp_seek(h, pos, SEEK_SET)) < 0) {
809  av_log(h, AV_LOG_ERROR, "Position cannot be restored.\n");
810  return err;
811  }
812  if (!retry_done) {
813  retry_done = 1;
814  goto retry;
815  }
816  }
817  return read;
818  }
819 
820  av_log(h, AV_LOG_DEBUG, "FTP read failed\n");
821  return AVERROR(EIO);
822 }
823 
824 static int ftp_write(URLContext *h, const unsigned char *buf, int size)
825 {
826  int err;
827  FTPContext *s = h->priv_data;
828  int written;
829 
830  ff_dlog(h, "ftp protocol write %d bytes\n", size);
831 
832  if (s->state == DISCONNECTED) {
833  if ((err = ftp_connect_data_connection(h)) < 0)
834  return err;
835  }
836  if (s->state == READY) {
837  if ((err = ftp_store(s)) < 0)
838  return err;
839  }
840  if (s->conn_data && s->state == UPLOADING) {
841  written = ffurl_write(s->conn_data, buf, size);
842  if (written > 0) {
843  s->position += written;
844  s->filesize = FFMAX(s->filesize, s->position);
845  }
846  return written;
847  }
848 
849  av_log(h, AV_LOG_ERROR, "FTP write failed\n");
850  return AVERROR(EIO);
851 }
852 
853 static int ftp_close(URLContext *h)
854 {
855  FTPContext *s = h->priv_data;
856 
857  ff_dlog(h, "ftp protocol close\n");
858 
860  av_freep(&s->user);
861  av_freep(&s->password);
862  av_freep(&s->hostname);
863  av_freep(&s->path);
864  av_freep(&s->features);
865 
866  return 0;
867 }
868 
870 {
871  FTPContext *s = h->priv_data;
872 
873  ff_dlog(h, "ftp protocol get_file_handle\n");
874 
875  if (s->conn_data)
876  return ffurl_get_file_handle(s->conn_data);
877 
878  return AVERROR(EIO);
879 }
880 
881 static int ftp_shutdown(URLContext *h, int flags)
882 {
883  FTPContext *s = h->priv_data;
884 
885  ff_dlog(h, "ftp protocol shutdown\n");
886 
887  if (s->conn_data)
888  return ffurl_shutdown(s->conn_data, flags);
889 
890  return AVERROR(EIO);
891 }
892 
894 {
895  FTPContext *s = h->priv_data;
896  int ret;
897 
898  if ((ret = ftp_connect(h, h->filename)) < 0)
899  goto fail;
900  if ((ret = ftp_set_dir(s)) < 0)
901  goto fail;
902  if ((ret = ftp_connect_data_connection(h)) < 0)
903  goto fail;
904  if ((ret = ftp_list(s)) < 0)
905  goto fail;
907  if (!s->dir_buffer) {
908  ret = AVERROR(ENOMEM);
909  goto fail;
910  }
911  s->dir_buffer[0] = 0;
912  if (s->conn_data && s->state == LISTING_DIR)
913  return 0;
914  fail:
916  ffurl_closep(&s->conn_data);
917  return ret;
918 }
919 
920 static int64_t ftp_parse_date(const char *date)
921 {
922  struct tm tv;
923  memset(&tv, 0, sizeof(struct tm));
924  av_small_strptime(date, "%Y%m%d%H%M%S", &tv);
925  return INT64_C(1000000) * av_timegm(&tv);
926 }
927 
928 static int ftp_parse_entry_nlst(char *line, AVIODirEntry *next)
929 {
930  next->name = av_strdup(line);
931  return 0;
932 }
933 
934 static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next)
935 {
936  char *fact, *value;
937  ff_dlog(NULL, "%s\n", mlsd);
938  while(fact = av_strtok(mlsd, ";", &mlsd)) {
939  if (fact[0] == ' ') {
940  next->name = av_strdup(&fact[1]);
941  continue;
942  }
943  fact = av_strtok(fact, "=", &value);
944  if (!av_strcasecmp(fact, "type")) {
945  if (!av_strcasecmp(value, "cdir") || !av_strcasecmp(value, "pdir"))
946  return 1;
947  if (!av_strcasecmp(value, "dir"))
948  next->type = AVIO_ENTRY_DIRECTORY;
949  else if (!av_strcasecmp(value, "file"))
950  next->type = AVIO_ENTRY_FILE;
951  else if (!av_strcasecmp(value, "OS.unix=slink:"))
953  } else if (!av_strcasecmp(fact, "modify")) {
954  next->modification_timestamp = ftp_parse_date(value);
955  } else if (!av_strcasecmp(fact, "UNIX.mode")) {
956  next->filemode = strtoumax(value, NULL, 8);
957  } else if (!av_strcasecmp(fact, "UNIX.uid") || !av_strcasecmp(fact, "UNIX.owner"))
958  next->user_id = strtoumax(value, NULL, 10);
959  else if (!av_strcasecmp(fact, "UNIX.gid") || !av_strcasecmp(fact, "UNIX.group"))
960  next->group_id = strtoumax(value, NULL, 10);
961  else if (!av_strcasecmp(fact, "size") || !av_strcasecmp(fact, "sizd"))
962  next->size = strtoll(value, NULL, 10);
963  }
964  return 0;
965 }
966 
967 /**
968  * @return 0 on success, negative on error, positive on entry to discard.
969  */
970 static int ftp_parse_entry(URLContext *h, char *line, AVIODirEntry *next)
971 {
972  FTPContext *s = h->priv_data;
973 
974  switch (s->listing_method) {
975  case MLSD:
976  return ftp_parse_entry_mlsd(line, next);
977  case NLST:
978  return ftp_parse_entry_nlst(line, next);
979  case UNKNOWN_METHOD:
980  default:
981  return -1;
982  }
983 }
984 
985 static int ftp_read_dir(URLContext *h, AVIODirEntry **next)
986 {
987  FTPContext *s = h->priv_data;
988  char *start, *found;
989  int ret, retried;
990 
991  do {
992  retried = 0;
993  start = s->dir_buffer + s->dir_buffer_offset;
994  while (!(found = strstr(start, "\n"))) {
995  if (retried)
996  return AVERROR(EIO);
998  s->dir_buffer_offset = 0;
999  if (s->dir_buffer_size)
1000  memmove(s->dir_buffer, start, s->dir_buffer_size);
1002  if (ret < 0)
1003  return ret;
1004  if (!ret) {
1005  *next = NULL;
1006  return 0;
1007  }
1008  s->dir_buffer_size += ret;
1009  s->dir_buffer[s->dir_buffer_size] = 0;
1010  start = s->dir_buffer;
1011  retried = 1;
1012  }
1013  s->dir_buffer_offset += (found + 1 - start);
1014  found[0] = 0;
1015  if (found > start && found[-1] == '\r')
1016  found[-1] = 0;
1017 
1018  *next = ff_alloc_dir_entry();
1019  if (!*next)
1020  return AVERROR(ENOMEM);
1021  (*next)->utf8 = s->utf8;
1022  ret = ftp_parse_entry(h, start, *next);
1023  if (ret) {
1025  if (ret < 0)
1026  return ret;
1027  }
1028  } while (ret > 0);
1029  return 0;
1030 }
1031 
1033 {
1034  FTPContext *s = h->priv_data;
1035  av_freep(&s->dir_buffer);
1037  ffurl_closep(&s->conn_data);
1038  return 0;
1039 }
1040 
1042 {
1043  FTPContext *s = h->priv_data;
1044  char command[MAX_URL_SIZE];
1045  static const int del_codes[] = {250, 421, 450, 500, 501, 502, 530, 550, 0};
1046  static const int rmd_codes[] = {250, 421, 500, 501, 502, 530, 550, 0};
1047  int ret;
1048 
1049  if ((ret = ftp_connect(h, h->filename)) < 0)
1050  goto cleanup;
1051 
1052  snprintf(command, sizeof(command), "DELE %s\r\n", s->path);
1053  if (ftp_send_command(s, command, del_codes, NULL) == 250) {
1054  ret = 0;
1055  goto cleanup;
1056  }
1057 
1058  snprintf(command, sizeof(command), "RMD %s\r\n", s->path);
1059  if (ftp_send_command(s, command, rmd_codes, NULL) == 250)
1060  ret = 0;
1061  else
1062  ret = AVERROR(EIO);
1063 
1064 cleanup:
1065  ftp_close(h);
1066  return ret;
1067 }
1068 
1069 static int ftp_move(URLContext *h_src, URLContext *h_dst)
1070 {
1071  FTPContext *s = h_src->priv_data;
1072  char command[MAX_URL_SIZE], path[MAX_URL_SIZE];
1073  static const int rnfr_codes[] = {350, 421, 450, 500, 501, 502, 503, 530, 0};
1074  static const int rnto_codes[] = {250, 421, 500, 501, 502, 503, 530, 532, 553, 0};
1075  int ret;
1076 
1077  if ((ret = ftp_connect(h_src, h_src->filename)) < 0)
1078  goto cleanup;
1079 
1080  snprintf(command, sizeof(command), "RNFR %s\r\n", s->path);
1081  if (ftp_send_command(s, command, rnfr_codes, NULL) != 350) {
1082  ret = AVERROR(EIO);
1083  goto cleanup;
1084  }
1085 
1086  av_url_split(0, 0, 0, 0, 0, 0, 0,
1087  path, sizeof(path),
1088  h_dst->filename);
1089  snprintf(command, sizeof(command), "RNTO %s\r\n", path);
1090  if (ftp_send_command(s, command, rnto_codes, NULL) == 250)
1091  ret = 0;
1092  else
1093  ret = AVERROR(EIO);
1094 
1095 cleanup:
1096  ftp_close(h_src);
1097  return ret;
1098 }
1099 
1101  .name = "ftp",
1102  .url_open = ftp_open,
1103  .url_read = ftp_read,
1104  .url_write = ftp_write,
1105  .url_seek = ftp_seek,
1106  .url_close = ftp_close,
1107  .url_get_file_handle = ftp_get_file_handle,
1108  .url_shutdown = ftp_shutdown,
1109  .priv_data_size = sizeof(FTPContext),
1110  .priv_data_class = &ftp_context_class,
1111  .url_open_dir = ftp_open_dir,
1112  .url_read_dir = ftp_read_dir,
1113  .url_close_dir = ftp_close_dir,
1114  .url_delete = ftp_delete,
1115  .url_move = ftp_move,
1117 };
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition: parseutils.c:539
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:3963
#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:255
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:1069
#define LIBAVUTIL_VERSION_INT
Definition: version.h:62
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:367
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:485
static int ftp_connect(URLContext *h, const char *url)
Definition: ftp.c:645
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:486
static int ftp_open(URLContext *h, const char *url, int flags)
Definition: ftp.c:697
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:593
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:985
static int ftp_connect_data_connection(URLContext *h)
Definition: ftp.c:574
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:881
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:468
static int ftp_delete(URLContext *h)
Definition: ftp.c:1041
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
av_default_item_name
#define AVERROR(e)
Definition: error.h:43
static int ftp_abort(URLContext *h)
Definition: ftp.c:607
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:79
#define fail()
Definition: checkasm.h:57
void avio_free_directory_entry(AVIODirEntry **entry)
Free entry allocated by avio_read_dir().
Definition: avio.c:548
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:928
static int ftp_read(URLContext *h, unsigned char *buf, int size)
Definition: ftp.c:767
static int ftp_close(URLContext *h)
Definition: ftp.c:853
URLContext * conn_data
Data connection, NULL when not connected.
Definition: ftp.c:51
#define FFMIN(a, b)
Definition: common.h:81
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:571
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:390
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:724
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
#define AV_BPRINT_SIZE_AUTOMATIC
static int ftp_close_dir(URLContext *h)
Definition: ftp.c:1032
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:869
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Definition: vf_drawtext.c:765
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:487
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:934
#define snprintf
Definition: snprintf.h:34
#define CONTROL_BUFFER_SIZE
Definition: ftp.c:30
misc parsing utilities
const char * name
Definition: url.h:53
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:824
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 ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:292
URLProtocol ff_ftp_protocol
Definition: ftp.c:1100
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:364
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:893
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: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:920
Definition: ftp.c:48
static int ftp_parse_entry(URLContext *h, char *line, AVIODirEntry *next)
Definition: ftp.c:970
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:353
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:127
static int ftp_list_nlst(FTPContext *s)
Definition: ftp.c:474