LCOV - code coverage report
Current view: top level - src/libavformat - avio.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 174 379 45.9 %
Date: 2017-09-22 00:04:37 Functions: 17 31 54.8 %

          Line data    Source code
       1             : /*
       2             :  * unbuffered I/O
       3             :  * Copyright (c) 2001 Fabrice Bellard
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include "libavutil/avstring.h"
      23             : #include "libavutil/dict.h"
      24             : #include "libavutil/opt.h"
      25             : #include "libavutil/time.h"
      26             : #include "libavutil/avassert.h"
      27             : #include "os_support.h"
      28             : #include "avformat.h"
      29             : #if CONFIG_NETWORK
      30             : #include "network.h"
      31             : #endif
      32             : #include "url.h"
      33             : 
      34             : /** @name Logging context. */
      35             : /*@{*/
      36           6 : static const char *urlcontext_to_name(void *ptr)
      37             : {
      38           6 :     URLContext *h = (URLContext *)ptr;
      39           6 :     if (h->prot)
      40           6 :         return h->prot->name;
      41             :     else
      42           0 :         return "NULL";
      43             : }
      44             : 
      45      858752 : static void *urlcontext_child_next(void *obj, void *prev)
      46             : {
      47      858752 :     URLContext *h = obj;
      48      858752 :     if (!prev && h->priv_data && h->prot->priv_data_class)
      49      429376 :         return h->priv_data;
      50      429376 :     return NULL;
      51             : }
      52             : 
      53             : #define OFFSET(x) offsetof(URLContext,x)
      54             : #define E AV_OPT_FLAG_ENCODING_PARAM
      55             : #define D AV_OPT_FLAG_DECODING_PARAM
      56             : static const AVOption options[] = {
      57             :     {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL },  CHAR_MIN, CHAR_MAX, D },
      58             :     {"protocol_blacklist", "List of protocols that are not allowed to be used", OFFSET(protocol_blacklist), AV_OPT_TYPE_STRING, { .str = NULL },  CHAR_MIN, CHAR_MAX, D },
      59             :     {"rw_timeout", "Timeout for IO operations (in microseconds)", offsetof(URLContext, rw_timeout), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_DECODING_PARAM },
      60             :     { NULL }
      61             : };
      62             : 
      63             : const AVClass ffurl_context_class = {
      64             :     .class_name       = "URLContext",
      65             :     .item_name        = urlcontext_to_name,
      66             :     .option           = options,
      67             :     .version          = LIBAVUTIL_VERSION_INT,
      68             :     .child_next       = urlcontext_child_next,
      69             :     .child_class_next = ff_urlcontext_child_class_next,
      70             : };
      71             : /*@}*/
      72             : 
      73      108294 : static int url_alloc_for_protocol(URLContext **puc, const URLProtocol *up,
      74             :                                   const char *filename, int flags,
      75             :                                   const AVIOInterruptCB *int_cb)
      76             : {
      77             :     URLContext *uc;
      78             :     int err;
      79             : 
      80             : #if CONFIG_NETWORK
      81      108294 :     if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init())
      82           0 :         return AVERROR(EIO);
      83             : #endif
      84      108294 :     if ((flags & AVIO_FLAG_READ) && !up->url_read) {
      85           0 :         av_log(NULL, AV_LOG_ERROR,
      86             :                "Impossible to open the '%s' protocol for reading\n", up->name);
      87           0 :         return AVERROR(EIO);
      88             :     }
      89      108294 :     if ((flags & AVIO_FLAG_WRITE) && !up->url_write) {
      90           0 :         av_log(NULL, AV_LOG_ERROR,
      91             :                "Impossible to open the '%s' protocol for writing\n", up->name);
      92           0 :         return AVERROR(EIO);
      93             :     }
      94      108294 :     uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
      95      108294 :     if (!uc) {
      96           0 :         err = AVERROR(ENOMEM);
      97           0 :         goto fail;
      98             :     }
      99      108294 :     uc->av_class = &ffurl_context_class;
     100      108294 :     uc->filename = (char *)&uc[1];
     101      108294 :     strcpy(uc->filename, filename);
     102      108294 :     uc->prot            = up;
     103      108294 :     uc->flags           = flags;
     104      108294 :     uc->is_streamed     = 0; /* default = not streamed */
     105      108294 :     uc->max_packet_size = 0; /* default: stream file */
     106      108294 :     if (up->priv_data_size) {
     107      108294 :         uc->priv_data = av_mallocz(up->priv_data_size);
     108      108294 :         if (!uc->priv_data) {
     109           0 :             err = AVERROR(ENOMEM);
     110           0 :             goto fail;
     111             :         }
     112      108294 :         if (up->priv_data_class) {
     113      106576 :             int proto_len= strlen(up->name);
     114      106576 :             char *start = strchr(uc->filename, ',');
     115      106576 :             *(const AVClass **)uc->priv_data = up->priv_data_class;
     116      106576 :             av_opt_set_defaults(uc->priv_data);
     117      106576 :             if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){
     118           0 :                 int ret= 0;
     119           0 :                 char *p= start;
     120           0 :                 char sep= *++p;
     121             :                 char *key, *val;
     122           0 :                 p++;
     123             : 
     124           0 :                 if (strcmp(up->name, "subfile"))
     125           0 :                     ret = AVERROR(EINVAL);
     126             : 
     127           0 :                 while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){
     128           0 :                     *val= *key= 0;
     129           0 :                     if (strcmp(p, "start") && strcmp(p, "end")) {
     130           0 :                         ret = AVERROR_OPTION_NOT_FOUND;
     131             :                     } else
     132           0 :                         ret= av_opt_set(uc->priv_data, p, key+1, 0);
     133           0 :                     if (ret == AVERROR_OPTION_NOT_FOUND)
     134           0 :                         av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p);
     135           0 :                     *val= *key= sep;
     136           0 :                     p= val+1;
     137             :                 }
     138           0 :                 if(ret<0 || p!=key){
     139           0 :                     av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start);
     140           0 :                     av_freep(&uc->priv_data);
     141           0 :                     av_freep(&uc);
     142           0 :                     err = AVERROR(EINVAL);
     143           0 :                     goto fail;
     144             :                 }
     145           0 :                 memmove(start, key+1, strlen(key));
     146             :             }
     147             :         }
     148             :     }
     149      108294 :     if (int_cb)
     150       74639 :         uc->interrupt_callback = *int_cb;
     151             : 
     152      108294 :     *puc = uc;
     153      108294 :     return 0;
     154           0 : fail:
     155           0 :     *puc = NULL;
     156           0 :     if (uc)
     157           0 :         av_freep(&uc->priv_data);
     158           0 :     av_freep(&uc);
     159             : #if CONFIG_NETWORK
     160           0 :     if (up->flags & URL_PROTOCOL_FLAG_NETWORK)
     161           0 :         ff_network_close();
     162             : #endif
     163           0 :     return err;
     164             : }
     165             : 
     166       74664 : int ffurl_connect(URLContext *uc, AVDictionary **options)
     167             : {
     168             :     int err;
     169       74664 :     AVDictionary *tmp_opts = NULL;
     170             :     AVDictionaryEntry *e;
     171             : 
     172       74664 :     if (!options)
     173           0 :         options = &tmp_opts;
     174             : 
     175             :     // Check that URLContext was initialized correctly and lists are matching if set
     176       74664 :     av_assert0(!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) ||
     177             :                (uc->protocol_whitelist && !strcmp(uc->protocol_whitelist, e->value)));
     178       74664 :     av_assert0(!(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) ||
     179             :                (uc->protocol_blacklist && !strcmp(uc->protocol_blacklist, e->value)));
     180             : 
     181       74664 :     if (uc->protocol_whitelist && av_match_list(uc->prot->name, uc->protocol_whitelist, ',') <= 0) {
     182           0 :         av_log(uc, AV_LOG_ERROR, "Protocol '%s' not on whitelist '%s'!\n", uc->prot->name, uc->protocol_whitelist);
     183           0 :         return AVERROR(EINVAL);
     184             :     }
     185             : 
     186       74664 :     if (uc->protocol_blacklist && av_match_list(uc->prot->name, uc->protocol_blacklist, ',') > 0) {
     187           0 :         av_log(uc, AV_LOG_ERROR, "Protocol '%s' on blacklist '%s'!\n", uc->prot->name, uc->protocol_blacklist);
     188           0 :         return AVERROR(EINVAL);
     189             :     }
     190             : 
     191       74664 :     if (!uc->protocol_whitelist && uc->prot->default_whitelist) {
     192       72861 :         av_log(uc, AV_LOG_DEBUG, "Setting default whitelist '%s'\n", uc->prot->default_whitelist);
     193       72861 :         uc->protocol_whitelist = av_strdup(uc->prot->default_whitelist);
     194      145722 :         if (!uc->protocol_whitelist) {
     195           0 :             return AVERROR(ENOMEM);
     196             :         }
     197        1803 :     } else if (!uc->protocol_whitelist)
     198        1719 :         av_log(uc, AV_LOG_DEBUG, "No default whitelist set\n"); // This should be an error once all declare a default whitelist
     199             : 
     200       74664 :     if ((err = av_dict_set(options, "protocol_whitelist", uc->protocol_whitelist, 0)) < 0)
     201           0 :         return err;
     202       74664 :     if ((err = av_dict_set(options, "protocol_blacklist", uc->protocol_blacklist, 0)) < 0)
     203           0 :         return err;
     204             : 
     205       74664 :     err =
     206       74665 :         uc->prot->url_open2 ? uc->prot->url_open2(uc,
     207           1 :                                                   uc->filename,
     208             :                                                   uc->flags,
     209      149328 :                                                   options) :
     210       74663 :         uc->prot->url_open(uc, uc->filename, uc->flags);
     211             : 
     212       74664 :     av_dict_set(options, "protocol_whitelist", NULL, 0);
     213       74664 :     av_dict_set(options, "protocol_blacklist", NULL, 0);
     214             : 
     215       74664 :     if (err)
     216           1 :         return err;
     217       74663 :     uc->is_connected = 1;
     218             :     /* We must be careful here as ffurl_seek() could be slow,
     219             :      * for example for http */
     220       74663 :     if ((uc->flags & AVIO_FLAG_WRITE) || !strcmp(uc->prot->name, "file"))
     221       74661 :         if (!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
     222        1718 :             uc->is_streamed = 1;
     223       74663 :     return 0;
     224             : }
     225             : 
     226           0 : int ffurl_accept(URLContext *s, URLContext **c)
     227             : {
     228           0 :     av_assert0(!*c);
     229           0 :     if (s->prot->url_accept)
     230           0 :         return s->prot->url_accept(s, c);
     231           0 :     return AVERROR(EBADF);
     232             : }
     233             : 
     234           0 : int ffurl_handshake(URLContext *c)
     235             : {
     236             :     int ret;
     237           0 :     if (c->prot->url_handshake) {
     238           0 :         ret = c->prot->url_handshake(c);
     239           0 :         if (ret)
     240           0 :             return ret;
     241             :     }
     242           0 :     c->is_connected = 1;
     243           0 :     return 0;
     244             : }
     245             : 
     246             : #define URL_SCHEME_CHARS                        \
     247             :     "abcdefghijklmnopqrstuvwxyz"                \
     248             :     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                \
     249             :     "0123456789+-."
     250             : 
     251      112649 : static const struct URLProtocol *url_find_protocol(const char *filename)
     252             : {
     253             :     const URLProtocol **protocols;
     254             :     char proto_str[128], proto_nested[128], *ptr;
     255      112649 :     size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
     256             :     int i;
     257             : 
     258      217690 :     if (filename[proto_len] != ':' &&
     259      112649 :         (strncmp(filename, "subfile,", 8) || !strchr(filename + proto_len + 1, ':')) ||
     260        7608 :         is_dos_path(filename))
     261      105041 :         strcpy(proto_str, "file");
     262             :     else
     263        7608 :         av_strlcpy(proto_str, filename,
     264        7608 :                    FFMIN(proto_len + 1, sizeof(proto_str)));
     265             : 
     266      112649 :     av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
     267      112649 :     if ((ptr = strchr(proto_nested, '+')))
     268           0 :         *ptr = '\0';
     269             : 
     270      112649 :     protocols = ffurl_get_protocols(NULL, NULL);
     271      112649 :     if (!protocols)
     272           0 :         return NULL;
     273      861173 :     for (i = 0; protocols[i]; i++) {
     274      861173 :             const URLProtocol *up = protocols[i];
     275      861173 :         if (!strcmp(proto_str, up->name)) {
     276      112649 :             av_freep(&protocols);
     277      112649 :             return up;
     278             :         }
     279      868779 :         if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
     280      120255 :             !strcmp(proto_nested, up->name)) {
     281           0 :             av_freep(&protocols);
     282           0 :             return up;
     283             :         }
     284             :     }
     285           0 :     av_freep(&protocols);
     286             : 
     287           0 :     return NULL;
     288             : }
     289             : 
     290      108294 : int ffurl_alloc(URLContext **puc, const char *filename, int flags,
     291             :                 const AVIOInterruptCB *int_cb)
     292             : {
     293      108294 :     const URLProtocol *p = NULL;
     294             : 
     295      108294 :     p = url_find_protocol(filename);
     296      108294 :     if (p)
     297      108294 :        return url_alloc_for_protocol(puc, p, filename, flags, int_cb);
     298             : 
     299           0 :     *puc = NULL;
     300           0 :     if (av_strstart(filename, "https:", NULL))
     301           0 :         av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with "
     302             :                                      "openssl, gnutls "
     303             :                                      "or securetransport enabled.\n");
     304           0 :     return AVERROR_PROTOCOL_NOT_FOUND;
     305             : }
     306             : 
     307       74664 : int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
     308             :                          const AVIOInterruptCB *int_cb, AVDictionary **options,
     309             :                          const char *whitelist, const char* blacklist,
     310             :                          URLContext *parent)
     311             : {
     312       74664 :     AVDictionary *tmp_opts = NULL;
     313             :     AVDictionaryEntry *e;
     314       74664 :     int ret = ffurl_alloc(puc, filename, flags, int_cb);
     315       74664 :     if (ret < 0)
     316           0 :         return ret;
     317       74664 :     if (parent)
     318           1 :         av_opt_copy(*puc, parent);
     319       83526 :     if (options &&
     320        8862 :         (ret = av_opt_set_dict(*puc, options)) < 0)
     321           0 :         goto fail;
     322       81808 :     if (options && (*puc)->prot->priv_data_class &&
     323        7144 :         (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
     324           0 :         goto fail;
     325             : 
     326       74664 :     if (!options)
     327       65802 :         options = &tmp_opts;
     328             : 
     329       74664 :     av_assert0(!whitelist ||
     330             :                !(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) ||
     331             :                !strcmp(whitelist, e->value));
     332       74664 :     av_assert0(!blacklist ||
     333             :                !(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) ||
     334             :                !strcmp(blacklist, e->value));
     335             : 
     336       74664 :     if ((ret = av_dict_set(options, "protocol_whitelist", whitelist, 0)) < 0)
     337           0 :         goto fail;
     338             : 
     339       74664 :     if ((ret = av_dict_set(options, "protocol_blacklist", blacklist, 0)) < 0)
     340           0 :         goto fail;
     341             : 
     342       74664 :     if ((ret = av_opt_set_dict(*puc, options)) < 0)
     343           0 :         goto fail;
     344             : 
     345       74664 :     ret = ffurl_connect(*puc, options);
     346             : 
     347       74664 :     if (!ret)
     348       74663 :         return 0;
     349           1 : fail:
     350           1 :     ffurl_close(*puc);
     351           1 :     *puc = NULL;
     352           1 :     return ret;
     353             : }
     354             : 
     355           0 : int ffurl_open(URLContext **puc, const char *filename, int flags,
     356             :                const AVIOInterruptCB *int_cb, AVDictionary **options)
     357             : {
     358           0 :     return ffurl_open_whitelist(puc, filename, flags,
     359             :                                 int_cb, options, NULL, NULL, NULL);
     360             : }
     361             : 
     362      414109 : static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
     363             :                                          int size, int size_min,
     364             :                                          int (*transfer_func)(URLContext *h,
     365             :                                                               uint8_t *buf,
     366             :                                                               int size))
     367             : {
     368             :     int ret, len;
     369      414109 :     int fast_retries = 5;
     370      414109 :     int64_t wait_since = 0;
     371             : 
     372      414109 :     len = 0;
     373     1231809 :     while (len < size_min) {
     374      414109 :         if (ff_check_interrupt(&h->interrupt_callback))
     375           0 :             return AVERROR_EXIT;
     376      414109 :         ret = transfer_func(h, buf + len, size - len);
     377      414109 :         if (ret == AVERROR(EINTR))
     378           0 :             continue;
     379      414109 :         if (h->flags & AVIO_FLAG_NONBLOCK)
     380           0 :             return ret;
     381      414109 :         if (ret == AVERROR(EAGAIN)) {
     382           0 :             ret = 0;
     383           0 :             if (fast_retries) {
     384           0 :                 fast_retries--;
     385             :             } else {
     386           0 :                 if (h->rw_timeout) {
     387           0 :                     if (!wait_since)
     388           0 :                         wait_since = av_gettime_relative();
     389           0 :                     else if (av_gettime_relative() > wait_since + h->rw_timeout)
     390           0 :                         return AVERROR(EIO);
     391             :                 }
     392           0 :                 av_usleep(1000);
     393             :             }
     394      414109 :         } else if (ret < 1)
     395       10518 :             return (ret < 0 && ret != AVERROR_EOF) ? ret : len;
     396      403591 :         if (ret) {
     397      403591 :             fast_retries = FFMAX(fast_retries, 2);
     398      403591 :             wait_since = 0;
     399             :         }
     400      403591 :         len += ret;
     401             :     }
     402      403591 :     return len;
     403             : }
     404             : 
     405      161511 : int ffurl_read(URLContext *h, unsigned char *buf, int size)
     406             : {
     407      161511 :     if (!(h->flags & AVIO_FLAG_READ))
     408           0 :         return AVERROR(EIO);
     409      161511 :     return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);
     410             : }
     411             : 
     412           0 : int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
     413             : {
     414           0 :     if (!(h->flags & AVIO_FLAG_READ))
     415           0 :         return AVERROR(EIO);
     416           0 :     return retry_transfer_wrapper(h, buf, size, size, h->prot->url_read);
     417             : }
     418             : 
     419      252598 : int ffurl_write(URLContext *h, const unsigned char *buf, int size)
     420             : {
     421      252598 :     if (!(h->flags & AVIO_FLAG_WRITE))
     422           0 :         return AVERROR(EIO);
     423             :     /* avoid sending too big packets */
     424      252598 :     if (h->max_packet_size && size > h->max_packet_size)
     425           0 :         return AVERROR(EIO);
     426             : 
     427      252598 :     return retry_transfer_wrapper(h, (unsigned char *)buf, size, size,
     428             :                                   (int (*)(struct URLContext *, uint8_t *, int))
     429      252598 :                                   h->prot->url_write);
     430             : }
     431             : 
     432      167468 : int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
     433             : {
     434             :     int64_t ret;
     435             : 
     436      167468 :     if (!h->prot->url_seek)
     437        1738 :         return AVERROR(ENOSYS);
     438      165730 :     ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
     439      165730 :     return ret;
     440             : }
     441             : 
     442      108294 : int ffurl_closep(URLContext **hh)
     443             : {
     444      108294 :     URLContext *h= *hh;
     445      108294 :     int ret = 0;
     446      108294 :     if (!h)
     447           0 :         return 0;     /* can happen when ffurl_open fails */
     448             : 
     449      108294 :     if (h->is_connected && h->prot->url_close)
     450       72576 :         ret = h->prot->url_close(h);
     451             : #if CONFIG_NETWORK
     452      108294 :     if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)
     453           0 :         ff_network_close();
     454             : #endif
     455      108294 :     if (h->prot->priv_data_size) {
     456      108294 :         if (h->prot->priv_data_class)
     457      106576 :             av_opt_free(h->priv_data);
     458      108294 :         av_freep(&h->priv_data);
     459             :     }
     460      108294 :     av_opt_free(h);
     461      108294 :     av_freep(hh);
     462      108294 :     return ret;
     463             : }
     464             : 
     465      108294 : int ffurl_close(URLContext *h)
     466             : {
     467      108294 :     return ffurl_closep(&h);
     468             : }
     469             : 
     470             : 
     471        4355 : const char *avio_find_protocol_name(const char *url)
     472             : {
     473        4355 :     const URLProtocol *p = url_find_protocol(url);
     474             : 
     475        4355 :     return p ? p->name : NULL;
     476             : }
     477             : 
     478       33630 : int avio_check(const char *url, int flags)
     479             : {
     480             :     URLContext *h;
     481       33630 :     int ret = ffurl_alloc(&h, url, flags, NULL);
     482       33630 :     if (ret < 0)
     483           0 :         return ret;
     484             : 
     485       33630 :     if (h->prot->url_check) {
     486       33630 :         ret = h->prot->url_check(h, flags);
     487             :     } else {
     488           0 :         ret = ffurl_connect(h, NULL);
     489           0 :         if (ret >= 0)
     490           0 :             ret = flags;
     491             :     }
     492             : 
     493       33630 :     ffurl_close(h);
     494       33630 :     return ret;
     495             : }
     496             : 
     497           0 : int avpriv_io_move(const char *url_src, const char *url_dst)
     498             : {
     499             :     URLContext *h_src, *h_dst;
     500           0 :     int ret = ffurl_alloc(&h_src, url_src, AVIO_FLAG_READ_WRITE, NULL);
     501           0 :     if (ret < 0)
     502           0 :         return ret;
     503           0 :     ret = ffurl_alloc(&h_dst, url_dst, AVIO_FLAG_WRITE, NULL);
     504           0 :     if (ret < 0) {
     505           0 :         ffurl_close(h_src);
     506           0 :         return ret;
     507             :     }
     508             : 
     509           0 :     if (h_src->prot == h_dst->prot && h_src->prot->url_move)
     510           0 :         ret = h_src->prot->url_move(h_src, h_dst);
     511             :     else
     512           0 :         ret = AVERROR(ENOSYS);
     513             : 
     514           0 :     ffurl_close(h_src);
     515           0 :     ffurl_close(h_dst);
     516           0 :     return ret;
     517             : }
     518             : 
     519           0 : int avpriv_io_delete(const char *url)
     520             : {
     521             :     URLContext *h;
     522           0 :     int ret = ffurl_alloc(&h, url, AVIO_FLAG_WRITE, NULL);
     523           0 :     if (ret < 0)
     524           0 :         return ret;
     525             : 
     526           0 :     if (h->prot->url_delete)
     527           0 :         ret = h->prot->url_delete(h);
     528             :     else
     529           0 :         ret = AVERROR(ENOSYS);
     530             : 
     531           0 :     ffurl_close(h);
     532           0 :     return ret;
     533             : }
     534             : 
     535           0 : int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options)
     536             : {
     537           0 :     URLContext *h = NULL;
     538           0 :     AVIODirContext *ctx = NULL;
     539             :     int ret;
     540           0 :     av_assert0(s);
     541             : 
     542           0 :     ctx = av_mallocz(sizeof(*ctx));
     543           0 :     if (!ctx) {
     544           0 :         ret = AVERROR(ENOMEM);
     545           0 :         goto fail;
     546             :     }
     547             : 
     548           0 :     if ((ret = ffurl_alloc(&h, url, AVIO_FLAG_READ, NULL)) < 0)
     549           0 :         goto fail;
     550             : 
     551           0 :     if (h->prot->url_open_dir && h->prot->url_read_dir && h->prot->url_close_dir) {
     552           0 :         if (options && h->prot->priv_data_class &&
     553           0 :             (ret = av_opt_set_dict(h->priv_data, options)) < 0)
     554           0 :             goto fail;
     555           0 :         ret = h->prot->url_open_dir(h);
     556             :     } else
     557           0 :         ret = AVERROR(ENOSYS);
     558           0 :     if (ret < 0)
     559           0 :         goto fail;
     560             : 
     561           0 :     h->is_connected = 1;
     562           0 :     ctx->url_context = h;
     563           0 :     *s = ctx;
     564           0 :     return 0;
     565             : 
     566           0 :   fail:
     567           0 :     av_free(ctx);
     568           0 :     *s = NULL;
     569           0 :     ffurl_close(h);
     570           0 :     return ret;
     571             : }
     572             : 
     573           0 : int avio_read_dir(AVIODirContext *s, AVIODirEntry **next)
     574             : {
     575             :     URLContext *h;
     576             :     int ret;
     577             : 
     578           0 :     if (!s || !s->url_context)
     579           0 :         return AVERROR(EINVAL);
     580           0 :     h = s->url_context;
     581           0 :     if ((ret = h->prot->url_read_dir(h, next)) < 0)
     582           0 :         avio_free_directory_entry(next);
     583           0 :     return ret;
     584             : }
     585             : 
     586           0 : int avio_close_dir(AVIODirContext **s)
     587             : {
     588             :     URLContext *h;
     589             : 
     590           0 :     av_assert0(s);
     591           0 :     if (!(*s) || !(*s)->url_context)
     592           0 :         return AVERROR(EINVAL);
     593           0 :     h = (*s)->url_context;
     594           0 :     h->prot->url_close_dir(h);
     595           0 :     ffurl_close(h);
     596           0 :     av_freep(s);
     597           0 :     *s = NULL;
     598           0 :     return 0;
     599             : }
     600             : 
     601           0 : void avio_free_directory_entry(AVIODirEntry **entry)
     602             : {
     603           0 :     if (!entry || !*entry)
     604           0 :         return;
     605           0 :     av_free((*entry)->name);
     606           0 :     av_freep(entry);
     607             : }
     608             : 
     609           0 : int64_t ffurl_size(URLContext *h)
     610             : {
     611             :     int64_t pos, size;
     612             : 
     613           0 :     size = ffurl_seek(h, 0, AVSEEK_SIZE);
     614           0 :     if (size < 0) {
     615           0 :         pos = ffurl_seek(h, 0, SEEK_CUR);
     616           0 :         if ((size = ffurl_seek(h, -1, SEEK_END)) < 0)
     617           0 :             return size;
     618           0 :         size++;
     619           0 :         ffurl_seek(h, pos, SEEK_SET);
     620             :     }
     621           0 :     return size;
     622             : }
     623             : 
     624           0 : int ffurl_get_file_handle(URLContext *h)
     625             : {
     626           0 :     if (!h->prot->url_get_file_handle)
     627           0 :         return -1;
     628           0 :     return h->prot->url_get_file_handle(h);
     629             : }
     630             : 
     631           0 : int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles)
     632             : {
     633           0 :     if (!h->prot->url_get_multi_file_handle) {
     634           0 :         if (!h->prot->url_get_file_handle)
     635           0 :             return AVERROR(ENOSYS);
     636           0 :         *handles = av_malloc(sizeof(**handles));
     637           0 :         if (!*handles)
     638           0 :             return AVERROR(ENOMEM);
     639           0 :         *numhandles = 1;
     640           0 :         *handles[0] = h->prot->url_get_file_handle(h);
     641           0 :         return 0;
     642             :     }
     643           0 :     return h->prot->url_get_multi_file_handle(h, handles, numhandles);
     644             : }
     645             : 
     646      413810 : int ffurl_get_short_seek(URLContext *h)
     647             : {
     648      413810 :     if (!h->prot->url_get_short_seek)
     649      413810 :         return AVERROR(ENOSYS);
     650           0 :     return h->prot->url_get_short_seek(h);
     651             : }
     652             : 
     653           0 : int ffurl_shutdown(URLContext *h, int flags)
     654             : {
     655           0 :     if (!h->prot->url_shutdown)
     656           0 :         return AVERROR(EINVAL);
     657           0 :     return h->prot->url_shutdown(h, flags);
     658             : }
     659             : 
     660      561247 : int ff_check_interrupt(AVIOInterruptCB *cb)
     661             : {
     662             :     int ret;
     663      561247 :     if (cb && cb->callback && (ret = cb->callback(cb->opaque)))
     664           0 :         return ret;
     665      561247 :     return 0;
     666             : }

Generated by: LCOV version 1.13