1 /* 2 * QEMU Block driver for CURL images 3 * 4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 #include "qemu-common.h" 25 #include "block/block_int.h" 26 #include "qapi/qmp/qbool.h" 27 #include <curl/curl.h> 28 29 // #define DEBUG 30 // #define DEBUG_VERBOSE 31 32 #ifdef DEBUG_CURL 33 #define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0) 34 #else 35 #define DPRINTF(fmt, ...) do { } while (0) 36 #endif 37 38 #if LIBCURL_VERSION_NUM >= 0x071000 39 /* The multi interface timer callback was introduced in 7.16.0 */ 40 #define NEED_CURL_TIMER_CALLBACK 41 #define HAVE_SOCKET_ACTION 42 #endif 43 44 #ifndef HAVE_SOCKET_ACTION 45 /* If curl_multi_socket_action isn't available, define it statically here in 46 * terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is 47 * less efficient but still safe. */ 48 static CURLMcode __curl_multi_socket_action(CURLM *multi_handle, 49 curl_socket_t sockfd, 50 int ev_bitmask, 51 int *running_handles) 52 { 53 return curl_multi_socket(multi_handle, sockfd, running_handles); 54 } 55 #define curl_multi_socket_action __curl_multi_socket_action 56 #endif 57 58 #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \ 59 CURLPROTO_FTP | CURLPROTO_FTPS | \ 60 CURLPROTO_TFTP) 61 62 #define CURL_NUM_STATES 8 63 #define CURL_NUM_ACB 8 64 #define SECTOR_SIZE 512 65 #define READ_AHEAD_DEFAULT (256 * 1024) 66 67 #define FIND_RET_NONE 0 68 #define FIND_RET_OK 1 69 #define FIND_RET_WAIT 2 70 71 #define CURL_BLOCK_OPT_URL "url" 72 #define CURL_BLOCK_OPT_READAHEAD "readahead" 73 #define CURL_BLOCK_OPT_SSLVERIFY "sslverify" 74 75 struct BDRVCURLState; 76 77 typedef struct CURLAIOCB { 78 BlockDriverAIOCB common; 79 QEMUBH *bh; 80 QEMUIOVector *qiov; 81 82 int64_t sector_num; 83 int nb_sectors; 84 85 size_t start; 86 size_t end; 87 } CURLAIOCB; 88 89 typedef struct CURLState 90 { 91 struct BDRVCURLState *s; 92 CURLAIOCB *acb[CURL_NUM_ACB]; 93 CURL *curl; 94 curl_socket_t sock_fd; 95 char *orig_buf; 96 size_t buf_start; 97 size_t buf_off; 98 size_t buf_len; 99 char range[128]; 100 char errmsg[CURL_ERROR_SIZE]; 101 char in_use; 102 } CURLState; 103 104 typedef struct BDRVCURLState { 105 CURLM *multi; 106 QEMUTimer timer; 107 size_t len; 108 CURLState states[CURL_NUM_STATES]; 109 char *url; 110 size_t readahead_size; 111 bool sslverify; 112 bool accept_range; 113 AioContext *aio_context; 114 } BDRVCURLState; 115 116 static void curl_clean_state(CURLState *s); 117 static void curl_multi_do(void *arg); 118 static void curl_multi_read(void *arg); 119 120 #ifdef NEED_CURL_TIMER_CALLBACK 121 static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque) 122 { 123 BDRVCURLState *s = opaque; 124 125 DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms); 126 if (timeout_ms == -1) { 127 timer_del(&s->timer); 128 } else { 129 int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000; 130 timer_mod(&s->timer, 131 qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns); 132 } 133 return 0; 134 } 135 #endif 136 137 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, 138 void *userp, void *sp) 139 { 140 BDRVCURLState *s; 141 CURLState *state = NULL; 142 curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state); 143 state->sock_fd = fd; 144 s = state->s; 145 146 DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd); 147 switch (action) { 148 case CURL_POLL_IN: 149 aio_set_fd_handler(s->aio_context, fd, curl_multi_read, 150 NULL, state); 151 break; 152 case CURL_POLL_OUT: 153 aio_set_fd_handler(s->aio_context, fd, NULL, curl_multi_do, state); 154 break; 155 case CURL_POLL_INOUT: 156 aio_set_fd_handler(s->aio_context, fd, curl_multi_read, 157 curl_multi_do, state); 158 break; 159 case CURL_POLL_REMOVE: 160 aio_set_fd_handler(s->aio_context, fd, NULL, NULL, NULL); 161 break; 162 } 163 164 return 0; 165 } 166 167 static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque) 168 { 169 BDRVCURLState *s = opaque; 170 size_t realsize = size * nmemb; 171 const char *accept_line = "Accept-Ranges: bytes"; 172 173 if (realsize >= strlen(accept_line) 174 && strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) { 175 s->accept_range = true; 176 } 177 178 return realsize; 179 } 180 181 static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque) 182 { 183 CURLState *s = ((CURLState*)opaque); 184 size_t realsize = size * nmemb; 185 int i; 186 187 DPRINTF("CURL: Just reading %zd bytes\n", realsize); 188 189 if (!s || !s->orig_buf) 190 return 0; 191 192 if (s->buf_off >= s->buf_len) { 193 /* buffer full, read nothing */ 194 return 0; 195 } 196 realsize = MIN(realsize, s->buf_len - s->buf_off); 197 memcpy(s->orig_buf + s->buf_off, ptr, realsize); 198 s->buf_off += realsize; 199 200 for(i=0; i<CURL_NUM_ACB; i++) { 201 CURLAIOCB *acb = s->acb[i]; 202 203 if (!acb) 204 continue; 205 206 if ((s->buf_off >= acb->end)) { 207 qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start, 208 acb->end - acb->start); 209 acb->common.cb(acb->common.opaque, 0); 210 qemu_aio_release(acb); 211 s->acb[i] = NULL; 212 } 213 } 214 215 return realsize; 216 } 217 218 static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len, 219 CURLAIOCB *acb) 220 { 221 int i; 222 size_t end = start + len; 223 224 for (i=0; i<CURL_NUM_STATES; i++) { 225 CURLState *state = &s->states[i]; 226 size_t buf_end = (state->buf_start + state->buf_off); 227 size_t buf_fend = (state->buf_start + state->buf_len); 228 229 if (!state->orig_buf) 230 continue; 231 if (!state->buf_off) 232 continue; 233 234 // Does the existing buffer cover our section? 235 if ((start >= state->buf_start) && 236 (start <= buf_end) && 237 (end >= state->buf_start) && 238 (end <= buf_end)) 239 { 240 char *buf = state->orig_buf + (start - state->buf_start); 241 242 qemu_iovec_from_buf(acb->qiov, 0, buf, len); 243 acb->common.cb(acb->common.opaque, 0); 244 245 return FIND_RET_OK; 246 } 247 248 // Wait for unfinished chunks 249 if (state->in_use && 250 (start >= state->buf_start) && 251 (start <= buf_fend) && 252 (end >= state->buf_start) && 253 (end <= buf_fend)) 254 { 255 int j; 256 257 acb->start = start - state->buf_start; 258 acb->end = acb->start + len; 259 260 for (j=0; j<CURL_NUM_ACB; j++) { 261 if (!state->acb[j]) { 262 state->acb[j] = acb; 263 return FIND_RET_WAIT; 264 } 265 } 266 } 267 } 268 269 return FIND_RET_NONE; 270 } 271 272 static void curl_multi_check_completion(BDRVCURLState *s) 273 { 274 int msgs_in_queue; 275 276 /* Try to find done transfers, so we can free the easy 277 * handle again. */ 278 for (;;) { 279 CURLMsg *msg; 280 msg = curl_multi_info_read(s->multi, &msgs_in_queue); 281 282 /* Quit when there are no more completions */ 283 if (!msg) 284 break; 285 286 if (msg->msg == CURLMSG_DONE) { 287 CURLState *state = NULL; 288 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, 289 (char **)&state); 290 291 /* ACBs for successful messages get completed in curl_read_cb */ 292 if (msg->data.result != CURLE_OK) { 293 int i; 294 for (i = 0; i < CURL_NUM_ACB; i++) { 295 CURLAIOCB *acb = state->acb[i]; 296 297 if (acb == NULL) { 298 continue; 299 } 300 301 acb->common.cb(acb->common.opaque, -EIO); 302 qemu_aio_release(acb); 303 state->acb[i] = NULL; 304 } 305 } 306 307 curl_clean_state(state); 308 break; 309 } 310 } 311 } 312 313 static void curl_multi_do(void *arg) 314 { 315 CURLState *s = (CURLState *)arg; 316 int running; 317 int r; 318 319 if (!s->s->multi) { 320 return; 321 } 322 323 do { 324 r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running); 325 } while(r == CURLM_CALL_MULTI_PERFORM); 326 327 } 328 329 static void curl_multi_read(void *arg) 330 { 331 CURLState *s = (CURLState *)arg; 332 333 curl_multi_do(arg); 334 curl_multi_check_completion(s->s); 335 } 336 337 static void curl_multi_timeout_do(void *arg) 338 { 339 #ifdef NEED_CURL_TIMER_CALLBACK 340 BDRVCURLState *s = (BDRVCURLState *)arg; 341 int running; 342 343 if (!s->multi) { 344 return; 345 } 346 347 curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running); 348 349 curl_multi_check_completion(s); 350 #else 351 abort(); 352 #endif 353 } 354 355 static CURLState *curl_init_state(BDRVCURLState *s) 356 { 357 CURLState *state = NULL; 358 int i, j; 359 360 do { 361 for (i=0; i<CURL_NUM_STATES; i++) { 362 for (j=0; j<CURL_NUM_ACB; j++) 363 if (s->states[i].acb[j]) 364 continue; 365 if (s->states[i].in_use) 366 continue; 367 368 state = &s->states[i]; 369 state->in_use = 1; 370 break; 371 } 372 if (!state) { 373 aio_poll(state->s->aio_context, true); 374 } 375 } while(!state); 376 377 if (!state->curl) { 378 state->curl = curl_easy_init(); 379 if (!state->curl) { 380 return NULL; 381 } 382 curl_easy_setopt(state->curl, CURLOPT_URL, s->url); 383 curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER, 384 (long) s->sslverify); 385 curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5); 386 curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, 387 (void *)curl_read_cb); 388 curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state); 389 curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state); 390 curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1); 391 curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1); 392 curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1); 393 curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg); 394 curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1); 395 396 /* Restrict supported protocols to avoid security issues in the more 397 * obscure protocols. For example, do not allow POP3/SMTP/IMAP see 398 * CVE-2013-0249. 399 * 400 * Restricting protocols is only supported from 7.19.4 upwards. 401 */ 402 #if LIBCURL_VERSION_NUM >= 0x071304 403 curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS); 404 curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS); 405 #endif 406 407 #ifdef DEBUG_VERBOSE 408 curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1); 409 #endif 410 } 411 412 state->s = s; 413 414 return state; 415 } 416 417 static void curl_clean_state(CURLState *s) 418 { 419 if (s->s->multi) 420 curl_multi_remove_handle(s->s->multi, s->curl); 421 s->in_use = 0; 422 } 423 424 static void curl_parse_filename(const char *filename, QDict *options, 425 Error **errp) 426 { 427 qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename)); 428 } 429 430 static void curl_detach_aio_context(BlockDriverState *bs) 431 { 432 BDRVCURLState *s = bs->opaque; 433 int i; 434 435 for (i = 0; i < CURL_NUM_STATES; i++) { 436 if (s->states[i].in_use) { 437 curl_clean_state(&s->states[i]); 438 } 439 if (s->states[i].curl) { 440 curl_easy_cleanup(s->states[i].curl); 441 s->states[i].curl = NULL; 442 } 443 if (s->states[i].orig_buf) { 444 g_free(s->states[i].orig_buf); 445 s->states[i].orig_buf = NULL; 446 } 447 } 448 if (s->multi) { 449 curl_multi_cleanup(s->multi); 450 s->multi = NULL; 451 } 452 453 timer_del(&s->timer); 454 } 455 456 static void curl_attach_aio_context(BlockDriverState *bs, 457 AioContext *new_context) 458 { 459 BDRVCURLState *s = bs->opaque; 460 461 aio_timer_init(new_context, &s->timer, 462 QEMU_CLOCK_REALTIME, SCALE_NS, 463 curl_multi_timeout_do, s); 464 465 assert(!s->multi); 466 s->multi = curl_multi_init(); 467 s->aio_context = new_context; 468 curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb); 469 #ifdef NEED_CURL_TIMER_CALLBACK 470 curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s); 471 curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb); 472 #endif 473 } 474 475 static QemuOptsList runtime_opts = { 476 .name = "curl", 477 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 478 .desc = { 479 { 480 .name = CURL_BLOCK_OPT_URL, 481 .type = QEMU_OPT_STRING, 482 .help = "URL to open", 483 }, 484 { 485 .name = CURL_BLOCK_OPT_READAHEAD, 486 .type = QEMU_OPT_SIZE, 487 .help = "Readahead size", 488 }, 489 { 490 .name = CURL_BLOCK_OPT_SSLVERIFY, 491 .type = QEMU_OPT_BOOL, 492 .help = "Verify SSL certificate" 493 }, 494 { /* end of list */ } 495 }, 496 }; 497 498 static int curl_open(BlockDriverState *bs, QDict *options, int flags, 499 Error **errp) 500 { 501 BDRVCURLState *s = bs->opaque; 502 CURLState *state = NULL; 503 QemuOpts *opts; 504 Error *local_err = NULL; 505 const char *file; 506 double d; 507 508 static int inited = 0; 509 510 if (flags & BDRV_O_RDWR) { 511 error_setg(errp, "curl block device does not support writes"); 512 return -EROFS; 513 } 514 515 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 516 qemu_opts_absorb_qdict(opts, options, &local_err); 517 if (local_err) { 518 error_propagate(errp, local_err); 519 goto out_noclean; 520 } 521 522 s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD, 523 READ_AHEAD_DEFAULT); 524 if ((s->readahead_size & 0x1ff) != 0) { 525 error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", 526 s->readahead_size); 527 goto out_noclean; 528 } 529 530 s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true); 531 532 file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL); 533 if (file == NULL) { 534 error_setg(errp, "curl block driver requires an 'url' option"); 535 goto out_noclean; 536 } 537 538 if (!inited) { 539 curl_global_init(CURL_GLOBAL_ALL); 540 inited = 1; 541 } 542 543 DPRINTF("CURL: Opening %s\n", file); 544 s->aio_context = bdrv_get_aio_context(bs); 545 s->url = g_strdup(file); 546 state = curl_init_state(s); 547 if (!state) 548 goto out_noclean; 549 550 // Get file size 551 552 s->accept_range = false; 553 curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1); 554 curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, 555 curl_header_cb); 556 curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s); 557 if (curl_easy_perform(state->curl)) 558 goto out; 559 curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d); 560 if (d) 561 s->len = (size_t)d; 562 else if(!s->len) 563 goto out; 564 if ((!strncasecmp(s->url, "http://", strlen("http://")) 565 || !strncasecmp(s->url, "https://", strlen("https://"))) 566 && !s->accept_range) { 567 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 568 "Server does not support 'range' (byte ranges)."); 569 goto out; 570 } 571 DPRINTF("CURL: Size = %zd\n", s->len); 572 573 curl_clean_state(state); 574 curl_easy_cleanup(state->curl); 575 state->curl = NULL; 576 577 curl_attach_aio_context(bs, bdrv_get_aio_context(bs)); 578 579 qemu_opts_del(opts); 580 return 0; 581 582 out: 583 error_setg(errp, "CURL: Error opening file: %s", state->errmsg); 584 curl_easy_cleanup(state->curl); 585 state->curl = NULL; 586 out_noclean: 587 g_free(s->url); 588 qemu_opts_del(opts); 589 return -EINVAL; 590 } 591 592 static void curl_aio_cancel(BlockDriverAIOCB *blockacb) 593 { 594 // Do we have to implement canceling? Seems to work without... 595 } 596 597 static const AIOCBInfo curl_aiocb_info = { 598 .aiocb_size = sizeof(CURLAIOCB), 599 .cancel = curl_aio_cancel, 600 }; 601 602 603 static void curl_readv_bh_cb(void *p) 604 { 605 CURLState *state; 606 int running; 607 608 CURLAIOCB *acb = p; 609 BDRVCURLState *s = acb->common.bs->opaque; 610 611 qemu_bh_delete(acb->bh); 612 acb->bh = NULL; 613 614 size_t start = acb->sector_num * SECTOR_SIZE; 615 size_t end; 616 617 // In case we have the requested data already (e.g. read-ahead), 618 // we can just call the callback and be done. 619 switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) { 620 case FIND_RET_OK: 621 qemu_aio_release(acb); 622 // fall through 623 case FIND_RET_WAIT: 624 return; 625 default: 626 break; 627 } 628 629 // No cache found, so let's start a new request 630 state = curl_init_state(s); 631 if (!state) { 632 acb->common.cb(acb->common.opaque, -EIO); 633 qemu_aio_release(acb); 634 return; 635 } 636 637 acb->start = 0; 638 acb->end = (acb->nb_sectors * SECTOR_SIZE); 639 640 state->buf_off = 0; 641 if (state->orig_buf) 642 g_free(state->orig_buf); 643 state->buf_start = start; 644 state->buf_len = acb->end + s->readahead_size; 645 end = MIN(start + state->buf_len, s->len) - 1; 646 state->orig_buf = g_malloc(state->buf_len); 647 state->acb[0] = acb; 648 649 snprintf(state->range, 127, "%zd-%zd", start, end); 650 DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n", 651 (acb->nb_sectors * SECTOR_SIZE), start, state->range); 652 curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range); 653 654 curl_multi_add_handle(s->multi, state->curl); 655 656 /* Tell curl it needs to kick things off */ 657 curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running); 658 } 659 660 static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, 661 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 662 BlockDriverCompletionFunc *cb, void *opaque) 663 { 664 CURLAIOCB *acb; 665 666 acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque); 667 668 acb->qiov = qiov; 669 acb->sector_num = sector_num; 670 acb->nb_sectors = nb_sectors; 671 672 acb->bh = aio_bh_new(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb); 673 qemu_bh_schedule(acb->bh); 674 return &acb->common; 675 } 676 677 static void curl_close(BlockDriverState *bs) 678 { 679 BDRVCURLState *s = bs->opaque; 680 681 DPRINTF("CURL: Close\n"); 682 curl_detach_aio_context(bs); 683 684 g_free(s->url); 685 } 686 687 static int64_t curl_getlength(BlockDriverState *bs) 688 { 689 BDRVCURLState *s = bs->opaque; 690 return s->len; 691 } 692 693 static BlockDriver bdrv_http = { 694 .format_name = "http", 695 .protocol_name = "http", 696 697 .instance_size = sizeof(BDRVCURLState), 698 .bdrv_parse_filename = curl_parse_filename, 699 .bdrv_file_open = curl_open, 700 .bdrv_close = curl_close, 701 .bdrv_getlength = curl_getlength, 702 703 .bdrv_aio_readv = curl_aio_readv, 704 705 .bdrv_detach_aio_context = curl_detach_aio_context, 706 .bdrv_attach_aio_context = curl_attach_aio_context, 707 }; 708 709 static BlockDriver bdrv_https = { 710 .format_name = "https", 711 .protocol_name = "https", 712 713 .instance_size = sizeof(BDRVCURLState), 714 .bdrv_parse_filename = curl_parse_filename, 715 .bdrv_file_open = curl_open, 716 .bdrv_close = curl_close, 717 .bdrv_getlength = curl_getlength, 718 719 .bdrv_aio_readv = curl_aio_readv, 720 721 .bdrv_detach_aio_context = curl_detach_aio_context, 722 .bdrv_attach_aio_context = curl_attach_aio_context, 723 }; 724 725 static BlockDriver bdrv_ftp = { 726 .format_name = "ftp", 727 .protocol_name = "ftp", 728 729 .instance_size = sizeof(BDRVCURLState), 730 .bdrv_parse_filename = curl_parse_filename, 731 .bdrv_file_open = curl_open, 732 .bdrv_close = curl_close, 733 .bdrv_getlength = curl_getlength, 734 735 .bdrv_aio_readv = curl_aio_readv, 736 737 .bdrv_detach_aio_context = curl_detach_aio_context, 738 .bdrv_attach_aio_context = curl_attach_aio_context, 739 }; 740 741 static BlockDriver bdrv_ftps = { 742 .format_name = "ftps", 743 .protocol_name = "ftps", 744 745 .instance_size = sizeof(BDRVCURLState), 746 .bdrv_parse_filename = curl_parse_filename, 747 .bdrv_file_open = curl_open, 748 .bdrv_close = curl_close, 749 .bdrv_getlength = curl_getlength, 750 751 .bdrv_aio_readv = curl_aio_readv, 752 753 .bdrv_detach_aio_context = curl_detach_aio_context, 754 .bdrv_attach_aio_context = curl_attach_aio_context, 755 }; 756 757 static BlockDriver bdrv_tftp = { 758 .format_name = "tftp", 759 .protocol_name = "tftp", 760 761 .instance_size = sizeof(BDRVCURLState), 762 .bdrv_parse_filename = curl_parse_filename, 763 .bdrv_file_open = curl_open, 764 .bdrv_close = curl_close, 765 .bdrv_getlength = curl_getlength, 766 767 .bdrv_aio_readv = curl_aio_readv, 768 769 .bdrv_detach_aio_context = curl_detach_aio_context, 770 .bdrv_attach_aio_context = curl_attach_aio_context, 771 }; 772 773 static void curl_block_init(void) 774 { 775 bdrv_register(&bdrv_http); 776 bdrv_register(&bdrv_https); 777 bdrv_register(&bdrv_ftp); 778 bdrv_register(&bdrv_ftps); 779 bdrv_register(&bdrv_tftp); 780 } 781 782 block_init(curl_block_init); 783