Line | Branch | Exec | Source |
---|---|---|---|
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 "internal.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 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (h->prot) |
40 | 6 | return h->prot->name; | |
41 | else | ||
42 | ✗ | return "NULL"; | |
43 | } | ||
44 | |||
45 | 34178 | static void *urlcontext_child_next(void *obj, void *prev) | |
46 | { | ||
47 | 34178 | URLContext *h = obj; | |
48 |
4/6✓ Branch 0 taken 17089 times.
✓ Branch 1 taken 17089 times.
✓ Branch 2 taken 17089 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17089 times.
✗ Branch 5 not taken.
|
34178 | if (!prev && h->priv_data && h->prot->priv_data_class) |
49 | 17089 | return h->priv_data; | |
50 | 17089 | 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 }, 0, 0, D }, | ||
58 | {"protocol_blacklist", "List of protocols that are not allowed to be used", OFFSET(protocol_blacklist), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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_iterate = ff_urlcontext_child_class_iterate, | ||
70 | }; | ||
71 | /*@}*/ | ||
72 | |||
73 | 144960 | 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 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 144960 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
144960 | if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init()) |
82 | ✗ | return AVERROR(EIO); | |
83 | #endif | ||
84 |
3/4✓ Branch 0 taken 137443 times.
✓ Branch 1 taken 7517 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 137443 times.
|
144960 | if ((flags & AVIO_FLAG_READ) && !up->url_read) { |
85 | ✗ | av_log(NULL, AV_LOG_ERROR, | |
86 | ✗ | "Impossible to open the '%s' protocol for reading\n", up->name); | |
87 | ✗ | return AVERROR(EIO); | |
88 | } | ||
89 |
3/4✓ Branch 0 taken 7595 times.
✓ Branch 1 taken 137365 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7595 times.
|
144960 | if ((flags & AVIO_FLAG_WRITE) && !up->url_write) { |
90 | ✗ | av_log(NULL, AV_LOG_ERROR, | |
91 | ✗ | "Impossible to open the '%s' protocol for writing\n", up->name); | |
92 | ✗ | return AVERROR(EIO); | |
93 | } | ||
94 | 144960 | uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); | |
95 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144960 times.
|
144960 | if (!uc) { |
96 | ✗ | err = AVERROR(ENOMEM); | |
97 | ✗ | goto fail; | |
98 | } | ||
99 | 144960 | uc->av_class = &ffurl_context_class; | |
100 | 144960 | uc->filename = (char *)&uc[1]; | |
101 | 144960 | strcpy(uc->filename, filename); | |
102 | 144960 | uc->prot = up; | |
103 | 144960 | uc->flags = flags; | |
104 | 144960 | uc->is_streamed = 0; /* default = not streamed */ | |
105 | 144960 | uc->max_packet_size = 0; /* default: stream file */ | |
106 |
1/2✓ Branch 0 taken 144960 times.
✗ Branch 1 not taken.
|
144960 | if (up->priv_data_size) { |
107 | 144960 | uc->priv_data = av_mallocz(up->priv_data_size); | |
108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144960 times.
|
144960 | if (!uc->priv_data) { |
109 | ✗ | err = AVERROR(ENOMEM); | |
110 | ✗ | goto fail; | |
111 | } | ||
112 |
2/2✓ Branch 0 taken 142571 times.
✓ Branch 1 taken 2389 times.
|
144960 | if (up->priv_data_class) { |
113 | char *start; | ||
114 | 142571 | *(const AVClass **)uc->priv_data = up->priv_data_class; | |
115 | 142571 | av_opt_set_defaults(uc->priv_data); | |
116 |
3/4✓ Branch 1 taken 2552 times.
✓ Branch 2 taken 140019 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2552 times.
|
142571 | if (av_strstart(uc->filename, up->name, (const char**)&start) && *start == ',') { |
117 | ✗ | int ret= 0; | |
118 | ✗ | char *p= start; | |
119 | ✗ | char sep= *++p; | |
120 | char *key, *val; | ||
121 | ✗ | p++; | |
122 | |||
123 | ✗ | if (strcmp(up->name, "subfile")) | |
124 | ✗ | ret = AVERROR(EINVAL); | |
125 | |||
126 | ✗ | while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){ | |
127 | ✗ | *val= *key= 0; | |
128 | ✗ | ret = av_opt_set(uc->priv_data, p, key+1, 0); | |
129 | ✗ | if (ret == AVERROR_OPTION_NOT_FOUND) | |
130 | ✗ | av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p); | |
131 | ✗ | *val= *key= sep; | |
132 | ✗ | p= val+1; | |
133 | } | ||
134 | ✗ | if(ret<0 || p!=key){ | |
135 | ✗ | av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start); | |
136 | ✗ | err = AVERROR(EINVAL); | |
137 | ✗ | goto fail; | |
138 | } | ||
139 | ✗ | memmove(start, key+1, strlen(key)); | |
140 | } | ||
141 | } | ||
142 | } | ||
143 |
2/2✓ Branch 0 taken 99548 times.
✓ Branch 1 taken 45412 times.
|
144960 | if (int_cb) |
144 | 99548 | uc->interrupt_callback = *int_cb; | |
145 | |||
146 | 144960 | *puc = uc; | |
147 | 144960 | return 0; | |
148 | ✗ | fail: | |
149 | ✗ | *puc = NULL; | |
150 | ✗ | if (uc) | |
151 | ✗ | av_freep(&uc->priv_data); | |
152 | ✗ | av_freep(&uc); | |
153 | #if CONFIG_NETWORK | ||
154 | ✗ | if (up->flags & URL_PROTOCOL_FLAG_NETWORK) | |
155 | ✗ | ff_network_close(); | |
156 | #endif | ||
157 | ✗ | return err; | |
158 | } | ||
159 | |||
160 | 99605 | int ffurl_connect(URLContext *uc, AVDictionary **options) | |
161 | { | ||
162 | int err; | ||
163 | 99605 | AVDictionary *tmp_opts = NULL; | |
164 | AVDictionaryEntry *e; | ||
165 | |||
166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 99605 times.
|
99605 | if (!options) |
167 | ✗ | options = &tmp_opts; | |
168 | |||
169 | // Check that URLContext was initialized correctly and lists are matching if set | ||
170 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 99605 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
99605 | av_assert0(!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) || |
171 | (uc->protocol_whitelist && !strcmp(uc->protocol_whitelist, e->value))); | ||
172 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 99605 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
99605 | av_assert0(!(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) || |
173 | (uc->protocol_blacklist && !strcmp(uc->protocol_blacklist, e->value))); | ||
174 | |||
175 |
3/4✓ Branch 0 taken 133 times.
✓ Branch 1 taken 99472 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 133 times.
|
99605 | if (uc->protocol_whitelist && av_match_list(uc->prot->name, uc->protocol_whitelist, ',') <= 0) { |
176 | ✗ | av_log(uc, AV_LOG_ERROR, "Protocol '%s' not on whitelist '%s'!\n", uc->prot->name, uc->protocol_whitelist); | |
177 | ✗ | return AVERROR(EINVAL); | |
178 | } | ||
179 | |||
180 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 99605 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
99605 | if (uc->protocol_blacklist && av_match_list(uc->prot->name, uc->protocol_blacklist, ',') > 0) { |
181 | ✗ | av_log(uc, AV_LOG_ERROR, "Protocol '%s' on blacklist '%s'!\n", uc->prot->name, uc->protocol_blacklist); | |
182 | ✗ | return AVERROR(EINVAL); | |
183 | } | ||
184 | |||
185 |
4/4✓ Branch 0 taken 99472 times.
✓ Branch 1 taken 133 times.
✓ Branch 2 taken 97082 times.
✓ Branch 3 taken 2390 times.
|
99605 | if (!uc->protocol_whitelist && uc->prot->default_whitelist) { |
186 | 97082 | av_log(uc, AV_LOG_DEBUG, "Setting default whitelist '%s'\n", uc->prot->default_whitelist); | |
187 | 97082 | uc->protocol_whitelist = av_strdup(uc->prot->default_whitelist); | |
188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97082 times.
|
97082 | if (!uc->protocol_whitelist) { |
189 | ✗ | return AVERROR(ENOMEM); | |
190 | } | ||
191 |
2/2✓ Branch 0 taken 2390 times.
✓ Branch 1 taken 133 times.
|
2523 | } else if (!uc->protocol_whitelist) |
192 | 2390 | av_log(uc, AV_LOG_DEBUG, "No default whitelist set\n"); // This should be an error once all declare a default whitelist | |
193 | |||
194 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99605 times.
|
99605 | if ((err = av_dict_set(options, "protocol_whitelist", uc->protocol_whitelist, 0)) < 0) |
195 | ✗ | return err; | |
196 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99605 times.
|
99605 | if ((err = av_dict_set(options, "protocol_blacklist", uc->protocol_blacklist, 0)) < 0) |
197 | ✗ | return err; | |
198 | |||
199 | 99605 | err = | |
200 | 99606 | uc->prot->url_open2 ? uc->prot->url_open2(uc, | |
201 | 1 | uc->filename, | |
202 | uc->flags, | ||
203 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99604 times.
|
99605 | options) : |
204 | 99604 | uc->prot->url_open(uc, uc->filename, uc->flags); | |
205 | |||
206 | 99605 | av_dict_set(options, "protocol_whitelist", NULL, 0); | |
207 | 99605 | av_dict_set(options, "protocol_blacklist", NULL, 0); | |
208 | |||
209 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99604 times.
|
99605 | if (err) |
210 | 1 | return err; | |
211 | 99604 | uc->is_connected = 1; | |
212 | /* We must be careful here as ffurl_seek() could be slow, | ||
213 | * for example for http */ | ||
214 |
4/4✓ Branch 0 taken 92165 times.
✓ Branch 1 taken 7439 times.
✓ Branch 2 taken 92163 times.
✓ Branch 3 taken 2 times.
|
99604 | if ((uc->flags & AVIO_FLAG_WRITE) || !strcmp(uc->prot->name, "file")) |
215 |
4/4✓ Branch 0 taken 97052 times.
✓ Branch 1 taken 2550 times.
✓ Branch 3 taken 2389 times.
✓ Branch 4 taken 94663 times.
|
99602 | if (!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0) |
216 | 2389 | uc->is_streamed = 1; | |
217 | 99604 | return 0; | |
218 | } | ||
219 | |||
220 | ✗ | int ffurl_accept(URLContext *s, URLContext **c) | |
221 | { | ||
222 | ✗ | av_assert0(!*c); | |
223 | ✗ | if (s->prot->url_accept) | |
224 | ✗ | return s->prot->url_accept(s, c); | |
225 | ✗ | return AVERROR(EBADF); | |
226 | } | ||
227 | |||
228 | ✗ | int ffurl_handshake(URLContext *c) | |
229 | { | ||
230 | int ret; | ||
231 | ✗ | if (c->prot->url_handshake) { | |
232 | ✗ | ret = c->prot->url_handshake(c); | |
233 | ✗ | if (ret) | |
234 | ✗ | return ret; | |
235 | } | ||
236 | ✗ | c->is_connected = 1; | |
237 | ✗ | return 0; | |
238 | } | ||
239 | |||
240 | #define URL_SCHEME_CHARS \ | ||
241 | "abcdefghijklmnopqrstuvwxyz" \ | ||
242 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ | ||
243 | "0123456789+-." | ||
244 | |||
245 | 152688 | static const struct URLProtocol *url_find_protocol(const char *filename) | |
246 | { | ||
247 | const URLProtocol **protocols; | ||
248 | char proto_str[128], proto_nested[128], *ptr; | ||
249 | 152688 | size_t proto_len = strspn(filename, URL_SCHEME_CHARS); | |
250 | int i; | ||
251 | |||
252 |
2/2✓ Branch 0 taken 142832 times.
✓ Branch 1 taken 9856 times.
|
152688 | if (filename[proto_len] != ':' && |
253 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 142832 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9856 times.
|
152688 | (strncmp(filename, "subfile,", 8) || !strchr(filename + proto_len + 1, ':')) || |
254 | 9856 | is_dos_path(filename)) | |
255 | 142832 | strcpy(proto_str, "file"); | |
256 | else | ||
257 | 9856 | av_strlcpy(proto_str, filename, | |
258 | 9856 | FFMIN(proto_len + 1, sizeof(proto_str))); | |
259 | |||
260 | 152688 | av_strlcpy(proto_nested, proto_str, sizeof(proto_nested)); | |
261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 152688 times.
|
152688 | if ((ptr = strchr(proto_nested, '+'))) |
262 | ✗ | *ptr = '\0'; | |
263 | |||
264 | 152688 | protocols = ffurl_get_protocols(NULL, NULL); | |
265 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 152688 times.
|
152688 | if (!protocols) |
266 | ✗ | return NULL; | |
267 |
1/2✓ Branch 0 taken 1467958 times.
✗ Branch 1 not taken.
|
1467958 | for (i = 0; protocols[i]; i++) { |
268 | 1467958 | const URLProtocol *up = protocols[i]; | |
269 |
2/2✓ Branch 0 taken 152688 times.
✓ Branch 1 taken 1315270 times.
|
1467958 | if (!strcmp(proto_str, up->name)) { |
270 | 152688 | av_freep(&protocols); | |
271 | 152688 | return up; | |
272 | } | ||
273 |
2/2✓ Branch 0 taken 162542 times.
✓ Branch 1 taken 1152728 times.
|
1315270 | if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME && |
274 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 162542 times.
|
162542 | !strcmp(proto_nested, up->name)) { |
275 | ✗ | av_freep(&protocols); | |
276 | ✗ | return up; | |
277 | } | ||
278 | } | ||
279 | ✗ | av_freep(&protocols); | |
280 | ✗ | if (av_strstart(filename, "https:", NULL) || av_strstart(filename, "tls:", NULL)) | |
281 | ✗ | av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with " | |
282 | "openssl, gnutls or securetransport enabled.\n"); | ||
283 | |||
284 | ✗ | return NULL; | |
285 | } | ||
286 | |||
287 | 144960 | int ffurl_alloc(URLContext **puc, const char *filename, int flags, | |
288 | const AVIOInterruptCB *int_cb) | ||
289 | { | ||
290 | 144960 | const URLProtocol *p = NULL; | |
291 | |||
292 | 144960 | p = url_find_protocol(filename); | |
293 |
1/2✓ Branch 0 taken 144960 times.
✗ Branch 1 not taken.
|
144960 | if (p) |
294 | 144960 | return url_alloc_for_protocol(puc, p, filename, flags, int_cb); | |
295 | |||
296 | ✗ | *puc = NULL; | |
297 | ✗ | return AVERROR_PROTOCOL_NOT_FOUND; | |
298 | } | ||
299 | |||
300 | 99605 | int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, | |
301 | const AVIOInterruptCB *int_cb, AVDictionary **options, | ||
302 | const char *whitelist, const char* blacklist, | ||
303 | URLContext *parent) | ||
304 | { | ||
305 | 99605 | AVDictionary *tmp_opts = NULL; | |
306 | AVDictionaryEntry *e; | ||
307 | 99605 | int ret = ffurl_alloc(puc, filename, flags, int_cb); | |
308 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 99605 times.
|
99605 | if (ret < 0) |
309 | ✗ | return ret; | |
310 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99604 times.
|
99605 | if (parent) { |
311 | 1 | ret = av_opt_copy(*puc, parent); | |
312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
313 | ✗ | goto fail; | |
314 | } | ||
315 |
3/4✓ Branch 0 taken 11790 times.
✓ Branch 1 taken 87815 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11790 times.
|
111395 | if (options && |
316 | 11790 | (ret = av_opt_set_dict(*puc, options)) < 0) | |
317 | ✗ | goto fail; | |
318 |
5/6✓ Branch 0 taken 11790 times.
✓ Branch 1 taken 87815 times.
✓ Branch 2 taken 9401 times.
✓ Branch 3 taken 2389 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9401 times.
|
109006 | if (options && (*puc)->prot->priv_data_class && |
319 | 9401 | (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0) | |
320 | ✗ | goto fail; | |
321 | |||
322 |
2/2✓ Branch 0 taken 87815 times.
✓ Branch 1 taken 11790 times.
|
99605 | if (!options) |
323 | 87815 | options = &tmp_opts; | |
324 | |||
325 |
3/6✓ Branch 0 taken 133 times.
✓ Branch 1 taken 99472 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 133 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
99605 | av_assert0(!whitelist || |
326 | !(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) || | ||
327 | !strcmp(whitelist, e->value)); | ||
328 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 99605 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
99605 | av_assert0(!blacklist || |
329 | !(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) || | ||
330 | !strcmp(blacklist, e->value)); | ||
331 | |||
332 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99605 times.
|
99605 | if ((ret = av_dict_set(options, "protocol_whitelist", whitelist, 0)) < 0) |
333 | ✗ | goto fail; | |
334 | |||
335 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99605 times.
|
99605 | if ((ret = av_dict_set(options, "protocol_blacklist", blacklist, 0)) < 0) |
336 | ✗ | goto fail; | |
337 | |||
338 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99605 times.
|
99605 | if ((ret = av_opt_set_dict(*puc, options)) < 0) |
339 | ✗ | goto fail; | |
340 | |||
341 | 99605 | ret = ffurl_connect(*puc, options); | |
342 | |||
343 |
2/2✓ Branch 0 taken 99604 times.
✓ Branch 1 taken 1 times.
|
99605 | if (!ret) |
344 | 99604 | return 0; | |
345 | 1 | fail: | |
346 | 1 | ffurl_closep(puc); | |
347 | 1 | return ret; | |
348 | } | ||
349 | |||
350 | 516778 | static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf, | |
351 | const uint8_t *cbuf, | ||
352 | int size, int size_min, | ||
353 | int read) | ||
354 | { | ||
355 | int ret, len; | ||
356 | 516778 | int fast_retries = 5; | |
357 | 516778 | int64_t wait_since = 0; | |
358 | |||
359 | 516778 | len = 0; | |
360 |
2/2✓ Branch 0 taken 516778 times.
✓ Branch 1 taken 504797 times.
|
1021575 | while (len < size_min) { |
361 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 516778 times.
|
516778 | if (ff_check_interrupt(&h->interrupt_callback)) |
362 | ✗ | return AVERROR_EXIT; | |
363 |
2/2✓ Branch 0 taken 201244 times.
✓ Branch 1 taken 315534 times.
|
516778 | ret = read ? h->prot->url_read (h, buf + len, size - len): |
364 | 315534 | h->prot->url_write(h, cbuf + len, size - len); | |
365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 516778 times.
|
516778 | if (ret == AVERROR(EINTR)) |
366 | ✗ | continue; | |
367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 516778 times.
|
516778 | if (h->flags & AVIO_FLAG_NONBLOCK) |
368 | ✗ | return ret; | |
369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 516778 times.
|
516778 | if (ret == AVERROR(EAGAIN)) { |
370 | ✗ | ret = 0; | |
371 | ✗ | if (fast_retries) { | |
372 | ✗ | fast_retries--; | |
373 | } else { | ||
374 | ✗ | if (h->rw_timeout) { | |
375 | ✗ | if (!wait_since) | |
376 | ✗ | wait_since = av_gettime_relative(); | |
377 | ✗ | else if (av_gettime_relative() > wait_since + h->rw_timeout) | |
378 | ✗ | return AVERROR(EIO); | |
379 | } | ||
380 | ✗ | av_usleep(1000); | |
381 | } | ||
382 |
2/2✓ Branch 0 taken 11981 times.
✓ Branch 1 taken 504797 times.
|
516778 | } else if (ret == AVERROR_EOF) |
383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11981 times.
|
11981 | return (len > 0) ? len : AVERROR_EOF; |
384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 504797 times.
|
504797 | else if (ret < 0) |
385 | ✗ | return ret; | |
386 |
1/2✓ Branch 0 taken 504797 times.
✗ Branch 1 not taken.
|
504797 | if (ret) { |
387 | 504797 | fast_retries = FFMAX(fast_retries, 2); | |
388 | 504797 | wait_since = 0; | |
389 | } | ||
390 | 504797 | len += ret; | |
391 | } | ||
392 | 504797 | return len; | |
393 | } | ||
394 | |||
395 | 201244 | int ffurl_read2(void *urlcontext, uint8_t *buf, int size) | |
396 | { | ||
397 | 201244 | URLContext *h = urlcontext; | |
398 | |||
399 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 201244 times.
|
201244 | if (!(h->flags & AVIO_FLAG_READ)) |
400 | ✗ | return AVERROR(EIO); | |
401 | 201244 | return retry_transfer_wrapper(h, buf, NULL, size, 1, 1); | |
402 | } | ||
403 | |||
404 | ✗ | int ffurl_read_complete(URLContext *h, unsigned char *buf, int size) | |
405 | { | ||
406 | ✗ | if (!(h->flags & AVIO_FLAG_READ)) | |
407 | ✗ | return AVERROR(EIO); | |
408 | ✗ | return retry_transfer_wrapper(h, buf, NULL, size, size, 1); | |
409 | } | ||
410 | |||
411 | #if FF_API_AVIO_WRITE_NONCONST | ||
412 | 315534 | int ffurl_write2(void *urlcontext, uint8_t *buf, int size) | |
413 | #else | ||
414 | int ffurl_write2(void *urlcontext, const uint8_t *buf, int size) | ||
415 | #endif | ||
416 | { | ||
417 | 315534 | URLContext *h = urlcontext; | |
418 | |||
419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 315534 times.
|
315534 | if (!(h->flags & AVIO_FLAG_WRITE)) |
420 | ✗ | return AVERROR(EIO); | |
421 | /* avoid sending too big packets */ | ||
422 |
3/4✓ Branch 0 taken 25476 times.
✓ Branch 1 taken 290058 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25476 times.
|
315534 | if (h->max_packet_size && size > h->max_packet_size) |
423 | ✗ | return AVERROR(EIO); | |
424 | |||
425 | 315534 | return retry_transfer_wrapper(h, NULL, buf, size, size, 0); | |
426 | } | ||
427 | |||
428 | 334500 | int64_t ffurl_seek2(void *urlcontext, int64_t pos, int whence) | |
429 | { | ||
430 | 334500 | URLContext *h = urlcontext; | |
431 | int64_t ret; | ||
432 | |||
433 |
2/2✓ Branch 0 taken 31055 times.
✓ Branch 1 taken 303445 times.
|
334500 | if (!h->prot->url_seek) |
434 | 31055 | return AVERROR(ENOSYS); | |
435 | 303445 | ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE); | |
436 | 303445 | return ret; | |
437 | } | ||
438 | |||
439 | 144960 | int ffurl_closep(URLContext **hh) | |
440 | { | ||
441 | 144960 | URLContext *h= *hh; | |
442 | 144960 | int ret = 0; | |
443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144960 times.
|
144960 | if (!h) |
444 | ✗ | return 0; /* can happen when ffurl_open fails */ | |
445 | |||
446 |
3/4✓ Branch 0 taken 99604 times.
✓ Branch 1 taken 45356 times.
✓ Branch 2 taken 99604 times.
✗ Branch 3 not taken.
|
144960 | if (h->is_connected && h->prot->url_close) |
447 | 99604 | ret = h->prot->url_close(h); | |
448 | #if CONFIG_NETWORK | ||
449 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144960 times.
|
144960 | if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK) |
450 | ✗ | ff_network_close(); | |
451 | #endif | ||
452 |
1/2✓ Branch 0 taken 144960 times.
✗ Branch 1 not taken.
|
144960 | if (h->prot->priv_data_size) { |
453 |
2/2✓ Branch 0 taken 142571 times.
✓ Branch 1 taken 2389 times.
|
144960 | if (h->prot->priv_data_class) |
454 | 142571 | av_opt_free(h->priv_data); | |
455 | 144960 | av_freep(&h->priv_data); | |
456 | } | ||
457 | 144960 | av_opt_free(h); | |
458 | 144960 | av_freep(hh); | |
459 | 144960 | return ret; | |
460 | } | ||
461 | |||
462 | 144958 | int ffurl_close(URLContext *h) | |
463 | { | ||
464 | 144958 | return ffurl_closep(&h); | |
465 | } | ||
466 | |||
467 | |||
468 | 7728 | const char *avio_find_protocol_name(const char *url) | |
469 | { | ||
470 | 7728 | const URLProtocol *p = url_find_protocol(url); | |
471 | |||
472 |
1/2✓ Branch 0 taken 7728 times.
✗ Branch 1 not taken.
|
7728 | return p ? p->name : NULL; |
473 | } | ||
474 | |||
475 | 45199 | int avio_check(const char *url, int flags) | |
476 | { | ||
477 | URLContext *h; | ||
478 | 45199 | int ret = ffurl_alloc(&h, url, flags, NULL); | |
479 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45199 times.
|
45199 | if (ret < 0) |
480 | ✗ | return ret; | |
481 | |||
482 |
1/2✓ Branch 0 taken 45199 times.
✗ Branch 1 not taken.
|
45199 | if (h->prot->url_check) { |
483 | 45199 | ret = h->prot->url_check(h, flags); | |
484 | } else { | ||
485 | ✗ | ret = ffurl_connect(h, NULL); | |
486 | ✗ | if (ret >= 0) | |
487 | ✗ | ret = flags; | |
488 | } | ||
489 | |||
490 | 45199 | ffurl_close(h); | |
491 | 45199 | return ret; | |
492 | } | ||
493 | |||
494 | 78 | int ffurl_move(const char *url_src, const char *url_dst) | |
495 | { | ||
496 | URLContext *h_src, *h_dst; | ||
497 | 78 | int ret = ffurl_alloc(&h_src, url_src, AVIO_FLAG_READ_WRITE, NULL); | |
498 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (ret < 0) |
499 | ✗ | return ret; | |
500 | 78 | ret = ffurl_alloc(&h_dst, url_dst, AVIO_FLAG_WRITE, NULL); | |
501 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (ret < 0) { |
502 | ✗ | ffurl_close(h_src); | |
503 | ✗ | return ret; | |
504 | } | ||
505 | |||
506 |
2/4✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
|
78 | if (h_src->prot == h_dst->prot && h_src->prot->url_move) |
507 | 78 | ret = h_src->prot->url_move(h_src, h_dst); | |
508 | else | ||
509 | ✗ | ret = AVERROR(ENOSYS); | |
510 | |||
511 | 78 | ffurl_close(h_src); | |
512 | 78 | ffurl_close(h_dst); | |
513 | 78 | return ret; | |
514 | } | ||
515 | |||
516 | ✗ | int ffurl_delete(const char *url) | |
517 | { | ||
518 | URLContext *h; | ||
519 | ✗ | int ret = ffurl_alloc(&h, url, AVIO_FLAG_WRITE, NULL); | |
520 | ✗ | if (ret < 0) | |
521 | ✗ | return ret; | |
522 | |||
523 | ✗ | if (h->prot->url_delete) | |
524 | ✗ | ret = h->prot->url_delete(h); | |
525 | else | ||
526 | ✗ | ret = AVERROR(ENOSYS); | |
527 | |||
528 | ✗ | ffurl_close(h); | |
529 | ✗ | return ret; | |
530 | } | ||
531 | |||
532 | #if !FF_API_AVIODIRCONTEXT | ||
533 | struct AVIODirContext { | ||
534 | struct URLContext *url_context; | ||
535 | }; | ||
536 | #endif | ||
537 | |||
538 | ✗ | int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options) | |
539 | { | ||
540 | ✗ | URLContext *h = NULL; | |
541 | ✗ | AVIODirContext *ctx = NULL; | |
542 | int ret; | ||
543 | ✗ | av_assert0(s); | |
544 | |||
545 | ✗ | ctx = av_mallocz(sizeof(*ctx)); | |
546 | ✗ | if (!ctx) { | |
547 | ✗ | ret = AVERROR(ENOMEM); | |
548 | ✗ | goto fail; | |
549 | } | ||
550 | |||
551 | ✗ | if ((ret = ffurl_alloc(&h, url, AVIO_FLAG_READ, NULL)) < 0) | |
552 | ✗ | goto fail; | |
553 | |||
554 | ✗ | if (h->prot->url_open_dir && h->prot->url_read_dir && h->prot->url_close_dir) { | |
555 | ✗ | if (options && h->prot->priv_data_class && | |
556 | ✗ | (ret = av_opt_set_dict(h->priv_data, options)) < 0) | |
557 | ✗ | goto fail; | |
558 | ✗ | ret = h->prot->url_open_dir(h); | |
559 | } else | ||
560 | ✗ | ret = AVERROR(ENOSYS); | |
561 | ✗ | if (ret < 0) | |
562 | ✗ | goto fail; | |
563 | |||
564 | ✗ | h->is_connected = 1; | |
565 | ✗ | ctx->url_context = h; | |
566 | ✗ | *s = ctx; | |
567 | ✗ | return 0; | |
568 | |||
569 | ✗ | fail: | |
570 | ✗ | av_free(ctx); | |
571 | ✗ | *s = NULL; | |
572 | ✗ | ffurl_close(h); | |
573 | ✗ | return ret; | |
574 | } | ||
575 | |||
576 | ✗ | int avio_read_dir(AVIODirContext *s, AVIODirEntry **next) | |
577 | { | ||
578 | URLContext *h; | ||
579 | int ret; | ||
580 | |||
581 | ✗ | if (!s || !s->url_context) | |
582 | ✗ | return AVERROR(EINVAL); | |
583 | ✗ | h = s->url_context; | |
584 | ✗ | if ((ret = h->prot->url_read_dir(h, next)) < 0) | |
585 | ✗ | avio_free_directory_entry(next); | |
586 | ✗ | return ret; | |
587 | } | ||
588 | |||
589 | ✗ | int avio_close_dir(AVIODirContext **s) | |
590 | { | ||
591 | URLContext *h; | ||
592 | |||
593 | ✗ | av_assert0(s); | |
594 | ✗ | if (!(*s) || !(*s)->url_context) | |
595 | ✗ | return AVERROR(EINVAL); | |
596 | ✗ | h = (*s)->url_context; | |
597 | ✗ | h->prot->url_close_dir(h); | |
598 | ✗ | ffurl_close(h); | |
599 | ✗ | av_freep(s); | |
600 | ✗ | *s = NULL; | |
601 | ✗ | return 0; | |
602 | } | ||
603 | |||
604 | ✗ | void avio_free_directory_entry(AVIODirEntry **entry) | |
605 | { | ||
606 | ✗ | if (!entry || !*entry) | |
607 | ✗ | return; | |
608 | ✗ | av_free((*entry)->name); | |
609 | ✗ | av_freep(entry); | |
610 | } | ||
611 | |||
612 | ✗ | int64_t ffurl_size(URLContext *h) | |
613 | { | ||
614 | int64_t pos, size; | ||
615 | |||
616 | ✗ | size = ffurl_seek(h, 0, AVSEEK_SIZE); | |
617 | ✗ | if (size < 0) { | |
618 | ✗ | pos = ffurl_seek(h, 0, SEEK_CUR); | |
619 | ✗ | if ((size = ffurl_seek(h, -1, SEEK_END)) < 0) | |
620 | ✗ | return size; | |
621 | ✗ | size++; | |
622 | ✗ | ffurl_seek(h, pos, SEEK_SET); | |
623 | } | ||
624 | ✗ | return size; | |
625 | } | ||
626 | |||
627 | ✗ | int ffurl_get_file_handle(URLContext *h) | |
628 | { | ||
629 | ✗ | if (!h || !h->prot || !h->prot->url_get_file_handle) | |
630 | ✗ | return -1; | |
631 | ✗ | return h->prot->url_get_file_handle(h); | |
632 | } | ||
633 | |||
634 | ✗ | int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles) | |
635 | { | ||
636 | ✗ | if (!h || !h->prot) | |
637 | ✗ | return AVERROR(ENOSYS); | |
638 | ✗ | if (!h->prot->url_get_multi_file_handle) { | |
639 | ✗ | if (!h->prot->url_get_file_handle) | |
640 | ✗ | return AVERROR(ENOSYS); | |
641 | ✗ | *handles = av_malloc(sizeof(**handles)); | |
642 | ✗ | if (!*handles) | |
643 | ✗ | return AVERROR(ENOMEM); | |
644 | ✗ | *numhandles = 1; | |
645 | ✗ | *handles[0] = h->prot->url_get_file_handle(h); | |
646 | ✗ | return 0; | |
647 | } | ||
648 | ✗ | return h->prot->url_get_multi_file_handle(h, handles, numhandles); | |
649 | } | ||
650 | |||
651 | 318162 | int ffurl_get_short_seek(void *urlcontext) | |
652 | { | ||
653 | 318162 | URLContext *h = urlcontext; | |
654 | |||
655 |
3/6✓ Branch 0 taken 318162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 318162 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 318162 times.
✗ Branch 5 not taken.
|
318162 | if (!h || !h->prot || !h->prot->url_get_short_seek) |
656 | 318162 | return AVERROR(ENOSYS); | |
657 | ✗ | return h->prot->url_get_short_seek(h); | |
658 | } | ||
659 | |||
660 | ✗ | int ffurl_shutdown(URLContext *h, int flags) | |
661 | { | ||
662 | ✗ | if (!h || !h->prot || !h->prot->url_shutdown) | |
663 | ✗ | return AVERROR(ENOSYS); | |
664 | ✗ | return h->prot->url_shutdown(h, flags); | |
665 | } | ||
666 | |||
667 | 699495 | int ff_check_interrupt(AVIOInterruptCB *cb) | |
668 | { | ||
669 |
3/4✓ Branch 0 taken 699495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 673203 times.
✓ Branch 3 taken 26292 times.
|
699495 | if (cb && cb->callback) |
670 | 673203 | return cb->callback(cb->opaque); | |
671 | 26292 | return 0; | |
672 | } | ||
673 | |||
674 | 78 | int ff_rename(const char *url_src, const char *url_dst, void *logctx) | |
675 | { | ||
676 | 78 | int ret = ffurl_move(url_src, url_dst); | |
677 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (ret < 0) |
678 | ✗ | av_log(logctx, AV_LOG_ERROR, "failed to rename file %s to %s: %s\n", url_src, url_dst, av_err2str(ret)); | |
679 | 78 | return ret; | |
680 | } | ||
681 |